From 1ac174de36da55274b2cb67dc2f58fd4deb551ee Mon Sep 17 00:00:00 2001
From: Thomas Schmitt
Date: Fri, 16 Sep 2016 10:44:37 +0000
Subject: [PATCH] Branching for libburn release 1.4.6
---
libburn/branches/1.4.6/AUTHORS | 3 +
libburn/branches/1.4.6/CONTRIBUTORS | 6 +
libburn/branches/1.4.6/COPYING | 280 +
libburn/branches/1.4.6/COPYRIGHT | 18 +
libburn/branches/1.4.6/ChangeLog | 472 +
libburn/branches/1.4.6/INSTALL | 234 +
libburn/branches/1.4.6/Makefile.am | 235 +
libburn/branches/1.4.6/NEWS | 1 +
libburn/branches/1.4.6/README | 815 +
libburn/branches/1.4.6/acinclude.m4 | 151 +
libburn/branches/1.4.6/bootstrap | 10 +
libburn/branches/1.4.6/cdrskin/README | 604 +
.../cdrskin/add_ts_changes_to_libburn_1_4_4 | 247 +
.../cdrskin/add_ts_changes_to_libburn_1_4_5 | 247 +
.../branches/1.4.6/cdrskin/cdrecord_spy.sh | 37 +
libburn/branches/1.4.6/cdrskin/cdrfifo.c | 1313 ++
libburn/branches/1.4.6/cdrskin/cdrfifo.h | 171 +
libburn/branches/1.4.6/cdrskin/cdrskin.1 | 1807 ++
libburn/branches/1.4.6/cdrskin/cdrskin.c | 9848 +++++++++++
.../branches/1.4.6/cdrskin/cdrskin_eng.html | 569 +
.../1.4.6/cdrskin/cdrskin_timestamp.h | 1 +
libburn/branches/1.4.6/cdrskin/changelog.txt | 13577 ++++++++++++++++
libburn/branches/1.4.6/cdrskin/cleanup.c | 216 +
libburn/branches/1.4.6/cdrskin/cleanup.h | 34 +
.../branches/1.4.6/cdrskin/compile_cdrskin.sh | 245 +
.../1.4.6/cdrskin/convert_man_to_html.sh | 82 +
.../1.4.6/cdrskin/doener_150x200_tr.png | Bin 0 -> 10595 bytes
.../1.4.6/cdrskin/doener_150x200_tr_octx.png | Bin 0 -> 9433 bytes
.../branches/1.4.6/cdrskin/make_timestamp.sh | 9 +
.../1.4.6/cdrskin/unite_html_b_line.c | 124 +
libburn/branches/1.4.6/cdrskin/wiki_plain.txt | 297 +
libburn/branches/1.4.6/configure.ac | 367 +
libburn/branches/1.4.6/doc/Makefile | 4 +
libburn/branches/1.4.6/doc/cdtext.txt | 736 +
libburn/branches/1.4.6/doc/comments | 119 +
libburn/branches/1.4.6/doc/cookbook.txt | 1520 ++
libburn/branches/1.4.6/doc/ddlp.txt | 388 +
libburn/branches/1.4.6/doc/doxygen.conf.in | 1884 +++
libburn/branches/1.4.6/doc/mediainfo.txt | 1216 ++
libburn/branches/1.4.6/libburn-1.pc.in | 12 +
libburn/branches/1.4.6/libburn/Makefile | 4 +
libburn/branches/1.4.6/libburn/Makefile.am | 65 +
libburn/branches/1.4.6/libburn/asserts.txt | 792 +
libburn/branches/1.4.6/libburn/async.c | 796 +
libburn/branches/1.4.6/libburn/async.h | 18 +
libburn/branches/1.4.6/libburn/back_hacks.h | 56 +
libburn/branches/1.4.6/libburn/cdtext.c | 1737 ++
libburn/branches/1.4.6/libburn/cleanup.c | 242 +
libburn/branches/1.4.6/libburn/cleanup.h | 34 +
libburn/branches/1.4.6/libburn/crc.c | 642 +
libburn/branches/1.4.6/libburn/crc.h | 33 +
libburn/branches/1.4.6/libburn/ddlpa.c | 621 +
libburn/branches/1.4.6/libburn/ddlpa.h | 107 +
libburn/branches/1.4.6/libburn/debug.c | 28 +
libburn/branches/1.4.6/libburn/debug.h | 8 +
libburn/branches/1.4.6/libburn/drive.c | 3615 ++++
libburn/branches/1.4.6/libburn/drive.h | 173 +
libburn/branches/1.4.6/libburn/ecma130ab.c | 855 +
libburn/branches/1.4.6/libburn/ecma130ab.h | 24 +
libburn/branches/1.4.6/libburn/error.h | 8 +
libburn/branches/1.4.6/libburn/file.c | 1083 ++
libburn/branches/1.4.6/libburn/file.h | 99 +
libburn/branches/1.4.6/libburn/init.c | 664 +
libburn/branches/1.4.6/libburn/init.h | 63 +
libburn/branches/1.4.6/libburn/libburn.h | 4357 +++++
libburn/branches/1.4.6/libburn/libburn.ver | 208 +
.../branches/1.4.6/libburn/libdax_audioxtr.c | 331 +
.../branches/1.4.6/libburn/libdax_audioxtr.h | 237 +
libburn/branches/1.4.6/libburn/libdax_msgs.c | 449 +
libburn/branches/1.4.6/libburn/libdax_msgs.h | 772 +
.../1.4.6/libburn/libdax_msgs_to_xyz_msgs.sh | 37 +
libburn/branches/1.4.6/libburn/mmc.c | 5442 +++++++
libburn/branches/1.4.6/libburn/mmc.h | 141 +
libburn/branches/1.4.6/libburn/null.c | 40 +
libburn/branches/1.4.6/libburn/null.h | 10 +
libburn/branches/1.4.6/libburn/options.c | 600 +
libburn/branches/1.4.6/libburn/options.h | 157 +
libburn/branches/1.4.6/libburn/os-dummy.h | 88 +
libburn/branches/1.4.6/libburn/os-freebsd.h | 65 +
libburn/branches/1.4.6/libburn/os-libcdio.h | 95 +
libburn/branches/1.4.6/libburn/os-linux.h | 81 +
libburn/branches/1.4.6/libburn/os-netbsd.h | 99 +
libburn/branches/1.4.6/libburn/os-solaris.h | 65 +
libburn/branches/1.4.6/libburn/os.h | 98 +
libburn/branches/1.4.6/libburn/read.c | 778 +
libburn/branches/1.4.6/libburn/read.h | 14 +
libburn/branches/1.4.6/libburn/sbc.c | 186 +
libburn/branches/1.4.6/libburn/sbc.h | 24 +
libburn/branches/1.4.6/libburn/sector.c | 953 ++
libburn/branches/1.4.6/libburn/sector.h | 44 +
libburn/branches/1.4.6/libburn/sg-dummy.c | 359 +
.../branches/1.4.6/libburn/sg-freebsd-port.c | 824 +
libburn/branches/1.4.6/libburn/sg-freebsd.c | 1176 ++
libburn/branches/1.4.6/libburn/sg-libcdio.c | 1014 ++
libburn/branches/1.4.6/libburn/sg-linux.c | 2523 +++
libburn/branches/1.4.6/libburn/sg-netbsd.c | 911 ++
libburn/branches/1.4.6/libburn/sg-solaris.c | 1013 ++
libburn/branches/1.4.6/libburn/sg.c | 93 +
libburn/branches/1.4.6/libburn/sg.h | 84 +
libburn/branches/1.4.6/libburn/source.c | 76 +
libburn/branches/1.4.6/libburn/source.h | 12 +
libburn/branches/1.4.6/libburn/spc.c | 2071 +++
libburn/branches/1.4.6/libburn/spc.h | 180 +
libburn/branches/1.4.6/libburn/structure.c | 2168 +++
libburn/branches/1.4.6/libburn/structure.h | 190 +
libburn/branches/1.4.6/libburn/toc.c | 162 +
libburn/branches/1.4.6/libburn/toc.h | 53 +
libburn/branches/1.4.6/libburn/transport.h | 531 +
libburn/branches/1.4.6/libburn/util.c | 402 +
libburn/branches/1.4.6/libburn/util.h | 25 +
libburn/branches/1.4.6/libburn/write.c | 3414 ++++
libburn/branches/1.4.6/libburn/write.h | 61 +
libburn/branches/1.4.6/libcevap/cgen.c | 1503 ++
libburn/branches/1.4.6/libcevap/cgen.h | 35 +
libburn/branches/1.4.6/libcevap/cgen.txt | 222 +
libburn/branches/1.4.6/libcevap/ctyp.c | 364 +
libburn/branches/1.4.6/libcevap/ctyp.h | 41 +
.../1.4.6/libcevap/extract_cgen_input.sh | 30 +
.../branches/1.4.6/libcevap/libcevap_gen.sh | 16 +
.../branches/1.4.6/libcevap/libdax_equip.gif | Bin 0 -> 10751 bytes
.../branches/1.4.6/libcevap/libdax_job.gif | Bin 0 -> 10532 bytes
.../branches/1.4.6/libcevap/libdax_model.txt | 944 ++
.../1.4.6/libcevap/libdax_overview.gif | Bin 0 -> 12521 bytes
libburn/branches/1.4.6/libcevap/main.c | 39 +
libburn/branches/1.4.6/libcevap/smem.c | 445 +
libburn/branches/1.4.6/libcevap/smem.h | 165 +
libburn/branches/1.4.6/test/Makefile | 4 +
libburn/branches/1.4.6/test/dewav.c | 216 +
libburn/branches/1.4.6/test/fake_au.c | 172 +
libburn/branches/1.4.6/test/libburner.c | 841 +
libburn/branches/1.4.6/test/offst_source.c | 134 +
libburn/branches/1.4.6/test/open-cd-excl.c | 133 +
libburn/branches/1.4.6/test/poll.c | 77 +
libburn/branches/1.4.6/test/telltoc.c | 1009 ++
libburn/branches/1.4.6/version.h.in | 3 +
135 files changed, 88772 insertions(+)
create mode 100644 libburn/branches/1.4.6/AUTHORS
create mode 100644 libburn/branches/1.4.6/CONTRIBUTORS
create mode 100644 libburn/branches/1.4.6/COPYING
create mode 100644 libburn/branches/1.4.6/COPYRIGHT
create mode 100644 libburn/branches/1.4.6/ChangeLog
create mode 100644 libburn/branches/1.4.6/INSTALL
create mode 100644 libburn/branches/1.4.6/Makefile.am
create mode 100644 libburn/branches/1.4.6/NEWS
create mode 100644 libburn/branches/1.4.6/README
create mode 100644 libburn/branches/1.4.6/acinclude.m4
create mode 100755 libburn/branches/1.4.6/bootstrap
create mode 100644 libburn/branches/1.4.6/cdrskin/README
create mode 100755 libburn/branches/1.4.6/cdrskin/add_ts_changes_to_libburn_1_4_4
create mode 100755 libburn/branches/1.4.6/cdrskin/add_ts_changes_to_libburn_1_4_5
create mode 100755 libburn/branches/1.4.6/cdrskin/cdrecord_spy.sh
create mode 100644 libburn/branches/1.4.6/cdrskin/cdrfifo.c
create mode 100644 libburn/branches/1.4.6/cdrskin/cdrfifo.h
create mode 100644 libburn/branches/1.4.6/cdrskin/cdrskin.1
create mode 100644 libburn/branches/1.4.6/cdrskin/cdrskin.c
create mode 100644 libburn/branches/1.4.6/cdrskin/cdrskin_eng.html
create mode 100644 libburn/branches/1.4.6/cdrskin/cdrskin_timestamp.h
create mode 100644 libburn/branches/1.4.6/cdrskin/changelog.txt
create mode 100644 libburn/branches/1.4.6/cdrskin/cleanup.c
create mode 100644 libburn/branches/1.4.6/cdrskin/cleanup.h
create mode 100755 libburn/branches/1.4.6/cdrskin/compile_cdrskin.sh
create mode 100755 libburn/branches/1.4.6/cdrskin/convert_man_to_html.sh
create mode 100644 libburn/branches/1.4.6/cdrskin/doener_150x200_tr.png
create mode 100644 libburn/branches/1.4.6/cdrskin/doener_150x200_tr_octx.png
create mode 100755 libburn/branches/1.4.6/cdrskin/make_timestamp.sh
create mode 100644 libburn/branches/1.4.6/cdrskin/unite_html_b_line.c
create mode 100644 libburn/branches/1.4.6/cdrskin/wiki_plain.txt
create mode 100644 libburn/branches/1.4.6/configure.ac
create mode 100644 libburn/branches/1.4.6/doc/Makefile
create mode 100644 libburn/branches/1.4.6/doc/cdtext.txt
create mode 100644 libburn/branches/1.4.6/doc/comments
create mode 100644 libburn/branches/1.4.6/doc/cookbook.txt
create mode 100644 libburn/branches/1.4.6/doc/ddlp.txt
create mode 100644 libburn/branches/1.4.6/doc/doxygen.conf.in
create mode 100644 libburn/branches/1.4.6/doc/mediainfo.txt
create mode 100644 libburn/branches/1.4.6/libburn-1.pc.in
create mode 100644 libburn/branches/1.4.6/libburn/Makefile
create mode 100644 libburn/branches/1.4.6/libburn/Makefile.am
create mode 100644 libburn/branches/1.4.6/libburn/asserts.txt
create mode 100644 libburn/branches/1.4.6/libburn/async.c
create mode 100644 libburn/branches/1.4.6/libburn/async.h
create mode 100644 libburn/branches/1.4.6/libburn/back_hacks.h
create mode 100755 libburn/branches/1.4.6/libburn/cdtext.c
create mode 100644 libburn/branches/1.4.6/libburn/cleanup.c
create mode 100644 libburn/branches/1.4.6/libburn/cleanup.h
create mode 100644 libburn/branches/1.4.6/libburn/crc.c
create mode 100644 libburn/branches/1.4.6/libburn/crc.h
create mode 100644 libburn/branches/1.4.6/libburn/ddlpa.c
create mode 100644 libburn/branches/1.4.6/libburn/ddlpa.h
create mode 100644 libburn/branches/1.4.6/libburn/debug.c
create mode 100644 libburn/branches/1.4.6/libburn/debug.h
create mode 100644 libburn/branches/1.4.6/libburn/drive.c
create mode 100644 libburn/branches/1.4.6/libburn/drive.h
create mode 100644 libburn/branches/1.4.6/libburn/ecma130ab.c
create mode 100644 libburn/branches/1.4.6/libburn/ecma130ab.h
create mode 100644 libburn/branches/1.4.6/libburn/error.h
create mode 100644 libburn/branches/1.4.6/libburn/file.c
create mode 100644 libburn/branches/1.4.6/libburn/file.h
create mode 100644 libburn/branches/1.4.6/libburn/init.c
create mode 100644 libburn/branches/1.4.6/libburn/init.h
create mode 100644 libburn/branches/1.4.6/libburn/libburn.h
create mode 100644 libburn/branches/1.4.6/libburn/libburn.ver
create mode 100644 libburn/branches/1.4.6/libburn/libdax_audioxtr.c
create mode 100644 libburn/branches/1.4.6/libburn/libdax_audioxtr.h
create mode 100644 libburn/branches/1.4.6/libburn/libdax_msgs.c
create mode 100644 libburn/branches/1.4.6/libburn/libdax_msgs.h
create mode 100755 libburn/branches/1.4.6/libburn/libdax_msgs_to_xyz_msgs.sh
create mode 100644 libburn/branches/1.4.6/libburn/mmc.c
create mode 100644 libburn/branches/1.4.6/libburn/mmc.h
create mode 100644 libburn/branches/1.4.6/libburn/null.c
create mode 100644 libburn/branches/1.4.6/libburn/null.h
create mode 100644 libburn/branches/1.4.6/libburn/options.c
create mode 100644 libburn/branches/1.4.6/libburn/options.h
create mode 100644 libburn/branches/1.4.6/libburn/os-dummy.h
create mode 100644 libburn/branches/1.4.6/libburn/os-freebsd.h
create mode 100644 libburn/branches/1.4.6/libburn/os-libcdio.h
create mode 100644 libburn/branches/1.4.6/libburn/os-linux.h
create mode 100644 libburn/branches/1.4.6/libburn/os-netbsd.h
create mode 100644 libburn/branches/1.4.6/libburn/os-solaris.h
create mode 100644 libburn/branches/1.4.6/libburn/os.h
create mode 100644 libburn/branches/1.4.6/libburn/read.c
create mode 100644 libburn/branches/1.4.6/libburn/read.h
create mode 100644 libburn/branches/1.4.6/libburn/sbc.c
create mode 100644 libburn/branches/1.4.6/libburn/sbc.h
create mode 100644 libburn/branches/1.4.6/libburn/sector.c
create mode 100644 libburn/branches/1.4.6/libburn/sector.h
create mode 100644 libburn/branches/1.4.6/libburn/sg-dummy.c
create mode 100644 libburn/branches/1.4.6/libburn/sg-freebsd-port.c
create mode 100644 libburn/branches/1.4.6/libburn/sg-freebsd.c
create mode 100644 libburn/branches/1.4.6/libburn/sg-libcdio.c
create mode 100644 libburn/branches/1.4.6/libburn/sg-linux.c
create mode 100644 libburn/branches/1.4.6/libburn/sg-netbsd.c
create mode 100644 libburn/branches/1.4.6/libburn/sg-solaris.c
create mode 100644 libburn/branches/1.4.6/libburn/sg.c
create mode 100644 libburn/branches/1.4.6/libburn/sg.h
create mode 100644 libburn/branches/1.4.6/libburn/source.c
create mode 100644 libburn/branches/1.4.6/libburn/source.h
create mode 100644 libburn/branches/1.4.6/libburn/spc.c
create mode 100644 libburn/branches/1.4.6/libburn/spc.h
create mode 100644 libburn/branches/1.4.6/libburn/structure.c
create mode 100644 libburn/branches/1.4.6/libburn/structure.h
create mode 100644 libburn/branches/1.4.6/libburn/toc.c
create mode 100644 libburn/branches/1.4.6/libburn/toc.h
create mode 100644 libburn/branches/1.4.6/libburn/transport.h
create mode 100644 libburn/branches/1.4.6/libburn/util.c
create mode 100644 libburn/branches/1.4.6/libburn/util.h
create mode 100644 libburn/branches/1.4.6/libburn/write.c
create mode 100644 libburn/branches/1.4.6/libburn/write.h
create mode 100644 libburn/branches/1.4.6/libcevap/cgen.c
create mode 100644 libburn/branches/1.4.6/libcevap/cgen.h
create mode 100644 libburn/branches/1.4.6/libcevap/cgen.txt
create mode 100644 libburn/branches/1.4.6/libcevap/ctyp.c
create mode 100644 libburn/branches/1.4.6/libcevap/ctyp.h
create mode 100755 libburn/branches/1.4.6/libcevap/extract_cgen_input.sh
create mode 100755 libburn/branches/1.4.6/libcevap/libcevap_gen.sh
create mode 100644 libburn/branches/1.4.6/libcevap/libdax_equip.gif
create mode 100644 libburn/branches/1.4.6/libcevap/libdax_job.gif
create mode 100644 libburn/branches/1.4.6/libcevap/libdax_model.txt
create mode 100644 libburn/branches/1.4.6/libcevap/libdax_overview.gif
create mode 100644 libburn/branches/1.4.6/libcevap/main.c
create mode 100644 libburn/branches/1.4.6/libcevap/smem.c
create mode 100644 libburn/branches/1.4.6/libcevap/smem.h
create mode 100644 libburn/branches/1.4.6/test/Makefile
create mode 100644 libburn/branches/1.4.6/test/dewav.c
create mode 100644 libburn/branches/1.4.6/test/fake_au.c
create mode 100644 libburn/branches/1.4.6/test/libburner.c
create mode 100644 libburn/branches/1.4.6/test/offst_source.c
create mode 100644 libburn/branches/1.4.6/test/open-cd-excl.c
create mode 100644 libburn/branches/1.4.6/test/poll.c
create mode 100644 libburn/branches/1.4.6/test/telltoc.c
create mode 100644 libburn/branches/1.4.6/version.h.in
diff --git a/libburn/branches/1.4.6/AUTHORS b/libburn/branches/1.4.6/AUTHORS
new file mode 100644
index 00000000..6a964a5c
--- /dev/null
+++ b/libburn/branches/1.4.6/AUTHORS
@@ -0,0 +1,3 @@
+Mario Danic
+Thomas Schmitt
+
diff --git a/libburn/branches/1.4.6/CONTRIBUTORS b/libburn/branches/1.4.6/CONTRIBUTORS
new file mode 100644
index 00000000..31b77c58
--- /dev/null
+++ b/libburn/branches/1.4.6/CONTRIBUTORS
@@ -0,0 +1,6 @@
+Joe Neeman
+Philippe Rouquier
+Gabriel Craciunescu
+George Danchev
+Jean-Francois Wauthy
+Lorenzo Taylor
diff --git a/libburn/branches/1.4.6/COPYING b/libburn/branches/1.4.6/COPYING
new file mode 100644
index 00000000..5a965fbc
--- /dev/null
+++ b/libburn/branches/1.4.6/COPYING
@@ -0,0 +1,280 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/libburn/branches/1.4.6/COPYRIGHT b/libburn/branches/1.4.6/COPYRIGHT
new file mode 100644
index 00000000..8cd566da
--- /dev/null
+++ b/libburn/branches/1.4.6/COPYRIGHT
@@ -0,0 +1,18 @@
+Derek Foreman and Ben Jansens
+Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
+Mario Danic , Thomas Schmitt
+Copyright (C) 2006-2014 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 version 2 or later
+ 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
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
diff --git a/libburn/branches/1.4.6/ChangeLog b/libburn/branches/1.4.6/ChangeLog
new file mode 100644
index 00000000..d5b1355e
--- /dev/null
+++ b/libburn/branches/1.4.6/ChangeLog
@@ -0,0 +1,472 @@
+
+SVN trunk (to become libburn-1.4.6 or higher)
+===============================================================================
+- no novelties yet -
+
+libburn-1.4.4.tar.gz Fri Jul 01 2016
+===============================================================================
+* Bug fix: Option drive_scsi_dev_family=sg did not convert /dev/sr* to /dev/sg*
+* Bug fix: burn_make_input_sheet_v07t() falsly recognized double byte encoding.
+ Affected cdrskin option: cdtext_to_v07t=
+* Bug fix: Double free at end of run if burn_write_opts_set_leadin_text() is
+ used. Affected cdrskin option: textfile=
+* Bug fix: DVD book type of DVD+RW DL and DVD+R DL was reported wrong.
+ Thanks to Etienne Bergeron.
+
+libburn-1.4.2.pl01.tar.gz Fri Jan 29 2016
+===============================================================================
+* Bug fix: cdrskin "failed to attach fifo" when burning from stdin.
+ Regression of 1.4.2, rev 5522.
+
+libburn-1.4.2.tar.gz Sat Nov 28 2015
+===============================================================================
+* Bug fix: burn_disc_get_media_id() returned BD identifiers 2 chars too long
+* Bug fix: burn_disc_get_multi_caps() returned 2048 bytes too many in
+ caps.start_range_high
+* Bug fix: Media summary session count of blank and closed media was short by 1
+* Bug fix: Endless loop if transport error occurs while waiting for drive ready
+* New API calls burn_drive_get_serial_no() and burn_drive_get_media_sno()
+* Result of a Coverity audit: 40+ code changes, but no easy-to-trigger bugs
+
+libburn-1.4.0.tar.gz Sun May 17 2015
+===============================================================================
+* Bug fix: Double free with cdrskin -vvv.
+ Introduced with rev 5065, version 1.3.1
+* Bug fix: Wrong read access to memory. Reported by valgrind of lian jianfei.
+
+libburn-1.3.8.tar.gz Sat Jun 28 2014
+===============================================================================
+* Bug fix: Wrong stack usage caused SIGBUS on sparc when compiled by gcc -O2
+* Bug fix: Minimum drive buffer fill was measured by cdrskin before the buffer
+ could get full
+* Bug fix: A failed MMC BLANK command did not cause error indication by libburn
+* Bug fix: A final fsync(2) was performed with stdio drives, even if not
+ desired
+
+libburn-1.3.6.pl01.tar.gz Tue Mar 18 2013
+===============================================================================
+* Bug fix: CD TAO with multiple tracks could cause a buffer overrun
+* Bug fix: Compilation warning for unsupported systems mutated into an error
+
+libburn-1.3.6.tar.gz Tue Mar 04 2013
+===============================================================================
+* New system adapter for NetBSD
+
+libburn-1.3.4.tar.gz Thu Dec 12 2013
+===============================================================================
+* Bug fix: Drive error reports were ignored during blanking and formatting
+* Bug fix: Drive LG BH16NS40 stalls on inspection of unformatted DVD+RW
+* New API call burn_disc_pretend_full_uncond()
+
+libburn-1.3.2.tar.gz Wed Aug 07 2013
+===============================================================================
+* Bug fix: cdrskin -msinfo on DVD and BD reported
+ old session start = next writable address.
+ Regression introduced by version 1.2.8 (rev 4956).
+* Bug fix: The signal handler aborted on SIGCONT, SIGTSTP, SIGTTIN, SIGTTOU
+* New API call burn_make_input_sheet_v07t()
+* API call burn_session_input_sheet_v07t(): read multiple blocks from same file
+* New API calls burn_drive_extract_audio(), burn_drive_extract_audio_track()
+* New cdrskin option textfile_to_v07t=
+* New cdrskin options cdtext_to_textfile= and cdtext_to_v07t=
+* New cdrskin options extract_audio_to= , extract_tracks= , extract_basename= ,
+ --extract_dap
+* New cdrskin option --pacifier_with_newline
+* Improved granularity of SCSI log time measurement, now with timestamp
+* Optional "make doc" now demands doxygen 1.8.4
+
+libburn-1.3.0.pl01.tar.gz Fri May 31 2013
+===============================================================================
+* Bug fix: cdrskin -msinfo on DVD and BD reported
+ old session start = next writable address.
+ Regression introduced by version 1.2.8.
+
+libburn-1.3.0.tar.gz Fri May 17 2013
+===============================================================================
+* Bug fix: Full formatting of BD-RE used certification regardless of drive
+ capabilities
+* Bug fix: DVD+R with damaged TOC were reported by -minfo with wrong end
+ address
+
+libburn-1.2.8.tar.gz Mon Mar 18 2013
+===============================================================================
+* Bug fix: All CD tracks were reported with the sizes of the tracks in the
+ first session. Regression introduced with version 1.2.0 (rev 4552).
+* Bug fix: On some drives the request for minimum speed yielded maximum speed
+* New cdrskin option --list_speeds
+* -toc and -minfo now report about tracks in the incomplete session
+* New API call burn_disc_get_incomplete_sessions()
+* New burn_toc_entry component .track_status_bits
+
+libburn-1.2.6.tar.gz Tue Jan 08 2013
+===============================================================================
+* Bug fix: Speed setting had no effect on BD media
+* New cdrskin option --no_load
+* New API call burn_read_audio()
+* New API call burn_list_sev_texts()
+
+libburn-1.2.4.tar.gz Fri Jul 20 2012
+===============================================================================
+* Bug fix: CD SAO sessions with data tracks started by an audio pause
+* Bug fix: CD tracks were perceived 2 sectors too short.
+ Nice with TAO, bad with SAO.
+* Bug fix: cdrskin SIGSEGV if track source was added when no drive was available
+* New API call burn_write_opts_set_obs_pad(), ./configure --enable-dvd-obs-pad
+* New cdrskin option --obs_pad
+
+libburn-1.2.2.tar.gz Mon Apr 02 2012
+===============================================================================
+* Small internal refinements
+
+libburn-1.2.0.tar.gz Sat Jan 28 2012
+===============================================================================
+* Bug fix: cdrskin produced a memory fault if interupted before writing began
+* Bug fix: Solaris adapter mishandled write commands which failed on first try
+* Bug fix: Interrupting libburn while drive tray is loading led to endless loop
+* Bug fix: Progress report with blanking and formatting could be bogus
+* New API calls burn_disc_get_leadin_text(), burn_write_opts_set_leadin_text()
+* New API calls for composing CD-TEXT, see doc/cdtext.txt
+* New API call burn_session_by_cue_file() for reading CDRWIN .cue files
+* New API call burn_track_set_isrc_string()
+* New API calls burn_track_set_index(), burn_track_clear_indice()
+* New API calls burn_session_set_start_tno(), burn_session_get_start_tno()
+* New API calls burn_track_set_pregap_size(), burn_track_set_postgap_size()
+* Implemented cdrskin option textfile=
+* Implemented cdrskin option combination -vv -toc for cdtext.dat production
+* Implemented cdrskin options mcn= and isrc=
+* Implemented cdrskin options -scms -copy -nocopy -preemp -nopreemp
+* Implemented cdrskin option index=
+* Partly implemented cdrskin options cuefile= and -text
+* New cdrskin option input_sheet_v07t= for CD-TEXT definition
+* New cdrskin options --cdtext_dummy and --cdtext_verbose
+* New cdrskin options --four_channel --two_channel
+* New cdrskin option cd_start_tno=
+* New cdrskin options sao_pregap=, sao_postgap=
+
+libburn-1.1.8.tar.gz Mon Nov 21 2011
+===============================================================================
+* Bug fix: Misinterpreted mode page 2A if block descriptors are present
+* Enabled recognition of QEMU DVD-ROM 0.12
+* Avoiding to intermediately close and open drive device file
+* New API call burn_drive_re_assess()
+
+libburn-1.1.6.tar.gz Tue Sep 27 2011
+===============================================================================
+* Bug fix: stdio sizes > 4 TB - 32 kB caused integer rollover
+* Worked around a collision with Linux udev which lets links vanish
+
+libburn-1.1.4.tar.gz Sun Aug 07 2011
+===============================================================================
+* Bug fix: Some drives return -150 as NWA of blank CD, rather than 0.
+ libburn forwarded this misleading information to the application.
+* Bug fix: Some drives returned wrong CD sizes after having burned DVD-R
+* Bug fix: Empty ROM drive was mistaken to hold an unsuitable disc
+* Bug fix: Avoiding to load speed descriptor list twice
+* New API call burn_lookup_device_link()
+* New API call burn_disc_get_phys_format_info()
+* New cdrskin option --device_links
+
+Release 1.1.2 was skipped to get back in sync with libisoburn.
+
+libburn-1.1.0.pl01.tar.gz Mon Jun 20 2011
+===============================================================================
+* Bug fix: libburn-1.1.0 compiled only on Linux, FreeBSD, and Solaris
+
+libburn-1.1.0.tar.gz Sat Jun 18 2011
+===============================================================================
+* Bug fix: burn_disc_format() on DVD-RW issued wrong block size with type 00h
+* New API call burn_disc_next_track_is_damaged()
+* New API call burn_disc_close_damaged()
+* Dropped suffix .plXY from tarball name
+
+Release 1.0.8 was skipped to get back in sync with libisofs and libisoburn.
+
+libburn-1.0.6.pl00.tar.gz Sat Apr 9 2011
+===============================================================================
+* Burning DVD-R DAO with 2 kB size granularity rather than 32 kB
+* New API call burn_allow_drive_role_4()
+
+libburn-1.0.4.pl00.tar.gz Thu Mar 3 2011
+===============================================================================
+* Bug fix: Read-only file descriptors were classified as write-only pseudo
+ drives
+
+libburn-1.0.2.pl00.tar.gz Wed Feb 23 2011
+===============================================================================
+* Removed compilation obstacles on Solaris 9.
+* Improved recognition of non-seekable stdio pseudo-drives.
+
+libburn-1.0.0.pl00.tar.gz Sun Jan 16 2011
+===============================================================================
+* Allowed umask to create stdio-drive files with rw-permissions for all
+* cdrskin now refuses to burn if the foreseeable size exceeds media capacity
+
+libburn-0.9.0.pl00.tar.gz Wed Dec 08 2010
+===============================================================================
+* Regression fix: SCSI reply data logging was disabled in release 0.8.6
+
+libburn-0.8.8.pl00.tar.gz Wed Oct 20 2010
+===============================================================================
+* New API call burn_offst_source_new()
+* New API call burn_disc_get_bd_spare_info()
+
+libburn-0.8.6.pl00.tar.gz Fri Sep 17 2010
+===============================================================================
+* Lifted test reservation on DVD-R DL media.
+* Hiding all non-API symbols from the linker by use of --version-script
+* Now with history of release notes in ./ChangeLog file.
+
+libburn-0.8.4.pl00.tar.gz Wed Jun 30 2010
+===============================================================================
+* General POSIX system adapters ignore SIGWINCH and SIGURG if defined
+* Allowed 64 kB max output buffer size on all OSes
+
+libburn-0.8.2.pl00.tar.gz Fri Jun 11 2010
+===============================================================================
+* New system adapter for Solaris uscsi (tested on snv134, kernel 5.11)
+* Bug fix: CD TOC was not read if the first track did not start at LBA 0
+* Bug fix: CD-ROM media got attributed random lead-in and lead-out adresses
+* Bug fix: SIGSEGV of experimental libcdio system adapter if drive list is
+ empty
+
+libburn-0.8.0.pl00.tar.gz Fri Apr 09 2010
+===============================================================================
+* libburn now works with ahci driver on FreeBSD 8-STABLE.
+
+libburn-0.7.8.pl00.tar.gz Wed Mar 10 2010
+===============================================================================
+* Bug fix: On FreeBSD, piped input was falsely attributed a small fixed size.
+* Built-in abort handling is more suitable for FreeBSD now.
+cdrskin novelties:
+* Bug fix: Option fs=0 led to SIGSEGV. Regression introduced by version 0.7.4
+ in december 2009.
+* Abort handling is more suitable for FreeBSD now.
+
+libburn-0.7.6.pl00.tar.gz Sat Jan 23 2010
+===============================================================================
+* Bug fix: System adapter for generic X/Open was missing in libburn release
+ tarball
+* Bug fix: with non-Linux adapters there were 0 readable bytes on block devices
+* Made FreeBSD system adapter safe from mutal burn spoiling and drive deadlock
+* Enabled FreeBSD system adapter for Debian kfreebsd
+* Experimental SCSI transport adapter via GNU libcdio 0.83git
+cdrskin novelties:
+* none
+
+libburn-0.7.4.pl01.tar.gz Sat Dec 26 2009
+===============================================================================
+* Bug fix: Added missing system adapter for generic X/Open to libburn release
+ tarball
+
+Libburn 0.7.4.pl00 Mon Dec 07 2009
+===============================================================================
+* Bug fix: SIGSEGV from NULL pointer with media product id inquiry on LG
+ GH22LS30
+* Bug fix: DVD DAO track size was rounded up much too generously
+* Workaround for Pioneer DVR-216D which got stuck on DVD-R burns.
+ (already fixed in 0.7.2.pl01)
+* Workaround for Pioneer DVR-216D refusal to eject.
+ (already fixed in 0.7.2.pl01)
+* Configure options --enable-dvd-obs-64k, --enable-track-src-odirect
+* New API calls burn_write_opts_set_dvd_obs(),
+ burn_write_opts_set_stdio_fsync()
+* New API call burn_set_scsi_logging()
+* New API calls burn_fifo_get_statistics(), burn_fifo_next_interval(),
+ burn_fifo_fill()
+* Re-implemented ECMA-130 P-parity, Q-parity and scrambling for BURN_WRITE_RAW
+cdrskin novelties:
+* cdrskin option -V for logging of SCSI commands
+* New cdrskin options dvd_obs= and stdio_fsync=
+* New compile_cdrskin.sh option -dvd_obs_64k
+
+libburn-0.7.2.pl01.tar.gz Fri Nov 13 2009
+===============================================================================
+* Workaround for Pioneer DVR-216D which got stuck on DVD-R burns.
+* Workaround for Pioneer DVR-216D refusal to eject.
+
+Libburn 0.7.2.pl00 Mon Oct 12 2009
+===============================================================================
+* Bug fix: CD TAO sessions with multiple tracks did not work in -dummy mode
+* New API calls burn_get_media_product_id() , burn_guess_manufacturer() ,
+ burn_guess_cd_manufacturer()
+* New API call burn_disc_get_cd_info()
+* New API call burn_track_set_cdxa_conv()
+cdrskin novelties:
+* Better interpretation of options -mode2, -xa, -xa1, -xa2
+* New option --xa1-ignore
+* New -atip report lines "Product Id:" and "Producer:"
+
+libburn-0.7.0.pl00.tar.gz Thu Aug 27 2009
+===============================================================================
+* New API calls burn_drive_get_all_profiles(), burn_obtain_profile_name() allow
+ to inquire and process the list of supported media types. cdrskin lists all
+ supported profiles with option -atip -v
+* New API call burn_drive_snooze() allows to calm down a drive when no i/o is
+ expected for a while.
+* Bug fix: Some SCSI commands stalled on U3 memory sticks which appear as a hub
+ with a memory stick and a CD-ROM drive containing a small CD. These commands
+ make not much sense with a CD-ROM and are now avoided for this media
+ situation.
+
+libburn-0.6.8.pl00.tar.gz Tue Jul 14 2009
+===============================================================================
+* Bug fix: Old MMC-1 drives were rejected because of mode page 2Ah length.
+* cdrskin -scanbus now works with high SCSI bus numbers.
+
+libburn-0.6.6.pl00.tar.gz Fri May 8 2009
+===============================================================================
+* Bug fix: Improper abort handling with broken pipe during outputto a stdio:
+ pseudo-drive.
+* Bug fix: Device scan stalled on FreeBSD with non-burner USB device
+
+libburn-0.6.4.pl00.tar.gz Fri Mar 13 2009
+===============================================================================
+* New operating system adapter "dummy" for stdio on general X/Open systems
+* New API function burn_drive_set_stream_recording() allows to write the
+ crucial start blocks of a filesystem with slow BD-RE Defect Management and to
+ write the bulk of data with full nominal speed.
+
+libburn-0.6.2.pl00.tar.gz Fri Feb 20 2009
+===============================================================================
+* Improvements with build system for FreeBSD
+
+libburn-0.6.0.pl01.tar.gz Wed Jan 07 2009
+===============================================================================
+* Bug fix: BD-R were not correctly finalized
+
+libburn-0.6.0.pl00.tar.gz Sun Jan 04 2009
+===============================================================================
+* Formatting and writing of BD-R media
+* New API function burn_get_read_capacity()
+
+libburn-0.5.8.pl00.tar.gz Mon Dec 08 2008
+===============================================================================
+* Bug fix: A session without leadout entry on CD caused a SIGSEGV by NULL
+* Improvements about BD-RE formatting
+
+libburn-0.5.6.pl00.tar.gz Wed Nov 12 2008
+===============================================================================
+* Bug fix: libburn fifo thread was not aborted when burn run was aborted which
+ could lead to use of freed memory.
+
+libburn-0.5.4.pl00.tar.gz Mon Oct 6 2008
+===============================================================================
+* Bug fix: On Linux 2.4 /dev/sr0 was accepted as enumerable address but then
+ failed to work.
+
+libburn-0.5.2.pl00.tar.gz Wed Aug 20 2008
+===============================================================================
+* Larger set of possibly acceptable drive device file names
+
+libburn-0.5.0.pl00.tar.gz Thu Jul 17 2008
+===============================================================================
+* Bug fix: cdrskin option drive_scsi_dev_family=scd lead to buffer overflow
+* Ability to use /dev/scd as fallback if /dev/sr does not exist
+* New API call burn_fifo_peek_data()
+
+libburn-0.4.8.pl00.tar.gz Sat May 17 2008
+===============================================================================
+* Bug fix: Random access addressing for DVD-RAM and BD-RE did not work.
+* cdrskin: Affected were options write_start_address= and
+ -- grow_overwriteable_iso on DVD-RAM or BD-RE.
+* xorriso: Affected were sessions on DVD-RAM or BD-RE after the first one.
+
+libburn-0.4.6.pl00.tar.gz Sun May 11 2008
+===============================================================================
+* Support for BD-RE media is now official
+* New burn_write_opts_set_stream_recording() can speed up DVD-RAM and BD-RE
+* New cdrskin option --list_formats
+* New cdrskin blank types for expert formatting of DVD-RAM and BD-RE
+* New cdrskin blank type blank=as_needed for automatic handling of media
+
+libburn-0.4.4.tar.gz Thu April 10 2008
+===============================================================================
+* Support for DVD+R/DL media is now official
+
+libburn-0.4.2.tar.gz Sun Feb 3 2008
+===============================================================================
+* Long term commitment to ABI libburn.so.4.
+* ABI compatibility is guaranteed for any older feature set released since
+ libburn-0.3.2 about one year ago.
+* libburn provides means for compile time and runtime checking of its version.
+* Compile time check in cdrskin for proper version of libburn include file.
+ Required is at least 0.4.2.
+* Runtime check in cdrskin prevents dynamic linking with outdated version of
+ libburn.so.4. Required is at least the version seen in the include file at
+ compile time.
+
+libburn-0.4.0.tar.gz Mon Oct 29 2007
+===============================================================================
+* New option direct_write_amount=
+* New option --grow_overwriteable_iso
+* New option --allow_emulated_drives dev=stdio:
+* More cdrecord options supported: -format, -inq, -load, -lock, -immed, -waiti
+* New option fallback_program=
+* A lot of libburn API additions.
+
+libburn-0.3.8.tar.gz Tue Jul 31 2007
+===============================================================================
+* Now able to cope with the peculiarities of Linux 2.4 USB
+* Refusal to perform -dummy runs on media which cannot simulate burning
+* New option modesty_on_drive= may help with hda -> hdb burns
+* New option minbuf= , cdrecord compatible frontend of modesty_on_drive=
+* New option --adjust_speed_to_drive
+* Precautions against using the burner drive as track source
+* Note: ABI has not been broken.
+
+libburn-0.3.6.tar.gz Thu Apr 26 2007
+===============================================================================
+* On Linux kernel 2.6, /dev/sr* gets used rather than /dev/sg*.
+* DVD+R now get finalized (if not -multi is given)
+
+libburn-0.3.4.tar.gz Mon Mar 12 2007
+===============================================================================
+* Multi-session recording on DVD+R, including -toc, -msinfo
+* Options --tell_media_space , assert_write_lba=
+* Bug fix of rare multi track fifo stall
+
+libburn-0.3.2.tar.gz Feb 11 2007
+===============================================================================
+* Burnfree enabled by default
+* Multi-session recording on sequential DVD-R[W], including -toc, -msinfo
+* DVD-R[W] Disk-at-once recording
+
+libburn-0.3.0.1.tar.gz Tue Jan 30 2007
+===============================================================================
+* Improved recognition of unsuitable media types
+* Replaced ban of chmod u+s by loud warning
+* detailed man page for cdrskin
+* Burning of DVD+RW and DVD-RAM media as single-track TAO-like initial session
+* Formatting and then burning to DVD-RW like to DVD+RW
+* New option -msifile=path from cdrkit/wodim
+* 0.3.0.1 release notes *
+* Bug fix enabling tracks >= 1.3 GB from disk file
+
+libburn-0.2.6.3.tar.gz Fri Dec 29 2006
+===============================================================================
+* 0.2.6 release notes (Wed Nov 22 2006)
+* After a lot of time with dedication to this project, we proudly present you
+ libburn 0.2.6. It is the first version of cdrskin and libburn after they have
+ been split from genisofs and libisofs. Main new features are write mode TAO
+ and support for multi session.
+* 0.2.6.1 release notes (Fri Nov 24 2006)
+* Point release to fix misleading version numbers in messages and documentation
+* 0.2.6.2 release notes (Sat Dec 16 2006)
+* cdrskin man page backported from development version 0.2.7.
+* 0.2.6.3 release notes (Fri Dec 29 2006)
+* Point release to fix build system problems people have experienced with the
+ past release.
+
+libburn-0.2.3.snapshot02.tar.gz Thu Nov 02 2006
+===============================================================================
+* Stabilized snapshot including release 0.2.4.pl01 of cdrskin
+* cdrskin 0.2.4 release notes
+* Compatibility with cdrecord has been improved in respect to drive addresses,
+ audio extraction from .wav, -scanbus, -toc, drive buffer fill indicator.
+* Note: The previous snapshot01 with the same source base is handicapped by a
+ broken ./configure setup. It works well on Intel compatible CPUs but is
+ supposed to be unusable on big-endian architectures.
+
+libburn-0.2.2.tar.gz Wed Sep 20 2006
+===============================================================================
+Initial release of libburnia's libburn combined with cdrskin.
diff --git a/libburn/branches/1.4.6/INSTALL b/libburn/branches/1.4.6/INSTALL
new file mode 100644
index 00000000..5458714e
--- /dev/null
+++ b/libburn/branches/1.4.6/INSTALL
@@ -0,0 +1,234 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006 Free Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/libburn/branches/1.4.6/Makefile.am b/libburn/branches/1.4.6/Makefile.am
new file mode 100644
index 00000000..069fdf93
--- /dev/null
+++ b/libburn/branches/1.4.6/Makefile.am
@@ -0,0 +1,235 @@
+
+# ts A90315 : LIBBURNIA_PKGCONFDIR is defined OS specific in acinclude.m4
+# was: pkgconfigdir=$(libdir)/pkgconfig
+pkgconfigdir=$(LIBBURNIA_PKGCONFDIR)
+
+libincludedir=$(includedir)/libburn
+
+lib_LTLIBRARIES = libburn/libburn.la
+ACLOCAL_AMFLAGS = -I ./
+
+## ========================================================================= ##
+
+# Build libraries
+libburn_libburn_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) $(LIBLDFLAGS)
+# This causes undesired .o names
+# configure.ac appends -D options to variable CFLAG
+### libburn_libburn_la_CFLAGS = $(LIBBURN_DVD_OBS_64K)
+libburn_libburn_la_LIBADD = $(LIBBURN_ARCH_LIBS) $(THREAD_LIBS)
+libburn_libburn_la_SOURCES = \
+ libburn/async.c \
+ libburn/async.h \
+ libburn/back_hacks.h \
+ libburn/cdtext.c \
+ libburn/cleanup.c \
+ libburn/cleanup.h \
+ libburn/crc.c \
+ libburn/crc.h \
+ libburn/debug.c \
+ libburn/debug.h \
+ libburn/drive.c \
+ libburn/drive.h \
+ libburn/ecma130ab.c \
+ libburn/ecma130ab.h \
+ libburn/error.h \
+ libburn/file.c \
+ libburn/file.h \
+ libburn/init.c \
+ libburn/init.h \
+ libburn/libburn.h \
+ libburn/libdax_audioxtr.h \
+ libburn/libdax_audioxtr.c \
+ libburn/libdax_msgs.h \
+ libburn/libdax_msgs.c \
+ libburn/mmc.c \
+ libburn/mmc.h \
+ libburn/null.c \
+ libburn/null.h \
+ libburn/options.c \
+ libburn/options.h \
+ libburn/os.h \
+ libburn/read.c \
+ libburn/read.h \
+ libburn/sbc.c \
+ libburn/sbc.h \
+ libburn/sector.c \
+ libburn/sector.h \
+ libburn/sg.c \
+ libburn/sg.h \
+ libburn/source.h \
+ libburn/source.c \
+ libburn/spc.c \
+ libburn/spc.h \
+ libburn/structure.c \
+ libburn/structure.h \
+ libburn/toc.c \
+ libburn/toc.h \
+ libburn/transport.h \
+ libburn/util.c \
+ libburn/util.h \
+ libburn/write.c \
+ libburn/write.h
+
+## libburn/sg-@ARCH@.c \
+
+libinclude_HEADERS = \
+ libburn/libburn.h
+
+install-exec-hook:
+ $(LIBBURNIA_LDCONFIG_CMD) "$(DESTDIR)$(libdir)" || echo 'NOTE: Explicit dynamic library configuration failed. If needed, configure manually for:' "$(DESTDIR)$(libdir)"
+
+## ========================================================================= ##
+
+## Build test applications
+noinst_PROGRAMS = \
+ test/libburner \
+ test/offst_source \
+ test/telltoc \
+ test/dewav \
+ test/fake_au \
+ test/poll
+
+bin_PROGRAMS = \
+ cdrskin/cdrskin
+
+LIBBURN_EXTRALIBS = $(LIBBURN_ARCH_LIBS) $(THREAD_LIBS)
+
+test_libburner_CPPFLAGS = -Ilibburn
+test_libburner_LDADD = $(libburn_libburn_la_OBJECTS) $(LIBBURN_EXTRALIBS)
+test_libburner_SOURCES = test/libburner.c
+test_offst_source_CPPFLAGS = -Ilibburn
+test_offst_source_LDADD = $(libburn_libburn_la_OBJECTS) $(LIBBURN_EXTRALIBS)
+test_offst_source_SOURCES = test/offst_source.c
+test_telltoc_CPPFLAGS = -Ilibburn
+test_telltoc_LDADD = $(libburn_libburn_la_OBJECTS) $(LIBBURN_EXTRALIBS)
+test_telltoc_SOURCES = test/telltoc.c
+test_dewav_CPPFLAGS = -Ilibburn
+test_dewav_LDADD = $(libburn_libburn_la_OBJECTS) $(LIBBURN_EXTRALIBS)
+test_dewav_SOURCES = test/dewav.c
+test_fake_au_CPPFLAGS =
+test_fake_au_LDADD =
+test_fake_au_SOURCES = test/fake_au.c
+test_poll_CPPFLAGS = -Ilibburn
+test_poll_LDADD = $(libburn_libburn_la_OBJECTS) $(LIBBURN_EXTRALIBS)
+test_poll_SOURCES = test/poll.c
+
+## cdrskin construction site - ts A60816 - B60701
+cdrskin_cdrskin_CPPFLAGS = -Ilibburn
+cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_1_4_5
+
+# cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(LIBBURN_EXTRALIBS)
+# ts A80123, change proposed by Simon Huggins to cause dynamic libburn linking
+cdrskin_cdrskin_LDADD = libburn/libburn.la $(LIBBURN_EXTRALIBS)
+
+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"
+##
+
+# "make clean" shall remove a few stubborn .libs directories
+# which George Danchev reported Dec 03 2011.
+# Learned from: http://www.gnu.org/software/automake/manual/automake.html#Clean
+clean-local:
+ -rm -rf cdrskin/.libs test/.libs
+
+
+## ========================================================================= ##
+
+## Build documentation (You need Doxygen for this to work)
+webhost = http://libburn-api.pykix.org
+webpath = /
+docdir = $(DESTDIR)$(prefix)/share/doc/$(PACKAGE)-$(VERSION)
+
+doc: doc/html
+
+doc/html: doc/doxygen.conf
+ if [ -f ./doc/doc.lock ]; then \
+ $(RM) -r doc/html; \
+ doxygen doc/doxygen.conf; \
+ fi
+
+doc-upload: doc/html
+ scp -r $* $(webhost):$(webpath)
+
+## ts B00729
+## Not by default any more.
+## It is unclear who is supposed to create file ./doc/doc.lock
+# all: doc
+
+install-data-local:
+ if [ -f ./doc/doc.lock ]; then \
+ $(mkinstalldirs) $(docdir)/html; \
+ $(INSTALL_DATA) doc/html/* $(docdir)/html; \
+ fi
+
+uninstall-local:
+ rm -rf $(docdir)
+
+## ========================================================================= ##
+
+# Indent source files
+indent_files = \
+ $(libburn_libburn_la_SOURCES) \
+ $(test_poll_SOURCES)
+
+
+indent: $(indent_files)
+ indent -bad -bap -nbbb -nbbo -nbc -bli0 -br -bls \
+ -cdw -ce -cli0 -ncs -nbfda -i8 -l79 -lc79 \
+ -lp -saf -sai -nprs -npsl -saw -sob -ss -ut \
+ -sbi0 -nsc -ts8 -npcs -ncdb -fca \
+ $^
+
+.PHONY: indent
+
+## ========================================================================= ##
+
+# Extra things
+nodist_pkgconfig_DATA = \
+ libburn-1.pc
+
+# http://www.nada.kth.se/cgi-bin/info?(automake.info)Man%20pages
+man_MANS = cdrskin/cdrskin.1
+
+EXTRA_DIST = \
+ bootstrap \
+ libburn-1.pc.in \
+ version.h.in \
+ doc/comments \
+ doc/doxygen.conf.in \
+ doc/cookbook.txt \
+ doc/mediainfo.txt \
+ doc/cdtext.txt \
+ README \
+ AUTHORS \
+ CONTRIBUTORS \
+ COPYRIGHT \
+ cdrskin/README \
+ cdrskin/cdrecord_spy.sh \
+ cdrskin/compile_cdrskin.sh \
+ cdrskin/convert_man_to_html.sh \
+ cdrskin/changelog.txt \
+ cdrskin/cdrskin_eng.html \
+ cdrskin/wiki_plain.txt \
+ cdrskin/cleanup.h \
+ cdrskin/cleanup.c \
+ libburn/libburn.ver \
+ libburn/os-dummy.h \
+ libburn/os-freebsd.h \
+ libburn/os-linux.h \
+ libburn/os-libcdio.h \
+ libburn/os-solaris.h \
+ libburn/os-netbsd.h \
+ libburn/sg-dummy.c \
+ libburn/sg-freebsd.c \
+ libburn/sg-linux.c \
+ libburn/sg-libcdio.c \
+ libburn/sg-solaris.c \
+ libburn/sg-netbsd.c \
+ COPYING \
+ NEWS \
+ ChangeLog \
+ INSTALL \
+ $(man_MANS)
+
diff --git a/libburn/branches/1.4.6/NEWS b/libburn/branches/1.4.6/NEWS
new file mode 100644
index 00000000..7001d0f2
--- /dev/null
+++ b/libburn/branches/1.4.6/NEWS
@@ -0,0 +1 @@
+nothing here now
diff --git a/libburn/branches/1.4.6/README b/libburn/branches/1.4.6/README
new file mode 100644
index 00000000..56f85c9b
--- /dev/null
+++ b/libburn/branches/1.4.6/README
@@ -0,0 +1,815 @@
+------------------------------------------------------------------------------
+ libburnia-project.org
+------------------------------------------------------------------------------
+This all is under GPL.
+(See GPL reference, our clarification and commitment at the end of this text)
+------------------------------------------------------------------------------
+libburnia-project.org
+By Mario Danic and Thomas Schmitt
+Copyright (C) 2006-2016 Mario Danic, Thomas Schmitt
+Still containing parts of Libburn. By Derek Foreman
+and Ben Jansens
+Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
+
+ http://files.libburnia-project.org/releases/libburn-1.4.4.tar.gz
+
+------------------------------------------------------------------------------
+
+ Build and Installation
+
+ From tarball
+
+Obtain libburn-1.4.4.tar.gz, take it to a directory of your choice and do:
+
+ tar xzf libburn-1.4.4.tar.gz
+ cd libburn-1.4.4
+ ./configure --prefix=/usr
+ make
+
+To make libburn accessible for running and application development,
+and to install the cdrecord compatibility binary cdrskin, do
+(as Superuser):
+
+ make install
+
+This procedure installs libburn.so.4 and cdrskin depending on it.
+For a standalone cdrskin binary, see cdrskin/README.
+
+A behavioral conflict is known between any burn software and demons like hald
+which probe CD drives. This can spoil burn runs for CD-R or CD-RW.
+You may have to keep your hald away from the drive. See for example
+ http://www.freebsd.org/gnome/docs/halfaq.html
+
+
+ From SVN
+
+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.
+Do in a directory of your choice:
+
+ svn co http://svn.libburnia-project.org/libburn/trunk libburn-svn
+ cd libburn-svn
+ ./bootstrap
+ ./configure --prefix=/usr
+ make
+ make install
+
+Warning: The trunk might contain experimental features which might not
+ persist until next release.
+
+
+ Special ./configure options
+
+make install on GNU/Linux will try to run program ldconfig with the library
+installation directory as only argument. Failure to do so will not abort
+installation. One may disable ldconfig by ./configure option:
+ --disable-ldconfig-at-install
+
+In some situations Linux may deliver a better write performance to drives if
+the track input is read with O_DIRECT (see man 2 open). The API call
+burn_os_open_track_src() and the input readers of cdrskin and libburn fifo
+can be told to use this peculiar read mode by:
+ --enable-track-src-odirect
+
+But often libburn call burn_write_opts_set_dvd_obs(opts, 64*1024) will yield
+even better performance in such a situation. 64k can be made default at
+configure time by:
+ --enable-dvd-obs-64k
+This may be combined with above --enable-track-src-odirect .
+
+If it is desired that DVD DAO writing and stdio: writing get padded up to
+a full write chunk of 32k or 64k, then use ./configure option:
+ --enable-dvd-obs-pad
+
+Alternatively the transport of SCSI commands can be done via libcdio-0.83.
+You may install it and re-run libburn's ./configure with option
+ --enable-libcdio
+
+By use of a version script, the libburn.so library exposes no other function
+names but those of the API definition in libburn/libburn.h.
+If -Wl,--version-script=... makes problems with the local compiler, then
+disable this encapsulation feature by
+ --disable-versioned-libs
+
+Make sure to re-compile all source files after running ./configure
+ make clean ; make
+ make install
+
+
+Linux only:
+
+libburn tries to avoid a collision with udev's drive examination by waiting
+0.1 seconds before opening the device file for a longer time, after udev
+might have been alarmed by drive scanning activities.
+The waiting time can be set at ./configure time with microsecond granularity.
+E.g. 2 seconds:
+ CFLAGS="$CFLAGS -DLibburn_udev_wait_useC=2000000"
+ ./configure ...options...
+Waiting can be disabled by zero waiting time:
+ CFLAGS="$CFLAGS -DLibburn_udev_wait_useC=0"
+Alternatively, libburn can try to be nice by opening the device file,
+closing it immediately, waiting, and only then opening it for real:
+ CFLAGS="$CFLAGS -DLibburn_udev_extra_open_cyclE -DLibburn_udev_wait_useC=500000"
+
+------------------------------------------------------------------------------
+
+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-project.org
+
+libburnia-project.org is an open-source software project for reading, mastering
+and writing optical discs.
+For now this means CD media, all DVD media, all BD media.
+
+The project comprises of several more or less interdependent parts which
+together strive to be a usable foundation for application development.
+These are libraries, language bindings, and middleware binaries which emulate
+classical (and valuable) Linux tools.
+Currently it is supported on GNU/Linux with kernels >= 2.4,
+on FreeBSD with ATAPI/CAM enabled in the kernel (see man atapicam),
+on OpenSolaris (tested with kernel 5.11),
+on NetBSD (tested with 6.1.3).
+On other X/Open compliant systems there will only be pseudo drives, but no
+direct MMC operation on real CD/DVD/BD drives.
+
+For full ports to other systems we would need : login on a development machine
+or 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 well tested code base for burning data and audio CDs, DVDs and BDs.
+The burn API is quite comprehensively documented and can be used to build a
+presentable application.
+We have a functional application 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/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 CD via libburn.
+ An own ISO 9660 extension stores ACLs, xattr, and MD5 of file
+ content.
+
+- libisoburn is an add-on to libburn and libisofs which coordinates both and
+ also can 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.
+ It also contains the methods of command oriented application
+ xorriso and offers them via a C language API.
+
+- 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.
+ 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 deleting, renaming, attribute
+ changing, incremental backups, activating boot images, and
+ extracting of files from ISO images to disk. There is also a
+ sparse emulation of cdrecord and a more laborate one of mkisofs.
+ All features of xorriso are also available via a C language API
+ of libisoburn.
+ A static compilation of xorriso and the libraries is dedicated
+ to the GNU Operating System. See xorriso/README_gnu_xorriso .
+
+- "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 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).
+
+Applications must use 64 bit off_t. E.g. by defining
+#define _LARGEFILE_SOURCE
+#define _FILE_OFFSET_BITS 64
+or take special precautions to interface with the libraries by 64 bit integers
+where the .h files prescribe off_t. To reduce libburn's off_t size to 32 bit
+will keep it from processing tracks of more than 2 GB size.
+
+
+------------------------------------------------------------------------------
+Project history as far as known to me:
+
+- Founded in 2002 as it seems. See mailing list archives
+ http://lists.freedesktop.org/archives/libburn/
+ The site of this founder team is reachable and offers download of a
+ (somewhat outdated) tarball and from CVS :
+ http://icculus.org/burn/
+ Copyright holders and most probably founders:
+ Derek Foreman and Ben Jansens.
+
+- I came to using libburn in 2005. Founded the cdrskin project and submitted
+ necessary patches which were accepted or implemented better. Except one
+ remaining patch which prevented cdrskin from using vanilla libburn from CVS.
+ The cdrskin project site is reachable and offers download of the heavily
+ patched (elsewise outdated) tarball under the name cdrskin-0.1.2 :
+ http://scdbackup.sourceforge.net/cdrskin_eng.html
+ It has meanwhile moved to use vanilla libburn.pykix.org , though.
+ Version 0.1.4 constitutes the first release of this kind.
+
+- 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 publicly 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 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
+
+- Mid August 2006 project cdrskin established a branch office in
+ libburn.pykix.org so that all maintainers of our tools have one single place
+ to get the current (at least slightely) usable coordinated versions of
+ everything.
+ Project cdrskin will live forth independendly for a while but it is committed
+ to stay in sync with libburn.pykix.org (or some successor, if ever).
+ cdrskin is also committed to support icculus.org/burn if the pending fork
+ is made reality by content changes in that project. It will cease to maintain
+ a patched version of icculus.org/burn though. Precondition for a new
+ release of cdrskin on base of icculus.org/burn would be the pending
+ "whitelist patch" therefore.
+ I would rather prefer if both projects find consense and merge, or at least
+ cooperate. I have not given up hope totally, yet.
+ I, personally, will honor any approach.
+
+- 2nd September 2006 the decision is made to strive for a consolidation of
+ copyright and a commitment to GPL in a reasonable and open minded way.
+ This is to avoid long term problems with code of unknown origin and
+ with finding consense among the not so clearly defined group of copyright
+ claimers and -holders.
+ libisofs is already claimed sole copyright Mario Danic.
+ cdrskin and libburner are already claimed sole copyright Thomas Schmitt.
+ Rewrites of other components will follow and concluded by claiming full
+ copyright within the group of libburn.pykix.org-copyright holders.
+
+- 16th September 2006 feature freeze for release of libburn-0.2.2 .
+
+- 20th September 2006 release of libburn-0.2.2 .
+
+- 26th October 2006 feature freeze for cdrskin-0.2.4 based on libburn-0.2.3 .
+ This version of cdrskin is much more cdrecord compatible in repect
+ to drive addressing and audio features.
+
+- 30th October 2006 release of cdrskin-0.2.4 .
+
+- 13th November 2006 splitting releases of libburn+cdrskin from libisofs.
+
+- 24th November 2006 release of libburn-0.2.6 and cdrskin-0.2.6 . cdrskin has
+ become suitable for unaware frontends as long as they perform only the core
+ of cdrecord use cases (including open-ended input streams, audio, and
+ multi-session).
+
+- 28th November 2006 the umbrella project which encloses both, libisofs and
+ libburn, is now called libburnia. For the origin of this name, see
+ http://en.wikipedia.org/wiki/Liburnians .
+
+- 16th January 2007 release of libburn-0.3.0 and cdrskin-0.3.0 . Now the scope
+ is widened to a first class of DVD media: overwriteable single layer types
+ DVD-RAM, DVD+RW, DVD-RW. This is not a cdrecord emulation but rather inspired
+ by dvd+rw-tools' "poor man" writing facility for this class of media.
+ Taking a bow towards Andy Polyakov.
+
+- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
+ multi-session and with DAO.
+
+- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
+ DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
+ yet.
+
+- 23th April 2007 version 0.3.6 follows the unanimous opinion of Linux kernel
+ people that one should not use /dev/sg on kernel 2.6.
+
+- 31st July 2007 version 0.3.8 marks the first anniversary of libburn revival.
+ We look back on improved stability, a substantially extended list of media
+ and write modes, and better protection against typical user mishaps.
+
+- 24th October 2007 version 0.4.0 is the foundation of new library libisoburn
+ and an upcoming 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 enable 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 cdrecord 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. So libisoburn can now perform 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 addressable. Enumeration is enhanced by examining
+ /proc/sys/dev/cdrom/info.
+
+- 24th Aug 2008 libisoburn/xorriso-0.2.4 introduces a media readability check
+ with data retrieval option.
+
+- 18th Sep 2008 libisofs-0.6.8 supports ISO 9660 Level 3 which can represent
+ very large data files in the image.
+
+- 20th Sep 2008 libisoburn/xorriso-0.2.6 takes into respect the new Level 3
+ capabilities of libisofs.
+
+- 6th Oct 2008 libburn-0.5.4 adjusts the changes of 0.5.2 to the needs of
+ Linux kernel 2.4 and introduces human readable SCSI error messages.
+
+- 6th Oct 2008 libisofs-0.6.10 fixes two bugs which prevented adding and
+ manipulation of ISOLINUX boot images.
+
+- 15th Oct 2008 libisoburn/xorriso-0.2.8 can activate and maintain an
+ ISOLINUX boot image by an EL Torito boot record.
+
+- 12th Nov 2008 libburn-0.5.6 fixes usage of freed memory by the fifo thread
+ of an aborted burn run.
+
+- 26th Nov 2008 libisofs-0.6.12 can produce a ISOLINUX isohybrid MBR on the fly
+ and can produce ISO images which resemble old mkisofs images.
+
+- 2nd Dec 2008 libisoburn-0.3.0. xorriso now is ready for exotic character
+ sets, for legacy FreeBSD systems which expect an outdated Rock Ridge
+ signature, and for producing ISO images with MBR which boot from hard disk
+ or USB stick. Three minor bugs were fixed.
+
+- 7th Dec 2008 libburn-0.5.8 prevents a SIGSEGV with weird CD table-of-content
+ and improves BD-RE formatting.
+
+- 9th Dec 2008 Our project received a donation from Thomas Weber.
+
+- 2nd Jan 2009 libburn-0.6.0 learned to format BD-R and write to either
+ formatted or unformatted BD-R.
+
+- 6th Jan 2009 libisoburn-0.3.2. xorriso can produce and execute commands for
+ mounting older sessions from all kinds of media. Pseudo-drives outside the
+ /dev/ tree can be addressed without prefix "stdio:".
+
+- 20th Feb 2009 libburn-0.6.2 source release now compiles out of the box
+ on FreeBSD.
+
+- 28 Feb 2009 libisofs-0.6.14 can record ACLs and Extended Attributes xattr
+ in its ISO images.
+
+- 01 Mar 2009 libisoburn-0.3.4. xorriso makes use of the ACL and xattr
+ capabilities provided by libisofs for xorriso backup features.
+
+- 11 Mar 2009 libisofs-0.6.16 of libisofs fixes two bugs which on Solaris
+ prevented to navigate the ISO images by ".." and to recognize the Rock Ridge
+ extensions of ISO images. The ban to build libisofs on operating systems
+ other than Linux and FreeBSD has been lifted.
+
+- 13 Mar 2009 libburn-0.6.4 got a dummy adapter for SCSI/MMC command transport.
+ It will show no drives and thus libburn will only be able to perform
+ operations on "stdio:" pseudo drives. Nevertheless this was precondition
+ to lift the ban to build libburn on operating systems other than Linux
+ and FreeBSD.
+
+- 16 Mar 2009 libisoburn-0.3.6: xorriso uses RRIP version 1.10 as default
+ in order to be mountable where mkisofs images are mountable.
+
+- 17 Apr 2009 libisofs-0.6.18 introduces content filtering of data files.
+ Built-in filters implement compression to formats gzip and zisofs. External
+ filter processes can perform arbitrary data conversions like encryption.
+
+- 19 Apr 2009 libisoburn-0.3.8 makes use of the new libisofs capability to
+ perform content filtering of data files.
+
+- 08 May 2009 libburn-0.6.6 fixes a bug with aborting on broken output pipe
+ and a bug with device scan on FreeBSD.
+
+- 31 May 2009 libisofs-0.6.20 can record hard link relations in ISO images
+ and offers support with restoring them to disk. Current Linux kernels will
+ mount images with such hard links but will attribute a unique inode number
+ to each file.
+
+- 28 Jun 2009 libisoburn-0.4.0: xorriso can record and restore hard link
+ relations of files. Performance of data reading has been improved. Option
+ -find now supports logical operators with its tests.
+
+- 14 Jul 2009 libburn-0.6.8 fixes bugs and shortcommings with old MMC-1 drives
+ and with large SCSI bus numbers as handed out by Linux for USB drives.
+
+- 20 Jul 2009 libisoburn-0.4.0.pl01 fixes a regression in xorriso which caused
+ data loss in older sessions if xorriso was used underneath growisofs.
+ Affected are releases since libisoburn-0.3.2 in january 2009.
+
+- 25 Aug 2009 libisofs-0.6.22 can record MD5 checksums for the whole session
+ and for each single data file. Checksum tags can be used to verify superblock
+ and directory tree before importing them.
+
+- 27 Aug 2009 libburn-0.7.0 learned to calm down a drive and to inquire its
+ supported profiles. It works around some pitfalls with U3 enhanced memory
+ sticks which emulate a CD-ROM.
+
+- 27 Aug 2009 libisoburn-0.4.0.pl00 can record MD5 checksums by which one may
+ verify the session or single data files in the image. When comparing image
+ files with files in the local filesystem, the MD5 sums avoid the need for
+ reading file content from the image.
+
+- 22 Sep 2009 libisoburn-0.4.0.pl01 fixes a bug in xorriso option -cut_out.
+
+- 08 Oct 2009 libisofs-0.6.24 fixes a bug which could cause the loss of blanks
+ in file names when a new session got added to an ISO image. With names
+ shorter than 251 characters this happened only to trailing blanks.
+
+- 08 Oct 2009 libisoburn-0.4.0.pl02 fixes bugs with xorriso option -for_backup,
+ with xorrisofs -help, and with xorrecord -help.
+
+- 12 Oct 2009 libburn-0.7.2 fixes a bug with CD TAO multi-track dummy sessions.
+ It can retrieve media product info and can process track input which was
+ prepared for CD-ROM XA Mode 2 Form 1. cdrskin now performs option -minfo.
+
+- 28 Oct 2009 libisoburn-0.4.4 fixes a bug with cdrecord emulation and
+ introduces new information options about media type and ISO image id strings.
+ On Linux it helps with mounting two sessions of the same media
+ simultaneously.
+
+- 12 Nov 2009 libburn-0.7.2.pl01 works around problems with Pioneer DVR-216D.
+ DVD-R runs made the drive stuck. Ejecting the tray did not work properly.
+
+- 06 Dec 2009 libburn-0.7.4 works around problems with newer DVD burners,
+ provides throughput enhancements with hampered busses on Linux, and new
+ API calls to log SCSI commands and to control the libburn fifo.
+
+- 09 Dec 2009 libisoburn-0.4.6 now offers performance tuning of output to DVD
+ drives or disk files.
+
+- 26 Dec 2009 libburn-0.7.4.pl01 fixes the release tarball which was lacking
+ the files of the generic system adapter for X/Open.
+
+- 29 Dec 2009 Our project received a donation for purchasing a fine small
+ computer which shall serve as OS farm for development and support.
+
+- 20 Jan 2010 Version 0.6.26 of libisofs fixes minor bugs and shall enhance
+ portability.
+
+- 22 Jan 2010 libburn-0.7.6 has an improved system adapter for FreeBSD,
+ fixes bugs about the generic X/Open system adapter, and can use
+ libcdio >= 0.83 as SCSI transport facility.
+
+- 10 Feb 2010 libisofs-0.6.28 fixes a regression about bootable images which
+ was introduced by version 0.6.22 in August 2009.
+
+- 23 Feb 2010 libisoburn-0.5.0 marks the transition of the xorriso standalone
+ version to an official GNU project. The name changed to "GNU xorriso" and its
+ license is now GPLv3+.
+ The licenses of libburnia libraries and applications are not affected by
+ this change.
+
+- 10 Mar 2010 libburn-0.7.8 fixes bugs and improves the built-in abort handler
+ on FreeBSD.
+
+- 30 Mar 2010 Release 0.5.2 of libisoburn provides xorriso documentation in
+ GNU Texinfo format with embedded extra data to derive a full man page.
+
+- 09 Apr 2010 libburn-0.8.0 now works with ahci driver on FreeBSD 8-STABLE.
+
+- 03 May 2010 Version 0.6.32 of libisofs is able to create ISO images with
+ multiple boot images. All boot catalog parameters described in El-Torito
+ specs can be set and inquired. This was needed to use GRUB boot images
+ for EFI.
+
+- 04 May 2010 Release 0.5.6.pl00 of libisoburn makes use of the new libisofs
+ capabilities about boot images.
+
+- 11 Jun 2010 libburn-0.8.2 now works on Solaris.
+
+- 14 Jun 2010 By release 0.5.8.pl00 of libisoburn, xorriso becomes a public C
+ language API of libisoburn. The emulations of mkisofs and cdrecord have
+ been enhanced.
+
+- Tue Jun 29 2010 Version 0.6.34 of libisofs provides new features about
+ hiding file names from directory trees.
+
+- Wed Jun 30 2010 libburn-0.8.4 removes some restrictions on operating
+ systems other than Linux and FreeBSD.
+
+- Fri Jul 02 2010 Release 0.6.0.pl00 of libisoburn adds more options to the
+ mkisofs emulation of xorriso. It also fixes minor bugs and shortcommings.
+
+- Wed Sep 15 2010 Version 0.6.36 of libisofs can produce ISO images which
+ bear a partiton 1 with non-zero start address. They can be mounted from
+ USB stick via the main device file (e.g. /dev/sdb) as well as via the
+ partition device file (e.g. /dev/sdb1).
+
+- Fri Sep 17 2010 libburn-0.8.6 lifts the test reservation on DVD-R DL media.
+
+- Sat Sep 18 2010 Release 0.6.2.pl00 of libisoburn introduces a partition
+ with non-zero offset for ISO 9660 images on USB sticks, improves mkisofs
+ emulation, and fixes a regression which existed since version 0.4.2.
+
+- Wed Oct 20 2010 libburn-0.8.8 can report the used amount of BD spare blocks.
+
+- Sat Oct 23 2010 Version 0.6.38 of libisofs can use libjte to produce jigdo
+ files along with the ISO image. Further filesystem images may be appended
+ as MBR partitions 1 to 4. The capability was added to produce boot blocks
+ for computers with MIPS CPU.
+
+- Tue Oct 26 2010 Release 0.6.4.pl00 of libisoburn and xorriso makes use of
+ the new libisofs capabilities.
+
+- Wed Dec 08 2010 libburn-0.9.0 fixes a regression with SCSI command logging.
+
+- Fri Dec 10 2010 Version 0.6.40 of libisofs makes the prediction of the
+ emerging image size less expensive and is able to make images bootable
+ for SUN SPARC systems.
+
+- Sun Dec 12 2010 Release 0.6.6.pl00 of libisoburn and xorriso can read ISO
+ images which were copied to a different start address than they were prepared
+ for.
+
+- Mon Jan 17 2011 we go for release 1.0.0. This does not indicate a
+ technological overhaul but shall emphasize the maturity of the software.
+ libisofs-1.0.0 fixes a bug about the length of ECMA-119 directory names and
+ is ready to store untranslated ECMA-119 names (violating the specs).
+ libburn-1.0.0.pl00 is now willing to create stdio-drive files with
+ rw-permissions for all, if umask really asks for it. cdrskin now refuses
+ to burn if the foreseeable size exceeds media capacity
+ libisoburn-1.0.0.pl00 can now create an ISO 9660:1999 directory tree,
+ improved the emulation fidelity of command -as mkisofs, lowered the default
+ abort threshold for xorriso batch mode, and increased that threshold for
+ xorriso dialog mode.
+
+- Wed Feb 23 2011 release 1.0.2:
+ libisofs fixes several bugs and introduces the capability to copy files
+ inside the ISO filesystem.
+ libburn removed a compilation obstacle on Solaris 9 and improved recognition
+ of stdio pseudo-drives.
+ libisoburn and xorriso fix bugs and make use of the new libisofs capability.
+ xorriso improves its mkisofs emulation.
+
+- Thu Mar 10 2011 release 1.0.4:
+ Several bugs were fixed in the libraries and in the mkisofs emulation of
+ xorriso. This emulation xorrisofs has now an own man page and info document.
+
+- Sat Apr 09 2011 release 1.0.6:
+ libburn refined its representation of emulated drives. The size alignment
+ of DVD DAO is now 2 kB rather than 32 kB. libisofs produces Joliet names of
+ up to 103 characters. xorriso fixes two bugs and makes use of the library
+ improvements.
+
+- Thu Apr 14 2011 release libisoburn-1.0.8:
+ A bug in the mkisofs emulation of xorriso could cause options to be ignored.
+ The problem was freshly introduced with libisoburn-1.0.6.
+
+- Fri May 13 2011 release libisofs-1.0.8:
+ Fixes a few rarely occurring bugs that have been found during the last month.
+
+- Sat Jun 18 2011 release 1.1.0:
+ The consumption of stack memory was reduced. Statical program analysis found
+ some rarely occurring memory leaks. Several small bugs were fixed.
+ The suffix .plXY was dropped from tarball names of libburn and libisoburn.
+
+- Mon Jun 20 2011 patch release libburn-1.1.0.pl01:
+ libburn-1.1.0 compiled only on Linux, FreeBSD, and Solaris, but not on
+ other X/Open compliant systems.
+
+- Fri Jul 08 2011 release libisofs-1.1.2 and libisoburn-1.1.2:
+ A severe regression was fixed in libisoburn and xorriso, which was introduced
+ with version 1.0.6. It caused ISO 9660 images to be unreadable if they were
+ written to a write-only random-access file. E.g. by: xorrisofs ... >image.iso
+
+- Mon Aug 08 2011 release 1.1.4:
+ Several bugs were fixed in libburn. The most severe of them prevented xorriso
+ on some drives from burning mountable ISO 9660 images to CD media.
+ New means to list drives by their udev symbolic links help to deal with
+ the non-persistent drive addresses on modern GNU/Linux.
+
+- Tue Sep 27 2011 release 1.1.6:
+ libisoburn now comes with a test suite. See releng/README. Bugs were fixed
+ in several rarely used features. Processing of ACL and extattr was enabled
+ on FreeBSD. Workarounds try to cope with vanishing udev links on GNU/Linux.
+
+- Mon Nov 21 2011 release libburn-1.1.8 and libisoburn-1.1.8:
+ libburn avoids to close and open drive device files while operating on them.
+ xorriso emulation mode xorrecord now has an own manual. libburn and xorriso
+ were prepared to operate on qemu virtio-blk-pci devices.
+
+- Sat Jan 28 2012 release 1.2.0:
+ libburn has learned to read and write CD-TEXT with CD SAO audio sessions.
+ It can now read CDRWIN .cue files which define pure audio or pure data
+ sessions. libisofs and libisoburn improved timestamp handling. Several
+ minor bugs were fixed.
+
+- Mon Apr 02 2012 release 1.2.2:
+ The handling of intentional deviations from ECMA-119 specifications has
+ been improved in libisofs. libisoburn and xorriso now make use of these
+ improvements. Some rarely occurring bugs have been fixed.
+
+- Fri Jul 20 2012 release 1.2.4:
+ libburn and libisofs got some rarely occurring bugs fixed. libisofs learned
+ to produce HFS+ metadata and Apple Partition Map. The capabilities of
+ isohybrid options --efi and --mac have been implemented (GPT and APM).
+
+- Tue Jan 08 2013 release 1.2.6:
+ Small improvements were made in libburn. Minor bugs were fixed in the
+ libraries. xorriso improved its capabilities to serve the needs of frontend
+ programs. A proof of concept for a GUI frontend has been implemented:
+ xorriso-tcltk
+
+- Mon Mar 18 2013 release 1.2.8:
+ Some rarely occurring bugs were fixed in libisofs and libburn. libburn's
+ handling of incomplete sessions has been improved. xorriso's mkisofs
+ emulation learned to set El Torito section id strings.
+
+- Fri May 17 2013 release 1.3.0:
+ Several bugs were fixed in the libraries and in xorriso. The recently
+ introduced new boot preparation capabilities have been tested. New
+ boot preparation options for GRUB2 were added.
+
+- Fri May 31 2013 patch release libburn-1.3.0.pl01:
+ cdrskin -msinfo on DVD and BD reported as old session start the same
+ number as the next writable address.
+ Regression introduced by version 1.2.8.
+
+- Fri Aug 07 2013 release 1.3.2:
+ cdrskin has acquired the capability to copy audio tracks to .wav files.
+ It can extract CD-TEXT in a form that is readable for humans and for
+ cdrskin itself. Several small bugs were fixed in xorriso. Its capabilities
+ to serve frontend programs in dialog mode have been improved.
+
+- Thu Dec 12 2013 release 1.3.4:
+ A long standing hidden bug was fixed, which affected inspection of
+ unformatted DVD+RW.
+ xorriso now by default puts EL Torito boot images to low block addresses.
+ It can report and set read speeds. Several rarely occurring bugs were fixed.
+
+- Tue Mar 04 2014 release 1.3.6:
+ libburn learned to operate optical drives and media on NetBSD. libisofs got
+ a bug fix about HFS+ and enhancements about character set conversion.
+ Minor bugs were fixed in libisoburn. xorriso can now find files with names
+ which cannot be represented unchanged in ECMA-119, Joliet, or HFS+.
+
+- Sat Jun 28 2014 release 1.3.8:
+ libburn got several bugs fixed. libisofs offers new API calls for inspection
+ of boot sectors in ISO 9660 filesystems. xorriso improved its support for
+ NetBSD, offers new features with command -find, and a command to extract
+ ISO 9660 file content onto standard output or into filter processes.
+
+- Sun May 17 2015 release 1.4.0:
+ This release is mainly about bug fixes and a new feature of xorriso to
+ propose commands or as_mkisofs options which can reproduce the boot
+ equipment of the loaded ISO filesystem.
+
+- Sat Nov 28 2015 release 1.4.2:
+ libburn got some bugs fixed and learned to inquire the drive serial number.
+ libisofs now sorts data file content by ECMA-119 file names for better
+ reproducability of ISO content. Rock Ridge filenames may be restricted to
+ lengths between 64 and 255 bytes. If needed, a qualified truncation happens.
+ xorriso now can replay boot settings when modifying ISO filesystems.
+ In order to avoid clogging of concurrent Linux SG_IO, xorriso got command
+ -modesty_on_drive to enable an old workaround from IDE master/slave days.
+ The source code underwent a scan by Coverity. About 150 code changes
+ resulted, but no easy-to-trigger bugs were found.
+
+- Fri Jan 29 2016 patch release libburn-1.4.2.pl01:
+ cdrskin did not work with "-" (stdin) as input.
+ Regression introduced by version 1.4.2.
+
+- Fri Jul 01 2016 release 1.4.4:
+ The capability to use Linux /dev/sg was revived in order to circumvent the
+ sr_mutex lock which hampers concurrent use of optical drives via SG_IO.
+ libisofs now can use appended partitions by El Torito, avoiding the need
+ for duplicate EFI System Partition images.
+ Several bugs have been fixed.
+
+
+------------------------------------------------------------------------------
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 or later
+ 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
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+------------------------------------------------------------------------------
+Clarification in my name and in the name of Mario Danic, upcoming copyright
+holders on toplevel of libburnia. To be fully in effect after the remaining
+other copyrighted code has been replaced by ours and by copyright-free
+contributions of our friends:
+------------------------------------------------------------------------------
+
+We, the copyright holders, agree on the interpretation that dynamical linking
+of our libraries constitutes "use of" and not "derivation from" our work in
+the sense of GPL, provided those libraries are compiled from our unaltered
+code or from altered code published under GPL.
+
+So we will not raise legal protest if you link our libraries dynamically with
+applications which are not under GPL, or if you distribute our libraries
+and application tools in binary form, as long as you fulfill the usual
+condition of GPL to offer a copy of their source code -altered or unaltered-
+under GPL.
+
+We ask you politely to use our work in open source spirit
+and with the due reference to the entire open source community.
+
+If there should really arise the case where above clarification
+does not suffice to fulfill a clear and neat request in open source
+spirit that would otherwise be declined for mere formal reasons,
+only in that case we will duely consider to issue a special license
+covering only that special case.
+It is the open source idea of responsible freedom which will be
+decisive and you will have to prove that you exhausted all own
+means to qualify for GPL.
+
+For now we are firmly committed to maintain one single license: GPL.
+
+signed: Mario Danic, Thomas Schmitt
+Agreement joined later by: Vreixo Formoso
+
diff --git a/libburn/branches/1.4.6/acinclude.m4 b/libburn/branches/1.4.6/acinclude.m4
new file mode 100644
index 00000000..ba7fcad9
--- /dev/null
+++ b/libburn/branches/1.4.6/acinclude.m4
@@ -0,0 +1,151 @@
+AC_DEFUN([LIBBURNIA_SET_FLAGS],
+[
+case $target_os in
+freebsd* | netbsd*)
+ LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+ ;;
+esac
+])
+
+
+AC_DEFUN([TARGET_SHIZZLE],
+[
+ ARCH=""
+ LIBBURNIA_PKGCONFDIR="$libdir"/pkgconfig
+
+ AC_MSG_CHECKING([target operating system])
+
+ LIBBURNIA_LDCONFIG_CMD="echo 'No ldconfig run performed. If needed, configure manually for:'"
+
+ case $target in
+ *-*-linux*)
+ ARCH=linux
+ LIBBURN_ARCH_LIBS=
+ LIBBURNIA_LDCONFIG_CMD=ldconfig
+ ;;
+ *-*-freebsd*)
+ ARCH=freebsd
+ LIBBURN_ARCH_LIBS=-lcam
+ LIBBURNIA_PKGCONFDIR=$(echo "$libdir" | sed 's/\/lib$/\/libdata/')/pkgconfig
+ ;;
+ *-kfreebsd*-gnu*)
+ ARCH=freebsd
+ LIBBURN_ARCH_LIBS=-lcam
+ ;;
+ *-solaris*)
+ ARCH=solaris
+ LIBBURN_ARCH_LIBS=-lvolmgt
+ ;;
+ *)
+ ARCH=
+ LIBBURN_ARCH_LIBS=
+# AC_ERROR([You are attempting to compile for an unsupported platform])
+ ;;
+ esac
+
+ AC_MSG_RESULT([$ARCH])
+])
+
+
+dnl LIBBURN_ASSERT_VERS_LIBS is by Thomas Schmitt, libburnia project
+dnl It tests whether -Wl,--version-script=... works with the compiler
+AC_DEFUN([LIBBURN_ASSERT_VERS_LIBS],
+[
+ libburnia_save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,--version-script=libburn/libburn.ver"
+ AC_TRY_LINK([#include ], [printf("Hello\n");],
+ [vers_libs_test="yes"], [vers_libs_test="no"])
+ if test x$vers_libs_test = xyes
+ then
+ LIBLDFLAGS="-Wl,--version-script=libburn/libburn.ver"
+ fi
+ LDFLAGS="$libburnia_save_LDFLAGS"
+ AC_SUBST(LIBLDFLAGS)
+])
+
+
+dnl LIBBURNIA_SET_PKGCONFIG determines the install directory for the *.pc file.
+dnl Important: Must be performed _after_ TARGET_SHIZZLE
+dnl
+AC_DEFUN([LIBBURNIA_SET_PKGCONFIG],
+[
+### for testing --enable-libdir-pkgconfig on Linux
+### LIBBURNIA_PKGCONFDIR="$libdir"data/pkgconfig
+
+if test "x$LIBBURNIA_PKGCONFDIR" = "x$libdir"/pkgconfig
+then
+ dummy=dummy
+else
+ AC_ARG_ENABLE(libdir-pkgconfig,
+ [ --enable-libdir-pkgconfig Install to $libdir/pkgconfig on any OS, default=no],
+ , enable_libdir_pkgconfig="no")
+ AC_MSG_CHECKING([for --enable-libdir-pkgconfig])
+ if test "x$enable_libdir_pkgconfig" = xyes
+ then
+ LIBBURNIA_PKGCONFDIR="$libdir"/pkgconfig
+ fi
+ AC_MSG_RESULT([$enable_libdir_pkgconfig])
+fi
+
+libburnia_pkgconfig_override="no"
+AC_ARG_ENABLE(pkgconfig-path,
+[ --enable-pkgconfig-path=DIR Absolute path of directory for libisofs-*.pc],
+libburnia_pkgconfig_override="yes" , enable_pkgconfig_path="none")
+AC_MSG_CHECKING([for overridden pkgconfig directory path])
+if test "x$enable_pkgconfig_path" = xno
+then
+ libburnia_pkgconfig_override="no"
+fi
+if test "x$enable_pkgconfig_path" = x -o "x$enable_pkgconfig_path" = xyes
+then
+ libburnia_pkgconfig_override="invalid argument"
+fi
+if test "x$libburnia_pkgconfig_override" = xyes
+then
+ LIBBURNIA_PKGCONFDIR="$enable_pkgconfig_path"
+ AC_MSG_RESULT([$LIBBURNIA_PKGCONFDIR])
+else
+ AC_MSG_RESULT([$libburnia_pkgconfig_override])
+fi
+AC_SUBST(LIBBURNIA_PKGCONFDIR)
+
+dnl For debugging only
+### AC_MSG_RESULT([LIBBURNIA_PKGCONFDIR = $LIBBURNIA_PKGCONFDIR])
+
+])
+
+dnl LIBBURNIA_CHECK_ARCH_LIBS is by Thomas Schmitt, libburnia project
+dnl It tests whether the OS dependent libraries are available.
+dnl With libisoburn they are needed only for the case that indirect linking
+dnl does not work. So it is worth a try to omit them.
+dnl $1 = "mandatory" or "optional" define the action if test linking fails.
+AC_DEFUN([LIBBURNIA_CHECK_ARCH_LIBS],
+[
+ libburnia_save_LIBS="$LIBS"
+ if test "x$LIBBURN_ARCH_LIBS" = x
+ then
+ dummy=dummy
+ else
+ LIBS="$LIBS $LIBBURN_ARCH_LIBS"
+ AC_TRY_LINK([#include ], [printf("Hello\n");],
+ [archlibs_test="yes"], [archlibs_test="no"])
+ LIBS="$libburnia_save_LIBS"
+ if test x$archlibs_test = xno
+ then
+ if test x"$1" = xmandatory
+ then
+ echo >&2
+ echo "FATAL: Test linking with mandatory library options failed: $LIBBURN_ARCH_LIBS" >&2
+ echo >&2
+ (exit 1); exit 1;
+ else
+ echo "disabled linking with $LIBBURN_ARCH_LIBS (because not found)"
+ LIBBURN_ARCH_LIBS=""
+ fi
+ else
+ echo "enabled linking with $LIBBURN_ARCH_LIBS"
+ fi
+ fi
+])
+
diff --git a/libburn/branches/1.4.6/bootstrap b/libburn/branches/1.4.6/bootstrap
new file mode 100755
index 00000000..faadaabc
--- /dev/null
+++ b/libburn/branches/1.4.6/bootstrap
@@ -0,0 +1,10 @@
+#!/bin/sh -x
+
+aclocal -I .
+libtoolize --copy --force
+autoconf
+
+# ts A61101 : libburn is not prepared for config.h
+# autoheader
+
+automake --foreign --add-missing --copy --include-deps
diff --git a/libburn/branches/1.4.6/cdrskin/README b/libburn/branches/1.4.6/cdrskin/README
new file mode 100644
index 00000000..1cdc2f40
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/README
@@ -0,0 +1,604 @@
+------------------------------------------------------------------------------
+ libburnia-project.org scdbackup.sourceforge.net/cdrskin_eng.html
+------------------------------------------------------------------------------
+cdrskin. By Thomas Schmitt
+Integrated sub project of libburnia-project.org but also published via:
+http://scdbackup.sourceforge.net/cdrskin_eng.html
+http://scdbackup.sourceforge.net/cdrskin-1.4.5.tar.gz
+
+Copyright (C) 2006-2016 Thomas Schmitt, provided under GPL version 2 or later.
+------------------------------------------------------------------------------
+
+
+cdrskin is a limited cdrecord compatibility wrapper which allows to use
+most of the libburn features from the command line.
+
+Currently it is fully supported on GNU/Linux with kernels >= 2.4, on FreeBSD,
+on OpenSolaris, and on NetBSD.
+IDE drives under Linux 2.4. need kernel module ide-scsi.
+ATA and SATA drives under FreeBSD need kernel module atapicam.
+On other X/Open compliant systems there will only be emulated drives, but no
+direct MMC operation on real CD/DVD/BD drives.
+
+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-1.4.5.tar.gz, take it to a directory of your choice and do:
+
+ tar xzf cdrskin-1.4.5.tar.gz
+ cd cdrskin-1.4.5
+
+Within that directory execute:
+
+ ./configure --prefix=/usr
+ make
+
+This will already produce a cdrskin binary. But it will be necessary to
+install libburn in order to use this binary.
+
+In order to surely get a standalone binary, execute
+
+ cdrskin/compile_cdrskin.sh
+
+Version identification and help texts available afterwards:
+ cdrskin/cdrskin -version
+ cdrskin/cdrskin --help
+ cdrskin/cdrskin -help
+ 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.
+E.g.:
+
+ cp cdrskin/cdrskin /usr/bin/cdrskin
+
+Check the version timestamps of the globally installed binary
+ cdrskin -version
+
+It is not necessary for the standalone cdrskin binary to have libburn
+installed, since it incorporates the necessary libburn parts at compile time.
+It will not collide with an installed version of libburn either.
+But libpthread must be installed on the system and glibc has to match. (See
+below for a way to create a totally static linked binary.)
+
+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
+
+The user of cdrskin needs rw-permission for the CD burner device.
+A list of rw-accessible drives can be obtained by
+
+ cdrskin --devices
+
+CD devices which offer no rw-permission are invisible to normal users.
+The superuser should be able to see any usable drive and then set the
+permissions as needed. If this hangs then there is a drive with
+unexpected problems (locked, busy, broken, whatever). You might have to
+guess the address of your (non-broken) burner by other means, then.
+On Linux 2.4 this would be some /dev/sgN and on 2.6. some /dev/srM or /dev/hdX.
+
+The output of cdrskin --devices might look like
+
+ 0 dev='/dev/sr0' rwrwr- : '_NEC' 'DVD_RW ND-4570A'
+ 1 dev='/dev/sr1' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
+
+On Linux, full and insecure enabling of both for everybody would look like
+ chmod a+rw /dev/sr0 /dev/hda
+This is equivalent to the traditional setup chmod a+x,u+s cdrecord.
+
+On FreeBSD, device rw-permissions are to be set in /etc/devfs.rules.
+On Solaris, pfexec privileges may be restricted to "basic,sys_devices".
+On NetBSD, rw-permission may be granted by chmod a+rw /dev/rcd?d.
+See below "System Dependend Drive Permission Examples".
+
+I strongly discourage to run cdrskin with setuid root or via sudo !
+It is not checked for the necessary degree of hacker safety.
+Better consider to grant the necessary permissions to group "floppy"
+and to add users to it.
+
+
+A behavioral conflict is known between any burn software and demons like hald
+which probe CD drives. This can spoil burn runs for CD-R or CD-RW.
+You may have to keep your hald away from the drive. See for example
+ http://www.freebsd.org/gnome/docs/halfaq.html
+
+
+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
+
+For options and recordable media classes see
+ man 1 cdrskin
+
+Get an overview of cdrecord style addresses of available devices
+ cdrskin -scanbus
+ cdrskin dev=ATA -scanbus
+ 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=/dev/sr0
+See also "Drive Addressing" below.
+
+Obtain some info about the drive
+ cdrskin dev=0,1,0 -checkdrive
+
+Obtain some info about the drive and the inserted media
+ cdrskin dev=0,1,0 -atip -v -minfo
+
+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
+
+De-format DVD-RW to make it capable of multi-session again
+ cdrskin -v dev=/dev/sr0 blank=deformat_sequential
+
+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[/DL]
+ cdrskin dev=/dev/hdc padsize=300k -multi 1.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 \
+ driveropts=burnfree padsize=300k -
+
+Burn 6 audio tracks from files with different formats to CD (not to any DVD).
+Anything except .wav or .au files has to be converted into raw format first.
+See below "Audio CD" for specifications.
+ ogg123 -d raw -f track01.cd /path/to/track1.ogg
+ oggdec -R -o track02.cd /path/to/track2.ogg
+ lame --decode -t /path/to/track3.mp3 track03.cd
+ madplay -o raw:track04.cd /path/to/track4.mp3
+ mppdec --raw-le /path/to/track5.mpc track05.cd
+
+ cdrskin -v dev=0,1,0 blank=fast -eject speed=48 -sao \
+ -audio -swab track0[1-5].cd /path/to/track6.wav
+
+Extract audio tracks and CD-TEXT from CD into directory /home/me/my_cd:
+ mkdir /home/me/my_cd
+ cdrskin -v dev=/dev/sr0 extract_audio_to=/home/me/my_cd \
+ cdtext_to_v07t=/home/me/my_cd/cdtext.v07t
+
+
+ Restrictions
+
+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.
+
+On the other hand, the capability of multi-session and of writing streams
+of unpredicted length surpass the current DVD capabilities of cdrecord.
+
+
+ Inspiration and Standard
+
+cdrskin combines the command line interface standard set by cdrecord with
+libburn, which is a control software for optical drives according to standard
+MMC-5. For particular CD legacy commands, standards MMC-3 and MMC-1 apply.
+
+For the original meaning of cdrecord options see :
+ man cdrecord
+ (http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html)
+Do not bother Joerg Schilling with any cdrskin problems.
+(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
+ this "don't bother Joerg" demand.)
+
+cdrskin does not contain any bytes copied from cdrecord's sources. Many bytes
+have been copied from the message output of cdrecord runs, though. I am
+thankful to Joerg Schilling for every single one of them.
+I have the hope that Joerg feels more flattered than annoyed by cdrskin.
+
+Many thanks to Andy Polyakov for his dvd+rw-tools
+ http://fy.chalmers.se/~appro/linux/DVD+RW/tools
+which provide me with examples and pointers into MMC specs for DVD writing.
+
+
+ Startup Files
+
+If not --no_rc is the first argument then cdrskin attempts on startup to read
+arguments from the following three files:
+ /etc/default/cdrskin
+ /etc/opt/cdrskin/rc
+ /etc/cdrskin/cdrskin.conf
+ $HOME/.cdrskinrc
+The files are read in the sequence given above.
+Each readable line is treated as one single argument. No extra blanks.
+A first character '#' marks a comment, empty lines are ignored.
+
+Example content of a startup file:
+# This is the default device
+dev=0,1,0
+
+# Some more options
+fifo_start_at=0
+fs=16m
+
+
+ Audio CD
+
+Lorenzo Taylor enabled option -audio in cdrskin (thanks !) and reports neat
+results with audio data files which are :
+ headerless PCM (i.e. uncompressed)
+ 44100 Hz sampling rate
+ 16 bits per sample
+ stereo (2 channels)
+ little-endian byte order with option -swab, or big-endian without -swab
+
+Files with name extension .wav get examined wether they are in Microsoft WAVE
+format with above parameters and eventually get extracted by cdrskin itself.
+In the same way files with name extension .au get examined wether they are
+in SUN's audio format. For both formats, track format -audio and eventual
+endianness option -swab are enabled automatically.
+
+Any other formats are to be converted to format .wav with above parameters
+or to be extracted as raw CD track data by commands like those given above
+under "Usage examples". Those raw files need option -audio and in most cases
+option -swab to mark them as little-endian/Intel/LSB-first 16-bit data.
+Incorrect endianness setting results in random noise on CD.
+
+I myself am not into audio. So libburn-hackers@pykix.org might be the
+best address for suggestions, requests and bug reports.
+
+
+ DVD+RW , DVD-RAM , BD-RE
+
+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) 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.
+
+BD-RE media need formatting before first use. cdrskin option "blank=as_needed"
+recognizes unformatted BD-RE and applies a lengthy formatting run.
+
+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.
+Instead of "on" one may also set a start address for stream recording.
+Like "stream_recording=100m". This will write slowly to the first 100 MB of
+the media and accelerate when writing to higher addresses.
+
+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 , DVD-R , DVD-R DL
+
+DVD-RW are usable if formatted to state "Restricted Overwrite" or if in state
+"Sequential Recording". DVD-R are always in sequential state. DVD-R DL are
+always sequential and incapable of multi-session.
+
+"Sequential" is the state of unused media and of media previously blanked
+or written by cdrecord. dvd+rw-format -blank can also achieve this state.
+The according cdrskin option is blank=deformat_sequential .
+If "Incremental Streaming" is available, then sequential media are capable
+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
+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.)
+
+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.)
+
+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
+drive and media, formatting can yield unusable media. It seems that those die
+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 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,
+but leaves the media in "intermediate" state. In the first session of writing
+one may only write sequentially to such a DVD. After that, it gets random
+addressable by cdrskin. DVD-ROM drives might show ill behavior with them.
+
+blank=format_overwrite_full uses preferably "Full Format" (type 00h).
+This formatting lasts as long as writing a full DVD. It includes writing of
+lead-out which is said to be good for DVD ROM compatibility.
+
+De-formatting options are available to make overwriteable DVD-RW sequential:
+
+blank=deformat_sequential performs thorough blanking of all states of DVD-RW.
+blank=all and blank=fast perform the same thorough blanking, but refuse to do
+this with overwriteable DVD-RW, thus preserving their formatting. The specs
+allow minimal blanking but the resulting media on my drives offer no
+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 DL , BD-R
+
+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.
+
+BD-R are sold unformatted blank. If used without initial formatting then the
+drive is supposed to format them to maximum payload size with no Defect
+Management (see also above with BD-RE).
+If Defect Management is desired then BD-R need to be formatted before the
+first attempt to write a session to them.
+blank=format_if_needed will detect the situation and eventually apply
+ default sized Defect Management formatting.
+blank=format_defectmgt_* will apply non-default parameters to formatting.
+
+
+ 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.
+
+
+------------------------------------------------------------------------------
+
+ Special compilation variations
+
+All following options of ./configure and cdrskin/compile_cdrskin.sh are
+combinable. After runs of ./configure do as next:
+ make clean ; make
+
+In some situations Linux may deliver a better write performance to drives if
+the track input is read with O_DIRECT (see man 2 open). The API call
+burn_os_open_track_src() and the input readers of cdrskin and libburn fifo
+can be told to use this peculiar read mode by:
+ --enable-track-src-odirect
+
+But often cdrskin option dvd_obs=64k will yield even better performance in
+such a situation. 64k can be made default at compile time by
+ cdrskin/compile_cdrskin.sh -dvd_obs_64k
+It can also be enabled at configure time by
+ ./configure ... --enable-dvd-obs-64k ...
+
+Alternatively the transport of SCSI commands can be done via libcdio-0.83.
+You may install it and re-run libburn's ./configure with option
+ --enable-libcdio
+Add option
+ -use_libcdio
+to your run of cdrskin/compile_cdrskin.sh .
+
+You may get a (super fat) statically linked binary by :
+ cdrskin/compile_cdrskin.sh -static
+if your system supports static linking, at all. This will not help with kernels
+which do not properly support the necessary low-level interfaces chosen by
+your compile-time libraries.
+
+A size reduced but fully functional binary may be produced by
+ cdrskin/compile_cdrskin.sh -do_strip
+
+An extra lean binary with reduced capabilities is created by
+ cdrskin/compile_cdrskin.sh -do_diet -do_strip
+It will not read startup files, will abort on option dev_translation= ,
+will not have a fifo buffer, and will not be able to put out help texts or
+debugging messages.
+
+
+Linux only:
+
+libburn tries to avoid a collision with udev's drive examination by waiting
+0.1 seconds before opening the device file for a longer time, after udev
+might have been alarmed by drive scanning activities.
+The waiting time can be set at ./configure time with microsecond granularity.
+E.g. 2 seconds:
+ CFLAGS="$CFLAGS -DLibburn_udev_wait_useC=2000000"
+ ./configure ...options...
+Waiting can be disabled by zero waiting time:
+ CFLAGS="$CFLAGS -DLibburn_udev_wait_useC=0"
+Alternatively, libburn can try to be nice by opening the device file,
+closing it immediately, waiting, and only then opening it for real:
+ CFLAGS="$CFLAGS -DLibburn_udev_extra_open_cyclE -DLibburn_udev_wait_useC=500000"
+
+------------------------------------------------------------------------------
+
+ System Dependend Drive Permission Examples
+
+Accessing the optical drives requires privileges which usually are granted
+only to the superuser. Linux, FreeBSD, Solaris, NetBSD, offer quite different
+approaches for avoiding the need for unrestricted privileges.
+
+First check whether some friendly system setting already allows you to
+access the drives as normal user:
+ cdrskin --devices
+Those drives of which you see address and type strings are already usable.
+
+If there remain drives invisible which the superuser can see by the same
+command, then the following examples might help:
+
+---------------
+On all systems:
+---------------
+Add the authorized users of CD drives to group "floppy" in /etc/group.
+If missing: create this group.
+Changes to /etc/group often only affect new login sessions. So log out and in
+before making the first tests.
+
+---------
+On Linux:
+---------
+Allow rw-access to the drives
+ chgrp floppy /dev/sr0 /dev/sr1
+ chmod g+rw /dev/sr0 /dev/sr1
+It might be necessary to perform chgrp and chmod after each reboot or to
+edit distro dependent device configuration files for permanent settings.
+
+-----------
+On FreeBSD:
+-----------
+Edit /etc/devfs.rules and make sure to have these lines
+ [localrules=10]
+ add path 'acd*' mode 0664 group floppy
+ add path 'cd*' mode 0664 group floppy
+ add path 'pass*' mode 0664 group floppy
+ add path 'xpt*' mode 0664 group floppy
+ [localrules=5]
+ add path 'pass*' mode 0664 group floppy
+ add path 'cd*' mode 0664 group floppy
+ add path 'xpt*' mode 0664 group floppy
+ add path 'acd*' mode 0664 group floppy
+
+Edit /etc/rc.conf and add the following line if missing
+ devfs_system_ruleset="localrules"
+
+This gets into effect by reboot or by command
+ /etc/rc.d/devfs start
+
+-----------
+On Solaris:
+-----------
+Run cdrskin by
+ pfexec cdrskin ...arguments...
+
+The following settings will make pfexec keep original UID and EUID and prevent
+most superuser powers. Be aware that you still can manipulate all device files
+if you have the file permissions for that.
+Full root privileges for cdrskin can then be acquired only by command su.
+
+Edit /etc/security/exec_attr and add this line to the other "Media Backup"
+lines:
+ Media Backup:solaris:cmd:::/usr/local/bin/cdrskin:privs=basic,sys_devices
+Edit /etc/user_attr and add profile "Media Backup" to the user's line:
+ thomas::::profiles=Media Backup,Primary Administrator;roles=root
+See also man privileges, man exec_attr, man user_attr.
+
+Then allow the group r-access to the drives
+ pfexec chgrp floppy /dev/rdsk/c3t0d0s2 /dev/rdsk/c4t0d0s2
+ pfexec chmod g+r /dev/rdsk/c3t0d0s2 /dev/rdsk/c4t0d0s2
+The last two commands have to be executed after each boot. I do not know
+the relevant device configuration files yet.
+
+----------
+On NetBSD:
+----------
+Allow rw-access to the drives
+ chgrp floppy /dev/rcd[01]d
+ chmod g+rw /dev/rcd[01]d
+
+------------------------------------------------------------------------------
+ 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 3.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 version 2 or later
+ 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
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+------------------------------------------------------------------------------
+Based on and sub project of:
+libburnia-project.org
+By Mario Danic and Thomas Schmitt
+Copyright (C) 2006-2014 Mario Danic, Thomas Schmitt
+
+libburnia-project.org is inspired by and in other components still containing
+parts of
+Libburn. By Derek Foreman and
+ Ben Jansens
+Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
+See toplevel README for an overview of the current copyright situation in
+libburnia-project.org.
+
+
diff --git a/libburn/branches/1.4.6/cdrskin/add_ts_changes_to_libburn_1_4_4 b/libburn/branches/1.4.6/cdrskin/add_ts_changes_to_libburn_1_4_4
new file mode 100755
index 00000000..c1946271
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/add_ts_changes_to_libburn_1_4_4
@@ -0,0 +1,247 @@
+#!/bin/sh
+
+set -x
+
+# This script documents how this cdrskin version was derived from
+# a vanilla libburn version. It is not intended nor needed for any
+# use of cdrskin but included here only to show the technical
+# relationship between both projects - which are close friends
+# and issue roughly the same software.
+#
+# Package maintainers are advised to cover rather libburn than
+# cdrskin unless they put only emphasis on the cdrecord emulation
+# provided by cdrskin. libburn contains cdrskin - cdrskin is an
+# oscillating, friendly and coordinated fork of libburn.
+#
+# Script results are a source tarball and two binaries
+# one dynamic and one static in respect to system libs.
+# Both binaries are static in respect to libburn.
+#
+# The script is to be run in the directory above the toplevel
+# directory of libburn (or cdrskin) development.
+#
+
+# The top level directory in the SVN snapshot is named
+intermediate="./libburn_pykix"
+
+# libburn source used: http://libburnia.pykix.org
+# Downloaded by:
+# $ svn co http://libburnia-svn.pykix.org/libburn/tags/... $intermediate
+# packed up in a tarball just to save it from inadverted changes by
+# $ tar czf libburn_svn.tgz $intermediate
+original="./libburn_svn_release.tgz"
+# Historic moments:
+# original="./libburn_svn_A60815.tgz"
+# original="./libburn_cdrskin_A60819.tgz"
+
+
+# My changes are in $changes , mainly in $changes/cdrskin
+changes="./libburn-release"
+
+skin_release="1.4.4"
+patch_level=""
+# patch_level=".pl00"
+skin_rev="$skin_release""$patch_level"
+
+# The result directory and the name of the result tarballs
+target="./cdrskin-${skin_release}"
+cdrskin_tarball="./cdrskin-${skin_rev}.tar.gz"
+cdrskin_tarball_svn="./cdrskin-${skin_rev}.svn.tar.gz"
+
+# (This once earned me an embarrassingly blooping source tarball)
+# compile_dir="$changes"
+
+compile_dir="$target"
+compile_cmd="./cdrskin/compile_cdrskin.sh"
+compile_static_opts="-static"
+compile_result="cdrskin/cdrskin"
+
+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_dynamic="cdrskin_${skin_rev}-amd64-debian8_0"
+bintarget_static="$bintarget_dynamic"-static
+
+if test -d "$changes"
+then
+ dummy=dummy
+else
+ echo "$0 : FATAL : no directory $changes" >&2
+ exit 1
+fi
+
+for i in "$target" "$intermediate"
+do
+ if test -e "$i"
+ then
+ echo "$0 : FATAL : already existing $i" >&2
+ exit 2
+ fi
+done
+
+if test -f "$original"
+then
+ dummy=dummy
+else
+ echo "$0 : FATAL : no file $original" >&2
+ exit 3
+fi
+
+
+# Unpack SVN snapshot.
+tar xzf "$original"
+
+
+# Rename the directory to the cdrskin name
+mv "$intermediate" "$target"
+
+
+# Copy the changes from the development tree
+#
+cdrskin_dir="$changes"/cdrskin
+libburn_dir="$changes"/libburn
+cdrskin_target="$target"/cdrskin
+libburn_target="$target"/libburn
+
+# Create version timestamp
+# timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
+# echo "$timestamp"
+# echo '#define Cdrskin_timestamP "'"$timestamp"'"' >"$cdrskin_dir"/cdrskin_timestamp.h
+
+# Add the cdrskin files
+if test -e "$cdrskin_target"
+then
+ rm -rf "$cdrskin_target"
+fi
+cp -a "$cdrskin_dir" "$cdrskin_target"
+
+# Remove copied vim.swp and binaries
+rm "$cdrskin_target"/.*.swp
+rm "$cdrskin_target"/.*.swo
+rm "$cdrskin_target"/*.o
+rm "$cdrskin_target"/cdrfifo
+rm "$cdrskin_target"/cdrskin
+rm "$cdrskin_target"/cleanup
+for i in std new make old
+do
+ if test -e "$cdrskin_target"/cdrskin_"$i"
+ then
+ rm "$cdrskin_target"/cdrskin_"$i"
+ fi
+done
+
+# Remove eventual SVN stuff from cdrskin directory
+for i in .deps .dirstamp .libs
+do
+ if test -e "$cdrskin_target"/"$i"
+ then
+ rm -rf "$cdrskin_target"/"$i"
+ fi
+done
+
+# Remove GIFs of cdrskin_eng.html
+rm "$cdrskin_target"/doener_*.gif "$cdrskin_target"/doener_*.png
+
+# Remove automatically generated HTML man page
+rm "$cdrskin_target"/man_1_cdrskin.html
+
+# Remove all add_ts_changes_to_libburn besides this one
+for i in "$cdrskin_target"/add_ts_changes_to_libburn*
+do
+ if test $(basename "$0") = $(basename "$i")
+ then
+ dummy=dummy
+ else
+ rm $i
+ fi
+done
+
+# Remove libcevap
+rm -rf "$target"/libcevap
+
+
+# Remove unwanted SVN stuff (TODO: avoid downloading it)
+for i in "$target"/.svn "$target"/*/.svn
+do
+ if test "$i" = "$target"'/*/.svn'
+ then
+ dummy=dummy
+ else
+ if test -e "$i"
+ then
+ rm -rf "$i"
+ fi
+ fi
+done
+
+
+# Make SVN state tarball for the libburn team
+tar czf "$cdrskin_tarball_svn" "$target"
+
+
+# Get over dependecy on autotools. Rely only on cc, make et. al.
+# This is not the same as "make dist" but i can do it without
+# having to evaluate the quality of said "make dist"
+#
+( cd "$target" ; ./bootstrap )
+
+# Remove unwanted stuff after bootstrap
+for i in "$target"/autom4te.cache
+do
+ if echo "$i" | grep '\*' >/dev/null
+ then
+ dummy=dummy
+ else
+ if test -e "$i"
+ then
+ rm -rf "$i"
+ fi
+ fi
+done
+
+# 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"
+
+# Produce a static and a dynamic binary, and a HTML man page
+(
+ cd "$compile_dir" || exit 1
+ ./configure
+ make
+ "$compile_cmd" -O2 -do_strip
+ cp "$compile_result" "../$bintarget_dynamic"
+ if test -n "$compile_static_opts"
+ then
+ "$compile_cmd" $compile_static_opts -O2 -do_strip
+ cp "$compile_result" "../$bintarget_static"
+ fi
+ "$man_to_html_cmd"
+ mv "$man_page_html" ..
+)
+
+# Remove the build area
+# Disable this for debugging the merge process
+rm -rf "$target"
+
+# Show the result
+./"$bintarget_dynamic" -version
+./"$bintarget_static" -version
+ls -l "$cdrskin_tarball"
+ls -l "$bintarget_dynamic"
+ls -l "$bintarget_static"
+ls -l $(basename "$man_page_html")
+
diff --git a/libburn/branches/1.4.6/cdrskin/add_ts_changes_to_libburn_1_4_5 b/libburn/branches/1.4.6/cdrskin/add_ts_changes_to_libburn_1_4_5
new file mode 100755
index 00000000..ef9d3d5b
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/add_ts_changes_to_libburn_1_4_5
@@ -0,0 +1,247 @@
+#!/bin/sh
+
+set -x
+
+# This script documents how this cdrskin version was derived from
+# a vanilla libburn version. It is not intended nor needed for any
+# use of cdrskin but included here only to show the technical
+# relationship between both projects - which are close friends
+# and issue roughly the same software.
+#
+# Package maintainers are advised to cover rather libburn than
+# cdrskin unless they put only emphasis on the cdrecord emulation
+# provided by cdrskin. libburn contains cdrskin - cdrskin is an
+# oscillating, friendly and coordinated fork of libburn.
+#
+# Script results are a source tarball and two binaries
+# one dynamic and one static in respect to system libs.
+# Both binaries are static in respect to libburn.
+#
+# The script is to be run in the directory above the toplevel
+# directory of libburn (or cdrskin) development.
+#
+
+# The top level directory in the SVN snapshot is named
+intermediate="./libburn_pykix"
+
+# libburn source used: http://libburnia-project.org
+# Downloaded by:
+# $ 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"
+# Historic moments:
+# original="./libburn_svn_A60815.tgz"
+# original="./libburn_cdrskin_A60819.tgz"
+
+
+# My changes are in $changes , mainly in $changes/cdrskin
+changes="./libburn-develop"
+
+skin_release="1.4.5"
+patch_level=""
+skin_rev="$skin_release""$patch_level"
+
+# The result directory and the name of the result tarballs
+target="./cdrskin-${skin_release}"
+cdrskin_tarball="./cdrskin-${skin_rev}.tar.gz"
+cdrskin_tarball_svn="./cdrskin-${skin_rev}.svn.tar.gz"
+
+# (This once earned me an embarrassingly blooping source tarball)
+# compile_dir="$changes"
+
+compile_dir="$target"
+compile_cmd="./cdrskin/compile_cdrskin.sh"
+compile_static_opts="-static"
+compile_result="cdrskin/cdrskin"
+
+man_to_html_cmd="./cdrskin/convert_man_to_html.sh"
+man_page_html="cdrskin/man_1_cdrskin.html"
+
+# bintarget_dynamic="cdrskin_${skin_rev}-amd64-suse10_2"
+bintarget_dynamic="cdrskin_${skin_rev}-amd64-debian8_0"
+bintarget_static="$bintarget_dynamic"-static
+
+if test -d "$changes"
+then
+ dummy=dummy
+else
+ echo "$0 : FATAL : no directory $changes" >&2
+ exit 1
+fi
+
+for i in "$target" "$intermediate"
+do
+ if test -e "$i"
+ then
+ echo "$0 : FATAL : already existing $i" >&2
+ exit 2
+ fi
+done
+
+if test -f "$original"
+then
+ dummy=dummy
+else
+ echo "$0 : FATAL : no file $original" >&2
+ exit 3
+fi
+
+
+# Unpack SVN snapshot.
+tar xzf "$original"
+
+
+# Rename the directory to the cdrskin name
+mv "$intermediate" "$target"
+
+
+# Copy the changes from the development tree
+#
+cdrskin_dir="$changes"/cdrskin
+libburn_dir="$changes"/libburn
+cdrskin_target="$target"/cdrskin
+libburn_target="$target"/libburn
+
+# Create version timestamp
+timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
+echo "$timestamp"
+echo '#define Cdrskin_timestamP "'"$timestamp"'"' >"$cdrskin_dir"/cdrskin_timestamp.h
+
+# Add the cdrskin files
+if test -e "$cdrskin_target"
+then
+ rm -rf "$cdrskin_target"
+fi
+cp -a "$cdrskin_dir" "$cdrskin_target"
+
+# Remove copied vim.swp and binaries
+rm "$cdrskin_target"/.*.swp
+rm "$cdrskin_target"/.*.swo
+rm "$cdrskin_target"/*.o
+rm "$cdrskin_target"/cdrfifo
+rm "$cdrskin_target"/cdrskin
+rm "$cdrskin_target"/cleanup
+for i in std new make old
+do
+ if test -e "$cdrskin_target"/cdrskin_"$i"
+ then
+ rm "$cdrskin_target"/cdrskin_"$i"
+ fi
+done
+
+# Remove eventual SVN stuff from cdrskin directory
+for i in .deps .dirstamp .libs
+do
+ if test -e "$cdrskin_target"/"$i"
+ then
+ rm -rf "$cdrskin_target"/"$i"
+ fi
+done
+
+# Remove GIFs of cdrskin_eng.html
+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
+ if test $(basename "$0") = $(basename "$i")
+ then
+ dummy=dummy
+ else
+ rm $i
+ fi
+done
+
+# Remove unwanted SVN stuff (TODO: avoid downloading it)
+for i in "$target"/.svn "$target"/*/.svn
+do
+ if test "$i" = "$target"'/*/.svn'
+ then
+ dummy=dummy
+ else
+ if test -e "$i"
+ then
+ rm -rf "$i"
+ fi
+ fi
+done
+
+
+# Make SVN state tarball for the libburn team
+tar czf "$cdrskin_tarball_svn" "$target"
+
+
+# Get over dependecy on autotools. Rely only on cc, make et. al.
+# This is not the same as "make dist" but i can do it without
+# having to evaluate the quality of said "make dist"
+#
+( cd "$target" ; ./bootstrap )
+
+# Remove unwanted stuff after bootstrap
+for i in "$target"/autom4te.cache
+do
+ if echo "$i" | grep '\*' >/dev/null
+ then
+ dummy=dummy
+ else
+ if test -e "$i"
+ then
+ rm -rf "$i"
+ fi
+ fi
+done
+
+# 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"
+
+# Produce a static and a dynamic binary, and a HTML man page
+(
+ cd "$compile_dir" || exit 1
+ ./configure
+ make
+ "$compile_cmd" -libburn_svn -O2 -do_strip
+ cp "$compile_result" "../$bintarget_dynamic"
+ if test -n "$compile_static_opts"
+ then
+ "$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" ..
+)
+
+# Remove the build area
+# Disable this for debugging the merge process
+rm -rf "$target"
+
+# Show the result
+./"$bintarget_dynamic" -version
+./"$bintarget_static" -version
+ls -l "$cdrskin_tarball"
+ls -l "$bintarget_dynamic"
+ls -l "$bintarget_static"
+ls -l $(basename "$man_page_html")
+
diff --git a/libburn/branches/1.4.6/cdrskin/cdrecord_spy.sh b/libburn/branches/1.4.6/cdrskin/cdrecord_spy.sh
new file mode 100755
index 00000000..54d7c344
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/cdrecord_spy.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Spying on the call to cdrecord.
+#
+# Move $(which cdrecord) to $(dirname $(which cdrecord))/real_cdrecord .
+# Install this sript instead. (Do not forget to revoke this after the test.)
+#
+
+# The report target is set in variable rt.
+# The default is this file :
+rt=/tmp/cdrecord_spy_log
+
+# To use a bystanding xterm as target i find out the pty address by
+# executing in that terminal
+# sleep 12345
+# and then running in another terminal
+# ps -ef | grep 'sleep 12345'
+# which answers something like
+# thomas 21303 30518 0 14:02 pts/23 00:00:00 sleep 12345
+# thomas 21421 30523 0 14:02 pts/24 00:00:00 grep sleep 12345
+# from which i learn that pts/23 is sleeping 12345. Now sleep can be aborted.
+#
+# rt=/dev/pts/23
+
+echo '------------------------------------- cdrecord_spy 0.1.0 -------' >>"$rt"
+date >>"$rt"
+echo '----------------------------------------------------------------' >>"$rt"
+echo "$0" >>"$rt"
+for i in "$@"
+do
+ echo "$i" >>"$rt"
+done
+echo '------------------------------------- cdrecord_spy 0.1.0 - end -' >>"$rt"
+
+real_cdrecord "$@"
+
+
diff --git a/libburn/branches/1.4.6/cdrskin/cdrfifo.c b/libburn/branches/1.4.6/cdrskin/cdrfifo.c
new file mode 100644
index 00000000..167dbbb3
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/cdrfifo.c
@@ -0,0 +1,1313 @@
+/*
+ cdrfifo.c , Copyright 2006 - 2016 Thomas Schmitt
+
+ A fd-to-fd or fd-to-memory fifo to be used within cdrskin or independently.
+ By chaining of fifo objects, several fifos can be run simultaneously
+ in fd-to-fd mode. Modes are controlled by parameter flag of
+ Cdrfifo_try_to_work().
+
+ Provided under GPL license within cdrskin and under BSD license elsewise.
+*/
+
+/*
+ Compile as standalone tool :
+ cc -g -o cdrfifo -DCdrfifo_standalonE cdrfifo.c
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef Cdrfifo_standalonE
+/* <<< until release of 0.7.4 : for Libburn_has_open_trac_srC */
+#include "../libburn/libburn.h"
+#endif
+
+#include "cdrfifo.h"
+
+
+/* Macro for creation of arrays of objects (or single objects) */
+#define TSOB_FELD(typ,anz) (typ *) calloc(anz, sizeof(typ));
+
+
+#define Cdrfifo_buffer_chunK 2048
+
+/** Number of follow-up fd pairs */
+#define Cdrfifo_ffd_maX 100
+
+
+/* 1= enable , 0= disable status messages to stderr
+ 2= report each
+*/
+static int Cdrfifo_debuG= 0;
+
+
+struct CdrfifO {
+ int chunk_size;
+
+ int source_fd;
+ double in_counter;
+
+ double fd_in_counter;
+ double fd_in_limit;
+
+ char *buffer;
+ int buffer_size;
+ int buffer_is_full;
+ int write_idx;
+ int read_idx;
+
+ int dest_fd;
+ double out_counter;
+
+ struct timeval start_time;
+ double speed_limit;
+
+ /* statistics */
+ double interval_counter;
+ struct timeval interval_start_time;
+ double interval_start_counter;
+ int total_min_fill;
+ int interval_min_fill;
+
+ double put_counter;
+ double get_counter;
+ 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 */
+ int follow_up_fds[Cdrfifo_ffd_maX][2];
+
+ /* index of first byte in buffer which does not belong to predecessor fd */
+ int follow_up_eop[Cdrfifo_ffd_maX];
+ /* if follow_up_eop[i]==buffer_size : read_idx was 0 when this was set */
+ int follow_up_was_full_buffer[Cdrfifo_ffd_maX];
+
+ /* index of first byte in buffer which belongs to [this] fd pair */
+ int follow_up_sod[Cdrfifo_ffd_maX];
+
+ /* values for fd_in_limit */
+ double follow_up_in_limits[Cdrfifo_ffd_maX];
+
+ /* number of defined follow-ups */
+ int follow_up_fd_counter;
+
+ /* index of currently active (i.e. reading) follow-up */
+ int follow_up_fd_idx;
+
+
+ /* (simultaneous) peer chaining */
+ struct CdrfifO *next;
+ struct CdrfifO *prev;
+
+ /* rank in peer chain */
+ int chain_idx;
+};
+
+
+/** Create a fifo object.
+ @param ff Returns the address of the new object.
+ @param source_fd Filedescriptor opened to a readable data stream.
+ @param dest_fd Filedescriptor opened to a writable data stream.
+ To work with libburn, it needs to be attached to a
+ struct burn_source object.
+ @param chunk_size Size of buffer block for a single transaction (0=default)
+ @param buffer_size Size of fifo buffer
+ @param flag bit0= Debugging verbosity
+ @return 1 on success, <=0 on failure
+*/
+int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
+ int chunk_size, int buffer_size, int flag)
+{
+ struct CdrfifO *o;
+ struct timezone tz;
+ int i;
+
+ (*ff)= o= TSOB_FELD(struct CdrfifO,1);
+ if(o==NULL)
+ return(-1);
+ if(chunk_size<=0)
+ chunk_size= Cdrfifo_buffer_chunK;
+ o->chunk_size= chunk_size;
+ if(buffer_size%chunk_size)
+ buffer_size+= chunk_size-(buffer_size%chunk_size);
+ o->source_fd= source_fd;
+ o->in_counter= 0.0;
+ o->fd_in_counter= 0;
+ o->fd_in_limit= -1.0;
+ o->buffer= NULL;
+ o->buffer_is_full= 0;
+ o->buffer_size= buffer_size;
+ o->write_idx= 0;
+ o->read_idx= 0;
+ o->dest_fd= dest_fd;
+ o->out_counter= 0.0;
+ memset(&(o->start_time),0,sizeof(o->start_time));
+ gettimeofday(&(o->start_time),&tz);
+ o->speed_limit= 0.0;
+ o->interval_counter= 0.0;
+ memset(&(o->interval_start_time),0,sizeof(o->interval_start_time));
+ gettimeofday(&(o->interval_start_time),&tz);
+ o->interval_start_counter= 0.0;
+ o->total_min_fill= buffer_size;
+ o->interval_min_fill= buffer_size;
+ o->put_counter= 0.0;
+ 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; ifollow_up_fds[i][0]= o->follow_up_fds[i][1]= -1;
+ o->follow_up_eop[i]= o->follow_up_sod[i]= -1;
+ o->follow_up_was_full_buffer[i]= 0;
+ o->follow_up_in_limits[i]= -1.0;
+ }
+ o->follow_up_fd_counter= 0;
+ o->follow_up_fd_idx= -1;
+ o->next= o->prev= NULL;
+ o->chain_idx= 0;
+
+#ifdef Libburn_has_open_trac_srC
+ o->buffer= burn_os_alloc_buffer((size_t) buffer_size, 0);
+#else
+ o->buffer= TSOB_FELD(char,buffer_size);
+#endif /* ! Libburn_has_open_trac_srC */
+
+ if(o->buffer==NULL)
+ goto failed;
+ return(1);
+failed:;
+ Cdrfifo_destroy(ff,0);
+ return(-1);
+}
+
+
+/** Close any output fds */
+int Cdrfifo_close(struct CdrfifO *o, int flag)
+{
+ int i;
+
+ if(o->dest_fd!=-1)
+ close(o->dest_fd);
+ o->dest_fd= -1;
+ for(i=0; ifollow_up_fd_counter; i++) {
+ if(o->follow_up_fds[i][1]!=-1)
+ close(o->follow_up_fds[i][1]);
+ o->follow_up_fds[i][1]= -1;
+ }
+ return(1);
+}
+
+
+/** Release from memory a fifo object previously created by Cdrfifo_new().
+ @param ff The victim (gets returned as NULL, call can stand *ff==NULL))
+ @param flag Bitfield for control purposes:
+ bit0= do not close destination fd
+*/
+int Cdrfifo_destroy(struct CdrfifO **ff, int flag)
+/* flag
+ bit0= do not close destination fd
+*/
+{
+ struct CdrfifO *o;
+
+ o= *ff;
+ if(o==NULL)
+ return(0);
+ if(o->next!=NULL)
+ o->next->prev= o->prev;
+ if(o->prev!=NULL)
+ o->prev->next= o->next;
+ if(!(flag&1))
+ Cdrfifo_close(o,0);
+
+ /* 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)
+#ifdef Libburn_has_open_trac_srC
+ burn_os_free_buffer(o->buffer, o->buffer_size, 0);
+#else
+ free((char *) o->buffer);
+#endif /* Libburn_has_open_trac_srC */
+
+ free((char *) o);
+ (*ff)= NULL;
+ return(1);
+}
+
+
+int Cdrfifo_get_sizes(struct CdrfifO *o, int *chunk_size, int *buffer_size,
+ int flag)
+{
+ *chunk_size= o->chunk_size;
+ *buffer_size= o->buffer_size;
+ return(1);
+}
+
+/** Set a speed limit for buffer output.
+ @param o The fifo object
+ @param bytes_per_second >0 catch up slowdowns over the whole run time
+ <0 catch up slowdowns only over one interval
+ =0 disable speed limit
+*/
+int Cdrfifo_set_speed_limit(struct CdrfifO *o, double bytes_per_second,
+ int flag)
+{
+ o->speed_limit= bytes_per_second;
+ return(1);
+}
+
+
+/** Set a fixed size for input in order to cut off any unwanted tail
+ @param o The fifo object
+ @param idx index for fds attached via Cdrfifo_attach_follow_up_fds(),
+ first attached is 0, <0 directs limit to active fd limit
+ (i.e. first track is -1, second track is 0, third is 1, ...)
+*/
+int Cdrfifo_set_fd_in_limit(struct CdrfifO *o, double fd_in_limit, int idx,
+ int flag)
+{
+ if(idx<0) {
+ o->fd_in_limit= fd_in_limit;
+ return(1);
+ }
+ if(idx >= o->follow_up_fd_counter)
+ return(0);
+ o->follow_up_in_limits[idx]= fd_in_limit;
+ return(1);
+}
+
+
+int Cdrfifo_set_fds(struct CdrfifO *o, int source_fd, int dest_fd, int flag)
+{
+ o->source_fd= source_fd;
+ o->dest_fd= dest_fd;
+ return(1);
+}
+
+
+int Cdrfifo_get_fds(struct CdrfifO *o, int *source_fd, int *dest_fd, int flag)
+{
+ *source_fd= o->source_fd;
+ *dest_fd= o->dest_fd;
+ return(1);
+}
+
+
+/** Attach a further pair of input and output fd which will use the same
+ fifo buffer when its predecessors are exhausted. Reading will start as
+ soon as reading of the predecessor encounters EOF. Writing will start
+ as soon as all pending predecessor data are written.
+ @return index number of new item + 1, <=0 indicates error
+*/
+int Cdrfifo_attach_follow_up_fds(struct CdrfifO *o, int source_fd, int dest_fd,
+ int flag)
+{
+ if(o->follow_up_fd_counter>=Cdrfifo_ffd_maX)
+ return(0);
+ o->follow_up_fds[o->follow_up_fd_counter][0]= source_fd;
+ o->follow_up_fds[o->follow_up_fd_counter][1]= dest_fd;
+ o->follow_up_fd_counter++;
+ return(o->follow_up_fd_counter);
+}
+
+
+/** Attach a further fifo which shall be processed simultaneously with this
+ one by Cdrfifo_try_to_work() in fd-to-fd mode.
+*/
+int Cdrfifo_attach_peer(struct CdrfifO *o, struct CdrfifO *next, int flag)
+{
+ int idx;
+ struct CdrfifO *s;
+
+ for(s= o;s->prev!=NULL;s= s->prev); /* determine start of o-chain */
+ for(;o->next!=NULL;o= o->next); /* determine end of o-chain */
+ for(;next->prev!=NULL;next= next->prev); /* determine start of next-chain */
+ next->prev= o;
+ o->next= next;
+ for(idx= 0;s!=NULL;s= s->next)
+ s->chain_idx= idx++;
+ return(1);
+}
+
+
+static int Cdrfifo_tell_buffer_space(struct CdrfifO *o, int flag)
+{
+ if(o->buffer_is_full)
+ return(0);
+ if(o->write_idx>=o->read_idx)
+ return((o->buffer_size - o->write_idx) + o->read_idx);
+ return(o->read_idx - o->write_idx);
+}
+
+
+/** Obtain buffer state.
+ @param o The buffer object
+ @param fill Returns the number of pending payload bytes in the buffer
+ @param space Returns the number of unused buffer bytes
+ @param flag Unused yet
+ @return -1=error , 0=inactive , 1=reading and writing ,
+ 2=reading ended (but still writing)
+*/
+int Cdrfifo_get_buffer_state(struct CdrfifO *o,int *fill,int *space,int flag)
+/* return :
+ -1=error
+ 0=inactive
+ 1=reading and writing
+ 2=reading ended, still writing
+*/
+{
+ *space= Cdrfifo_tell_buffer_space(o,0);
+ *fill= o->buffer_size-(*space);
+ if(o->dest_fd==-1)
+ return(0);
+ if(o->source_fd<0)
+ return(2);
+ return(1);
+}
+
+
+int Cdrfifo_get_counters(struct CdrfifO *o,
+ double *in_counter, double *out_counter, int flag)
+{
+ *in_counter= o->in_counter;
+ *out_counter= o->out_counter;
+ return(1);
+}
+
+
+/** reads min_fill and begins measurement interval for next min_fill */
+int Cdrfifo_next_interval(struct CdrfifO *o, int *min_fill, int flag)
+{
+ struct timezone tz;
+
+ o->interval_counter++;
+ gettimeofday(&(o->interval_start_time),&tz);
+ o->interval_start_counter= o->out_counter;
+ *min_fill= o->interval_min_fill;
+ o->interval_min_fill= o->buffer_size - Cdrfifo_tell_buffer_space(o,0);
+ return(1);
+}
+
+
+int Cdrfifo_get_min_fill(struct CdrfifO *o, int *total_min_fill,
+ int *interval_min_fill, int flag)
+{
+ *total_min_fill= o->total_min_fill;
+ *interval_min_fill= o->interval_min_fill;
+ return(1);
+}
+
+
+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.
+*/
+int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
+ double *put_counter, double *get_counter,
+ double *empty_counter, double *full_counter,
+ int flag)
+{
+ *put_counter= o->put_counter;
+ *get_counter= o->get_counter;
+ *empty_counter= o->empty_counter;
+ *full_counter= o->full_counter;
+ return(1);
+}
+
+
+/** Adjust a given buffer fill value so it will not cross an eop boundary.
+ @param o The fifo to exploit.
+ @param buffer_fill The byte count to adjust.
+ @param eop_idx If eop boundary exactly hit: index of follow-up fd pair
+ @param flag Unused yet.
+ @return 0= nothing changed , 1= buffer_fill adjusted
+*/
+int Cdrfifo_eop_adjust(struct CdrfifO *o,int *buffer_fill, int *eop_idx,
+ int flag)
+{
+ int i,eop_is_near= 0,valid_fill;
+
+ *eop_idx= -1;
+ valid_fill= *buffer_fill;
+ for(i=0; i<=o->follow_up_fd_idx; i++) {
+ if(o->follow_up_eop[i]>=0 && o->follow_up_eop[i]>=o->read_idx) {
+ eop_is_near= 1;
+ if(o->follow_up_eop[i]buffer_size || o->read_idx>0) {
+ valid_fill= o->follow_up_eop[i]-o->read_idx;
+ o->follow_up_was_full_buffer[i]= 0;
+ } else {
+ /*
+ If an input fd change hit exactly the buffer end then follow_up_eop
+ points to buffer_size and not to 0. So it is time to switch output
+ pipes unless this is immediately after follow_up_eop was set and
+ read_idx was 0 (... if this is possible at all while write_idx is 0).
+ follow_up_was_full_buffer was set in this case and gets invalid as
+ soon as a non-0 read_idx is detected (see above).
+ */
+ if(o->follow_up_was_full_buffer[i])
+ valid_fill= o->buffer_size;
+ else
+ valid_fill= 0; /* the current pipe is completely served */
+ }
+ if(valid_fill==0)
+ *eop_idx= i;
+ else if(valid_fillchunk_size)
+ eop_is_near= 2; /* for debugging. to carry a break point */
+ break;
+ }
+ }
+ if(*buffer_fill>valid_fill)
+ *buffer_fill= valid_fill;
+ return(!!eop_is_near);
+}
+
+
+/* Perform pre-select activities of Cdrfifo_try_to_work() */
+static int Cdrfifo_setup_try(struct CdrfifO *o, struct timeval start_tv,
+ double start_out_counter, int *still_to_wait,
+ int *speed_limiter, int *ready_to_write,
+ fd_set *rds, fd_set *wts, int *max_fd, int flag)
+/* flag:
+ bit0= enable debug pacifier (same with Cdrfifo_debuG)
+ bit1= do not write, just fill buffer
+ bit2= fd-to-memory mode (else fd-to-fd mode):
+ rather than writing a chunk return it and its size in reply_*
+ bit3= with bit2: do not check destination fd for readiness
+*/
+{
+ int buffer_space,buffer_fill,eop_reached= -1,eop_is_near= 0,was_closed;
+ int fd_buffer_fill, eop_reached_counter= 0;
+ struct timeval current_tv;
+ struct timezone tz;
+ double diff_time,diff_counter,limit,min_wait_time;
+
+setup_try:;
+ buffer_space= Cdrfifo_tell_buffer_space(o,0);
+ fd_buffer_fill= buffer_fill= o->buffer_size - buffer_space;
+
+#ifdef NIX
+ fprintf(stderr,"cdrfifo_debug: o->write_idx=%d o->read_idx=%d o->source_fd=%d\n",o->write_idx,o->read_idx,o->source_fd);
+ if(buffer_fill>10)
+ sleep(1);
+#endif
+
+ if(o->follow_up_fd_idx>=0)
+ eop_is_near= Cdrfifo_eop_adjust(o,&fd_buffer_fill,&eop_reached,0);
+
+ if(fd_buffer_fill<=0 && (o->source_fd==-1 || eop_reached>=0) ) {
+ was_closed= 0;
+ if(o->dest_fd!=-1 && !(flag&4))
+ close(o->dest_fd);
+ if(o->dest_fd<0)
+ was_closed= 1;
+ else
+ o->dest_fd= -1;
+
+ if(eop_reached>=0) { /* switch to next output fd */
+ o->dest_fd= o->follow_up_fds[eop_reached][1];
+ if(Cdrfifo_debuG)
+ fprintf(stderr,"\ncdrfifo %d: new fifo destination fd : %d\n",
+ o->chain_idx,o->dest_fd);
+ o->read_idx= o->follow_up_sod[eop_reached];
+ o->follow_up_eop[eop_reached]= -1;
+ eop_is_near= 0;
+ eop_reached= -1;
+ eop_reached_counter= 0;
+ goto setup_try;
+ } else {
+ /* work is really done */
+ if((!was_closed) && ((flag&1)||Cdrfifo_debuG))
+ fprintf(stderr,
+ "\ncdrfifo %d: w=%d r=%d | b=%d s=%d | i=%.f o=%.f (done)\n",
+ o->chain_idx,o->write_idx,o->read_idx,buffer_fill,buffer_space,
+ o->in_counter,o->out_counter);
+ return(2);
+ }
+ } else if(eop_reached>=0)
+ eop_reached_counter++;
+ if(o->interval_counter>0) {
+ if(o->total_min_fill>buffer_fill && o->source_fd>=0)
+ o->total_min_fill= buffer_fill;
+ if(o->interval_min_fill>buffer_fill)
+ o->interval_min_fill= buffer_fill;
+ }
+ *speed_limiter= 0;
+ if(o->speed_limit!=0) {
+ gettimeofday(¤t_tv,&tz);
+ if(o->speed_limit>0) {
+ diff_time= ((double) current_tv.tv_sec)-((double) o->start_time.tv_sec)+
+ (((double) current_tv.tv_usec)-((double) o->start_time.tv_usec))*1e-6;
+ diff_counter= o->out_counter;
+ limit= o->speed_limit;
+ } else if(flag&4) {
+ if(o->interval_start_time.tv_sec==0)
+ o->interval_start_time= start_tv;
+ diff_time= ((double) current_tv.tv_sec)
+ - ((double) o->interval_start_time.tv_sec)
+ + (((double) current_tv.tv_usec)
+ -((double) o->interval_start_time.tv_usec))*1e-6;
+ diff_counter= o->out_counter - o->interval_start_counter;
+ limit= -o->speed_limit;
+ } else {
+ diff_time= ((double) current_tv.tv_sec) - ((double) start_tv.tv_sec)
+ + (((double) current_tv.tv_usec)
+ -((double)start_tv.tv_usec))*1e-6;
+ diff_counter= o->out_counter - start_out_counter;
+ limit= -o->speed_limit;
+ }
+ if(diff_time>0.0)
+ if(diff_counter/diff_time>limit) {
+ min_wait_time= (diff_counter/limit - diff_time)*1.0e6;
+ if(min_wait_time<*still_to_wait)
+ *still_to_wait= min_wait_time;
+ if(*still_to_wait>0)
+ *speed_limiter= 1;
+ }
+ }
+ if(o->source_fd>=0) {
+ if(buffer_space>0) {
+ FD_SET((o->source_fd),rds);
+ if(*max_fdsource_fd)
+ *max_fd= o->source_fd;
+ } else if(o->interval_counter>0)
+ o->full_counter++;
+ }
+ *ready_to_write= 0;
+ if(o->dest_fd>=0 && (!(flag&2)) && !*speed_limiter) {
+ if(fd_buffer_fill>=o->chunk_size || o->source_fd<0 || eop_is_near) {
+ if((flag&(4|8))==(4|8)) {
+ *still_to_wait= 0;
+ *ready_to_write= 1;
+ } else {
+ FD_SET((o->dest_fd),wts);
+ if(*max_fddest_fd)
+ *max_fd= o->dest_fd;
+ }
+ } else if(o->interval_counter>0)
+ o->empty_counter++;
+ }
+ return(1);
+}
+
+
+/* Perform post-select activities of Cdrfifo_try_to_work() */
+static int Cdrfifo_transact(struct CdrfifO *o, fd_set *rds, fd_set *wts,
+ char *reply_buffer, int *reply_count, int flag)
+/* flag:
+ bit0= enable debug pacifier (same with Cdrfifo_debuG)
+ bit1= do not write, just fill buffer
+ bit2= fd-to-memory mode (else fd-to-fd mode):
+ rather than writing a chunk return it and its size in reply_*
+ bit3= with bit2: do not check destination fd for readiness
+return: <0 = error , 0 = idle , 1 = did some work
+*/
+{
+ double buffer_space;
+ int can_read,can_write= 0,ret,did_work= 0,idx,sod, eop_idx;
+
+ buffer_space= Cdrfifo_tell_buffer_space(o,0);
+ if(o->dest_fd>=0) if(FD_ISSET((o->dest_fd),wts)) {
+ can_write= o->buffer_size - buffer_space;
+ if(can_write>o->chunk_size)
+ can_write= o->chunk_size;
+ if(o->read_idx+can_write > o->buffer_size)
+ can_write= o->buffer_size - o->read_idx;
+ if(o->follow_up_fd_idx>=0) {
+ Cdrfifo_eop_adjust(o,&can_write,&eop_idx,0);
+ if(can_write<=0)
+ goto after_write;
+ }
+ if(flag&4) {
+ memcpy(reply_buffer,o->buffer+o->read_idx,can_write);
+ *reply_count= ret= can_write;
+ } else {
+ ret= write(o->dest_fd,o->buffer+o->read_idx,can_write);
+ }
+ if(ret==-1) {
+
+ /* >>> handle broken pipe */;
+ fprintf(stderr,"\ncdrfifo %d: on write: errno=%d , \"%s\"\n",
+ o->chain_idx,errno,
+ errno==0?"-no error code available-":strerror(errno));
+
+ if(!(flag&4))
+ close(o->dest_fd);
+ o->dest_fd= -1;
+ {ret= -1; goto ex;}
+ }
+ did_work= 1;
+ o->get_counter++;
+ o->out_counter+= can_write;
+ o->read_idx+= can_write;
+ if(o->read_idx>=o->buffer_size)
+ o->read_idx= 0;
+ o->buffer_is_full= 0;
+ }
+after_write:;
+ if(o->source_fd>=0) if(FD_ISSET((o->source_fd),rds)) {
+ can_read= o->buffer_size - o->write_idx;
+
+#ifdef Libburn_has_open_trac_srC
+
+ /* ts A91115
+ This chunksize must be aligned to filesystem blocksize.
+ */
+#define Cdrfifo_o_direct_chunK 32768
+
+ if(o->write_idx < o->read_idx && o->write_idx + can_read > o->read_idx)
+ can_read= o->read_idx - o->write_idx;
+ if(o->fd_in_limit>=0.0)
+ if(can_read > o->fd_in_limit - o->fd_in_counter)
+ can_read= o->fd_in_limit - o->fd_in_counter;
+ /* Make sure to read with properly aligned size */
+ if(can_read > Cdrfifo_o_direct_chunK)
+ can_read= Cdrfifo_o_direct_chunK;
+ else if(can_read < Cdrfifo_o_direct_chunK)
+ can_read= -1;
+ ret= 0;
+ if(can_read>0)
+ ret= read(o->source_fd,o->buffer+o->write_idx,can_read);
+ if(can_read < 0) {
+ /* waiting for a full Cdrfifo_o_direct_chunK to fit */
+ if(can_write <= 0 && o->dest_fd >= 0) {
+ fd_set rds,wts,exs;
+ struct timeval wt;
+
+ FD_ZERO(&rds);
+ FD_ZERO(&wts);
+ FD_ZERO(&exs);
+ FD_SET((o->dest_fd),&wts);
+ wt.tv_sec= 0;
+ wt.tv_usec= 10000;
+ select(o->dest_fd + 1,&rds, &wts, &exs, &wt);
+
+ }
+ } else
+
+#else /* Libburn_has_open_trac_srC */
+
+ if(can_read>o->chunk_size)
+ can_read= o->chunk_size;
+ if(o->write_idxread_idx && o->write_idx+can_read > o->read_idx)
+ can_read= o->read_idx - o->write_idx;
+ if(o->fd_in_limit>=0.0)
+ if(can_read > o->fd_in_limit - o->fd_in_counter)
+ can_read= o->fd_in_limit - o->fd_in_counter;
+ ret= 0;
+ if(can_read>0)
+ ret= read(o->source_fd,o->buffer+o->write_idx,can_read);
+
+#endif /* ! Libburn_has_open_trac_srC */
+
+ if(ret==-1) {
+
+ /* >>> handle input error */;
+ fprintf(stderr,"\ncdrfifo %d: on read: errno=%d , \"%s\"\n",
+ o->chain_idx,errno,
+ errno==0?"-no error code available-":strerror(errno));
+
+ o->source_fd= -1;
+ } else if(ret==0) { /* eof */
+ /* activate eventual follow-up source fd */
+ if(Cdrfifo_debuG || (flag&1))
+ fprintf(stderr,"\ncdrfifo %d: on read(%d,buffer,%d): eof\n",
+ o->chain_idx,o->source_fd,can_read);
+ if(o->follow_up_fd_idx+1 < o->follow_up_fd_counter) {
+ idx= ++(o->follow_up_fd_idx);
+ o->source_fd= o->follow_up_fds[idx][0];
+ /* End-Of-Previous */
+ if(o->write_idx==0) {
+ o->follow_up_eop[idx]= o->buffer_size;
+
+ /* A70304 : can this happen ? */
+ o->follow_up_was_full_buffer[idx]= (o->read_idx==0);
+
+ if(Cdrfifo_debuG || (flag&1))
+ fprintf(stderr,"\ncdrfifo %d: write_idx 0 on eop: read_idx= %d\n",
+ o->chain_idx,o->read_idx);
+
+ } else
+ o->follow_up_eop[idx]= o->write_idx;
+ /* Start-Of-Data . Try to start at next full chunk */
+ sod= o->write_idx;
+ if(o->write_idx%o->chunk_size)
+ sod+= o->chunk_size - (o->write_idx%o->chunk_size);
+ /* but do not catch up to the read pointer */
+ if((o->write_idx<=o->read_idx && o->read_idx<=sod) || sod==o->read_idx)
+ sod= o->write_idx;
+ if(sod>=o->buffer_size)
+ sod= 0;
+ o->follow_up_sod[idx]= sod;
+ o->write_idx= sod;
+ o->fd_in_counter= 0;
+ o->fd_in_limit= o->follow_up_in_limits[idx];
+ if(Cdrfifo_debuG || (flag&1))
+ fprintf(stderr,"\ncdrfifo %d: new fifo source fd : %d\n",
+ o->chain_idx,o->source_fd);
+ } else {
+ o->source_fd= -1;
+ }
+ } else {
+ did_work= 1;
+ o->put_counter++;
+ o->in_counter+= ret;
+ o->fd_in_counter+= ret;
+ o->write_idx+= ret;
+ if(o->write_idx>=o->buffer_size)
+ o->write_idx= 0;
+ if(o->write_idx==o->read_idx)
+ o->buffer_is_full= 1;
+ }
+ }
+ ret= !!did_work;
+ex:;
+ return(ret);
+}
+
+
+/** Check for pending data at the fifo's source file descriptor and wether the
+ fifo is ready to take them. Simultaneously check the buffer for existing
+ data and the destination fd for readiness to accept some. If so, a small
+ chunk of data is transferred to and/or from the fifo.
+ This is done for the given fifo object and all members of its next-chain.
+ The check and transactions are repeated until a given timespan has elapsed.
+ libburn applications call this function in the burn loop instead of sleep().
+ It may also be used instead of read(). Then it returns as soon as an output
+ transaction would be performed. See flag:bit2.
+ @param o The fifo object
+ @param wait_usec The time in microseconds after which the function shall
+ return.
+ @param reply_buffer with bit2: Returns write-ready buffer chunk and must
+ be able to take at least chunk_size bytes
+ @param reply_count with bit2: Returns number of writeable bytes in reply
+ @param flag Bitfield for control purposes:
+ bit0= Enable debug pacifier (same with Cdrfifo_debuG)
+ bit1= Do not write, just fill buffer
+ bit2= fd-to-memory mode (else fd-to-fd mode):
+ Rather than writing a chunk return it and its size.
+ No simultaneous processing of chained fifos.
+ bit3= With bit2: do not check destination fd for readiness
+ @return <0 = error , 0 = idle , 1 = did some work , 2 = all work is done
+*/
+int Cdrfifo_try_to_work(struct CdrfifO *o, int wait_usec,
+ char *reply_buffer, int *reply_count, int flag)
+{
+ struct timeval wt,start_tv,current_tv;
+ struct timezone tz;
+ fd_set rds,wts,exs;
+ int ready,ret,max_fd= -1,buffer_space,dummy,still_active= 0;
+ int did_work= 0,elapsed,still_to_wait,speed_limiter= 0,ready_to_write= 0;
+ double start_out_counter;
+ struct CdrfifO *ff;
+
+ start_out_counter= o->out_counter;
+ gettimeofday(&start_tv,&tz);
+ still_to_wait= wait_usec;
+ if(flag&4)
+ *reply_count= 0;
+
+try_again:;
+ /* is there still a destination open ? */
+ for(ff= o; ff!=NULL; ff= ff->next)
+ if(ff->dest_fd!=-1)
+ break;
+ if(ff==NULL)
+ return(2);
+ FD_ZERO(&rds);
+ FD_ZERO(&wts);
+ FD_ZERO(&exs);
+
+ for(ff= o; ff!=NULL; ff= ff->next) {
+ ret= Cdrfifo_setup_try(ff,start_tv,start_out_counter,
+ &still_to_wait,&speed_limiter,&ready_to_write,
+ &rds,&wts,&max_fd,flag&15);
+ if(ret<=0)
+ return(ret);
+ else if(ret==2) {
+ /* This fifo is done */;
+ } else
+ still_active= 1;
+ if(flag&2)
+ break;
+ }
+ if(!still_active)
+ return(2);
+
+ if(still_to_wait>0 || max_fd>=0) {
+ wt.tv_sec= still_to_wait/1000000;
+ wt.tv_usec= still_to_wait%1000000;
+ ready= select(max_fd+1,&rds,&wts,&exs,&wt);
+ } else
+ ready= 0;
+ if(ready<=0) {
+ if(!ready_to_write)
+ goto check_wether_done;
+ FD_ZERO(&rds);
+ }
+ if(ready_to_write)
+ FD_SET((o->dest_fd),&wts);
+
+ for(ff= o; ff!=NULL; ff= ff->next) {
+ ret= Cdrfifo_transact(ff,&rds,&wts,reply_buffer,reply_count,flag&15);
+ if(ret<0)
+ goto ex;
+ if(ret>0)
+ did_work= 1;
+ if(flag&2)
+ break;
+ }
+
+check_wether_done:;
+ if((flag&4) && *reply_count>0)
+ {ret= 1; goto ex;}
+ gettimeofday(¤t_tv,&tz);
+ elapsed= (current_tv.tv_sec-start_tv.tv_sec)*1000000 +
+ (((int) current_tv.tv_usec) - ((int) start_tv.tv_usec));
+ still_to_wait= wait_usec-elapsed;
+ if(still_to_wait>0)
+ goto try_again;
+ ret= !!did_work;
+ex:;
+ if(flag&4) {
+ gettimeofday(¤t_tv,&tz);
+ elapsed= (current_tv.tv_sec - o->interval_start_time.tv_sec)*1000000
+ + (((int) current_tv.tv_usec)
+ - ((int) o->interval_start_time.tv_usec));
+ } else
+ elapsed= wait_usec;
+ if(elapsed>=wait_usec) {
+ if((flag&1)||Cdrfifo_debuG>=2) {
+ fprintf(stderr,"\n");
+ for(ff= o; ff!=NULL; ff= ff->next) {
+ buffer_space= Cdrfifo_tell_buffer_space(ff,0);
+ fprintf(stderr,
+ "cdrfifo %d: w=%d r=%d | b=%d s=%d | i=%.f o=%.f\n",
+ ff->chain_idx,ff->write_idx,ff->read_idx,
+ ff->buffer_size-buffer_space,buffer_space,
+ ff->in_counter,ff->out_counter);
+ }
+ }
+ if(flag&4)
+ Cdrfifo_next_interval(o,&dummy,0);
+ }
+ return(ret);
+}
+
+
+/** Fill the fifo as far as possible without writing to destination fd */
+int Cdrfifo_fill(struct CdrfifO *o, int size, int flag)
+{
+ int ret,fill= 0,space,state;
+
+ while(1) {
+ state= Cdrfifo_get_buffer_state(o,&fill,&space,0);
+ if(state==-1) {
+
+ /* >>> handle error */;
+
+ return(0);
+ } else if(state!=1)
+ break;
+ if(space<=0)
+ break;
+ if(size>=0 && fill>=size)
+ break;
+ ret= Cdrfifo_try_to_work(o,100000,NULL,NULL,2);
+ if(ret<0) {
+
+ /* >>> handle error */;
+
+ return(0);
+ }
+ 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);
+}
+
+
+int Cdrfifo_close_all(struct CdrfifO *o, int flag)
+{
+ struct CdrfifO *ff;
+
+ if(o==NULL)
+ return(0);
+ for(ff= o; ff->prev!=NULL; ff= ff->prev);
+ for(; ff!=NULL; ff= ff->next)
+ Cdrfifo_close(ff,0);
+ return(1);
+}
+
+
+
+#ifdef Cdrfifo_standalonE
+
+/* ---------------------------------------------------------------------- */
+
+/** Application example. See also cdrskin.c */
+
+
+double Scanf_io_size(char *text, int flag)
+/*
+ bit0= default value -1 rather than 0
+*/
+{
+ int c;
+ double ret= 0.0;
+
+ if(flag&1)
+ ret= -1.0;
+ if(text[0]==0)
+ return(ret);
+ sscanf(text,"%lf",&ret);
+ c= text[strlen(text)-1];
+ if(c=='k' || c=='K') ret*= 1024.0;
+ if(c=='m' || c=='M') ret*= 1024.0*1024.0;
+ if(c=='g' || c=='G') ret*= 1024.0*1024.0*1024.0;
+ if(c=='t' || c=='T') ret*= 1024.0*1024.0*1024.0*1024.0;
+ if(c=='p' || c=='P') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0;
+ if(c=='e' || c=='E') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0*1024.0;
+ if(c=='s' || c=='S') ret*= 2048.0;
+ return(ret);
+}
+
+
+/* This is a hardcoded test mock-up for two simultaneous fifos of which the
+ one runs with block size 2048 and feeds the other which runs with 2352.
+ Both fifos have the same number of follow_up pipes (tracks) which shall
+ be connected 1-to-1.
+*/
+int Test_mixed_bs(char **paths, int path_count,
+ int fs_size, double speed_limit, double interval, int flag)
+/*
+ bit0= debugging verbousity
+*/
+{
+ int fd_in[100],fd_out[100],ret,pipe_fds[100][2];
+ int i,iv,stall_counter= 0,cycle_counter= 0.0;
+ char target_path[80];
+ double in_counter, out_counter, prev_in= -1.0, prev_out= -1.0;
+ struct CdrfifO *ff_in= NULL, *ff_out= NULL;
+
+ if(path_count<1)
+ return(2);
+ Cdrfifo_new(&ff_in,fd_in[0],fd_out[0],2048,fs_size,0);
+ for(i= 0; ichain_idx,ret);
+ if(ret<0)
+ return(-7);
+ break;
+ }
+ cycle_counter++;
+ Cdrfifo_get_counters(ff_in, &in_counter, &out_counter, 0);
+ if(prev_in == in_counter && prev_out == out_counter)
+ stall_counter++;
+ prev_in= in_counter;
+ prev_out= out_counter;
+ }
+ return(1);
+}
+
+
+/* This is a hardcoded test mock-up for two simultaneous fifos of which the
+ first one simulates the cdrskin fifo feeding libburn and the second one
+ simulates libburn and the burner at given speed. Both have two fd pairs
+ (i.e. tracks). The tracks are read from /u/test/cdrskin/in_[12] and
+ written to /u/test/cdrskin/out_[12].
+*/
+int Test_multi(int fs_size, double speed_limit, double interval, int flag)
+/*
+ bit0= debugging verbousity
+*/
+{
+ int fd_in[4],fd_out[4],ret,pipe_fds[4][2];
+ int i,iv;
+ struct CdrfifO *ff1= NULL,*ff2= NULL;
+
+ /* open four pairs of fds */
+ fd_in[0]= open("/u/test/cdrskin/in_1",O_RDONLY);
+ fd_in[1]= open("/u/test/cdrskin/in_2",O_RDONLY);
+ fd_out[2]= open("/u/test/cdrskin/out_1",
+ O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+ fd_out[3]= open("/u/test/cdrskin/out_2",
+ O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+ if(pipe(pipe_fds[0])==-1)
+ return(-3);
+ if(pipe(pipe_fds[1])==-1)
+ return(-3);
+ fd_out[0]= pipe_fds[0][1];
+ fd_out[1]= pipe_fds[1][1];
+ fd_in[2]= pipe_fds[0][0];
+ fd_in[3]= pipe_fds[1][0];
+ for(i=0;i<4;i++) {
+ if(fd_in[i]==-1)
+ return(-1);
+ if(fd_out[i]==-1)
+ return(-2);
+ }
+
+ /* Create two fifos with two sequential fd pairs each and chain them for
+ simultaneous usage. */
+ Cdrfifo_new(&ff1,fd_in[0],fd_out[0],2048,fs_size,0);
+ Cdrfifo_new(&ff2,fd_in[2],fd_out[2],2048,2*1024*1024,0); /*burner cache 2 MB*/
+ if(ff1==NULL || ff2==NULL)
+ return(-3);
+ Cdrfifo_set_speed_limit(ff2,speed_limit,0);
+ ret= Cdrfifo_attach_follow_up_fds(ff1,fd_in[1],fd_out[1],0);
+ if(ret<=0)
+ return(-4);
+ ret= Cdrfifo_attach_follow_up_fds(ff2,fd_in[3],fd_out[3],0);
+ if(ret<=0)
+ return(-4);
+ Cdrfifo_attach_peer(ff1,ff2,0);
+
+ /* Let the fifos work */
+ iv= interval*1e6;
+ while(1) {
+ ret= Cdrfifo_try_to_work(ff1,iv,NULL,NULL,flag&1);
+ if(ret<0 || ret==2) { /* <0 = error , 2 = work is done */
+ fprintf(stderr,"\ncdrfifo %d: fifo ended work with ret=%d\n",
+ ff1->chain_idx,ret);
+ if(ret<0)
+ return(-7);
+ break;
+ }
+ }
+ return(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ int i,ret,exit_value= 0,verbous= 1,fill_buffer= 0,min_fill,fifo_percent,fd;
+ double fs_value= 4.0*1024.0*1024.0,bs_value= 2048,in_counter,out_counter;
+ double interval= 1.0,speed_limit= 0.0;
+ char output_file[4096];
+ struct CdrfifO *ff= NULL;
+
+ strcpy(output_file,"-");
+ fd= 1;
+
+ for(i= 1; i1024.0*1024.0*1024.0) {
+ fprintf(stderr,
+ "cdrfifo: FATAL : bs=N expects a size between 1 and 1g\n");
+ {exit_value= 2; goto ex;}
+ }
+ } else if(strncmp(argv[i],"fl=",3)==0) {
+ sscanf(argv[i]+3,"%d",&fill_buffer);
+ fill_buffer= !!fill_buffer;
+ } else if(strncmp(argv[i],"fs=",3)==0) {
+ fs_value= Scanf_io_size(argv[i]+3,0);
+ if(fs_value<=0 || fs_value>1024.0*1024.0*1024.0) {
+ fprintf(stderr,
+ "cdrfifo: FATAL : fs=N expects a size between 1 and 1g\n");
+ {exit_value= 2; goto ex;}
+ }
+ } else if(strncmp(argv[i],"iv=",3)==0) {
+ sscanf(argv[i]+3,"%lf",&interval);
+ if(interval<0.001 || interval>1000.0)
+ interval= 1;
+ } else if(strncmp(argv[i],"of=",3)==0) {
+ if(strcmp(argv[i]+3,"-")==0 || argv[i][3]==0)
+ continue;
+ fd= open(argv[i]+3,O_WRONLY|O_CREAT);
+ if(fd<0) {
+ fprintf(stderr,"cdrfifo: FATAL : cannot open output file '%s'\n",
+ argv[i]+3);
+ fprintf(stderr,"cdrfifo: errno=%d , \"%s\"\n",
+ errno,errno==0?"-no error code available-":strerror(errno));
+ {exit_value= 4; goto ex;}
+ }
+ } else if(strncmp(argv[i],"sl=",3)==0) {
+ speed_limit= Scanf_io_size(argv[i]+3,0);
+ } else if(strncmp(argv[i],"vb=",3)==0) {
+ sscanf(argv[i]+3,"%d",&verbous);
+
+ } else if(strcmp(argv[i],"-mixed_bs_test")==0) {
+
+ ret= Test_mixed_bs(argv+i+1,argc-i-1,
+ (int) fs_value,speed_limit,interval,(verbous>=2));
+ fprintf(stderr,"Test_mixed_bs(): ret= %d\n",ret);
+ exit(ret<0);
+
+ } else if(strcmp(argv[i],"-multi_test")==0) {
+
+ if(speed_limit==0.0)
+ speed_limit= 10*150*1024;
+ ret= Test_multi((int) fs_value,speed_limit,interval,(verbous>=2));
+ fprintf(stderr,"Test_multi(): ret= %d\n",ret);
+ exit(ret<0);
+
+ } else {
+ fprintf(stderr,"cdrfifo 0.3 : stdin-to-stdout fifo buffer.\n");
+ fprintf(stderr,"usage : %s [bs=block_size] [fl=fillfirst]\n",argv[0]);
+ fprintf(stderr," [fs=fifo_size] [iv=interval] [of=output_file]\n");
+ fprintf(stderr," [sl=bytes_per_second_limit] [vb=verbosity]\n");
+ fprintf(stderr,"fl=1 reads full buffer before writing starts.\n");
+ fprintf(stderr,"sl>0 allows catch up for whole run time.\n");
+ fprintf(stderr,"sl<0 allows catch up for single interval.\n");
+ fprintf(stderr,"vb=0 is silent, vb=2 is debug.\n");
+ fprintf(stderr,"example: cdrfifo bs=8k fl=1 fs=32m iv=0.1 sl=-5400k\n");
+ if(strcmp(argv[i],"-help")!=0 && strcmp(argv[i],"--help")!=0) {
+ fprintf(stderr,"\ncdrfifo: FATAL : option not recognized: '%s'\n",
+ argv[i]);
+ exit_value= 1;
+ }
+ goto ex;
+ }
+ }
+ if(verbous>=1) {
+ fprintf(stderr,
+ "cdrfifo: bs=%.lf fl=%d fs=%.lf iv=%lf of='%s' sl=%.lf vb=%d\n",
+ bs_value,fill_buffer,fs_value,interval,output_file,speed_limit,
+ verbous);
+ }
+
+ ret= Cdrfifo_new(&ff,0,fd,(int) bs_value,(int) fs_value,0);
+ if(ret<=0) {
+ fprintf(stderr,
+ "cdrfifo: FATAL : creation of fifo object with %.lf bytes failed\n",
+ fs_value);
+ {exit_value= 3; goto ex;}
+ }
+ if(speed_limit!=0.0)
+ Cdrfifo_set_speed_limit(ff,speed_limit,0);
+ if(fill_buffer) {
+ ret= Cdrfifo_fill(ff,0,0);
+ if(ret<=0) {
+ fprintf(stderr,
+ "cdrfifo: FATAL : initial filling of fifo buffer failed\n");
+ {exit_value= 4; goto ex;}
+ }
+ }
+ while(1) {
+ ret= Cdrfifo_try_to_work(ff,(int) (interval*1000000.0),
+ NULL,NULL,(verbous>=2));
+ if(ret<0) {
+ fprintf(stderr,"\ncdrfifo: FATAL : fifo aborted. errno=%d , \"%s\"\n",
+ errno,errno==0?"-no error code available-":strerror(errno));
+ {exit_value= 4; goto ex;}
+ } else if(ret==2) {
+ if(verbous>=1) {
+ double put_counter,get_counter,empty_counter,full_counter;
+ int total_min_fill;
+ Cdrfifo_get_counters(ff,&in_counter,&out_counter,0);
+ fprintf(stderr,"\ncdrfifo: done : %.lf bytes in , %.lf bytes out\n",
+ in_counter,out_counter);
+ Cdrfifo_get_min_fill(ff,&total_min_fill,&min_fill,0);
+ fifo_percent= 100.0*((double) total_min_fill)/fs_value;
+ if(fifo_percent==0 && total_min_fill>0)
+ fifo_percent= 1;
+ Cdrfifo_get_cdr_counters(ff,&put_counter,&get_counter,
+ &empty_counter,&full_counter,0);
+ fprintf(stderr,"cdrfifo: fifo had %.lf puts and %.lf gets.\n",
+ put_counter,get_counter);
+ fprintf(stderr,
+"cdrfifo: fifo was %.lf times empty and %.lf times full, min fill was %d%%.\n",
+ empty_counter,full_counter,fifo_percent);
+ }
+ break;
+ }
+ Cdrfifo_next_interval(ff,&min_fill,0);
+ }
+
+ex:;
+ Cdrfifo_destroy(&ff,0);
+ exit(exit_value);
+}
+
+
+#endif /* Cdrfifo_standalonE */
+
diff --git a/libburn/branches/1.4.6/cdrskin/cdrfifo.h b/libburn/branches/1.4.6/cdrskin/cdrfifo.h
new file mode 100644
index 00000000..d7b0c5df
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/cdrfifo.h
@@ -0,0 +1,171 @@
+
+/*
+ cdrfifo.c , Copyright 2006 - 2016 Thomas Schmitt
+
+ A fd-to-fd or fd-to-memory fifo to be used within cdrskin or independently.
+ By chaining of fifo objects, several fifos can be run simultaneously
+ in fd-to-fd mode. Modes are controlled by parameter flag of
+ Cdrfifo_try_to_work().
+
+ Provided under GPL license within cdrskin and under BSD license elsewise.
+*/
+
+#ifndef Cdrfifo_headerfile_includeD
+#define Cdrfifo_headerfile_includeD
+
+
+/** The fifo buffer which will smoothen the data stream from data provider
+ to data consumer. Although this is not a mandatory lifesaver for modern
+ burners any more, a fifo can speed up burning of data which is delivered
+ with varying bandwidths (e.g. compressed archives created on the fly
+ or mkisofs running at its speed limit.).
+ This structure is opaque to applications and may only be used via
+ the Cdrfifo*() methods described in cdrfifo.h .
+*/
+struct CdrfifO;
+
+
+/** Create a fifo object.
+ @param ff Returns the address of the new object.
+ @param source_fd Filedescriptor opened to a readable data stream.
+ @param dest_fd Filedescriptor opened to a writable data stream.
+ To work with libburn, it needs to be attached to a
+ struct burn_source object.
+ @param chunk_size Size of buffer block for a single transaction (0=default)
+ @param buffer_size Size of fifo buffer
+ @param flag bit0= Debugging verbosity
+ @return 1 on success, <=0 on failure
+*/
+int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
+ int chunk_size, int buffer_size, int flag);
+
+/** Release from memory a fifo object previously created by Cdrfifo_new().
+ @param ff The victim (gets returned as NULL, call can stand *ff==NULL)
+ @param flag Bitfield for control purposes:
+ bit0= do not close destination fd
+*/
+int Cdrfifo_destroy(struct CdrfifO **ff, int flag);
+
+/** Close any output fds */
+int Cdrfifo_close(struct CdrfifO *o, int flag);
+
+/** Close any output fds of o and its chain peers */
+int Cdrfifo_close_all(struct CdrfifO *o, int flag);
+
+int Cdrfifo_get_sizes(struct CdrfifO *o, int *chunk_size, int *buffer_size,
+ int flag);
+
+/** Set a speed limit for buffer output.
+ @param o The fifo object
+ @param bytes_per_second >0 catch up slowdowns over the whole run time
+ <0 catch up slowdowns only over one interval
+ =0 disable speed limit
+*/
+int Cdrfifo_set_speed_limit(struct CdrfifO *o, double bytes_per_second,
+ int flag);
+
+/** Set a fixed size for input in order to cut off any unwanted tail
+ @param o The fifo object
+ @param idx index for fds attached via Cdrfifo_attach_follow_up_fds(),
+ first attached is 0, <0 directs limit to active fd limit
+ (i.e. first track is -1, second track is 0, third is 1, ...)
+*/
+int Cdrfifo_set_fd_in_limit(struct CdrfifO *o, double fd_in_limit, int idx,
+ int flag);
+
+
+int Cdrfifo_set_fds(struct CdrfifO *o, int source_fd, int dest_fd, int flag);
+int Cdrfifo_get_fds(struct CdrfifO *o, int *source_fd, int *dest_fd, int flag);
+
+
+/** Attach a further pair of input and output fd which will use the same
+ fifo buffer when its predecessors are exhausted. Reading will start as
+ soon as reading of the predecessor encounters EOF. Writing will start
+ as soon as all pending predecessor data are written.
+ @return index number of new item + 1, <=0 indicates error
+*/
+int Cdrfifo_attach_follow_up_fds(struct CdrfifO *o, int source_fd, int dest_fd,
+ int flag);
+
+/** Attach a further fifo which shall be processed simultaneously with this
+ one by Cdrfifo_try_to_work() in fd-to-fd mode.
+*/
+int Cdrfifo_attach_peer(struct CdrfifO *o, struct CdrfifO *next, int flag);
+
+
+/** Obtain buffer state.
+ @param o The buffer object
+ @param fill Returns the number of pending payload bytes in the buffer
+ @param space Returns the number of unused buffer bytes
+ @param flag unused yet
+ @return -1=error , 0=inactive , 1=reading and writing ,
+ 2=reading ended (but still writing)
+*/
+int Cdrfifo_get_buffer_state(struct CdrfifO *o,int *fill,int *space,int flag);
+
+int Cdrfifo_get_counters(struct CdrfifO *o,
+ double *in_counter, double *out_counter, int flag);
+
+/** reads min_fill and begins measurement interval for next min_fill */
+int Cdrfifo_next_interval(struct CdrfifO *o, int *min_fill, int flag);
+
+int Cdrfifo_get_min_fill(struct CdrfifO *o, int *total_min_fill,
+ int *interval_min_fill, int flag);
+
+int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
+ double *put_counter, double *get_counter,
+ double *empty_counter, double *full_counter,
+ int flag);
+
+/** Inquire the eventually detected size of an eventual ISO-9660 file system
+ @return 0=no ISO 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
+ data and the destination fd for readiness to accept some. If so, a small
+ chunk of data is transferred to and/or from the fifo.
+ This is done for the given fifo object and all members of its next-chain.
+ The check and transactions are repeated until a given timespan has elapsed.
+ libburn applications call this function in the burn loop instead of sleep().
+ It may also be used instead of read(). Then it returns as soon as an output
+ transaction would be performed. See flag:bit2.
+ @param o The fifo object
+ @param wait_usec The time in microseconds after which the function shall
+ return.
+ @param reply_buffer with bit2: Returns write-ready buffer chunk and must
+ be able to take at least chunk_size bytes
+ @param reply_count with bit2: Returns number of writeable bytes in reply_pt
+ @param flag Bitfield for control purposes:
+ bit0= Enable debug pacifier (same with Cdrfifo_debuG)
+ bit1= Do not write, just fill buffer
+ bit2= fd-to-memory mode (else fd-to-fd mode):
+ Rather than writing a chunk return it and its size.
+ No simultaneous processing of chained fifos.
+ bit3= With bit2: do not check destination fd for readiness
+ @return <0 = error , 0 = idle , 1 = did some work , 2 = all work is done
+*/
+int Cdrfifo_try_to_work(struct CdrfifO *o, int wait_usec,
+ char *reply_buffer, int *reply_count, int flag);
+
+/** Fill the fifo as far as possible without writing to destination fd.
+ @param size if >=0 : end filling after the given number of bytes
+ @return 1 on success, <=0 on failure
+*/
+int Cdrfifo_fill(struct CdrfifO *o, int size, int flag);
+
+
+#endif /* Cdrfifo_headerfile_includeD */
+
diff --git a/libburn/branches/1.4.6/cdrskin/cdrskin.1 b/libburn/branches/1.4.6/cdrskin/cdrskin.1
new file mode 100644
index 00000000..94bbdd88
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/cdrskin.1
@@ -0,0 +1,1807 @@
+.\" Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH CDRSKIN 1 "Version 1.4.5, Jul 30, 2016"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh disable hyphenation
+.\" .hy enable hyphenation
+.\" .ad l left justify
+.\" .ad b justify to both left and right margins
+.\" .nf disable filling
+.\" .fi enable filling
+.\" .br insert line break
+.\" .sp insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+cdrskin \- burns preformatted data to CD, DVD, and BD via libburn.
+.SH SYNOPSIS
+.B cdrskin
+.RI [ options | track_source_addresses ]
+.br
+.SH DESCRIPTION
+.PP
+.\" TeX users may be more comfortable with the \fB\fP and
+.\" \fI\fP escape sequences to invode bold face and italics,
+.\" respectively.
+.PP
+\fBcdrskin\fP is a program that provides some of cdrecord's options
+in a compatible way for CD media. With DVD and BD it has its own ways.
+You do not need to be superuser for its daily usage.
+.SS
+.B Overview of features:
+.br
+Blanking of CD-RW and DVD-RW.
+.br
+Formatting of DVD-RW, DVD+RW, DVD-RAM, BD.
+.br
+Burning of data tracks or audio tracks with CD-TEXT to CD,
+.br
+either in versatile Track at Once mode (TAO)
+.br
+or in Session at Once mode for seamless tracks.
+.br
+Multi session on CD (follow-up sessions in TAO only)
+.br
+or on DVD-R[W] (in Incremental mode) or DVD+R[/DL] or BD-R.
+.br
+Single session Disk-at-once on DVD-RW, DVD-R, DVD-R DL.
+.br
+Single session or emulated ISO-9660 multi-session
+.br
+on overwriteable DVD+RW, DVD-RW, DVD-RAM, BD-RE
+.br
+or on data file or block device.
+.br
+Extraction of audio tracks and CD-TEXT to hard disk files.
+.br
+Bus scan, burnfree, speed options, retrieving media info, padding, fifo.
+.br
+See section EXAMPLES at the end of this text.
+.SS
+.B General information paragraphs:
+.br
+Track recording model
+.br
+Write mode selection
+.br
+Recordable CD Media
+.br
+Sequentially Recordable DVD or BD Media
+.br
+Overwriteable DVD or BD Media
+.br
+Drive preparation and addressing
+.br
+Emulated drives
+.SS
+.B Track recording model:
+.br
+The input-output entities which get processed are called tracks.
+A \fBtrack\fP stores a stream of bytes.
+.br
+More than one track can be burned by a single run of cdrskin.
+In the terms of the MMC standard all tracks written by the same run constitute
+a \fBsession\fP.
+.br
+Normally, each track is initiated by one track source address argument,
+which may either be "-" for standard input or the address of a readable file.
+Alternatively, option cuefile= may be used to read a session description
+from a text file and to read the session content from a single data file.
+.br
+If no write mode
+is given explicitly then one will be chosen which matches the peculiarities
+of track sources and the state of the output media.
+.PP
+Some media types can be kept appendable so that further tracks can
+be written to them in subsequent runs of cdrskin (see option -multi).
+Info about the addresses of burned tracks is kept in a table of
+content (TOC) on media and can be retrieved via cdrskin option -toc.
+This information is also used by the operating systems' CD-ROM read drivers.
+.PP
+In general there are two types of tracks: data and audio. They differ in
+sector size, throughput and readability via the systems' CD-ROM drivers
+and by music CD players. With DVD and BD there is only type data.
+.br
+If not explicitly option -audio is given, then any track is burned as type
+data, unless the track source is a file with suffix ".wav" or ".au" and has a
+header part which identifies it as MS-WAVE or SUN Audio with suitable
+parameters. Such files are burned as audio tracks by default.
+.PP
+While audio tracks just contain a given time span of acoustic vibrations,
+data tracks may have an arbitrary meaning. Nevertheless, ISO-9660 filesystems
+are established as a format which can represent a tree of directories and
+files on all major operating systems. Such filesystem images can be
+produced by programs mkisofs or genisoimage or xorriso.
+They can also be extended by follow-up tracks if prepared properly.
+See the man pages of said programs.
+cdrskin is able to fulfill the needs about their option -C.
+.br
+Another type of data track content are archive formats which originally
+have been developed for magnetic tapes. Only formats which mark a detectable
+end-of-archive in their data are suitable, though. Well tested are
+the archivers afio and star. Not suitable seems GNU tar.
+.SS
+.B Write mode selection:
+.br
+In general there are two approaches for writing media:
+.br
+A permissive mode selected by option
+.B -tao
+which needs no predicted track size and can use
+multi-session capabilities if offered by drive and medium.
+.br
+A more restrictive mode
+.B -sao
+(alias -dao) which usually demands a predictable track size and is not
+necessarily capable of multi-session. It can be used to write CD-TEXT and
+it is the only one that works with option cuefile=.
+.br
+If none of the options -dao, -tao or -sao is given then the program will
+try to choose a write mode which matches the defined recording job,
+the capabilities of the drive and the state of the present media.
+.br
+So the mentioning of write modes in the following paragraphs and in the
+examples is not so much a demand that the user shall choose one explicitly,
+but rather an illustration of what to expect with particular media types.
+.SS
+.B Recordable CD Media:
+.br
+CD-R can be initially written only once and eventually extended until they
+get closed (or are spoiled because they are overly full). After that they are
+read-only. Closing is done automatically unless option
+.B -multi
+is given which keeps the media appendable.
+.br
+Write mode
+-tao is able to use track sources of unpredictable length (like stdin) and
+to write further sessions to appendable media.
+-sao produces audio sessions with seamless tracks but needs predicted track
+sizes and cannot append sessions to media.
+.br
+CD-RW media can be blanked to make them re-usable for another
+round of overwriting. Usually
+.B blank=fast
+is the appropriate option.
+Blanking damages the previous content but does not
+make it completely unreadable. It is no effective privacy precaution.
+Multiple cycles of blanking and overwriting with random numbers might be
+needed.
+.SS
+.B Sequentially Recordable DVD or BD Media:
+.br
+Currently DVD-RW, DVD-R[DL], DVD+R[DL], and BD-R can be used for the Sequential
+recording model. It resembles the model of CD media. Only DVD-RW can be
+blanked and re-used from scratch.
+.br
+DVD-RW are sequential media if they are in state "Sequential Recording".
+The media must be either blank or appendable.
+Newly purchased DVD-RW and DVD-R media are in this state.
+Used DVD-RW get into blank sequential state by option
+.B blank=deformat_sequential .
+.br
+With DVD-R[W] two write modes may be available:
+.br
+Mode DAO has many restrictions. It does not work with
+appendable media, cannot do -multi and writes only a single track.
+The size of the
+track needs to be known in advance. So either its source has to be a disk file
+of recognizable size or the size has to be announced explicitly by options
+.B tsize=
+or
+.B tao_to_sao_tsize= .
+.br
+DAO is the only mode for DVD-R media which do not offer feature 21h Incremental
+Streaming (e.g. DVD-R DL). DAO may also be selected explicitly by option
+.B -sao .
+Program growisofs uses DAO on sequential DVD-R[W] media for maximum
+DVD-ROM/-Video compatibility.
+.br
+The other mode, Incremental Streaming, is the default write mode if
+it is available and if the restrictions of DAO would prevent the job.
+Incremental Streaming may be selected explicitly by option
+.B -tao
+as it resembles much CD TAO by accepting track sources of
+unpredicted length and being able to keep media appendable by option
+.B -multi . It does not work with DVD-R DL and minimally blanked DVD-RW.
+The only restriction towards CD-R[W] is the lack of support for -audio tracks.
+Multiple tracks per session are permissible.
+.br
+The write modes for DVD+R[/DL] and BD-R resemble those with DVD-R except that
+each track gets wrapped in an own session. There is no -dummy writing
+with DVD+R[/DL] or BD-R.
+.br
+Quite deliberately write mode -sao insists in the tradition of a predicted
+track size and blank media, whereas -tao writes the tracks open ended and
+can be applied to appendable media.
+.br
+BD-R may be formatted before first use to enable the Defect Management which
+might catch and repair some bad spots at the expense of slow speed
+even with flawless media.
+.br
+.B Note:
+Option -multi might make DVD media unreadable in some DVD-ROM drives.
+Best reader compatibility is achieved without it
+(i.e. by single session media).
+.SS
+.B Overwriteable DVD or BD Media:
+.br
+Currently types DVD+RW, DVD-RW, DVD-RAM and BD-RE can be overwritten via
+cdrskin.
+.br
+Option -audio is not allowed. Only one track is allowed.
+Option -multi cannot mark a recognizable end of overwriteable media.
+Therefore -multi is banned unless ISO-9660 images shall be expandable by help
+of option
+.B --grow_overwriteable_iso .
+Without this option or without an ISO-9660 filesystem image present
+on media, -toc does not return information about the media content and
+media get treated as blank regardless whether they hold data or not.
+.br
+Currently there is no difference between -sao and -tao. If ever, then -tao
+will be the mode which preserves the current behavior.
+.PP
+DVD+RW and DVD-RAM media need no special initial formatting. They offer a
+single continuous data area for blockwise random access. BD-RE need
+explicit formatting before use. See
+.B blank=as_needed
+or blank=format_defectmgt .
+.br
+DVD-RW are sold in state "Sequential Recording". To become suitable for the
+Overwriteable DVD recording model they need to get formatted to state
+"Restricted Overwrite". Then they behave much like DVD+RW. This formatting
+can be done by option
+.B blank=format_overwrite .
+.br
+Several programs like dvd+rw-format, cdrecord, wodim, or cdrskin
+can bring a DVD-RW out of overwriteable state so
+that it has to be formatted again. If in doubt, just give it a try.
+.SS
+.B Drive preparation and addressing:
+.br
+The drives, CD, DVD, or BD burners, are accessed via addresses which
+are specific to libburn and the operating system. Those addresses get listed
+by a run of \fBcdrskin --devices\fP or \fBcdrskin --device_links\fP.
+.br
+On Linux, they are device files which traditionally do not offer
+w-permissions for normal users. Because libburn needs rw-permission,
+it might be only the
+.B superuser
+who is able to get this list without further
+precautions.
+.br
+It is consensus that \fBchmod a+rw /dev/sr0\fP or \fBchmod a+rw /dev/hdc\fP
+is less security sensitive than chmod u+s,a+x /usr/bin/cdrskin. The risk for
+the drive is somewhat higher but the overall system is much less at stake.
+Consider to restrict rw-access to a single group which bundles the users who
+are allowed to use the burner drive (like group "floppy").
+.br
+For drive permission examples on Linux, FreeBSD, and Solaris,
+see cdrskin/README.
+.br
+.PP
+If you only got one CD capable drive then you may leave out cdrskin option
+\fBdev=\fP. Else you should use this option to address the drive you want.
+.br
+cdrskin option dev= not only accepts the listed addresses but also
+traditional cdrecord SCSI addresses which consist of three numbers:
+Bus,Target,Lun. On Linux there is also a related address family "ATA" which
+accesses IDE drives not under control of Linux SCSI drivers:
+ATA:Bus,Target,Lun.
+.br
+See option -scanbus for getting a list of cdrecord style addresses.
+.br
+Further are accepted: links to libburn-suitable device files,
+device files which have the same major and minor device number,
+and device files which have the same SCSI address parameters (e.g. /dev/sg0).
+.br
+.SS
+.B Emulated drives:
+.br
+Option
+.B --allow_emulated_drives
+enables addressing of pseudo-drives
+which get emulated on top of filesystem objects. Regular data files and
+block devices result in pseudo-drives which behave much like DVD-RAM.
+If the given address does not exist yet but its directory exists, then
+it gets created as regular file.
+Other file types like character devices or pipes result in pseudo-drives
+which behave much like blank DVD-R.
+The target file address is given after prefix "stdio:".
+.br
+E.g.: dev=stdio:/tmp/my_pseudo_drive
+.br
+Addresses of the form "stdio:/dev/fd/" are treated special. The
+number is read literally and used as open file descriptor. With
+dev="stdio:/dev/fd/1" the normal standard output of the program is
+redirected to stderr and the stream data of a burn run will appear on stdout.
+.br
+Not good for terminals ! Redirect it.
+.br
+Pseudo-drives support -dummy. Their reply with --tell_media_space can be utopic.
+-dummy burn runs touch the file but do not modify its data content.
+.br
+Note: --allow_emulated_drives is restricted to stdio:/dev/null if cdrskin
+is run by the
+.B superuser
+or if it has changed user identity via the
+.B setuid
+bit of its access permissions. The ban for the superuser can be lifted by a
+skillfully created file. See section FILES below.
+.br
+.SH OPTIONS
+.TP
+.BI \-\-help
+Show non-cdrecord compatible options.
+.TP
+.BI \-help
+Show cdrecord compatible options.
+.br
+Note that some of the help texts are quite wrong - for cdrecord as well as
+for cdrskin (e.g. -format, blank=, -load). They are, nevertheless, traditional
+indicators for the availability of the listed options. Some frontend programs
+make decisions after reading them.
+.TP
+.BI \-version
+Print cdrskin id line, compatibility lure line, libburn version, cdrskin
+version, version timestamp, build timestamp (if available), and then exit.
+.PP
+Alphabetical list of options which are intended to be compatible with
+original cdrecord by Joerg Schilling:
+.TP
+.BI \-atip
+Retrieve some info about media state. With CD-RW print "Is erasable".
+With DVD media print "book type:" and a media type text. With BD media
+print "Mounted Media:" and media type text.
+.TP
+.BI \-audio
+Announces that the subsequent tracks are to be burned as audio.
+The source is supposed to be uncompressed headerless PCM, 44100 Hz, 16 bit,
+stereo. For little-endian byte order (which is usual on PCs) use option
+-swab. Unless marked explicitly by option -data, input files with suffix
+".wav" are examined whether they have a header in MS-WAVE format confirming
+those parameters and eventually raw audio data get extracted and burned as
+audio track. Same is done for suffix ".au" and SUN Audio.
+.br
+Option -audio may be used only with CD media and not with DVD or BD.
+.TP
+.BI blank= type
+Blank a CD-RW, DVD-RW, or format a DVD-RW, DVD+RW, DVD-RAM, BD.
+This is combinable with burning in the same run of cdrskin.
+The type given with blank= selects the particular behavior:
+.RS
+.TP
+as_needed
+Try to make the media ready for writing from scratch. If it needs formatting,
+then format it. If it is not blank, then try to apply blank=fast.
+It is a reason to abort if the media cannot assume thoroughly writeable state,
+e.g. if it is non-blank write-once.
+.br
+This leaves unformatted DVD-RW in unformatted blank state. To format DVD-RW use
+blank=format_overwriteable. Blank unformatted BD-R stay unformatted.
+.br
+(Note: blank=as_needed is not an original cdrecord option.)
+.TP
+The following blank types are specific to particular media familes. Use them if special features are desired.
+.TP
+all
+Blank an entire CD-RW or an unformatted DVD-RW.
+(See also --prodvd_cli_compatible, --grow_overwriteable_iso)
+.TP
+fast
+Minimally blank an entire CD-RW or blank an unformatted DVD-RW.
+(See also --prodvd_cli_compatible, --grow_overwriteable_iso)
+.TP
+deformat_sequential
+Like blank=all but with the additional ability to blank overwriteable DVD-RW.
+This will destroy their formatting and make them sequentially recordable.
+Another peculiarity is the ability to blank media which appear already blank.
+This is similar to option -force but does not try to blank media other than
+recognizable CD-RW and DVD-RW.
+.br
+(Note: blank=deformat_* are not original cdrecord options.)
+.TP
+deformat_sequential_quickest
+Like blank=deformat_sequential but blanking DVD-RW only minimally.
+This is faster than full blanking but may yield media incapable of
+Incremental Streaming (-tao).
+.TP
+format_if_needed
+Format a media if it is not formatted yet,
+and if cdrskin supports formatting for the media type,
+and if formatting will not happen automatically during write.
+This currently applies to unformatted DVD-RW, DVD-RAM, BD-RE,
+and blank unformatted BD-R.
+Eventually the appropriate default formatting is chosen.
+If other media or states are encountered then nothing happens.
+.br
+The following formatting types are more specialized to particular
+media families.
+.TP
+format_overwrite
+Format a DVD-RW to "Restricted Overwrite". The user should bring some patience.
+.br
+(Note: blank=format_* are not original cdrecord options.)
+.TP
+format_overwrite_quickest
+Like format_overwrite without creating a 128 MiB trailblazer session.
+Leads to "intermediate" state which only supports sequential write
+beginning from address 0.
+The "intermediate" state ends after the first session of writing data.
+.TP
+format_overwrite_full
+For DVD-RW this is like format_overwrite but claims full media size
+rather than just 128 MiB.
+Most traditional formatting is attempted. No data get written.
+Much patience is required.
+.br
+This option treats already formatted media even if not option -force is given.
+.br
+For DVD+RW this is the only supported explicit formatting type. It provides
+complete "de-icing" so no reader slips on unwritten data areas.
+.TP
+format_defectmgt
+Format DVD-RAM or BD to reserve the default amount of spare blocks for
+defect management.
+.br
+The following format_defectmgt_* enable the user to submit wishes which
+nevertheless have to match one of the available formats. These formats are
+offered by the drive after examining the media.
+.TP
+format_defectmgt_cert_off
+Disable the usual media quality certification in order to save time and
+format to default size.
+The certification setting persists even if subsequent blank= options override
+the size of the format selection.
+.br
+Whether formatting without certification works properly depends much on the
+drive. One should check the "Format status:" from --list_formats afterwards.
+.TP
+format_defectmgt_cert_on
+Re-enable the usual media quality certification and format to default size.
+The certification setting persists like with format_defectmgt_cert_off.
+.br
+Whether there happens certification at all depends much on the media state
+and the actually selected format descriptor.
+.TP
+format_defectmgt_max
+Format DVD-RAM or BD to reserve a maximum number of spare blocks.
+.TP
+format_defectmgt_min
+Format DVD-RAM or BD to reserve a minimum number of spare blocks.
+It might be necessary to format format_defectmgt_none first in order to get
+offered the most minmal spare blocks sizes for format_defectmgt_min.
+.TP
+format_defectmgt_none
+Format DVD-RAM or BD-RE to the largest available payload in the hope to disable
+defect management at all. This may or may not have a speed increasing effect.
+Unformatted blank BD-R will be left unformatted.
+.TP
+format_defectmgt_payload_
+Format DVD-RAM or BD. The text after "format_defectmgt_payload_" gives a
+number of bytes, eventually with suffixes "s", "k", "m". The largest number
+of spare blocks will be chosen which enables at least the given payload size.
+.TP
+format_by_index_
+Format DVD-RW, DVD+RW, DVD-RAM or BD.
+The number after "format_by_index_" is used as index to the list of available
+format descriptors. This list can be obtained by option --list_formats.
+The numbers after text "Format idx" are the ones to be used with
+format_by_index_. Format descriptor lists are volatile. Do neither eject
+nor write the media between the run of --list_formats and the run of
+blank=format_by_index_ or else you may get a different format than desired.
+.TP
+help
+Print this list of blanking types.
+.RE
+.TP
+.BI \-checkdrive
+Retrieve some info about the addressed drive and then exit.
+Exits with non-zero value if the drive cannot be found and opened.
+.TP
+.BI \-copy
+Create the subsequent tracks with permission for an unlimited number of copies.
+.TP
+.BI cuefile= path
+Read a session description from a cue sheet file in CDRWIN format.
+Base the tracks on a single file which is given in the sheet by command FILE.
+To enable CD-TEXT from the cue sheet file, cdrskin option -text has to be
+present.
+.br
+cdrskin currently supports TRACK datatypes AUDIO and MODE1/2048 which may
+not be mixed.
+Data source may be of FILE type BINARY, MOTOROLA, or WAVE.
+.br
+Non-CDRWIN commands ARRANGER, COMPOSER, MESSAGE are supported.
+.br
+Cue sheet file commands CATALOG and ISRC may be overridden by option mcn=
+and by input_sheet_v07t= purpose specifiers "UPC / EAN" and "ISRC".
+This does not affect their appearance in CD-TEXT, but only on Q sub-channel.
+.br
+The track numbers may be overridden by option cd_start_tno=.
+.TP
+.BI \-dao
+Alias for option -sao. Write CD in Session at Once mode
+or DVD-R[W] in Disc-at-once mode.
+.TP
+.BI \-data
+Subsequent tracks are data tracks. This option is default and only needed
+to mark the end of the range of an eventual option -audio or -xa1.
+.br
+Options -mode2, -xa, and -xa2 get mapped to -data, not using the desired CD
+sector formats and thus not taking advantage of eventual higher payload.
+.BI \-xa1
+Subsequent tracks are data tracks with input suitable for CD-ROM XA mode 2
+form 1. This differs from -data input by 8 additional header bytes per block.
+cdrskin will not write CD-ROM XA but rather strip the header bytes and write as
+-data tracks.
+.TP
+.BI dev= target
+Set the address of the drive to use. Valid are at least the
+addresses listed with options --devices or --device_links,
+X,Y,Z addresses listed with option -scanbus,
+ATA:X,Y,Z addresses listed with options dev=ATA -scanbus,
+and volatile libburn drive numbers (numbering starts at "0").
+Other device file addresses which lead to the same drive might work too.
+.br
+If no dev= is given, volatile address "dev=0" is assumed. That is the first
+drive found being available. Better avoid this ambiguity on systems with more
+than one drive.
+.br
+The special target "help" lists hints about available addressing formats.
+Be aware that deprecated option --old_pseudo_scsi_adr may change the meaning
+of Bus,Target,Lun addresses.
+.TP
+.BI driveropts= opt
+Set "driveropts=noburnfree" to disable the drive's eventual protection
+mechanism against temporary lack of source data (i.e. buffer underrun).
+A drive that announces no such capabilities will not get them enabled anyway,
+even if attempted explicitly via "driveropts=burnfree".
+.TP
+.BI \-dummy
+Try to perform the drive operations without actually affecting the inserted
+media. There is no warranty that this will work with a particular combination
+of drive, media, and write mode. Blanking is prevented reliably, though.
+To avoid inadverted real burning, -dummy refuses burn runs on anything but
+CD-R[W], DVD-R[W], or emulated stdio-drives.
+.TP
+.BI \-eject
+Eject the disc after work is done.
+.TP
+.BI \-force
+Assume that the user knows better in situations when cdrskin or libburn are
+insecure about drive or media state. This includes the attempt to blank
+media which are classified as unknown or unsuitable, and the attempt to use
+write modes which libburn believes they are not supported by the drive.
+.br
+Another application is to enforce blanking or re-formatting of media
+which appear to be in the desired blank or format state already.
+.br
+This option enables a burn run with option -dummy even if libburn believes
+that drive and media will not simulate the write mode but will write for real.
+.br
+It enables a burn run where cdrskin expects to exceed the available media
+capacity.
+.br
+.B Caution:
+Use this only when in urgent need.
+.TP
+.BI \-format
+Same as blank=format_overwrite_full -force but restricted to DVD+RW.
+.TP
+.BI fs= size
+Set the fifo size to the given value. The value may have appended letters which
+multiply the preceding number:
+.br
+"k" or "K" = 1024 , "m" or "M" = 1024k , "g" or "G" = 1024m , "s" or "S" = 2048
+.br
+Set size to 0 in order to disable the fifo (default is "4m").
+.br
+The fifo buffers an eventual temporary surplus of track source data in order to
+provide the drive with a steady stream during times of temporary lack of track
+source supply.
+The larger the fifo, the longer periods of poor source supply can be
+compensated.
+But a large fifo needs substantial time to fill up if not curbed via
+option fifo_start_at=size.
+.TP
+.BI gracetime= seconds
+Set the grace time before starting to write. (Default is 0)
+.TP
+.BI -immed
+Equivalent to:
+.br
+modesty_on_drive=1:min_percent=75:max_percent=95
+.br
+The name of this cdrecord option stems from the "Immed" bit which can make some
+long running drive commands asynchronous and thus eases the load on some
+wiring hardware types. Regardless of option -immed, cdrskin uses asynchronous
+commands where possible and appropriate. To really disable asynchronous command
+execution, use option use_immed_bit=off .
+.TP
+.BI index= list
+Set a comma separated list of index start address numbers for the next track.
+This applies to CD SAO sessions only.
+.br
+The addresses count sectors from the start of the next track. The first number
+is for index 1 and must be 0. The following numbers have to be larger than
+their respective predecessors. Up to 99 numbers are allowed.
+.br
+Sector numbers are computed from Min:Sec:Frame addresses by
+.br
+ Sector = ((Min*60)+Sec)*75+Frame
+.br
+E.g.: "0,7512,20408" sets index 2 to 01:40:12 and index 3 to 04:32:08.
+.TP
+.BI -inq
+Print the identification of the drive and then exit.
+.TP
+.BI -isosize
+The next track following this option will try to obtain its source size from
+the header information out of the first few blocks of the source data.
+If these blocks indicate an ISO-9660 filesystem then its declared size
+will be used under the assumption that it is a single session filesystem.
+.br
+If not, then the burn run will be aborted.
+.br
+The range of -isosize is exactly one track. Further tracks may be preceded
+by further -isosize options, though. At least 15 blocks of padding will be
+added to each -isosize track. But be advised to rather use padsize=300k.
+.br
+This option can be performed on track sources which are regular files or block
+devices. For the first track of the session it can be performed on any type
+of source if there is a fifo of at least 64 kiB. See option fs= .
+.TP
+.BI isrc= text
+Set the ISRC for the next track source to the given text, which must be exactly
+13 characters long. It must comply to the format CCOOOYYSSSSS.
+.br
+CC is the country code. OOO is the owner code. Both may consist of capital
+letters A to Z and of decimal digits 0 to 9. YY depicts the year (00 to 99).
+SSSSS is the serial number (00000 to 99999).
+.br
+This option does not affect CD-TEXT but only the Q sub-channel.
+.TP
+.BI -load
+Load the media and exit. Exit value is 0 if any kind of media was found, non
+zero else. Note: Option -eject will unload the media even if -load is given.
+.TP
+.BI -lock
+Like option -load but leave the drive's eject button disabled if there is any
+media found and not option -eject is given.
+.br
+Use program "eject" or cdrskin -eject to get the tray out of the drive.
+Runs of programs like cdrecord, growisofs, wodim, cdrskin will not be hampered
+and normally enable the drive's eject button when they are done.
+.TP
+.BI mcn= text
+Set the CD Media Catalog Number to text, which must be exactly 13 characters
+long and should consist of decimal digits.
+.br
+This option does not affect CD-TEXT but only the Q sub-channel.
+.TP
+.BI minbuf= percentage
+Equivalent to:
+.br
+modesty_on_drive=1:min_percent=:max_percent=95
+.br
+Percentage is permissible between 25 and 95.
+.TP
+.BI -minfo
+Print information about the loaded media. This includes media type, writability
+state, and a quite readable table of content.
+.TP
+.BI msifile= path
+Run option -msinfo and copy the result line into the file given by path.
+Unlike -msinfo this option does not redirect all normal output away from
+standard output. But it may be combined with -msinfo to achieve this.
+.br
+Note: msifile=path is actually an option of wodim and not of cdrecord.
+.TP
+.BI \-msinfo
+Retrieve multi-session info for preparing a follow-up session by option -C
+of programs mkisofs, genisoimage, or xorriso -as mkisofs.
+Print result to standard output.
+This option redirects to stderr all message output except the one of option
+--tell_media_space and its own result string, which consists of two numbers.
+The result string shall be used as argument of option -C with said programs.
+It gives the start address of the most recent session and the predicted
+start address of the next session to be appended. The string is empty if
+the most recent session was not written with option -multi.
+.br
+To have a chance for working on overwriteable media, this option has to be
+accompanied by option --grow_overwriteable_iso.
+.TP
+.BI \-multi
+This option keeps CD, unformatted DVD-R[W], DVD+R, or BD-R appendable
+after the current session has been written.
+Without it the disc gets closed and may not be written any more - unless it
+is a -RW and gets blanked which causes loss of its content.
+.br
+The following sessions can only be written in -tao mode. -multi is prohibited
+with DVD-R[W] DAO write mode and on DVD-R DL media.
+Option --prodvd_cli_compatible eventually makes
+-multi tolerable but cannot make it work.
+.br
+In order to have all filesystem content accessible, the eventual ISO-9660
+filesystem of a follow-up
+session needs to be prepared in a special way by the filesystem formatter
+program. mkisofs and genisoimage expect particular info about the situation
+which can be retrieved by cdrskin option -msinfo.
+.br
+To retrieve an archive file which was written as follow-up session,
+you may use option -toc to learn about the "lba" of the desired track number.
+This lba is the address of the 2048 byte block where the archive begins.
+.br
+With overwriteable DVD or BD media, -multi cannot mark the end of the session.
+So when adding a new session this end has to be determined from the payload.
+Currently only ISO-9660 filesystems can be used that way. See option
+.B \--grow_overwriteable_iso
+for lifting the ban on -multi.
+.br
+Note: -multi might make DVD media unreadable in some DVD-ROM drives.
+.TP
+.BI \-nocopy
+Create subsequent tracks with permission for a single level of copies.
+I.e. those copies would then be marked by -scms as offering no permission
+for further copies.
+.TP
+.BI \-nopad
+Do not add trailing zeros to the data stream. Nevertheless, since there seems
+to be no use for audio tracks with incomplete last sector, this option applies
+only to data tracks. There it is default.
+.TP
+.BI \-nopreemp
+Indicate for subsequent tracks that they were mastered without pre-emphasis.
+.TP
+.BI \-pad
+Add 30 kiB of trailing zeros to each data track. (This is not sufficient to
+avoid problems with various CD-ROM read drivers.)
+.TP
+.BI padsize= size
+Add the given amount of trailing zeros to the next data track. This option
+gets reset to padsize=0 after that next track is written. It may be set
+again before the next track argument. About size specifiers, see option fs=.
+.TP
+.BI \-preemp
+Indicate for subsequent tracks that they were mastered with pre-emphasis.
+.TP
+.BI \-sao
+Write CD in Session At Once mode or sequential DVD-R[W] in Disc-at-once
+(DAO) mode.
+.br
+With CD this mode is able to put several audio tracks on media without
+producing audible gaps between them.
+.br
+With DVD-R[W] this mode can only write a single track.
+No -multi is allowed with DVD-R[W] -sao.
+.br
+-sao is permissible with overwriteable DVD, or DVD+R[/DL], or BD but actually
+only imposes restrictions without providing known advantages.
+.br
+-sao can only be used for tracks of fixely predicted size. This implies that
+track arguments which depict stdin or named pipes need to be preceded by
+option tsize= or by option tao_to_sao_tsize=.
+.br
+-sao cannot be used on appendable media.
+.TP
+.BI \-scanbus
+Scan the system for drives. On Linux the drives at /dev/s* and at /dev/hd*
+are to be scanned by two separate runs. One without dev= for /dev/s* and
+one with dev=ATA for /dev/hd* devices. (Option --drives lists all available
+drives in a single run.)
+.br
+Drives which are busy or which offer no rw-permission to the user of cdrskin
+are not listed. Busy drives get reported in form of warning messages.
+.br
+The useful fields in a result line are:
+.br
+Bus,Target,Lun Number) 'Vendor' 'Mode' 'Revision'
+.TP
+.BI \-scms
+Create subsequent tracks without permission for being copied. This is usually
+done for tracks which are copies of tracks that were marked with -nocopy
+(but not yet with -scms). So copies of copies are prohibited.
+.br
+This option gets reset by option -copy. Thus the combination -copy -nocopy
+means -nocopy surely without -scms.
+.TP
+.BI speed= number
+Set speed of drive. With data CD, 1x speed corresponds to a throughput of
+150,000 bytes/second. With DVD, 1x = 1,385,000 bytes/second.
+With BD 1x = 4,495,625 bytes/second.
+It is not an error to set a speed higher than is suitable for drive
+and media. One should stay within a realistic speed range, though.
+Special speed settings are:
+.br
+0 = minimal speed , -1 = maximal speed (default), text "any" = like -1.
+.TP
+.BI \-swab
+Announce that the raw audio data source of subsequent tracks is byte swapped
+versus the expectations of cdrecord. This option is suitable for audio where
+the least significant byte of a 16 bit word is first (little-endian, Intel).
+Most raw audio data on PC systems are available in this byte order.
+Less guesswork is needed if track sources are in format MS-WAVE in a file with
+suffix ".wav".
+.TP
+.BI \-tao
+Write CD in Track At Once (TAO) mode, sequential DVD-R[W] in Incremental
+Streaming mode, or DVD+R[/DL] without traditional -sao restrictions.
+This mode also applies pro-forma to overwriteable media
+.br
+Mode -tao can be used with track sources of unpredictable size, like standard
+input or named pipes. It is also the only mode that can be used for writing
+to appendable media which already hold data. With unformatted DVD-R[W] it is
+the only mode which can keep media appendable by option -multi.
+.br
+Mode -tao is not usable for minimally blanked DVD-RW and for DVD-R DL.
+.TP
+.BI \-text
+Enable writing of CD-TEXT attributes read by option cuefile=.
+Without option -text, cue sheet file command CDTEXTFILE will be ignored and
+no CD-TEXT attributes will be read from the file. Nevertheless, CATALOG and
+ISRC will have the same effect as options mcn= and isrc=.
+.TP
+.BI textfile= path
+Read CD-TEXT packs from the file depicted by path and put them into the
+Lead-in of the emerging session. This session has to be done by Session At Once
+(SAO) mode and may only contain audio tracks.
+.br
+path must lead to a regular file, which consists of an optional header of four
+bytes and one or more text packs of 18 bytes each. Suitable would be the
+file 'cdtext.dat' which gets extracted from CD media by options -vv -toc
+and shown in human readable form by -vvv -toc.
+.br
+The header, if present, must tell the file size minus 2, encoded as big-endian
+16 bit word. The other two bytes must be 0.
+.br
+If there is no 4-byte header, then a trailing 0-byte, as of Sony specification,
+is tolerated and ignored.
+.br
+A text pack consists of a pack type byte, a track number byte, a counter byte,
+a Block Number and Character Indicator byte, 12 text characters or data bytes,
+two optional CRC bytes. For details see libburn documentation file
+doc/cdtext.txt.
+.br
+By default, the input file is checked for correct CRC bytes. If all CRC bytes
+are 0, then the correct values get silently inserted. If there are non-zero
+CRC bytes, then a mismatch causes the abort of the burn run.
+This check can be disabled by option -force.
+.br
+Note that this option overrides option input_sheet_v07t= .
+.TP
+.BI \-toc
+Print the table of content (TOC) which describes the tracks recorded on disc.
+The output contains all info from option -atip plus lines which begin with
+"track:", the track number, the word "lba:" and a number which gives the
+start address of the track. Addresses are counted in CD sectors which with
+SAO or TAO data tracks hold 2048 bytes each.
+.br
+If verbosity is set to level 2 (-v -v) then the CD-TEXT packs from the lead-in
+of an audio CD get extracted and written into file 'cdtext.dat', if that file
+does not yet exist. Prepended is a 4 byte header, followed by one or more
+packs of 18 bytes each.
+.br
+Verbosity level 3 causes the CD-TEXT packs to be printed as hex numbers to
+standard output. Bytes 4 to 15 of certain pack types are printed as ASCII
+characters if they have values in the range of 32 to 126.
+.br
+See option textfile= for more information about the text pack format.
+.RS
+.TP
+Example. Retrieve an afio archive from track number 2:
+.br
+tracknumber=2
+.br
+lba=$(cdrskin dev=/dev/cdrom -toc 2>&1 | \\
+.br
+grep '^track:[ ]*[ 0-9][0-9]' | \\
+.br
+tail +"$tracknumber" | head -1 | \\
+.br
+awk '{ print $4}' )
+.br
+dd if=/dev/cdrom bs=2048 skip="$lba" | \\
+.br
+afio -t - | less
+.RE
+.TP
+.BI tsize= size
+Announces the exact size of the next track source. This is necessary with any
+write mode other than -tao if the track source is not a regular disk file, but
+e.g. "-" (standard input) or a named pipe.
+About size specifiers, see option fs=.
+.br
+If the track source does not deliver the predicted amount of bytes, the
+remainder of the track is padded with zeros. This is not considered an error.
+If on the other hand the track source delivers more than the announced bytes
+then the track on media gets truncated to the predicted size and cdrskin exits
+with non-zero value.
+.TP
+.BI \-v
+Increment verbosity level by one. Startlevel is 0 with only few messages.
+Level 1 prints progress report with long running operations and also causes
+some extra lines to be put out with info retrieval options.
+Level 2 additionally reports about option settings derived from arguments or
+startup files. Level 3 is for debugging and useful mainly in conjunction with
+somebody who had a look into the program sourcecode.
+.TP
+.BI \-V
+Enable logging of SCSI commands to stderr. This is helpful for expert
+examination of the interaction between libburn and the drive.
+The commands are specified in SCSI-3 standards SPC, SBC, MMC.
+.TP
+.BI \-waiti
+Wait until input data is available at stdin or EOF occurs at stdin.
+Only then begin to access any drives.
+.br
+One should use this if cdrskin is working at the end of a pipe where the
+feeder process reads from the drive before it starts writing its output into
+cdrskin. Example:
+.br
+mkisofs ... -C 0,12800 -M /dev/sr0 | \\
+.br
+cdrskin dev=/dev/sr0 ... -waiti -
+.br
+This option works even if stdin is not among the track sources. If no process
+is piping in, then the Enter key of your terminal will act as trigger for
+cdrskin. Note that this input line will not be consumed by cdrskin if stdin
+is not among the track sources. It will end up as shell command, usually.
+.PP
+Alphabetical list of options which are genuine to cdrskin and intended for
+normal use:
+.TP
+.BI \--adjust_speed_to_drive
+Curb explicitly given speed= values to the maximum which is announced by the
+drive for the loaded media. By default, such an adjustment is only made with
+pseudo-speeds 0 and -1 whereas speed settings > 0 are sent unchanged to the
+drive which will then choose an appropriate speed on its own.
+.TP
+.BI \--allow_emulated_drives
+Enable drive addresses of the form dev=stdio:. See above, paragraph
+"Drive preparation and addressing".
+.TP
+.BI \--allow_setuid
+Disable the loud warning about insecure discrepance between login user and
+effective user which indicates application of chmod u+s to the program binary.
+One should not do this chmod u+s , but it is an old cdrecord tradition.
+.TP
+.BI \--any_track
+Allow source_addresses to begin with "-" (plus further characters) or to
+contain a "=" character.
+By default such arguments are seen as misspelled options. It is nevertheless
+not possible to use one of the options listed with --list_ignored_options.
+.TP
+.BI assert_write_lba= block_number | byte_address
+Abort if the write address given with this option is not the same as predicted
+immediately before the write session starts. This option can ensure that a
+start address which was presumed by a formatter like mkisofs -C is really used
+by the drive for writing.
+assert_write_lba=0 effectively demands blank media and excludes appendables.
+.br
+Block numbering is peculiar: If the last character of the option string is
+a letter [a-zA-Z] then the usual unit scaling by "s", "k", "m", etc. applies
+and the result is divided by 2048. Else the number value of the string is
+taken as plain block number with block size 2048 byte.
+(E.g ...=1000 or ...=1000s means block 1000, ...=1m means block
+512, ...=4096b means block number 2)
+.TP
+.BI cd_start_tno= number
+Set the number which shall be written as CD track number with the first
+track of the session. The following tracks will then get written with
+consecutive CD track numbers. The resulting number of the last track
+must not exceed 99. The lowest possible start number is 1, which is also
+the default.
+.br
+This setting applies only to CD SAO writing. It overrides the track number
+settings caused by options cuefile= or input_sheet_v07t=.
+.TP
+.BI cdtext_to_textfile= path
+Extract the CD-TEXT packs from the lead-in of an audio CD and write them to
+the file with the given path. If CD-TEXT can be retrieved, then this file
+will be suitable for option textfile=.
+.br
+Not all drives can read CD-TEXT and not all audio CDs bear CD-TEXT.
+It is not considered an error if no CD-TEXT is available.
+.TP
+.BI cdtext_to_v07t= path
+Extract the CD-TEXT packs from the lead-in of an audio CD and write them
+as human readable Sony Input Sheet Version 0.7T to the file with the
+given path. If CD-TEXT can be retrieved, then this file
+will be suitable for option input_sheet_v07t=.
+.br
+If the given path is "-", then the result is printed to standard output.
+.br
+Not all drives can read CD-TEXT and not all audio CDs bear CD-TEXT.
+It is not considered an error if no CD-TEXT is available.
+.TP
+.BI \--demand_a_drive
+Exit with a nonzero value if no drive can be found during a bus scan.
+.TP
+.BI \--devices
+List the device file addresses of all accessible CD drives. In order to get
+listed, a drive has to offer rw-permission for the cdrskin user and it may
+not be busy. The superuser should be able to see all idle drives listed and
+busy drives reported as "SORRY" messages.
+.br
+Each available drive gets listed by a line containing the following fields:
+.br
+Number dev='Devicefile' rw-Permissions : 'Vendor' 'Model'
+.br
+Number and Devicefile can both be used with option dev=, but number is
+volatile (numbering changes if drives become busy).
+.TP
+.BI \--device_links
+Like --devices, but presenting the drives with addresses of symbolic links
+which point to the actual device files.
+.br
+Modern GNU/Linux systems may shuffle drive addresses from boot to boot.
+The udev daemon is supposed to create links which always point to the
+same drive, regardless of its system address.
+Option --device_links shows the addresses of such links if they begin
+by "/dev/dvd" or "/dev/cd".
+Precedence is: "dvdrw", "cdrw", "dvd", "cdrom", "cd".
+.TP
+.BI direct_write_amount= size
+Do not write a session with tracks but rather make an appropriate number of
+direct write operations with no preparations. Flushing the drive buffer will
+be the only finalization. It is advised to eject the media afterwards because
+the write operations circumvent the usual system i/o with its caches and
+buffers. By ejecting, those invalid memory copies get surely discarded.
+.br
+Only few media can be written this way: DVD-RAM, BD-RE, RVD+RW and
+overwriteable DVD-RW. Writing is restricted to the already formatted
+area of the media.
+.br
+Writing starts at byte 0 of the media or at the address given by option
+.B write_start_address= .
+Only the first track source is used as input for the write operations.
+The fifo (fs=) is disabled.
+.br
+Parameter
+.B size
+controls the amount of data to be written. Size 0 means that the track source
+shall be used up until EOF. In this case, the last write transaction gets
+padded up to the necessary size by zeros. Size -1 revokes direct writing
+and switches back to normal session oriented writing.
+.br
+Both, write_start_address and direct_write_amount size must be aligned to a
+media dependend transaction size. With DVD-RAM, BD-RE, DVD+RW this is 2k, with
+overwriteable DVD-RW it is 32k.
+.TP
+.BI dvd_obs= default|32k|64k
+Set the number of bytes to be transmitted with each write operation to DVD
+or BD media. With most write types, tracks get padded up to the next multiple
+of this write size (see option --obs_pad).
+A number of 64 KB may improve throughput with systems
+which show latency problems. The default depends on media type, option
+stream_recording=, and on compile time options.
+.TP
+.BI extract_audio_to= directory_path
+Extract tracks from an audio CD as separate WAVE audio files into the
+given directory.
+This directory has to already exist, but none of the track files may exist.
+This option will rather fail than overwrite an existing file.
+.br
+By default all tracks of the CD are extracted to files with names
+trackNN.wav, where NN is the track number from 01 to at most 99.
+.TP
+.BI extract_basename= name
+Set a filename which shall be used by extract_audio_to= instead of the default
+name "track".
+.TP
+.BI --extract_dap
+Enable Digital Audio Play flaw obscuring mechanisms
+like audio data mute and interpolate.
+.TP
+.BI extract_tracks= number[,number[,...]]
+Set a list of track numbers to define which tracks shall be extracted
+by extract_audio_to=.
+If no extract_tracks= is given, then all audio tracks get extracted.
+It is permissible to have more than one extract_tracks= option in order
+to split a long list into shorter pieces.
+.br
+The lowest permissible track number is 1, the highest is 99.
+.TP
+.BI fallback_program= command
+Set a command name to be executed if cdrskin encounters a known cdrecord
+option which it does not yet support. If a non-empty command is given with
+fallback_program=, and if no essential options are given which are specific
+to cdrskin, then cdrskin will delegate the job to said command.
+.br
+The natural commands to be given are cdrecord or wodim but one may well submit
+the address of an own program.
+.br
+The fallback program will get all arguments of cdrskin which do not match
+the shell patterns --?* or *_*=* . This eventually suppresses path names of
+track sources which happen to match those patterns. The options from the
+startup files are not handed to the fallback program.
+.br
+Fallback program execution is disabled if cdrskin is run setuid and not
+option --allow_setuid is given. In general, the drive's device files and the
+involved programs should be set up so that each program runs under its advised
+conditions. (E.g. cdrskin as member of group floppy, cdrecord setuid root.)
+.br
+Two alias names for cdrskin are predefined with default fallback programs:
+.br
+.B unicord
+implies fallback_program=cdrecord
+.br
+.B codim
+implies fallback_program=wodim
+.TP
+.BI --four_channel
+Indicate for subsequent tracks that they were mastered with four channels.
+.TP
+.BI fifo_start_at= size
+Do not wait for full fifo but start burning as soon as the given number
+of bytes is read. This option may be helpful to bring the average throughput
+near to the maximum throughput of a drive. A large fs= and a small
+fifo_start_at= combine a quick burn start and a large savings buffer to
+compensate for temporary lack of source data. At the beginning of burning,
+the software protection against buffer underrun is as weak as the size of
+fifo_start_at= . So it is best if the drive offers hardware protection which
+is enabled automatically if not driveropts=noburnfree is given.
+.TP
+.BI \--grow_overwriteable_iso
+Enable emulation of multi-session writing on overwriteable media which
+contain an ISO-9660 filesystem. This emulation is learned from growisofs -M
+but adapted to the usage model of
+.br
+.B cdrskin -msinfo
+.br
+.B mkisofs -C -M | cdrskin -waiti [-multi] -
+.br
+--grow_overwriteable_iso does not hamper the use of true multi-session media.
+I.e. it is possible to use the same cdrskin options with both kinds of media
+and to achieve similar results if ISO-9660 filesystem images are to be written.
+This option implies option -isosize and therefore demands that the track
+source is a ISO-9660 filesystem image.
+.br
+With overwriteable media and no option blank=fast|all present it expands an
+eventual ISO-9660 filesystem on media. It is assumed that this image's inner
+size description points to the end of the valuable data.
+Overwriteable media with a recognizable ISO-9660 size will be regarded as
+appendable rather than as blank. I.e. options -msinfo and -toc will work.
+-toc will always show a single session with its size increasing with
+every added mkisofs image.
+.br
+If not overridden by option write_start_address=, the track with the new image
+will be placed behind the end of the old one. One may use option
+assert_write_lba= to make sure that media state and mkisofs job do match.
+.br
+--grow_overwriteable_iso causes option blank=fast|all to invalidate an
+eventual ISO-9660 image by altering the first few bytes of block 16 on
+overwriteable media.
+Option -multi is tolerated in order not to hamper true multi-session media.
+.br
+An equivalent of growisofs -Z for overwriteable media is:
+.br
+.B mkisofs | cdrskin --grow_overwriteable_iso blank=fast [-multi] -
+.br
+With multi-session DVD, blank=fast will act like dvd+rw-format -blank=full .
+.br
+growisofs -dvd-compat is roughly equivalent to cdrskin without option -multi.
+.TP
+.BI input_sheet_v07t= path
+Read CD-TEXT definitions from a Sony Input Sheet version 0.7T. Up to eight
+or seven such sheets can be read by multiple input_sheet_v07t= options.
+Each will define one CD-TEXT language block.
+.br
+The first line of a sheet file decides whether more than one sheet
+may be defined by the file. If it is
+.br
+ Input Sheet Version = 0.7T
+.br
+then each further line with that text switches to the next sheet for the next block.
+If it is not, then all definitions apply to a single block.
+.br
+The information in such a sheet is given by text lines of the following form:
+.br
+ purpose specifier [whitespace] = [whitespace] content text
+.br
+[whitespace] is zero or more ASCII 32 (space) or ASCII 9 (tab) characters.
+The purpose specifier tells the meaning of the content text.
+Empty content text does not cause a CD-TEXT attribute to be attached.
+.br
+The following purpose specifiers apply to the session as a whole:
+.br
+ Purpose specifier | Content example
+.br
+ -------------------------------------------------------------
+.br
+ Text Code = 8859
+.br
+ Language Code = English
+.br
+ Album Title = Joyful Nights
+.br
+ Artist Name = United Cat Orchestra
+.br
+ Songwriter = Various Songwriters
+.br
+ Composer = Various Composers
+.br
+ Arranger = Tom Cat
+.br
+ Album Message = For all our fans
+.br
+ Catalog Number = 1234567890
+.br
+ Genre Code = Classical
+.br
+ Genre Information = Feline classic music
+.br
+ Closed Information = This is not to be shown by CD players
+.br
+ UPC / EAN = 1234567890123
+.br
+ Text Data Copy Protection = OFF
+.br
+ First Track Number = 1
+.br
+ Last Track Number = 3
+.br
+The following purpose specifiers apply to particular tracks:
+.br
+ Purpose specifier | Content example
+.br
+ -------------------------------------------------------------
+.br
+ Track 01 Title = Song of Joy
+.br
+ Track 01 Artist = Felix and The Purrs
+.br
+ Track 01 Songwriter = Friedrich Schiller
+.br
+ Track 01 Composer = Ludwig van Beethoven
+.br
+ Track 01 Arranger = Tom Cat
+.br
+ Track 01 Message = Fritz and Louie once were punks
+.br
+ ISRC 01 = XYCRR1101234
+.br
+Track numbers are decimal despite the leading 0. There should be as many track
+definitions as there are track source files given.
+.br
+See libburn's doc/cdtext.txt for a detailed definition of 0.7T and the
+possible values for Text Code, Language Code, Genre Code, Text Data Copy
+Protection.
+.br
+The Q sub-channel settings by "UPC / EAN" and "ISRC" may be overridden by
+options mcn= and isrc=. This will not affect their appearance as CD-TEXT.
+They may override cuefile= commands CATALOG and ISRC in the same way.
+.br
+If options -text cuefile= are given and if the cue sheet file defines CD-TEXT,
+then only seven input_sheet_v07t= options may be given. They will then be
+used as CD-TEXT language blocks 1 to 7.
+.br
+This option will get into effect only if no option textfile= is given.
+The write mode must be SAO on CD. All tracks must be -audio tracks.
+.br
+The track numbers may be overridden by option cd_start_tno=.
+.TP
+.BI \--list_formats
+List the available format descriptors as reported by the drive for the
+loaded media. Each descriptor line begins with "Format idx" and the
+descriptor's list index, followed by a ":", the format type, the number
+of payload blocks and that same number converted to MiB.
+.br
+The meaning of the format types is defined by the MMC standard
+with command FORMAT UNIT. A user will more be interested in the
+sizes than in the types.
+.TP
+.BI \--list_ignored_options
+List all ignored cdrecord options. The "-" options cannot be used as addresses
+of track sources. No track source address may begin with a text equal to an
+option which ends by "=". The list is ended by an empty line.
+.TP
+.BI \--list_speeds
+Put out a list of speed values as reported by the output drive with
+the loaded medium. This does not necessarily mean that the medium is writable
+or that these speeds are actually achievable. Especially the
+lists reported with empty drive or with ROM media obviously advertise
+speeds for other media.
+.br
+It is not mandatory to use speed values out of the listed range.
+The drive is supposed to choose a safe speed that is as near to the desired
+speed as possible.
+.br
+At the end of the list, "Write speed L" and "Write speed H"
+are the best guesses for lower and upper speed limit.
+"Write speed l" and "Write speed h" may appear only with CD
+and eventually override the list of other speed offers.
+.br
+Only if the drive reports contradicting speed information there will appear
+"Write speed 0" or "Write speed-1", which tell the outcome of speed selection
+by options speed=0 or speed=-1, if it deviates from "Write speed L"
+or "Write speed H", respectively.
+.TP
+.BI \--long_toc
+Like option -toc but marking each session start by a line "first: X last: Y"
+and each session end by "track:lout ...".
+.TP
+.BI \--no_load
+When aquiring the optical drive, do not try to load its tray. This yields the
+same behavior for desktop drives with tray loader as is shown by laptop drives
+which usually lack a motorized tray loader.
+.TP
+.BI \--no_rc
+Only if used as first command line argument this option prevents reading and
+interpretation of eventual startup files. See section FILES below.
+.TP
+.BI \--pacifier_with_newline
+Adds a newline character to each pacifier line that would elsewise be
+overwritten by the next pacifier line. Such lines are emitted during a
+run of writing, formatting, or blanking if option -v is given.
+.TP
+.BI \--prodvd_cli_compatible
+Activates behavior modifications with some DVD situations which bring cdrskin
+nearer to the behavior of cdrecord-ProDVD:
+.br
+Option -multi with unsuitable media is not an error but simply has no effect.
+.br
+Options blank=fast and blank=all deformat overwriteable DVD-RW media.
+.br
+Option blank=fast does indeed minmal blanking with DVD-RW. This may yield media
+which can only do DAO but not Incremental Streaming.
+.TP
+.BI \--single_track
+Accept only the last argument of the command line as track source address.
+.TP
+.BI stdio_sync= on|off|number
+Set the number of bytes after which to force output to drives with prefix
+"stdio:". This forcing keeps the memory from being clogged with lots of
+pending data for slow devices. Default "on" is the same as "16m".
+Forced output can be disabled by "off".
+.TP
+.BI stream_recording= on|off|number
+By setting "on" request that compliance to the desired speed setting is
+preferred over management of write errors. With DVD-RAM and BD this can
+bring effective write speed near to the nominal write speed of the media.
+But it will also disable the automatic use of replacement blocks
+if write errors occur. It might as well be disliked or ignored by the drive.
+.br
+If a number is given, then error management stays enabled for all byte
+addresses below that number. Any number below 16s is the same as "off".
+.TP
+.BI tao_to_sao_tsize= size
+Set an exact fixed size for the next track to be in effect only if the track
+source cannot deliver a size prediction and no tsize= was specified and an
+exact track size prediction is demanded by the write mode.
+.br
+This was the fallback from bad old times when cdrskin was unable to burn
+in mode -tao . It came back with minimally blanked DVD-RW, which cannot do
+Incremental Streaming (-tao), and with explicitly selected write mode -sao
+for best DVD-ROM compatibility.
+.br
+If the track source delivers less bytes than announced then the missing ones
+will be filled with zeros.
+.TP
+.BI --tell_media_space
+Prepare a recording session, do not perform it but rather inquire the
+maximum number of 2048 byte data blocks which may be written in
+the current state of media with the prepared setup. So this option disables
+recording of data. It does not disable blanking, though, and will measure space
+afterwards.
+.br
+It is not mandatory to give track sources but their nature may influence
+the available capacity. So for most realistic results one may set up
+the full burn session and add --tell_media_space. But if one has to expect
+a cdrskin version prior to 0.3.3 no track source should be given in order
+not to start an involuntary burn session.
+In this case set at least -sao or -tao explicitly.
+.br
+The result gets printed to standard output. It is 0 or empty if no writing
+is possible with the given options.
+This option redirects to stderr all message output except its own result
+string and eventual output of -msinfo.
+.TP
+.BI textfile_to_v07t= path
+Read a CD-TEXT pack file (e.g. cdtext.dat from a run with -v -v -toc)
+and print its content in the human readable format that is described
+with option input_sheet_v07t=.
+.br
+The program run ends immediately thereafter.
+No drive scan will happen and no drive will be acquired.
+.br
+To avoid the cdrskin start message in the output, run:
+ cdrskin textfile_to_v07t=cdtext.dat | grep -v '^cdrskin'
+.TP
+.BI --two_channel
+Indicate for subsequent tracks that they were mastered with two channels.
+.TP
+.BI write_start_address= byte_offset
+Set the address on media where to start writing the track. With DVD+RW, DVD-RAM
+or BD-RE byte_offset must be aligned to 2 kiB blocks, but better is 32 kiB.
+With DVD-RW 32 kiB alignment is mandatory.
+.br
+Other media are not suitable for this option yet.
+.TP
+.BI modesty_on_drive= [:parameter=[:parameter=...]]
+Mode 1 keeps the program from trying to write to the burner drive while its
+buffer is in danger to be filled by more than parameter "max_percent".
+If this filling is exceeded then the program will wait until the filling
+is at most the value of parameter "min_percent".
+.br
+Percentages are permissible in the range of 25 to 100.
+.br
+This can ease the load on operating system and drive controller and thus help
+with achieving better input bandwidth if disk and burner are not on independent
+controllers (like hda and hdb). Unsufficient input bandwidth is indicated by
+output "(fifo xy%)" of option -v if xy is lower than 90 for some time.
+modesty_on_drive= might hamper output bandwidth and cause buffer underruns.
+.br
+A new use case is to work around the poor simultaneous performance of multiple
+burn runs on Linux kernel 3.16 and alike. Here it is not about giving the
+hard disk enough time to fill the fifo, but about keeping ioctl(SG_IO) from
+blocking for a longer time and thus blocking all other burn runs.
+.br
+To have max_percent larger than the burner's best actual
+buffer fill has the same effect as min_percent==max_percent. Some burners
+do not use their full buffer with all media types. Watch output "[buf xy%]"
+of option -v to get an impression of the actual buffer usage. Some burners
+are not suitable because they report buffer fill with granularity too large
+in size or time, or because they go to full speed only when their buffer is
+full.
+.br
+If a write attempt is delayed, the program will wait for a number of
+microseconds which is given by parameter "min_usec" before inquiring the buffer
+again. iIf more retries occur, this waiting time between inquiries increases
+up to the value of parameter "max_usec".
+.br
+If the delay lasts longer than the number of seconds given by parameter
+"timeout_sec", then mode 1 is set 0 and normal burning goes on.
+.br
+Mode 0 disables this feature. Mode -1 keeps it unchanged. Default is:
+.br
+ 0:min_percent=65:max_percent=95:timeout_sec=120:
+ min_usec=10000:max_usec=100000
+.br
+The defaults of cdrskin are good for IDE problems. With concurrent Linux SG_IO
+problems on modern hardware, higher min_percent and lower usec might yield
+better buffer fills while still avoiding the problem:
+.br
+ min_percent=90:max_percent=95:min_usec=5000:max_usec=25000
+.PP
+Alphabetical list of options which are only intended for very special
+situations and not for normal use:
+.TP
+.BI \--abort_handler
+Establish default signal handling not to leave a drive in busy state
+but rather to shut it down and to wait until it has ended the final operations.
+This option is only needed for revoking eventual --ignore_signals or
+--no_abort_handler.
+.TP
+.BI \--allow_untested_media
+Enable the use of media profiles which have been implemented but not yet
+tested. Currently this option is without effect because no media types are
+under test reservation.
+.br
+(If you really test experimental media, then please report the outcome on
+libburn-hackers@pykix.org)
+.TP
+.BI \--cdtext_dummy
+Prepare a burn run, report the effective array of CD-TEXT packs to stdout,
+and then end the program run without starting to burn the session.
+A blank CD-R or CD-RW has to be present in the drive, nevertheless.
+.br
+The output is formatted in lines which describe 18 bytes as 2-digit hex
+numbers or as single printable characters.
+See libburn document doc/cdtext.txt about the format of these records.
+.TP
+.BI \--cdtext_verbose
+Like --cdtext_dummy but without preventing the burn run. Combinable with
+option -dummy to exercise a CD burn run with no persistent impact on the
+medium.
+.TP
+.BI dev_translation=
+Set drive address alias. This was necessary before cdrskin-0.2.4 to manually
+translate cdrecord addresses into cdrskin addresses.
+.br
+ is a single character which may not occur in the address string
+. is an address as expected to be given by the user via option
+dev=. is the address to be used instead whenever is given.
+More than one translation instruction can be given in one cdrskin run.
+.br
+E.g.: dev_translation=+ATA:1,0,0+/dev/sr1 dev_translation=+ATA:1,1,0+/dev/sr2
+.TP
+.BI \--drive_abort_on_busy
+Linux specific: Abort process if a busy drive is encountered.
+.TP
+.BI \--drive_blocking
+Linux specific: Try to wait for a busy drive to become free.
+This is not guaranteed to work with all drivers. Some need nonblocking i/o.
+.TP
+.BI \--drive_f_setlk
+Linux specific: Try to get exclusive lock on drive device file via fcntl(2).
+.TP
+.BI \--drive_not_exclusive
+Linux specific: Combine --drive_not_f_setlk and --drive_not_o_excl.
+.TP
+.BI \--drive_not_f_setlk
+Linux specific: Do not try to get exclusive lock on drive device file via
+fcntl(2).
+.TP
+.BI \--drive_not_o_excl
+Linux specific: Do not ask the operating system to prevent opening busy drives.
+Whether this leads to senseful behavior depends on operating system and kernel.
+.TP
+.BI drive_scsi_dev_family= sr | scd | sg
+Linux specific: Select a SCSI device file family to be scanned for by
+options --devices, --device_links and -scanbus.
+Normally this is /dev/sgN on kernel versions < 2.6 and /dev/srN
+on kernels >= 2.6 . This option explicitly overrides that default
+in order to meet other programs at a common device file for each drive.
+On kernel 2.4 families sr and scd will find no drives.
+.br
+Device file family /dev/hdX on kernel >= 2.6 is not affected by this setting.
+.TP
+.BI \--drive_scsi_exclusive
+Linux specific:
+Try to exclusively reserve device files /dev/srN, /dev/scdM, /dev/sgK of drives.
+This would be helpful to protect against collisions with program growisofs.
+Regrettably on Linux kernel 2.4 with ide-scsi emulation this seems not to
+work. Whether it becomes helpful with new Linux systems has to be evaluated.
+.TP
+.BI \--fifo_disable
+Disable fifo despite any fs=.
+.TP
+.BI \--fifo_per_track
+Use a separate fifo for each track.
+.TP
+.BI \--fill_up_media
+Expand the last track of the session to occupy all remaining free space on
+the media.
+.br
+This option overrides option -multi. It will not fill up media if option -sao
+is given with CD media.
+.br
+.B Caution:
+With multi-session media this option might increase readatibility on DVD-ROM
+drives but with some DVD recorders and media types it might also fail to
+produce readable media at all. "Your mileage may vary".
+.br
+You can expect the best possible read compatibility if you do not use -multi at
+all.
+.TP
+.BI grab_drive_and_wait= seconds
+Open the addressed drive, wait the given number of seconds, release the drive,
+and do normal work as indicated by the other options used. This option helps
+to explore the program behavior when faced with busy drives. Just start a
+second cdrskin with option --devices while grab_drive_and_wait= is still
+active.
+.TP
+.BI \--ignore_signals
+Try to ignore any signals rather than to abort the program. This is not a
+very good idea. You might end up waiting a very long time for cdrskin
+to finish.
+.TP
+.BI \--no_abort_handler
+On signals exit even if the drive is in busy state. This is not a very good
+idea. You might end up with a stuck drive that refuses to hand out the media.
+.TP
+.BI \--no_blank_appendable
+Refuse to blank appendable CD-RW or DVD-RW. This is a feature that was once
+builtin with libburn. No information available for what use case it was needed.
+.TP
+.BI \--no_convert_fs_adr
+Do only literal translations of dev=. This prevents cdrskin from test-opening
+device files in order to find one that matches the given dev= specifier.
+.br
+Partly Linux specific:
+Such opening is needed for Bus,Target,Lun addresses unless option
+--old_pseudo_scsi_adr is given. It is also needed to resolve device file
+addresses which are not listed with cdrskin --devices but nevertheless point
+to a usable drive. (Like /dev/sg0 using the same SCSI address as /dev/sr0.)
+.TP
+.BI \--obs_pad
+Pad the data of last write operation of a DVD-R[W] DAO session or
+stdio: pseudo-drive up to the full size of an output chunk.
+This padding has to be applied automatically to the other DVD and BD media
+types, where it causes e.g. ISO images to have trailing unclaimed blocks.
+.br
+Use this option if there is the suspicion that DAO sessions abort with
+your kernel and/or DVD drive, if their size is not a multiple of 16 blocks.
+.br
+This option may also get enabled at compile time of libburn.
+.TP
+.BI \--old_pseudo_scsi_adr
+Linux specific:
+Use and report literal Bus,Target,Lun addresses rather than real SCSI and
+pseudo ATA addresses. This method is outdated and was never compatible with
+original cdrecord.
+.TP
+.BI sao_postgap= off|number
+Define whether a post-gap shall be written at the end of the track and
+how many sectors this gap shall have. A post-gap occupies the range of
+an additional index of the track. It contains zeros. No bytes from the
+track source will be read for writing the post-gap.
+.br
+This setting affects only CD SAO write runs.
+.TP
+.BI sao_pregap= off|number
+Define whether a pre-gap shall be written before the track and how many
+sectors this pre-gap shall have. A pre-gap is written in the range of track
+index 0 and contains zeros. No bytes from the track source
+will be read for writing the pre-gap.
+.br
+This setting affects only CD SAO write runs.
+.br
+The first track automatically gets a pre-gap of at least 150 sectors. Its
+size can only be enlarged by this call.
+.TP
+.BI use_immed_bit= on|off|default
+Control whether several long lasting SCSI commands shall be executed with the
+Immed bit, which makes the commands end early while the drive operation is
+still going on. cdrskin then inquires progress indication until the drive
+reports to be ready again. If this feature is turned off, then blanking and
+formatting will show no progress indication.
+.br
+It may depend on the operating system whether use_immed_bit= is set to "off"
+by default.
+.TP
+.BI --xa1-ignore
+Silently interpret option -xa1 as -data. This may be necessary if a frontend
+does not prepare -xa1 block headers but insists in using option -xa1.
+.SH EXAMPLES
+.SS
+.B Get an overview of drives and their addresses:
+.br
+cdrskin -scanbus
+.br
+cdrskin dev=ATA -scanbus
+.br
+cdrskin --device_links
+.SS
+.B Get info about a particular drive or loaded media:
+.br
+cdrskin dev=0,1,0 -checkdrive
+.br
+cdrskin dev=ATA:1,0,0 -v -atip
+.br
+cdrskin dev=/dev/hdc -minfo
+.SS
+.B Prepare CD-RW or DVD-RW for re-use, DVD-RAM or BD-RE for first use:
+.br
+cdrskin -v dev=/dev/sg1 blank=as_needed -eject
+.SS
+.B Format DVD-RW to avoid need for blanking before re-use:
+.br
+cdrskin -v dev=/dev/sr0 blank=format_overwrite
+.SS
+.B De-format DVD-RW to make it capable of multi-session again:
+.br
+cdrskin -v dev=/dev/sr0 blank=deformat_sequential
+.SS
+.B Write ISO-9660 filesystem image as only one to blank or formatted media:
+.br
+cdrskin -v dev=/dev/hdc speed=12 fs=8m \\
+.br
+ blank=as_needed -eject padsize=300k my_image.iso
+.SS
+.B Write compressed afio archive on-the-fly (not possible with minimally blanked DVD-RW or DVD-R DL):
+.br
+find . | afio -oZ - | \\
+.br
+cdrskin -v dev=0,1,0 fs=32m speed=8 \\
+.br
+ blank=as_needed padsize=300k -
+.SS
+.B Write multi-session to the same CD, DVD-R[W], DVD+R[/DL], or BD-R:
+.br
+cdrskin dev=/dev/sr0 -v padsize=300k -multi 1.iso
+.br
+cdrskin dev=/dev/sr0 -v padsize=300k -multi 2.iso
+.br
+cdrskin dev=/dev/sr0 -v padsize=300k -multi 3.iso
+.br
+cdrskin dev=/dev/sr0 -v padsize=300k 4.iso
+.SS
+.B Get multi-session info for option -C of program mkisofs:
+.br
+c_values=$(cdrskin dev=/dev/hdc -msinfo 2>/dev/null)
+.br
+mkisofs ... -C "$c_values" ...
+.SS
+.B Inquire free space on media for a -multi run:
+.br
+x=$(cdrskin dev=/dev/sr0 -multi \\
+.br
+ --tell_media_space 2>/dev/null)
+.br
+echo "Available: $x blocks of 2048 data bytes"
+.SS
+.B Write audio tracks and CD-TEXT to CD:
+.br
+cdrskin -v dev=ATA:1,0,0 speed=48 -sao \\
+.br
+ input_sheet_v07t=cdtext.v07t \\
+.br
+ track1.wav track2.au -audio -swab track3.raw
+.SS
+.B Extract audio tracks and CD-TEXT from CD into directory /home/me/my_cd:
+.br
+mkdir /home/me/my_cd
+.br
+cdrskin -v dev=/dev/sr0 extract_audio_to=/home/me/my_cd \\
+.br
+ cdtext_to_v07t=/home/me/my_cd/cdtext.v07t
+.SH FILES
+.SS
+Startup files:
+.br
+If not --no_rc is given as the first argument then cdrskin attempts on
+startup to read the arguments from the following files:
+.PP
+.br
+.B /etc/default/cdrskin
+.br
+.B /etc/opt/cdrskin/rc
+.br
+.B /etc/cdrskin/cdrskin.conf
+.br
+.B $HOME/.cdrskinrc
+.br
+.PP
+The files are read in the sequence given above, but none of them is
+required for cdrskin to function properly. Each readable line is treated
+as one single argument. No extra blanks.
+A first character '#' marks a comment, empty lines are ignored.
+.br
+Example content of a startup file:
+.br
+# This is the default device
+.br
+dev=0,1,0
+.br
+# Some more options
+.br
+fifo_start_at=0
+.br
+fs=16m
+.br
+.SS
+Disabling superuser safety precautions:
+The superuser is normally banned from using any other emulated drive but
+/dev/null. This ban can be lifted by the existence of file
+.PP
+.B /root/cdrskin_permissions/allow_emulated_drives
+.PP
+where the directory must be owned by the superuser and must not offer
+w-permissions for group or others.
+.br
+Warning: Superusers must take care not to spoil their hard disk via its raw
+block device (like stdio:/dev/hda or stdio:/dev/sd0).
+
+.SH SEE ALSO
+.TP
+Formatting data track sources for cdrskin:
+.br
+.BR mkisofs (8),
+.BR genisoimage (8),
+.BR xorriso (1),
+.BR afio (1),
+.BR star (1)
+.br
+.TP
+Other CD/DVD/BD burn programs:
+.br
+.BR cdrecord (1),
+.BR wodim (1),
+.BR xorriso (1)
+.br
+.TP
+For DVD/BD burning (also tutor of libburn's DVD/BD capabilities):
+.br
+.BR growisofs (1)
+.br
+.SH AUTHOR
+cdrskin was written by Thomas Schmitt .
+.PP
+This manual page was started by George Danchev and
+is now maintained by Thomas Schmitt.
+
diff --git a/libburn/branches/1.4.6/cdrskin/cdrskin.c b/libburn/branches/1.4.6/cdrskin/cdrskin.c
new file mode 100644
index 00000000..c0b3d641
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/cdrskin.c
@@ -0,0 +1,9848 @@
+
+/*
+ cdrskin.c , Copyright 2006-2016 Thomas Schmitt
+Provided under GPL version 2 or later.
+
+A cdrecord compatible command line interface for libburn.
+
+This project is neither directed against original cdrecord nor does it exploit
+any source code of said program. It rather tries to be an alternative method
+to burn CD, DVD, or BD, which is not based on the same code as cdrecord.
+See also : http://scdbackup.sourceforge.net/cdrskin_eng.html
+
+Interested users of cdrecord are encouraged to contribute further option
+implementations as they need them. Contributions will get published under GPL
+but it is essential that the authors allow a future release under LGPL.
+
+There is a script test/cdrecord_spy.sh which may be installed between
+the cdrecord command and real cdrecord in order to learn about the options
+used by your favorite cdrecord frontend. Edit said script and install it
+according to the instructions given inside.
+
+The implementation of an option would probably consist of
+- necessary structure members for structs CdrpreskiN and/or CdrskiN
+- code in Cdrpreskin_setup() and Cdrskin_setup() which converts
+ argv[i] into CdrpreskiN/CdrskiN members (or into direct actions)
+- removal of option from ignore list "ignored_partial_options" or
+ "ignored_full_options" in Cdrskin_setup()
+- functions which implement the option's run time functionality
+- eventually calls of those functions in Cdrskin_run()
+- changes to be made within Cdrskin_burn() or Cdrskin_blank() or other
+ existing methods
+See option blank= for an example.
+
+------------------------------------------------------------------------------
+
+For a more comprehensive example of the advised way to write an application
+of libburn see test/libburner.c .
+
+------------------------------------------------------------------------------
+This program is currently copyright Thomas Schmitt only.
+The copyrights of several components of libburnia-project.org are willfully
+tangled at toplevel to form an irrevocable commitment to true open source
+spirit.
+We have chosen the GPL for legal compatibility and clearly express that it
+shall not hamper the use of our software by non-GPL applications which show
+otherwise the due respect to the open source community.
+See toplevel README and cdrskin/README for that commitment.
+
+For a short time, this place showed a promise to release a BSD license on
+mere request. I have to retract that promise now, and replace it by the
+promise to make above commitment reality in a way that any BSD conformant
+usage in due open source spirit will be made possible somehow and in the
+particular special case. I will not raise public protest if you fork yourself
+a BSD license from an (outdated) cdrskin.c which still bears that old promise.
+Note that this extended commitment is valid only for cdrskin.[ch],
+cdrfifo.[ch] and cleanup.[ch], but not for libburnia-project.org as a whole.
+
+cdrskin is originally inspired by libburn-0.2/test/burniso.c :
+(c) Derek Foreman and Ben Jansens
+
+------------------------------------------------------------------------------
+
+Compilation within cdrskin-* :
+
+ cd cdrskin
+ cc -g -I.. -DCdrskin_build_timestamP='...' \
+ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 \
+ -o cdrskin cdrskin.c cdrfifo.c cleanup.c \
+ -L../libburn/.libs -lburn -lpthread
+
+or
+
+ cd ..
+ cc -g -I. -DCdrskin_build_timestamP='...' \
+ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 \
+ -o cdrskin/cdrskin cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cleanup.c \
+ libburn/async.o libburn/crc.o libburn/debug.o libburn/drive.o \
+ libburn/file.o libburn/init.o libburn/lec.o \
+ libburn/mmc.o libburn/options.o libburn/sbc.o libburn/sector.o \
+ libburn/sg.o libburn/spc.o libburn/source.o libburn/structure.o \
+ libburn/toc.o libburn/util.o libburn/write.o libburn/read.o \
+ libburn/libdax_audioxtr.o libburn/libdax_msgs.o \
+ -lpthread
+
+*/
+
+
+/** The official program version */
+#ifndef Cdrskin_prog_versioN
+#define Cdrskin_prog_versioN "1.4.5"
+#endif
+
+/** The official libburn interface revision to use.
+ (May get changed further below)
+*/
+#ifndef Cdrskin_libburn_majoR
+#define Cdrskin_libburn_majoR 1
+#endif
+#ifndef Cdrskin_libburn_minoR
+#define Cdrskin_libburn_minoR 4
+#endif
+#ifndef Cdrskin_libburn_micrO
+#define Cdrskin_libburn_micrO 4
+#endif
+
+
+/** The source code release timestamp */
+#include "cdrskin_timestamp.h"
+#ifndef Cdrskin_timestamP
+#define Cdrskin_timestamP "-none-given-"
+#endif
+
+/** The binary build timestamp is to be set externally by the compiler */
+#ifndef Cdrskin_build_timestamP
+#define Cdrskin_build_timestamP "-none-given-"
+#endif
+
+
+#ifdef Cdrskin_libburn_versioN
+#undef Cdrskin_libburn_versioN
+#endif
+
+#ifdef Cdrskin_libburn_1_4_4
+#define Cdrskin_libburn_versioN "1.4.4"
+#endif
+
+#ifdef Cdrskin_libburn_1_4_5
+#define Cdrskin_libburn_versioN "1.4.5"
+#endif
+
+#ifndef Cdrskin_libburn_versioN
+#define Cdrskin_libburn_1_4_4
+#define Cdrskin_libburn_versioN "1.4.4"
+#endif
+
+#ifdef Cdrskin_libburn_1_4_4
+#undef Cdrskin_libburn_majoR
+#undef Cdrskin_libburn_minoR
+#undef Cdrskin_libburn_micrO
+#define Cdrskin_libburn_majoR 1
+#define Cdrskin_libburn_minoR 4
+#define Cdrskin_libburn_micrO 4
+#endif
+#ifdef Cdrskin_libburn_1_4_5
+#undef Cdrskin_libburn_majoR
+#undef Cdrskin_libburn_minoR
+#undef Cdrskin_libburn_micrO
+#define Cdrskin_libburn_majoR 1
+#define Cdrskin_libburn_minoR 4
+#define Cdrskin_libburn_micrO 5
+#endif
+
+
+/* History of development macros.
+ As of version 1.1.8 they are now unconditional, thus removing the option
+ to compile a heavily restricted cdrskin for the old libburn at icculus.org.
+*/
+
+/* 0.2.2 */
+/* Cdrskin_libburn_does_ejecT */
+/* Cdrskin_libburn_has_drive_get_adR */
+/* Cdrskin_progress_track_does_worK */
+/* Cdrskin_is_erasable_on_load_does_worK */
+/* Cdrskin_grab_abort_does_worK */
+
+/* 0.2.4 */
+/* Cdrskin_allow_libburn_taO */
+/* Cdrskin_libburn_has_is_enumerablE */
+/* Cdrskin_libburn_has_convert_fs_adR */
+/* Cdrskin_libburn_has_convert_scsi_adR */
+/* Cdrskin_libburn_has_burn_msgS */
+/* Cdrskin_libburn_has_burn_aborT */
+/* Cdrskin_libburn_has_cleanup_handleR */
+/* Cdrskin_libburn_has_audioxtR */
+/* Cdrskin_libburn_has_get_start_end_lbA */
+/* Cdrskin_libburn_has_burn_disc_unsuitablE */
+/* Cdrskin_libburn_has_read_atiP */
+/* Cdrskin_libburn_has_buffer_progresS */
+
+/* 0.2.6 */
+/* Cdrskin_libburn_has_pretend_fulL */
+/* Cdrskin_libburn_has_multI */
+/* Cdrskin_libburn_has_buffer_min_filL */
+
+/* 0.3.0 */
+/* Cdrskin_atip_speed_is_oK */
+/* Cdrskin_libburn_has_get_profilE */
+/* Cdrskin_libburn_has_set_start_bytE */
+/* Cdrskin_libburn_has_wrote_welL */
+/* Cdrskin_libburn_has_bd_formattinG */
+/* Cdrskin_libburn_has_burn_disc_formaT */
+
+/* 0.3.2 */
+/* Cdrskin_libburn_has_get_msc1 */
+/* Cdrskin_libburn_has_toc_entry_extensionS */
+/* Cdrskin_libburn_has_get_multi_capS */
+
+/* 0.3.4 */
+/* Cdrskin_libburn_has_set_filluP */
+/* Cdrskin_libburn_has_get_spacE */
+/* Cdrskin_libburn_write_mode_ruleS */
+/* Cdrskin_libburn_has_allow_untested_profileS */
+/* Cdrskin_libburn_has_set_forcE */
+
+/* 0.3.6 */
+/* Cdrskin_libburn_preset_device_familY */
+/* Cdrskin_libburn_has_track_set_sizE */
+
+/* 0.3.8 */
+/* Cdrskin_libburn_has_set_waitinG */
+/* Cdrskin_libburn_has_get_best_speeD */
+
+/* 0.4.0 */
+/* Cdrskin_libburn_has_random_access_rW */
+/* Cdrskin_libburn_has_get_drive_rolE */
+/* Cdrskin_libburn_has_drive_equals_adR */
+
+/* 0.4.2 */
+/* no novel libburn features but rather organizational changes */
+
+/* 0.4.4 */
+/* novel libburn features are transparent to cdrskin */
+
+/* 0.4.6 */
+/* Cdrskin_libburn_has_stream_recordinG */
+
+/* 0.4.8 */
+/* Bug fix release for write_start_address=... on DVD-RAM and BD-RE */
+
+/* 0.5.0 , 0.5.2 , 0.5.4 , 0.5.6 , 0.5.8 , 0.6.0 , 0.6.2 */
+/* novel libburn features are transparent to cdrskin */
+
+/* 0.6.4 */
+/* Ended to mark novelties by macros.
+ libburnia libburn and cdrskin are fixely in sync now.
+ icculus libburn did not move for 30 months.
+*/
+
+/* 1.1.8 */
+/* The code which got enabled by novelty macros was made unconditional.
+*/
+
+
+#ifdef Cdrskin_new_api_tesT
+
+/* put macros under test caveat here */
+
+
+#endif /* Cdrskin_new_api_tesT */
+
+
+/** ts A90901
+ The raw write modes of libburn depend in part on code borrowed from cdrdao.
+ Since this code is not understood by the current developers and since CDs
+ written with cdrskin -raw96r seem unreadable anyway, -raw96r is given up
+ for now.
+*/
+#define Cdrskin_disable_raw96R 1
+
+
+/** A macro which is able to eat up a function call like printf() */
+#ifdef Cdrskin_extra_leaN
+#define ClN(x)
+#define Cdrskin_no_cdrfifO 1
+#else
+#define ClN(x) x
+#ifdef Cdrskin_use_libburn_fifO
+/*
+ # define Cdrskin_no_cdrfifO 1
+*/
+#endif
+#endif
+
+/** Verbosity level for pacifying progress messages */
+#define Cdrskin_verbose_progresS 1
+
+/** Verbosity level for command recognition and execution logging */
+#define Cdrskin_verbose_cmD 2
+
+/** Verbosity level for reporting of debugging messages */
+#define Cdrskin_verbose_debuG 3
+
+/** Verbosity level for fifo debugging */
+#define Cdrskin_verbose_debug_fifO 4
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../libburn/libburn.h"
+
+
+#define Cleanup_set_handlers burn_set_signal_handling
+#define Cleanup_app_handler_T burn_abort_handler_t
+
+/*
+ # define Cdrskin_use_libburn_cleanuP 1
+*/
+/* May not use libburn cleanup with cdrskin fifo */
+#ifndef Cdrskin_use_libburn_fifO
+#ifdef Cdrskin_use_libburn_cleanuP
+#undef Cdrskin_use_libburn_cleanuP
+#endif
+#endif
+
+#ifdef Cdrskin_use_libburn_cleanuP
+#define Cleanup_handler_funC NULL
+#define Cleanup_handler_handlE "cdrskin: "
+#define Cleanup_handler_flaG 48
+#else
+#define Cleanup_handler_funC (Cleanup_app_handler_T) Cdrskin_abort_handler
+#define Cleanup_handler_handlE skin
+#define Cleanup_handler_flaG 4
+#endif /* ! Cdrskin_use_libburn_cleanuP */
+
+/* 0= no abort going on, -1= Cdrskin_abort_handler was called
+*/
+static int Cdrskin_abort_leveL= 0;
+
+
+/** The size of a string buffer for pathnames and similar texts */
+#define Cdrskin_strleN 4096
+
+/** The maximum length +1 of a drive address */
+#define Cdrskin_adrleN BURN_DRIVE_ADR_LEN
+
+
+/** If tsize= sets a value smaller than media capacity divided by this
+ number then there will be a warning and gracetime set at least to 15 */
+#define Cdrskin_minimum_tsize_quotienT 2048.0
+
+
+/* --------------------------------------------------------------------- */
+
+/* Imported from scdbackup-0.8.5/src/cd_backup_planer.c */
+
+/** Macro for creation of arrays of objects (or single objects) */
+#define TSOB_FELD(typ,anz) (typ *) calloc(anz, sizeof(typ));
+
+
+/** Convert a text so that eventual characters special to the shell are
+ made literal. Note: this does not make a text terminal-safe !
+ @param in_text The text to be converted
+ @param out_text The buffer for the result.
+ It should have size >= strlen(in_text)*5+2
+ @param flag Unused yet
+ @return For convenience out_text is returned
+*/
+char *Text_shellsafe(char *in_text, char *out_text, int flag)
+{
+ int l,i,w=0;
+
+ /* enclose everything by hard quotes */
+ l= strlen(in_text);
+ out_text[w++]= '\'';
+ for(i=0;i0) if(line[l-1]=='\r') line[--l]= 0;
+ if(l>0) if(line[l-1]=='\n') line[--l]= 0;
+ if(l>0) if(line[l-1]=='\r') line[--l]= 0;
+ return(ret);
+}
+
+#ifndef Cdrskin_extra_leaN
+
+
+/** Destroy a synthetic argument array */
+int Sfile_destroy_argv(int *argc, char ***argv, int flag)
+{
+ int i;
+
+ if(*argc>0 && *argv!=NULL){
+ for(i=0;i<*argc;i++){
+ if((*argv)[i]!=NULL)
+ free((*argv)[i]);
+ }
+ free((char *) *argv);
+ }
+ *argc= 0;
+ *argv= NULL;
+ return(1);
+}
+
+
+/** Read a synthetic argument array from a list of files.
+ @param progname The content for argv[0]
+ @param filenames The paths of the filex from where to read
+ @param filenamecount The number of paths in filenames
+ @param argc Returns the number of read arguments (+1 for progname)
+ @param argv Returns the array of synthetic arguments
+ @param argidx Returns source file indice of argv[] items
+ @param arglno Returns source file line numbers of argv[] items
+ @param flag Bitfield for control purposes:
+ bit0= read progname as first argument from line
+ bit1= just release argument array argv and return
+ bit2= tolerate failure to open file
+ @return 1=ok , 0=cannot open file , -1=cannot create memory objects
+*/
+int Sfile_multi_read_argv(char *progname, char **filenames, int filename_count,
+ int *argc, char ***argv, int **argidx, int **arglno,
+ int flag)
+{
+ int ret,i,pass,maxl=0,l,argcount=0,line_no;
+ char buf[Cdrskin_strleN];
+ FILE *fp= NULL;
+
+ Sfile_destroy_argv(argc,argv,0);
+ if(flag&2)
+ return(1);
+ if((*argidx)!=NULL)
+ free((char *) *argidx);
+ if((*arglno)!=NULL)
+ free((char *) *arglno);
+ *argidx= *arglno= NULL;
+
+ for(pass=0;pass<2;pass++) {
+ if(!(flag&1)){
+ argcount= 1;
+ if(pass==0)
+ maxl= strlen(progname)+1;
+ else {
+ (*argv)[0]= (char *) calloc(1, strlen(progname)+1);
+ if((*argv)[0]==NULL)
+ {ret= -1; goto ex;}
+ strcpy((*argv)[0],progname);
+ }
+ } else {
+ argcount= 0;
+ if(pass==0)
+ maxl= 1;
+ }
+ for(i=0; imaxl)
+ maxl= l;
+ } else {
+ if(argcount >= *argc)
+ break;
+ (*argv)[argcount]= (char *) calloc(1, l+1);
+ if((*argv)[argcount]==NULL)
+ {ret= -1; goto ex;}
+ strcpy((*argv)[argcount],buf);
+ (*argidx)[argcount]= i;
+ (*arglno)[argcount]= line_no;
+ }
+ argcount++;
+ }
+ fclose(fp); fp= NULL;
+ }
+ if(pass==0){
+ *argc= argcount;
+ if(argcount>0) {
+ *argv= (char **) calloc(argcount, sizeof(char *));
+ *argidx= (int *) calloc(argcount, sizeof(int));
+ *arglno= (int *) calloc(argcount, sizeof(int));
+ if(*argv==NULL || *argidx==NULL || *arglno==NULL)
+ {ret= -1; goto ex;}
+ }
+ for(i=0;i<*argc;i++) {
+ (*argv)[i]= NULL;
+ (*argidx)[i]= -1;
+ (*arglno)[i]= -1;
+ }
+ }
+ }
+
+ ret= 1;
+ex:;
+ if(fp!=NULL)
+ fclose(fp);
+ return(ret);
+}
+
+
+/** Combine environment variable HOME with given filename
+ @param filename Address relative to $HOME
+ @param fileadr Resulting combined address
+ @param fa_size Size of array fileadr
+ @param flag Unused yet
+ @return 1=ok , 0=no HOME variable , -1=result address too long
+*/
+int Sfile_home_adr_s(char *filename, char *fileadr, int fa_size, int flag)
+{
+ char *home;
+
+ strcpy(fileadr,filename);
+ home= getenv("HOME");
+ if(home==NULL)
+ return(0);
+ if((int) (strlen(home) + strlen(filename) + 1) >= fa_size)
+ return(-1);
+ strcpy(fileadr,home);
+ if(filename[0]!=0){
+ strcat(fileadr,"/");
+ strcat(fileadr,filename);
+ }
+ return(1);
+}
+
+
+#endif /* ! Cdrskin_extra_leaN */
+
+
+/* -------------------------- other misc functions ----------------------- */
+
+
+/* Learned from reading growisofs.c ,
+ watching mkisofs, and viewing its results via od -c */
+/* @return 0=no size found , 1=*size_in_bytes is valid */
+int Scan_for_iso_size(unsigned char data[2048], double *size_in_bytes,
+ int flag)
+{
+ double sectors= 0.0;
+
+ if(data[0]!=1)
+ return(0);
+ if(strncmp((char *) (data+1),"CD001",5)!=0)
+ return(0);
+ sectors= data[80] | (data[81]<<8) | (data[82]<<16) | (data[83]<<24);
+ *size_in_bytes= sectors*2048.0;
+ return(1);
+}
+
+
+int Set_descr_iso_size(unsigned char data[2048], double size_in_bytes,
+ int flag)
+{
+ unsigned int sectors, i;
+
+ sectors= size_in_bytes/2048.0;
+ if(size_in_bytes>((double) sectors) * 2048.0)
+ sectors++;
+ for(i=0;i<4;i++)
+ data[87-i]= data[80+i]= (sectors >> (8*i)) & 0xff;
+ return(1);
+}
+
+
+int Wait_for_input(int fd, int microsec, int flag)
+{
+ struct timeval wt;
+ fd_set rds,wts,exs;
+ int ready;
+
+ FD_ZERO(&rds);
+ FD_ZERO(&wts);
+ FD_ZERO(&exs);
+ FD_SET(fd,&rds);
+ FD_SET(fd,&exs);
+ wt.tv_sec= microsec/1000000;
+ wt.tv_usec= microsec%1000000;
+ ready= select(fd+1,&rds,&wts,&exs,&wt);
+ if(ready<=0)
+ return(0);
+ if(FD_ISSET(fd,&exs))
+ return(-1);
+ if(FD_ISSET(fd,&rds))
+ return(1);
+ return(0);
+}
+
+
+/* --------------------------------------------------------------------- */
+
+/** Address translation table for users/applications which do not look
+ for the output of -scanbus but guess a Bus,Target,Lun on their own.
+*/
+
+/** The maximum number of entries in the address translation table */
+#define Cdradrtrn_leN 256
+
+/** The address prefix which will prevent translation */
+#define Cdrskin_no_transl_prefiX "LITERAL_ADR:"
+
+
+struct CdradrtrN {
+ char *from_address[Cdradrtrn_leN];
+ char *to_address[Cdradrtrn_leN];
+ int fill_counter;
+};
+
+
+#ifndef Cdrskin_extra_leaN
+
+/** Create a device address translator object */
+int Cdradrtrn_new(struct CdradrtrN **trn, int flag)
+{
+ struct CdradrtrN *o;
+ int i;
+
+ (*trn)= o= TSOB_FELD(struct CdradrtrN,1);
+ if(o==NULL)
+ return(-1);
+ for(i= 0;ifrom_address[i]= NULL;
+ o->to_address[i]= NULL;
+ }
+ o->fill_counter= 0;
+ return(1);
+}
+
+
+/** Release from memory a device address translator object */
+int Cdradrtrn_destroy(struct CdradrtrN **o, int flag)
+{
+ int i;
+ struct CdradrtrN *trn;
+
+ trn= *o;
+ if(trn==NULL)
+ return(0);
+ for(i= 0;ifill_counter;i++) {
+ if(trn->from_address[i]!=NULL)
+ free(trn->from_address[i]);
+ if(trn->to_address[i]!=NULL)
+ free(trn->to_address[i]);
+ }
+ free((char *) trn);
+ *o= NULL;
+ return(1);
+}
+
+
+/** Add a translation pair to the table
+ @param trn The translator which shall learn
+ @param from The user side address
+ @param to The cdrskin side address
+ @param flag Bitfield for control purposes:
+ bit0= "from" contains from+to address, to[0] contains delimiter
+*/
+int Cdradrtrn_add(struct CdradrtrN *trn, char *from, char *to, int flag)
+{
+ char buf[2*Cdrskin_adrleN+1],*from_pt,*to_pt;
+ int cnt;
+
+ cnt= trn->fill_counter;
+ if(cnt>=Cdradrtrn_leN)
+ return(-1);
+ if(flag&1) {
+ if(strlen(from)>=sizeof(buf))
+ return(0);
+ strcpy(buf,from);
+ to_pt= strchr(buf,to[0]);
+ if(to_pt==NULL)
+ return(0);
+ *(to_pt)= 0;
+ from_pt= buf;
+ to_pt++;
+ } else {
+ from_pt= from;
+ to_pt= to;
+ }
+ if(strlen(from)>=Cdrskin_adrleN || strlen(to)>=Cdrskin_adrleN)
+ return(0);
+ trn->from_address[cnt]= calloc(1, strlen(from_pt)+1);
+ trn->to_address[cnt]= calloc(1, strlen(to_pt)+1);
+ if(trn->from_address[cnt]==NULL ||
+ trn->to_address[cnt]==NULL)
+ return(-2);
+ strcpy(trn->from_address[cnt],from_pt);
+ strcpy(trn->to_address[cnt],to_pt);
+ trn->fill_counter++;
+ return(1);
+}
+
+
+/** Apply eventual device address translation
+ @param trn The translator
+ @param from The address from which to translate
+ @param driveno With backward translation only: The libburn drive number
+ @param to The result of the translation
+ @param flag Bitfield for control purposes:
+ bit0= translate backward
+ @return <=0 error, 1=no translation found, 2=translation found,
+ 3=collision avoided
+*/
+int Cdradrtrn_translate(struct CdradrtrN *trn, char *from, int driveno,
+ char to[Cdrskin_adrleN], int flag)
+{
+ int i,ret= 1;
+ char *adr;
+
+ to[0]= 0;
+ adr= from;
+ if(flag&1)
+ goto backward;
+
+ if(strncmp(adr,Cdrskin_no_transl_prefiX,
+ strlen(Cdrskin_no_transl_prefiX))==0) {
+ adr= adr+strlen(Cdrskin_no_transl_prefiX);
+ ret= 2;
+ } else {
+ for(i=0;ifill_counter;i++)
+ if(strcmp(adr,trn->from_address[i])==0)
+ break;
+ if(ifill_counter) {
+ adr= trn->to_address[i];
+ ret= 2;
+ }
+ }
+ if(strlen(adr)>=Cdrskin_adrleN)
+ return(-1);
+ strcpy(to,adr);
+ return(ret);
+
+backward:;
+ if(strlen(from)>=Cdrskin_adrleN)
+ sprintf(to,"%s%d",Cdrskin_no_transl_prefiX,driveno);
+ else
+ strcpy(to,from);
+ for(i=0;ifill_counter;i++)
+ if(strcmp(from,trn->to_address[i])==0 &&
+ strlen(trn->from_address[i])fill_counter) {
+ ret= 2;
+ strcpy(to,trn->from_address[i]);
+ } else {
+ for(i=0;ifill_counter;i++)
+ if(strcmp(from,trn->from_address[i])==0)
+ break;
+ if(ifill_counter)
+ if(strlen(from)+strlen(Cdrskin_no_transl_prefiX)boss= boss;
+ o->trackno= trackno;
+ o->source_path[0]= 0;
+ o->original_source_path[0]= 0;
+ o->source_fd= -1;
+ o->is_from_stdin= !!(flag&2);
+ o->fixed_size= 0.0;
+ o->tao_to_sao_tsize= 0.0;
+ o->padding= 0.0;
+ o->set_by_padsize= 0;
+ o->sector_pad_up= 1;
+ o->track_type= BURN_MODE1;
+ o->mode_modifiers= 0;
+ o->sector_size= 2048.0;
+ o->track_type_by_default= 1;
+ o->swap_audio_bytes= 0;
+ o->cdxa_conversion= 0;
+ o->isrc[0]= 0;
+ o->index_string= NULL;
+ o->sao_pregap= -1;
+ o->sao_postgap= -1;
+ o->data_image_size= -1.0;
+ o->iso_fs_descr= NULL;
+ o->use_data_image_size= 0;
+ o->extracting_container= 0;
+ o->fifo_enabled= 0;
+ o->fifo= NULL;
+ o->fifo_outlet_fd= -1;
+ o->fifo_size= 0;
+ o->ff_fifo= NULL;
+ o->ff_idx= -1;
+ o->libburn_track= NULL;
+ o->libburn_track_is_own= 0;
+#ifdef Cdrskin_use_libburn_fifO
+ o->libburn_fifo= NULL;
+#endif /* Cdrskin_use_libburn_fifO */
+
+ if(flag & 1)
+ return(1);
+
+ ret= Cdrskin_get_source(boss,o->source_path,&(o->fixed_size),
+ &(o->tao_to_sao_tsize),&(o->use_data_image_size),
+ &(o->padding),&(o->set_by_padsize),&(skin_track_type),
+ &(o->track_type_by_default), &(o->mode_modifiers),
+ &(o->swap_audio_bytes), &(o->cdxa_conversion), 0);
+ if(ret<=0)
+ goto failed;
+ strcpy(o->original_source_path,o->source_path);
+ if(o->fixed_size>0.0)
+ o->extracting_container= 1;
+ Cdrtrack_set_track_type(o,skin_track_type,0);
+
+#ifndef Cdrskin_extra_leaN
+ ret= Cdrskin_get_fifo_par(boss, &(o->fifo_enabled),&(o->fifo_size),
+ &fifo_start_at,0);
+ if(ret<=0)
+ goto failed;
+#endif /* ! Cdrskin_extra_leaN */
+
+ return(1);
+failed:;
+ Cdrtrack_destroy(track,0);
+ return(-1);
+}
+
+
+/** Release from memory a track object previously created by Cdrtrack_new() */
+int Cdrtrack_destroy(struct CdrtracK **o, int flag)
+{
+ struct CdrtracK *track;
+
+ track= *o;
+ if(track==NULL)
+ return(0);
+
+#ifndef Cdrskin_no_cdrfifO
+ Cdrfifo_destroy(&(track->fifo),0);
+#endif
+
+ if(track->libburn_track != NULL && track->libburn_track_is_own)
+ burn_track_free(track->libburn_track);
+ if(track->iso_fs_descr!=NULL)
+ free((char *) track->iso_fs_descr);
+ if(track->index_string != NULL)
+ free(track->index_string);
+ free((char *) track);
+ *o= NULL;
+ return(1);
+}
+
+
+int Cdrtrack_set_track_type(struct CdrtracK *o, int track_type, int flag)
+{
+ if(track_type==BURN_AUDIO) {
+ o->track_type= BURN_AUDIO;
+ o->sector_size= 2352.0;
+ } else {
+ o->track_type= BURN_MODE1;
+ o->sector_size= 2048.0;
+ }
+ return(1);
+}
+
+
+int Cdrtrack_get_track_type(struct CdrtracK *o, int *track_type,
+ int *sector_size, int flag)
+{
+ *track_type= o->track_type;
+ *sector_size= o->sector_size;
+ return(1);
+}
+
+
+/**
+ @param flag Bitfield for control purposes:
+ bit0= size returns number of actually processed source bytes
+ rather than the predicted fixed_size (if available).
+ padding returns the difference from number of written
+ bytes.
+ bit1= size returns fixed_size, padding returns tao_to_sao_tsize
+*/
+int Cdrtrack_get_size(struct CdrtracK *track, double *size, double *padding,
+ double *sector_size, int *use_data_image_size, int flag)
+{
+ off_t readcounter= 0,writecounter= 0;
+
+ *size= track->fixed_size;
+ *padding= track->padding;
+ *use_data_image_size= track->use_data_image_size;
+ if((flag&1) && track->libburn_track!=NULL) {
+ burn_track_get_counters(track->libburn_track,&readcounter,&writecounter);
+ *size= readcounter;
+ *padding= writecounter-readcounter;
+ } else if(flag&2)
+ *padding= track->tao_to_sao_tsize;
+ *sector_size= track->sector_size;
+ return(1);
+}
+
+
+int Cdrtrack_get_iso_fs_descr(struct CdrtracK *track,
+ char **descr, double *size, int flag)
+{
+ *descr= track->iso_fs_descr;
+ *size= track->data_image_size;
+ return(*descr != NULL && *size > 0.0);
+}
+
+
+int Cdrtrack_get_source_path(struct CdrtracK *track,
+ char **source_path, int *source_fd, int *is_from_stdin, int flag)
+{
+ *source_path= track->original_source_path;
+ *source_fd= track->source_fd;
+ *is_from_stdin= track->is_from_stdin;
+ return(1);
+}
+
+
+#ifdef Cdrskin_use_libburn_fifO
+
+int Cdrtrack_get_libburn_fifo(struct CdrtracK *track,
+ struct burn_source **fifo, int flag)
+{
+ *fifo= track->libburn_fifo;
+ return(1);
+}
+
+
+int Cdrtrack_report_fifo(struct CdrtracK *track, int flag)
+{
+ int size, free_bytes, ret;
+ int total_min_fill, interval_min_fill, put_counter, get_counter;
+ int empty_counter, full_counter;
+ double fifo_percent;
+ char *status_text;
+
+ if(track->libburn_fifo == NULL)
+ return(0);
+
+ /* Check for open input or leftover bytes in liburn fifo */
+ ret = burn_fifo_inquire_status(track->libburn_fifo, &size, &free_bytes,
+ &status_text);
+ if(ret >= 0 && size - free_bytes > 1) {
+ /* not clear why free_bytes is reduced by 1 */
+ fprintf(stderr,
+ "cdrskin: FATAL : Fifo still contains data after burning has ended.\n");
+ fprintf(stderr,
+ "cdrskin: FATAL : %d bytes left.\n", size - free_bytes - 1);
+ fprintf(stderr,
+ "cdrskin: FATAL : This indicates an overflow of the last track.\n");
+ fprintf(stderr,
+ "cdrskin: NOTE : The media might appear ok but is probably truncated.\n");
+ return(-1);
+ }
+
+ burn_fifo_get_statistics(track->libburn_fifo, &total_min_fill,
+ &interval_min_fill, &put_counter, &get_counter,
+ &empty_counter, &full_counter);
+ fifo_percent= 100.0*((double) total_min_fill)/(double) size;
+ if(fifo_percent==0 && total_min_fill>0)
+ fifo_percent= 1;
+ fflush(stdout);
+ fprintf(stderr,"Cdrskin: fifo had %d puts and %d gets.\n",
+ put_counter,get_counter);
+ fprintf(stderr,
+ "Cdrskin: fifo was %d times empty and %d times full, min fill was %.f%%.\n",
+ empty_counter, full_counter, fifo_percent);
+ return(1);
+}
+
+#endif /* Cdrskin_use_libburn_fifO */
+
+
+int Cdrtrack_get_fifo(struct CdrtracK *track, struct CdrfifO **fifo, int flag)
+{
+ *fifo= track->fifo;
+ return(1);
+}
+
+
+/** Try whether automatic audio extraction is appropriate and eventually open
+ a file descriptor to the raw data.
+ @return -3 identified as .wav but with cdrecord-inappropriate parameters
+ -2 could not open track source, no use in retrying
+ -1 severe error
+ 0 not appropriate to extract, burn plain file content
+ 1 to be extracted, *fd is a filedescriptor delivering raw data
+*/
+int Cdrtrack_extract_audio(struct CdrtracK *track, int *fd, off_t *xtr_size,
+ int flag)
+{
+ int l, ok= 0;
+ struct libdax_audioxtr *xtr= NULL;
+ char *fmt,*fmt_info;
+ int num_channels,sample_rate,bits_per_sample,msb_first,ret;
+
+ *fd= -1;
+
+ if(track->track_type!=BURN_AUDIO && !track->track_type_by_default)
+ return(0);
+ l= strlen(track->source_path);
+ if(l>=4)
+ if(strcmp(track->source_path+l-4,".wav")==0)
+ ok= 1;
+ if(l>=3)
+ if(strcmp(track->source_path+l-3,".au")==0)
+ ok= 1;
+ if(!ok)
+ return(0);
+
+ if(track->track_type_by_default) {
+ Cdrtrack_set_track_type(track,BURN_AUDIO,0);
+ track->track_type_by_default= 2;
+ fprintf(stderr,"cdrskin: NOTE : Activated -audio for '%s'\n",
+ track->source_path);
+ }
+
+ ret= libdax_audioxtr_new(&xtr,track->source_path,0);
+ if(ret<=0)
+ return(ret);
+ libdax_audioxtr_get_id(xtr,&fmt,&fmt_info,
+ &num_channels,&sample_rate,&bits_per_sample,&msb_first,0);
+ if((strcmp(fmt,".wav")!=0 && strcmp(fmt,".au")!=0) ||
+ num_channels!=2 || sample_rate!=44100 || bits_per_sample!=16) {
+ fprintf(stderr,"cdrskin: ( %s )\n",fmt_info);
+ fprintf(stderr,"cdrskin: FATAL : Inappropriate audio coding in '%s'.\n",
+ track->source_path);
+ {ret= -3; goto ex;}
+ }
+ libdax_audioxtr_get_size(xtr,xtr_size,0);
+ ret= libdax_audioxtr_detach_fd(xtr,fd,0);
+ if(ret<=0)
+ {ret= -1*!!ret; goto ex;}
+ track->swap_audio_bytes= !!msb_first;
+ track->extracting_container= 1;
+ fprintf(stderr,"cdrskin: NOTE : %.f %saudio bytes in '%s'\n",
+ (double) *xtr_size, (msb_first ? "" : "(-swab) "),
+ track->source_path);
+ ret= 1;
+ex:
+ libdax_audioxtr_destroy(&xtr,0);
+ return(ret);
+}
+
+
+/* @param flag bit0=set *size_used as the detected data image size
+*/
+int Cdrtrack_activate_image_size(struct CdrtracK *track, double *size_used,
+ int flag)
+{
+ if(flag&1)
+ track->data_image_size= *size_used;
+ else
+ *size_used= track->data_image_size;
+ if(track->use_data_image_size!=1)
+ return(2);
+ if(*size_used<=0)
+ return(0);
+ track->fixed_size= *size_used;
+ track->use_data_image_size= 2;
+ if(track->libburn_track!=NULL)
+ burn_track_set_size(track->libburn_track, (off_t) *size_used);
+ /* man cdrecord prescribes automatic -pad with -isosize.
+ cdrskin obeys only if the current padding is less than that. */
+ if(track->padding<15*2048) {
+ track->padding= 15*2048;
+ track->set_by_padsize= 0;
+ }
+ track->extracting_container= 1;
+
+#ifndef Cdrskin_no_cdrfifO
+ if(track->ff_fifo!=NULL)
+ Cdrfifo_set_fd_in_limit(track->ff_fifo,track->fixed_size,track->ff_idx,0);
+#endif
+
+ return(1);
+}
+
+
+int Cdrtrack_seek_isosize(struct CdrtracK *track, int fd, int flag)
+{
+ struct stat stbuf;
+ char secbuf[2048];
+ int ret,got,i;
+ double size;
+
+ if(fstat(fd,&stbuf)==-1)
+ return(0);
+ if((stbuf.st_mode&S_IFMT)!=S_IFREG && (stbuf.st_mode&S_IFMT)!=S_IFBLK)
+ return(2);
+
+ if(track->iso_fs_descr!=NULL)
+ free((char *) track->iso_fs_descr);
+ track->iso_fs_descr= TSOB_FELD(char,16*2048);
+ if(track->iso_fs_descr==NULL)
+ return(-1);
+ for(i=0;i<32 && track->data_image_size<=0;i++) {
+ for(got= 0; got<2048;got+= ret) {
+ ret= read(fd, secbuf+got, 2048-got);
+ if(ret<=0)
+ return(0);
+ }
+ if(i<16)
+ continue;
+ memcpy(track->iso_fs_descr+(i-16)*2048,secbuf,2048);
+ if(i>16)
+ continue;
+ ret= Scan_for_iso_size((unsigned char *) secbuf, &size, 0);
+ if(ret<=0)
+ break;
+ track->data_image_size= size;
+ if(track->use_data_image_size) {
+ Cdrtrack_activate_image_size(track,&size,1);
+ track->fixed_size= size;
+ track->use_data_image_size= 2;
+ }
+ }
+ ret= lseek(fd, (off_t) 0, SEEK_SET);
+ if(ret!=0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Cannot lseek() to 0 after -isosize determination\n");
+ if(errno!=0)
+ fprintf(stderr, "cdrskin: errno=%d : %s\n", errno, strerror(errno));
+ return(-1);
+ }
+ return(track->data_image_size>0);
+}
+
+
+/** Deliver an open file descriptor corresponding to the source path of track.
+ @param flag Bitfield for control purposes:
+ bit0=debugging verbosity
+ bit1=open as source for direct write:
+ no audio extract, no minimum track size
+ bit2=permission to use burn_os_open_track_src() (evtl O_DIRECT)
+ @return <=0 error, 1 success
+*/
+int Cdrtrack_open_source_path(struct CdrtracK *track, int *fd, int flag)
+{
+ int is_wav= 0, size_from_file= 0, ret, self_opened= 0;
+ off_t xtr_size= 0;
+ struct stat stbuf;
+ char *device_adr,*raw_adr;
+ int no_convert_fs_adr;
+ int Cdrskin_get_device_adr(struct CdrskiN *skin,
+ char **device_adr, char **raw_adr, int *no_convert_fs_adr,int flag);
+ int Cdrskin_get_drive(struct CdrskiN *skin, struct burn_drive **drive,
+ int flag);
+ struct burn_drive *drive;
+
+ if(track->source_path[0]=='-' && track->source_path[1]==0)
+ *fd= 0;
+ else if(track->source_path[0]=='#' &&
+ (track->source_path[1]>='0' && track->source_path[1]<='9'))
+ *fd= atoi(track->source_path+1);
+ else {
+ *fd= -1;
+ self_opened= 1;
+
+ ret= Cdrskin_get_device_adr(track->boss,&device_adr,&raw_adr,
+ &no_convert_fs_adr,0);
+ if(ret <= 0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : No drive found. Cannot prepare track.\n");
+ return(0);
+ }
+/*
+ fprintf(stderr,
+ "cdrskin: DEBUG : device_adr='%s' , raw_adr='%s' , ncfs=%d\n",
+ device_adr, raw_adr, no_convert_fs_adr);
+*/
+ if(!no_convert_fs_adr) {
+ if(flag&1)
+ ClN(fprintf(stderr,
+ "cdrskin_debug: checking track source for identity with drive\n"));
+
+ ret= Cdrskin_get_drive(track->boss,&drive,0);
+ if(ret<=0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Program error. Cannot determine libburn drive.\n");
+ return(0);
+ }
+ if(burn_drive_equals_adr(drive,track->source_path,2)>0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : track source address leads to burner drive\n");
+ fprintf(stderr,
+ "cdrskin: : dev='%s' -> '%s' <- track source '%s'\n",
+ raw_adr, device_adr, track->source_path);
+ return(0);
+ }
+ }
+/*
+ fprintf(stderr,"cdrskin: EXPERIMENTAL : Deliberate abort\n");
+ return(0);
+*/
+
+ if(!(flag&2))
+ is_wav= Cdrtrack_extract_audio(track,fd,&xtr_size,0);
+ if(is_wav==-1)
+ return(-1);
+ if(is_wav==-3)
+ return(0);
+ if(is_wav==0) {
+ if(track->track_type != BURN_MODE1 ||
+ (track->cdxa_conversion & 0x7fffffff))
+ flag&= ~4; /* Better avoid O_DIRECT with odd sectors */
+ if(flag & 4)
+ *fd= burn_os_open_track_src(track->source_path, O_RDONLY, 0);
+ else
+ *fd= open(track->source_path, O_RDONLY);
+ }
+ if(*fd==-1) {
+ fprintf(stderr,"cdrskin: failed to open source address '%s'\n",
+ track->source_path);
+ fprintf(stderr,"cdrskin: errno=%d , \"%s\"\n",errno,
+ errno==0?"-no error code available-":strerror(errno));
+ return(0);
+ }
+ if(track->use_data_image_size==1 && xtr_size<=0) {
+ ret= Cdrtrack_seek_isosize(track,*fd,0);
+ if(ret == -1) {
+ close(*fd);
+ *fd= -1;
+ return(-1);
+ }
+ } else if(track->fixed_size<=0) {
+
+ /* >>> ??? is it intentional that tsize overrides .wav header ? */
+ if(xtr_size>0) {
+
+ track->fixed_size= xtr_size;
+ if(track->use_data_image_size==1)
+ track->use_data_image_size= 2; /* count this as image size found */
+ size_from_file= 1;
+ } else {
+ if(fstat(*fd,&stbuf)!=-1) {
+ if((stbuf.st_mode&S_IFMT)==S_IFREG) {
+ track->fixed_size= stbuf.st_size;
+ size_from_file= 1;
+ } /* all other types are assumed of open ended size */
+ }
+ }
+ }
+ }
+
+ track->source_fd= *fd;
+ if(track->fixed_size < Cdrtrack_minimum_sizE * track->sector_size
+ && (track->fixed_size>0 || size_from_file) && !(flag&2)) {
+ if(track->track_type == BURN_AUDIO) {
+ /* >>> cdrecord: We differ in automatic padding with audio:
+ Audio tracks must be at least 705600 bytes and a multiple of 2352.
+ */
+ fprintf(stderr,
+ "cdrskin: FATAL : Audio tracks must be at least %.f bytes\n",
+ Cdrtrack_minimum_sizE*track->sector_size);
+ return(0);
+ } else {
+ fprintf(stderr,
+ "cdrskin: NOTE : Enforcing minimum track size of %.f bytes\n",
+ Cdrtrack_minimum_sizE*track->sector_size);
+ track->fixed_size= Cdrtrack_minimum_sizE*track->sector_size;
+ }
+ }
+ return((*fd >= 0) * (1 + self_opened));
+}
+
+
+#ifndef Cdrskin_no_cdrfifO
+
+/** Install a fifo object between data source and libburn.
+ Its parameters are known to track.
+ @param outlet_fd Returns the filedescriptor of the fifo outlet.
+ @param previous_fifo Object address for chaining or follow-up attachment.
+ @param flag Bitfield for control purposes:
+ bit0= Debugging verbosity
+ bit1= Do not create and attach a new fifo
+ but attach new follow-up fd pair to previous_fifo
+ bit2= Do not enforce fixed_size if not container extraction
+ @return <=0 error, 1 success
+*/
+int Cdrtrack_attach_fifo(struct CdrtracK *track, int *outlet_fd,
+ struct CdrfifO *previous_fifo, int flag)
+{
+ struct CdrfifO *ff;
+ int source_fd,pipe_fds[2],ret;
+
+ *outlet_fd= -1;
+ if(track->fifo_size<=0)
+ return(2);
+ ret= Cdrtrack_open_source_path(track,&source_fd,
+ (flag&1) | (4 * (track->fifo_size >= 256 * 1024)));
+ if(ret<=0)
+ return(ret);
+ if(pipe(pipe_fds)==-1)
+ return(0);
+
+ Cdrfifo_destroy(&(track->fifo),0);
+ if(flag&2) {
+ ret= Cdrfifo_attach_follow_up_fds(previous_fifo,source_fd,pipe_fds[1],0);
+ if(ret<=0)
+ return(ret);
+ track->ff_fifo= previous_fifo;
+ track->ff_idx= ret-1;
+ } else {
+
+ /* >>> ??? obtain track sector size and use instead of 2048 ? */
+
+ ret= Cdrfifo_new(&ff,source_fd,pipe_fds[1],2048,track->fifo_size, flag & 1);
+ if(ret<=0)
+ return(ret);
+ if(previous_fifo!=NULL)
+ Cdrfifo_attach_peer(previous_fifo,ff,0);
+ track->fifo= track->ff_fifo= ff;
+ track->ff_idx= -1;
+ }
+ track->fifo_outlet_fd= pipe_fds[0];
+
+ if((track->extracting_container || !(flag&4)) && track->fixed_size>0)
+ Cdrfifo_set_fd_in_limit(track->ff_fifo,track->fixed_size,track->ff_idx,0);
+
+ if(flag&1)
+ printf(
+ "cdrskin_debug: track %d fifo replaced source_address '%s' by '#%d'\n",
+ track->trackno+1,track->source_path,track->fifo_outlet_fd);
+ sprintf(track->source_path,"#%d",track->fifo_outlet_fd);
+ track->source_fd= track->fifo_outlet_fd;
+ *outlet_fd= track->fifo_outlet_fd;
+ return(1);
+}
+
+#endif /* ! Cdrskin_no_cdrfifO */
+
+
+#ifndef Cdrskin_extra_leaN
+
+#ifdef Cdrskin_use_libburn_fifO
+
+/** Read data into the eventual libburn fifo until either fifo_start_at bytes
+ are read (-1 = no limit), it is full or or the data source is exhausted.
+ @return <=0 error, 1 success
+*/
+int Cdrtrack_fill_libburn_fifo(struct CdrtracK *track, int fifo_start_at,
+ int flag)
+{
+ int ret, bs= 32 * 1024;
+ int buffer_size, buffer_free;
+ double data_image_size;
+ char buf[64 * 1024], *buffer_text;
+
+ if(fifo_start_at == 0)
+ return(2);
+ if(track->libburn_fifo == NULL)
+ return(2);
+
+ if(fifo_start_at>0 && fifo_start_atfifo_size)
+ printf(
+ "cdrskin: NOTE : Input buffer will be initially filled up to %d bytes\n",
+ fifo_start_at);
+ printf("Waiting for reader process to fill input buffer ... ");
+ fflush(stdout);
+ ret= burn_fifo_fill(track->libburn_fifo, fifo_start_at,
+ (fifo_start_at == -1));
+ if(ret < 0)
+ return(0);
+
+/** Ticket 55: check fifos for input, throw error on 0-bytes from stdin
+ @return <=0 abort run, 1 go on with burning
+*/
+ ret= burn_fifo_inquire_status(track->libburn_fifo, &buffer_size,
+ &buffer_free, &buffer_text);
+ if(track->is_from_stdin) {
+ if(ret<0 || buffer_size <= buffer_free) {
+ fprintf(stderr,"\ncdrskin: FATAL : (First track) fifo did not read a single byte from stdin\n");
+ return(0);
+ }
+ }
+
+ /* Try to obtain ISO 9660 Volume Descriptors and size from fifo.
+ Not an error if there is no ISO 9660. */
+ if(track->iso_fs_descr != NULL)
+ free(track->iso_fs_descr);
+ track->iso_fs_descr = NULL;
+ if(buffer_size - buffer_free >= 64 * 1024) {
+ ret= burn_fifo_peek_data(track->libburn_fifo, buf, 64 * 1024, 0);
+ if(ret == 1) {
+ track->iso_fs_descr = calloc(1, bs);
+ if(track->iso_fs_descr == NULL)
+ return(-1);
+ memcpy(track->iso_fs_descr, buf + bs, bs);
+ ret= Scan_for_iso_size((unsigned char *) buf + bs, &data_image_size, 0);
+ if(ret > 0)
+ track->data_image_size= data_image_size;
+ }
+ }
+ return(1);
+}
+
+#endif /* Cdrskin_use_libburn_fifO */
+
+
+#ifdef Cdrskin_no_cdrfifO
+
+int Cdrtrack_fill_fifo(struct CdrtracK *track, int fifo_start_at, int flag)
+{
+ return(Cdrtrack_fill_libburn_fifo(track, fifo_start_at, 0));
+}
+
+#else /* Cdrskin_no_cdrfifO */
+
+int Cdrtrack_fill_fifo(struct CdrtracK *track, int fifo_start_at, int flag)
+{
+ int ret,buffer_fill,buffer_space;
+ double data_image_size;
+
+ if(fifo_start_at==0)
+ return(2);
+ if(track->fifo==NULL) {
+#ifdef Cdrskin_use_libburn_fifO
+ ret= Cdrtrack_fill_libburn_fifo(track, fifo_start_at, 0);
+ return(ret);
+#else
+ return(2);
+#endif
+ }
+ if(fifo_start_at>0 && fifo_start_atfifo_size)
+ printf(
+ "cdrskin: NOTE : Input buffer will be initially filled up to %d bytes\n",
+ fifo_start_at);
+ printf("Waiting for reader process to fill input buffer ... ");
+ fflush(stdout);
+ ret= Cdrfifo_fill(track->fifo,fifo_start_at,0);
+ if(ret<=0)
+ return(ret);
+
+/** Ticket 55: check fifos for input, throw error on 0-bytes from stdin
+ @return <=0 abort run, 1 go on with burning
+*/
+ if(track->is_from_stdin) {
+ ret= Cdrfifo_get_buffer_state(track->fifo,&buffer_fill,&buffer_space,0);
+ if(ret<0 || buffer_fill<=0) {
+ fprintf(stderr,"\ncdrskin: FATAL : (First track) fifo did not read a single byte from stdin\n");
+ return(0);
+ }
+ }
+ ret= Cdrfifo_get_iso_fs_size(track->fifo,&data_image_size,0);
+ if(ret>0)
+ track->data_image_size= data_image_size;
+ if(track->iso_fs_descr!=NULL)
+ free((char *) track->iso_fs_descr);
+ Cdrfifo_adopt_iso_fs_descr(track->fifo,&(track->iso_fs_descr),0);
+ return(1);
+}
+
+#endif /* ! Cdrskin_no_cdrfifO */
+#endif /* ! Cdrskin_extra_leaN */
+
+
+int Cdrtrack_set_indice(struct CdrtracK *track, int flag)
+{
+ int idx= 1, adr, prev_adr= -1, ret;
+ char *cpt, *ept;
+
+ if(track->sao_pregap >= 0) {
+ ret= burn_track_set_pregap_size(track->libburn_track, track->sao_pregap, 0);
+ if(ret <= 0)
+ return(ret);
+ }
+ if(track->sao_postgap >= 0) {
+ ret= burn_track_set_postgap_size(track->libburn_track, track->sao_postgap,
+ 0);
+ if(ret <= 0)
+ return(ret);
+ }
+
+ if(track->index_string == NULL)
+ return(2);
+
+ for(ept= cpt= track->index_string; ept != NULL; cpt= ept + 1) {
+ ept= strchr(cpt, ',');
+ if(ept != NULL)
+ *ept= 0;
+ adr= -1;
+ sscanf(cpt, "%d", &adr);
+ if(adr < 0) {
+ fprintf(stderr, "cdrskin: SORRY : Bad address number with index=\n");
+ return(0);
+ }
+ if(idx == 1 && adr != 0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : First address number of index= is not 0\n");
+ return(0);
+ }
+ if(idx > 1 && adr < prev_adr) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Backward address number with index=\n");
+ return(0);
+ }
+ ret= burn_track_set_index(track->libburn_track, idx, adr, 0);
+ if(ret <= 0)
+ return(ret);
+ prev_adr= adr;
+ if(ept != NULL)
+ *ept= ',';
+ idx++;
+ }
+
+ return(1);
+}
+
+/** Create a corresponding libburn track object and add it to the libburn
+ session. This may change the trackno index set by Cdrtrack_new().
+*/
+int Cdrtrack_add_to_session(struct CdrtracK *track, int trackno,
+ struct burn_session *session, int flag)
+/*
+ bit0= debugging verbosity
+ bit1= apply padding hack (<<< should be unused for now)
+ bit2= permission to use O_DIRECT (if enabled at compile time)
+*/
+{
+ struct burn_track *tr;
+ struct burn_source *src= NULL;
+ double padding,lib_padding;
+ int ret,sector_pad_up;
+ double fixed_size;
+ int source_fd;
+
+#ifdef Cdrskin_use_libburn_fifO
+ struct burn_source *fd_src= NULL;
+#endif
+
+ track->trackno= trackno;
+ tr= burn_track_create();
+ if(tr == NULL)
+ {ret= -1; goto ex;}
+ track->libburn_track= tr;
+ track->libburn_track_is_own= 1;
+
+ /* Note: track->track_type may get set in here */
+ if(track->source_fd==-1) {
+ ret= Cdrtrack_open_source_path(track, &source_fd, flag & (4 | 1));
+ if(ret<=0)
+ goto ex;
+ }
+
+ padding= 0.0;
+ sector_pad_up= track->sector_pad_up;
+ if(track->padding>0) {
+ if(track->set_by_padsize || track->track_type!=BURN_AUDIO)
+ padding= track->padding;
+ else
+ sector_pad_up= 1;
+ }
+ if(flag&2)
+ lib_padding= 0.0;
+ else
+ lib_padding= padding;
+ if(flag&1) {
+ if(sector_pad_up) {
+ ClN(fprintf(stderr,"cdrskin_debug: track %d telling burn_track_define_data() to pad up last sector\n",trackno+1));
+ }
+ if(lib_padding>0 || !sector_pad_up) {
+ ClN(fprintf(stderr,
+ "cdrskin_debug: track %d telling burn_track_define_data() to pad %.f bytes\n",
+ trackno+1,lib_padding));
+ }
+ }
+ burn_track_define_data(tr,0,(int) lib_padding,sector_pad_up,
+ track->track_type | track->mode_modifiers);
+ burn_track_set_default_size(tr, (off_t) track->tao_to_sao_tsize);
+ burn_track_set_byte_swap(tr,
+ (track->track_type==BURN_AUDIO && track->swap_audio_bytes));
+ if(!(track->cdxa_conversion & (1 << 31)))
+ burn_track_set_cdxa_conv(tr, track->cdxa_conversion & 0x7fffffff);
+
+ fixed_size= track->fixed_size;
+ if((flag&2) && track->padding>0) {
+ if(flag&1)
+ ClN(fprintf(stderr,"cdrskin_debug: padding hack : %.f + %.f = %.f\n",
+ track->fixed_size,track->padding,
+ track->fixed_size+track->padding));
+ fixed_size+= track->padding;
+ }
+ src= burn_fd_source_new(track->source_fd,-1,(off_t) fixed_size);
+
+#ifdef Cdrskin_use_libburn_fifO
+
+ if(src != NULL && track->fifo == NULL) {
+ int fifo_enabled, fifo_size, fifo_start_at, chunksize, chunks;
+ int Cdrskin_get_fifo_par(struct CdrskiN *skin, int *fifo_enabled,
+ int *fifo_size, int *fifo_start_at, int flag);
+
+ Cdrskin_get_fifo_par(track->boss, &fifo_enabled, &fifo_size, &fifo_start_at,
+ 0);
+
+ if(track->track_type == BURN_AUDIO)
+ chunksize= 2352;
+ else if (track->cdxa_conversion == 1)
+ chunksize= 2056;
+ else
+ chunksize= 2048;
+ chunks= fifo_size / chunksize;
+ if(chunks > 1 && fifo_enabled) {
+ fd_src= src;
+ src= burn_fifo_source_new(fd_src, chunksize, chunks,
+ (chunksize * chunks >= 128 * 1024));
+ if((flag & 1) || src == NULL)
+ fprintf(stderr, "cdrskin_DEBUG: %s libburn fifo of %d bytes\n",
+ src != NULL ? "installed" : "failed to install",
+ chunksize * chunks);
+ track->libburn_fifo= src;
+ if(src == NULL) {
+ src= fd_src;
+ fd_src= NULL;
+ }
+ }
+ }
+
+#endif /* Cdrskin_use_libburn_fifO */
+
+ if(src==NULL) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Could not create libburn data source object\n");
+ {ret= 0; goto ex;}
+ }
+ if(burn_track_set_source(tr,src)!=BURN_SOURCE_OK) {
+ fprintf(stderr,"cdrskin: FATAL : libburn rejects data source object\n");
+ {ret= 0; goto ex;}
+ }
+ ret= Cdrtrack_set_indice(track, 0);
+ if(ret <= 0)
+ goto ex;
+
+ burn_session_add_track(session,tr,BURN_POS_END);
+ ret= 1;
+ex:
+
+#ifdef Cdrskin_use_libburn_fifO
+ if(fd_src!=NULL)
+ burn_source_free(fd_src);
+#endif
+
+ if(src!=NULL)
+ burn_source_free(src);
+ return(ret);
+}
+
+
+/** Release libburn track information after a session is done */
+int Cdrtrack_cleanup(struct CdrtracK *track, int flag)
+{
+ if(track->libburn_track==NULL)
+ return(0);
+ if(track->libburn_track_is_own)
+ burn_track_free(track->libburn_track);
+ track->libburn_track= NULL;
+ return(1);
+}
+
+
+int Cdrtrack_ensure_padding(struct CdrtracK *track, int flag)
+/*
+flag:
+ bit0= debugging verbosity
+*/
+{
+ if(track->track_type!=BURN_AUDIO)
+ return(2);
+ if(flag&1)
+ fprintf(stderr,"cdrskin_debug: enforcing -pad on last -audio track\n");
+ track->sector_pad_up= 1;
+ return(1);
+}
+
+
+int Cdrtrack_get_sectors(struct CdrtracK *track, int flag)
+{
+ return(burn_track_get_sectors(track->libburn_track));
+}
+
+
+#ifndef Cdrskin_no_cdrfifO
+
+/** Try to read bytes from the track's fifo outlet and eventually discard
+ them. Not to be called unless the track is completely written.
+*/
+int Cdrtrack_has_input_left(struct CdrtracK *track, int flag)
+{
+ int ready,ret;
+ char buf[2];
+
+ if(track->fifo_outlet_fd<=0)
+ return(0);
+ ready= Wait_for_input(track->fifo_outlet_fd, 0, 0);
+ if(ready<=0)
+ return(0);
+ ret= read(track->fifo_outlet_fd,buf,1);
+ if(ret>0)
+ return(1);
+ return(0);
+}
+
+#endif /* ! Cdrskin_no_cdrfifO */
+
+
+/* --------------------------------------------------------------------- */
+
+/** The list of startup file names */
+#define Cdrpreskin_rc_nuM 4
+
+static char Cdrpreskin_sys_rc_nameS[Cdrpreskin_rc_nuM][80]= {
+ "/etc/default/cdrskin",
+ "/etc/opt/cdrskin/rc",
+ "/etc/cdrskin/cdrskin.conf",
+ "placeholder for $HOME/.cdrskinrc"
+};
+
+
+/** A structure which bundles several parameters for creation of the CdrskiN
+ object. It finally becomes a managed subordinate of the CdrskiN object.
+*/
+struct CdrpreskiN {
+
+ /* to be transferred into skin */
+ int verbosity;
+ char queue_severity[81];
+ char print_severity[81];
+
+ /** Whether to wait for available standard input data before touching drives*/
+ int do_waiti;
+
+ /** Stores eventually given absolute device address before translation */
+ char raw_device_adr[Cdrskin_adrleN];
+
+ /** Stores an eventually given translated absolute device address between
+ Cdrpreskin_setup() and Cdrskin_create() .
+ */
+ char device_adr[Cdrskin_adrleN];
+
+ /** The eventual address translation table */
+ struct CdradrtrN *adr_trn;
+
+ /** Memorizes the abort handling mode from presetup to creation of
+ control object. Defined handling modes are:
+ 0= no abort handling
+ 1= try to cancel, release, exit (leave signal mode as set by caller)
+ 2= try to ignore all signals
+ 3= mode 1 in normal operation, mode 2 during abort handling
+ 4= mode 1 in normal operation, mode 0 during abort handling
+ -1= install abort handling 1 only in Cdrskin_burn() after burning started
+ */
+ int abort_handler;
+
+ /** Whether to allow getuid()!=geteuid() */
+ int allow_setuid;
+
+ /** Whether to allow user provided addresses like #4 */
+ int allow_fd_source;
+
+ /** Whether to support media types which are implemented but yet untested */
+ int allow_untested_media;
+
+ /** Whether to allow libburn pseudo-drives "stdio:" .
+ 0=forbidden, 1=seems ok,
+ 2=potentially forbidden (depends on uid, euid, file type)
+ */
+ int allow_emulated_drives;
+
+ /** Whether an option is given which needs a full bus scan */
+ int no_whitelist;
+
+ /** Whether the translated device address shall not follow softlinks, device
+ clones and SCSI addresses */
+ int no_convert_fs_adr;
+
+ /** Whether Bus,Target,Lun addresses shall be converted literally as old
+ Pseudo SCSI-Adresses. New default is to use (possibly system emulated)
+ real SCSI addresses via burn_drive_convert_scsi_adr() and literally
+ emulated and cdrecord-incompatible ATA: addresses. */
+ int old_pseudo_scsi_adr;
+
+ /** Whether to omit bus scanning */
+ int do_not_scan;
+
+ /** Whether bus scans shall exit!=0 if no drive was found */
+ int scan_demands_drive;
+
+ /** Whether to abort when a busy drive is encountered during bus scan */
+ int abort_on_busy_drive;
+
+ /** Linux specific : Whether to try to avoid collisions when opening drives */
+ int drive_exclusive;
+
+ /** Linux specific : Whether to obtain an exclusive drive lock via fcntl() */
+ int drive_fcntl_f_setlk;
+
+ /** Linux specific : Device file address family to use :
+ 0=default , 1=sr , 2=scd , 4=sg */
+ int drive_scsi_dev_family;
+
+
+ /** Whether to try to wait for unwilling drives to become willing to open */
+ int drive_blocking;
+
+ /** Explicit write mode option is determined before skin processes
+ any track arguments */
+ char write_mode_name[80];
+
+#ifndef Cdrskin_extra_leaN
+
+ /** List of startupfiles */
+ char rc_filenames[Cdrpreskin_rc_nuM][Cdrskin_strleN];
+ int rc_filename_count;
+
+ /** Non-argument options from startupfiles */
+ int pre_argc;
+ char **pre_argv;
+ int *pre_argidx;
+ int *pre_arglno;
+
+#endif /* ! Cdrskin_extra_leaN */
+
+ /* The eventual name of a program to be executed if demands_cdrecord_caps
+ is >0 and demands_cdrskin_caps is <=0
+ */
+ char fallback_program[Cdrskin_strleN];
+ int demands_cdrecord_caps;
+ int demands_cdrskin_caps;
+
+ int result_fd;
+
+};
+
+
+/** Create a preliminary cdrskin program run control object. It will become
+ part of the final control object.
+ @param preskin Returns pointer to resulting
+ @param flag Bitfield for control purposes: unused yet
+ @return <=0 error, 1 success
+*/
+int Cdrpreskin_new(struct CdrpreskiN **preskin, int flag)
+{
+ struct CdrpreskiN *o;
+ int i;
+
+ (*preskin)= o= TSOB_FELD(struct CdrpreskiN,1);
+ if(o==NULL)
+ return(-1);
+
+ o->verbosity= 0;
+ strcpy(o->queue_severity,"NEVER");
+ strcpy(o->print_severity,"SORRY");
+ o->do_waiti= 0;
+ o->raw_device_adr[0]= 0;
+ o->device_adr[0]= 0;
+ o->adr_trn= NULL;
+ o->abort_handler= 3;
+ o->allow_setuid= 0;
+ o->allow_fd_source= 0;
+ o->allow_untested_media= 0;
+ o->allow_emulated_drives= 0;
+ o->no_whitelist= 0;
+ o->no_convert_fs_adr= 0;
+ o->old_pseudo_scsi_adr= 0;
+ o->do_not_scan= 0;
+ o->scan_demands_drive= 0;
+ o->abort_on_busy_drive= 0;
+ o->drive_exclusive= 1;
+ o->drive_fcntl_f_setlk= 1;
+ o->drive_scsi_dev_family= 0;
+ o->drive_blocking= 0;
+ strcpy(o->write_mode_name,"DEFAULT");
+
+#ifndef Cdrskin_extra_leaN
+ o->rc_filename_count= Cdrpreskin_rc_nuM;
+ for(i=0;irc_filename_count-1;i++)
+ strcpy(o->rc_filenames[i],Cdrpreskin_sys_rc_nameS[i]);
+ o->rc_filenames[o->rc_filename_count-1][0]= 0;
+ o->pre_argc= 0;
+ o->pre_argv= NULL;
+ o->pre_argidx= NULL;
+ o->pre_arglno= NULL;
+#endif /* ! Cdrskin_extra_leaN */
+
+ o->fallback_program[0]= 0;
+ o->demands_cdrecord_caps= 0;
+ o->demands_cdrskin_caps= 0;
+ o->result_fd = -1;
+ return(1);
+}
+
+
+int Cdrpreskin_destroy(struct CdrpreskiN **preskin, int flag)
+{
+ struct CdrpreskiN *o;
+
+ o= *preskin;
+ if(o==NULL)
+ return(0);
+
+#ifndef Cdrskin_extra_leaN
+ if((o->pre_arglno)!=NULL)
+ free((char *) o->pre_arglno);
+ if((o->pre_argidx)!=NULL)
+ free((char *) o->pre_argidx);
+ if(o->pre_argc>0 && o->pre_argv!=NULL)
+ Sfile_destroy_argv(&(o->pre_argc),&(o->pre_argv),0);
+ Cdradrtrn_destroy(&(o->adr_trn),0);
+#endif /* ! Cdrskin_extra_leaN */
+
+ free((char *) o);
+ *preskin= NULL;
+ return(1);
+}
+
+
+int Cdrpreskin_set_severities(struct CdrpreskiN *preskin, char *queue_severity,
+ char *print_severity, int flag)
+{
+ if(queue_severity!=NULL)
+ strcpy(preskin->queue_severity,queue_severity);
+ if(print_severity!=NULL)
+ strcpy(preskin->print_severity,print_severity);
+ burn_msgs_set_severities(preskin->queue_severity, preskin->print_severity,
+ "cdrskin: ");
+ return(1);
+}
+
+
+int Cdrpreskin_initialize_lib(struct CdrpreskiN *preskin, int flag)
+{
+ int ret, major, minor, micro;
+
+ /* Needed are at least 44 bits in signed type off_t .
+ This is a popular mistake in configuration or compilation.
+ */
+ if(sizeof(off_t) < 6) {
+ fprintf(stderr,
+"\ncdrskin: FATAL : Compile time misconfiguration. sizeof(off_t) too small.\n"
+ );
+ return(0);
+ }
+
+/* This is the minimum requirement of cdrskin towards the libburn header
+ at compile time.
+ It gets compared against the version macros in libburn/libburn.h :
+ burn_header_version_major
+ burn_header_version_minor
+ burn_header_version_micro
+ If the header is too old then the following code shall cause failure of
+ cdrskin compilation rather than to allow production of a program with
+ unpredictable bugs or memory corruption.
+ The compiler message supposed to appear in this case is:
+ error: 'LIBBURN_MISCONFIGURATION' undeclared (first use in this function)
+ error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_cdrskin_dot_c' undeclared (first use in this function)
+ error: 'LIBBURN_MISCONFIGURATION_' undeclared (first use in this function)
+*/
+
+/* The indendation is an advise of man gcc to help old compilers ignoring */
+ #if Cdrskin_libburn_majoR > burn_header_version_major
+ #define Cdrskin_libburn_dot_h_too_olD 1
+ #endif
+ #if Cdrskin_libburn_majoR == burn_header_version_major && Cdrskin_libburn_minoR > burn_header_version_minor
+ #define Cdrskin_libburn_dot_h_too_olD 1
+ #endif
+ #if Cdrskin_libburn_minoR == burn_header_version_minor && Cdrskin_libburn_micrO > burn_header_version_micro
+ #define Cdrskin_libburn_dot_h_too_olD 1
+ #endif
+
+#ifdef Cdrskin_libburn_dot_h_too_olD
+LIBBURN_MISCONFIGURATION = 0;
+INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_cdrskin_dot_c = 0;
+LIBBURN_MISCONFIGURATION_ = 0;
+#endif
+
+ ret= burn_initialize();
+ if(ret==0) {
+ fprintf(stderr,"cdrskin: FATAL : Initialization of libburn failed\n");
+ return(0);
+ }
+
+ /* This is the runtime check towards eventual dynamically linked libburn.
+ cdrskin deliberately does not to allow the library to be older than
+ the header file which was seen at compile time. More liberal would be
+ to use here Cdrskin_libburn_* instead of burn_header_version_* .
+ */
+ burn_version(&major, &minor, µ);
+ if(majorqueue_severity);
+ strcpy(print_severity,o->print_severity);
+ }
+ if(o->verbosity>=Cdrskin_verbose_debuG)
+ Cdrpreskin_set_severities(o,"DEBUG","NEVER",0);
+ else
+ Cdrpreskin_set_severities(o,"SORRY","NEVER",0);
+ queueing= 1;
+ return(1);
+ }
+
+ if(queueing)
+ Cdrpreskin_set_severities(o,queue_severity,print_severity,0);
+ queueing= 0;
+
+ for(first= 1; ; first= 0) {
+ ret= burn_msgs_obtain("ALL",&error_code,msg,&os_errno,msg_severity);
+ if(ret==0)
+ break;
+ if(ret<0) {
+ fprintf(stderr,
+ "cdrskin: NOTE : Please inform libburn-hackers@pykix.org about:\n");
+ fprintf(stderr,
+ "cdrskin: burn_msgs_obtain() returns %d\n",ret);
+ break;
+ }
+ if(first)
+ fprintf(stderr,
+"cdrskin: -------------------- Messages from Libburn ---------------------\n");
+ for(i=0;msg_severity[i]!=0;i++)
+ filler[i]= ' ';
+ filler[i]= 0;
+ fprintf(stderr,"cdrskin: %s : %s\n",msg_severity,msg);
+ if(strcmp(msg_severity,"DEBUG")!=0 && os_errno!=0)
+ fprintf(stderr,"cdrskin: %s ( errno=%d '%s')\n",
+ filler,os_errno,strerror(os_errno));
+ }
+ if(first==0)
+ fprintf(stderr,
+"cdrskin: ----------------------------------------------------------------\n");
+
+#endif /* Cdrskin_debug_libdax_msgS */
+
+ return(1);
+}
+
+
+/** Evaluate whether the user would be allowed in any case to use device_adr
+ as pseudo-drive */
+int Cdrpreskin__allows_emulated_drives(char *device_adr, char reason[4096],
+ int flag)
+{
+ struct stat stbuf;
+
+ reason[0]= 0;
+ if(device_adr[0]) {
+ if(strcmp(device_adr,"/dev/null")==0)
+ return(1);
+ strcat(reason,"File object is not /dev/null. ");
+ }
+
+ if(getuid()!=geteuid()) {
+ strcat(reason,"UID and EUID differ");
+ return(0);
+ }
+ if(getuid()!=0)
+ return(1);
+
+ strcat(reason,"UID is 0. ");
+ /* Directory must be owned by root and write protected against any others*/
+ if(lstat("/root/cdrskin_permissions",&stbuf)==-1 || !S_ISDIR(stbuf.st_mode)) {
+ strcat(reason, "No directory /root/cdrskin_permissions exists");
+ return(0);
+ }
+ if(stbuf.st_uid!=0) {
+ strcat(reason, "Directory /root/cdrskin_permissions not owned by UID 0");
+ return(0);
+ }
+ if(stbuf.st_mode & (S_IWGRP | S_IWOTH)) {
+ strcat(reason,
+ "Directory /root/cdrskin_permissions has w-permission for group or others");
+ return(0);
+ }
+ if(stat("/root/cdrskin_permissions/allow_emulated_drives",&stbuf)==-1) {
+ strcat(reason,
+ "No file /root/cdrskin_permissions/allow_emulated_drives exists");
+ return(0);
+ }
+ reason[0]= 0;
+ return(1);
+}
+
+
+int Cdrpreskin_consider_normal_user(int flag)
+{
+ fprintf(stderr,
+ "cdrskin: HINT : Consider to allow rw-access to the writer devices and\n");
+ fprintf(stderr,
+ "cdrskin: HINT : to run cdrskin under your normal user identity.\n");
+ return(1);
+}
+
+
+/* Start the fallback program as replacement of the cdrskin run.
+ @param flag bit0=do not report start command
+*/
+int Cdrpreskin_fallback(struct CdrpreskiN *preskin, int argc, char **argv,
+ int flag)
+{
+ char **hargv= NULL;
+ int i, wp= 1;
+ char *ept, *upt;
+
+ if(preskin->fallback_program[0] == 0)
+ return(1);
+ if(getuid()!=geteuid() && !preskin->allow_setuid) {
+ fprintf(stderr,
+ "cdrskin: SORRY : uid and euid differ. Will not start external fallback program.\n");
+ Cdrpreskin_consider_normal_user(0);
+ fprintf(stderr,
+ "cdrskin: HINT : Option --allow_setuid disables this safety check.\n");
+ goto failure;
+ }
+ if(!(flag&1)) {
+ fprintf(stderr,"cdrskin: --------------------------------------------------------------------\n");
+ fprintf(stderr,"cdrskin: Starting fallback program:\n");
+ }
+ hargv= TSOB_FELD(char *,argc+1);
+ if(hargv==NULL)
+ goto failure;
+ hargv[0]= strdup(preskin->fallback_program);
+ if(argv[0]==NULL)
+ goto failure;
+ if(!(flag&1))
+ fprintf(stderr," %s", hargv[0]);
+ for(i= 1; ifallback_program);
+ fprintf(stderr,"cdrskin: errno=%d \"%s\"\n",
+ errno, (errno > 0 ? strerror(errno) : "unidentified error"));
+ exit(15);
+}
+
+
+/** Convert a cdrecord-style device address into a libburn device address or
+ into a libburn drive number. It depends on the "scsibus" number of the
+ cdrecord-style address which kind of libburn address emerges:
+ bus=0 : drive number , bus=1 : /dev/sgN , bus=2 : /dev/hdX
+ (This call intentionally has no CdrpreskiN argument)
+ @param flag Bitfield for control purposes:
+ bit0= old_pseudo_scsi_adr
+ @return 1 success, 0=no recognizable format, -1=severe error,
+ -2 could not find scsi device, -3 address format error
+*/
+int Cdrpreskin__cdrecord_to_dev(char *adr, char device_adr[Cdrskin_adrleN],
+ int *driveno, int flag)
+{
+ int comma_seen= 0,digit_seen= 0,busno= 0,k,lun_no= -1;
+
+ *driveno= -1;
+ device_adr[0]= 0;
+ if(strlen(adr)==0)
+ return(0);
+ if(strncmp(adr,"stdio:",6)==0)
+ return(0);
+
+ /* read the trailing numeric string as device address code */
+ /* accepts "1" , "0,1,0" , "ATA:0,1,0" , ... */
+ for(k= strlen(adr)-1;k>=0;k--) {
+ if(adr[k]==',' && !comma_seen) {
+ sscanf(adr+k+1,"%d",&lun_no);
+ comma_seen= 1;
+ digit_seen= 0;
+ continue;
+ }
+ if(adr[k]<'0' || adr[k]>'9')
+ break;
+ digit_seen= 1;
+ }
+ if(!digit_seen) {
+ k= strlen(adr)-1;
+ if(adr[k]==':' || (adr[k]>='A' && adr[k]<='Z')) {/* empty prefix ? */
+ *driveno= 0;
+ return(1);
+ }
+ return(0);
+ }
+ sscanf(adr+k+1,"%d",driveno);
+
+ digit_seen= 0;
+ if(k>0) if(adr[k]==',') {
+ for(k--;k>=0;k--) {
+ if(adr[k]<'0' || adr[k]>'9')
+ break;
+ digit_seen= 1;
+ }
+ if(digit_seen) {
+ sscanf(adr+k+1,"%d",&busno);
+ if(flag&1) {
+ /* look for symbolic bus : 1=/dev/sgN 2=/dev/hdX */
+ if(busno==1) {
+ sprintf(device_adr,"/dev/sg%d",*driveno);
+ } else if(busno==2) {
+ sprintf(device_adr,"/dev/hd%c",'a'+(*driveno));
+ } else if(busno!=0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : dev=[Prefix:]Bus,Target,Lun expects Bus out of {0,1,2}\n");
+ return(-3);
+ }
+ } else {
+ if(busno<0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : dev=[Prefix:]Bus,Target,Lun expects Bus number >= 0\n");
+ return(-3);
+ }
+ if(busno>=1000) {
+ busno-= 1000;
+ goto ata_bus;
+ } else if((strncmp(adr,"ATA",3)==0 && (adr[3]==0 || adr[3]==':')) ||
+ (strncmp(adr,"ATAPI",5)==0 && (adr[5]==0 || adr[5]==':'))) {
+ata_bus:;
+ if(busno>12 || (*driveno)<0 || (*driveno)>1) {
+ fprintf(stderr,
+"cdrskin: FATAL : dev=ATA:Bus,Target,Lun expects Bus {0..12}, Target {0,1}\n");
+ return(-3);
+ }
+ sprintf(device_adr,"/dev/hd%c",'a'+(2*busno)+(*driveno));
+
+ } else {
+ int ret;
+
+ ret= burn_drive_convert_scsi_adr(busno,-1,-1,*driveno,lun_no,
+ device_adr);
+ if(ret==0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Cannot find /dev/* with Bus,Target,Lun = %d,%d,%d\n",
+ busno,*driveno,lun_no);
+ fprintf(stderr,
+ "cdrskin: HINT : This drive may be in use by another program currently\n");
+ return(-2);
+ } else if(ret<0)
+ return(-1);
+ return(1);
+ }
+ }
+ }
+ }
+ return(1);
+}
+
+
+/** Set the eventual output fd for the result of Cdrskin_msinfo()
+*/
+int Cdrpreskin_set_result_fd(struct CdrpreskiN *o, int result_fd, int flag)
+{
+ o->result_fd= result_fd;
+ return(1);
+}
+
+
+#ifndef Cdrskin_extra_leaN
+
+/** Load content startup files into preskin cache */
+int Cdrpreskin_read_rc(struct CdrpreskiN *o, char *progname, int flag)
+{
+ int ret,i;
+ char **filenames_v;
+
+ filenames_v= TSOB_FELD(char *, o->rc_filename_count+1);
+ if(filenames_v==NULL)
+ return(-1);
+ for(i=0;irc_filename_count;i++)
+ filenames_v[i]= o->rc_filenames[i];
+ Sfile_home_adr_s(".cdrskinrc",o->rc_filenames[o->rc_filename_count-1],
+ Cdrskin_strleN,0);
+ ret= Sfile_multi_read_argv(progname,filenames_v,o->rc_filename_count,
+ &(o->pre_argc),&(o->pre_argv),
+ &(o->pre_argidx),&(o->pre_arglno),4);
+ free((char *) filenames_v);
+ return(ret);
+}
+
+#endif /* ! Cdrskin_extra_leaN */
+
+
+/** Interpret those arguments which do not need libburn or which influence the
+ startup of libburn and/or the creation of the CdrskiN object. This is run
+ before libburn gets initialized and before Cdrskin_new() is called.
+ Options which need libburn or a CdrskiN object are processed in a different
+ function named Cdrskin_setup().
+ @param flag Bitfield for control purposes:
+ bit0= do not finalize setup
+ bit1= do not read and interpret rc files
+ @return <=0 error, 1 success , 2 end program run with exit value 0
+*/
+int Cdrpreskin_setup(struct CdrpreskiN *o, int argc, char **argv, int flag)
+/*
+return:
+ <=0 error
+ 1 ok
+ 2 end program run (--help)
+*/
+{
+ int i,ret;
+ char *value_pt, reason[4096], *argpt;
+
+#ifndef Cdrskin_extra_leaN
+ if(argc>1) {
+ if(strcmp(argv[1],"--no_rc")==0 || strcmp(argv[1],"-version")==0 ||
+ strcmp(argv[1],"--help")==0 || strcmp(argv[1],"-help")==0 ||
+ strncmp(argv[1], "textfile_to_v07t=", 17) == 0 ||
+ strncmp(argv[1], "-textfile_to_v07t=", 18) == 0)
+ flag|= 2;
+ }
+ if(!(flag&2)) {
+ ret= Cdrpreskin_read_rc(o,argv[0],0);
+ if(ret<0)
+ return(-1);
+ if(o->pre_argc>1) {
+ ret= Cdrpreskin_setup(o,o->pre_argc,o->pre_argv,flag|1|2);
+ if(ret<=0)
+ return(ret);
+ /* ??? abort on ret==2 ? */
+ }
+ }
+#endif
+
+ if(argc==1) {
+ fprintf(stderr,"cdrskin: SORRY : No options given. Try option --help\n");
+ return(0);
+ }
+
+ /* The two predefined fallback personalities are triggered by the progname */
+ value_pt= strrchr(argv[0],'/');
+ if(value_pt==NULL)
+ value_pt= argv[0];
+ else
+ value_pt++;
+ if(strcmp(value_pt,"unicord")==0)
+ strcpy(o->fallback_program,"cdrecord");
+ else if(strcmp(value_pt,"codim")==0)
+ strcpy(o->fallback_program,"wodim");
+
+ for (i= 1;i 3)
+ argpt++;
+
+ if(strcmp(argv[i],"--abort_handler")==0) {
+ o->abort_handler= 3;
+
+ } else if(strcmp(argv[i],"--allow_emulated_drives")==0) {
+ if(Cdrpreskin__allows_emulated_drives("",reason,0)<=0) {
+ fprintf(stderr,"cdrskin: WARNING : %s.\n",reason);
+ fprintf(stderr,
+ "cdrskin: WARNING : Only /dev/null will be available with \"stdio:\".\n");
+ Cdrpreskin_consider_normal_user(0);
+ o->allow_emulated_drives= 2;
+ } else
+ o->allow_emulated_drives= 1;
+
+ } else if(strcmp(argv[i],"--allow_setuid")==0) {
+ o->allow_setuid= 1;
+
+ } else if(strcmp(argv[i],"--allow_untested_media")==0) {
+ o->allow_untested_media= 1;
+
+ } else if(strcmp(argpt, "blank=help") == 0 ||
+ strcmp(argpt, "-blank=help") == 0) {
+
+#ifndef Cdrskin_extra_leaN
+
+ fprintf(stderr,"Blanking options:\n");
+ fprintf(stderr,"\tall\t\tblank the entire disk\n");
+ fprintf(stderr,"\tdisc\t\tblank the entire disk\n");
+ fprintf(stderr,"\tdisk\t\tblank the entire disk\n");
+ fprintf(stderr,"\tfast\t\tminimally blank the entire disk\n");
+ fprintf(stderr,"\tminimal\t\tminimally blank the entire disk\n");
+ fprintf(stderr,
+ "\tas_needed\tblank or format media to make it ready for (re-)use\n");
+ fprintf(stderr,
+ "\tdeformat_sequential\t\tfully blank, even formatted DVD-RW\n");
+ fprintf(stderr,
+ "\tdeformat_sequential_quickest\tminimally blank, even DVD-RW\n");
+ fprintf(stderr,
+ "\tformat_if_needed\t\tmake overwriteable if needed and possible\n");
+ fprintf(stderr,
+ "\tformat_overwrite\t\tformat a DVD-RW to \"Restricted Overwrite\"\n");
+ fprintf(stderr,
+ "\tformat_overwrite_quickest\tto \"Restricted Overwrite intermediate\"\n");
+ fprintf(stderr,
+ "\tformat_overwrite_full\t\tfull-size format a DVD-RW or DVD+RW\n");
+ fprintf(stderr,
+ "\tformat_defectmgt[_max|_min|_none]\tformat DVD-RAM or BD-R[E]\n");
+ fprintf(stderr,
+ "\tformat_defectmgt[_cert_on|_cert_off]\tcertification slow|quick\n");
+ fprintf(stderr,
+ "\tformat_defectmgt_payload_\tformat DVD-RAM or BD-R[E]\n");
+ fprintf(stderr,
+ "\tformat_by_index_\t\tformat by index from --list_formats\n");
+
+#else /* ! Cdrskin_extra_leaN */
+
+ goto see_cdrskin_eng_html;
+
+#endif /* ! Cdrskin_extra_leaN */
+
+ if(argc==2)
+ {ret= 2; goto final_checks;}
+
+ } else if(strcmp(argv[i],"--bragg_with_audio")==0) {
+ /* OBSOLETE 0.2.3 */;
+
+ } else if(strcmp(argv[i],"--demand_a_drive")==0) {
+ o->scan_demands_drive= 1;
+ o->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(argv[i],"--devices") == 0 ||
+ strcmp(argv[i],"--device_links") == 0) {
+ o->no_whitelist= 1;
+ o->demands_cdrskin_caps= 1;
+
+ } else if(strncmp(argv[i],"dev_translation=",16)==0) {
+ o->demands_cdrskin_caps= 1;
+
+#ifndef Cdrskin_extra_leaN
+
+ if(o->adr_trn==NULL) {
+ ret= Cdradrtrn_new(&(o->adr_trn),0);
+ if(ret<=0)
+ goto no_adr_trn_mem;
+ }
+ if(argv[i][16]==0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : dev_translation= : missing separator character\n");
+ return(0);
+ }
+ ret= Cdradrtrn_add(o->adr_trn,argv[i]+17,argv[i]+16,1);
+ if(ret==-2) {
+no_adr_trn_mem:;
+ fprintf(stderr,
+ "cdrskin: FATAL : address_translation= : cannot allocate memory\n");
+ } else if(ret==-1)
+ fprintf(stderr,
+ "cdrskin: FATAL : address_translation= : table full (%d items)\n",
+ Cdradrtrn_leN);
+ else if(ret==0)
+ fprintf(stderr,
+ "cdrskin: FATAL : address_translation= : no address separator '%c' found\n",
+ argv[i][17]);
+ if(ret<=0)
+ return(0);
+
+#else /* ! Cdrskin_extra_leaN */
+
+ fprintf(stderr,
+ "cdrskin: FATAL : dev_translation= is not available in lean version\n");
+ return(0);
+
+#endif /* Cdrskin_extra_leaN */
+
+
+ } else if(strncmp(argpt, "-dev=", 5) == 0) {
+ value_pt= argpt + 5;
+ goto set_dev;
+ } else if(strncmp(argpt, "dev=", 4) == 0) {
+ value_pt= argpt + 4;
+set_dev:;
+ if(strcmp(value_pt,"help")==0) {
+
+#ifndef Cdrskin_extra_leaN
+
+ printf("\nSupported SCSI transports for this platform:\n");
+ fflush(stdout);
+ if(o->old_pseudo_scsi_adr) {
+ fprintf(stderr,"\nTransport name:\t\tlibburn OLD_PSEUDO\n");
+ fprintf(stderr,
+ "Transport descr.:\tBus0=DriveNum , Bus1=/dev/sgN , Bus2=/dev/hdX\n");
+ } else {
+ fprintf(stderr,"\nTransport name:\t\tlibburn SCSI\n");
+ fprintf(stderr,
+ "Transport descr.:\tSCSI Bus,Id,Lun as of operating system\n");
+ }
+ fprintf(stderr,"Transp. layer ind.:\t\n");
+ fprintf(stderr,"Target specifier:\tbus,target,lun\n");
+ fprintf(stderr,"Target example:\t\t1,2,0\n");
+ fprintf(stderr,"SCSI Bus scanning:\tsupported\n");
+ fprintf(stderr,"Open via UNIX device:\tsupported\n");
+ if(!o->old_pseudo_scsi_adr) {
+ fprintf(stderr,"\nTransport name:\t\tlibburn HD\n");
+ fprintf(stderr,
+ "Transport descr.:\tLinux specific alias for /dev/hdX\n");
+ fprintf(stderr,"Transp. layer ind.:\tATA:\n");
+ fprintf(stderr,"Target specifier:\tbus,target,lun\n");
+ fprintf(stderr,"Target example:\t\tATA:1,0,0\n");
+ fprintf(stderr,"SCSI Bus scanning:\tsupported\n");
+ fprintf(stderr,"Open via UNIX device:\tsupported\n");
+ }
+ if(o->allow_emulated_drives) {
+ fprintf(stderr,"\nTransport name:\t\tlibburn on standard i/o\n");
+ if(o->allow_emulated_drives==2)
+ fprintf(stderr, "Transport descr.:\troot or setuid may only write into /dev/null\n");
+ else
+ fprintf(stderr, "Transport descr.:\twrite into file objects\n");
+ fprintf(stderr,"Transp. layer ind.:\tstdio:\n");
+ fprintf(stderr,"Target specifier:\tpath\n");
+ fprintf(stderr,"Target example:\t\tstdio:/tmp/pseudo_drive\n");
+ fprintf(stderr,"SCSI Bus scanning:\tnot supported\n");
+ fprintf(stderr,"Open via UNIX device:\tnot supported\n");
+ } else {
+ if(Cdrpreskin__allows_emulated_drives("",reason,0)>0)
+ printf("\ncdrskin: NOTE : Option --allow_emulated_drives would allow dev=stdio:\n");
+ }
+
+#else /* ! Cdrskin_extra_leaN */
+
+ goto see_cdrskin_eng_html;
+
+#endif /* Cdrskin_extra_leaN */
+
+ {ret= 2; goto final_checks;}
+ }
+ if(strlen(value_pt)>=sizeof(o->raw_device_adr))
+ goto dev_too_long;
+ strcpy(o->raw_device_adr,value_pt);
+
+ } else if(strcmp(argv[i],"--drive_abort_on_busy")==0) {
+ o->abort_on_busy_drive= 1;
+
+ } else if(strcmp(argv[i],"--drive_blocking")==0) {
+ o->drive_blocking= 1;
+
+ } else if(strcmp(argv[i],"--drive_f_setlk")==0) {
+ o->drive_fcntl_f_setlk= 1;
+
+ } else if(strcmp(argv[i],"--drive_not_exclusive")==0) {
+ o->drive_exclusive= 0;
+ o->drive_fcntl_f_setlk= 0;
+
+ } else if(strcmp(argv[i],"--drive_not_f_setlk")==0) {
+ o->drive_fcntl_f_setlk= 0;
+
+ } else if(strcmp(argv[i],"--drive_not_o_excl")==0) {
+ o->drive_exclusive= 0;
+
+ } else if(strncmp(argv[i],"drive_scsi_dev_family=",22)==0) {
+ value_pt= argv[i]+22;
+ if(strcmp(value_pt,"sr")==0)
+ o->drive_scsi_dev_family= 1;
+ else if(strcmp(value_pt,"scd")==0)
+ o->drive_scsi_dev_family= 2;
+ else if(strcmp(value_pt,"sg")==0)
+ o->drive_scsi_dev_family= 4;
+ else
+ o->drive_scsi_dev_family= 0;
+ } else if(strcmp(argv[i],"--drive_scsi_exclusive")==0) {
+ o->drive_exclusive= 2;
+ o->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(argpt,"driveropts=help")==0 ||
+ strcmp(argpt,"-driveropts=help")==0) {
+
+#ifndef Cdrskin_extra_leaN
+
+ fprintf(stderr,"Driver options:\n");
+ fprintf(stderr,"burnfree\tPrepare writer to use BURN-Free technology\n");
+ fprintf(stderr,"noburnfree\tDisable using BURN-Free technology\n");
+
+#else /* ! Cdrskin_extra_leaN */
+
+ goto see_cdrskin_eng_html;
+
+#endif /* Cdrskin_extra_leaN */
+
+ if(argc==2 || (i==2 && argc==3 && strncmp(argv[1],"dev=",4)==0))
+ {ret= 2; goto final_checks;}
+
+ } else if(strcmp(argv[i],"--help")==0) {
+
+#ifndef Cdrskin_extra_leaN
+
+ printf("\n");
+ printf("Usage: %s [options|source_addresses]\n", argv[0]);
+ printf("Burns preformatted data to CD or DVD via libburn.\n");
+ printf("For the cdrecord compatible options which control the work of\n");
+ printf(
+ "blanking and burning see output of option -help rather than --help.\n");
+ printf("Non-cdrecord options:\n");
+ printf(" --abort_handler do not leave the drive in busy state\n");
+ printf(
+ " --adjust_speed_to_drive set only speeds offered by drive and media\n");
+ printf(" --allow_emulated_drives dev=stdio: on file objects\n");
+ printf(
+ " --allow_setuid disable setuid warning (setuid is insecure !)\n");
+ printf(
+ " --allow_untested_media enable implemented untested media types\n");
+ printf(
+ " --any_track allow source_addresses to match '^-.' or '='\n");
+ printf(
+ " assert_write_lba= abort if not next write address == lba\n");
+ printf(
+ " cd_start_tno= set number of first track in CD SAO session\n");
+ printf(
+ " --cdtext_dummy show CD-TEXT pack array instead of writing CD\n");
+ printf(
+ " cdtext_to_textfile= extract CD-TEXT from CD to disk file\n");
+ printf(
+ " cdtext_to_v07t= report CD-TEXT from CD to file or stdout\n");
+ printf(" --cdtext_verbose show CD-TEXT pack array before writing CD\n");
+ printf(
+ " direct_write_amount= write random access to media like DVD+RW\n");
+ printf(" --demand_a_drive exit !=0 on bus scans with empty result\n");
+ printf(" --devices list accessible devices (tells /dev/...)\n");
+ printf(" --device_links list accessible devices by (udev) links\n");
+ printf(
+ " dev_translation= set input address alias\n");
+ printf(" e.g.: dev_translation=+ATA:1,0,0+/dev/sg1\n");
+ printf(" --drive_abort_on_busy abort process if busy drive is found\n");
+ printf(" (might be triggered by a busy hard disk)\n");
+ printf(" --drive_blocking try to wait for busy drive to become free\n");
+ printf(" (might be stalled by a busy hard disk)\n");
+ printf(" --drive_f_setlk obtain exclusive lock via fcntl.\n");
+ printf(" --drive_not_exclusive combined not_o_excl and not_f_setlk.\n");
+ printf(" --drive_not_f_setlk do not obtain exclusive lock via fcntl.\n");
+ printf(" --drive_not_o_excl do not ask kernel to prevent opening\n");
+ printf(" busy drives. Effect is kernel dependend.\n");
+ printf(
+ " drive_scsi_dev_family= select Linux device\n");
+ printf(" file family to be used for (pseudo-)SCSI.\n");
+ printf(
+ " --drive_scsi_exclusive try to exclusively reserve device files\n");
+ printf(" /dev/srN, /dev/scdM, /dev/stK of drive.\n");
+ printf(" dvd_obs=\"default\"|number\n");
+ printf(
+ " set number of bytes per DVD/BD write: 32k or 64k\n");
+ printf(" extract_audio_to=\n");
+ printf(
+ " Copy all tracks of an audio CD as separate\n");
+ printf(
+ " .WAV files /track.wav to hard disk\n");
+ printf(" extract_basename=\n");
+ printf(
+ " Compose track files as /.wav\n");
+ printf(
+ " --extract_dap Enable flaw obscuring mechanisms for audio reading\n");
+ printf(" extract_tracks=\n");
+ printf(
+ " Restrict extract_audio_to= to list of tracks.\n");
+ printf(
+ " fallback_program= use external program for exotic CD jobs.\n");
+ printf(" --fifo_disable disable fifo despite any fs=...\n");
+ printf(" --fifo_per_track use a separate fifo for each track\n");
+ printf(
+ " fifo_start_at= do not wait for full fifo but start burning\n");
+ printf(
+ " as soon as the given number of bytes is read\n");
+ printf(" --fill_up_media cause the last track to have maximum size\n");
+ printf(" --four_channel indicate that audio tracks have 4 channels\n");
+ printf(
+ " grab_drive_and_wait= grab drive, wait given number of\n");
+ printf(
+ " seconds, release drive, and do normal work\n");
+ printf(
+ " --grow_overwriteable_iso emulate multi-session on media like DVD+RW\n");
+ printf(
+ " --ignore_signals try to ignore any signals rather than to abort\n");
+ printf(" input_sheet_v07t= read a Sony CD-TEXT definition file\n");
+ printf(" --list_formats list format descriptors for loaded media.\n");
+ printf(" --list_ignored_options list all ignored cdrecord options.\n");
+ printf(" --list_speeds list speed descriptors for loaded media.\n");
+ printf(" --long_toc print overview of media content\n");
+ printf(" modesty_on_drive= no writing into full drive buffer\n");
+ printf(" --no_abort_handler exit even if the drive is in busy state\n");
+ printf(" --no_blank_appendable refuse to blank appendable CD-RW\n");
+ printf(" --no_convert_fs_adr only literal translations of dev=\n");
+ printf(" --no_load do not try to load the drive tray\n");
+ printf(
+ " --no_rc as first argument: do not read startup files\n");
+ printf(" --obs_pad pad DVD DAO to full 16 or 32 blocks\n");
+ printf(" --old_pseudo_scsi_adr use and report literal Bus,Target,Lun\n");
+ printf(" rather than real SCSI and pseudo ATA.\n");
+ printf(
+ " --pacifier_with_newline do not overwrite pacifier line by next one.\n");
+ printf(" --prodvd_cli_compatible react on some DVD types more like\n");
+ printf(" cdrecord-ProDVD with blank= and -multi\n");
+ printf(" sao_postgap=\"off\"|number\n");
+ printf(" defines whether the next track will get a\n");
+ printf(
+ " post-gap and how many sectors it shall have\n");
+ printf(" sao_pregap=\"off\"|number\n");
+ printf(" defines whether the next track will get a\n");
+ printf(
+ " pre-gap and how many sectors it shall have\n");
+ printf(
+ " --single_track accept only last argument as source_address\n");
+ printf(" stream_recording=\"on\"|\"off\"|number\n");
+ printf(
+ " \"on\" requests to prefer speed over write\n");
+ printf(
+ " error management. A number prevents this with\n");
+ printf(
+ " byte addresses below that number.\n");
+ printf(" stdio_sync=\"default\"|\"off\"|number\n");
+ printf(
+ " set number of bytes after which to force output\n");
+ printf(
+ " to drives with prefix \"stdio:\".\n");
+ printf(
+ " tao_to_sao_tsize= use num as fixed track size if in a\n");
+ printf(
+ " non-TAO mode track data are read from \"-\"\n");
+ printf(
+ " and no tsize= was specified.\n");
+ printf(
+ " --tell_media_space print maximum number of writeable data blocks\n");
+ printf(" textfile_to_v07t=file_path\n");
+ printf(
+ " print CD-TEXT file in Sony format and exit.\n");
+ printf(" --two_channel indicate that audio tracks have 2 channels\n");
+ printf(
+ " use_immed_bit=on|off|default real control over SCSI Immed bit\n");
+ printf(
+ " write_start_address= write to given byte address (DVD+RW)\n");
+ printf(
+ " --xa1-ignore with -xa1 do not strip 8 byte headers\n");
+ printf(
+ " -xamix DO NOT USE (Dummy announcement to make K3B use -xa)\n");
+ printf(
+ "Preconfigured arguments are read from the following startup files\n");
+ printf(
+ "if they exist and are readable. The sequence is as listed here:\n");
+ printf(" /etc/default/cdrskin /etc/opt/cdrskin/rc\n");
+ printf(" /etc/cdrskin/cdrskin.conf $HOME/.cdrskinrc\n");
+ printf("Each file line is a single argument. No whitespace.\n");
+ printf(
+ "By default any argument that does not match grep '^-.' or '=' is\n");
+ printf(
+ "used as track source. If it is \"-\" then stdin is used.\n");
+ printf("cdrskin : http://scdbackup.sourceforge.net/cdrskin_eng.html\n");
+ printf(" mailto:scdbackup@gmx.net (Thomas Schmitt)\n");
+ printf("libburn : http://libburnia-project.org\n");
+ printf("cdrecord : ftp://ftp.berlios.de/pub/cdrecord/\n");
+ printf("My respect to the authors of cdrecord and libburn.\n");
+ printf("scdbackup: http://scdbackup.sourceforge.net/main_eng.html\n");
+ printf("\n");
+
+#else /* ! Cdrskin_extra_leaN */
+
+see_cdrskin_eng_html:;
+ printf("This is a capability reduced lean version without help texts.\n");
+ printf("See http://scdbackup.sourceforge.net/cdrskin_eng.html\n");
+
+#endif /* Cdrskin_extra_leaN */
+
+
+ {ret= 2; goto final_checks;}
+ } else if(strcmp(argv[i],"-help")==0) {
+
+#ifndef Cdrskin_extra_leaN
+
+ fprintf(stderr,"Usage: %s [options|source_addresses]\n",argv[0]);
+ fprintf(stderr,"Note: This is not cdrecord. See cdrskin start message on stdout. See --help.\n");
+ fprintf(stderr,"Options:\n");
+ fprintf(stderr,"\t-version\tprint version information and exit\n");
+ fprintf(stderr,
+ "\tdev=target\tpseudo-SCSI target to use as CD-Recorder\n");
+ fprintf(stderr,
+ "\tgracetime=#\tset the grace time before starting to write to #.\n");
+ fprintf(stderr,"\t-v\t\tincrement general verbose level by one\n");
+ fprintf(stderr,
+ "\t-V\t\tincrement SCSI command transport verbose level by one\n");
+ fprintf(stderr,
+ "\tdriveropts=opt\topt= one of {burnfree,noburnfree,help}\n");
+ fprintf(stderr,
+ "\t-checkdrive\tcheck if a driver for the drive is present\n");
+ fprintf(stderr,"\t-inq\t\tdo an inquiry for the drive and exit\n");
+ fprintf(stderr,"\t-scanbus\tscan the SCSI bus and exit\n");
+ fprintf(stderr,"\tspeed=#\t\tset speed of drive\n");
+ fprintf(stderr,"\tblank=type\tblank a CD-RW disc (see blank=help)\n");
+ fprintf(stderr,"\t-format\t\tformat a CD-RW/DVD-RW/DVD+RW disc\n");
+ fprintf(stderr,
+ "\tfs=#\t\tSet fifo size to # (0 to disable, default is 4 MB)\n");
+ fprintf(stderr,
+ "\t-load\t\tload the disk and exit (works only with tray loader)\n");
+ fprintf(stderr,
+ "\t-lock\t\tload and lock the disk and exit (works only with tray loader)\n");
+ fprintf(stderr,
+ "\t-eject\t\teject the disk after doing the work\n");
+ fprintf(stderr,"\t-dummy\t\tdo everything with laser turned off\n");
+ fprintf(stderr,"\t-minfo\t\tretrieve and print media information/status\n");
+ fprintf(stderr,"\t-media-info\tretrieve and print media information/status\n");
+ fprintf(stderr,
+ "\t-msinfo\t\tretrieve multi-session info for mkisofs >= 1.10\n");
+ fprintf(stderr,"\tmsifile=path\trun -msinfo and copy output to file\n");
+ fprintf(stderr,"\t-toc\t\tretrieve and print TOC/PMA data\n");
+ fprintf(stderr,
+ "\t-atip\t\tretrieve media state, print \"Is *erasable\"\n");
+ fprintf(stderr,
+ "\tminbuf=percent\tset lower limit for drive buffer modesty\n");
+ fprintf(stderr,
+ "\t-multi\t\tgenerate a TOC that allows multi session\n");
+ fprintf(stderr,
+ "\t-waiti\t\twait until input is available before opening SCSI\n");
+ fprintf(stderr,
+ "\t-immed\t\tTry to use the SCSI IMMED flag with certain long lasting commands\n");
+ fprintf(stderr,
+ "\t-force\t\tforce to continue on some errors to allow blanking\n");
+ fprintf(stderr,"\t-tao\t\tWrite disk in TAO mode.\n");
+ fprintf(stderr,"\t-dao\t\tWrite disk in SAO mode.\n");
+ fprintf(stderr,"\t-sao\t\tWrite disk in SAO mode.\n");
+
+#ifndef Cdrskin_disable_raw96R
+ fprintf(stderr,"\t-raw96r\t\tWrite disk in RAW/RAW96R mode\n");
+#endif
+
+ fprintf(stderr,"\ttsize=#\t\tannounces exact size of source data\n");
+ fprintf(stderr,"\tpadsize=#\tAmount of padding\n");
+ fprintf(stderr,
+ "\tmcn=text\tSet the media catalog number for this CD to 'text'\n");
+ fprintf(stderr,
+ "\tisrc=text\tSet the ISRC number for the next track to 'text'\n");
+ fprintf(stderr,
+ "\tindex=list\tSet the index list for the next track to 'list'\n");
+ fprintf(stderr,
+ "\t-text\t\tWrite CD-Text from information from *.cue files\n");
+ fprintf(stderr,
+ "\ttextfile=name\tSet the file with CD-Text data to 'name'\n");
+ fprintf(stderr,
+ "\tcuefile=name\tSet the file with CDRWIN CUE data to 'name'\n");
+ fprintf(stderr,"\t-audio\t\tSubsequent tracks are CD-DA audio tracks\n");
+ fprintf(stderr,
+ "\t-data\t\tSubsequent tracks are CD-ROM data mode 1 (default)\n");
+ fprintf(stderr,
+ "\t-xa1\t\tSubsequent tracks are CD-ROM XA mode 2 form 1 - 2056 bytes\n");
+ fprintf(stderr,
+ "\t-isosize\tUse iso9660 file system size for next data track\n");
+ fprintf(stderr,"\t-preemp\t\tAudio tracks are mastered with 50/15 microseconds preemphasis\n");
+ fprintf(stderr,"\t-nopreemp\tAudio tracks are mastered with no preemphasis (default)\n");
+ fprintf(stderr,"\t-copy\t\tAudio tracks have unlimited copy permission\n");
+ fprintf(stderr,"\t-nocopy\t\tAudio tracks may only be copied once for personal use (default)\n");
+ fprintf(stderr,"\t-scms\t\tAudio tracks will not have any copy permission at all\n");
+ fprintf(stderr,"\t-pad\t\tpadsize=30k\n");
+ fprintf(stderr,
+ "\t-nopad\t\tDo not pad (default, but applies only to data tracks)\n");
+ fprintf(stderr,
+ "\t-swab\t\tAudio data source is byte-swapped (little-endian/Intel)\n");
+ fprintf(stderr,"\t-help\t\tprint this text to stderr and exit\n");
+ fprintf(stderr,
+ "Without option -data, .wav and .au files are extracted and burned as -audio.\n");
+ fprintf(stderr,
+ "By default any argument that does not match grep '^-.' or '=' is used\n");
+ fprintf(stderr,
+ "as track source address. Address \"-\" means stdin.\n");
+ fprintf(stderr,
+ "cdrskin will ensure that an announced tsize= is written even if\n");
+ fprintf(stderr,
+ "the source delivers fewer bytes. But 0 bytes from stdin with fifo\n");
+ fprintf(stderr,
+ "enabled will lead to abort and no burn attempt at all.\n");
+
+#else /* ! Cdrskin_extra_leaN */
+
+ fprintf(stderr,"Note: This is not cdrecord. See cdrskin start message on stdout.\n");
+ fprintf(stderr,
+ "(writer profile: -atip retrieve, blank=type, -eject after work)\n");
+ goto see_cdrskin_eng_html;
+
+#endif /* Cdrskin_extra_leaN */
+
+ {ret= 2; goto final_checks;}
+
+ } else if(strcmp(argv[i],"--ignore_signals")==0) {
+ o->abort_handler= 2;
+
+ } else if(strncmp(argv[i],"fallback_program=",17)==0) {
+ if(strlen(argv[i] + 17) >= sizeof(o->fallback_program)) {
+ fprintf(stderr,
+ "cdrskin: FATAL : fallback_program=... too long (max. %d characters)\n",
+ (int) sizeof(o->fallback_program) - 1);
+ {ret= 0; goto ex;}
+ }
+ strcpy(o->fallback_program,argv[i]+17);
+
+ } else if(strcmp(argv[i],"--no_abort_handler")==0) {
+ o->abort_handler= 0;
+
+ } else if(strcmp(argv[i],"--no_convert_fs_adr")==0) {
+ o->no_convert_fs_adr= 1;
+
+ } else if(strcmp(argv[i],"--old_pseudo_scsi_adr")==0) {
+ o->old_pseudo_scsi_adr= 1;
+ o->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(argv[i],"--no_rc")==0) {
+ if(i!=1)
+ fprintf(stderr,
+ "cdrskin: NOTE : option --no_rc would only work as first argument.\n");
+
+#ifndef Cdrskin_disable_raw96R
+ } else if(strcmp(argpt,"-raw96r")==0) {
+ strcpy(o->write_mode_name,"RAW/RAW96R");
+#endif
+
+ } else if(strcmp(argpt,"-sao")==0 || strcmp(argpt,"-dao")==0) {
+ strcpy(o->write_mode_name,"SAO");
+
+ } else if(strcmp(argpt,"-scanbus")==0) {
+ o->no_whitelist= 1;
+
+ } else if(strcmp(argpt,"-tao")==0) {
+ strcpy(o->write_mode_name,"TAO");
+
+ } else if(strncmp(argpt, "-textfile_to_v07t=", 18) == 0) {
+ o->do_not_scan= 1;
+ } else if(strncmp(argpt ,"textfile_to_v07t=", 17) == 0) {
+ o->do_not_scan= 1;
+
+ } else if(strcmp(argv[i],"-V")==0 || strcmp(argpt, "-Verbose") == 0) {
+ burn_set_scsi_logging(2 | 4); /* log SCSI to stderr */
+
+ } else if(strcmp(argv[i],"-v")==0 || strcmp(argpt, "-verbose") == 0) {
+ (o->verbosity)++;
+ ClN(printf("cdrskin: verbosity level : %d\n",o->verbosity));
+set_severities:;
+ if(o->verbosity>=Cdrskin_verbose_debuG)
+ Cdrpreskin_set_severities(o,"NEVER","DEBUG",0);
+ else if(o->verbosity >= Cdrskin_verbose_progresS)
+ Cdrpreskin_set_severities(o, "NEVER", "UPDATE", 0);
+
+ } else if(strcmp(argv[i],"-vv")==0 || strcmp(argv[i],"-vvv")==0 ||
+ strcmp(argv[i],"-vvvv")==0) {
+ (o->verbosity)+= strlen(argv[i])-1;
+ goto set_severities;
+
+ } else if(strcmp(argpt,"-version")==0) {
+ int major, minor, micro;
+
+ printf(
+"Cdrecord 2.01a27 Emulation. Copyright (C) 2006-2016, see libburnia-project.org\n");
+ if(o->fallback_program[0]) {
+ char *hargv[2];
+
+ printf("Fallback program : %s\n",o->fallback_program);
+ printf("Fallback version :\n");
+ hargv[0]= argv[0];
+ hargv[1]= "-version";
+ Cdrpreskin_fallback(o,2,hargv,1); /* dirty never come back */
+ }
+ printf("System adapter : %s\n", burn_scsi_transport_id(0));
+ printf("libburn interface : %d.%d.%d\n",
+ burn_header_version_major, burn_header_version_minor,
+ burn_header_version_micro);
+ burn_version(&major, &minor, µ);
+ printf("libburn in use : %d.%d.%d\n", major, minor, micro);
+
+#ifndef Cdrskin_extra_leaN
+ printf("cdrskin version : %s\n",Cdrskin_prog_versioN);
+#else
+ printf("cdrskin version : %s.lean (capability reduced lean version)\n",
+ Cdrskin_prog_versioN);
+#endif
+
+ printf("Version timestamp : %s\n",Cdrskin_timestamP);
+ printf("Build timestamp : %s\n",Cdrskin_build_timestamP);
+ {ret= 2; goto ex;}
+
+ } else if(strcmp(argpt,"-waiti")==0) {
+ o->do_waiti= 1;
+
+ } else if(strcmp(argpt,"-xamix")==0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Option -xamix not implemented and data not yet convertible to other modes.\n");
+ return(0);
+ }
+
+ }
+ ret= 1;
+final_checks:;
+ if(flag&1)
+ goto ex;
+ if(o->verbosity >= Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "cdrskin: DEBUG : Using %s\n", burn_scsi_transport_id(0)));
+ if(o->do_waiti) {
+ fprintf(stderr,
+ "cdrskin: Option -waiti pauses program until input appears at stdin\n");
+ printf("Waiting for data on stdin...\n");
+ for(ret= 0; ret==0; )
+ ret= Wait_for_input(0,1000000,0);
+ if(ret<0 || feof(stdin))
+ fprintf(stderr,
+ "cdrskin: NOTE : stdin produces exception rather than data\n");
+ fprintf(stderr,"cdrskin: Option -waiti pausing is done.\n");
+ }
+ burn_preset_device_open(o->drive_exclusive
+ | (o->drive_scsi_dev_family<<2)
+ | ((!!o->drive_fcntl_f_setlk)<<5),
+ o->drive_blocking,
+ o->abort_on_busy_drive);
+
+ if(strlen(o->raw_device_adr)>0 && !o->no_whitelist) {
+ int driveno,hret;
+ char *adr,buf[Cdrskin_adrleN];
+
+ if(strcmp(o->raw_device_adr,"stdio:-")==0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Cannot accept drive address \"stdio:-\".\n");
+ fprintf(stderr,
+ "cdrskin: HINT : Use \"stdio:/dev/fd/1\" if you really want to write to stdout.\n");
+ {ret= 0; goto ex;}
+ }
+ adr= o->raw_device_adr;
+
+#ifndef Cdrskin_extra_leaN
+ if(o->adr_trn!=NULL) {
+ hret= Cdradrtrn_translate(o->adr_trn,adr,-1,buf,0);
+ if(hret<=0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : address translation failed (address too long ?) \n");
+ {ret= 0; goto ex;}
+ }
+ adr= buf;
+ }
+#endif /* ! Cdrskin_extra_leaN */
+
+ if(adr[0]=='/') {
+ if(strlen(adr)>=sizeof(o->device_adr)) {
+dev_too_long:;
+ fprintf(stderr,
+ "cdrskin: FATAL : dev=... too long (max. %d characters)\n",
+ (int) sizeof(o->device_adr)-1);
+ {ret= 0; goto ex;}
+ }
+ strcpy(o->device_adr,adr);
+ } else {
+ ret= Cdrpreskin__cdrecord_to_dev(adr,o->device_adr,&driveno,
+ !!o->old_pseudo_scsi_adr);
+ if(ret==-2 || ret==-3)
+ {ret= 0; goto ex;}
+ if(ret<0)
+ goto ex;
+ if(ret==0) {
+ strcpy(o->device_adr,adr);
+ ret= 1;
+ }
+ }
+
+ if(strlen(o->device_adr)>0 && !o->no_convert_fs_adr) {
+ int lret;
+ char link_adr[Cdrskin_strleN+1];
+
+ strcpy(link_adr,o->device_adr);
+ lret = burn_drive_convert_fs_adr(link_adr,o->device_adr);
+ if(lret<0) {
+ fprintf(stderr,
+ "cdrskin: NOTE : Please inform libburn-hackers@pykix.org about:\n");
+ fprintf(stderr,
+ "cdrskin: burn_drive_convert_fs_adr() returned %d\n",lret);
+ }
+ }
+
+ }
+
+ burn_allow_untested_profiles(!!o->allow_untested_media);
+
+ /* A60927 : note to myself : no "ret= 1;" here. It breaks --help , -version */
+
+ex:;
+ /* Eventually replace current stdout by dup(1) from start of program */
+ if(strcmp(o->device_adr,"stdio:/dev/fd/1")==0 && o->result_fd >= 0)
+ sprintf(o->device_adr,"stdio:/dev/fd/%d",o->result_fd);
+
+#ifndef Cdrskin_extra_leaN
+ if(ret<=0 || !(flag&1))
+ Cdradrtrn_destroy(&(o->adr_trn),0);
+#endif
+
+ return(ret);
+}
+
+
+/* --------------------------------------------------------------------- */
+
+
+
+/** The maximum number of tracks */
+#define Cdrskin_track_maX 99
+
+
+/** Work around the fact that libburn leaves the track input fds open
+ after the track is done. This can hide a few overflow bytes buffered
+ by the fifo-to-libburn pipe which would cause a broken-pipe error
+ if libburn would close that outlet.
+ This macro enables a coarse workaround which tries to read bytes from
+ the track inlets after burning has ended. Probably not a good idea if
+ libburn would close the inlet fds.
+*/
+#define Cdrskin_libburn_leaves_inlet_opeN 1
+
+
+/** List of furter wishes towards libburn:
+ - a possibility to implement cdrskin -reset
+*/
+
+
+#define Cdrskin_tracksize_maX 1024.0*1024.0*1024.0*1024.0
+
+
+/* Some constants obtained by hearsay and experiments */
+
+/** The CD payload speed factor for reporting progress: 1x = 150 kB/s */
+static double Cdrskin_cd_speed_factoR= 150.0*1024.0;
+/** The DVD payload speed factor for reporting progress: 1x */
+static double Cdrskin_dvd_speed_factoR= 1385000;
+/** The BD payload speed factor for reporting progress: 1x */
+static double Cdrskin_bd_speed_factoR= 4495625;
+
+/** The effective payload speed factor for reporting progress */
+static double Cdrskin_speed_factoR= 150.0*1024.0;
+
+/** The speed conversion factors consumer x-speed to libburn speed as used with
+ burn_drive_set_speed() burn_drive_get_write_speed()
+*/
+static double Cdrskin_libburn_cd_speed_factoR= 176.4;
+static double Cdrskin_libburn_dvd_speed_factoR= 1385.0;
+static double Cdrskin_libburn_bd_speed_factoR= 4495.625;
+
+/* The effective speed conversion factor for burn_drive_set_speed() */
+static double Cdrskin_libburn_speed_factoR= 176.4;
+
+/** Add-on for burn_drive_set_speed() to accommodate to the slightly oversized
+ speed ideas of my LG DVDRAM GSA-4082B. LITE-ON LTR-48125S tolerates it.
+*/
+static double Cdrskin_libburn_cd_speed_addoN= 40.0;
+static double Cdrskin_libburn_dvd_speed_addoN= 1.0; /*poor accuracy with 2.4x*/
+static double Cdrskin_libburn_bd_speed_addoN= 1.0;
+static double Cdrskin_libburn_speed_addoN = 40.0;
+
+
+/** The program run control object. Defaults: see Cdrskin_new(). */
+struct CdrskiN {
+
+ /** Settings already interpreted by Cdrpreskin_setup */
+ struct CdrpreskiN *preskin;
+
+ /** Job: what to do, plus some parameters. */
+ int verbosity;
+ int pacifier_with_newline;
+ double x_speed;
+ int adjust_speed_to_drive;
+ int gracetime;
+ int dummy_mode;
+ int force_is_set;
+ int stream_recording_is_set; /* see burn_write_opts_set_stream_recording() */
+ int dvd_obs; /* DVD write chunk size: 0, 32k or 64k */
+ int obs_pad; /* Whether to force obs end padding */
+ int stdio_sync; /* stdio fsync interval: -1, 0, >=32 */
+ int single_track;
+ int prodvd_cli_compatible;
+ int use_immed; /* 1= yes, 0= libburn default, -1= no */
+
+ int do_devices; /* 1= --devices , 2= --device_links */
+
+ int do_scanbus;
+
+ int do_load; /* 1= -load , 2= -lock , -1= --no_load */
+
+ int do_checkdrive;
+
+ int do_msinfo;
+ char msifile[Cdrskin_strleN];
+
+ int do_atip;
+ int do_list_speeds;
+ int do_list_formats;
+ int do_cdtext_to_textfile;
+ char cdtext_to_textfile_path[Cdrskin_strleN];
+ int do_cdtext_to_vt07;
+ char cdtext_to_vt07_path[Cdrskin_strleN];
+ int do_extract_audio;
+ char extract_audio_dir[Cdrskin_strleN];
+ char extract_basename[249];
+ char extract_audio_tracks[100]; /* if [i] > 0 : extract track i */
+ int extract_flags; /* bit3 = for flag bit3 of
+ burn_drive_extract_audio()
+ */
+
+#ifdef Libburn_develop_quality_scaN
+ int do_qcheck; /* 0= no , 1=nec_optiarc_rep_err_rate */
+#endif /* Libburn_develop_quality_scaN */
+
+ int do_blank;
+ int blank_fast;
+ int no_blank_appendable;
+ int blank_format_type; /* bit0-7: job type
+ 0=blank
+ 1=format_overwrite for DVD+RW, DVD-RW
+ bit8-15: bit0-7 of burn_disc_format(flag)
+ bit8 = write zeros after formatting
+ bit9 = insist in size 0
+ bit10= format to maximum available size
+ bit11= - reserved -
+ bit12= - reserved -
+ bit13= try to disable eventual defect management
+ bit14= - reserved -
+ bit15= format by index
+ 2=deformat_sequential (blank_fast might matter)
+ 3=format (= format_overwrite restricted to DVD+RW)
+ 4=format_defectmgt for DVD-RAM, BD-R[E]
+ bit8-15: bit0-7 of burn_disc_format(flag)
+ bit8 = write zeros after formatting
+ bit9+10: size mode
+ 0 = use parameter size as far as it makes sense
+ 1 = (identical to size mode 0)
+ 2 = without bit7: format to maximum size
+ with bit7 : take size from indexed format
+ descriptor
+ 3 = without bit7: format to default size
+ with bit7 : take size from indexed format
+ descriptor
+ bit11= - reserved -
+ bit12= - reserved -
+ bit13= try to disable defect management
+ bit14= - reserved -
+ bit15= format by index
+ 5=format_by_index
+ gets mapped to 4 with DVD-RAM and BD-RE else to 1,
+ bit15 should be set and bit16-23 should contain
+ a usable index number
+ 6=format_if_needed
+ gets mapped to default variants of specialized
+ formats if the media state requires formatting
+ before writing
+ 7=if_needed
+ gets mapped to 6 for DVD-RAM and BD-RE,
+ to 0 with all other non-blanks
+
+ bit8-15: bit0-7 of burn_disc_format(flag)
+ depending on job type
+ */
+ int blank_format_index; /* bit8-15 of burn_disc_format(flag) */
+ double blank_format_size; /* to be used with burn_disc_format() */
+ int blank_format_no_certify;
+
+ int do_direct_write;
+ int do_burn;
+ int tell_media_space; /* actually do not burn but tell the available space */
+ int burnfree;
+ /** The write mode (like SAO or TAO). See libburn.
+ Controlled by preskin->write_mode_name */
+ enum burn_write_types write_type;
+ int block_type;
+ int multi;
+ int cdxa_conversion; /* bit0-30: for burn_track_set_cdxa_conv()
+ bit31 : ignore bits 0 to 30
+ */
+ int modesty_on_drive;
+ int min_buffer_usec; /* The other parameters for this function */
+ int max_buffer_usec;
+ int buffer_timeout_sec;
+ int min_buffer_percent;
+ int max_buffer_percent;
+
+ double write_start_address;
+ double direct_write_amount;
+ int assert_write_lba;
+
+ int do_eject;
+ char eject_device[Cdrskin_strleN];
+
+
+ /** The current data source and its eventual parameters.
+ source_path may be either "-" for stdin, "#N" for open filedescriptor N
+ or the address of a readable file.
+ */
+ char source_path[Cdrskin_strleN];
+ double fixed_size;
+ double smallest_tsize;
+ int has_open_ended_track;
+ double padding;
+ int set_by_padsize;
+ int fill_up_media;
+
+ /** track_type may be set to BURN_MODE1, BURN_AUDIO, etc. */
+ int track_type;
+ int track_type_by_default; /* 0= explicit, 1=not set, 2=by file extension */
+ int swap_audio_bytes;
+ int track_modemods;
+
+ /** CDRWIN cue sheet file */
+ char cuefile[Cdrskin_adrleN];
+ int use_cdtext;
+
+ /** CD-TEXT */
+ unsigned char *text_packs;
+ int num_text_packs;
+
+ int sheet_v07t_blocks;
+ char sheet_v07t_paths[8][Cdrskin_adrleN];
+
+ int cdtext_test;
+
+ /* Media Catalog Number and ISRC */
+ char mcn[14];
+ char next_isrc[13];
+
+ char *index_string;
+
+ int sao_pregap;
+ int sao_postgap;
+
+ /** The list of tracks with their data sources and parameters */
+ struct CdrtracK *tracklist[Cdrskin_track_maX];
+ int track_counter;
+ /** a guess about what track might be processing right now */
+ int supposed_track_idx;
+
+ /** The number of the first track in a CD SAO session */
+ int cd_start_tno;
+
+ int fifo_enabled;
+ /** Optional fifo between input fd and libburn. It uses a pipe(2) to transfer
+ data to libburn. This fifo may be actually the start of a chain of fifos
+ which are to be processed simultaneously.
+ The fifo object knows the real input fd and the fd[1] of the pipe.
+ This is just a reference pointer. The fifos are managed by the tracks
+ which either line up their fifos or share the fifo of the first track.
+ */
+ struct CdrfifO *fifo;
+ /** fd[0] of the fifo pipe. This is from where libburn reads its data. */
+ int fifo_outlet_fd;
+ int fifo_size;
+ int fifo_start_at;
+ int fifo_per_track;
+ struct burn_source *cuefile_fifo;
+
+ /** User defined address translation */
+ struct CdradrtrN *adr_trn;
+
+
+ /** The drives known to libburn after scan */
+ struct burn_drive_info *drives;
+ unsigned int n_drives;
+ /** The drive selected for operation by CdrskiN */
+ int driveno;
+ /** The persistent drive address of that drive */
+ char device_adr[Cdrskin_adrleN];
+
+
+ /** Progress state info: whether libburn is actually processing payload data*/
+ int is_writing;
+ /** Previously detected drive state */
+ enum burn_drive_status previous_drive_status;
+
+ /** abort parameters */
+ int abort_max_wait;
+
+ /** Engagement info for eventual abort */
+ int lib_is_initialized;
+ pid_t control_pid; /* pid of the thread that calls libburn */
+ int drive_is_grabbed;
+ struct burn_drive *grabbed_drive;
+ /* Whether drive was told to do something cancel-worthy
+ 0= no: directly call burn_abort
+ 1= yes: A worker thread is busy (e.g. writing, formatting)
+ 2= yes: A synchronous operation is busy (e.g. grabbing).
+ */
+ int drive_is_busy;
+
+#ifndef Cdrskin_extra_leaN
+ /** Abort test facility */
+ double abort_after_bytecount;
+#endif /* ! Cdrskin_extra_leaN */
+
+
+ /** Some intermediate option info which is stored until setup finalization */
+ double tao_to_sao_tsize;
+ int stdin_source_used;
+
+ /* Info about media capabilities */
+ int media_does_multi;
+ int media_is_overwriteable;
+
+ /* For option -isosize and --grow_overwriteable_iso */
+ int use_data_image_size;
+
+ /* For growisofs stunt :
+ 0=disabled,
+ 1=do stunt, fabricate toc, allow multi,
+ 2=overwriteable_iso_head is valid
+ 3=initial session (mostly to appease -multi on overwriteables)
+ */
+ int grow_overwriteable_iso;
+ /* New image head buffer for --grow_overwriteable_iso */
+ char overwriteable_iso_head[32*2048]; /* block 0 to 31 of target */
+
+};
+
+int Cdrskin_destroy(struct CdrskiN **o, int flag);
+int Cdrskin_grab_drive(struct CdrskiN *skin, int flag);
+int Cdrskin_release_drive(struct CdrskiN *skin, int flag);
+int Cdrskin_report_disc_status(struct CdrskiN *skin, enum burn_disc_status s,
+ int flag);
+
+/** Create a cdrskin program run control object.
+ @param skin Returns pointer to resulting
+ @param flag Bitfield for control purposes:
+ bit0= library is already initialized
+ @return <=0 error, 1 success
+*/
+int Cdrskin_new(struct CdrskiN **skin, struct CdrpreskiN *preskin, int flag)
+{
+ struct CdrskiN *o;
+ int ret,i;
+
+ (*skin)= o= TSOB_FELD(struct CdrskiN,1);
+ if(o==NULL)
+ return(-1);
+ o->preskin= preskin;
+ o->verbosity= preskin->verbosity;
+ o->pacifier_with_newline= 0;
+ o->x_speed= -1.0;
+ o->adjust_speed_to_drive= 0;
+ o->gracetime= 0;
+ o->dummy_mode= 0;
+ o->force_is_set= 0;
+ o->stream_recording_is_set= 0;
+ o->dvd_obs= 0;
+ o->obs_pad= 0;
+ o->stdio_sync= 0;
+ o->single_track= 0;
+ o->prodvd_cli_compatible= 0;
+ o->use_immed= 0;
+ o->do_devices= 0;
+ o->do_scanbus= 0;
+ o->do_load= 0;
+ o->do_checkdrive= 0;
+ o->do_msinfo= 0;
+ o->msifile[0]= 0;
+ o->do_atip= 0;
+ o->do_list_speeds= 0;
+ o->do_list_formats= 0;
+ o->do_cdtext_to_textfile= 0;
+ o->cdtext_to_textfile_path[0]= 0;
+ o->do_cdtext_to_vt07= 0;
+ o->cdtext_to_vt07_path[0]= 0;
+ o->do_extract_audio= 0;
+ o->extract_audio_dir[0]= 0;
+ o->extract_basename[0]= 0;
+ for(i= 0; i < 100; i++)
+ o->extract_audio_tracks[i]= 0;
+ o->extract_flags= 0;
+
+#ifdef Libburn_develop_quality_scaN
+ o->do_qcheck= 0;
+#endif /* Libburn_develop_quality_scaN */
+
+ o->do_blank= 0;
+ o->blank_fast= 0;
+ o->no_blank_appendable= 0;
+ o->blank_format_type= 0;
+ o->blank_format_index= -1;
+ o->blank_format_size= 0.0;
+ o->blank_format_no_certify= 0;
+ o->do_direct_write= 0;
+ o->do_burn= 0;
+ o->tell_media_space= 0;
+ o->write_type= BURN_WRITE_SAO;
+ o->block_type= BURN_BLOCK_SAO;
+ o->multi= 0;
+ o->cdxa_conversion= 0;
+ o->modesty_on_drive= 0;
+ o->buffer_timeout_sec= 120;
+ o->min_buffer_usec= 10000;
+ o->max_buffer_usec= 100000;
+ o->min_buffer_percent= 65;
+ o->max_buffer_percent= 95;
+ o->write_start_address= -1.0;
+ o->direct_write_amount= -1.0;
+ o->assert_write_lba= -1;
+ o->burnfree= 1;
+ o->do_eject= 0;
+ o->eject_device[0]= 0;
+ o->source_path[0]= 0;
+ o->fixed_size= 0.0;
+ o->smallest_tsize= -1.0;
+ o->has_open_ended_track= 0;
+ o->padding= 0.0;
+ o->set_by_padsize= 0;
+ o->fill_up_media= 0;
+ o->track_type= BURN_MODE1;
+ o->swap_audio_bytes= 1; /* cdrecord default is big-endian (msb_first) */
+ o->cuefile[0] = 0;
+ o->use_cdtext = 0;
+ o->text_packs= NULL;
+ o->num_text_packs= 0;
+ o->sheet_v07t_blocks= 0;
+ for(i= 0; i < 8; i++)
+ memset(o->sheet_v07t_paths, 0, Cdrskin_adrleN);
+ o->cdtext_test= 0;
+ o->mcn[0]= 0;
+ o->next_isrc[0]= 0;
+ o->index_string= NULL;
+ o->sao_pregap= -1;
+ o->sao_postgap= -1;
+ o->track_modemods= 0;
+ o->track_type_by_default= 1;
+ for(i=0;itracklist[i]= NULL;
+ o->track_counter= 0;
+ o->supposed_track_idx= -1;
+ o->cd_start_tno= 0;
+ o->fifo_enabled= 1;
+ o->fifo= NULL;
+ o->fifo_outlet_fd= -1;
+ o->fifo_size= 4*1024*1024;
+ o->fifo_start_at= -1;
+ o->fifo_per_track= 0;
+ o->cuefile_fifo= NULL;
+ o->adr_trn= NULL;
+ o->drives= NULL;
+ o->n_drives= 0;
+ o->driveno= 0;
+ o->device_adr[0]= 0;
+ o->is_writing= 0;
+ o->previous_drive_status = BURN_DRIVE_IDLE;
+ o->abort_max_wait= 74*60;
+ o->lib_is_initialized= (flag&1);
+ o->control_pid= getpid();
+ o->drive_is_grabbed= 0;
+ o->drive_is_busy= 0;
+ o->grabbed_drive= NULL;
+#ifndef Cdrskin_extra_leaN
+ o->abort_after_bytecount= -1.0;
+#endif /* ! Cdrskin_extra_leaN */
+ o->tao_to_sao_tsize= 0.0;
+ o->stdin_source_used= 0;
+ o->use_data_image_size= 0;
+ o->media_does_multi= 0;
+ o->media_is_overwriteable= 0;
+ o->grow_overwriteable_iso= 0;
+ memset(o->overwriteable_iso_head,0,sizeof(o->overwriteable_iso_head));
+
+#ifndef Cdrskin_extra_leaN
+ ret= Cdradrtrn_new(&(o->adr_trn),0);
+ if(ret<=0)
+ goto failed;
+#endif /* ! Cdrskin_extra_leaN */
+
+ return(1);
+failed:;
+ Cdrskin_destroy(skin,0);
+ return(-1);
+}
+
+
+/** Release from memory a cdrskin object */
+int Cdrskin_destroy(struct CdrskiN **o, int flag)
+{
+ struct CdrskiN *skin;
+ int i;
+
+ skin= *o;
+ if(skin==NULL)
+ return(0);
+ if(skin->drive_is_grabbed)
+ Cdrskin_release_drive(skin,0);
+ for(i=0;itrack_counter;i++)
+ Cdrtrack_destroy(&(skin->tracklist[i]),0);
+ if(skin->index_string != NULL)
+ free(skin->index_string);
+
+#ifndef Cdrskin_extra_leaN
+ Cdradrtrn_destroy(&(skin->adr_trn),0);
+#endif /* ! Cdrskin_extra_leaN */
+
+ if(skin->cuefile_fifo != NULL)
+ burn_source_free(skin->cuefile_fifo);
+ if(skin->text_packs != NULL)
+ free(skin->text_packs);
+ Cdrpreskin_destroy(&(skin->preskin),0);
+ if(skin->drives!=NULL)
+ burn_drive_info_free(skin->drives);
+ free((char *) skin);
+ *o= NULL;
+ return(1);
+}
+
+
+int Cdrskin_assert_driveno(struct CdrskiN *skin, int flag)
+{
+ if(skin->driveno < 0 || (unsigned int) skin->driveno >= skin->n_drives) {
+ fprintf(stderr,
+ "cdrskin: FATAL : No drive found. Cannot perform desired operation.\n");
+ return(0);
+ }
+ return(1);
+}
+
+
+/** Return the addresses of the drive. device_adr is the libburn persistent
+ address of the drive, raw_adr is the address as given by the user.
+*/
+int Cdrskin_get_device_adr(struct CdrskiN *skin,
+ char **device_adr, char **raw_adr, int *no_convert_fs_adr, int flag)
+{
+ int ret;
+
+ if(skin->driveno < 0 || (unsigned int) skin->driveno >= skin->n_drives)
+ return(0);
+ ret= burn_drive_get_adr(&skin->drives[skin->driveno],skin->device_adr);
+ if(ret <= 0)
+ return(0);
+ *device_adr= skin->device_adr;
+ *raw_adr= skin->preskin->raw_device_adr;
+ *no_convert_fs_adr= skin->preskin->no_convert_fs_adr;
+ return(1);
+}
+
+
+int Cdrskin_get_drive(struct CdrskiN *skin, struct burn_drive **drive,int flag)
+{
+ if(skin->driveno<0 || (unsigned int) skin->driveno >= skin->n_drives)
+ return(0);
+ *drive= skin->drives[skin->driveno].drive;
+ return ((*drive) != NULL);
+}
+
+
+/** Return information about current track source */
+int Cdrskin_get_source(struct CdrskiN *skin, char *source_path,
+ double *fixed_size, double *tao_to_sao_tsize,
+ int *use_data_image_size,
+ double *padding, int *set_by_padsize,
+ int *track_type, int *track_type_by_default,
+ int *mode_mods,
+ int *swap_audio_bytes, int *cdxa_conversion, int flag)
+{
+ strcpy(source_path,skin->source_path);
+ *fixed_size= skin->fixed_size;
+ *tao_to_sao_tsize = skin->tao_to_sao_tsize;
+ *use_data_image_size= skin->use_data_image_size;
+ *padding= skin->padding;
+ *set_by_padsize= skin->set_by_padsize;
+ *track_type= skin->track_type;
+ *track_type_by_default= skin->track_type_by_default;
+ *mode_mods= skin->track_modemods;
+ *swap_audio_bytes= skin->swap_audio_bytes;
+ *cdxa_conversion= skin->cdxa_conversion;
+ return(1);
+}
+
+
+#ifndef Cdrskin_extra_leaN
+
+/** Return information about current fifo setting */
+int Cdrskin_get_fifo_par(struct CdrskiN *skin, int *fifo_enabled,
+ int *fifo_size, int *fifo_start_at, int flag)
+{
+ *fifo_enabled= skin->fifo_enabled;
+ *fifo_size= skin->fifo_size;
+ *fifo_start_at= skin->fifo_start_at;
+ return(1);
+}
+
+
+#ifndef Cdrskin_no_cdrfifO
+
+/** Create and install fifo objects between track data sources and libburn.
+ The sources and parameters are known to skin.
+ @return <=0 error, 1 success
+*/
+int Cdrskin_attach_fifo(struct CdrskiN *skin, int flag)
+{
+ struct CdrfifO *ff= NULL;
+ int ret,i,hflag;
+
+#ifdef Cdrskin_use_libburn_fifO
+
+ int profile_number;
+ char profile_name[80];
+
+ ret= Cdrskin_assert_driveno(skin, 0);
+ if(ret <= 0)
+ return(ret);
+
+ /* Refuse here and thus use libburn fifo only with single track, non-CD */
+ ret= burn_disc_get_profile(skin->drives[skin->driveno].drive,
+ &profile_number, profile_name);
+ if(profile_number != 0x09 && profile_number != 0x0a &&
+ skin->track_counter == 1)
+ return(1);
+
+#endif /* Cdrskin_use_libburn_fifO */
+
+ skin->fifo= NULL;
+ for(i=0;itrack_counter;i++) {
+ hflag= (skin->verbosity>=Cdrskin_verbose_debuG);
+ if(i==skin->track_counter-1)
+ hflag|= 4;
+ if(skin->verbosity>=Cdrskin_verbose_cmD) {
+ if(skin->fifo_per_track)
+ printf("cdrskin: track %d establishing fifo of %d bytes\n",
+ i+1,skin->fifo_size);
+ else if(i==0)
+ printf("cdrskin: establishing fifo of %d bytes\n",skin->fifo_size);
+ else {
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: attaching track %d to fifo\n",i+1));
+ hflag|= 2;
+ }
+ }
+ ret= Cdrtrack_attach_fifo(skin->tracklist[i],&(skin->fifo_outlet_fd),ff,
+ hflag);
+ if(ret<=0) {
+ fprintf(stderr,"cdrskin: FATAL : failed to attach fifo.\n");
+ return(0);
+ }
+ if(i==0 || skin->fifo_per_track)
+ Cdrtrack_get_fifo(skin->tracklist[i],&ff,0);
+ if(i==0)
+ skin->fifo= ff;
+ }
+ return(1);
+}
+
+#endif /* ! Cdrskin_no_cdrfifO */
+
+
+/** Read data into the track fifos until either #1 is full or its data source
+ is exhausted.
+ @return <=0 error, 1 success
+*/
+int Cdrskin_fill_fifo(struct CdrskiN *skin, int flag)
+{
+ int ret;
+
+ ret= Cdrtrack_fill_fifo(skin->tracklist[0],skin->fifo_start_at,0);
+ if(ret<=0)
+ return(ret);
+ printf("input buffer ready.\n");
+ fflush(stdout);
+ return(1);
+}
+
+#endif /* ! Cdrskin_extra_leaN */
+
+
+/** Inform libburn about the consumer x-speed factor of skin */
+int Cdrskin_adjust_speed(struct CdrskiN *skin, int flag)
+{
+ int k_speed, modesty= 0;
+
+ if(skin->x_speed<0)
+ k_speed= 0; /* libburn.h promises 0 to be max speed. */
+ else if(skin->x_speed==0) { /* cdrecord specifies 0 as minimum speed. */
+ k_speed= -1;
+ } else
+ k_speed= skin->x_speed*Cdrskin_libburn_speed_factoR +
+ Cdrskin_libburn_speed_addoN;
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: k_speed= %d\n",k_speed));
+
+ if(skin->adjust_speed_to_drive && !skin->force_is_set) {
+ struct burn_speed_descriptor *best_descr;
+ burn_drive_get_best_speed(skin->drives[skin->driveno].drive,k_speed,
+ &best_descr,0);
+ if(best_descr!=NULL) {
+ k_speed= best_descr->write_speed;
+ skin->x_speed = ((double) k_speed) / Cdrskin_libburn_speed_factoR;
+ }
+ }
+ burn_drive_set_speed(skin->drives[skin->driveno].drive,k_speed,k_speed);
+ modesty= skin->modesty_on_drive;
+ burn_drive_set_buffer_waiting(skin->drives[skin->driveno].drive,
+ modesty, skin->min_buffer_usec,
+ skin->max_buffer_usec, skin->buffer_timeout_sec,
+ skin->min_buffer_percent,
+ skin->max_buffer_percent);
+ return(1);
+}
+
+
+int Cdrskin_determine_media_caps(struct CdrskiN *skin, int flag)
+{
+ int ret;
+ struct burn_multi_caps *caps = NULL;
+
+ skin->media_is_overwriteable= skin->media_does_multi= 0;
+ ret= burn_disc_get_multi_caps(skin->grabbed_drive,BURN_WRITE_NONE,&caps,0);
+ if(ret<=0)
+ goto ex;
+ skin->media_is_overwriteable= !!caps->start_adr;
+ skin->media_does_multi= !!caps->multi_session;
+ ret= 1;
+ex:;
+ if(caps != NULL)
+ burn_disc_free_multi_caps(&caps);
+ return(ret);
+}
+
+
+int Cdrskin__is_aborting(int flag)
+{
+ if(Cdrskin_abort_leveL)
+ return(-1);
+ return(burn_is_aborting(0));
+}
+
+
+int Cdrskin_abort(struct CdrskiN *skin, int flag)
+{
+ int ret;
+
+ Cdrskin_abort_leveL= 1;
+ ret= burn_abort(skin->abort_max_wait, burn_abort_pacifier, "cdrskin: ");
+ if(ret<=0) {
+ fprintf(stderr,
+ "\ncdrskin: ABORT : Cannot cancel burn session and release drive.\n");
+ } else {
+ fprintf(stderr,
+ "cdrskin: ABORT : Drive is released and library is shut down now.\n");
+ }
+ fprintf(stderr,
+ "cdrskin: ABORT : Program done. Even if you do not see a shell prompt.\n");
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+
+/** Obtain access to a libburn drive for writing or information retrieval.
+ If libburn is not restricted to a single persistent address then the
+ unused drives are dropped. This might be done by shutting down and
+ restartiing libburn with the wanted drive only. Thus, after this call,
+ libburn is supposed to have open only the reserved drive.
+ All other drives should be free for other use.
+ Warning: Do not store struct burn_drive pointer over this call.
+ Any such pointer might be invalid afterwards.
+ @param flag Bitfield for control purposes:
+ bit0= bus is unscanned, device is known,
+ use burn_drive_scan_and_grab()
+ bit1= do not load drive tray
+ bit2= do not issue error message on failure
+ bit3= demand and evtl. report media, return 0 if none to see
+ bit4= grab drive with unsuitable media even if fallback program
+ bit5= do not re-assess the drive if it is already grabbed
+ but rather perform a release-and-grab cycle
+ @return <=0 error, 1 success
+*/
+int Cdrskin_grab_drive(struct CdrskiN *skin, int flag)
+{
+ int ret,i,profile_number, mem;
+ struct burn_drive *drive;
+ char profile_name[80];
+ enum burn_disc_status s;
+
+ if(skin->drive_is_grabbed && (flag & 32))
+ Cdrskin_release_drive(skin,0);
+
+ if(!skin->drive_is_grabbed) {
+ if(flag&1) {
+ skin->driveno= 0;
+ drive= NULL;
+ skin->grabbed_drive= drive;
+ } else {
+ ret= Cdrskin_assert_driveno(skin, 0);
+ if(ret <= 0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+ skin->grabbed_drive= drive;
+ }
+ }
+ if(skin->drive_is_grabbed) {
+ drive= skin->grabbed_drive;
+ mem= skin->drive_is_busy;
+ skin->drive_is_busy= 2;
+ ret= burn_drive_re_assess(skin->grabbed_drive, 0);
+ skin->drive_is_busy= mem;
+ if(Cdrskin__is_aborting(0)) {
+ fprintf(stderr,"cdrskin: ABORT : Drive re-assessment aborted\n");
+ Cdrskin_abort(skin, 0); /* Never comes back */
+ }
+ if(ret <= 0) {
+ if(!(flag&4))
+ fprintf(stderr,"cdrskin: FATAL : unable to re-assess drive '%s'\n",
+ skin->preskin->device_adr);
+ goto ex;
+ }
+ } else if(flag&1) {
+ mem= skin->drive_is_busy;
+ skin->drive_is_busy= 2;
+ ret= burn_drive_scan_and_grab(&(skin->drives),skin->preskin->device_adr,
+ (skin->do_load != -1) && !(flag&2));
+ skin->drive_is_busy= mem;
+ if(Cdrskin__is_aborting(0)) {
+aborted:;
+ fprintf(stderr,"cdrskin: ABORT : Drive aquiration aborted\n");
+ Cdrskin_abort(skin, 0); /* Never comes back */
+ }
+ if(ret<=0) {
+ if(!(flag&4))
+ fprintf(stderr,"cdrskin: FATAL : unable to open drive '%s'\n",
+ skin->preskin->device_adr);
+ goto ex;
+ }
+ skin->driveno= 0;
+ drive= skin->drives[skin->driveno].drive;
+ skin->grabbed_drive= drive;
+ } else {
+ if(strlen(skin->preskin->device_adr)<=0) {
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "cdrskin_debug: Cdrskin_grab_drive() dropping unwanted drives (%d)\n",
+ skin->n_drives-1));
+ for(i= 0; i < (int) skin->n_drives; i++) {
+ if(i==skin->driveno)
+ continue;
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "cdrskin_debug: Cdrskin_grab_drive() dropped drive number %d\n",i));
+ ret= burn_drive_info_forget(&(skin->drives[i]), 0);
+ if(ret==1 || ret==2)
+ continue;
+ fprintf(stderr,
+ "cdrskin: NOTE : Please inform libburn-hackers@pykix.org about:\n");
+ fprintf(stderr,
+ "cdrskin: burn_drive_info_forget() returns %d\n",ret);
+ }
+ }
+
+ mem= skin->drive_is_busy;
+ skin->drive_is_busy= 2;
+ ret= burn_drive_grab(drive,(skin->do_load != -1) && !(flag&2));
+ skin->drive_is_busy= mem;
+ if(Cdrskin__is_aborting(0))
+ goto aborted;
+ if(ret==0) {
+ if(!(flag&4))
+ fprintf(stderr,"cdrskin: FATAL : unable to open drive %d\n",
+ skin->driveno);
+ goto ex;
+ }
+ }
+ if(skin->use_immed != 0)
+ burn_drive_set_immed(drive, skin->use_immed > 0);
+ skin->drive_is_grabbed= 1;
+
+ s= burn_disc_get_status(drive);
+ if((flag&8)) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ Cdrskin_report_disc_status(skin,s,1);
+ if(s==BURN_DISC_EMPTY) {
+ Cdrskin_release_drive(skin,0);
+ fprintf(stderr,"cdrskin: SORRY : No media found in drive\n");
+ ret= 0; goto ex;
+ }
+ }
+
+ Cdrskin_speed_factoR= Cdrskin_cd_speed_factoR;
+ Cdrskin_libburn_speed_factoR= Cdrskin_libburn_cd_speed_factoR;
+ Cdrskin_libburn_speed_addoN= Cdrskin_libburn_cd_speed_addoN;
+ ret= burn_disc_get_profile(drive,&profile_number,profile_name);
+ if(ret>0) {
+ if(strstr(profile_name,"DVD")==profile_name ||
+ strstr(profile_name,"stdio")==profile_name ) {
+ Cdrskin_speed_factoR= Cdrskin_dvd_speed_factoR;
+ Cdrskin_libburn_speed_factoR= Cdrskin_libburn_dvd_speed_factoR;
+ Cdrskin_libburn_speed_addoN= Cdrskin_libburn_dvd_speed_addoN;
+ } else if(strstr(profile_name,"BD")==profile_name) {
+ Cdrskin_speed_factoR= Cdrskin_bd_speed_factoR;
+ Cdrskin_libburn_speed_factoR= Cdrskin_libburn_bd_speed_factoR;
+ Cdrskin_libburn_speed_addoN= Cdrskin_libburn_bd_speed_addoN;
+ }
+ }
+ if(skin->preskin->fallback_program[0] && s==BURN_DISC_UNSUITABLE &&
+ skin->preskin->demands_cdrskin_caps<=0 && !(flag&16)) {
+ skin->preskin->demands_cdrecord_caps= 1;
+ fprintf(stderr,
+ "cdrskin: NOTE : Will delegate job to fallback program '%s'.\n",
+ skin->preskin->fallback_program);
+ Cdrskin_release_drive(skin,0);
+ ret= 0; goto ex;
+ }
+
+ Cdrskin_determine_media_caps(skin,0);
+
+ ret= 1;
+ex:;
+ if(ret<=0) {
+ skin->drive_is_grabbed= 0;
+ skin->grabbed_drive= NULL;
+ }
+ return(ret);
+}
+
+
+/** Release grabbed libburn drive
+ @param flag Bitfield for control purposes:
+ bit0= eject
+ bit1= leave tray locked (eventually overrides bit0)
+*/
+int Cdrskin_release_drive(struct CdrskiN *skin, int flag)
+{
+ if((!skin->drive_is_grabbed) || skin->grabbed_drive==NULL) {
+ fprintf(stderr,"cdrskin: CAUGHT : release of non-grabbed drive.\n");
+ return(0);
+ }
+ if(flag&2)
+ burn_drive_leave_locked(skin->grabbed_drive,0);
+ else
+ burn_drive_release(skin->grabbed_drive,(flag&1));
+ skin->drive_is_grabbed= 0;
+ skin->grabbed_drive= NULL;
+ return(1);
+}
+
+
+/** Clean up resources in abort situations. To be called by Cleanup subsystem
+ but hardly ever by the application. The program must exit afterwards.
+*/
+int Cdrskin_abort_handler(struct CdrskiN *skin, int signum, int flag)
+{
+ struct burn_progress p;
+ enum burn_drive_status drive_status= BURN_DRIVE_SPAWNING;
+
+/*
+ fprintf(stderr,
+"cdrskin_DEBUG: Cdrskin_abort_handler: signum=%d, flag=%d, drive_is_busy=%d\n",
+ signum, flag, skin->drive_is_busy);
+*/
+
+ if(skin->drive_is_busy == 0)
+ Cdrskin_abort(skin, 0); /* Never comes back */
+
+ if(getpid()!=skin->control_pid) {
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "\ncdrskin_debug: ABORT : [%lu] Thread rejected: pid=%lu, signum=%lu\n",
+ (unsigned long int) skin->control_pid, (unsigned long int) getpid(),
+ (unsigned long int) signum));
+
+#ifdef Not_yeT
+ /* >>> find more abstract and system independent way to determine
+ signals which make no sense with a return */
+ if(signum==11) {
+ Cleanup_set_handlers(NULL,NULL,1); /* allow abort */
+ return(0); /* let exit */
+ }
+#endif
+ usleep(1000000);
+
+ return(-2); /* do only process the control thread */
+ }
+ if(skin->preskin->abort_handler==3)
+ Cleanup_set_handlers(NULL,NULL,2); /* ignore all signals */
+ else if(skin->preskin->abort_handler==4)
+ Cleanup_set_handlers(NULL,NULL,1); /* allow abort */
+ fprintf(stderr,
+ "\ncdrskin: ABORT : Handling started. Please do not press CTRL+C now.\n");
+ if(skin->preskin->abort_handler==3)
+ fprintf(stderr,"cdrskin: ABORT : Trying to ignore any further signals\n");
+
+#ifndef Cdrskin_no_cdrfifO
+ if(skin->fifo!=NULL)
+ Cdrfifo_close_all(skin->fifo,0);
+#endif
+
+ /* Only for user info */
+ if(skin->grabbed_drive!=NULL)
+ drive_status= burn_drive_get_status(skin->grabbed_drive,&p);
+ if(drive_status!=BURN_DRIVE_IDLE) {
+ fprintf(stderr,"cdrskin: ABORT : Abort processing depends on speed and buffer size\n");
+ fprintf(stderr,"cdrskin: ABORT : Usually it is done with 4x speed after about a MINUTE\n");
+ fprintf(stderr,"cdrskin: URGE : But wait at least the normal burning time before any kill -9\n");
+ }
+
+ Cdrskin_abort_leveL= -1;
+ if (!(flag & 1)) {
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin: ABORT : Calling burn_abort(-1)\n"));
+ burn_abort(-1, burn_abort_pacifier, "cdrskin: ");
+ }
+ fprintf(stderr,
+ "cdrskin: ABORT : Urged drive worker threads to do emergency halt.\n");
+ return(-2);
+}
+
+
+/** Convert a libburn device address into a libburn drive number
+ @return <=0 error, 1 success
+*/
+int Cdrskin_driveno_of_location(struct CdrskiN *skin, char *devicename,
+ int *driveno, int flag)
+{
+ int i,ret;
+ char adr[Cdrskin_adrleN];
+
+ for(i= 0; i < (int) skin->n_drives; i++) {
+ ret= burn_drive_get_adr(&(skin->drives[i]), adr);
+ if(ret<=0)
+ continue;
+ if(strcmp(adr,devicename)==0) {
+ *driveno= i;
+ return(1);
+ }
+ }
+ return(0);
+}
+
+
+/** Convert a cdrskin address into a libburn drive number
+ @return <=0 error, 1 success
+*/
+int Cdrskin_dev_to_driveno(struct CdrskiN *skin, char *in_adr, int *driveno,
+ int flag)
+{
+ int ret;
+ char *adr,translated_adr[Cdrskin_adrleN],synthetic_adr[Cdrskin_adrleN];
+
+ adr= in_adr;
+
+#ifndef Cdrskin_extra_leaN
+ /* user defined address translation */
+ ret= Cdradrtrn_translate(skin->adr_trn,adr,-1,translated_adr,0);
+ if(ret<=0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : address translation failed (address too long ?) \n");
+ return(0);
+ }
+ if(skin->verbosity>=Cdrskin_verbose_cmD && strcmp(adr,translated_adr)!=0)
+ printf("cdrskin: dev_translation=... : dev='%s' to dev='%s'\n",
+ adr,translated_adr);
+ adr= translated_adr;
+#endif /* ! Cdrskin_extra_leaN */
+
+ if(strncmp(adr, "stdio:", 6)==0) {
+ if(skin->n_drives<=0)
+ goto wrong_devno;
+ *driveno= 0;
+ return(1);
+ } else if(adr[0]=='/') {
+ ret= Cdrskin_driveno_of_location(skin,adr,driveno,0);
+ if(ret<=0) {
+location_not_found:;
+ fprintf(stderr,
+ "cdrskin: FATAL : cannot find '%s' among accessible drive devices.\n",
+ adr);
+ fprintf(stderr,
+ "cdrskin: HINT : use option --devices for a list of drive devices.\n");
+ return(0);
+ }
+ return(1);
+ }
+ ret= Cdrpreskin__cdrecord_to_dev(adr,synthetic_adr,driveno,
+ !!skin->preskin->old_pseudo_scsi_adr);
+ if(ret<=0) {
+wrong_devno:;
+ if(skin->n_drives<=0) {
+ fprintf(stderr,"cdrskin: FATAL : No accessible drives.\n");
+ } else {
+ fprintf(stderr,
+ "cdrskin: FATAL : Address does not lead to an accessible drive: %s\n",
+ in_adr);
+ fprintf(stderr,
+ "cdrskin: HINT : dev= expects /dev/xyz, Bus,Target,0 or a number [0,%d]\n",
+ skin->n_drives-1);
+ }
+ return(0);
+ }
+ if(strlen(synthetic_adr)>0) {
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: converted address '%s' to '%s'\n",adr,synthetic_adr));
+ ret= Cdrskin_driveno_of_location(skin,synthetic_adr,driveno,0);
+ if(ret<=0) {
+ fprintf(stderr,
+ "cdrskin: failure while using address converted from '%s'\n",adr);
+ adr= synthetic_adr;
+ goto location_not_found;
+ }
+ }
+ if((unsigned int) (*driveno) >= skin->n_drives || (*driveno) < 0) {
+ ClN(fprintf(stderr,"cdrskin: obtained drive number %d from '%s'\n",
+ *driveno,adr));
+ goto wrong_devno;
+ }
+ return(1);
+}
+
+
+/** Convert a libburn drive number into a cdrecord-style address which
+ represents a device address if possible and the drive number else.
+ @param flag Bitfield for control purposes:
+ bit0= do not apply user defined address translation
+ @return <0 error,
+ pseudo transport groups:
+ 0 volatile drive number,
+ 1 /dev/sgN, 2 /dev/hdX, 3 stdio,
+ 1000000+busno = non-pseudo SCSI bus
+ 2000000+busno = pseudo-ATA|ATAPI SCSI bus (currently busno==2)
+*/
+int Cdrskin_driveno_to_btldev(struct CdrskiN *skin, int driveno,
+ char btldev[Cdrskin_adrleN], int flag)
+{
+ int k,ret,still_untranslated= 1,hret,k_start;
+ char *loc= NULL,buf[Cdrskin_adrleN],adr[Cdrskin_adrleN];
+
+ if(driveno < 0 || driveno > (int) skin->n_drives)
+ goto fallback;
+
+ ret= burn_drive_get_adr(&(skin->drives[driveno]), adr);
+ if(ret<=0)
+ goto fallback;
+ loc= adr;
+ ret= burn_drive_get_drive_role(skin->drives[driveno].drive);
+ if(ret!=1) {
+ sprintf(btldev,"stdio:%s",adr);
+ {ret= 2; goto adr_translation;}
+ }
+
+ if(!skin->preskin->old_pseudo_scsi_adr) {
+ int host_no= -1,channel_no= -1,target_no= -1,lun_no= -1, bus_no= -1;
+
+ ret= burn_drive_obtain_scsi_adr(loc,&bus_no,&host_no,&channel_no,
+ &target_no,&lun_no);
+ if(ret<=0) {
+ if(strncmp(loc,"/dev/hd",7)==0)
+ if(loc[7]>='a' && loc[7]<='z')
+ if(loc[8]==0) {
+ bus_no= (loc[7]-'a')/2;
+ sprintf(btldev,"%d,%d,0",bus_no,(loc[7]-'a')%2);
+ {ret= 2000000 + bus_no; goto adr_translation;}
+ }
+ goto fallback;
+ } else {
+ sprintf(btldev,"%d,%d,%d",bus_no,target_no,lun_no);
+ ret= 1000000+bus_no;
+ goto adr_translation;
+ }
+ }
+
+ k_start= 0;
+ if(strncmp(loc,"/dev/sg",7)==0 || strncmp(loc,"/dev/sr",7)==0)
+ k_start= 7;
+ if(strncmp(loc,"/dev/scd",8)==0)
+ k_start= 8;
+ if(k_start>0) {
+ for(k= k_start;loc[k]!=0;k++)
+ if(loc[k]<'0' || loc[k]>'9')
+ break;
+ if(loc[k]==0 && k>k_start) {
+ sprintf(btldev,"1,%s,0",loc+k_start);
+ {ret= 1; goto adr_translation;}
+ }
+ }
+ if(strncmp(loc,"/dev/hd",7)==0)
+ if(loc[7]>='a' && loc[7]<='z')
+ if(loc[8]==0) {
+ sprintf(btldev,"2,%d,0",loc[7]-'a');
+ {ret= 2; goto adr_translation;}
+ }
+fallback:;
+ if(skin->preskin->old_pseudo_scsi_adr) {
+ sprintf(btldev,"0,%d,0",driveno);
+ } else {
+ if(loc!=NULL)
+ strcpy(btldev,loc);
+ else
+ sprintf(btldev,"%d",driveno);
+ }
+ ret= 0;
+
+adr_translation:;
+#ifndef Cdrskin_extra_leaN
+ /* user defined address translation */
+ if(!(flag&1)) {
+ if(ret>0) {
+ /* try whether a translation points to loc */
+ hret= Cdradrtrn_translate(skin->adr_trn,loc,driveno,buf,1);
+ if(hret==2) {
+ still_untranslated= 0;
+ strcpy(btldev,buf);
+ }
+ }
+ if(still_untranslated) {
+ Cdradrtrn_translate(skin->adr_trn,btldev,driveno,buf,1);
+ strcpy(btldev,buf);
+ }
+ }
+#endif /* ! Cdrskin_extra_leaN */
+
+ return(ret);
+}
+
+
+/** Read and buffer the start of an existing ISO-9660 image from
+ overwriteable target media.
+*/
+int Cdrskin_overwriteable_iso_size(struct CdrskiN *skin, int *size, int flag)
+{
+ int ret;
+ off_t data_count= 0;
+ double size_in_bytes;
+ char *buf;
+
+ buf= skin->overwriteable_iso_head;
+ if(!skin->media_is_overwriteable)
+ {ret= 0; goto ex;}
+ /* Read first 64 kB */
+ ret= burn_read_data(skin->grabbed_drive,(off_t) 0,buf,32*2048,&data_count,0);
+ if(ret<=0)
+ {ret= 0; goto ex;}
+ ret= Scan_for_iso_size((unsigned char *) (buf+16*2048), &size_in_bytes,0);
+ if(ret<=0) {
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: No detectable ISO-9660 size on media\n"));
+ {ret= 0; goto ex;}
+ }
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: detected ISO-9660 size : %.f (%fs)\n",
+ size_in_bytes, size_in_bytes/2048.0));
+ if(size_in_bytes/2048.0>2147483647-1-16) {
+ fprintf(stderr,
+ "cdrskin: FATAL : ISO-9660 filesystem in terabyte size detected\n");
+ {ret= 0; goto ex;}
+ }
+ *size= size_in_bytes/2048.0;
+ if(size_in_bytes-((double) *size)*2048.0>0.0)
+ (*size)++;
+ if((*size)%16)
+ *size+= 16-((*size)%16);
+ if(skin->grow_overwriteable_iso==1)
+ skin->grow_overwriteable_iso= 2;
+ ret= 1;
+ex:;
+ return(ret);
+}
+
+
+int Cdrskin_invalidate_iso_head(struct CdrskiN *skin, int flag)
+{
+ int ret;
+ int size;
+
+ fprintf(stderr,
+ "cdrskin: blank=... : invalidating ISO-9660 head on overwriteable media\n");
+ ret= Cdrskin_overwriteable_iso_size(skin,&size,0);
+ if(ret<=0) {
+ fprintf(stderr,
+ "cdrskin: NOTE : Not an ISO-9660 file system. Left unaltered.\n");
+ return(2);
+ }
+ skin->overwriteable_iso_head[16*2048]=
+ skin->overwriteable_iso_head[16*2048+3]=
+ skin->overwriteable_iso_head[16*2048+4]= 'x';
+ ret= burn_random_access_write(skin->grabbed_drive,(off_t) 16*2048,
+ skin->overwriteable_iso_head+16*2048,
+ (off_t) 16*2048,1);
+ return(ret);
+}
+
+
+/** Report media status s to the user
+ @param flag Bitfield for control purposes:
+ bit0= permission to check for overwriteable ISO image
+ bit1= do not report media profile
+ bit2= do not report but only check for pseudo appendable
+ @return 1=ok, 2=ok, is pseudo appendable, <=0 error
+*/
+int Cdrskin_report_disc_status(struct CdrskiN *skin, enum burn_disc_status s,
+ int flag)
+{
+ int ret, iso_size, pseudo_appendable= 0;
+
+ if(flag&1) {
+ if(skin->media_is_overwriteable && skin->grow_overwriteable_iso>0) {
+ if(skin->grow_overwriteable_iso==2)
+ ret= 1;
+ else
+ ret= Cdrskin_overwriteable_iso_size(skin,&iso_size,0);
+ if(ret>0) {
+ s= BURN_DISC_APPENDABLE;
+ pseudo_appendable= 1;
+ }
+ }
+ }
+ if(flag&4)
+ return(1+pseudo_appendable);
+
+ printf("cdrskin: status %d ",s);
+ if(s==BURN_DISC_FULL) {
+ printf("burn_disc_full \"There is a disc with data on it in the drive\"\n");
+ } else if(s==BURN_DISC_BLANK) {
+ printf("burn_disc_blank \"The drive holds a blank disc\"\n");
+ } else if(s==BURN_DISC_APPENDABLE) {
+ printf(
+ "BURN_DISC_APPENDABLE \"There is an incomplete disc in the drive\"\n");
+ } else if(s==BURN_DISC_EMPTY) {
+ printf("BURN_DISC_EMPTY \"There is no disc at all in the drive\"\n");
+ } else if(s==BURN_DISC_UNREADY) {
+ printf("BURN_DISC_UNREADY \"The current status is not yet known\"\n");
+ } else if(s==BURN_DISC_UNGRABBED) {
+ printf("BURN_DISC_UNGRABBED \"API usage error: drive not grabbed\"\n");
+ } else if(s==BURN_DISC_UNSUITABLE) {
+ printf("BURN_DISC_UNSUITABLE \"Media is not suitable\"\n");
+ } else
+ printf("-unknown status code-\n");
+
+ if(flag&2)
+ return(1+pseudo_appendable);
+
+ if((s==BURN_DISC_FULL || s==BURN_DISC_APPENDABLE || s==BURN_DISC_BLANK ||
+ s==BURN_DISC_UNSUITABLE) && skin->driveno>=0) {
+ char profile_name[80];
+ int profile_number;
+
+ printf("Current: ");
+ ret= burn_disc_get_profile(skin->drives[skin->driveno].drive,
+ &profile_number,profile_name);
+ if(ret>0 && profile_name[0]!=0)
+ printf("%s\n", profile_name);
+ else if(ret>0)
+ printf("UNSUITABLE MEDIA (Profile %4.4Xh)\n",profile_number);
+ else
+ printf("-unidentified-\n");
+ } else if(s==BURN_DISC_EMPTY) {
+ printf("Current: none\n");
+ }
+
+ return(1+pseudo_appendable);
+}
+
+
+/** Perform operations -scanbus or --devices
+ @param flag Bitfield for control purposes:
+ bit0= perform --devices rather than -scanbus
+ bit1= with bit0: perform --device_links
+ @return <=0 error, 1 success
+*/
+int Cdrskin_scanbus(struct CdrskiN *skin, int flag)
+{
+ int ret,i,busno,first_on_bus,pseudo_transport_group= 0,skipped_devices= 0;
+ int busmax= 16, busidx, max_dev_len, pad, j;
+ char shellsafe[5*Cdrskin_strleN+2],perms[40],btldev[Cdrskin_adrleN];
+ char adr[Cdrskin_adrleN],*raw_dev,*drives_shown= NULL;
+ char link_adr[BURN_DRIVE_ADR_LEN];
+ int *drives_busses= NULL;
+ struct stat stbuf;
+
+ drives_shown= calloc(1, skin->n_drives+1);
+ drives_busses= calloc((skin->n_drives+1), sizeof(int));
+ if(drives_shown == NULL || drives_busses == NULL)
+ {ret= -1; goto ex;}
+
+ if(flag&1) {
+ max_dev_len= 0;
+ for(i= 0; i < (int) skin->n_drives; i++) {
+ drives_shown[i]= 0;
+ ret= burn_drive_get_adr(&(skin->drives[i]), adr);
+ if(ret<=0)
+ continue;
+ if(flag & 2) {
+ ret= burn_lookup_device_link(adr, link_adr, "/dev", NULL, 0, 0);
+ if(ret == 1)
+ strcpy(adr, link_adr);
+ }
+ if(strlen(adr)>=Cdrskin_strleN)
+ Text_shellsafe("failure:oversized string", shellsafe, 0);
+ else
+ Text_shellsafe(adr, shellsafe,0);
+ if((int) strlen(shellsafe) > max_dev_len)
+ max_dev_len= strlen(shellsafe);
+ }
+ printf("cdrskin: Overview of accessible drives (%d found) :\n",
+ skin->n_drives);
+ printf("-----------------------------------------------------------------------------\n");
+ for(i= 0; i < (int) skin->n_drives; i++) {
+ ret= burn_drive_get_adr(&(skin->drives[i]), adr);
+ if(ret<=0) {
+ /* >>> one should massively complain */;
+ continue;
+ }
+ if(stat(adr,&stbuf)==-1) {
+ sprintf(perms,"errno=%d",errno);
+ } else {
+ strcpy(perms,"------");
+ if(stbuf.st_mode&S_IRUSR) perms[0]= 'r';
+ if(stbuf.st_mode&S_IWUSR) perms[1]= 'w';
+ if(stbuf.st_mode&S_IRGRP) perms[2]= 'r';
+ if(stbuf.st_mode&S_IWGRP) perms[3]= 'w';
+ if(stbuf.st_mode&S_IROTH) perms[4]= 'r';
+ if(stbuf.st_mode&S_IWOTH) perms[5]= 'w';
+ }
+ if(flag & 2) {
+ ret= burn_lookup_device_link(adr, link_adr, "/dev", NULL, 0, 0);
+ if(ret == 1)
+ strcpy(adr, link_adr);
+ }
+ if(strlen(adr)>=Cdrskin_strleN)
+ Text_shellsafe("failure:oversized string",shellsafe,0);
+ else
+ Text_shellsafe(adr,shellsafe,0);
+ printf("%d dev=%s", i, shellsafe);
+ pad= max_dev_len - strlen(shellsafe);
+ if(pad > 0)
+ for(j= 0; j < pad; j++)
+ printf(" ");
+ printf(" %s : '%-8.8s' '%s'\n",
+ perms, skin->drives[i].vendor, skin->drives[i].product);
+ }
+ printf("-----------------------------------------------------------------------------\n");
+ } else {
+ if(!skin->preskin->old_pseudo_scsi_adr) {
+ pseudo_transport_group= 1000000;
+ raw_dev= skin->preskin->raw_device_adr;
+ if(strncmp(raw_dev,"ATA",3)==0 && (raw_dev[3]==0 || raw_dev[3]==':'))
+ pseudo_transport_group= 2000000;
+ if(strncmp(raw_dev,"ATAPI",5)==0 && (raw_dev[5]==0 || raw_dev[5]==':'))
+ pseudo_transport_group= 2000000;
+ if(pseudo_transport_group==2000000) {
+ fprintf(stderr,"scsidev: 'ATA'\ndevname: 'ATA'\n");
+ fprintf(stderr,"scsibus: -2 target: -2 lun: -2\n");
+ }
+ }
+ /* >>> fprintf(stderr,"Linux sg driver version: 3.1.25\n"); */
+ printf("Using libburn version '%s'.\n", Cdrskin_libburn_versioN);
+ if(pseudo_transport_group!=1000000)
+ if(skin->preskin->old_pseudo_scsi_adr)
+ printf("cdrskin: NOTE : The printed addresses are not cdrecord compatible !\n");
+
+ for(i= 0; i < (int) skin->n_drives; i++) {
+ drives_busses[i]= -1;
+ ret= Cdrskin_driveno_to_btldev(skin,i,btldev,1);
+ if(ret >= pseudo_transport_group &&
+ ret < pseudo_transport_group + 1000000) {
+ drives_busses[i]= ret - pseudo_transport_group;
+ if(ret > pseudo_transport_group + busmax)
+ busmax= 1 + ret - pseudo_transport_group;
+ }
+ }
+ for(busidx= 0; busidx < (int) skin->n_drives + 1; busidx++) {
+ if(busidx < (int) skin->n_drives)
+ busno= drives_busses[busidx];
+ else
+ busno= busmax;
+ if(busno < 0)
+ continue;
+ for(i= 0; i < busidx; i++)
+ if(drives_busses[i] == busno)
+ break;
+ if(i < busidx)
+ continue;
+ first_on_bus= 1;
+ for(i= 0; i < (int) skin->n_drives; i++) {
+ ret= Cdrskin_driveno_to_btldev(skin,i,btldev,1);
+ if(busno==busmax && drives_shown[i]==0) {
+ if(ret/1000000 != pseudo_transport_group) {
+ skipped_devices++;
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: skipping drive '%s%s'\n",
+ ((ret/1000000)==2?"ATA:":""), btldev));
+ continue;
+ }
+ } else if(ret != pseudo_transport_group + busno)
+ continue;
+ if(first_on_bus)
+ printf("scsibus%d:\n",busno);
+ first_on_bus= 0;
+ printf("\t%s\t %d) '%-8s' '%-16s' '%-4s' Removable CD-ROM\n",
+ btldev,i,skin->drives[i].vendor,skin->drives[i].product,
+ skin->drives[i].revision);
+ drives_shown[i]= 1;
+ }
+ }
+ }
+ if(skipped_devices>0) {
+ if(skipped_devices>1)
+ printf("cdrskin: NOTE : There were %d drives not shown.\n",
+ skipped_devices);
+ else
+ printf("cdrskin: NOTE : There was 1 drive not shown.\n");
+ printf("cdrskin: HINT : To surely see all drives try option: --devices\n");
+ if(pseudo_transport_group!=2000000)
+ printf("cdrskin: HINT : or try options: dev=ATA -scanbus\n");
+ }
+ ret= 1;
+ex:;
+ if(drives_shown!=NULL)
+ free((char *) drives_shown);
+ if(drives_busses!=NULL)
+ free((char *) drives_busses);
+ return(ret);
+}
+
+
+/** Perform -checkdrive .
+ @param flag Bitfield for control purposes:
+ bit0= do not print message about pseudo-checkdrive
+ @return <=0 error, 1 success
+*/
+int Cdrskin_checkdrive(struct CdrskiN *skin, char *profile_name, int flag)
+{
+ struct burn_drive_info *drive_info;
+ int ret;
+ char btldev[Cdrskin_adrleN];
+ char *sno= NULL;
+ int sno_len = 0;
+
+ if(!(flag&1)) {
+ if(flag&2)
+ ClN(printf("cdrskin: pseudo-inquiry on drive %d\n",skin->driveno));
+ else
+ ClN(printf("cdrskin: pseudo-checkdrive on drive %d\n",skin->driveno));
+ }
+ if(skin->driveno >= (int) skin->n_drives || skin->driveno < 0) {
+ fprintf(stderr,"cdrskin: FATAL : there is no drive #%d\n",skin->driveno);
+ {ret= 0; goto ex;}
+ }
+ drive_info= &(skin->drives[skin->driveno]);
+ ret= Cdrskin_driveno_to_btldev(skin,skin->driveno,btldev,0);
+ if(ret>=0)
+ fprintf(stderr,"scsidev: '%s'\n",btldev);
+ printf("Device type : ");
+ ret= burn_drive_get_drive_role(drive_info->drive);
+ if(ret==0)
+ printf("%s\n","Emulated (null-drive)");
+ else if(ret==2)
+ printf("%s\n","Emulated (stdio-drive, 2k random read-write)");
+ else if(ret==3)
+ printf("%s\n","Emulated (stdio-drive, sequential write-only)");
+ else if(ret==4)
+ printf("%s\n","Emulated (stdio-drive, 2k random read-only)");
+ else if(ret == 5)
+ printf("%s\n","Emulated (stdio-drive, 2k random write-only)");
+ else if(ret!=1)
+ printf("%s\n","Emulated (stdio-drive)");
+ else
+ printf("%s\n","Removable CD-ROM");
+ printf("Vendor_info : '%s'\n",drive_info->vendor);
+ printf("Identifikation : '%s'\n",drive_info->product);
+ printf("Revision : '%s'\n",drive_info->revision);
+
+ if(flag&2)
+ {ret= 1; goto ex;}
+
+ burn_drive_get_serial_no(drive_info->drive, &sno, &sno_len);
+ if(sno_len > 0)
+ printf("Drive id : '%s'\n", sno);
+ if(sno != NULL)
+ free(sno);
+ sno= NULL;
+ printf("Driver flags : %s\n","BURNFREE");
+ printf("Supported modes:");
+ if((drive_info->tao_block_types & (BURN_BLOCK_MODE1))
+ == (BURN_BLOCK_MODE1))
+ printf(" TAO");
+ if(drive_info->sao_block_types & BURN_BLOCK_SAO)
+ printf(" SAO");
+
+#ifndef Cdrskin_disable_raw96R
+ if((drive_info->raw_block_types & BURN_BLOCK_RAW96R) &&
+ strstr(profile_name,"DVD")!=profile_name &&
+ strstr(profile_name,"BD")!=profile_name)
+ printf(" RAW/RAW96R");
+#endif /* ! Cdrskin_disable_raw96R */
+
+ printf("\n");
+ ret= 1;
+ex:;
+ return(ret);
+}
+
+
+/** Predict address block number where the next write will go to
+ @param flag Bitfield for control purposes:
+ bit0= do not return nwa from eventual write_start_address
+ @return <=0 error, 1 nwa from drive , 2 nwa from write_start_address
+*/
+int Cdrskin_obtain_nwa(struct CdrskiN *skin, int *nwa, int flag)
+{
+ int ret,lba;
+ struct burn_drive *drive;
+ struct burn_write_opts *o= NULL;
+
+ if(skin->write_start_address>=0 && !(flag&1)) {
+ /* (There is no sense in combining random addressing with audio) */
+ *nwa= skin->write_start_address/2048;
+ return(2);
+ }
+
+ /* Set write opts in order to provoke MODE SELECT. LG GSA-4082B needs it. */
+ drive= skin->drives[skin->driveno].drive;
+ o= burn_write_opts_new(drive);
+ if(o!=NULL) {
+ burn_write_opts_set_perform_opc(o, 0);
+ burn_write_opts_set_write_type(o,skin->write_type,skin->block_type);
+ burn_write_opts_set_underrun_proof(o,skin->burnfree);
+ }
+ ret= burn_disc_track_lba_nwa(drive,o,0,&lba,nwa);
+ if(o!=NULL)
+ burn_write_opts_free(o);
+ return(ret);
+}
+
+
+/* @param flag bit0-3= source of text packs:
+ 0= CD Lead-in
+ 1= session and tracks
+ 2= textfile=
+ bit4-7= output format
+ 0= -vv -toc
+ 1= Sony CD-TEXT Input Sheet Version 0.7T
+*/
+int Cdrskin_print_text_packs(struct CdrskiN *skin, unsigned char *text_packs,
+ int num_packs, int flag)
+{
+ int i, j, from, fmt, ret, char_code= 0;
+ char *from_text= "", *result= NULL;
+ unsigned char *pack;
+
+ from= flag & 15;
+ fmt= (flag >> 4) & 15;
+ if(from == 0)
+ from_text= " from CD Lead-in";
+ else if(from == 1)
+ from_text= " from session and tracks";
+ else if(from == 2)
+ from_text= " from textfile= or cuefile= CDTEXTFILE";
+ if (fmt == 1) {
+ ret = burn_make_input_sheet_v07t(text_packs, num_packs, 0, 0, &result,
+ &char_code, 0);
+ if(ret <= 0)
+ goto ex;
+ if(char_code == 0x80)
+ fprintf(stderr,
+ "cdrskin : WARNING : Double byte characters encountered.\n");
+ for(i = 0; i < ret; i++)
+ printf("%c", result[i]);
+ } else {
+ printf("CD-TEXT data%s:\n", from_text);
+ for(i= 0; i < num_packs; i++) {
+ pack= text_packs + 18 * i;
+ printf("%4d :", i);
+ for(j= 0; j < 18; j++) {
+ if(j >= 4 && j <= 15 && pack[j] >= 32 && pack[j] <= 126 &&
+ pack[0] != 0x88 && pack[0] != 0x89 && pack[0] != 0x8f)
+ printf(" %c", pack[j]);
+ else
+ printf(" %2.2x", pack[j]);
+ }
+ printf("\n");
+ }
+ }
+ ret= 1;
+ex:;
+ if(result != NULL)
+ free(result);
+ return(ret);
+}
+
+
+/* @param flag bit4= no not overwrite existing target file
+*/
+int Cdrskin_store_text_packs(struct CdrskiN *skin, unsigned char *text_packs,
+ int num_packs, char *path, int flag)
+{
+ int data_length, ret;
+ struct stat stbuf;
+ FILE *fp;
+ unsigned char fake_head[4];
+
+ if(stat(path, &stbuf) != -1 && (flag & 16)) {
+ fprintf(stderr, "cdrskin: SORRY : Will not overwrite file '%s'\n", path);
+ return(0);
+ }
+ fp= fopen(path, "w");
+ if(fp == NULL) {
+ fprintf(stderr, "cdrskin: SORRY : Cannot open file '%s' for storing extracted CD-TEXT\n", path);
+ fprintf(stderr, "cdrskin: %s (errno=%d)\n", strerror(errno), errno);
+ return(0);
+ }
+ data_length= num_packs * 18 + 2;
+ fake_head[0]= (data_length >> 8) & 0xff;
+ fake_head[1]= data_length & 0xff;
+ fake_head[2]= fake_head[3]= 0;
+ ret= fwrite(fake_head, 4, 1, fp);
+ if(ret != 1) {
+write_failure:;
+ fprintf(stderr,
+ "cdrskin: SORRY : Cannot write all data to file '%s'\n", path);
+ fprintf(stderr, "cdrskin: %s (errno=%d)\n", strerror(errno), errno);
+ fclose(fp);
+ return(0);
+ }
+ ret= fwrite(text_packs, data_length - 2, 1, fp);
+ if(ret != 1)
+ goto write_failure;
+ fprintf(stderr,
+ "cdrskin: NOTE : Wrote header and %d CD-TEXT bytes to file '%s'\n",
+ data_length - 2, path);
+ fclose(fp);
+ return(1);
+}
+
+
+/* @param flag bit0-3= output format
+ 1= Sony CD-TEXT Input Sheet Version 0.7T
+ 15= Cdrskin_store_text_packs
+ bit4= do not overwrite existing the target file
+*/
+int Cdrskin_cdtext_to_file(struct CdrskiN *skin, char *path, int flag)
+{
+ int ret, fmt, char_code= 0, to_write;
+ struct burn_drive *drive;
+ unsigned char *text_packs= NULL;
+ int num_packs= 0;
+ char *result= 0;
+ FILE *fp= NULL;
+ struct stat stbuf;
+
+ ret= Cdrskin_grab_drive(skin, 0);
+ if(ret<=0)
+ goto ex;
+
+ fmt= flag & 15;
+ drive= skin->drives[skin->driveno].drive;
+ ret= burn_disc_get_leadin_text(drive, &text_packs, &num_packs, 0);
+ if(ret <= 0 || num_packs <= 0) {
+ fprintf(stderr, "cdrskin: No CD-Text or CD-Text unaware drive.\n");
+ ret= 2; goto ex;
+ }
+ if(fmt == 1) {
+ ret = burn_make_input_sheet_v07t(text_packs, num_packs, 0, 0, &result,
+ &char_code, 0);
+ if(ret <= 0)
+ goto ex;
+ to_write= ret;
+ if(stat(path, &stbuf) != -1 && (flag & 16)) {
+ fprintf(stderr, "cdrskin: SORRY : Will not overwrite file '%s'\n", path);
+ return(0);
+ }
+ if(strcmp(path, "-") == 0)
+ fp= stdout;
+ else
+ fp = fopen(path, "w");
+ if(fp == NULL) {
+ if(errno > 0)
+ fprintf(stderr, "cdrskin: %s (errno=%d)\n", strerror(errno), errno);
+ fprintf(stderr,
+ "cdrskin: SORRY : Cannot write CD-TEXT list to file '%s'\n",
+ path);
+ {ret= 0; goto ex;}
+ }
+ ret = fwrite(result, to_write, 1, fp);
+ if(ret != 1) {
+ if(errno > 0)
+ fprintf(stderr, "cdrskin: %s (errno=%d)\n", strerror(errno), errno);
+ fprintf(stderr,
+ "cdrskin: SORRY : Cannot write all CD-TEXT to file '%s'\n", path);
+ ret= 0;
+ }
+ if(ret <= 0)
+ goto ex;
+
+ } else if(fmt == 15) {
+ if(skin->verbosity >= Cdrskin_verbose_debuG)
+ Cdrskin_print_text_packs(skin, text_packs, num_packs, 0);
+ ret= Cdrskin_store_text_packs(skin, text_packs, num_packs, path, flag & 16);
+ if(ret <= 0)
+ goto ex;
+ printf("CD-Text len: %d\n", num_packs * 18 + 4);
+
+ } else {
+ fprintf(stderr, "cdrskin: FATAL : Program error : Unknown format %d with Cdrskin_cdtext_to_file.\n", fmt);
+ {ret= -1; goto ex;}
+ }
+ ret= 1;
+ex:;
+ if(result != NULL)
+ free(result);
+ if(text_packs != NULL)
+ free(text_packs);
+ if(fp != NULL && fp != stdout)
+ fclose(fp);
+ return(1);
+}
+
+
+/** Perform -toc under control of Cdrskin_atip().
+ @param flag Bitfield for control purposes:
+ bit0= do not list sessions separately (do it cdrecord style)
+ @return <=0 error, 1 success
+*/
+int Cdrskin_toc(struct CdrskiN *skin, int flag)
+{
+ int num_sessions= 0,num_tracks= 0,lba= 0,track_count= 0,total_tracks= 0;
+ int session_no, track_no, pmin, psec, pframe, ret, final_ret= 1;
+ int track_offset = 1, open_sessions= 0, have_real_open_session= 0;
+ struct burn_drive *drive;
+ struct burn_disc *disc= NULL;
+ struct burn_session **sessions;
+ struct burn_track **tracks;
+ struct burn_toc_entry toc_entry;
+ enum burn_disc_status s;
+ char profile_name[80];
+ int profile_number;
+
+ drive= skin->drives[skin->driveno].drive;
+
+ s= burn_disc_get_status(drive);
+ if(s == BURN_DISC_EMPTY || s == BURN_DISC_BLANK)
+ goto summary;
+ disc= burn_drive_get_disc(drive);
+ if(disc==NULL) {
+ if(skin->grow_overwriteable_iso>0) {
+ ret= Cdrskin_overwriteable_iso_size(skin,&lba,0);
+ if(ret>0) {
+ printf(
+"first: 1 last: 1 (fabricated from ISO-9660 image on overwriteable media)\n");
+ printf(
+"track: 1 lba: 0 ( 0) 00:02:00 adr: 1 control: 4 mode: 1\n");
+ burn_lba_to_msf(lba, &pmin, &psec, &pframe);
+ printf("track:lout lba: %9d (%9d) %2.2d:%2.2d:%2.2d",
+ lba,4*lba,pmin,psec,pframe);
+ printf(" adr: 1 control: 4 mode: -1\n");
+ goto summary;
+ }
+ }
+ goto cannot_read;
+ }
+ sessions= burn_disc_get_sessions(disc,&num_sessions);
+ open_sessions= burn_disc_get_incomplete_sessions(disc);
+ if(num_sessions > 0)
+ track_offset = burn_session_get_start_tno(sessions[0], 0);
+ if(track_offset <= 0)
+ track_offset= 1;
+ if(flag&1) {
+ for(session_no= 0; session_no < num_sessions + open_sessions;
+ session_no++) {
+ tracks= burn_session_get_tracks(sessions[session_no],&num_tracks);
+ total_tracks+= num_tracks;
+ if(session_no == num_sessions + open_sessions - 1 && open_sessions > 0) {
+ total_tracks--; /* Do not count invisible track */
+ if(num_tracks > 1)
+ have_real_open_session= 1;
+ }
+ }
+ printf("first: %d last %d\n",
+ track_offset, total_tracks + track_offset - 1);
+ }
+ for(session_no= 0; session_no < num_sessions + open_sessions; session_no++) {
+ tracks= burn_session_get_tracks(sessions[session_no],&num_tracks);
+ if(tracks==NULL)
+ continue;
+ if(session_no == num_sessions + open_sessions - 1 && open_sessions > 0)
+ num_tracks--;
+ if(num_tracks <= 0)
+ continue;
+ if(!(flag&1))
+ printf("first: %d last: %d\n",
+ track_count + track_offset,
+ track_count + num_tracks + track_offset - 1);
+ for(track_no= 0; track_no>> From where does cdrecord take "mode" ? */
+
+ /* This is not the "mode" as printed by cdrecord :
+ printf(" mode: %d\n",burn_track_get_mode(tracks[track_no]));
+ */
+ /* own guess: cdrecord says "1" on data and "0" on audio : */
+ printf(" mode: %d\n",((toc_entry.control&7)<4?0:1));
+
+ }
+ if((flag&1) &&
+ session_no < num_sessions + open_sessions - 1 + have_real_open_session - 1)
+ continue;
+ if(have_real_open_session) {
+ /* Use start of invisible track */
+ burn_track_get_entry(tracks[num_tracks], &toc_entry);
+ } else {
+ burn_session_get_leadout_entry(sessions[session_no],&toc_entry);
+ }
+ if(toc_entry.extensions_valid&1) { /* DVD extension valid */
+ lba= toc_entry.start_lba;
+ burn_lba_to_msf(lba, &pmin, &psec, &pframe);
+ } else {
+ pmin= toc_entry.pmin;
+ psec= toc_entry.psec;
+ pframe= toc_entry.pframe;
+ lba= burn_msf_to_lba(pmin,psec,pframe);
+ }
+ printf("track:lout lba: %9d (%9d) %2.2d:%2.2d:%2.2d",
+ lba,4*lba,pmin,psec,pframe);
+ printf(" adr: %d control: %d",toc_entry.adr,toc_entry.control);
+ printf(" mode: -1\n");
+ }
+
+ if(skin->verbosity >= Cdrskin_verbose_cmD) {
+ ret= Cdrskin_cdtext_to_file(skin, "cdtext.dat", 15 | 16);
+ if(ret <= 0 && ret < final_ret)
+ final_ret= ret;
+ }
+
+summary:
+ ret= burn_disc_get_profile(drive, &profile_number, profile_name);
+ if(ret <= 0)
+ strcpy(profile_name, "media");
+
+ if(open_sessions > 0 && !have_real_open_session)
+ open_sessions--;
+ printf("Media summary: %d sessions, %d tracks, %s %s\n",
+ num_sessions + open_sessions, track_count,
+ s==BURN_DISC_BLANK ? "blank" :
+ s==BURN_DISC_APPENDABLE ? "appendable" :
+ s==BURN_DISC_FULL ? "closed" :
+ s==BURN_DISC_EMPTY ? "no " : "unknown ",
+ profile_name);
+
+ if(have_real_open_session)
+ printf("Warning : Incomplete session encountered !\n");
+
+ if(disc!=NULL)
+ burn_disc_free(disc);
+ if(s == BURN_DISC_EMPTY)
+ return(0);
+ return(final_ret);
+cannot_read:;
+ fprintf(stderr,"cdrecord_emulation: Cannot read TOC header\n");
+ fprintf(stderr,"cdrecord_emulation: Cannot read TOC/PMA\n");
+ return(0);
+}
+
+
+/** Perform -minfo under control of Cdrskin_atip().
+ @param flag Bitfield for control purposes:
+ @return <=0 error, 1 success
+*/
+int Cdrskin_minfo(struct CdrskiN *skin, int flag)
+{
+ int num_sessions= 0,num_tracks= 0,lba= 0,track_count= 0,total_tracks= 0;
+ int session_no, track_no, pmin, psec, pframe, ret, size= 0, nwa= 0;
+ int last_leadout= 0, ovwrt_full= 0, track_offset= 1, open_sessions= 0;
+ struct burn_drive *drive;
+ struct burn_disc *disc= NULL;
+ struct burn_session **sessions= NULL;
+ struct burn_track **tracks;
+ struct burn_toc_entry toc_entry;
+ enum burn_disc_status s, show_status;
+ char profile_name[80];
+ int pno;
+ char media_class[80];
+ int nominal_sessions= 1, ftils= 1, ltils= 1, first_track= 1, read_capacity= 0;
+ int app_code, cd_info_valid, lra, alloc_blocks, free_blocks;
+ int have_real_open_session= 0;
+ off_t avail, buf_count;
+ char disc_type[80], bar_code[9], buf[2 * 2048], *type_text;
+ unsigned int disc_id;
+
+ drive= skin->drives[skin->driveno].drive;
+
+ s= burn_disc_get_status(drive);
+ if(s == BURN_DISC_EMPTY) {
+ fprintf(stderr, "cdrecord-Emulation: No disk / Wrong disk!\n");
+ return(1);
+ }
+ ret= burn_disc_get_profile(drive, &pno, profile_name);
+ if(ret <= 0) {
+ fprintf(stderr, "cdrskin: SORRY : Cannot inquire current media profile\n");
+ return(1);
+ }
+ if(pno >= 0x08 && pno <= 0x0a)
+ strcpy(media_class, "CD");
+ else if(pno >= 0x10 && pno <= 0x2f)
+ strcpy(media_class, "DVD");
+ else if(pno >= 0x40 && pno <= 0x43)
+ strcpy(media_class, "BD");
+ else
+ sprintf(media_class, "Unknown class (profile 0x%4.4X)", pno);
+
+ printf("\n");
+ printf("Mounted media class: %s\n", media_class);
+ printf("Mounted media type: %s\n", profile_name);
+ ret= burn_disc_erasable(drive);
+ printf("Disk Is %serasable\n",
+ (ret || skin->media_is_overwriteable) ? "" : "not ");
+ show_status= s;
+ ret = burn_get_read_capacity(drive, &read_capacity, 0);
+ if(ret <= 0)
+ read_capacity= 0;
+ if(skin->media_is_overwriteable && read_capacity > 0)
+ ovwrt_full= 1;
+ if(ovwrt_full)
+ show_status= BURN_DISC_FULL;
+ printf("disk status: %s\n",
+ show_status == BURN_DISC_BLANK ? "empty" :
+ show_status == BURN_DISC_APPENDABLE ? "incomplete/appendable" :
+ show_status == BURN_DISC_FULL ? "complete" :
+ "unusable");
+ printf("session status: %s\n",
+ show_status == BURN_DISC_BLANK ? "empty" :
+ show_status == BURN_DISC_APPENDABLE ? "empty" :
+ show_status == BURN_DISC_FULL ? "complete" :
+ "unknown");
+
+ disc= burn_drive_get_disc(drive);
+ if(disc==NULL || s == BURN_DISC_BLANK) {
+ first_track= 1;
+ num_sessions= 0;
+ nominal_sessions= 1;
+ ftils= ltils= 1;
+ } else {
+
+ sessions= burn_disc_get_sessions(disc, &num_sessions);
+ open_sessions= burn_disc_get_incomplete_sessions(disc);
+ if(num_sessions > 0)
+ track_offset= burn_session_get_start_tno(sessions[0], 0);
+ if(track_offset <= 0)
+ track_offset= 1;
+ first_track= track_offset;
+ nominal_sessions= num_sessions + open_sessions;
+ if(s == BURN_DISC_APPENDABLE && open_sessions == 0)
+ nominal_sessions++;
+ for(session_no= 0; session_no < num_sessions + open_sessions;
+ session_no++) {
+ ftils= total_tracks + 1;
+ tracks= burn_session_get_tracks(sessions[session_no],&num_tracks);
+ if(tracks==NULL)
+ continue;
+ total_tracks+= num_tracks;
+ ltils= total_tracks;
+ if(session_no==0 && burn_session_get_hidefirst(sessions[session_no])
+ && total_tracks >= 2)
+ first_track= 2;
+ }
+ if(s == BURN_DISC_APPENDABLE && open_sessions == 0)
+ ftils= ltils= total_tracks + 1;
+ }
+ printf("first track: %d\n", first_track);
+ printf("number of sessions: %d\n", nominal_sessions);
+ printf("first track in last sess: %d\n", ftils + track_offset - 1);
+ printf("last track in last sess: %d\n", ltils + track_offset - 1);
+
+ burn_disc_get_cd_info(drive, disc_type, &disc_id, bar_code, &app_code,
+ &cd_info_valid);
+ printf("Disk Is %sunrestricted\n", (cd_info_valid & 16) ? "" : "not ");
+ if((cd_info_valid & 8) && !(cd_info_valid & 16))
+ printf("Disc application code: %d\n", app_code);
+ if(strcmp(media_class, "DVD") == 0 || strcmp(media_class, "BD") == 0)
+ printf("Disk type: DVD, HD-DVD or BD\n");
+ else if(strcmp(media_class, "CD") == 0 && (cd_info_valid & 1))
+ printf("Disk type: %s\n", disc_type);
+ else
+ printf("Disk type: unrecognizable\n");
+ if(cd_info_valid & 2)
+ printf("Disk id: 0x%-X\n", disc_id);
+ ret= burn_disc_get_bd_spare_info(drive, &alloc_blocks, &free_blocks, 0);
+ if(ret == 1) {
+ printf("BD Spare Area consumed: %d\n", alloc_blocks - free_blocks);
+ printf("BD Spare Area available: %d\n", free_blocks);
+ }
+
+ printf("\n");
+ printf("Track Sess Type Start Addr End Addr Size\n");
+ printf("==============================================\n");
+ for(session_no= 0; session_no < num_sessions + open_sessions; session_no++) {
+ tracks= burn_session_get_tracks(sessions[session_no],&num_tracks);
+ if(tracks==NULL)
+ continue;
+ for(track_no= 0; track_no= 0x08 && pno <= 0x0a && ((toc_entry.control & 7) >= 4) &&
+ lra >= 2 && size >= 2) {
+ /* If last two blocks not readable then assume TAO and subtract 2
+ from lra and size.
+ */;
+ ret= burn_read_data(drive, (off_t) (lra - 1) * (off_t) 2048, buf,
+ 2 * 2048, &buf_count, 2 | 4);
+ if(ret <= 0) {
+ lra-= 2;
+ size-= 2;
+ }
+ }
+
+#ifdef Cdrskin_with_last_recorded_addresS
+
+ /* Interesting, but obviously not what cdrecord prints as "End Addr" */
+ if(toc_entry.extensions_valid & 2) { /* LRA extension valid */
+ if(pno == 0x11 || pno == 0x13 || pno == 0x14 || pno == 0x15 ||
+ pno == 0x41 || pno == 0x42 || pno == 0x51)
+ lra= toc_entry.last_recorded_address;
+ }
+
+#endif /* Cdrskin_with_last_recorded_addresS */
+
+ if(session_no < num_sessions) {
+ type_text= ((toc_entry.control&7)<4) ? "Audio" : "Data";
+ } else {
+ if(track_no < num_tracks - 1) {
+ type_text= "Rsrvd";
+ have_real_open_session = 1;
+ } else {
+ type_text= "Blank";
+ }
+ if(toc_entry.extensions_valid & 4) {
+ if(toc_entry.track_status_bits & (1 << 14))
+ type_text= "Blank";
+ else if(toc_entry.track_status_bits & (1 << 16)) {
+ type_text= "Apdbl";
+ have_real_open_session = 1;
+ } else if(toc_entry.track_status_bits & (1 << 15)) {
+ type_text= "Rsrvd";
+ have_real_open_session = 1;
+ } else
+ type_text= "Invsb";
+ }
+ }
+ printf("%5d %5d %-6s %-10d %-10d %-10d\n",
+ track_count + track_offset - 1, session_no + 1,
+ type_text, lba, lra, size);
+ if(session_no < num_sessions)
+ last_leadout= lba + size;
+ }
+ }
+ if(last_leadout > 0)
+ if(read_capacity > last_leadout)
+ read_capacity= last_leadout;
+ if(nominal_sessions > num_sessions) {
+ ret= burn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
+ if(ret > 0) {
+ avail= burn_disc_available_space(drive, NULL);
+ size= avail / 2048;
+ if(read_capacity == 0 && skin->media_is_overwriteable)
+ size= 0; /* unformatted overwriteable media */
+ if(nominal_sessions > num_sessions + open_sessions) {
+ printf("%5d %5d %-6s %-10d %-10d %-10d\n",
+ track_count + track_offset, nominal_sessions,
+ ovwrt_full ? "Data" : "Blank",
+ nwa, nwa + size - 1, size);
+ }
+ }
+ }
+ printf("\n");
+
+ if(num_sessions > 0) {
+ ret= burn_disc_get_msc1(drive, &lba);
+ if(ret > 0)
+ printf("Last session start address: %-10d\n", lba);
+ if(last_leadout > 0)
+ printf("Last session leadout start address: %-10d\n", last_leadout);
+ if(s == BURN_DISC_FULL) {
+ if(read_capacity > 0 && (last_leadout != read_capacity ||
+ pno == 0x08 || pno == 0x10 || pno == 0x40 || pno == 0x50))
+ printf("Read capacity: %-10d\n", read_capacity);
+ }
+ } else if(ovwrt_full) {
+ printf("Last session start address: %-10d\n", nwa);
+ printf("Last session leadout start address: %-10d\n", size);
+ }
+ if(nominal_sessions > num_sessions && !skin->media_is_overwriteable) {
+ printf("Next writable address: %-10d\n", nwa);
+ printf("Remaining writable size: %-10d\n", size);
+ }
+
+ if(ovwrt_full) {
+ printf("\n");
+ printf("cdrskin: Media is overwriteable. No blanking needed. No reliable track size.\n");
+ printf("cdrskin: Above contrary statements follow cdrecord traditions.\n");
+ }
+
+ if(have_real_open_session)
+ printf("\nWarning: Incomplete session encountered !\n");
+
+ if(disc!=NULL)
+ burn_disc_free(disc);
+ if(s == BURN_DISC_EMPTY)
+ return(0);
+ return(1);
+}
+
+
+int Cdrskin_print_all_profiles(struct CdrskiN *skin, struct burn_drive *drive,
+ int flag)
+{
+ int num_profiles, profiles[64], i, ret;
+ char is_current[64], profile_name[80];
+
+ burn_drive_get_all_profiles(drive, &num_profiles, profiles, is_current);
+ for(i= 0; i < num_profiles; i++) {
+ ret= burn_obtain_profile_name(profiles[i], profile_name);
+ if(ret <= 0)
+ strcpy(profile_name, "unknown");
+ printf("Profile: 0x%4.4X (%s)%s\n", (unsigned int) profiles[i],
+ profile_name, is_current[i] ? " (current)" : "");
+ }
+ return(1);
+}
+
+
+/** Perform -atip .
+ @param flag Bitfield for control purposes:
+ bit0= perform -toc
+ bit1= perform -toc with session markers
+ bit2= perform -minfo
+ @return <=0 error, 1 success
+*/
+int Cdrskin_atip(struct CdrskiN *skin, int flag)
+{
+ int ret,is_not_really_erasable= 0, current_is_cd= 1;
+ double x_speed_max= -1.0, x_speed_min= -1.0;
+ enum burn_disc_status s;
+ struct burn_drive *drive;
+ int profile_number= 0;
+ char profile_name[80], *manuf= NULL, *media_code1= NULL, *media_code2= NULL;
+ char *book_type= NULL, *product_id= NULL;
+ char *sno= NULL;
+ int sno_len = 0, i;
+
+ ClN(printf("cdrskin: pseudo-atip on drive %d\n",skin->driveno));
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+ s= burn_disc_get_status(drive);
+ Cdrskin_report_disc_status(skin,s,1|2);
+ if(s==BURN_DISC_APPENDABLE && skin->no_blank_appendable)
+ is_not_really_erasable= 1;
+
+ profile_name[0]= 0;
+ ret= burn_disc_get_profile(drive,&profile_number,profile_name);
+ if(ret<=0) {
+ profile_number= 0;
+ strcpy(profile_name, "-unidentified-");
+ }
+ if(profile_number != 0x08 && profile_number != 0x09 && profile_number != 0x0a)
+ current_is_cd= 0;
+
+ ret= Cdrskin_checkdrive(skin,profile_name,1);
+ if(ret<=0)
+ return(ret);
+
+ if(burn_disc_get_status(drive) != BURN_DISC_UNSUITABLE) {
+ ret= burn_disc_read_atip(drive);
+ if(ret>0) {
+ ret= burn_drive_get_min_write_speed(drive);
+ x_speed_min= ((double) ret)/Cdrskin_libburn_speed_factoR;
+ }
+ }
+ if(burn_disc_get_status(drive) == BURN_DISC_UNSUITABLE) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(profile_name[0])
+ printf("Current: %s\n",profile_name);
+ else
+ printf("Current: UNSUITABLE MEDIA (Profile %4.4Xh)\n",profile_number);
+ }
+ {ret= 0; goto ex;}
+ }
+ if(burn_disc_get_status(drive) != BURN_DISC_EMPTY) {
+ ret= burn_drive_get_write_speed(drive);
+ x_speed_max= ((double) ret)/Cdrskin_libburn_speed_factoR;
+ if(x_speed_min<0)
+ x_speed_min= x_speed_max;
+ }
+ printf("cdrskin: burn_drive_get_write_speed = %d (%.1fx)\n",ret,x_speed_max);
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(burn_disc_get_status(drive) == BURN_DISC_EMPTY)
+ printf("Current: none\n");
+ else if(profile_name[0])
+ printf("Current: %s\n",profile_name);
+ else if(burn_disc_erasable(drive))
+ printf("Current: CD-RW\n");
+ else
+ printf("Current: CD-R\n");
+ Cdrskin_print_all_profiles(skin, drive, 0);
+ }
+
+ if(burn_disc_get_status(drive) == BURN_DISC_EMPTY)
+ {ret= 0; goto ex;}
+
+ if(strstr(profile_name,"DVD")==profile_name) {
+ /* These are dummy messages for project scdbackup, so its media recognition
+ gets a hint that the media is suitable and not in need of blanking.
+ scdbackup will learn to interpret cdrskin's DVD messages but the
+ current stable version needs to believe it is talking to its own
+ growisofs_wrapper. So this is an emulation of an emulator.
+ The real book type is available meanwhile. But that one is not intended.
+ */
+ printf("book type: %s (emulated booktype)\n", profile_name);
+ if(profile_number==0x13) /* DVD-RW */
+ printf("cdrskin: message for sdvdbackup: \"(growisofs mode Restricted Overwrite)\"\n");
+ } else if(strstr(profile_name,"BD")==profile_name) {
+ printf("Mounted Media: %2.2Xh, %s\n", profile_number, profile_name);
+ } else {
+ printf("ATIP info from disk:\n");
+ if(burn_disc_erasable(drive)) {
+ if(is_not_really_erasable)
+ printf(" Is erasable (but not while in this incomplete state)\n");
+ else
+ printf(" Is erasable\n");
+ } else {
+ printf(" Is not erasable\n");
+ }
+ { int start_lba,end_lba,min,sec,fr;
+ int m_lo, s_lo, f_lo;
+
+ ret= burn_drive_get_start_end_lba(drive,&start_lba,&end_lba,0);
+ if(ret>0) {
+ burn_lba_to_msf(start_lba,&min,&sec,&fr);
+ printf(" ATIP start of lead in: %d (%-2.2d:%-2.2d/%-2.2d)\n",
+ start_lba,min,sec,fr);
+ burn_lba_to_msf(end_lba,&m_lo,&s_lo,&f_lo);
+ printf(" ATIP start of lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n",
+ end_lba, m_lo, s_lo, f_lo);
+ if(current_is_cd)
+ manuf= burn_guess_cd_manufacturer(min, sec, fr, m_lo, s_lo, f_lo, 0);
+ }
+ }
+ printf(" 1T speed low: %.f 1T speed high: %.f\n",x_speed_min,x_speed_max);
+ }
+
+ ret= burn_disc_get_media_id(drive, &product_id, &media_code1, &media_code2,
+ &book_type, 0);
+ if(ret > 0 && (!current_is_cd) &&
+ manuf == NULL && media_code1 != NULL && media_code2 != NULL) {
+
+ manuf= burn_guess_manufacturer(profile_number, media_code1, media_code2, 0);
+ }
+ if(product_id != NULL)
+ printf("Product Id: %s\n", product_id);
+ if(manuf != NULL)
+ printf("Producer: %s\n", manuf);
+ if(skin->verbosity >= Cdrskin_verbose_progresS) {
+ if (current_is_cd) {
+ if(manuf != NULL)
+ printf("Manufacturer: %s\n", manuf);
+ } else if(product_id != NULL && media_code1 != NULL && media_code2 != NULL){
+ free(product_id);
+ free(media_code1);
+ free(media_code2);
+ if(book_type != NULL)
+ free(book_type);
+ product_id= media_code1= media_code2= book_type= NULL;
+ ret= burn_disc_get_media_id(drive, &product_id, &media_code1,
+ &media_code2, &book_type, 1);
+ if(ret > 0) {
+ if(profile_number == 0x11 || profile_number == 0x13 ||
+ profile_number == 0x14 || profile_number == 0x15)
+ printf("Manufacturer: '%s'\n", media_code1);
+ else if(profile_number >= 0x40 && profile_number <= 0x43) {
+ printf("Manufacturer: '%s'\n", media_code1);
+ if(media_code2[0])
+ printf("Media type: '%s'\n", media_code2);
+ } else {
+ printf("Manufacturer: '%s'\n", media_code1);
+ if(media_code2[0])
+ printf("Media type: '%s'\n", media_code2);
+ }
+ }
+ }
+ }
+
+ burn_drive_get_media_sno(drive, &sno, &sno_len);
+ if(sno_len > 0) {
+ printf("Media id: ");
+ for(i= 0; i < sno_len && i < 1024; i++)
+ printf("%2.2X", (unsigned int) ((unsigned char *) sno)[i]);
+ if(i < sno_len)
+ printf("...");
+ printf("\n");
+ }
+ if(sno != NULL)
+ free(sno);
+ sno= NULL;
+
+
+ ret= 1;
+ if(flag&1)
+ ret= Cdrskin_toc(skin, !(flag & 2));
+ /*cdrecord seems to ignore -toc errors if -atip is ok */
+ if(ret > 0 && (flag & 4))
+ ret= Cdrskin_minfo(skin, 0);
+
+ex:;
+ if(manuf != NULL)
+ free(manuf);
+ if(media_code1 != NULL)
+ free(media_code1);
+ if(media_code2 != NULL)
+ free(media_code2);
+ if(book_type != NULL)
+ free(book_type);
+ if(product_id != NULL)
+ free(product_id);
+
+ return(ret);
+}
+
+
+/** Perform --list_formats
+ @param flag Bitfield for control purposes:
+ @return <=0 error, 1 success
+*/
+int Cdrskin_list_formats(struct CdrskiN *skin, int flag)
+{
+ struct burn_drive *drive;
+ int ret, i, status, num_formats, profile_no, type, alloc_blocks, free_blocks;
+ off_t size;
+ unsigned dummy;
+ char status_text[80], profile_name[90];
+
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+
+ ret = burn_disc_get_formats(drive, &status, &size, &dummy,
+ &num_formats);
+ if(ret <= 0) {
+ fprintf(stderr, "cdrskin: SORRY: Cannot obtain format list info\n");
+ ret= 0; goto ex;
+ }
+ ret= burn_disc_get_profile(drive, &profile_no, profile_name);
+ printf("Media current: ");
+ if(profile_no > 0 && ret > 0) {
+ if(profile_name[0])
+ printf("%s\n", profile_name);
+ else
+ printf("%4.4Xh\n", profile_no);
+ } else
+ printf("is not recognizable\n");
+
+ if(status == BURN_FORMAT_IS_UNFORMATTED)
+ sprintf(status_text, "unformatted, up to %.1f MiB",
+ ((double) size) / 1024.0 / 1024.0);
+ else if(status == BURN_FORMAT_IS_FORMATTED) {
+ if(profile_no==0x12 || profile_no==0x13 || profile_no==0x1a ||
+ profile_no==0x43)
+ sprintf(status_text, "formatted, with %.1f MiB",
+ ((double) size) / 1024.0 / 1024.0);
+ else
+ sprintf(status_text, "written, with %.1f MiB",
+ ((double) size) / 1024.0 / 1024.0);
+ } else if(status == BURN_FORMAT_IS_UNKNOWN) {
+ if (profile_no > 0)
+ sprintf(status_text, "intermediate or unknown");
+ else
+ sprintf(status_text, "no media or unknown media");
+ } else
+ sprintf(status_text, "illegal status according to MMC-5");
+ printf("Format status: %s\n", status_text);
+ ret= burn_disc_get_bd_spare_info(drive, &alloc_blocks, &free_blocks, 0);
+ if(ret == 1)
+ printf("BD Spare Area: %d blocks consumed, %d blocks available\n",
+ alloc_blocks - free_blocks, free_blocks);
+
+ for (i = 0; i < num_formats; i++) {
+ ret= burn_disc_get_format_descr(drive, i, &type, &size, &dummy);
+ if (ret <= 0)
+ continue;
+ printf("Format idx %-2d: %2.2Xh , %.fs , %.1f MiB\n",
+ i, type, ((double) size) / 2048.0, ((double) size) / 1024.0/1024.0);
+ }
+ ret= 1;
+ex:;
+ return(ret);
+}
+
+
+/** Perform --list_speeds
+ @param flag Bitfield for control purposes:
+ @return <=0 error, 1 success
+*/
+int Cdrskin_list_speeds(struct CdrskiN *skin, int flag)
+{
+ struct burn_drive *drive;
+ int ret, i, profile_no, high= -1, low= 0x7fffffff, is_cd= 0;
+ char profile_name[90], *speed_unit= "D";
+ double speed_factor= 1385000.0, cd_factor= 75.0 * 2352;
+ struct burn_speed_descriptor *speed_list= NULL, *item, *other;
+
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+ ret= burn_drive_get_speedlist(drive, &speed_list);
+ if(ret <= 0) {
+ fprintf(stderr, "cdrskin: SORRY: Cannot obtain speed list info\n");
+ ret= 0; goto ex;
+ }
+ ret= burn_disc_get_profile(drive, &profile_no, profile_name);
+ printf("Media current: ");
+ if(profile_no > 0 && ret > 0) {
+ if(profile_name[0])
+ printf("%s\n", profile_name);
+ else
+ printf("%4.4Xh\n", profile_no);
+ } else
+ printf("is not recognizable\n");
+ if(profile_no >= 0x08 && profile_no <= 0x0a)
+ is_cd= profile_no;
+ speed_factor= Cdrskin_libburn_speed_factoR * 1000.0;
+ if(Cdrskin_libburn_speed_factoR == Cdrskin_libburn_cd_speed_factoR)
+ speed_unit= "C";
+ else if(Cdrskin_libburn_speed_factoR == Cdrskin_libburn_bd_speed_factoR)
+ speed_unit= "B";
+
+ for (item= speed_list; item != NULL; item= item->next) {
+ if(item->source == 1) {
+ /* CD mode page 2Ah : report only if not same speed by GET PERFORMANCE */
+ for(other= speed_list; other != NULL; other= other->next)
+ if(other->source == 2 && item->write_speed == other->write_speed)
+ break;
+ if(other != NULL)
+ continue;
+ }
+ printf("Write speed : %5dk , %4.1fx%s\n",
+ item->write_speed,
+ ((double) item->write_speed) * 1000.0 / speed_factor, speed_unit);
+ if(item->write_speed > high)
+ high= item->write_speed;
+ if(item->write_speed < low)
+ low= item->write_speed;
+ }
+
+ /* Maybe there is ATIP info */
+ if(is_cd) {
+ ret= burn_disc_read_atip(drive);
+ if(ret < 0)
+ goto ex;
+ if(ret > 0) {
+ for(i= 0; i < 2; i++) {
+ if(i == 0)
+ ret= burn_drive_get_min_write_speed(drive);
+ else
+ ret= burn_drive_get_write_speed(drive);
+ if(ret > 0) {
+ if(ret < low || (i == 0 && ret != low)) {
+ printf("Write speed l: %5dk , %4.1fx%s\n",
+ ret, ((double) ret) * 1000.0 / cd_factor, "C");
+ low= ret;
+ }
+ if(ret > high || (i == 1 && ret != high)) {
+ printf("Write speed h: %5dk , %4.1fx%s\n",
+ ret, ((double) ret) * 1000.0 / cd_factor, "C");
+ high= ret;
+ }
+ }
+ }
+ }
+ }
+ if(high > -1) {
+ printf("Write speed L: %5dk , %4.1fx%s\n",
+ low, ((double) low) * 1000.0 / speed_factor, speed_unit);
+ printf("Write speed H: %5dk , %4.1fx%s\n",
+ high, ((double) high) * 1000.0 / speed_factor, speed_unit);
+ ret= burn_drive_get_best_speed(drive, -1, &item, 2);
+ if(ret > 0 && item != NULL)
+ if(item->write_speed != low)
+ printf("Write speed 0: %5dk , %4.1fx%s\n",
+ item->write_speed,
+ ((double) item->write_speed) * 1000.0 / speed_factor, speed_unit);
+ ret= burn_drive_get_best_speed(drive, 0, &item, 2);
+ if(ret > 0 && item != NULL)
+ if(item->write_speed != high)
+ printf("Write speed-1: %5dk , %4.1fx%s\n",
+ item->write_speed,
+ ((double) item->write_speed) * 1000.0 / speed_factor, speed_unit);
+ } else {
+ fprintf(stderr,
+ "cdrskin: SORRY : Could not get any write speed information from drive");
+ }
+ ret= 1;
+ex:;
+ if(speed_list != NULL)
+ burn_drive_free_speedlist(&speed_list);
+ return(ret);
+}
+
+
+int Cdrskin_read_textfile(struct CdrskiN *skin, char *path, int flag)
+{
+ int ret, num_packs = 0;
+ unsigned char *text_packs = NULL;
+
+ ret= burn_cdtext_from_packfile(path, &text_packs, &num_packs, 0);
+ if(ret <= 0)
+ goto ex;
+
+ if(skin->text_packs != NULL)
+ free(skin->text_packs);
+ skin->text_packs= text_packs;
+ skin->num_text_packs= num_packs;
+ ret= 1;
+ex:;
+ if(ret <= 0 && text_packs != NULL)
+ free(text_packs);
+ return(ret);
+}
+
+
+/*
+ @param flag Bitfield for control purposes:
+ bit3= Enable DAP : "flaw obscuring mechanisms like
+ audio data mute and interpolate"
+*/
+int Cdrskin_extract_audio_to_dir(struct CdrskiN *skin,
+ char *dir, char *basename,
+ char print_tracks[100], int flag)
+{
+ int num_sessions= 0, num_tracks= 0, profile_number, session_no, track_no;
+ int track_count= 0, existing= 0, ret, pass, not_audio= 0, pick_tracks= 0, i;
+ int tracks_extracted= 0, min_tno= 100, max_tno= 0;
+ struct burn_drive *drive;
+ struct burn_disc *disc= NULL;
+ struct burn_session **sessions;
+ struct burn_track **tracks;
+ enum burn_disc_status s;
+ struct burn_toc_entry toc_entry;
+ struct stat stbuf;
+ char profile_name[80], path[4096 + 256];
+
+ ret= Cdrskin_grab_drive(skin, 0);
+ if(ret<=0)
+ goto ex;
+ drive= skin->drives[skin->driveno].drive;
+ s= burn_disc_get_status(drive);
+ disc= burn_drive_get_disc(drive);
+ if(s == BURN_DISC_EMPTY || s == BURN_DISC_BLANK || disc == NULL) {
+not_readable:;
+ fprintf(stderr, "cdrskin: SORRY : No audio CD in drive.\n");
+ ret= 0; goto ex;
+ }
+ ret= burn_disc_get_profile(drive, &profile_number, profile_name);
+ if(ret <= 0 || profile_number < 0x08 || profile_number > 0x0a) {
+not_audio_cd:;
+ fprintf(stderr, "cdrskin: SORRY : Medium in drive is not an audio CD.\n");
+ ret= 0; goto ex;
+ }
+ for(i= 0; i < 99; i++)
+ if(print_tracks[i])
+ pick_tracks= 1;
+ sessions= burn_disc_get_sessions(disc, &num_sessions);
+ if(num_sessions <= 0)
+ goto not_readable;
+ for(pass= 0; pass < 2; pass++) {
+ if(pass > 0) {
+ if(existing > 0)
+ {ret= 0; goto ex;}
+ if(not_audio == track_count)
+ goto not_audio_cd;
+ }
+ track_count= 0;
+ for(session_no= 0; session_no < num_sessions; session_no++) {
+ tracks= burn_session_get_tracks(sessions[session_no],&num_tracks);
+ if(tracks==NULL)
+ continue;
+ for(track_no= 0; track_no < num_tracks; track_no++) {
+ track_count++;
+ burn_track_get_entry(tracks[track_no], &toc_entry);
+ if(toc_entry.point < min_tno)
+ min_tno= toc_entry.point;
+ if(toc_entry.point > max_tno)
+ max_tno= toc_entry.point;
+ if(pick_tracks) {
+ if(toc_entry.point <= 0 || toc_entry.point > 99)
+ continue; /* should not happen */
+ if(print_tracks[toc_entry.point] == 0)
+ continue;
+ }
+ if((toc_entry.control & 7) >= 4) {
+ if(pass == 0)
+ fprintf(stderr,
+ "cdrskin: WARNING : Track %2.2d is not an audio track.\n",
+ toc_entry.point);
+ not_audio++;
+ continue;
+ }
+ sprintf(path, "%s/%s%2.2u.wav", dir, basename, toc_entry.point);
+ if(pass == 0) {
+ if(stat(path, &stbuf) != -1) {
+ fprintf(stderr,
+ "cdrskin: SORRY : May not overwrite existing file: '%s'\n",
+ path);
+ existing++;
+ }
+ continue;
+ }
+ if(skin->verbosity >= Cdrskin_verbose_progresS)
+ fprintf(stderr, "cdrskin: Writing audio track file: %s\n", path);
+ ret= burn_drive_extract_audio_track(drive, tracks[track_no], path,
+ (flag & 8) | (skin->verbosity >= Cdrskin_verbose_progresS));
+ if(ret <= 0)
+ goto ex;
+ tracks_extracted++;
+ }
+ }
+ }
+ if(tracks_extracted == 0 && pick_tracks) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Not a single track matched the list of extract_tracks=\n");
+ if(min_tno < 100 && max_tno > 0)
+ fprintf(stderr, "cdrskin: HINT : Track range is %2.2d to %2.2d\n",
+ min_tno, max_tno);
+ ret= 0; goto ex;
+ }
+ ret= 1;
+ex:;
+ return(ret);
+}
+
+
+#ifndef Cdrskin_extra_leaN
+
+/* A70324: proposal by Eduard Bloch */
+int Cdrskin_warn_of_mini_tsize(struct CdrskiN *skin, int flag)
+{
+ off_t media_space= 0;
+ enum burn_disc_status s;
+ struct burn_drive *drive;
+ int ret;
+
+ ret= burn_drive_get_drive_role(skin->drives[skin->driveno].drive);
+ if(ret != 1)
+ return(1);
+
+ if(skin->multi || skin->has_open_ended_track || skin->smallest_tsize<0)
+ return(1);
+ drive= skin->drives[skin->driveno].drive;
+ s= burn_disc_get_status(drive);
+ if(s!=BURN_DISC_BLANK)
+ return(1);
+ media_space= burn_disc_available_space(drive, NULL);
+ if(media_space<=0 ||
+ skin->smallest_tsize >= media_space / Cdrskin_minimum_tsize_quotienT)
+ return(1);
+ fprintf(stderr,"\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,
+ "cdrskin: WARNING: Very small track size set by option tsize=\n");
+ fprintf(stderr,
+ "cdrskin: Track size %.1f MB <-> media capacity %.1f MB\n",
+ skin->smallest_tsize/1024.0/1024.0,
+ ((double) media_space)/1024.0/1024.0);
+ fprintf(stderr,"\n");
+ fprintf(stderr,
+ "cdrskin: Will wait at least 15 seconds until real burning starts\n");
+ fprintf(stderr,"\n");
+ if(skin->gracetime<15)
+ skin->gracetime= 15;
+ return(1);
+}
+
+
+/** Emulate the gracetime= behavior of cdrecord
+ @param flag Bitfield for control purposes:
+ bit0= do not print message about pseudo-checkdrive
+*/
+int Cdrskin_wait_before_action(struct CdrskiN *skin, int flag)
+/* flag: bit0= BLANK rather than write mode
+ bit1= FORMAT rather than write mode
+*/
+{
+ int i;
+
+ Cdrskin_warn_of_mini_tsize(skin,0);
+
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ char speed_text[80];
+ if(skin->x_speed<0)
+ strcpy(speed_text,"MAX");
+ else if(skin->x_speed==0)
+ strcpy(speed_text,"MIN");
+ else
+ sprintf(speed_text,"%.f",skin->x_speed);
+ printf(
+ "Starting to write CD/DVD at speed %s in %s %s mode for %s session.\n",
+ speed_text,(skin->dummy_mode?"dummy":"real"),
+ (flag&2?"FORMAT":(flag&1?"BLANK":skin->preskin->write_mode_name)),
+ (skin->multi?"multi":"single"));
+ printf("Last chance to quit, starting real write in %3d seconds.",
+ skin->gracetime);
+ fflush(stdout);
+ }
+ for(i= skin->gracetime-1;i>=0;i--) {
+ usleep(1000000);
+ if(Cdrskin__is_aborting(0))
+ return(0);
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ printf("\b\b\b\b\b\b\b\b\b\b\b\b\b %3d seconds.",i);
+ fflush(stdout);
+ }
+ }
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ {printf(" Operation starts.\n");fflush(stdout);}
+ return(1);
+}
+
+#endif /* Cdrskin_extra_leaN */
+
+
+/** Perform blank=[all|fast]
+ @return <=0 error, 1 success
+*/
+int Cdrskin_blank(struct CdrskiN *skin, int flag)
+{
+ enum burn_disc_status s;
+ struct burn_progress p;
+ struct burn_drive *drive;
+ int ret,loop_counter= 0,hint_force= 0,do_format= 0, profile_number= -1;
+ int wrote_well= 1, format_flag= 0, status, num_formats, using_immed= 1;
+ off_t size;
+ unsigned dummy;
+ double start_time;
+ char *verb= "blank", *presperf="blanking", *fmt_text= "...";
+ char profile_name[80], progress_text[40];
+ static char fmtp[][40]= {
+ "...", "format_overwrite", "deformat_sequential",
+ "(-format)", "format_defectmgt", "format_by_index",
+ "format_if_needed", "as_needed"};
+ static int fmtp_max= 7;
+
+ start_time= Sfile_microtime(0); /* will be refreshed later */
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+ s= burn_disc_get_status(drive);
+ profile_name[0]= 0;
+ if(skin->grabbed_drive)
+ burn_disc_get_profile(skin->grabbed_drive,&profile_number,profile_name);
+
+ ret= Cdrskin_report_disc_status(skin,s,
+ 1|(4*!(skin->verbosity>=Cdrskin_verbose_progresS)));
+ if(ret==2)
+ s= BURN_DISC_APPENDABLE;
+ do_format= skin->blank_format_type & 0xff;
+ if(s==BURN_DISC_UNSUITABLE) {
+ if(skin->force_is_set) {
+ ClN(fprintf(stderr,"cdrskin: NOTE : -force blank=... : Treating unsuitable media as burn_disc_full\n"));
+ ret= burn_disc_pretend_full(drive);
+ if(ret <= 0) {
+ ClN(fprintf(stderr,
+ "cdrskin: FAILURE : Medium still considered unsuitable\n"));
+ {ret= 0; goto ex;}
+ }
+ s= burn_disc_get_status(drive);
+ } else
+ hint_force= 1;
+ }
+ if(do_format)
+ if(do_format>=0 && do_format<=fmtp_max)
+ fmt_text= fmtp[do_format];
+ if(do_format==5) { /* format_by_index */
+ if(profile_number == 0x12 || profile_number == 0x43)
+ do_format= 4;
+ else
+ do_format= 1;
+ } else if(do_format==6 || do_format==7) { /* format_if_needed , as_needed */
+ /* Find out whether format is needed at all.
+ Eventuelly set up a suitable formatting run
+ */
+ if(profile_number == 0x14 && do_format==6) { /* sequential DVD-RW */
+ do_format= 1;
+ skin->blank_format_type= 1|(1<<8);
+ skin->blank_format_size= 128*1024*1024;
+ } else if(profile_number == 0x12 ||
+ profile_number == 0x43 ||
+ (profile_number == 0x41 && do_format==6)) {
+ /* DVD-RAM , BD-RE , BD-R SRM */
+ ret= burn_disc_get_formats(drive, &status, &size, &dummy, &num_formats);
+ if((ret>0 && status!=BURN_FORMAT_IS_FORMATTED)) {
+ do_format= 4;
+ skin->blank_format_type= 4|(3<<9); /* default payload size */
+ skin->blank_format_size= 0;
+ }
+ } else if(do_format==7) { /* try to blank what is not blank yet */
+ if(s!=BURN_DISC_BLANK) {
+ do_format= 0;
+ skin->blank_fast= 1;
+ }
+ }
+ if(do_format==6 || do_format==7) {
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(fprintf(stderr,
+ "cdrskin: NOTE : blank=%s : no need for action detected\n", fmt_text));
+ {ret= 2; goto ex;}
+ }
+ }
+
+ if(do_format == 1 || do_format == 3 || do_format == 4) {
+ verb= "format";
+ presperf= "formatting";
+ }
+ if(do_format==2) {
+ /* Forceful blanking to Sequential Recording for DVD-R[W] and CD-RW */
+
+ if(!(profile_number == 0x14 || profile_number == 0x13 ||
+ profile_number == 0x0a)) {
+ if(skin->grow_overwriteable_iso>0 && skin->media_is_overwriteable)
+ goto pseudo_blank_ov;
+ else
+ goto unsupported_format_type;
+ }
+
+ } else if(do_format==1 || do_format==3) {
+ /* Formatting to become overwriteable for DVD-RW and DVD+RW */
+
+ if(do_format==3 && profile_number != 0x1a) {
+ fprintf(stderr, "cdrskin: SORRY : -format does DVD+RW only\n");
+ if(profile_number==0x14)
+ fprintf(stderr,
+ "cdrskin: HINT : blank=format_overwrite would format this media\n");
+ {ret= 0; goto ex;}
+ }
+
+ if(profile_number == 0x14) { /* DVD-RW sequential */
+ /* ok */;
+ } else if(profile_number == 0x13) { /* DVD-RW restricted overwrite */
+ if(!(skin->force_is_set || ((skin->blank_format_type>>8)&4))) {
+ fprintf(stderr,
+ "cdrskin: NOTE : blank=format_... : media is already formatted\n");
+ fprintf(stderr,
+ "cdrskin: HINT : If you really want to re-format, add option -force\n");
+ {ret= 2; goto ex;}
+ }
+ } else if(profile_number == 0x1a) { /* DVD+RW */
+ if(!((skin->blank_format_type>>8)&4)) {
+ fprintf(stderr,
+ "cdrskin: NOTE : blank=format_... : DVD+RW do not need this\n");
+ fprintf(stderr,
+ "cdrskin: HINT : For de-icing use option blank=format_overwrite_full\n");
+ {ret= 2; goto ex;}
+ }
+ } else {
+ fprintf(stderr,
+ "cdrskin: SORRY : blank=%s for now does DVD-RW and DVD+RW only\n",
+ fmt_text);
+ {ret= 0; goto ex;}
+ }
+ if(s==BURN_DISC_UNSUITABLE)
+ fprintf(stderr,
+ "cdrskin: NOTE : blank=%s accepted not yet suitable media\n",
+ fmt_text);
+
+ } else if(do_format==4) {
+ /* Formatting and influencing defect management of DVD-RAM , BD-RE */
+ if(!(profile_number == 0x12 || profile_number == 0x41 ||
+ profile_number == 0x43)) {
+ fprintf(stderr,
+ "cdrskin: SORRY : blank=%s for now does DVD-RAM and BD only\n",
+ fmt_text);
+ {ret= 0; goto ex;}
+ }
+ if(s==BURN_DISC_UNSUITABLE)
+ fprintf(stderr,
+ "cdrskin: NOTE : blank=%s accepted not yet suitable media\n",
+ fmt_text);
+
+ } else if(do_format==0) {
+ /* Classical blanking of erasable media */
+
+ if(skin->grow_overwriteable_iso>0 && skin->media_is_overwriteable) {
+pseudo_blank_ov:;
+ if(skin->dummy_mode) {
+ fprintf(stderr,
+ "cdrskin: would have begun to pseudo-blank disc if not in -dummy mode\n");
+ goto blanking_done;
+ }
+ skin->grow_overwriteable_iso= 3;
+ ret= Cdrskin_invalidate_iso_head(skin, 0);
+ if(ret<=0)
+ goto ex;
+ goto blanking_done;
+ } else if(s!=BURN_DISC_FULL &&
+ (s!=BURN_DISC_APPENDABLE || skin->no_blank_appendable) &&
+ (profile_number!=0x13 || !skin->prodvd_cli_compatible) &&
+ (s!=BURN_DISC_BLANK || !skin->force_is_set)) {
+ if(s==BURN_DISC_BLANK) {
+ fprintf(stderr,
+ "cdrskin: NOTE : blank=... : media was already blank (and still is)\n");
+ {ret= 2; goto ex;}
+ } else if(s==BURN_DISC_APPENDABLE) {
+ fprintf(stderr,
+ "cdrskin: FATAL : blank=... : media is still appendable\n");
+ } else {
+ fprintf(stderr,
+ "cdrskin: FATAL : blank=... : no blankworthy disc found\n");
+ if(hint_force)
+ fprintf(stderr,
+ "cdrskin: HINT : If you are certain to have a CD-RW, try option -force\n");
+ }
+ {ret= 0; goto ex;}
+ }
+ if(!burn_disc_erasable(drive)) {
+ fprintf(stderr,"cdrskin: FATAL : blank=... : media is not erasable\n");
+ {ret= 0; goto ex;}
+ }
+ if((profile_number == 0x14 || profile_number == 0x13) &&
+ !skin->prodvd_cli_compatible)
+ skin->blank_fast= 0; /* only with deformat_sequential_quickest */
+
+ } else {
+unsupported_format_type:;
+ fprintf(stderr,
+ "cdrskin: SORRY : blank=%s is unsupported with media type %s\n",
+ fmt_text, profile_name);
+ {ret= 0; goto ex;}
+ }
+
+ if(skin->dummy_mode) {
+ fprintf(stderr,
+ "cdrskin: would have begun to %s disc if not in -dummy mode\n",
+ verb);
+ goto blanking_done;
+ }
+ fprintf(stderr,"cdrskin: beginning to %s disc\n",verb);
+ Cdrskin_adjust_speed(skin,0);
+
+#ifndef Cdrskin_extra_leaN
+ Cdrskin_wait_before_action(skin,
+ 1+(do_format==1 || do_format==3 || do_format==4));
+#endif /* ! Cdrskin_extra_leaN */
+
+ if(Cdrskin__is_aborting(0))
+ {ret= 0; goto ex;}
+ using_immed= burn_drive_get_immed(drive);
+ skin->drive_is_busy= 1;
+ if(do_format==0 || do_format==2) {
+ burn_disc_erase(drive,skin->blank_fast);
+
+ } else if(do_format==1 || do_format==3 || do_format==4) {
+ format_flag= (skin->blank_format_type>>8)&(1|2|4|32|128);
+ if(skin->force_is_set)
+ format_flag|= 16;
+ if(format_flag&128)
+ format_flag|= (skin->blank_format_index&255)<<8;
+ if(skin->blank_format_no_certify)
+ format_flag|= 64;
+ burn_disc_format(drive,(off_t) skin->blank_format_size,format_flag);
+
+ } else {
+ fprintf(stderr,"cdrskin: SORRY : Format type %d not implemented yet.\n",
+ do_format);
+ ret= 0; goto ex;
+ }
+
+ loop_counter= 0;
+ start_time= Sfile_microtime(0);
+ if(!using_immed)
+ sprintf(progress_text, "synchronous");
+ while(burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
+ if(loop_counter>0)
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ double percent= 50.0;
+
+ if(p.sectors>0) /* i want a display of 1 to 99 percent */
+ percent= 1.0+((double) p.sector+1.0)/((double) p.sectors)*98.0;
+ if(using_immed)
+ sprintf(progress_text, "done %.1f%%", percent);
+ fprintf(stderr,
+ "%scdrskin: %s ( %s , %lu seconds elapsed ) %s",
+ skin->pacifier_with_newline ? "" : "\r",
+ presperf,
+ progress_text,
+ (unsigned long) (Sfile_microtime(0)-start_time),
+ skin->pacifier_with_newline ? "\n" : "");
+ }
+ sleep(1);
+ loop_counter++;
+ }
+blanking_done:;
+ wrote_well = burn_drive_wrote_well(drive);
+ if(wrote_well && skin->verbosity>=Cdrskin_verbose_progresS) {
+ fprintf(stderr,
+ "%scdrskin: %s done \n",
+ skin->pacifier_with_newline ? "" : "\r", presperf);
+ printf("%s time: %.3fs\n",
+ (do_format==1 || do_format==3 || do_format==4 ?
+ "Formatting":"Blanking"),
+ Sfile_microtime(0)-start_time);
+ }
+ fflush(stdout);
+ if(!wrote_well)
+ fprintf(stderr,
+ "%scdrskin: %s failed \n",
+ skin->pacifier_with_newline ? "" : "\r", presperf);
+ ret= !!(wrote_well);
+ex:;
+ skin->drive_is_busy= 0;
+ if(Cdrskin__is_aborting(0))
+ Cdrskin_abort(skin, 0); /* Never comes back */
+ return(ret);
+}
+
+
+int Cdrskin__libburn_fifo_status(struct burn_source *current_fifo,
+ char fifo_text[80], int flag)
+{
+ int ret, size, free_space, fill, fifo_percent;
+ char *status_text= "";
+
+ ret= burn_fifo_inquire_status(current_fifo, &size, &free_space,
+ &status_text);
+ if(ret <= 0 || ret >= 4) {
+ strcpy(fifo_text, "(fifo 0%) ");
+ } else if(ret == 1) {
+ burn_fifo_next_interval(current_fifo, &fill);
+ fifo_percent= 100.0 * ((double) fill) / (double) size;
+ if(fifo_percent<100 && fill>0)
+ fifo_percent++;
+ sprintf(fifo_text, "(fifo %3d%%) ", fifo_percent);
+ }
+ return(1);
+}
+
+
+/** Report burn progress. This is done partially in cdrecord style.
+ Actual reporting happens only if write progress hit the next MB or if in
+ non-write-progress states a second has elapsed since the last report.
+ After an actual report a new statistics interval begins.
+ @param drive_status As obtained from burn_drive_get_status()
+ @param p Progress information from burn_drive_get_status()
+ @param start_time Timestamp of burn start in seconds
+ @param last_time Timestamp of report interval start in seconds
+ @param total_count Returns the total number of bytes written so far
+ @param total_count Returns the number of bytes written during interval
+ @param flag Bitfield for control purposes:
+ bit0= report in growisofs style rather than cdrecord style
+ @return <=0 error, 1 seems to be writing payload, 2 doing something else
+*/
+int Cdrskin_burn_pacifier(struct CdrskiN *skin, int start_tno,
+ enum burn_drive_status drive_status,
+ struct burn_progress *p,
+ double start_time, double *last_time,
+ double *total_count, double *last_count,
+ int *min_buffer_fill, int flag)
+/*
+ bit0= growisofs style
+*/
+{
+ double bytes_to_write= 0.0;
+ double written_bytes= 0.0,written_total_bytes= 0.0;
+ double fixed_size= 0.0, padding,sector_size,speed_factor;
+ double measured_total_speed,measured_speed;
+ double elapsed_time,elapsed_total_time,current_time;
+ double estim_time,estim_minutes,estim_seconds,percent;
+ int ret,fifo_percent,fill,advance_interval=0,new_mb,old_mb,time_to_tell;
+ int old_track_idx,buffer_fill,formatting= 0,use_data_image_size;
+ char fifo_text[80],mb_text[40], pending[40];
+ char *debug_mark= ""; /* use this to prepend a marker text for experiments */
+
+#ifndef Cdrskin_no_cdrfifO
+ double buffer_size;
+ int fs, bs, space;
+#endif
+
+#ifdef Cdrskin_use_libburn_fifO
+ struct burn_source *current_fifo= NULL;
+
+#ifdef NIX
+ int size, free_space;
+ char *status_text= "";
+#endif
+
+#endif /* Cdrskin_use_libburn_fifO */
+
+ /* for debugging */
+ static double last_fifo_in= 0.0,last_fifo_out= 0.0,curr_fifo_in,curr_fifo_out;
+
+ if(Cdrskin__is_aborting(0))
+ Cdrskin_abort(skin, 0); /* Never comes back */
+
+ current_time= Sfile_microtime(0);
+ elapsed_total_time= current_time-start_time;
+ elapsed_time= current_time-*last_time;
+ time_to_tell= (elapsed_time>=1.0)&&(elapsed_total_time>=1.0);
+ written_total_bytes= *last_count; /* to be overwritten by p.sector */
+
+ if(drive_status==BURN_DRIVE_FORMATTING)
+ formatting= 1;
+ if(drive_status==BURN_DRIVE_WRITING) {
+ ;
+ } else if(drive_status==BURN_DRIVE_WRITING_LEADIN
+ || drive_status==BURN_DRIVE_WRITING_PREGAP
+ || formatting) {
+ if(time_to_tell || skin->is_writing) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(skin->is_writing)
+ fprintf(stderr,"\n");
+ fprintf(stderr,
+ "%scdrskin: %s (burning since %.f seconds)%s",
+ skin->pacifier_with_newline ? "" : "\r",
+ (formatting?"formatting":"working pre-track"), elapsed_total_time,
+ skin->pacifier_with_newline ? "\n" : " ");
+ }
+ skin->is_writing= 0;
+ advance_interval= 1;
+ }
+ {ret= 2; goto ex;}
+ } else if(drive_status==BURN_DRIVE_WRITING_LEADOUT
+ || drive_status==BURN_DRIVE_CLOSING_TRACK
+ || drive_status==BURN_DRIVE_CLOSING_SESSION) {
+
+ if(drive_status==BURN_DRIVE_CLOSING_SESSION &&
+ skin->previous_drive_status!=drive_status)
+ {printf("\nFixating...\n"); fflush(stdout);}
+ if(time_to_tell || skin->is_writing) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(skin->is_writing && !skin->pacifier_with_newline)
+ fprintf(stderr,"\n");
+ fprintf(stderr,
+ "%scdrskin: working post-track (burning since %.f seconds)%s",
+ skin->pacifier_with_newline ? "" : "\r", elapsed_total_time,
+ skin->pacifier_with_newline ? "\n" : " ");
+ }
+ skin->is_writing= 0;
+ advance_interval= 1;
+ }
+ {ret= 2; goto ex;}
+ } else
+ goto thank_you_for_patience;
+
+ old_track_idx= skin->supposed_track_idx;
+ skin->supposed_track_idx= p->track;
+
+ if(old_track_idx>=0 && old_track_idxsupposed_track_idx &&
+ skin->supposed_track_idx < skin->track_counter) {
+ Cdrtrack_get_size(skin->tracklist[old_track_idx],&fixed_size,&padding,
+ §or_size,&use_data_image_size,1);
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ printf("\n");
+ printf("%sTrack %-2.2d: Total bytes read/written: %.f/%.f (%.f sectors).\n",
+ debug_mark, old_track_idx + start_tno, fixed_size,fixed_size+padding,
+ (fixed_size+padding)/sector_size);
+ *last_count= 0;
+ }
+
+ sector_size= 2048.0;
+ if(skin->supposed_track_idx>=0 &&
+ skin->supposed_track_idxtrack_counter)
+ Cdrtrack_get_size(skin->tracklist[skin->supposed_track_idx],&fixed_size,
+ &padding,§or_size,&use_data_image_size,0);
+
+ bytes_to_write= ((double) p->sectors)*sector_size;
+ written_total_bytes= ((double) p->sector)*sector_size;
+ written_bytes= written_total_bytes-*last_count;
+ if(written_total_bytes<1024*1024) {
+thank_you_for_patience:;
+ if(time_to_tell || (skin->is_writing && elapsed_total_time>=1.0)) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(skin->is_writing) {
+ fprintf(stderr,"\n");
+ }
+ pending[0]= 0;
+/*
+ if(bytes_to_write > 0 && skin->verbosity >= Cdrskin_verbose_debuG)
+ sprintf(pending, " pnd %.f", bytes_to_write - written_total_bytes);
+*/
+ fprintf(stderr,
+ "%scdrskin: thank you for being patient for %.f seconds%21.21s%s",
+ skin->pacifier_with_newline ? "" : "\r",
+ elapsed_total_time, pending,
+ skin->pacifier_with_newline ? "\n" : "");
+ }
+ advance_interval= 1;
+ }
+ skin->is_writing= 0;
+ {ret= 2; goto ex;}
+ }
+ new_mb= written_total_bytes/(1024*1024);
+ old_mb= (*last_count)/(1024*1024);
+ if(new_mb==old_mb && !(written_total_bytes>=skin->fixed_size &&
+ skin->fixed_size>0 && time_to_tell))
+ {ret= 1; goto ex;}
+
+
+#ifndef Cdrskin_extra_leaN
+
+ percent= 0.0;
+ if(bytes_to_write>0)
+ percent= written_total_bytes/bytes_to_write*100.0;
+ measured_total_speed= 0.0;
+ measured_speed= 0.0;
+ estim_time= -1.0;
+ estim_minutes= -1.0;
+ estim_seconds= -1.0;
+ if(elapsed_total_time>0.0) {
+ measured_total_speed= written_total_bytes/elapsed_total_time;
+ estim_time= (bytes_to_write-written_bytes)/measured_total_speed;
+ if(estim_time>0.0 && estim_time<86400.0) {
+ estim_minutes= ((int) estim_time)/60;
+ estim_seconds= estim_time-estim_minutes*60.0;
+ if(estim_seconds<0.0)
+ estim_seconds= 0.0;
+ }
+ }
+ if(written_bytes==written_total_bytes && elapsed_total_time>0) {
+ measured_speed= measured_total_speed;
+ } else if(elapsed_time>0.0) {
+ measured_speed= written_bytes/elapsed_time;
+ } else if(written_bytes>0.0) {
+ measured_speed= 99.91*Cdrskin_speed_factoR;
+ }
+
+ if(measured_speed<=0.0 && written_total_bytes>=skin->fixed_size &&
+ skin->fixed_size>0) {
+ if(!skin->is_writing)
+ goto thank_you_for_patience;
+ skin->is_writing= 0;
+ measured_speed= measured_total_speed;
+ } else
+ skin->is_writing= 1;
+ if(skin->supposed_track_idx<0)
+ skin->supposed_track_idx= 0;
+ if(*last_count <= 0.0 && !skin->pacifier_with_newline)
+ printf("\r%-78.78s\r", ""); /* wipe output line */
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(flag&1) {
+ printf("%.f/%.f (%2.1f%%) @%1.1f, remaining %.f:%2.2d\n",
+ written_total_bytes,bytes_to_write,percent,
+ measured_speed/Cdrskin_speed_factoR,
+ estim_minutes,(int) estim_seconds);
+ } else {
+ fill= 0;
+ fifo_percent= 50;
+ fifo_text[0]= 0;
+ curr_fifo_in= last_fifo_in;
+ curr_fifo_out= last_fifo_out;
+
+ if(skin->cuefile_fifo != NULL)
+ Cdrskin__libburn_fifo_status(skin->cuefile_fifo, fifo_text, 0);
+
+#ifdef Cdrskin_use_libburn_fifO
+
+ /* Inquire fifo fill and format fifo pacifier text */
+ if(skin->fifo == NULL && skin->supposed_track_idx >= 0 &&
+ skin->supposed_track_idx < skin->track_counter &&
+ skin->fifo_size > 0 && fifo_text[0] == 0) {
+ Cdrtrack_get_libburn_fifo(skin->tracklist[skin->supposed_track_idx],
+ ¤t_fifo, 0);
+ if(current_fifo != NULL) {
+ Cdrskin__libburn_fifo_status(current_fifo, fifo_text, 0);
+ } else if(skin->fifo_size > 0) {
+ strcpy(fifo_text, "(fifo 100%) ");
+ }
+ }
+
+#endif /* Cdrskin_use_libburn_fifO */
+
+#ifndef Cdrskin_no_cdrfifO
+
+ if(skin->fifo!=NULL) {
+ ret= Cdrfifo_get_buffer_state(skin->fifo,&fill,&space,0);
+ buffer_size= fill+space;
+ if(ret==2 || ret==0) {
+ fifo_percent= 100;
+ } else if(ret>0 && buffer_size>0.0) {
+ /* obtain minimum fill of pacifier interval */
+ Cdrfifo_next_interval(skin->fifo,&fill,0);
+ fifo_percent= 100.0*((double) fill)/buffer_size;
+ if(fifo_percent<100 && fill>0)
+ fifo_percent++;
+ }
+ if(skin->verbosity>=Cdrskin_verbose_debuG) {
+ Cdrfifo_get_counters(skin->fifo,&curr_fifo_in,&curr_fifo_out,0);
+ Cdrfifo_get_sizes(skin->fifo,&bs,&fs,0);
+ }
+ if(skin->fifo_size>0) {
+ sprintf(fifo_text,"(fifo %3d%%) ",fifo_percent);
+ if(skin->verbosity>=Cdrskin_verbose_debug_fifO) {
+ fprintf(stderr,
+ "\ncdrskin_debug: fifo >= %9d / %d : %8.f in, %8.f out\n",
+ fill,(int) buffer_size,
+ curr_fifo_in-last_fifo_in,curr_fifo_out-last_fifo_out);
+ last_fifo_in= curr_fifo_in;
+ last_fifo_out= curr_fifo_out;
+ }
+ }
+ }
+
+#endif /* ! Cdrskin_no_cdrfifO */
+
+ if(skin->supposed_track_idx >= 0 &&
+ skin->supposed_track_idx < skin->track_counter) {
+ /* fixed_size,padding are fetched above via Cdrtrack_get_size() */;
+ } else if(skin->fixed_size!=0) {
+ fixed_size= skin->fixed_size;
+ padding= skin->padding;
+ }
+ if(fixed_size || (skin->fill_up_media &&
+ skin->supposed_track_idx==skin->track_counter-1)) {
+ sprintf(mb_text,"%4d of %4d",(int) (written_total_bytes/1024.0/1024.0),
+ (int) ((double) Cdrtrack_get_sectors(
+ skin->tracklist[skin->supposed_track_idx],0)*
+ sector_size/1024.0/1024.0));
+ } else
+ sprintf(mb_text,"%4d",(int) (written_total_bytes/1024.0/1024.0));
+ speed_factor= Cdrskin_speed_factoR*sector_size/2048;
+
+ buffer_fill= 50;
+ if(p->buffer_capacity>0)
+ buffer_fill= (double) (p->buffer_capacity - p->buffer_available)*100.0
+ / (double) p->buffer_capacity;
+
+ if(p->buffered_bytes > p->buffer_capacity)
+ if(buffer_fill < *min_buffer_fill)
+ *min_buffer_fill= buffer_fill;
+
+ printf("%s%sTrack %-2.2d: %s MB written %s[buf %3d%%] %4.1fx.%s",
+ skin->pacifier_with_newline ? "" : "\r",
+ debug_mark, skin->supposed_track_idx + start_tno, mb_text,
+ fifo_text, buffer_fill, measured_speed / speed_factor,
+ skin->pacifier_with_newline ? "\n" : "");
+ fflush(stdout);
+ }
+ if(skin->is_writing==0) {
+ printf("\n");
+ goto thank_you_for_patience;
+ }
+ }
+
+#else /* ! Cdrskin_extra_leaN */
+
+ if(skin->supposed_track_idx<0)
+ skin->supposed_track_idx= 0;
+ if(written_bytes<=0.0 && written_total_bytes>=skin->fixed_size &&
+ skin->fixed_size>0) {
+ if(!skin->is_writing)
+ goto thank_you_for_patience;
+ skin->is_writing= 0;
+ } else {
+ if((!skin->is_writing) && !skin->pacifier_with_newline)
+ printf("\n");
+ skin->is_writing= 1;
+ }
+ printf("%sTrack %-2.2d: %3d MB written %s",
+ skin->pacifier_with_newline ? "" : "\r",
+ skin->supposed_track_idx + start_tno,
+ (int) (written_total_bytes / 1024.0 / 1024.0),
+ skin->pacifier_with_newline ? "\n" : "");
+ if(skin->is_writing == 0 && !skin->pacifier_with_newline)
+ printf("\n");
+ fflush(stdout);
+
+#endif /* Cdrskin_extra_leaN */
+
+
+ advance_interval= 1;
+ ret= 1;
+ex:;
+ if(advance_interval) {
+ if(written_total_bytes>0)
+ *last_count= written_total_bytes;
+ else
+ *last_count= 0.0;
+ if(*last_count>*total_count)
+ *total_count= *last_count;
+ *last_time= current_time;
+ }
+ skin->previous_drive_status= drive_status;
+ return(ret);
+}
+
+
+/** After everything else about burn_write_opts and burn_disc is set up, this
+ call determines the effective write mode and checks whether the drive
+ promises to support it.
+*/
+int Cdrskin_activate_write_mode(struct CdrskiN *skin,
+ struct burn_write_opts *opts,
+ struct burn_disc *disc,
+ int flag)
+{
+ int profile_number= -1, ret, was_still_default= 0;
+ char profile_name[80], reasons[BURN_REASONS_LEN];
+ enum burn_disc_status s= BURN_DISC_UNGRABBED;
+ enum burn_write_types wt;
+
+ profile_name[0]= 0;
+ if(skin->grabbed_drive) {
+ burn_disc_get_profile(skin->grabbed_drive,&profile_number,profile_name);
+ s= burn_disc_get_status(skin->grabbed_drive);
+ }
+ if(strcmp(skin->preskin->write_mode_name,"DEFAULT")==0) {
+ was_still_default= 1;
+ wt= burn_write_opts_auto_write_type(opts, disc, reasons, 0);
+ if(wt==BURN_WRITE_NONE) {
+ if(strncmp(reasons,"MEDIA: ",7)==0)
+ ret= -1;
+ else
+ ret= 0;
+ goto report_failure;
+ }
+ skin->write_type= wt;
+
+#ifndef Cdrskin_disable_raw96R
+ if(wt==BURN_WRITE_RAW)
+ strcpy(skin->preskin->write_mode_name,"RAW/RAW96R");
+ else
+#endif /* ! Cdrskin_disable_raw96R */
+ if(wt==BURN_WRITE_TAO)
+ strcpy(skin->preskin->write_mode_name,"TAO");
+ else if(wt==BURN_WRITE_SAO)
+ strcpy(skin->preskin->write_mode_name,"SAO");
+ else
+ sprintf(skin->preskin->write_mode_name,"LIBBURN/%d", (int) wt);
+ }
+
+#ifndef Cdrskin_disable_raw96R
+ if(strcmp(skin->preskin->write_mode_name,"RAW/RAW96R")==0) {
+ skin->write_type= BURN_WRITE_RAW;
+ skin->block_type= BURN_BLOCK_RAW96R;
+ } else
+#endif /* ! Cdrskin_disable_raw96R */
+
+ if(strcmp(skin->preskin->write_mode_name,"TAO")==0) {
+ skin->write_type= BURN_WRITE_TAO;
+ skin->block_type= BURN_BLOCK_MODE1;
+ } else if(strncmp(skin->preskin->write_mode_name,"LIBBURN/",8)==0) {
+ skin->block_type= BURN_BLOCK_MODE1;
+ } else {
+ strcpy(skin->preskin->write_mode_name,"SAO");
+ skin->write_type= BURN_WRITE_SAO;
+ skin->block_type= BURN_BLOCK_SAO;
+ /* cdrecord tolerates the combination of -sao and -multi. -multi wins. */
+ burn_write_opts_set_write_type(opts,skin->write_type,skin->block_type);
+ ret = burn_precheck_write(opts,disc,reasons,0);
+ if(ret <= 0) {
+ if(strstr(reasons, "multi session capability lacking") != NULL) {
+ fprintf(stderr,"cdrskin: WARNING : Cannot do SAO/DAO. Reason: %s\n",
+ reasons);
+ fprintf(stderr,"cdrskin: Defaulting to TAO/Incremental.\n");
+ skin->write_type= BURN_WRITE_TAO;
+ skin->block_type= BURN_BLOCK_MODE1;
+ }
+ }
+ }
+ if(!was_still_default)
+ burn_write_opts_set_write_type(opts,skin->write_type,skin->block_type);
+ ret = burn_precheck_write(opts,disc,reasons,0);
+ if(ret<=0) {
+report_failure:;
+ if(ret!=-1)
+ fprintf(stderr,"cdrskin: Reason: %s\n",reasons);
+ fprintf(stderr,"cdrskin: Media : %s%s\n",
+ s==BURN_DISC_BLANK?"blank ":
+ s==BURN_DISC_APPENDABLE?"appendable ":
+ s==BURN_DISC_FULL?"** closed ** ":"",
+ profile_name[0]?profile_name:
+ s==BURN_DISC_EMPTY?"no media":"unknown media");
+ return(0);
+ }
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ printf("cdrskin: Write type : %s\n", skin->preskin->write_mode_name);
+ return(1);
+}
+
+
+#ifndef Cdrskin_extra_leaN
+
+int Cdrskin_announce_tracks(struct CdrskiN *skin, int start_tno, int flag)
+{
+ int i,mb,use_data_image_size;
+ double size,padding,sector_size= 2048.0;
+ double sectors;
+
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(start_tno < 1)
+ start_tno= 1;
+ for(i=0;itrack_counter;i++) {
+ Cdrtrack_get_size(skin->tracklist[i],&size,&padding,§or_size,
+ &use_data_image_size,0);
+ if(size<=0) {
+ printf("Track %-2.2d: %s unknown length",
+ i + start_tno, (sector_size==2048?"data ":"audio"));
+ } else {
+ mb= size/1024.0/1024.0;
+ printf("Track %-2.2d: %s %4d MB ",
+ i + start_tno, (sector_size==2048?"data ":"audio"), mb);
+ }
+ if(padding>0)
+ printf(" padsize: %.f KB\n",padding/1024.0);
+ else
+ printf("\n");
+ }
+ if(skin->fixed_size<=0) {
+ printf("Total size: 0 MB (00:00.00) = 0 sectors\n");
+ printf("Lout start: 0 MB (00:02/00) = 0 sectors\n");
+ } else {
+ /* >>> This is quite a fake. Need to learn about 12:35.25 and "Lout"
+ ??? Is there a way to obtain the toc in advance (print_cue()) ? */
+ double seconds;
+ int min,sec,frac;
+
+ mb= skin->fixed_size/1024.0/1024.0;
+ seconds= skin->fixed_size/150.0/1024.0+2.0;
+ min= seconds/60.0;
+ sec= seconds-min*60;
+ frac= (seconds-min*60-sec)*100;
+ if(frac>99)
+ frac= 99;
+ sectors= (int) (skin->fixed_size/sector_size);
+ if(sectors*sector_size != skin->fixed_size)
+ sectors++;
+ printf("Total size: %5d MB (%-2.2d:%-2.2d.%-2.2d) = %d sectors\n",
+ mb,min,sec,frac,(int) sectors);
+ seconds+= 2;
+ min= seconds/60.0;
+ sec= seconds-min*60;
+ frac= (seconds-min*60-sec)*100;
+ if(frac>99)
+ frac= 99;
+ sectors+= 150;
+ printf("Lout start: %5d MB (%-2.2d:%-2.2d/%-2.2d) = %d sectors\n",
+ mb,min,sec,frac,(int) sectors);
+ }
+ }
+ return(1);
+}
+
+#endif /* ! Cdrskin_extra_leaN */
+
+
+int Cdrskin_direct_write(struct CdrskiN *skin, int flag)
+{
+ off_t byte_address, data_count, chunksize, i, alignment, fill;
+ int ret, max_chunksize= 64*1024, source_fd= -1, is_from_stdin, eof_sensed= 0;
+ int self_opened= 0;
+ char *buf= NULL, *source_path, amount_text[81];
+ struct burn_multi_caps *caps= NULL;
+
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ goto ex;
+
+ ret= burn_disc_get_multi_caps(skin->grabbed_drive,BURN_WRITE_NONE,&caps,0);
+ if(ret<=0)
+ goto ex;
+ if(caps->start_adr==0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Direct writing is not supported by drive and media\n");
+ {ret= 0; goto ex;}
+ }
+ alignment= caps->start_alignment;
+ if(alignment>0 && (((off_t) skin->direct_write_amount) % alignment)!=0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : direct_write_amount=%.f not aligned to blocks of %dk\n",
+ skin->direct_write_amount,(int) alignment/1024);
+ {ret= 0; goto ex;}
+ }
+
+ if(skin->track_counter<=0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : No track source given for direct writing\n");
+ {ret= 0; goto ex;}
+ }
+ Cdrtrack_get_source_path(skin->tracklist[0],
+ &source_path,&source_fd,&is_from_stdin,0);
+ if(source_fd==-1) {
+ ret= Cdrtrack_open_source_path(skin->tracklist[0],&source_fd,
+ 2 | (skin->verbosity >= Cdrskin_verbose_debuG) |
+ (4 * (skin->fifo_size >= 256 * 1024)));
+ if(ret<=0)
+ goto ex;
+ if(ret == 2)
+ self_opened= 1;
+ }
+ buf= calloc(1, max_chunksize);
+ if(buf==NULL) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Cannot allocate %d bytes of read buffer.\n",
+ max_chunksize);
+ {ret= -1; goto ex;}
+ }
+ byte_address= skin->write_start_address;
+ if(byte_address<0)
+ byte_address= 0;
+ data_count= skin->direct_write_amount;
+ if(data_count>0)
+ sprintf(amount_text,"%.fk",(double) (data_count/1024));
+ else
+ strcpy(amount_text,"0=open_ended");
+ fprintf(stderr,"Beginning direct write (start=%.fk,amount=%s) ...\n",
+ (double) (byte_address/1024),amount_text);
+ for(i= 0; i 0 ? alignment : 2048);
+ else
+ chunksize= data_count-i;
+ if(chunksize>max_chunksize)
+ chunksize= max_chunksize;
+
+ /* read buffer from first track */
+ for(fill= 0; fill0)
+ fprintf(stderr,"cdrskin: %s (errno=%d)\n", strerror(errno), errno);
+ ret= 0; goto ex;
+ } else if(ret==0) {
+ eof_sensed= 1;
+ if(data_count==0) {
+ memset(buf+fill,0,(size_t) (chunksize-fill));
+ break;
+ } else {
+ fprintf(stderr,
+ "cdrskin: FATAL : Premature EOF while reading from '%s'\n",
+ source_path);
+ ret= 0; goto ex;
+ }
+ }
+ }
+ ret= burn_random_access_write(skin->grabbed_drive,byte_address,
+ buf,chunksize,0);
+ if(ret<=0)
+ goto ex;
+ if(eof_sensed)
+ break;
+ byte_address+= chunksize;
+ fprintf(stderr, "%s%9.fk written %s",
+ skin->pacifier_with_newline ? "" : "\r",
+ ((double) (i+chunksize)) / 1024.0,
+ skin->pacifier_with_newline ? "\n" : "");
+ }
+ fprintf(stderr, "%s%9.fk written \n",
+ skin->pacifier_with_newline ? "" : "\r", ((double) i) / 1024.0);
+ /* flush drive buffer */
+ fprintf(stderr,"syncing cache ...\n");
+ ret = burn_random_access_write(skin->grabbed_drive,byte_address,buf,0,1);
+ if(ret<=0)
+ goto ex;
+ ret= 1;
+ex:;
+ if(caps!=NULL)
+ burn_disc_free_multi_caps(&caps);
+ if(buf!=NULL)
+ free(buf);
+ if(self_opened && source_fd >= 0)
+ close(source_fd);
+ if(ret>0)
+ fprintf(stderr,"writing done\n");
+ else
+ fprintf(stderr,"writing failed\n");
+ return(ret);
+}
+
+
+int Cdrskin_grow_overwriteable_iso(struct CdrskiN *skin, int flag)
+{
+ int ret, i, went_well= 1;
+ char *track_descr, *md;
+ unsigned char *td; /* Because the representation of 255 in char is ambigous */
+ double track_size, media_size;
+
+ ret= Cdrtrack_get_iso_fs_descr(skin->tracklist[0],&track_descr,&track_size,0);
+ if(ret<=0) {
+ fprintf(stderr,"cdrskin: SORRY : Saw no ISO-9660 filesystem in track 0\n");
+ return(ret);
+ }
+ if(skin->grow_overwriteable_iso==3) /* initial session */
+ return(1);
+ if(skin->grow_overwriteable_iso!=2) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Could not read ISO-9660 descriptors from media\n");
+ return(0);
+ }
+ ret= Scan_for_iso_size((unsigned char *) skin->overwriteable_iso_head+16*2048,
+ &media_size, 0);
+ if(ret<=0) {
+ fprintf(stderr,"cdrskin: SORRY : No recognizable ISO-9660 on media\n");
+ return(0);
+ }
+ if(skin->write_start_address>=0.0)
+ media_size= skin->write_start_address;
+
+ /* Write new sum into media descr 0 */
+ md= skin->overwriteable_iso_head+16*2048;
+ memcpy(md,track_descr,2048);
+ Set_descr_iso_size((unsigned char *) md,track_size+media_size,0);
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: new ISO-9660 size : %.f (%fs)\n",
+ track_size+media_size, (track_size+media_size)/2048));
+
+ /* Copy type 255 CD001 descriptors from track to media descriptor buffer
+ and adjust their size entries */
+ for(i=1; i<16; i++) {
+ td= (unsigned char *) (track_descr + i * 2048);
+ md= skin->overwriteable_iso_head+(16+i)*2048;
+ if(td[0] != 255)
+ break;
+ /* demand media descrN[0] == track descrN[0] */
+ if(((char *) td)[0] != md[0]) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Type mismatch of ISO volume descriptor #%d (%u <-> %u)\n",
+ i, ((unsigned int) td[0]) & 0xff, ((unsigned int) md[0])&0xff);
+ went_well= 0;
+ }
+ memcpy(md,td,2048);
+ Set_descr_iso_size((unsigned char *) md,track_size+media_size,0);
+ }
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: copied %d secondary ISO descriptors\n",
+ i-1));
+
+ /* write block 16 to 31 to media */
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: writing to media: blocks 16 to 31\n"));
+ ret= burn_random_access_write(skin->grabbed_drive, (off_t) (16*2048),
+ skin->overwriteable_iso_head+16*2048,
+ (off_t) (16*2048), 1);
+ if(ret<=0)
+ return(ret);
+
+ return(went_well);
+}
+
+
+int Cdrskin_cdtext_test(struct CdrskiN *skin, struct burn_write_opts *o,
+ struct burn_session *session, int flag)
+{
+ int ret, num_packs;
+ unsigned char *text_packs = NULL;
+
+ if(skin->num_text_packs > 0) {
+ Cdrskin_print_text_packs(skin, skin->text_packs, skin->num_text_packs, 2);
+ ret= 1; goto ex;
+ }
+ ret= burn_cdtext_from_session(session, &text_packs, &num_packs, 0);
+ if(ret < 0)
+ goto ex;
+ if(ret > 0) {
+ Cdrskin_print_text_packs(skin, text_packs, num_packs, 1);
+ ret= 1; goto ex;
+ }
+ ret= 1;
+ex:
+ if (text_packs != NULL)
+ free(text_packs);
+ return(ret);
+}
+
+
+int Cdrskin_read_input_sheet_v07t(struct CdrskiN *skin, char *path, int block,
+ struct burn_session *session, int flag)
+{
+ int ret= 0;
+
+ ret= burn_session_input_sheet_v07t(session, path, block, 1);
+ return(ret);
+}
+
+
+int Cdrskin_cdrtracks_from_session(struct CdrskiN *skin,
+ struct burn_session *session, int flag)
+{
+ int ret, num_tracks, i;
+ struct burn_track **tracks;
+ struct CdrtracK *t;
+ double sectors;
+
+ for(i= 0; i < skin->track_counter; i++)
+ Cdrtrack_destroy(&(skin->tracklist[i]), 0);
+ skin->track_counter= 0;
+
+ tracks= burn_session_get_tracks(session, &num_tracks);
+ if(num_tracks <= 0) {
+ fprintf(stderr, "cdrskin: SORRY : No tracks defined for burn run.\n");
+ ret= 0; goto ex;
+ }
+ for(i= 0; i < num_tracks; i++) {
+ /* Create Cdrtrack without reading parameters from skin */
+ ret= Cdrtrack_new(&(skin->tracklist[skin->track_counter]), skin,
+ skin->track_counter, 1);
+ if(ret <= 0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Creation of track control object failed.\n");
+ goto ex;
+ }
+
+ /* Set essential properties */
+ t= skin->tracklist[skin->track_counter];
+ t->track_type= burn_track_get_mode(tracks[i]);
+ if(t->track_type & BURN_AUDIO) {
+ t->sector_size= 2352;
+ t->track_type= BURN_AUDIO;
+ } else {
+ t->sector_size= 2048;
+ t->track_type= BURN_MODE1;
+ }
+ sectors= burn_track_get_sectors(tracks[i]);
+ t->fixed_size= sectors * t->sector_size;
+ t->libburn_track= tracks[i];
+ t->libburn_track_is_own= 0;
+
+ skin->track_counter++;
+ }
+ ret= 1;
+ex:
+ if(ret <= 0) {
+ for(i= 0; i < skin->track_counter; i++)
+ Cdrtrack_destroy(&(skin->tracklist[i]), 0);
+ skin->track_counter= 0;
+ }
+ return(ret);
+}
+
+
+int Cdrskin_write_result_string(struct CdrskiN *skin, char *msg, int flag)
+{
+ int ret;
+
+ if(skin->preskin->result_fd < 0) {
+ printf("%s",msg);
+ return(1);
+ }
+ ret= write(skin->preskin->result_fd, msg, strlen(msg));
+ if(ret != (int) strlen(msg))
+ return(0);
+ return(1);
+}
+
+
+/** Burn data via libburn according to the parameters set in skin.
+ @return <=0 error, 1 success
+*/
+int Cdrskin_burn(struct CdrskiN *skin, int flag)
+{
+ struct burn_disc *disc = NULL;
+ struct burn_session *session = NULL;
+ struct burn_write_opts *o = NULL;
+ struct burn_source *cuefile_fifo= NULL;
+ enum burn_disc_status s;
+ enum burn_drive_status drive_status;
+ struct burn_progress p;
+ struct burn_drive *drive;
+ int ret,loop_counter= 0,max_track= -1,i,hflag,nwa,num, wrote_well= 2;
+ int fifo_disabled= 0, min_buffer_fill= 101, length, start_tno= 1;
+ int use_data_image_size, needs_early_fifo_fill= 0,iso_size= -1, non_audio= 0;
+ double start_time,last_time;
+ double total_count= 0.0,last_count= 0.0,size,padding,sector_size= 2048.0;
+ char *doing;
+ char *source_path;
+ unsigned char *payload;
+ int source_fd, is_from_stdin;
+ int text_flag= 4; /* Check CRCs and silently repair CRCs if all are 0 */
+ unsigned char *text_packs= NULL;
+ int num_packs= 0, start_block, block_no;
+
+#ifndef Cdrskin_no_cdrfifO
+ double put_counter, get_counter, empty_counter, full_counter;
+ int total_min_fill, fifo_percent;
+#endif
+ off_t free_space;
+ char msg[80];
+
+ if(skin->tell_media_space)
+ doing= "estimating";
+ else
+ doing= "burning";
+ printf("cdrskin: beginning to %s disc\n",
+ skin->tell_media_space?"estimate":"burn");
+ if(skin->fill_up_media && skin->multi) {
+ ClN(fprintf(stderr,
+ "cdrskin: NOTE : Option --fill_up_media disabled option -multi\n"));
+ skin->multi= 0;
+ }
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ goto burn_failed;
+ drive= skin->drives[skin->driveno].drive;
+ s= burn_disc_get_status(drive);
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ Cdrskin_report_disc_status(skin,s,1);
+
+ disc= burn_disc_create();
+ session= burn_session_create();
+ ret= burn_disc_add_session(disc,session,BURN_POS_END);
+ if(ret==0) {
+ fprintf(stderr,"cdrskin: FATAL : Cannot add session to disc object.\n");
+burn_failed:;
+ ret= 0; goto ex;
+ }
+ skin->fixed_size= 0.0;
+ skin->has_open_ended_track= 0;
+ if(skin->cuefile[0]) {
+ if(skin->track_counter > 0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Option cuefile= cannot be combined with track sources\n");
+ goto burn_failed;
+ }
+ if(strcmp(skin->preskin->write_mode_name, "SAO") != 0 &&
+ strcmp(skin->preskin->write_mode_name, "DEFAULT") != 0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Option cuefile= works only with write mode SAO");
+ goto burn_failed;
+ }
+ strcpy(skin->preskin->write_mode_name, "SAO");
+
+ ret= burn_session_by_cue_file(session, skin->cuefile, skin->fifo_size,
+ &cuefile_fifo,
+ &text_packs, &num_packs, !skin->use_cdtext);
+ if(ret <= 0)
+ goto burn_failed;
+ if(num_packs > 0) {
+ if(skin->num_text_packs > 0) {
+ fprintf(stderr, "cdrskin: WARNING : Option textfile= overrides CDTEXTFILE from option cuesheet=\n");
+ if(text_packs != NULL)
+ free(text_packs);
+ } else {
+ skin->text_packs= text_packs;
+ skin->num_text_packs= num_packs;
+ }
+ }
+ text_packs= NULL; /* Now either freed or attached */
+ ret= Cdrskin_cdrtracks_from_session(skin, session, 0);
+ if(ret <= 0)
+ goto burn_failed;
+ skin->cuefile_fifo= cuefile_fifo;
+ cuefile_fifo= NULL;
+
+ } else {
+ for(i=0;itrack_counter;i++) {
+ hflag= (skin->verbosity>=Cdrskin_verbose_debuG);
+ if(i==skin->track_counter-1)
+ Cdrtrack_ensure_padding(skin->tracklist[i],hflag&1);
+
+/* if(skin->fifo_size >= 256 * 1024) */
+
+ hflag|= 4;
+
+ ret= Cdrtrack_add_to_session(skin->tracklist[i],i,session,hflag);
+ if(ret<=0) {
+ fprintf(stderr,"cdrskin: FATAL : Cannot add track %d to session.\n",i+1);
+ goto burn_failed;
+ }
+ Cdrtrack_get_size(skin->tracklist[i],&size,&padding,§or_size,
+ &use_data_image_size,0);
+ if(use_data_image_size==1) {
+ /* still unfulfilled -isosize demand pending */
+ needs_early_fifo_fill= 1;
+ }
+ non_audio|= (skin->tracklist[i]->track_type != BURN_AUDIO);
+ }
+ }
+
+ if(skin->sheet_v07t_blocks > 0) {
+ if(skin->num_text_packs > 0) {
+ fprintf(stderr, "cdrskin: WARNING : Option textfile= or cuefile= overrides option input_sheet_v07t=\n");
+ } else if(non_audio) {
+ fprintf(stderr, "cdrskin: SORRY : Option input_sheet_v07t= works only if all tracks are -audio\n");
+ goto burn_failed;
+ } else {
+ /* If cuefile and session has block 0, then start at block 1 */
+ start_block= 0;
+ if(skin->cuefile[0]) {
+ for(i= 0x80; i < 0x8f; i++) {
+ ret= burn_session_get_cdtext(session, 0, i, "", &payload, &length, 0);
+ if(ret > 0 && length > 0)
+ break;
+ }
+ if(i < 0x8f)
+ start_block= 1;
+ }
+ block_no = start_block;
+ for(i= 0; i < skin->sheet_v07t_blocks && block_no < 8; i++) {
+ ret= Cdrskin_read_input_sheet_v07t(skin, skin->sheet_v07t_paths[i],
+ block_no, session, 0);
+ if(ret <= 0)
+ goto burn_failed;
+ block_no += ret;
+ }
+ if(i < skin->sheet_v07t_blocks) {
+ fprintf(stderr, "cdrskin: WARNING : Too many CD-TEXT blocks. input_sheet_v07t= files ignored: %d\n",
+ skin->sheet_v07t_blocks - i);
+ }
+ }
+ }
+
+#ifndef Cdrskin_extra_leaN
+ /* Final decision on track size has to be made after eventual -isosize
+ determination via fifo content.
+ */
+ if(needs_early_fifo_fill && !skin->tell_media_space) {
+ int start_memorized;
+
+ start_memorized= skin->fifo_start_at;
+ /* try ISO-9660 size recognition via fifo */
+ if(32*2048<=skin->fifo_size)
+ skin->fifo_start_at= 32*2048;
+ else
+ skin->fifo_start_at= skin->fifo_size;
+ ret= Cdrskin_fill_fifo(skin,0);
+ if(ret<=0)
+ goto fifo_filling_failed;
+ if((start_memorized>skin->fifo_start_at || start_memorized<=0) &&
+ skin->fifo_start_atfifo_size)
+ needs_early_fifo_fill= 2; /* continue filling fifo at normal stage */
+ skin->fifo_start_at= start_memorized;
+ }
+#endif /* Cdrskin_extra_leaN */
+
+ for(i=0;itrack_counter;i++) {
+ Cdrtrack_get_size(skin->tracklist[i],&size,&padding,§or_size,
+ &use_data_image_size,0);
+ if(use_data_image_size==1 && size<=0 && skin->tell_media_space)
+ size= 1024*1024; /* a dummy size */
+ ret= Cdrtrack_activate_image_size(skin->tracklist[i],&size,
+ !!skin->tell_media_space);
+ if(ret<=0) {
+ Cdrtrack_get_source_path(skin->tracklist[i],
+ &source_path,&source_fd,&is_from_stdin,0);
+ fprintf(stderr,
+ "cdrskin: FATAL : Cannot determine -isosize of track source\n");
+ fprintf(stderr,
+ "cdrskin: '%s'\n", source_path);
+ {ret= 0; goto ex;}
+ }
+ Cdrtrack_get_size(skin->tracklist[i],&size,&padding,§or_size,
+ &use_data_image_size,0);
+ if(use_data_image_size==2 && skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "cdrskin: DEBUG: track %2.2d : activated -isosize %.fs (= %.fb)\n",
+ i+1, size/2048.0,size));
+ if(size>0)
+ skin->fixed_size+= size+padding;
+ else
+ skin->has_open_ended_track= 1;
+ if(skin->tracklist[i]->isrc[0] &&
+ skin->tracklist[i]->libburn_track != NULL) {
+ ret= burn_track_set_isrc_string(skin->tracklist[i]->libburn_track,
+ skin->tracklist[i]->isrc, 0);
+ if(ret <= 0)
+ goto ex;
+ }
+ }
+
+ o= burn_write_opts_new(drive);
+ burn_write_opts_set_perform_opc(o, 0);
+
+/* growisofs stunt: assessment of media and start for next session */
+ if((skin->grow_overwriteable_iso==1 || skin->grow_overwriteable_iso==2) &&
+ skin->media_is_overwriteable) {
+ /* Obtain ISO size from media, keep 64 kB head in memory */
+ ret= Cdrskin_overwriteable_iso_size(skin,&iso_size,0);
+ if(ret<0)
+ goto ex;
+ if(ret>0 && skin->write_start_address<0) {
+ skin->write_start_address= ((double) iso_size)*2048.0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: write start address by --grow_overwriteable_iso : %ds\n",
+ iso_size));
+ } else if(ret==0)
+ skin->grow_overwriteable_iso= 3; /* do not patch ISO header later on */
+ }
+
+ burn_write_opts_set_start_byte(o, skin->write_start_address);
+
+ if(skin->media_is_overwriteable && skin->multi) {
+ if(skin->grow_overwriteable_iso<=0) {
+ fprintf(stderr, "cdrskin: FATAL : -multi cannot leave a recognizable end mark on this media.\n");
+ fprintf(stderr, "cdrskin: HINT : For ISO-9660 images try --grow_overwriteable_iso -multi\n");
+ {ret= 0; goto ex;}
+ }
+ skin->multi= 0;
+ }
+ if(skin->multi && !skin->media_does_multi) {
+ if(skin->prodvd_cli_compatible) {
+ skin->multi= 0;
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ fprintf(stderr, "cdrskin: NOTE : Ignored option -multi.\n");
+ }
+ }
+ burn_write_opts_set_multi(o,skin->multi);
+ burn_write_opts_set_fillup(o, skin->fill_up_media);
+
+ burn_write_opts_set_force(o, !!skin->force_is_set);
+ burn_write_opts_set_stream_recording(o, skin->stream_recording_is_set);
+
+#ifdef Cdrskin_dvd_obs_default_64K
+ if(skin->dvd_obs == 0)
+ burn_write_opts_set_dvd_obs(o, 64 * 1024);
+ else
+#endif
+ burn_write_opts_set_dvd_obs(o, skin->dvd_obs);
+ burn_write_opts_set_obs_pad(o, skin->obs_pad);
+ burn_write_opts_set_stdio_fsync(o, skin->stdio_sync);
+
+ if(skin->dummy_mode) {
+ fprintf(stderr,
+ "cdrskin: NOTE : -dummy mode will prevent actual writing\n");
+ burn_write_opts_set_simulate(o, 1);
+ }
+ burn_write_opts_set_underrun_proof(o,skin->burnfree);
+ if(skin->num_text_packs > 0) {
+ if(non_audio) {
+ fprintf(stderr, "cdrskin: SORRY : Option textfile= works only if all tracks are -audio\n");
+ goto burn_failed;
+ }
+ if(!!skin->force_is_set)
+ text_flag= 1; /* No CRC verification or repairing */
+ ret= burn_write_opts_set_leadin_text(o, skin->text_packs,
+ skin->num_text_packs, text_flag);
+ if(ret <= 0)
+ goto burn_failed;
+ }
+ if(skin->mcn[0]) {
+ burn_write_opts_set_mediacatalog(o, (unsigned char *) skin->mcn);
+ burn_write_opts_set_has_mediacatalog(o, 1);
+ }
+ if(skin->cd_start_tno >= 1 && skin->cd_start_tno <= 99) {
+ ret= burn_session_set_start_tno(session, skin->cd_start_tno, 0);
+ if(ret <= 0)
+ goto burn_failed;
+ }
+ ret= Cdrskin_activate_write_mode(skin,o,disc,0);
+ if(ret<=0)
+ goto burn_failed;
+
+ if(skin->cdtext_test) {
+ ret= Cdrskin_cdtext_test(skin, o, session, (skin->cdtext_test == 1));
+ if(ret <= 0)
+ goto ex;
+ if(skin->cdtext_test >= 2) {
+ fprintf(stderr,
+ "cdrskin: Option --cdtext_dummy prevents actual burn run\n");
+ ret= 1; goto ex;
+ }
+ }
+
+ ret= Cdrskin_obtain_nwa(skin, &nwa,0);
+ if(ret<=0)
+ nwa= -1;
+ if(skin->assert_write_lba>=0 && nwa!=skin->assert_write_lba) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Option assert_write_lba= demands block number %10d\n",
+ skin->assert_write_lba);
+ fprintf(stderr,
+ "cdrskin: FATAL : but predicted actual write start address is %10d\n",
+ nwa);
+ {ret= 0; goto ex;}
+ }
+
+#ifndef Cdrskin_extra_leaN
+ Cdrskin_announce_tracks(skin, burn_session_get_start_tno(session, 0), 0);
+#endif
+
+ if(skin->tell_media_space || skin->track_counter <= 0) {
+ /* write capacity estimation and return without actual burning */
+
+ free_space= burn_disc_available_space(drive,o);
+ sprintf(msg,"%d\n",(int) (free_space/(off_t) 2048));
+ Cdrskin_write_result_string(skin, msg, 0);
+ if(skin->track_counter>0)
+ fprintf(stderr,
+ "cdrskin: NOTE : %s burn run suppressed by option --tell_media_space\n",
+ skin->preskin->write_mode_name);
+ {ret= 1; goto ex;}
+ }
+
+ if(skin->fixed_size > 0 && !skin->force_is_set) {
+ free_space= burn_disc_available_space(drive,o);
+ if(skin->fixed_size > free_space && free_space > 0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : predicted session size %lus does not fit on media (%lus)\n",
+ (unsigned long) ((skin->fixed_size + 2047.0) / 2048.0),
+ (unsigned long) ((free_space + 2047) / 2048));
+ ClN(fprintf(stderr,
+ "cdrskin: HINT : This test may be disabled by option -force\n");)
+ {ret= 0; goto ex;}
+ }
+ }
+
+ Cdrskin_adjust_speed(skin,0);
+
+#ifndef Cdrskin_extra_leaN
+ Cdrskin_wait_before_action(skin,0);
+ if(burn_is_aborting(0))
+ {ret= 0; goto ex;}
+
+ if(needs_early_fifo_fill==1)
+ ret= 1;
+ else if(skin->cuefile[0] != 0)
+ ret= 1;
+ else
+ ret= Cdrskin_fill_fifo(skin,0);
+ if(ret<=0) {
+fifo_filling_failed:;
+ fprintf(stderr,"cdrskin: FATAL : Filling of fifo failed\n");
+ goto ex;
+ }
+
+#endif /* ! Cdrskin_extra_leaN */
+
+ start_tno = burn_session_get_start_tno(session, 0);
+ if(skin->verbosity>=Cdrskin_verbose_progresS && nwa>=0) {
+ printf("Starting new track at sector: %d\n",nwa);
+ fflush(stdout);
+ }
+ if(burn_is_aborting(0))
+ {ret= 0; goto ex;}
+ skin->drive_is_busy= 1;
+ burn_disc_write(o, disc);
+ if(skin->preskin->abort_handler==-1)
+ Cleanup_set_handlers(Cleanup_handler_handlE, Cleanup_handler_funC,
+ Cleanup_handler_flaG);
+ last_time= start_time= Sfile_microtime(0);
+
+ burn_write_opts_free(o);
+ o= NULL;
+
+ while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING) {
+
+ /* >>> how do i learn about success or failure ? */
+
+ ;
+ }
+ loop_counter= 0;
+ while (1) {
+ drive_status= burn_drive_get_status(drive, &p);
+ if(drive_status==BURN_DRIVE_IDLE)
+ break;
+
+ /* >>> how do i learn about success or failure ? */
+
+ if(loop_counter>0 || Cdrskin__is_aborting(0))
+ Cdrskin_burn_pacifier(skin, start_tno,
+ drive_status,&p,start_time,&last_time,
+ &total_count,&last_count,&min_buffer_fill,0);
+
+ if(max_tracksupposed_track_idx)
+ max_track= skin->supposed_track_idx;
+
+
+#ifndef Cdrskin_extra_leaN
+
+ /* <<< debugging : artificial abort without a previous signal */;
+ if(skin->abort_after_bytecount>=0.0 &&
+ total_count>=skin->abort_after_bytecount) {
+ /* whatever signal handling is installed: this thread is the boss now */
+ fprintf(stderr,
+ "cdrskin: DEVELOPMENT : synthetic abort by abort_after_bytecount=%.f\n",
+ skin->abort_after_bytecount);
+ skin->control_pid= getpid();
+ ret= Cdrskin_abort_handler(skin,0,0);
+ fprintf(stderr,"cdrskin: done (aborted)\n");
+ exit(1);
+ }
+
+ if(Cdrskin__is_aborting(0))
+ fifo_disabled= 1;
+ if(skin->fifo==NULL || fifo_disabled) {
+ usleep(20000);
+ } else {
+
+#ifdef Cdrskin_no_cdrfifO
+
+ /* Should never happen as skin->fifo should be NULL */
+ usleep(20000);
+
+#else /* Cdrskin_no_cdrfifO */
+
+ ret= Cdrfifo_try_to_work(skin->fifo,20000,NULL,NULL,0);
+ if(ret<0) {
+ int abh;
+
+ abh= skin->preskin->abort_handler;
+ if(abh!=2)
+ fprintf(stderr,
+ "\ncdrskin: FATAL : Fifo encountered error during burn loop.\n");
+ if(abh==0) {
+ ret= -1; goto ex;
+ } else if(abh==1 || abh==3 || abh==4 || abh==-1) {
+ Cdrskin_abort_handler(skin,0,0);
+ fprintf(stderr,"cdrskin: done (aborted)\n");
+ exit(10);
+ } else {
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ fprintf(stderr,
+ "\ncdrskin_debug: Cdrfifo_try_to_work() returns %d\n",ret);
+ }
+ }
+ if(ret==2) { /* <0 = error , 2 = work is done */
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ fprintf(stderr,"\ncdrskin_debug: fifo ended work with ret=%d\n",ret);
+ fifo_disabled= 1;
+ }
+
+#endif /* ! Cdrskin_no_cdrfifO */
+
+ }
+
+#else /* ! Cdrskin_extra_leaN */
+ usleep(20000);
+#endif /* Cdrskin_extra_leaN */
+
+ loop_counter++;
+ }
+ skin->drive_is_busy= 0;
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ printf("\n");
+
+ if(Cdrskin__is_aborting(0))
+ Cdrskin_abort(skin, 0); /* Never comes back */
+
+ wrote_well = burn_drive_wrote_well(drive);
+ if(skin->media_is_overwriteable && skin->grow_overwriteable_iso>0 &&
+ wrote_well) {
+ /* growisofs final stunt : update volume descriptors at start of media */
+ ret= Cdrskin_grow_overwriteable_iso(skin,0);
+ if(ret<=0)
+ wrote_well= 0;
+ }
+ if(max_track<0) {
+ printf("Track %-2.2d: Total bytes read/written: %.f/%.f (%.f sectors).\n",
+ start_tno, total_count, total_count, total_count / sector_size);
+ } else {
+ Cdrtrack_get_size(skin->tracklist[max_track],&size,&padding,§or_size,
+ &use_data_image_size,1);
+ if (start_tno <= 0)
+ start_tno = 1;
+ printf("Track %-2.2d: Total bytes read/written: %.f/%.f (%.f sectors).\n",
+ max_track + start_tno, size,size+padding,(size+padding)/sector_size);
+ }
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ printf("Writing time: %.3fs\n",Sfile_microtime(0)-start_time);
+
+
+#ifndef Cdrskin_extra_leaN
+
+#ifdef Cdrskin_use_libburn_fifO
+
+ if(skin->fifo == NULL && skin->verbosity>=Cdrskin_verbose_progresS) {
+ /* >>> this should rather be done for each track
+ (for now this libburn_fifo should only be used with single track)
+ */
+ Cdrtrack_report_fifo(skin->tracklist[skin->track_counter - 1], 0);
+ }
+
+#endif /* Cdrskin_use_libburn_fifO */
+
+#ifndef Cdrskin_no_cdrfifO
+
+ if(skin->fifo!=NULL && skin->fifo_size>0 && wrote_well) {
+ int dummy,final_fill;
+ Cdrfifo_get_buffer_state(skin->fifo,&final_fill,&dummy,0);
+ if(final_fill>0) {
+fifo_full_at_end:;
+ fprintf(stderr,
+ "cdrskin: FATAL : Fifo still contains data after burning has ended.\n");
+ fprintf(stderr,
+ "cdrskin: FATAL : %.d bytes left.\n",final_fill);
+ fprintf(stderr,
+ "cdrskin: FATAL : This indicates an overflow of the last track.\n");
+ fprintf(stderr,
+ "cdrskin: NOTE : The media might appear ok but is probably truncated.\n");
+ ret= -1; goto ex;
+ }
+
+#ifdef Cdrskin_libburn_leaves_inlet_opeN
+ for(i= 0;itrack_counter;i++) {
+ ret= Cdrtrack_has_input_left(skin->tracklist[i],0);
+ if(ret>0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Fifo outlet of track #%d is still buffering some bytes.\n",
+ i+1);
+ goto fifo_full_at_end;
+ }
+ }
+#endif /* Cdrskin_libburn_leaves_inlet_opeN */
+
+ }
+
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(skin->fifo!=NULL && skin->fifo_size>0) {
+ int dummy;
+
+ Cdrfifo_get_min_fill(skin->fifo,&total_min_fill,&dummy,0);
+ fifo_percent= 100.0*((double) total_min_fill)/(double) skin->fifo_size;
+ if(fifo_percent==0 && total_min_fill>0)
+ fifo_percent= 1;
+ Cdrfifo_get_cdr_counters(skin->fifo,&put_counter,&get_counter,
+ &empty_counter,&full_counter,0);
+ fflush(stdout);
+ fprintf(stderr,"Cdrskin: fifo had %.f puts and %.f gets.\n",
+ put_counter,get_counter);
+ fprintf(stderr,
+ "Cdrskin: fifo was %.f times empty and %.f times full, min fill was %d%%.\n",
+ empty_counter,full_counter,fifo_percent);
+ }
+ }
+
+#endif /* ! Cdrskin_no_cdrfifO */
+
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ drive_status= burn_drive_get_status(drive, &p);
+ if(p.buffer_min_fill<=p.buffer_capacity && p.buffer_capacity>0) {
+ num= 100.0 * ((double) p.buffer_min_fill)/(double) p.buffer_capacity;
+ if(num100)
+ min_buffer_fill= 50;
+ printf("Min drive buffer fill was %d%%\n", min_buffer_fill);
+ }
+
+#endif /* ! Cdrskin_extra_leaN */
+
+ ret= 1;
+ if(wrote_well) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ printf("cdrskin: burning done\n");
+ } else
+ ret= 0;
+ex:;
+ if(ret<=0) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ printf("cdrskin: %s failed\n",doing);
+ fprintf(stderr,"cdrskin: FATAL : %s failed.\n",doing);
+ }
+ skin->drive_is_busy= 0;
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(printf("cdrskin_debug: do_eject= %d\n",skin->do_eject));
+ for(i= 0;itrack_counter;i++)
+ Cdrtrack_cleanup(skin->tracklist[i],0);
+ if(o != NULL)
+ burn_write_opts_free(o);
+ if(cuefile_fifo != NULL)
+ burn_source_free(cuefile_fifo);
+ if(session != NULL)
+ burn_session_free(session);
+ if(disc != NULL)
+ burn_disc_free(disc);
+ return(ret);
+}
+
+
+#ifdef Libburn_develop_quality_scaN
+
+int Cdrskin_qcheck(struct CdrskiN *skin, int flag)
+{
+ struct burn_drive *drive;
+ int ret, rate_period, profile_number;
+ char profile_name[80];
+
+ printf("cdrskin: beginning to perform quality check on disc\n");
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+
+ ret= burn_disc_get_profile(drive, &profile_number, profile_name);
+ if(ret <= 0)
+ profile_number= 0;
+ if(profile_number != 0x08 && profile_number != 0x09 && profile_number != 0x0a)
+ rate_period= 8;
+ else
+ rate_period= 75;
+ if(skin->do_qcheck == 1) {
+ ret= burn_nec_optiarc_rep_err_rate(drive, 0, rate_period, 0);
+ if(ret<=0)
+ return(ret);
+ }
+ return(1);
+}
+
+#endif /* Libburn_develop_quality_scaN */
+
+
+/** Print lba of first track of last session and Next Writeable Address of
+ the next unwritten session.
+*/
+int Cdrskin_msinfo(struct CdrskiN *skin, int flag)
+{
+ int num_sessions, session_no, ret, num_tracks, open_sessions= 0;
+ int nwa= -123456789, lba= -123456789, aux_lba;
+ char msg[80];
+ enum burn_disc_status s;
+ struct burn_drive *drive;
+ struct burn_disc *disc= NULL;
+ struct burn_session **sessions= NULL;
+ struct burn_track **tracks;
+ struct burn_toc_entry toc_entry;
+
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+ s= burn_disc_get_status(drive);
+ if(s!=BURN_DISC_APPENDABLE) {
+ if(skin->grow_overwriteable_iso==1 || skin->grow_overwriteable_iso==2) {
+ lba= 0;
+ ret= Cdrskin_overwriteable_iso_size(skin,&nwa,0);
+ if(ret>0) {
+ s= BURN_DISC_APPENDABLE;
+ goto put_out;
+ }
+ }
+ Cdrskin_report_disc_status(skin,s,0);
+ fprintf(stderr,"cdrskin: FATAL : -msinfo can only operate on appendable (i.e. -multi) discs\n");
+ if(skin->grow_overwriteable_iso>0)
+ fprintf(stderr,"cdrskin: or on overwriteables with existing ISO-9660 file system.\n");
+ {ret= 0; goto ex;}
+ }
+ disc= burn_drive_get_disc(drive);
+ if(disc==NULL) {
+ /* No TOC available. Try to inquire directly. */
+ ret= burn_disc_get_msc1(drive,&lba);
+ if(ret>0)
+ goto obtain_nwa;
+ fprintf(stderr,"cdrskin: FATAL : Cannot obtain info about CD content\n");
+ {ret= 0; goto ex;}
+ }
+ sessions= burn_disc_get_sessions(disc,&num_sessions);
+ open_sessions= burn_disc_get_incomplete_sessions(disc);
+ for(session_no= 0; session_no < num_sessions + open_sessions; session_no++) {
+ tracks= burn_session_get_tracks(sessions[session_no],&num_tracks);
+ if(tracks==NULL || num_tracks<=0)
+ continue;
+ burn_track_get_entry(tracks[0],&toc_entry);
+ if(toc_entry.extensions_valid&1) { /* DVD extension valid */
+ if(session_no >= num_sessions) {
+ if(!(toc_entry.extensions_valid & 4))
+ continue; /* open session with no track status bits from libburn */
+ if((toc_entry.track_status_bits & (1 << 14)) ||
+ !((toc_entry.track_status_bits & (1 << 16)) ||
+ ((toc_entry.track_status_bits & (1 << 17)) &&
+ toc_entry.last_recorded_address > toc_entry.start_lba)))
+ continue; /* Blank or not appendable and not recorded */
+ }
+ lba= toc_entry.start_lba;
+ } else {
+ lba= burn_msf_to_lba(toc_entry.pmin,toc_entry.psec,toc_entry.pframe);
+ }
+ }
+ if(lba==-123456789) {
+ fprintf(stderr,"cdrskin: FATAL : Cannot find any track on CD\n");
+ {ret= 0; goto ex;}
+ }
+
+obtain_nwa:;
+ ret= Cdrskin_obtain_nwa(skin,&nwa,flag);
+ if(ret<=0) {
+ if (sessions == NULL) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Cannot obtain next writeable address\n");
+ {ret= 0; goto ex;}
+ }
+ ClN(fprintf(stderr,
+ "cdrskin: NOTE : Guessing next writeable address from leadout\n"));
+ burn_session_get_leadout_entry(sessions[num_sessions-1],&toc_entry);
+ if(toc_entry.extensions_valid&1) { /* DVD extension valid */
+ aux_lba= toc_entry.start_lba;
+ } else {
+ aux_lba= burn_msf_to_lba(toc_entry.pmin,toc_entry.psec,toc_entry.pframe);
+ }
+ if(num_sessions>0)
+ nwa= aux_lba+6900;
+ else
+ nwa= aux_lba+11400;
+ }
+
+put_out:;
+ sprintf(msg,"%d,%d\n",lba,nwa);
+ Cdrskin_write_result_string(skin, msg, 0);
+
+ if(strlen(skin->msifile)) {
+ FILE *fp;
+
+ fp = fopen(skin->msifile, "w");
+ if(fp==NULL) {
+ if(errno>0)
+ fprintf(stderr,"cdrskin: %s (errno=%d)\n", strerror(errno), errno);
+ fprintf(stderr,"cdrskin: FATAL : Cannot write msinfo to file '%s'\n",
+ skin->msifile);
+ {ret= 0; goto ex;}
+ }
+ fprintf(fp,"%d,%d",lba,nwa);
+ fclose(fp);
+ }
+ ret= 1;
+ex:;
+ if(disc!=NULL)
+ burn_disc_free(disc);
+ return(ret);
+}
+
+
+/** Work around the failure of libburn to eject the tray.
+ This employs a system(2) call and is therefore an absolute no-no for any
+ pseudo user identities.
+ @return <=0 error, 1 success
+*/
+int Cdrskin_eject(struct CdrskiN *skin, int flag)
+{
+ int i,ret,max_try= 5;
+
+ if(!skin->do_eject)
+ return(1);
+
+ if((int) skin->n_drives <= skin->driveno || skin->driveno < 0)
+ return(2);
+
+ /* ??? A61012 : retry loop might now be obsolete
+ (a matching bug in burn_disc_write_sync() was removed ) */
+ /* A61227 : A kindof race condition with -atip -eject on SuSE 9.3. Loop saved
+ me. Waiting seems to help. I suspect the media demon. */
+
+ for(i= 0;i0 || i>=max_try-1)
+ break;
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ ClN(fprintf(stderr,
+ "cdrskin: NOTE : Attempt #%d of %d failed to grab drive for eject\n",
+ i+1,max_try));
+ usleep(1000000);
+ }
+ if(ret>0) {
+ ret= Cdrskin_release_drive(skin,1);
+ if(ret<=0)
+ goto sorry_failed_to_eject;
+ } else {
+sorry_failed_to_eject:;
+ fprintf(stderr,"cdrskin: SORRY : Failed to finally eject tray.\n");
+ return(0);
+ }
+ return(1);
+}
+
+
+/** Interpret all arguments of the program after libburn has been initialized
+ and drives have been scanned. This call reports to stderr any valid
+ cdrecord options which are not implemented yet.
+ @param flag Bitfield for control purposes:
+ bit0= do not finalize setup
+ bit1= do not interpret (again) skin->preskin->pre_argv
+ @return <=0 error, 1 success
+*/
+int Cdrskin_setup(struct CdrskiN *skin, int argc, char **argv, int flag)
+{
+ int i,k,l,ret, idx= -1, cd_start_tno;
+ double value,grab_and_wait_value= -1.0, num;
+ char *cpt,*value_pt,adr[Cdrskin_adrleN],*blank_mode= "", *argpt;
+ struct stat stbuf;
+
+ /* cdrecord 2.01 options which are not scheduled for implementation, yet */
+ static char ignored_partial_options[][41]= {
+ "timeout=", "debug=", "kdebug=", "kd=", "driver=", "ts=",
+ "pregap=", "defpregap=",
+ "pktsize=",
+ ""
+ };
+ static char ignored_full_options[][41]= {
+ "-d", "-silent", "-s", "-setdropts", "-prcap",
+ "-reset", "-abort", "-overburn", "-ignsize", "-useinfo",
+ "-fix", "-nofix",
+ "-raw", "-raw96p", "-raw16", "-raw96r",
+ "-clone",
+ "-cdi",
+ "-shorttrack", "-noshorttrack", "-packet", "-noclose",
+ ""
+ };
+
+ /* are we pretending to be cdrecord ? */
+ cpt= strrchr(argv[0],'/');
+ if(cpt==NULL)
+ cpt= argv[0];
+ else
+ cpt++;
+ if(strcmp(cpt,"cdrecord")==0 && !(flag&1)) {
+ fprintf(stderr,"\n");
+ fprintf(stderr,
+ "Note: This is not cdrecord by Joerg Schilling. Do not bother him.\n");
+ fprintf(stderr,
+ " See cdrskin start message on stdout. See --help. See -version.\n");
+ fprintf(stderr,"\n");
+ /* allow automatic -tao to -sao redirection */
+ skin->tao_to_sao_tsize=650*1024*1024;
+ }
+
+#ifndef Cdrskin_extra_leaN
+ if(!(flag&2)) {
+ if(skin->preskin->pre_argc>1) {
+ ret= Cdrskin_setup(skin,skin->preskin->pre_argc,skin->preskin->pre_argv,
+ flag|1|2);
+ if(ret<=0)
+ return(ret);
+ }
+ }
+#endif
+
+ for (i= 1;i 3)
+ argpt++;
+
+ /* is this a known option which is not planned to be implemented ? */
+ /* such an option will not be accepted as data source */
+ for(k=0;ignored_partial_options[k][0]!=0;k++) {
+ if(argpt[0]=='-')
+ if(strncmp(argpt+1,ignored_partial_options[k],
+ strlen(ignored_partial_options[k]))==0)
+ goto no_volunteer;
+ if(strncmp(argpt,ignored_partial_options[k],
+ strlen(ignored_partial_options[k]))==0)
+ goto no_volunteer;
+ }
+ for(k=0;ignored_full_options[k][0]!=0;k++)
+ if(strcmp(argpt,ignored_full_options[k])==0)
+ goto no_volunteer;
+ if(0) {
+no_volunteer:;
+ skin->preskin->demands_cdrecord_caps= 1;
+ if(skin->preskin->fallback_program[0])
+ fprintf(stderr,"cdrskin: NOTE : Unimplemented option: '%s'\n",argpt);
+ else
+ fprintf(stderr,"cdrskin: NOTE : ignoring unimplemented option : '%s'\n",
+ argpt);
+ fprintf(stderr,
+ "cdrskin: NOTE : option is waiting for a volunteer to implement it.\n");
+ continue;
+ }
+
+#ifndef Cdrskin_extra_leaN
+ if(strncmp(argv[i],"abort_after_bytecount=",22)==0) {
+ skin->abort_after_bytecount= Scanf_io_size(argv[i]+22,0);
+ fprintf(stderr,
+ "cdrskin: NOTE : will perform synthetic abort after %.f bytes\n",
+ skin->abort_after_bytecount);
+
+ } else if(strcmp(argv[i],"--abort_handler")==0) {
+#else /* ! Cdrskin_extra_leaN */
+ if(strcmp(argv[i],"--abort_handler")==0) {
+#endif
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strncmp(argv[i],"-abort_max_wait=",16)==0) {
+ value_pt= argv[i]+16;
+ goto set_abort_max_wait;
+
+ } else if(strncmp(argv[i],"abort_max_wait=",15)==0) {
+ value_pt= argv[i]+15;
+set_abort_max_wait:;
+ value= Scanf_io_size(value_pt,0);
+ if(value<0 || value>86400) {
+ fprintf(stderr,
+ "cdrskin: NOTE : ignored out-of-range value: abort_max_wait=%s\n",
+ value_pt);
+ } else {
+ skin->abort_max_wait= value;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ printf(
+ "cdrskin: maximum waiting time with abort handling : %d seconds\n",
+ skin->abort_max_wait);
+ }
+
+ } else if(strcmp(argv[i],"--adjust_speed_to_drive")==0) {
+ skin->adjust_speed_to_drive= 1;
+
+ } else if(strcmp(argv[i],"--allow_emulated_drives")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--allow_setuid")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--allow_untested_media")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--any_track")==0) {
+ skin->single_track= -1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: --any_track : will accept any unknown option as track source\n"));
+
+ } else if(strncmp(argv[i],"assert_write_lba=",17)==0) {
+ value_pt= argv[i]+17;
+ value= Scanf_io_size(value_pt,0);
+ l= strlen(value_pt);
+ if(l>1) if(isalpha(value_pt[l-1]))
+ value/= 2048.0;
+ skin->assert_write_lba= value;
+
+ } else if(strcmp(argpt,"-atip")==0) {
+ if(skin->do_atip<1)
+ skin->do_atip= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: will put out some -atip style lines\n"));
+
+ } else if(strcmp(argpt,"-audio")==0) {
+ skin->track_type= BURN_AUDIO;
+ skin->track_type_by_default= 0;
+
+ } else if(strncmp(argpt,"-blank=",7)==0) {
+ cpt= argpt + 7;
+ goto set_blank;
+ } else if(strncmp(argpt,"blank=",6)==0) {
+ cpt= argpt + 6;
+set_blank:;
+ skin->blank_format_type= 0;
+ blank_mode= cpt;
+ if(strcmp(cpt,"all")==0 || strcmp(cpt,"disc")==0
+ || strcmp(cpt,"disk")==0) {
+ skin->do_blank= 1;
+ skin->blank_fast= 0;
+ blank_mode= "all";
+ } else if(strcmp(cpt,"fast")==0 || strcmp(cpt,"minimal")==0) {
+ skin->do_blank= 1;
+ skin->blank_fast= 1;
+ blank_mode= "fast";
+ } else if(strcmp(cpt,"format_if_needed")==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 6;
+ skin->preskin->demands_cdrskin_caps= 1;
+ } else if(strcmp(cpt,"format_overwrite")==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 1|(1<<8);
+ skin->blank_format_size= 128*1024*1024;
+ skin->preskin->demands_cdrskin_caps= 1;
+ } else if(strcmp(cpt,"format_overwrite_full")==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 1|(1<<10);
+ skin->blank_format_size= 0;
+ skin->preskin->demands_cdrskin_caps= 1;
+ } else if(strcmp(cpt,"format_overwrite_quickest")==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 1;
+ skin->blank_format_size= 0;
+ skin->preskin->demands_cdrskin_caps= 1;
+ } else if(strncmp(cpt,"format_defectmgt",16)==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 4|(3<<9); /* default payload size */
+ skin->blank_format_size= 0;
+ skin->preskin->demands_cdrskin_caps= 1;
+ if(cpt[16]=='_') {
+ cpt+= 17;
+ if(strcmp(cpt,"none")==0)
+ skin->blank_format_type= 4|(1<<13);
+ else if(strcmp(cpt,"max")==0)
+ skin->blank_format_type= 4; /* smallest payload size above 0 */
+ else if(strcmp(cpt,"min")==0)
+ skin->blank_format_type= 4|(2<<9); /*largest payload size with mgt*/
+ else if(strncmp(cpt,"payload_",8)==0) {
+ skin->blank_format_size= Scanf_io_size(cpt+8,0);
+ skin->blank_format_type= 4;
+ } else if(strcmp(cpt,"cert_off")==0)
+ skin->blank_format_no_certify= 1;
+ else if(strcmp(cpt,"cert_on")==0)
+ skin->blank_format_no_certify= 0;
+ else
+ goto unsupported_blank_option;
+ }
+ skin->preskin->demands_cdrskin_caps= 1;
+ } else if(strncmp(cpt,"format_by_index_",16)==0) {
+ sscanf(cpt+16, "%d", &idx);
+ if(idx<0 || idx>255) {
+ fprintf(stderr,"cdrskin: SORRY : blank=%s provides unusable index\n",
+ cpt);
+ return(0);
+ }
+ skin->do_blank= 1;
+ skin->blank_format_type= 5|(2<<9)|(1<<15);
+ skin->blank_format_index= idx;
+ skin->blank_format_size= 0;
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(cpt,"deformat_sequential")==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 2;
+ skin->blank_fast= 0;
+ skin->preskin->demands_cdrskin_caps= 1;
+ } else if(strcmp(cpt,"deformat_sequential_quickest")==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 2;
+ skin->blank_fast= 1;
+ skin->preskin->demands_cdrskin_caps= 1;
+ } else if(strcmp(cpt,"as_needed")==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 7;
+ } else if(strcmp(cpt,"help")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+ continue;
+ } else {
+unsupported_blank_option:;
+ fprintf(stderr,"cdrskin: FATAL : Blank option '%s' not supported yet\n",
+ cpt);
+ return(0);
+ }
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: blank mode : blank=%s\n",blank_mode));
+
+ } else if(strcmp(argv[i],"--bragg_with_audio")==0) {
+ /* OBSOLETE 0.2.3 : was handled in Cdrpreskin_setup() */;
+
+ } else if(strncmp(argv[i], "-cd_start_tno=", 14) == 0) {
+ value_pt= argv[i] + 14;
+ goto set_cd_start_tno;
+ } else if(strncmp(argv[i], "cd_start_tno=", 13) == 0) {
+ value_pt= argv[i] + 13;
+set_cd_start_tno:;
+ cd_start_tno= -1;
+ sscanf(value_pt, "%d", &cd_start_tno);
+ if(cd_start_tno < 1 || cd_start_tno > 99) {
+ fprintf(stderr,
+ "cdrskin: FATAL : cd_start_tno= gives a number outside [1 ... 99]\n");
+ return(0);
+ }
+ skin->cd_start_tno= cd_start_tno;
+
+ } else if(strcmp(argv[i],"--cdtext_dummy")==0) {
+ skin->cdtext_test= 2;
+
+ } else if(strncmp(argv[i], "-cdtext_to_textfile=", 20) == 0) {
+ value_pt= argv[i] + 20;
+ goto set_cdtext_to_textfile;
+ } else if(strncmp(argv[i], "cdtext_to_textfile=", 19) == 0) {
+ value_pt= argv[i] + 19;
+set_cdtext_to_textfile:;
+ if(strlen(value_pt) >= sizeof(skin->cdtext_to_textfile_path)) {
+ fprintf(stderr,
+ "cdrskin: FATAL : cdtext_to_textfile=... too long. (max: %d, given: %d)\n",
+ (int) sizeof(skin->cdtext_to_textfile_path)-1,(int) strlen(value_pt));
+ return(0);
+ }
+ skin->do_cdtext_to_textfile= 1;
+ strcpy(skin->cdtext_to_textfile_path, value_pt);
+
+ } else if(strncmp(argv[i], "-cdtext_to_v07t=", 16) == 0) {
+ value_pt= argv[i] + 16;
+ goto set_cdtext_to_v07t;
+ } else if(strncmp(argv[i], "cdtext_to_v07t=", 15) == 0) {
+ value_pt= argv[i] + 15;
+set_cdtext_to_v07t:;
+ if(strlen(value_pt) >= sizeof(skin->cdtext_to_vt07_path)) {
+ fprintf(stderr,
+ "cdrskin: FATAL : cdtext_to_vt07=... too long. (max: %d, given: %d)\n",
+ (int) sizeof(skin->cdtext_to_vt07_path)-1,(int) strlen(value_pt));
+ return(0);
+ }
+ skin->do_cdtext_to_vt07= 1;
+ strcpy(skin->cdtext_to_vt07_path, value_pt);
+
+ } else if(strcmp(argv[i],"--cdtext_verbose")==0) {
+ skin->cdtext_test= 1;
+
+ } else if(strcmp(argpt,"-checkdrive")==0) {
+ skin->do_checkdrive= 1;
+
+ } else if(strcmp(argpt,"-copy")==0) {
+ skin->track_modemods|= BURN_COPY;
+ skin->track_modemods&= ~BURN_SCMS;
+
+ } else if(strncmp(argpt, "-cuefile=", 9)==0) {
+ value_pt= argpt + 9;
+ goto set_cuefile;
+ } else if(strncmp(argpt, "cuefile=", 8)==0) {
+ value_pt= argpt + 8;
+set_cuefile:;
+ if(strlen(value_pt) >= sizeof(skin->cuefile)) {
+ fprintf(stderr,
+ "cdrskin: FATAL : cuefile=... too long. (max: %d, given: %d)\n",
+ (int) sizeof(skin->cuefile) - 1, (int) strlen(value_pt));
+ return(0);
+ }
+ strcpy(skin->cuefile, value_pt);
+ skin->do_burn= 1;
+
+ } else if(strcmp(argpt,"-data")==0) {
+option_data:;
+ /* All Subsequent Tracks Option */
+ skin->cdxa_conversion= (skin->cdxa_conversion & ~0x7fffffff) | 0;
+ skin->track_type= BURN_MODE1;
+ skin->track_type_by_default= 0;
+
+ } else if(strcmp(argv[i],"--demand_a_drive")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--devices")==0) {
+ skin->do_devices= 1;
+
+ } else if(strcmp(argv[i],"--device_links")==0) {
+ skin->do_devices= 2;
+
+#ifndef Cdrskin_extra_leaN
+
+ } else if(strncmp(argv[i],"dev_translation=",16)==0) {
+ if(argv[i][16]==0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : dev_translation= : missing separator character\n");
+ return(0);
+ }
+ ret= Cdradrtrn_add(skin->adr_trn,argv[i]+17,argv[i]+16,1);
+ if(ret==-2)
+ fprintf(stderr,
+ "cdrskin: FATAL : address_translation= : cannot allocate memory\n");
+ else if(ret==-1)
+ fprintf(stderr,
+ "cdrskin: FATAL : address_translation= : table full (%d items)\n",
+ Cdradrtrn_leN);
+ else if(ret==0)
+ fprintf(stderr,
+ "cdrskin: FATAL : address_translation= : no address separator '%c' found\n",
+ argv[i][17]);
+ if(ret<=0)
+ return(0);
+
+#endif /* ! Cdrskin_extra_leaN */
+
+
+ } else if(strncmp(argpt,"-dev=",5)==0) {
+ /* is handled in Cdrpreskin_setup() */;
+ } else if(strncmp(argpt,"dev=",4)==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strncmp(argv[i],"direct_write_amount=",20)==0) {
+ skin->direct_write_amount= Scanf_io_size(argv[i]+20,0);
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: amount for direct writing : %.f\n",
+ skin->direct_write_amount));
+ if(skin->direct_write_amount>=0.0) {
+ skin->do_direct_write= 1;
+ printf("cdrskin: NOTE : Direct writing will only use first track source and no fifo.\n");
+ skin->preskin->demands_cdrskin_caps= 1;
+ } else
+ skin->do_direct_write= 0;
+
+ } else if(strcmp(argv[i],"--drive_abort_on_busy")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--drive_blocking")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--drive_not_exclusive")==0 ||
+ strcmp(argv[i],"--drive_not_f_setlk")==0 ||
+ strcmp(argv[i],"--drive_not_o_excl")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strncmp(argv[i],"drive_scsi_dev_family=",22)==0) {
+ /* is handled in Cdrpreskin_setup() */;
+ if(skin->verbosity>=Cdrskin_verbose_debuG &&
+ skin->preskin->drive_scsi_dev_family!=0)
+ ClN(fprintf(stderr,"cdrskin_debug: drive_scsi_dev_family= %d\n",
+ skin->preskin->drive_scsi_dev_family));
+
+ } else if(strcmp(argv[i],"--drive_scsi_exclusive")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strncmp(argpt, "-driveropts=", 12)==0) {
+ value_pt= argpt + 12;
+ goto set_driveropts;
+ } else if(strncmp(argpt, "driveropts=", 11)==0) {
+ value_pt= argpt + 11;
+set_driveropts:;
+ if(strcmp(value_pt,"burnfree")==0 || strcmp(value_pt,"burnproof")==0) {
+ skin->burnfree= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: burnfree : on\n"));
+ } else if(strcmp(argpt+11,"noburnfree")==0 ||
+ strcmp(argpt+11,"noburnproof")==0 ) {
+ skin->burnfree= 0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: burnfree : off\n"));
+ } else if(strcmp(argpt+11,"help")==0) {
+ /* handled in Cdrpreskin_setup() */;
+ } else
+ goto ignore_unknown;
+
+ } else if(strcmp(argpt,"-dummy")==0) {
+ skin->dummy_mode= 1;
+
+ } else if(strncmp(argv[i], "-dvd_obs=", 9)==0) {
+ value_pt= argv[i] + 9;
+ goto dvd_obs;
+ } else if(strncmp(argv[i], "dvd_obs=", 8)==0) {
+ value_pt= argv[i] + 8;
+dvd_obs:;
+ if(strcmp(value_pt, "default") == 0)
+ num= 0;
+ else
+ num = Scanf_io_size(value_pt,0);
+ if(num != 0 && num != 32768 && num != 65536) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Option dvd_obs= accepts only sizes 0, 32k, 64k\n");
+ } else
+ skin->dvd_obs= num;
+
+ } else if(strcmp(argpt,"-eject")==0) {
+ skin->do_eject= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: eject after work : on\n"));
+
+ } else if(strncmp(argv[i],"eject_device=",13)==0) {
+ if(strlen(argv[i]+13)>=sizeof(skin->eject_device)) {
+ fprintf(stderr,
+ "cdrskin: FATAL : eject_device=... too long. (max: %d, given: %d)\n",
+ (int) sizeof(skin->eject_device)-1,(int) strlen(argv[i]+13));
+ return(0);
+ }
+ strcpy(skin->eject_device,argv[i]+13);
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: ignoring obsolete eject_device=%s\n",
+ skin->eject_device));
+
+ } else if(strncmp(argv[i],"-extract_audio_to=", 18)==0) {
+ value_pt= argpt + 18;
+ goto extract_audio_to;
+ } else if(strncmp(argpt, "extract_audio_to=", 17) == 0) {
+ value_pt= argpt + 17;
+extract_audio_to:;
+ if(strlen(value_pt) >= sizeof(skin->extract_audio_dir)) {
+ fprintf(stderr,
+ "cdrskin: FAILURE : extract_audio_to=... is much too long.\n");
+ return(0);
+ }
+ skin->do_extract_audio= 1;
+ strcpy(skin->extract_audio_dir, value_pt);
+
+ } else if(strncmp(argv[i],"-extract_tracks=", 16)==0) {
+ value_pt= argpt + 16;
+ goto extract_tracks;
+ } else if(strncmp(argpt, "extract_tracks=", 15) == 0) {
+ value_pt= argpt + 15;
+extract_tracks:;
+ value= 0.0;
+ for(cpt= value_pt; ; cpt++) {
+ if(*cpt >= '0' && *cpt <= '9') {
+ value= value * 10 + *cpt - '0';
+ } else {
+ if(value >= 1.0 && value <= 99.0) {
+ skin->extract_audio_tracks[(int) value]= 1;
+ if(skin->verbosity >= Cdrskin_verbose_cmD)
+ fprintf(stderr, "cdrskin: Will extract track number %.f\n",
+ value);
+ } else {
+ fprintf(stderr,
+ "cdrskin: WARNING : extract_tracks= with unsuitable number: %.f\n",
+ value);
+ }
+ if(*cpt == 0)
+ break;
+ value= 0;
+ }
+ }
+
+ } else if(strncmp(argv[i],"-extract_basename=", 18)==0) {
+ value_pt= argpt + 18;
+ goto extract_basename;
+ } else if(strncmp(argpt, "extract_basename=", 17) == 0) {
+ value_pt= argpt + 17;
+extract_basename:;
+ if(strchr(value_pt, '/') != NULL) {
+ fprintf(stderr,
+ "cdrskin: FAILURE : extract_basename=... may not contain '/'\n");
+ return(0);
+ }
+ if(strlen(value_pt) > 248) {
+ fprintf(stderr,
+ "cdrskin: FAILURE : Oversized extract_basename=... (Max. 248)\n");
+ return(0);
+ }
+ strcpy(skin->extract_basename, value_pt);
+
+ } else if(strcmp(argv[i],"--extract_dap") == 0) {
+ skin->extract_flags|= 8;
+
+#ifndef Cdrskin_extra_leaN
+
+ } else if(strcmp(argv[i],"--fifo_disable")==0) {
+ skin->fifo_enabled= 0;
+ skin->fifo_size= 0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: option fs=... disabled\n"));
+
+ } else if(strcmp(argv[i],"--fifo_start_empty")==0) { /* obsoleted */
+ skin->fifo_start_at= 0;
+
+ } else if(strncmp(argv[i],"fifo_start_at=",14)==0) {
+ value= Scanf_io_size(argv[i]+14,0);
+ if(value>1024.0*1024.0*1024.0)
+ value= 1024.0*1024.0*1024.0;
+ else if(value<0)
+ value= 0;
+ skin->fifo_start_at= value;
+
+ } else if(strcmp(argv[i],"--fifo_per_track")==0) {
+ skin->fifo_per_track= 1;
+
+#endif /* ! Cdrskin_extra_leaN */
+
+ } else if(strcmp(argv[i],"--fill_up_media")==0) {
+ skin->fill_up_media= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: will fill up last track to full free media space\n"));
+
+ } else if(strcmp(argpt,"-force")==0) {
+ skin->force_is_set= 1;
+
+ } else if(strcmp(argpt,"-format")==0) {
+ skin->do_blank= 1;
+ skin->blank_format_type= 3|(1<<10);
+ skin->blank_format_size= 0;
+ skin->force_is_set= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: will format DVD+RW by blank=format_overwrite_full -force\n"));
+
+ } else if(strcmp(argv[i],"--four_channel")==0) {
+ skin->track_modemods|= BURN_4CH;
+
+#ifndef Cdrskin_extra_leaN
+
+ } else if(strncmp(argpt, "-fs=", 4) == 0) {
+ value_pt= argpt + 4;
+ goto fs_equals;
+ } else if(strncmp(argpt, "fs=", 3) == 0) {
+ value_pt= argpt + 3;
+fs_equals:;
+ if(skin->fifo_enabled) {
+ value= Scanf_io_size(value_pt,0);
+ if(value<0.0 || value>1024.0*1024.0*1024.0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : fs=N expects a size between 0 and 1g\n");
+ return(0);
+ }
+ skin->fifo_size= value;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ printf("cdrskin: fifo size : %d\n",skin->fifo_size);
+ }
+
+ } else if(strncmp(argv[i],"grab_drive_and_wait=",20)==0) {
+ value_pt= argv[i]+20;
+ grab_and_wait_value= Scanf_io_size(value_pt,0);
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strncmp(argpt, "-gracetime=", 11) == 0) {
+ value_pt= argpt + 11;
+ goto gracetime_equals;
+ } else if(strncmp(argpt, "gracetime=", 10) == 0) {
+ value_pt= argpt + 10;
+gracetime_equals:;
+ sscanf(value_pt,"%d",&(skin->gracetime));
+
+ } else if(strncmp(argv[i],"--grow_overwriteable_iso",24)==0) {
+ skin->grow_overwriteable_iso= 1;
+ skin->use_data_image_size= 1;
+ skin->preskin->demands_cdrskin_caps= 1;
+
+#else /* ! Cdrskin_extra_leaN */
+
+ } else if(
+ strcmp(argv[i],"--fifo_disable")==0 ||
+ strcmp(argv[i],"--fifo_start_empty")==0 ||
+ strncmp(argv[i],"fifo_start_at=",14)==0 ||
+ strcmp(argv[i],"--fifo_per_track")==0 ||
+ strncmp(argv[i],"-fs=",4)==0 ||
+ strncmp(argv[i],"fs=",3)==0 ||
+ strncmp(argv[i],"-gracetime=",11)==0 ||
+ strncmp(argv[i],"gracetime=",10)==0) {
+ fprintf(stderr,
+ "cdrskin: NOTE : lean version ignores option: '%s'\n",
+ argv[i]);
+
+#endif /* Cdrskin_extra_leaN */
+
+ } else if(strcmp(argv[i],"--help")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"-help")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--ignore_signals")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argpt,"-immed")==0) {
+ skin->modesty_on_drive= 1;
+ skin->min_buffer_percent= 75;
+ skin->max_buffer_percent= 95;
+
+ } else if(strncmp(argpt, "-index=", 7) == 0) {
+ value_pt= argpt + 7;
+ goto set_index;
+ } else if(strncmp(argpt, "index=", 6) == 0) {
+ value_pt= argpt + 6;
+set_index:;
+ if(skin->index_string != NULL)
+ free(skin->index_string);
+ skin->index_string= strdup(value_pt);
+ if(skin->index_string == NULL) {
+ fprintf(stderr, "cdrskin: FATAL : Out of memory\n");
+ return(-1);
+ }
+
+ } else if(strncmp(argv[i], "input_sheet_v07t=", 17)==0) {
+ if(skin->sheet_v07t_blocks >= 8) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Too many input_sheet_v07t= options. (Max. 8)\n");
+ return(0);
+ }
+ if(argv[i][17] == 0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Missing file path after option input_sheet_v07t=\n");
+ return(0);
+ }
+ if(strlen(argv[i] + 17) > Cdrskin_adrleN) {
+ fprintf(stderr,
+ "cdrskin: SORRY : File path too long after option input_sheet_v07t=\n");
+ return(0);
+ }
+ strcpy(skin->sheet_v07t_paths[skin->sheet_v07t_blocks], argv[i] + 17);
+ skin->sheet_v07t_blocks++;
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(argpt,"-inq")==0) {
+ skin->do_checkdrive= 2;
+
+ } else if(strcmp(argpt,"-isosize")==0) {
+ skin->use_data_image_size= 1;
+
+ } else if(strncmp(argpt, "-isrc=", 6) == 0) {
+ value_pt= argpt + 6;
+ goto set_isrc;
+ } else if(strncmp(argpt, "isrc=", 5) == 0) {
+ value_pt= argpt + 5;
+set_isrc:;
+ if(strlen(value_pt) != 12) {
+ fprintf(stderr,
+ "cdrskin: SORRY : isrc=... is not exactly 12 characters long.\n");
+ return(0);
+ }
+ memcpy(skin->next_isrc, value_pt, 13);
+
+ } else if(strcmp(argv[i],"--list_formats")==0) {
+ skin->do_list_formats= 1;
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(argv[i],"--list_ignored_options")==0) {
+ /* is also handled in Cdrpreskin_setup() */;
+
+ printf("cdrskin: List of all ignored options:\n");
+ for(k=0;ignored_partial_options[k][0]!=0;k++)
+ printf("%s\n",ignored_partial_options[k]);
+ for(k=0;ignored_full_options[k][0]!=0;k++)
+ printf("%s\n",ignored_full_options[k]);
+ printf("\n");
+
+ } else if(strcmp(argv[i],"--list_speeds")==0) {
+ skin->do_list_speeds= 1;
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strncmp(argv[i],"fallback_program=",17)==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argpt,"-load")==0) {
+ skin->do_load= 1;
+
+ } else if(strcmp(argpt,"-lock")==0) {
+ skin->do_load= 2;
+
+ } else if(strcmp(argv[i],"--long_toc")==0) {
+ skin->do_atip= 3;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: will put out some -atip style lines plus -toc\n"));
+
+ } else if(strncmp(argpt,"-mcn=", 5) == 0) {
+ value_pt= argpt + 5;
+ goto set_mcn;
+ } else if(strncmp(argpt,"mcn=", 4) == 0) {
+ value_pt= argpt + 4;
+set_mcn:;
+ if(strlen(value_pt) != 13) {
+ fprintf(stderr,
+ "cdrskin: SORRY : mcn=... is not exactly 13 characters long.\n");
+ return(0);
+ }
+ memcpy(skin->mcn, value_pt, 14);
+
+ } else if(strncmp(argpt, "-minbuf=", 8) == 0) {
+ value_pt= argpt + 8;
+ goto minbuf_equals;
+ } else if(strncmp(argpt, "minbuf=", 7) == 0) {
+ value_pt= argpt + 7;
+minbuf_equals:;
+ skin->modesty_on_drive= 1;
+ sscanf(value_pt,"%lf",&value);
+ if (value<25 || value>95) {
+ fprintf(stderr,
+ "cdrskin: FATAL : minbuf= value must be between 25 and 95\n");
+ return(0);
+ }
+ skin->min_buffer_percent= value;
+ skin->max_buffer_percent= 95;
+ ClN(printf("cdrskin: minbuf=%d percent desired buffer fill\n",
+ skin->min_buffer_percent));
+
+ } else if(strcmp(argpt,"-minfo") == 0 ||
+ strcmp(argpt,"-media-info") == 0) {
+ skin->do_atip= 4;
+
+ } else if(strcmp(argpt, "-mode2") == 0) {
+ fprintf(stderr,
+ "cdrskin: NOTE : defaulting option -mode2 to option -data\n");
+ goto option_data;
+
+ } else if(strncmp(argv[i],"modesty_on_drive=",17)==0) {
+ value_pt= argv[i]+17;
+ if(*value_pt == '0' || strncmp(value_pt, "off", 3) == 0) {
+ skin->modesty_on_drive= 0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: modesty_on_drive=0 : buffer waiting by os driver\n"));
+ } else if(*value_pt=='1' || strncmp(value_pt, "on", 2) == 0) {
+ skin->modesty_on_drive= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: modesty_on_drive=1 : buffer waiting by libburn\n"));
+ } else if(*value_pt=='-' && argv[i][18]=='1') {
+ skin->modesty_on_drive= -1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: modesty_on_drive=-1 : buffer waiting as libburn defaults\n"));
+ } else {
+ fprintf(stderr,
+ "cdrskin: FATAL : modesty_on_drive= must be -1, 0 or 1\n");
+ return(0);
+ }
+ while(1) {
+ value_pt= strchr(value_pt,':');
+ if(value_pt==NULL)
+ break;
+ value_pt++;
+ if(strncmp(value_pt,"min_percent=",12)==0) {
+ sscanf(value_pt+12,"%lf",&value);
+ if (value<25 || value>100) {
+ fprintf(stderr,
+ "cdrskin: FATAL : modest_on_drive= min_percent value must be between 25 and 100\n");
+ return(0);
+ }
+ skin->min_buffer_percent= value;
+ if(skin->verbosity >= Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: modesty_on_drive : %d percent min buffer fill\n",
+ skin->min_buffer_percent));
+ } else if(strncmp(value_pt,"max_percent=",12)==0) {
+ sscanf(value_pt+12,"%lf",&value);
+ if (value<25 || value>100) {
+ fprintf(stderr,
+ "cdrskin: FATAL : modest_on_drive= max_percent value must be between 25 and 100\n");
+ return(0);
+ }
+ skin->max_buffer_percent= value;
+ if(skin->verbosity >= Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: modesty_on_drive : %d percent max buffer fill\n",
+ skin->max_buffer_percent));
+ } else if(strncmp(value_pt, "min_usec=", 9) == 0) {
+ sscanf(value_pt + 9, "%lf", &value);
+ if(value < 0)
+ value= 0;
+ skin->min_buffer_usec= value;
+ if(skin->verbosity >= Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: modesty_on_drive : %d microseconds minimum sleep time\n",
+ skin->min_buffer_usec));
+ } else if(strncmp(value_pt,"max_usec=", 9)==0) {
+ sscanf(value_pt + 9, "%lf", &value);
+ if(value < 0)
+ value= 0;
+ skin->max_buffer_usec= value;
+ if(skin->verbosity >= Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: modesty_on_drive : %d microseconds maximum sleep time\n",
+ skin->max_buffer_usec));
+ } else if(strncmp(value_pt,"timeout_sec=", 12)==0) {
+ sscanf(value_pt + 9, "%lf", &value);
+ if(value < 0)
+ value= 0;
+ skin->buffer_timeout_sec= value;
+ if(skin->verbosity >= Cdrskin_verbose_cmD)
+ ClN(printf(
+ "cdrskin: modesty_on_drive : %d seconds fallback timeout\n",
+ skin->max_buffer_usec));
+ } else {
+ fprintf(stderr,
+ "cdrskin: SORRY : modest_on_drive= unknown option code : %s\n",
+ value_pt);
+ }
+ }
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(argpt,"-multi")==0) {
+ skin->multi= 1;
+
+ } else if(strncmp(argpt, "-msifile=", 9) == 0) {
+ value_pt= argpt + 9;
+ goto msifile_equals;
+ } else if(strncmp(argpt, "msifile=", 8) == 0) {
+ value_pt= argpt + 8;
+msifile_equals:;
+ if(strlen(value_pt)>=sizeof(skin->msifile)) {
+ fprintf(stderr,
+ "cdrskin: FATAL : msifile=... too long. (max: %d, given: %d)\n",
+ (int) sizeof(skin->msifile)-1,(int) strlen(value_pt));
+ return(0);
+ }
+ strcpy(skin->msifile, value_pt);
+ skin->do_msinfo= 1;
+
+ } else if(strcmp(argpt,"-msinfo")==0) {
+ skin->do_msinfo= 1;
+
+#ifdef Libburn_develop_quality_scaN
+
+ } else if(strcmp(argv[i],"--nec_optiarc_qcheck")==0) {
+ skin->do_qcheck= 1;
+
+#endif /* Libburn_develop_quality_scaN */
+
+ } else if(strcmp(argv[i],"--no_abort_handler")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--no_blank_appendable")==0) {
+ skin->no_blank_appendable= 1;
+
+ } else if(strcmp(argv[i],"--no_convert_fs_adr")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"--no_load")==0) {
+ skin->do_load= -1;
+
+ } else if(strcmp(argv[i],"--no_rc")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argpt,"-nocopy")==0) {
+ skin->track_modemods&= ~BURN_COPY;
+
+ } else if(strcmp(argpt,"-nopad")==0) {
+ skin->padding= 0.0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: padding : off\n"));
+
+ } else if(strcmp(argpt,"-nopreemp")==0) {
+ skin->track_modemods&= ~BURN_PREEMPHASIS;
+
+ } else if(strcmp(argv[i],"--obs_pad")==0) {
+ skin->obs_pad= 1;
+
+ } else if(strcmp(argv[i],"--old_pseudo_scsi_adr")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i], "--pacifier_with_newline") == 0) {
+ skin->pacifier_with_newline= 1;
+
+ } else if(strcmp(argpt,"-pad")==0) {
+ skin->padding= 15*2048;
+ skin->set_by_padsize= 0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: padding : %.f\n",skin->padding));
+
+ } else if(strncmp(argpt, "-padsize=", 9) == 0) {
+ value_pt= argpt + 9;
+ goto set_padsize;
+ } else if(strncmp(argpt, "padsize=", 8) == 0) {
+ value_pt= argpt + 8;
+set_padsize:;
+ skin->padding= Scanf_io_size(value_pt, 0);
+ skin->set_by_padsize= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: padding : %.f\n",skin->padding));
+
+ } else if(strcmp(argpt,"-preemp")==0) {
+ skin->track_modemods|= BURN_PREEMPHASIS;
+
+ } else if(strcmp(argv[i],"--prodvd_cli_compatible")==0) {
+ skin->prodvd_cli_compatible= 1;
+
+ } else if(strcmp(argpt,"-sao")==0 || strcmp(argpt,"-dao")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argpt,"-scanbus")==0) {
+ skin->do_scanbus= 1;
+
+ } else if(strcmp(argpt,"-scms")==0) {
+ skin->track_modemods|= BURN_SCMS;
+
+ } else if(strcmp(argv[i],"--single_track")==0) {
+ skin->single_track= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf(
+"cdrskin: --single_track : will only accept last argument as track source\n"));
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strncmp(argv[i], "-sao_postgap=", 13) == 0) {
+ value_pt= argv[i] + 13;
+ goto set_sao_postgap;
+ } else if(strncmp(argv[i], "sao_postgap=", 12) == 0) {
+ value_pt= argv[i] + 12;
+set_sao_postgap:;
+ skin->sao_postgap= -1;
+ if(strcmp(value_pt, "off") == 0)
+ skin->sao_postgap = -1;
+ else
+ sscanf(value_pt, "%d", &(skin->sao_postgap));
+ if(skin->sao_postgap < 0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : sao_postgap must be \"off\" or a number >= 0\n");
+ return(0);
+ }
+
+ } else if(strncmp(argv[i], "-sao_pregap=", 12) == 0) {
+ value_pt= argv[i] + 12;
+ goto set_sao_pregap;
+ } else if(strncmp(argv[i], "sao_pregap=", 11) == 0) {
+ value_pt= argv[i] + 11;
+set_sao_pregap:;
+ skin->sao_pregap= -1;
+ if(strcmp(value_pt, "off") == 0)
+ skin->sao_pregap = -1;
+ else
+ sscanf(value_pt, "%d", &(skin->sao_pregap));
+ if(skin->sao_pregap < 0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : sao_pregap must be \"off\" or a number >= 0\n");
+ return(0);
+ }
+
+ } else if(strncmp(argpt, "-speed=", 7) == 0) {
+ value_pt= argpt + 7;
+ goto set_speed;
+ } else if(strncmp(argpt, "speed=", 6) == 0) {
+ value_pt= argpt + 6;
+set_speed:;
+ if(strcmp(value_pt,"any")==0)
+ skin->x_speed= -1;
+ else
+ sscanf(value_pt,"%lf",&(skin->x_speed));
+ if(skin->x_speed<1.0 && skin->x_speed!=0.0 && skin->x_speed!=-1) {
+ fprintf(stderr,"cdrskin: FATAL : speed= must be -1, 0 or at least 1\n");
+ return(0);
+ }
+ if(skin->x_speed<0)
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ /* >>> cdrecord speed=0 -> minimum speed , libburn -> maximum speed */;
+
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: speed : %f\n",skin->x_speed));
+
+ } else if(strncmp(argv[i], "-stdio_sync=", 12)==0) {
+ value_pt= argv[i] + 12;
+ goto stdio_sync;
+ } else if(strncmp(argv[i], "stdio_sync=", 11)==0) {
+ value_pt= argv[i] + 11;
+stdio_sync:;
+ if(strcmp(value_pt, "default") == 0 || strcmp(value_pt, "on") == 0)
+ num= 0;
+ else if(strcmp(value_pt, "off") == 0)
+ num= -1;
+ else
+ num = Scanf_io_size(value_pt,0);
+ if(num > 0)
+ num/= 2048;
+ if(num != -1 && num != 0 && (num < 32 || num > 512 * 1024)) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Option stdio_sync= accepts only sizes -1, 0, 32k ... 1g\n");
+ } else
+ skin->stdio_sync= num;
+
+ } else if(strncmp(argv[i],"-stream_recording=",18)==0) {
+ value_pt= argv[i]+18;
+ goto set_stream_recording;
+ } else if(strncmp(argv[i],"stream_recording=",17)==0) {
+ value_pt= argv[i]+17;
+set_stream_recording:;
+ if(strcmp(value_pt, "on")==0)
+ skin->stream_recording_is_set= 1;
+ else if(value_pt[0] >= '0' && value_pt[0] <= '9') {
+ num= Scanf_io_size(value_pt, 0);
+ num/= 2048.0;
+ if(num >= 16 && num <= 0x7FFFFFFF)
+ skin->stream_recording_is_set= num;
+ else
+ skin->stream_recording_is_set= 0;
+ } else
+ skin->stream_recording_is_set= 0;
+ } else if(strcmp(argpt,"-swab")==0) {
+ skin->swap_audio_bytes= 0;
+
+ } else if(strcmp(argpt,"-tao")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strncmp(argv[i],"tao_to_sao_tsize=",17)==0) {
+ skin->tao_to_sao_tsize= Scanf_io_size(argv[i]+17,0);
+ if(skin->tao_to_sao_tsize>Cdrskin_tracksize_maX)
+ goto track_too_large;
+ skin->preskin->demands_cdrskin_caps= 1;
+
+#ifndef Cdrskin_extra_leaN
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ printf("cdrskin: size default for non-tao write modes: %.f\n",
+ skin->tao_to_sao_tsize);
+#endif /* ! Cdrskin_extra_leaN */
+
+ } else if(strcmp(argv[i],"--tell_media_space")==0) {
+ skin->tell_media_space= 1;
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(argpt, "-text") == 0) {
+ skin->use_cdtext= 1;
+
+ } else if(strncmp(argpt, "-textfile=", 10) == 0) {
+ value_pt= argpt + 10;
+ goto set_textfile;
+ } else if(strncmp(argpt ,"textfile=", 9) == 0) {
+ value_pt= argpt + 9;
+set_textfile:;
+ ret= Cdrskin_read_textfile(skin, value_pt, 0);
+ if(ret <= 0)
+ return(ret);
+
+ } else if(strncmp(argpt, "-textfile_to_v07t=", 18) == 0) {
+ value_pt= argpt + 18;
+ goto textfile_to_v07t;
+ } else if(strncmp(argpt ,"textfile_to_v07t=", 17) == 0) {
+ value_pt= argpt + 17;
+textfile_to_v07t:;
+ ret= Cdrskin_read_textfile(skin, value_pt, 0);
+ if(ret <= 0)
+ return(ret);
+ ret= Cdrskin_print_text_packs(skin, skin->text_packs,
+ skin->num_text_packs, (1 << 4) | 2);
+ if(ret <= 0)
+ return(ret);
+ if(i != 1 || argc != 2)
+ fprintf(stderr, "cdrskin: WARNING : Program run ended by option textfile_to_v07t=. Other options may have been ignored.\n");
+ return(2);
+
+ } else if(strcmp(argpt,"-toc")==0) {
+ skin->do_atip= 2;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: will put out some -atip style lines plus -toc\n"));
+
+ } else if(strncmp(argpt, "-tsize=", 7) == 0) {
+ value_pt= argpt + 7;
+ goto set_tsize;
+ } else if(strncmp(argpt, "tsize=", 6) == 0) {
+ value_pt= argpt + 6;
+set_tsize:;
+ skin->fixed_size= Scanf_io_size(value_pt,0);
+ if(skin->fixed_size>Cdrskin_tracksize_maX) {
+track_too_large:;
+ fprintf(stderr,"cdrskin: FATAL : Track size too large\n");
+ return(0);
+ }
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: fixed track size : %.f\n",skin->fixed_size));
+ if(skin->smallest_tsize<0 || skin->smallest_tsize>skin->fixed_size)
+ skin->smallest_tsize= skin->fixed_size;
+
+ } else if(strcmp(argv[i],"--two_channel")==0) {
+ skin->track_modemods&= ~BURN_4CH;
+
+ } else if(strncmp(argv[i], "use_immed_bit=", 14) == 0) {
+ if(strcmp(argv[i] + 14, "on") == 0) {
+ skin->use_immed= 1;
+ } else if(strcmp(argv[i] + 14, "off") == 0) {
+ skin->use_immed= -1;
+ } else if(strcmp(argv[i] + 14, "default") == 0) {
+ skin->use_immed= 0;
+ } else {
+ fprintf(stderr, "cdrskin: FATAL : use_immed_bits= must be \"on\", \"off\", or \"default\"\n");
+ return(0);
+ }
+
+ } else if(strcmp(argv[i],"-V")==0 || strcmp(argpt, "-Verbose")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+ } else if(strcmp(argv[i],"-v")==0 || strcmp(argpt,"-verbose")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+ } else if(strcmp(argv[i],"-vv")==0 || strcmp(argv[i],"-vvv")==0 ||
+ strcmp(argv[i],"-vvvv")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argpt,"-version")==0) {
+ /* is handled in Cdrpreskin_setup() and should really not get here */;
+
+ } else if(strcmp(argpt,"-waiti")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strncmp(argv[i],"write_start_address=",20)==0) {
+ skin->write_start_address= Scanf_io_size(argv[i]+20,0);
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: write start address : %.f\n",
+ skin->write_start_address));
+ skin->preskin->demands_cdrskin_caps= 1;
+
+ } else if(strcmp(argpt, "-xa") == 0) {
+ fprintf(stderr,"cdrskin: NOTE : defaulting option -xa to option -data\n");
+ goto option_data;
+
+ } else if(strcmp(argpt, "-xa1") == 0) {
+ /* All Subsequent Tracks Option */
+ skin->cdxa_conversion= (skin->cdxa_conversion & ~0x7fffffff) | 1;
+ skin->track_type= BURN_MODE1;
+ skin->track_type_by_default= 0;
+
+ } else if(strcmp(argpt, "-xa2") == 0) {
+ fprintf(stderr,
+ "cdrskin: NOTE : defaulting option -xa2 to option -data\n");
+ goto option_data;
+
+ } else if(strcmp(argv[i], "--xa1-ignore") == 0) {
+ skin->cdxa_conversion|= (1 << 31);
+
+ } else if( i==argc-1 ||
+ (skin->single_track==0 && strchr(argv[i],'=')==NULL
+ && !(argv[i][0]=='-' && argv[i][1]!=0) ) ||
+ (skin->single_track==-1)) {
+ if(strlen(argv[i])>=sizeof(skin->source_path)) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Source address too long. (max: %d, given: %d)\n",
+ (int) sizeof(skin->source_path)-1,(int) strlen(argv[i]));
+ return(0);
+ }
+ strcpy(skin->source_path,argv[i]);
+ if(strcmp(skin->source_path,"-")==0) {
+ if(skin->stdin_source_used) {
+ fprintf(stderr,
+ "cdrskin: FATAL : \"-\" (stdin) can be used as track source only once.\n");
+ return(0);
+ }
+ skin->stdin_source_used= 1;
+ } else if(argv[i][0]=='#' && (argv[i][1]>='0' && argv[i][1]<='9')) {
+ if(skin->preskin->allow_fd_source==0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : '%s' is a reserved source path with cdrskin\n",
+ argv[i]);
+ fprintf(stderr,
+ "cdrskin: SORRY : which would use an open file descriptor as source.\n");
+ fprintf(stderr,
+ "cdrskin: SORRY : Its usage is dangerous and disabled for now.\n");
+ return(0);
+ }
+ } else {
+ if(stat(skin->source_path,&stbuf)!=-1) {
+ if((stbuf.st_mode&S_IFMT)==S_IFREG)
+ ;
+ else if((stbuf.st_mode&S_IFMT)==S_IFDIR) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Source address is a directory: '%s'\n",
+ skin->source_path);
+ return(0);
+ }
+ }
+ }
+
+ if(skin->track_counter>=Cdrskin_track_maX) {
+ fprintf(stderr,"cdrskin: FATAL : Too many tracks given. (max %d)\n",
+ Cdrskin_track_maX);
+ return(0);
+ }
+ ret= Cdrtrack_new(&(skin->tracklist[skin->track_counter]),skin,
+ skin->track_counter,
+ (strcmp(skin->source_path,"-")==0)<<1);
+ if(ret<=0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Creation of track control object failed.\n");
+ return(ret);
+ }
+ if(skin->next_isrc[0])
+ memcpy(skin->tracklist[skin->track_counter]->isrc, skin->next_isrc, 13);
+ skin->tracklist[skin->track_counter]->index_string= skin->index_string;
+ skin->tracklist[skin->track_counter]->sao_pregap= skin->sao_pregap;
+ skin->tracklist[skin->track_counter]->sao_postgap= skin->sao_postgap;
+ skin->index_string= NULL;
+ skin->sao_postgap= skin->sao_pregap= -1;
+ skin->track_counter++;
+ skin->use_data_image_size= 0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD) {
+ if(strcmp(skin->source_path,"-")==0)
+ printf("cdrskin: track %d data source : '-' (i.e. standard input)\n",
+ skin->track_counter);
+ else
+ printf("cdrskin: track %d data source : '%s'\n",
+ skin->track_counter,skin->source_path);
+ }
+ /* reset track options */
+ if(skin->set_by_padsize)
+ skin->padding= 0; /* cdrecord-ProDVD-2.01b31 resets to 30k
+ the man page says padsize= is reset to 0
+ Joerg Schilling will change in 2.01.01 to 0 */
+ skin->fixed_size= 0;
+ skin->next_isrc[0]= 0;
+ } else {
+ignore_unknown:;
+ if(skin->preskin->fallback_program[0])
+ fprintf(stderr,"cdrskin: NOTE : Unknown option : '%s'\n",argv[i]);
+ else
+ fprintf(stderr,"cdrskin: NOTE : ignoring unknown option : '%s'\n",
+ argv[i]);
+ skin->preskin->demands_cdrecord_caps= 1;
+ }
+ }
+
+ if(flag&1) /* no finalizing yet */
+ return(1);
+
+ if(skin->preskin->fallback_program[0] &&
+ skin->preskin->demands_cdrecord_caps>0 &&
+ skin->preskin->demands_cdrskin_caps<=0) {
+ fprintf(stderr,"cdrskin: NOTE : Unsupported options found.\n");
+ fprintf(stderr,
+ "cdrskin: NOTE : Will delegate job to fallback program '%s'.\n",
+ skin->preskin->fallback_program);
+ return(0);
+ }
+
+#ifndef Cdrskin_extra_leaN
+ if(skin->verbosity>=Cdrskin_verbose_cmD) {
+ if(skin->preskin->abort_handler==1)
+ printf("cdrskin: installed abort handler.\n");
+ else if(skin->preskin->abort_handler==2)
+ printf("cdrskin: will try to ignore any signals.\n");
+ else if(skin->preskin->abort_handler==3)
+ printf("cdrskin: installed hard abort handler.\n");
+ else if(skin->preskin->abort_handler==4)
+ printf("cdrskin: installed soft abort handler.\n");
+ else if(skin->preskin->abort_handler==-1)
+ printf("cdrskin: will install abort handler in eventual burn loop.\n");
+ }
+#endif /* ! Cdrskin_extra_leaN */
+
+ if(strlen(skin->preskin->raw_device_adr)>0 ||
+ strlen(skin->preskin->device_adr)>0) {
+ if(strlen(skin->preskin->device_adr)>0)
+ cpt= skin->preskin->device_adr;
+ else
+ cpt= skin->preskin->raw_device_adr;
+ if(strcmp(cpt,"ATA")!=0 && strcmp(cpt,"ATAPI")!=0 && strcmp(cpt,"SCSI")!=0){
+ ret= Cdrskin_dev_to_driveno(skin,cpt,&(skin->driveno),0);
+ if(ret<=0)
+ return(ret);
+ if(skin->verbosity>=Cdrskin_verbose_cmD) {
+ ret= burn_drive_get_adr(&(skin->drives[skin->driveno]), adr);
+ if(ret<=0)
+ adr[0]= 0;
+ printf("cdrskin: active drive number : %d '%s'\n",
+ skin->driveno,adr);
+ }
+ }
+ }
+ if(grab_and_wait_value>0) {
+ Cdrskin_grab_drive(skin,16);
+ for(k= 0; kpacifier_with_newline ? "" : "\r", k,
+ skin->pacifier_with_newline ? "\n" : " ");
+ usleep(1000000);
+ }
+ fprintf(stderr,
+ "%scdrskin: held drive grabbed for %d seconds \n",
+ skin->pacifier_with_newline ? "" : "\r", k);
+ Cdrskin_release_drive(skin,0);
+ }
+
+ if(skin->track_counter>0) {
+ skin->do_burn= 1;
+
+#ifndef Cdrskin_no_cdrfifO
+ if(!skin->do_direct_write) {
+ ret= Cdrskin_attach_fifo(skin,0);
+ if(ret<=0)
+ return(ret);
+ }
+#endif /* ! Cdrskin_no_cdrfifO */
+
+ }
+ return(1);
+}
+
+
+/** Initialize libburn, create a CdrskiN program run control object,
+ set eventual device whitelist, and obtain the list of available drives.
+ @param o Returns the CdrskiN object created
+ @param lib_initialized Returns whether libburn was initialized here
+ @param exit_value Returns after error the proposal for an exit value
+ @param flag bit0= do not scan for devices
+ @return <=0 error, 1 success
+*/
+int Cdrskin_create(struct CdrskiN **o, struct CdrpreskiN **preskin,
+ int *exit_value, int flag)
+{
+ int ret, stdio_drive= 0, mem;
+ struct CdrskiN *skin;
+ char reason[4096];
+
+ *o= NULL;
+ *exit_value= 0;
+
+ if(strlen((*preskin)->device_adr)>0) { /* disable scan for all others */
+ ClN(printf(
+ "cdrskin: NOTE : greying out all drives besides given dev='%s'\n",
+ (*preskin)->device_adr));
+ burn_drive_add_whitelist((*preskin)->device_adr);
+ if(strncmp((*preskin)->device_adr, "stdio:", 6)==0) {
+ ret= Cdrpreskin__allows_emulated_drives((*preskin)->device_adr+6,reason,0);
+ if((*preskin)->allow_emulated_drives && ret>0) {
+ stdio_drive= 1;
+ (*preskin)->demands_cdrskin_caps= 1;
+ } else if((*preskin)->allow_emulated_drives) {
+ fprintf(stderr,"cdrskin: SORRY : dev=stdio:... rejected despite --allow_emulated_drives\n");
+ fprintf(stderr,"cdrskin: SORRY : Reason: %s.\n", reason);
+ } else {
+ fprintf(stderr,"cdrskin: SORRY : dev=stdio:... works only with option --allow_emulated_drives\n");
+ if(ret<=0) {
+ fprintf(stderr,"cdrskin: SORRY : but: %s.\n", reason);
+ fprintf(stderr,
+ "cdrskin: SORRY : So this option would not help anyway.\n");
+ }
+ }
+ if(!stdio_drive) {
+ Cdrpreskin_consider_normal_user(0);
+ {*exit_value= 2; goto ex;}
+ }
+ }
+ }
+
+ ret= Cdrskin_new(&skin,*preskin,1);
+ if(ret<=0) {
+ fprintf(stderr,"cdrskin: FATAL : Creation of control object failed\n");
+ {*exit_value= 2; goto ex;}
+ }
+ *preskin= NULL; /* the preskin object now is under management of skin */
+ *o= skin;
+ if(skin->preskin->abort_handler==1 || skin->preskin->abort_handler==3 ||
+ skin->preskin->abort_handler==4)
+ Cleanup_set_handlers(Cleanup_handler_handlE, Cleanup_handler_funC,
+ Cleanup_handler_flaG);
+ else if(skin->preskin->abort_handler==2)
+ Cleanup_set_handlers(Cleanup_handler_handlE, Cleanup_handler_funC,
+ 2 | 8);
+
+ if(!(flag & 1))
+ printf("cdrskin: scanning for devices ...\n");
+ fflush(stdout);
+
+ if(skin->preskin->verbositypreskin,1);
+
+ if(stdio_drive) {
+ mem= skin->drive_is_busy;
+ skin->drive_is_busy= 1;
+ ret= burn_drive_scan_and_grab(&(skin->drives),skin->preskin->device_adr,0);
+ skin->drive_is_busy= mem;
+ if(Cdrskin__is_aborting(0)) {
+ fprintf(stderr,"cdrskin: ABORT : Startup aborted\n");
+ Cdrskin_abort(skin, 0); /* Never comes back */
+ }
+ if(ret <= 0) {
+ fprintf(stderr,"cdrskin: FATAL : Failed to grab emulated stdio-drive\n");
+ {*exit_value= 2; goto ex;}
+ }
+ skin->n_drives= 1;
+ skin->driveno= 0;
+ burn_drive_release(skin->drives[0].drive, 0);
+ } else if(flag & 1){
+ skin->n_drives= 0;
+ skin->driveno= 0;
+ } else {
+ while (!burn_drive_scan(&(skin->drives), &(skin->n_drives))) {
+ usleep(20000);
+ /* >>> ??? set a timeout ? */
+ }
+ if(skin->n_drives <= 0)
+ skin->driveno= -1;
+ }
+
+ burn_msgs_set_severities(skin->preskin->queue_severity,
+ skin->preskin->print_severity, "cdrskin: ");
+
+ /* This prints the eventual queued messages */
+ Cdrpreskin_queue_msgs(skin->preskin,0);
+
+ if(!(flag & 1))
+ printf("cdrskin: ... scanning for devices done\n");
+ fflush(stdout);
+ex:;
+ return((*exit_value)==0);
+}
+
+
+/** Perform the activities which were ordered by setup
+ @param skin Knows what to do
+ @param exit_value Returns the proposal for an exit value
+ @param flag Unused yet
+ @return <=0 error, 1 success
+*/
+int Cdrskin_run(struct CdrskiN *skin, int *exit_value, int flag)
+{
+ int ret;
+
+ *exit_value= 0;
+
+ if(skin->preskin->allow_setuid==0 && getuid()!=geteuid()) {
+ fprintf(stderr,"\n");
+ fprintf(stderr,"cdrskin: WARNING : THIS PROGRAM WAS TREATED WITH chmod u+s WHICH IS INSECURE !\n");
+ fprintf(stderr,
+ "cdrskin: HINT : Consider to allow rw-access to the writer device and\n");
+ fprintf(stderr,
+ "cdrskin: HINT : to run cdrskin under your normal user identity.\n");
+ fprintf(stderr,
+ "cdrskin: HINT : Option --allow_setuid disables this safety check.\n");
+ fprintf(stderr,"\n");
+ }
+
+ if(skin->do_devices) {
+ if(skin->n_drives<=0 && skin->preskin->scan_demands_drive)
+ {*exit_value= 4; goto no_drive;}
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_scanbus(skin, 1 | (2 * (skin->do_devices == 2)));
+ if(ret<=0) {
+ fprintf(stderr,"cdrskin: FATAL : --devices failed.\n");
+ {*exit_value= 4; goto ex;}
+ }
+ }
+
+ if(skin->do_scanbus) {
+ if(skin->n_drives<=0 && skin->preskin->scan_demands_drive)
+ {*exit_value= 5; goto no_drive;}
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_scanbus(skin,0);
+ if(ret<=0)
+ fprintf(stderr,"cdrskin: FATAL : -scanbus failed.\n");
+ {*exit_value= 5*(ret<=0); goto ex;}
+ }
+ if(skin->do_load > 0) {
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_grab_drive(skin,8);
+ if(ret>0) {
+ if(skin->do_load==2 && !skin->do_eject) {
+ printf(
+ "cdrskin: NOTE : Option -lock orders program to exit with locked tray.\n");
+ printf(
+ "cdrskin: HINT : Run cdrskin with option -eject to unlock the drive tray.\n");
+ } else if(!skin->do_eject)
+ printf(
+ "cdrskin: NOTE : option -load orders program to exit after loading tray.\n");
+ Cdrskin_release_drive(skin,(skin->do_load==2)<<1);
+ }
+ {*exit_value= 14*(ret<=0); goto ex;}
+ }
+ if(skin->do_checkdrive) {
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_checkdrive(skin,"",(skin->do_checkdrive==2)<<1);
+ {*exit_value= 6*(ret<=0); goto ex;}
+ }
+ if(skin->do_msinfo) {
+ if(skin->n_drives<=0)
+ {*exit_value= 12; goto no_drive;}
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_msinfo(skin,0);
+ if(ret<=0)
+ {*exit_value= 12; goto ex;}
+ }
+ if(skin->do_atip) {
+ if(skin->n_drives<=0)
+ {*exit_value= 7; goto no_drive;}
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_atip(skin, skin->do_atip == 4 ? 4 :
+ (skin->do_atip>1) | (2 * (skin->do_atip > 2)));
+ if(ret<=0)
+ {*exit_value= 7; goto ex;}
+ }
+ if(skin->do_cdtext_to_textfile) {
+ ret= Cdrskin_cdtext_to_file(skin, skin->cdtext_to_textfile_path, 15);
+ if(ret<=0)
+ {*exit_value= 18; goto ex;}
+ }
+ if(skin->do_cdtext_to_vt07) {
+ ret= Cdrskin_cdtext_to_file(skin, skin->cdtext_to_vt07_path, 1);
+ if(ret<=0)
+ {*exit_value= 19; goto ex;}
+ }
+ if(skin->do_extract_audio) {
+ ret= Cdrskin_extract_audio_to_dir(skin, skin->extract_audio_dir,
+ skin->extract_basename,
+ skin->extract_audio_tracks,
+ skin->extract_flags & 8);
+ if(ret<=0)
+ {*exit_value= 19; goto ex;}
+ }
+ if(skin->do_list_speeds) {
+ if(skin->n_drives<=0)
+ {*exit_value= 17; goto no_drive;}
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_list_speeds(skin, 0);
+ if(ret<=0)
+ {*exit_value= 17; goto ex;}
+ }
+ if(skin->do_list_formats) {
+ if(skin->n_drives<=0)
+ {*exit_value= 16; goto no_drive;}
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_list_formats(skin, 0);
+ if(ret<=0)
+ {*exit_value= 16; goto ex;}
+ }
+ if(skin->do_blank) {
+ if(skin->n_drives<=0)
+ {*exit_value= 8; goto no_drive;}
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_blank(skin,0);
+ if(ret<=0)
+ {*exit_value= 8; goto ex;}
+ }
+ if(skin->do_direct_write) {
+ skin->do_burn= 0;
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_direct_write(skin,0);
+ if(ret<=0)
+ {*exit_value= 13; goto ex;}
+ }
+ if(skin->do_burn || skin->tell_media_space) {
+ if(skin->n_drives<=0)
+ {*exit_value= 10; goto no_drive;}
+ if(Cdrskin__is_aborting(0))
+ goto ex;
+ ret= Cdrskin_burn(skin,0);
+ if(ret<=0)
+ {*exit_value= 10; goto ex;}
+ }
+
+#ifdef Libburn_develop_quality_scaN
+
+ if(skin->do_qcheck) {
+ ret= Cdrskin_qcheck(skin, 0);
+ if(ret<=0)
+ {*exit_value= 15; goto ex;}
+ }
+
+#endif /* Libburn_develop_quality_scaN */
+
+ex:;
+ if(Cdrskin__is_aborting(0))
+ Cdrskin_abort(skin, 0); /* Never comes back */
+ return((*exit_value)==0);
+no_drive:;
+ fprintf(stderr,"cdrskin: FATAL : This run would need an accessible drive\n");
+ goto ex;
+}
+
+
+int main(int argc, char **argv)
+{
+ int ret,exit_value= 0,lib_initialized= 0,i,result_fd= -1, do_not_scan;
+ struct CdrpreskiN *preskin= NULL, *h_preskin= NULL;
+ struct CdrskiN *skin= NULL;
+ char *lean_id= "";
+#ifdef Cdrskin_extra_leaN
+ lean_id= ".lean";
+#endif
+
+ /* For -msinfo: Redirect normal stdout to stderr */
+ for(i=1; ido_not_scan; /* preskin will vanish in Cdrskin_create */
+ ret= Cdrskin_create(&skin,&preskin,&exit_value, preskin->do_not_scan);
+ if(ret<=0)
+ {exit_value= 2; goto ex;}
+ if(skin->n_drives<=0 && !do_not_scan) {
+ fprintf(stderr,"cdrskin: NOTE : No usable drive detected.\n");
+ if(getuid()!=0) {
+ fprintf(stderr,
+ "cdrskin: HINT : Run this program as superuser with option --devices\n");
+ fprintf(stderr,
+ "cdrskin: HINT : Allow rw-access to the dev='...' file of the burner.\n");
+ fprintf(stderr,
+ "cdrskin: HINT : Busy drives are invisible. (Busy = open O_EXCL)\n");
+ }
+ }
+
+ ret= Cdrskin_setup(skin,argc,argv,0);
+ if(ret<=0)
+ {exit_value= 3; goto ex;}
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: called as : %s\n",argv[0]));
+
+ if(skin->verbosity>=Cdrskin_verbose_debuG) {
+#ifdef Cdrskin_new_api_tesT
+ ClN(fprintf(stderr,"cdrskin_debug: Compiled with option -experimental\n"));
+#endif
+ }
+
+ if(!Cdrskin__is_aborting(0))
+ Cdrskin_run(skin,&exit_value,0);
+
+ex:;
+ if(Cdrskin__is_aborting(0))
+ Cdrskin_abort(skin, 0); /* Never comes back */
+
+ if(preskin!=NULL)
+ h_preskin= preskin;
+ else if(skin!=NULL)
+ h_preskin= skin->preskin;
+ if(h_preskin!=NULL) {
+ if(skin!=NULL)
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "cdrskin_debug: demands_cdrecord_caps= %d , demands_cdrskin_caps= %d\n",
+ h_preskin->demands_cdrecord_caps, h_preskin->demands_cdrskin_caps));
+
+ if(exit_value && h_preskin->demands_cdrecord_caps>0 &&
+ h_preskin->demands_cdrskin_caps<=0) { /* prepare fallback */
+ /* detach preskin from managers which would destroy it */
+ preskin= NULL;
+ if(skin!=NULL)
+ skin->preskin= NULL;
+ } else
+ h_preskin= NULL; /* prevent fallback */
+ }
+ if(skin!=NULL) {
+ Cleanup_set_handlers(NULL,NULL,1);
+ if(skin->preskin!=NULL)
+ Cdrskin_eject(skin,0);
+ Cdrskin_destroy(&skin,0);
+ }
+ Cdrpreskin_destroy(&preskin,0);
+ if(lib_initialized)
+ burn_finish();
+ if(h_preskin!=NULL)
+ Cdrpreskin_fallback(h_preskin,argc,argv,0); /* never come back */
+ exit(exit_value);
+}
diff --git a/libburn/branches/1.4.6/cdrskin/cdrskin_eng.html b/libburn/branches/1.4.6/cdrskin/cdrskin_eng.html
new file mode 100644
index 00000000..1c7fab4c
--- /dev/null
+++ b/libburn/branches/1.4.6/cdrskin/cdrskin_eng.html
@@ -0,0 +1,569 @@
+
+
+
+
+
+
+cdrskin homepage english
+
+
+
+
+
+
+
+
+
+ Homepage of
+ cdrskin
+
+Limited cdrecord compatibility wrapper for libburn
+
+
+
+
Purpose:
+Burns preformatted data to CD, DVD, and BD media:
+CD-R, DVD-R, DVD-R DL, DVD+R, DVD+R DL, BD-R, CD-RW,
+DVD-RW, DVD-RAM, DVD+RW, BD-RE
+
+
+This program system has been tested on Intel/AMD with Linux, FreeBSD,
+OpenSolaris, and NetBSD based operating systems.
+Ports to other usable systems are appreciated. Reports are welcome.
+
+
+
+
+
+Example how to setup K3b to use cdrskin for burning data CD projects.
+
+(K3b
+is a GUI frontend which uses cdrecord for CD burning.)
+
+
+
+
+
+
+