From 0abe149510d7a5bd6a08bbb362ed2a47c049f150 Mon Sep 17 00:00:00 2001
From: Mario Danic
Date: Sun, 11 May 2008 10:26:51 +0000
Subject: [PATCH] Tagged libburn-0.4.6
---
AUTHORS | 3 +
CONTRIBUTORS | 6 +
COPYING | 280 +
COPYRIGHT | 18 +
ChangeLog | 1 +
INSTALL | 234 +
Makefile.am | 202 +
NEWS | 1 +
README | 332 +
acinclude.m4 | 22 +
bootstrap | 10 +
cdrskin/README | 481 ++
cdrskin/add_ts_changes_to_libburn_0_4_6 | 244 +
cdrskin/add_ts_changes_to_libburn_0_4_7 | 245 +
cdrskin/cdrecord_spy.sh | 37 +
cdrskin/cdrfifo.c | 1253 ++++
cdrskin/cdrfifo.h | 171 +
cdrskin/cdrskin.1 | 1334 ++++
cdrskin/cdrskin.c | 8292 +++++++++++++++++++++++
cdrskin/cdrskin_eng.html | 500 ++
cdrskin/cdrskin_timestamp.h | 1 +
cdrskin/changelog.txt | 5561 +++++++++++++++
cdrskin/cleanup.c | 215 +
cdrskin/cleanup.h | 34 +
cdrskin/compile_cdrskin.sh | 216 +
cdrskin/convert_man_to_html.sh | 78 +
cdrskin/doener_150x200_tr.png | Bin 0 -> 10595 bytes
cdrskin/doener_150x200_tr_octx.png | Bin 0 -> 9433 bytes
cdrskin/make_timestamp.sh | 9 +
cdrskin/wiki_plain.txt | 318 +
configure.ac | 181 +
doc/Makefile | 4 +
doc/comments | 180 +
doc/cookbook.txt | 1201 ++++
doc/ddlp.txt | 388 ++
doc/doxygen.conf.in | 1300 ++++
libburn-1.pc.in | 12 +
libburn/Makefile | 4 +
libburn/Makefile.am | 65 +
libburn/asserts.txt | 792 +++
libburn/async.c | 545 ++
libburn/async.h | 14 +
libburn/back_hacks.h | 54 +
libburn/cleanup.c | 215 +
libburn/cleanup.h | 34 +
libburn/crc.c | 122 +
libburn/crc.h | 9 +
libburn/ddlpa.c | 614 ++
libburn/ddlpa.h | 107 +
libburn/debug.c | 35 +
libburn/debug.h | 8 +
libburn/drive.c | 2469 +++++++
libburn/drive.h | 128 +
libburn/error.h | 8 +
libburn/file.c | 542 ++
libburn/file.h | 62 +
libburn/init.c | 416 ++
libburn/init.h | 21 +
libburn/lec.c | 451 ++
libburn/lec.h | 12 +
libburn/libburn.h | 2369 +++++++
libburn/libdax_audioxtr.c | 326 +
libburn/libdax_audioxtr.h | 229 +
libburn/libdax_msgs.c | 439 ++
libburn/libdax_msgs.h | 682 ++
libburn/libdax_msgs_to_xyz_msgs.sh | 37 +
libburn/mmc.c | 3494 ++++++++++
libburn/mmc.h | 80 +
libburn/null.c | 31 +
libburn/null.h | 10 +
libburn/options.c | 447 ++
libburn/options.h | 100 +
libburn/os-freebsd.h | 61 +
libburn/os-linux.h | 76 +
libburn/os.h | 34 +
libburn/read.c | 490 ++
libburn/read.h | 14 +
libburn/sbc.c | 114 +
libburn/sbc.h | 18 +
libburn/sector.c | 846 +++
libburn/sector.h | 35 +
libburn/sg-freebsd-port.c | 631 ++
libburn/sg-freebsd.c | 673 ++
libburn/sg-linux.c | 1444 ++++
libburn/sg.c | 17 +
libburn/sg.h | 36 +
libburn/source.c | 55 +
libburn/source.h | 10 +
libburn/spc.c | 997 +++
libburn/spc.h | 62 +
libburn/structure.c | 517 ++
libburn/structure.h | 112 +
libburn/toc.c | 141 +
libburn/toc.h | 48 +
libburn/transport.h | 361 +
libburn/util.c | 60 +
libburn/util.h | 8 +
libburn/write.c | 2334 +++++++
libburn/write.h | 48 +
libcevap/cgen.c | 1503 ++++
libcevap/cgen.h | 35 +
libcevap/cgen.txt | 222 +
libcevap/ctyp.c | 364 +
libcevap/ctyp.h | 41 +
libcevap/extract_cgen_input.sh | 30 +
libcevap/libcevap_gen.sh | 16 +
libcevap/libdax_equip.gif | Bin 0 -> 10751 bytes
libcevap/libdax_job.gif | Bin 0 -> 10532 bytes
libcevap/libdax_model.txt | 944 +++
libcevap/libdax_overview.gif | Bin 0 -> 12521 bytes
libcevap/main.c | 39 +
libcevap/smem.c | 445 ++
libcevap/smem.h | 165 +
test/Makefile | 4 +
test/dewav.c | 215 +
test/fake_au.c | 164 +
test/libburner.c | 797 +++
test/open-cd-excl.c | 133 +
test/poll.c | 78 +
test/structest.c | 48 +
test/telltoc.c | 921 +++
version.h.in | 3 +
122 files changed, 53744 insertions(+)
create mode 100644 AUTHORS
create mode 100644 CONTRIBUTORS
create mode 100644 COPYING
create mode 100644 COPYRIGHT
create mode 100644 ChangeLog
create mode 100644 INSTALL
create mode 100644 Makefile.am
create mode 100644 NEWS
create mode 100644 README
create mode 100644 acinclude.m4
create mode 100755 bootstrap
create mode 100644 cdrskin/README
create mode 100755 cdrskin/add_ts_changes_to_libburn_0_4_6
create mode 100755 cdrskin/add_ts_changes_to_libburn_0_4_7
create mode 100755 cdrskin/cdrecord_spy.sh
create mode 100644 cdrskin/cdrfifo.c
create mode 100644 cdrskin/cdrfifo.h
create mode 100644 cdrskin/cdrskin.1
create mode 100644 cdrskin/cdrskin.c
create mode 100644 cdrskin/cdrskin_eng.html
create mode 100644 cdrskin/cdrskin_timestamp.h
create mode 100644 cdrskin/changelog.txt
create mode 100644 cdrskin/cleanup.c
create mode 100644 cdrskin/cleanup.h
create mode 100755 cdrskin/compile_cdrskin.sh
create mode 100755 cdrskin/convert_man_to_html.sh
create mode 100644 cdrskin/doener_150x200_tr.png
create mode 100644 cdrskin/doener_150x200_tr_octx.png
create mode 100755 cdrskin/make_timestamp.sh
create mode 100644 cdrskin/wiki_plain.txt
create mode 100644 configure.ac
create mode 100644 doc/Makefile
create mode 100644 doc/comments
create mode 100644 doc/cookbook.txt
create mode 100644 doc/ddlp.txt
create mode 100644 doc/doxygen.conf.in
create mode 100644 libburn-1.pc.in
create mode 100644 libburn/Makefile
create mode 100644 libburn/Makefile.am
create mode 100644 libburn/asserts.txt
create mode 100644 libburn/async.c
create mode 100644 libburn/async.h
create mode 100644 libburn/back_hacks.h
create mode 100644 libburn/cleanup.c
create mode 100644 libburn/cleanup.h
create mode 100644 libburn/crc.c
create mode 100644 libburn/crc.h
create mode 100644 libburn/ddlpa.c
create mode 100644 libburn/ddlpa.h
create mode 100644 libburn/debug.c
create mode 100644 libburn/debug.h
create mode 100644 libburn/drive.c
create mode 100644 libburn/drive.h
create mode 100644 libburn/error.h
create mode 100644 libburn/file.c
create mode 100644 libburn/file.h
create mode 100644 libburn/init.c
create mode 100644 libburn/init.h
create mode 100644 libburn/lec.c
create mode 100644 libburn/lec.h
create mode 100644 libburn/libburn.h
create mode 100644 libburn/libdax_audioxtr.c
create mode 100644 libburn/libdax_audioxtr.h
create mode 100644 libburn/libdax_msgs.c
create mode 100644 libburn/libdax_msgs.h
create mode 100755 libburn/libdax_msgs_to_xyz_msgs.sh
create mode 100644 libburn/mmc.c
create mode 100644 libburn/mmc.h
create mode 100644 libburn/null.c
create mode 100644 libburn/null.h
create mode 100644 libburn/options.c
create mode 100644 libburn/options.h
create mode 100644 libburn/os-freebsd.h
create mode 100644 libburn/os-linux.h
create mode 100644 libburn/os.h
create mode 100644 libburn/read.c
create mode 100644 libburn/read.h
create mode 100644 libburn/sbc.c
create mode 100644 libburn/sbc.h
create mode 100644 libburn/sector.c
create mode 100644 libburn/sector.h
create mode 100644 libburn/sg-freebsd-port.c
create mode 100644 libburn/sg-freebsd.c
create mode 100644 libburn/sg-linux.c
create mode 100644 libburn/sg.c
create mode 100644 libburn/sg.h
create mode 100644 libburn/source.c
create mode 100644 libburn/source.h
create mode 100644 libburn/spc.c
create mode 100644 libburn/spc.h
create mode 100644 libburn/structure.c
create mode 100644 libburn/structure.h
create mode 100644 libburn/toc.c
create mode 100644 libburn/toc.h
create mode 100644 libburn/transport.h
create mode 100644 libburn/util.c
create mode 100644 libburn/util.h
create mode 100644 libburn/write.c
create mode 100644 libburn/write.h
create mode 100644 libcevap/cgen.c
create mode 100644 libcevap/cgen.h
create mode 100644 libcevap/cgen.txt
create mode 100644 libcevap/ctyp.c
create mode 100644 libcevap/ctyp.h
create mode 100755 libcevap/extract_cgen_input.sh
create mode 100755 libcevap/libcevap_gen.sh
create mode 100644 libcevap/libdax_equip.gif
create mode 100644 libcevap/libdax_job.gif
create mode 100644 libcevap/libdax_model.txt
create mode 100644 libcevap/libdax_overview.gif
create mode 100644 libcevap/main.c
create mode 100644 libcevap/smem.c
create mode 100644 libcevap/smem.h
create mode 100644 test/Makefile
create mode 100644 test/dewav.c
create mode 100644 test/fake_au.c
create mode 100644 test/libburner.c
create mode 100644 test/open-cd-excl.c
create mode 100644 test/poll.c
create mode 100644 test/structest.c
create mode 100644 test/telltoc.c
create mode 100644 version.h.in
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..6a964a5
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Mario Danic
+Thomas Schmitt
+
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 0000000..31b77c5
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,6 @@
+Joe Neeman
+Philippe Rouquier
+Gabriel Craciunescu
+George Danchev
+Jean-Francois Wauthy
+Lorenzo Taylor
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5a965fb
--- /dev/null
+++ b/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/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..7b7b4b7
--- /dev/null
+++ b/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-2008 Mario Danic, Thomas Schmitt
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 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/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..7001d0f
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1 @@
+nothing here now
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5458714
--- /dev/null
+++ b/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/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..f1a4e42
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,202 @@
+pkgconfigdir=$(libdir)/pkgconfig
+libincludedir=$(includedir)/libburn
+
+lib_LTLIBRARIES = libburn/libburn.la
+
+## ========================================================================= ##
+
+# Build libraries
+libburn_libburn_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+libburn_libburn_la_LIBADD = $(LIBBURN_ARCH_LIBS) $(THREAD_LIBS)
+libburn_libburn_la_SOURCES = \
+ libburn/async.c \
+ libburn/async.h \
+ libburn/back_hacks.h \
+ 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/error.h \
+ libburn/file.c \
+ libburn/file.h \
+ libburn/init.c \
+ libburn/init.h \
+ libburn/lec.c \
+ libburn/lec.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 \
+ version.h
+
+## libburn/sg-@ARCH@.c \
+
+libinclude_HEADERS = \
+ libburn/libburn.h
+
+## ========================================================================= ##
+
+## Build test applications
+noinst_PROGRAMS = \
+ test/libburner \
+ test/telltoc \
+ test/dewav \
+ test/fake_au \
+ test/poll \
+ test/structest
+
+bin_PROGRAMS = \
+ cdrskin/cdrskin
+
+test_libburner_CPPFLAGS = -Ilibburn
+test_libburner_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
+test_libburner_SOURCES = test/libburner.c
+test_telltoc_CPPFLAGS = -Ilibburn
+test_telltoc_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
+test_telltoc_SOURCES = test/telltoc.c
+test_dewav_CPPFLAGS = -Ilibburn
+test_dewav_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
+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) $(THREAD_LIBS)
+test_poll_SOURCES = test/poll.c
+test_structest_CPPFLAGS = -Ilibburn
+test_structest_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
+test_structest_SOURCES = test/structest.c
+
+## cdrskin construction site - ts A60816 - A80510
+cdrskin_cdrskin_CPPFLAGS = -Ilibburn
+cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_4_6
+
+# cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
+# ts A80123, change proposed by Simon Huggins to cause dynamic libburn linking
+cdrskin_cdrskin_LDADD = libburn/libburn.la $(THREAD_LIBS)
+
+cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cdrskin_timestamp.h
+##
+## Open questions: how to compute $timestamp and express -DX="$timestamp"
+##
+
+
+
+## ========================================================================= ##
+
+## 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)
+
+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) \
+ $(test_structest_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 = \
+ libburn-1.pc.in \
+ version.h.in \
+ doc/comments \
+ doc/doxygen.conf.in \
+ 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/os-freebsd.h \
+ libburn/os-linux.h \
+ libburn/sg-freebsd.c \
+ libburn/sg-linux.c \
+ COPYING \
+ NEWS \
+ ChangeLog \
+ INSTALL \
+ $(man_MANS)
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..7001d0f
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+nothing here now
diff --git a/README b/README
new file mode 100644
index 0000000..2f1ac8b
--- /dev/null
+++ b/README
@@ -0,0 +1,332 @@
+------------------------------------------------------------------------------
+ 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-2008 Mario Danic, Thomas Schmitt
+
+Still containing parts of
+Libburn. By Derek Foreman and
+ Ben Jansens
+Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
+These parts are to be replaced by own code of above libburnia-project.org
+copyright holders and then libburnia-project.org is to be their sole copyright.
+This is done to achieve the right to issue the clarification and the
+commitment as written at the end of this text.
+The rights and merits of the Libburn-copyright holders Derek Foreman and
+Ben Jansens will be duely respected.
+
+This libburnia-project.org toplevel README (C) 2006-2008 Thomas Schmitt
+------------------------------------------------------------------------------
+
+ Build and Installation
+
+Our build system is based on autotools. For preparing the build of a SVN
+snapshot you will need autotools of at least version 1.7.
+Check out from SVN by
+ svn co http://svn.libburnia-project.org/libburn/trunk libburn
+go into directory libburn and apply autotools by
+ ./bootstrap
+
+Alternatively you may unpack a release tarball for which you do not need
+autotools installed.
+
+To build a libburnia-project.org subproject it should be sufficient to go
+into its toplevel directory (here: "libburn") and execute
+ ./configure --prefix=/usr
+ make
+
+To make the libraries accessible for running resp. developing applications
+and to install the cdrecord compatibility binary cdrskin, do:
+ make install
+
+
+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 only CD media and all single layer DVD media except DVD+R.
+
+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.
+
+Our scope is currently Linux 2.4 and 2.6 only. For ports to other systems
+we would need : login on a development machine resp. a live OS on CD or DVD,
+advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
+volunteers for testing of realistic use cases.
+
+We have a well tested code base for burning data and audio CDs and many DVD
+types. The burn API is quite comprehensively documented and can be used to
+build a presentable application.
+We have a functional binary which emulates the core use cases of cdrecord in
+order to prove that usability, and in order to allow you to explore libburn's
+scope by help of existing cdrecord frontends.
+
+ISO 9660 filesystems with Rock Ridge and Joliet extensions can be created
+and manipulated quite freely. This capability together with our burn capability
+makes possible a single binary application which covers all steps of image
+composition, updating and writing. Quite unique in the Linux world.
+
+The project components (list subject to growth, hopefully):
+
+- libburn is the library by which preformatted data get onto optical media.
+ It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
+ /dev/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.
+ libisofs is to be the foundation of our upcoming mkisofs emulation.
+
+- libisoburn is an add-on to libburn and libisofs which coordinates both and
+ also allows to grow ISO-9660 filesystem images on multi-session
+ media as well as on overwriteable media via the same API.
+ All media peculiarities are handled automatically.
+
+- cdrskin is a limited cdrecord compatibility wrapper for libburn.
+ cdrecord is a powerful GPL'ed burn program included in Joerg
+ Schilling's cdrtools. cdrskin strives to be a second source for
+ the services traditionally provided by cdrecord. Additionally it
+ provides libburn's DVD capabilities, where only -sao is compatible
+ with cdrecord.
+ cdrskin does not contain any bytes copied from cdrecord's sources.
+ Many bytes have been copied from the message output of cdrecord
+ runs, though.
+ See cdrskin/README for more.
+
+- xorriso is an application of all three libraries which creates, loads,
+ manipulates and writes ISO 9660 filesystem images with
+ Rock Ridge extensions. Manipulation is not only adding or
+ overwriting of files but also deletion, renaming, and attribute
+ changing.
+ See xorriso/README for more.
+
+- "test" is a collection of application gestures and examples given by the
+ authors of the library features. The burn API example of libburn
+ is named test/libburner.c . The API for media information inquiry is
+ demonstrated in test/telltoc.c .
+ Explore these examples if you look for inspiration.
+
+We 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).
+
+
+------------------------------------------------------------------------------
+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 publically regret it and then - after i
+ got the opportunity to move in with cdrskin - gave me true reason to
+ personally apologize to Derek Foreman, Ben Jansens and the contibutors at
+ 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 upcomming integrated application for manipulating and writing
+ ISO 9660 + Rock Ridge images. cdrskin-0.4.0 got capabilities like growisofs
+ by these enhancements: growing of overwriteable media and disk files.
+ Taking again a bow towards Andy Polyakov.
+
+- 26th Januar 2008 version 0.4.2 rectifies the version numbering so that we
+ reliably release libburn.so.4 as should have been done since libburn-0.3.2.
+ cdrskin now is by default linked dynamically and does a runtime check
+ to ensure not to be started with a libburn which is older than itself.
+
+- 3rd Feb 2008 libisofs-0.2.x (.so.5) has been deprecated.
+
+- 14th Feb 2008 libisofs-0.6.2 permanently replaces the old libisofs-0.2.x.
+ It is the first release of new libisofs.so.6 which will guarantee future
+ API/ABI compatibility for its whole feature set.
+
+- 15th Feb 2008 libisoburn-0.1.0 (.so.1) coordinates libisofs and libburn for
+ the purpose of ISO image reading and writing. It emulates multi-session on
+ overwriteable media. Application xorriso makes use of all three libraries.
+
+- 8th Apr 2008 libburn-0.4.4 has proven to be capable of burning to DVD+R/DL
+ and read performance on disk file pseudo-drives has been improved.
+
+- 27th Apr 2008 libisofs-0.6.4 can now read data file content from images
+ and can map pieces of disk files onto image files. Image directory iteration
+ has been enhanced. Input data streams and extended information have been
+ exposed in the API to allow future development.
+
+- 29th Apr 2008 libisoburn-0.1.4 was made more efficient with reading of
+ image tree nodes. It now depends on libisofs-0.6.4 and libburn-0.4.4.
+ xorriso makes use of new libisofs features by performing incremental
+ updates of directory trees and by cutting oversized data files into
+ pieces. A primitive single session emulation of cdrcord and mkisofs is
+ provided.
+
+- 10th May 2008 libburn-0.4.6 supports formatting and writing of BD-RE,
+ full nominal speed for DVD-RAM and BD-RE. cdrskin has a unified blank
+ type with automatic media state recognition.
+
+
+------------------------------------------------------------------------------
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation. To be exact: version 2 of that License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 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.
+
+Thus you may link our libraries dynamically with applications
+which are not under GPL. You may distribute our libraries and
+application tools in binary form, if you fulfill the usual
+condition of GPL to offer a copy of the source code -altered
+or unaltered- under GPL.
+
+We ask you politely to use our work in open source spirit
+and with the due reference to the entire open source community.
+
+If there should really arise the case where above clarification
+does not suffice to fulfill a clear and neat request in open source
+spirit that would otherwise be declined for mere formal reasons,
+only in that case we will duely consider to issue a special license
+covering only that special case.
+It is the open source idea of responsible freedom which will be
+decisive and you will have to prove that you exhausted all own
+means to qualify for GPL.
+
+For now we are firmly committed to maintain one single license: GPL.
+
+signed: Mario Danic, Thomas Schmitt
+
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..861847b
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,22 @@
+AC_DEFUN([TARGET_SHIZZLE],
+[
+ ARCH=""
+
+ AC_MSG_CHECKING([target operating system])
+
+ case $target in
+ *-*-linux*)
+ ARCH=linux
+ LIBBURN_ARCH_LIBS=
+ ;;
+ *-*-freebsd*)
+ ARCH=freebsd
+ LIBBURN_ARCH_LIBS=-lcam
+ ;;
+ *)
+ AC_ERROR([You are attempting to compile for an unsupported platform])
+ ;;
+ esac
+
+ AC_MSG_RESULT([$ARCH])
+])
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 0000000..86709bf
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,10 @@
+#!/bin/sh -x
+
+aclocal
+libtoolize --copy --force
+autoconf
+
+# ts A61101 : libburn is not prepared for config.h
+# autoheader
+
+automake --foreign --add-missing --copy --include-deps
diff --git a/cdrskin/README b/cdrskin/README
new file mode 100644
index 0000000..b2bb0f8
--- /dev/null
+++ b/cdrskin/README
@@ -0,0 +1,481 @@
+------------------------------------------------------------------------------
+ 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-0.4.6.pl00.tar.gz
+Copyright (C) 2006-2008 Thomas Schmitt, provided under GPL version 2.
+------------------------------------------------------------------------------
+
+
+cdrskin is a limited cdrecord compatibility wrapper which allows to use
+most of the libburn features from the command line.
+
+Currently it is only supported on Linux with kernels >= 2.4.
+
+By using this software you agree to the disclaimer at the end of this text
+"This software is provided as is. There is no warranty implied and ..."
+
+
+ Compilation, First Glimpse, Installation
+
+Obtain cdrskin-0.4.6.pl00.tar.gz, take it to a directory of your choice and do:
+
+ tar xzf cdrskin-0.4.6.pl00.tar.gz
+ cd cdrskin-0.4.6
+
+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. Installation of libburn is
+beyond the scope of cdrskin. For this, see included libburn docs.
+
+In order to surely get a standalone binary, execute
+
+ cdrskin/compile_cdrskin.sh
+
+Version identification and help texts available afterwards:
+ cdrskin/cdrskin -version
+ cdrskin/cdrskin --help
+ cdrskin/cdrskin -help
+ 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.
+
+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 statically 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'
+
+So full and insecure enabling of both for everybody would look like
+
+ chmod a+rw /dev/sr0 /dev/sr1
+
+This is equivalent to the traditional setup chmod a+x,u+s cdrecord.
+
+I strongly discourage to run cdrskin with setuid root or via sudo !
+It is not checked for the necessary degree of hacker safety.
+
+Consider to put all authorized users into group "floppy", to chgrp the
+device file to that group and to disallow w-access to others.
+
+Helpful with Linux kernel 2.4 is a special SCSI feature:
+It is possible to address a scsi(-emulated) drive via associated device files
+which are not listed by option --devices but point to the same SCSI addresses
+as listed device files. This addressing via e.g. /dev/sr0 or /dev/scd1 is
+compatible with generic read programs like dd and with write program growisofs.
+For finding /dev/sg1 from /dev/sr0, the program needs rw-access to both files.
+
+
+ Usage examples
+
+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
+
+Make used CD-RW or used unformatted DVD-RW writeable again
+ cdrskin -v dev=0,1,0 blank=fast -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 -tao 2.iso
+ cdrskin dev=/dev/hdc padsize=300k -multi -tao 3.iso
+ cdrskin dev=/dev/hdc padsize=300k -tao 4.iso
+
+Get multi-session info for option -C of program mkisofs:
+ c_values=$(cdrskin dev=/dev/hdc -msinfo 2>/dev/null)
+ mkisofs ... -C "$c_values" ...
+
+Burn a compressed afio archive to media on-the-fly
+ find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 -tao \
+ 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
+
+
+ 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.
+
+DVD support is restricted to single layer DVD for now. Double layer media
+are implemented but untested.
+On the other hand, the capability of multi-session and of writing streams
+of unpredicted lenght surpass the current DVD capabilities of cdrecord.
+
+
+ Inspiration and Standard
+
+cdrskin combines the command line interface standard set by cdrecord with
+libburn, which is a control software for optical drives according to standard
+MMC-5. For particular CD legacy commands, standards MMC-3 and MMC-1 apply.
+
+For the original meaning of cdrecord options see :
+ man cdrecord
+ (http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html)
+Do not bother Joerg Schilling with any cdrskin problems.
+(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
+ this "don't bother Joerg" demand.)
+
+cdrskin does not contain any bytes copied from cdrecord's sources. Many bytes
+have been copied from the message output of cdrecord runs, though. I am
+thankful to Joerg Schilling for every single one of them.
+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.
+
+Option --grow_overwriteable_iso allows -multi (although unneeded), enables
+-msinfo and -toc, and makes blank=fast an invalidator for ISO filesystems
+on overwriteable media.
+
+Initial session (equivalent to growisofs -Z):
+ mkisofs ... | cdrskin --grow_overwriteable_iso blank=fast ...
+
+Add-on session (equivalent to growisofs -M):
+ cparms=$(cdrskin dev=/dev/sr0 --grow_overwriteable_iso -msinfo)
+ mkisofs -C "$cparms" -M /dev/sr0 ... | \
+ cdrskin dev=/dev/sr0 --grow_overwriteable_iso ... -
+
+
+ DVD-RW and DVD-R
+
+DVD-RW are usable if formatted to state "Restricted Overwrite" or if in state
+"Sequential Recording". DVD-R are always in sequential state.
+
+"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 preferrably "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 and DVD+R/DL
+
+From the view of cdrskin they behave much like DVD-R. Each track gets wrapped
+into an own session, though.
+DVD+R/DL appear as extra large DVD+R. cdrskin does not allow to set the address
+of the layer break where ia reading drive might show some delay while switching
+between both media layers.
+
+
+ Emulated Drives
+
+cdrskin can use filesystem objects as emulated drives. Regular files or block
+devices appear similar to DVD-RAM. Other file types resemble blank DVD-R.
+Necessary precondition is option --allow_emulated_drives which is not accepted
+if cdrskin took another user identity because of the setuid bit of its access
+permissions.
+Addresses of emulated drives begin with prefix "stdio:". E.g.
+ dev=stdio:/tmp/my_pseudo_drive
+
+For safety reasons the superuser is only allowed to use /dev/null as emulated
+drive. See man page section FILES for a way to lift that ban.
+
+
+------------------------------------------------------------------------------
+
+ Special compilation variations
+
+You may get a (super fat) statically linked binary by :
+ cdrskin/compile_cdrskin.sh -static
+if your system supports static linking, at all. This will not help with kernels
+which do not properly support the necessary low-level interfaces chosen by
+your compile-time libraries.
+
+A size reduced but fully functional binary may be produced by
+ cdrskin/compile_cdrskin.sh -do_strip
+
+An extra lean binary with reduced capabilities is created by
+ cdrskin/compile_cdrskin.sh -do_diet -do_strip
+It will not read startup files, will abort on option dev_translation= ,
+will not have a fifo buffer, and will not be able to put out help texts or
+debugging messages.
+
+
+------------------------------------------------------------------------------
+ Project aspects and legal stuff
+------------------------------------------------------------------------------
+
+Important Disclaimer :
+
+This software is provided as is. There is no warranty implied and no
+protection against possible damages. You use this on your own risk.
+Don't blame me or other authors of libburn if anything goes wrong.
+
+Actually, in case of severe trouble, nearly always the drive and the media
+are the cause. Any mistake of the burn program is supposed to be caught
+by the drive's firmware and to lead to mere misburns.
+The worst mishaps which hit the author implied the need to reboot the
+system because of drives gnawing endlessly on ill media. Permanent hardware
+damage did not occur in 1.5 years of development.
+
+------------------------------------------------------------------------------
+
+Interested users are invited to participate in the development of cdrskin.
+Contact: scdbackup@gmx.net or libburn-hackers@pykix.org .
+We will keep copyright narrow but will of course acknowledge valuable
+contributions in a due way.
+
+------------------------------------------------------------------------------
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 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-2008 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.
+
+
+------------------------------------------------------------------------------
+cdrskin is currently copyright Thomas Schmitt only.
+It adopts the following commitment by the toplevel copyright holders:
+------------------------------------------------------------------------------
+
+We, the copyright holders, agree on the interpretation that
+dynamical linking of our libraries constitutes "use of" and
+not "derivation from" our work in the sense of GPL, provided
+those libraries are compiled from our unaltered code.
+
+Thus you may link our libraries dynamically with applications
+which are not under GPL. You may distribute our libraries and
+application tools in binary form, if you fulfill the usual
+condition of GPL to offer a copy of the source code -altered
+or unaltered- under GPL.
+
+We ask you politely to use our work in open source spirit
+and with the due reference to the entire open source community.
+
+If there should really arise the case where above clarification
+does not suffice to fulfill a clear and neat request in open source
+spirit that would otherwise be declined for mere formal reasons,
+only in that case we will duely consider to issue a special license
+covering only that special case.
+It is the open source idea of responsible freedom which will be
+decisive and you will have to prove that you exhausted all own
+means to qualify for GPL.
+
+For now we are firmly committed to maintain one single license: GPL.
+
+signed for cdrskin: Thomas Schmitt
diff --git a/cdrskin/add_ts_changes_to_libburn_0_4_6 b/cdrskin/add_ts_changes_to_libburn_0_4_6
new file mode 100755
index 0000000..e632a10
--- /dev/null
+++ b/cdrskin/add_ts_changes_to_libburn_0_4_6
@@ -0,0 +1,244 @@
+#!/bin/sh
+
+set -x
+
+# This script documents how this cdrskin version was derived from
+# a vanilla libburn version. It is not intended nor needed for any
+# use of cdrskin but included here only to show the technical
+# relationship between both projects - which are close friends
+# and issue roughly the same software.
+#
+# Package maintainers are advised to cover rather libburn than
+# cdrskin unless they put only emphasis on the cdrecord emulation
+# provided by cdrskin. libburn contains cdrskin - cdrskin is an
+# oscillating, friendly and coordinated fork of libburn.
+#
+# Script results are a source tarball and two binaries
+# one dynamic and one static in respect to system libs.
+# Both binaries are static in respect to libburn.
+#
+# The script is to be run in the directory above the toplevel
+# directory of libburn resp. cdrskin development.
+#
+
+# 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="0.4.6"
+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_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"/*.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/cdrskin/add_ts_changes_to_libburn_0_4_7 b/cdrskin/add_ts_changes_to_libburn_0_4_7
new file mode 100755
index 0000000..3da243e
--- /dev/null
+++ b/cdrskin/add_ts_changes_to_libburn_0_4_7
@@ -0,0 +1,245 @@
+#!/bin/sh
+
+set -x
+
+# This script documents how this cdrskin version was derived from
+# a vanilla libburn version. It is not intended nor needed for any
+# use of cdrskin but included here only to show the technical
+# relationship between both projects - which are close friends
+# and issue roughly the same software.
+#
+# Package maintainers are advised to cover rather libburn than
+# cdrskin unless they put only emphasis on the cdrecord emulation
+# provided by cdrskin. libburn contains cdrskin - cdrskin is an
+# oscillating, friendly and coordinated fork of libburn.
+#
+# Script results are a source tarball and two binaries
+# one dynamic and one static in respect to system libs.
+# Both binaries are static in respect to libburn.
+#
+# The script is to be run in the directory above the toplevel
+# directory of libburn resp. cdrskin development.
+#
+
+# 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="0.4.7"
+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_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"/*.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/cdrskin/cdrecord_spy.sh b/cdrskin/cdrecord_spy.sh
new file mode 100755
index 0000000..54d7c34
--- /dev/null
+++ b/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/cdrskin/cdrfifo.c b/cdrskin/cdrfifo.c
new file mode 100644
index 0000000..e61c533
--- /dev/null
+++ b/cdrskin/cdrfifo.c
@@ -0,0 +1,1253 @@
+/*
+ cdrfifo.c , Copyright 2006 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
+
+#include "cdrfifo.h"
+
+
+/* Macro for creation of arrays of objects (or single objects) */
+#define TSOB_FELD(typ,anz) (typ *) malloc((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 Unused yet
+ @return 1 on success, <=0 on failure
+*/
+int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
+ int chunk_size, int buffer_size, int flag)
+{
+ 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;
+ o->buffer= TSOB_FELD(char,buffer_size);
+ 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)
+ free((char *) o->buffer);
+ 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,ret,did_work= 0,idx,sod,eop_is_near,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) {
+ eop_is_near= 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;
+ 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);
+ 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 transfered to and/or from the fifo.
+ This is done for the given fifo object and all members of its next-chain.
+ The check and transactions are repeated until a given timespan has elapsed.
+ libburn applications call this function in the burn loop instead of sleep().
+ It may also be used instead of read(). Then it returns as soon as an output
+ transaction would be performed. See flag:bit2.
+ @param o The fifo object
+ @param wait_usec The time in microseconds after which the function shall
+ return.
+ @param reply_buffer with bit2: Returns write-ready buffer chunk and must
+ be able to take at least chunk_size bytes
+ @param reply_count with bit2: Returns number of writeable bytes in reply
+ @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],real_out[100];
+ int i,iv,stall_counter= 0,cycle_counter= 0.0;
+ char buf[10240], target_path[80];
+ double in_counter, out_counter, prev_in= -1.0, prev_out= -1.0;
+ struct CdrfifO *ff_in= NULL, *ff_out= NULL;
+
+ if(path_count<1)
+ return(2);
+ Cdrfifo_new(&ff_in,fd_in[0],fd_out[0],2048,fs_size,0);
+ for(i= 0; 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],real_out[4],pipe_idx;
+ int i,iv;
+ char buf[10240];
+ 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/cdrskin/cdrfifo.h b/cdrskin/cdrfifo.h
new file mode 100644
index 0000000..1237d20
--- /dev/null
+++ b/cdrskin/cdrfifo.h
@@ -0,0 +1,171 @@
+
+/*
+ cdrfifo.c , Copyright 2006 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 unused yet
+ @return 1 on success, <=0 on failure
+*/
+int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
+ int chunk_size, int buffer_size, int flag);
+
+/** Release from memory a fifo object previously created by Cdrfifo_new().
+ @param ff The victim (gets returned as NULL, call can stand *ff==NULL)
+ @param flag Bitfield for control purposes:
+ bit0= do not close destination fd
+*/
+int Cdrfifo_destroy(struct CdrfifO **ff, int flag);
+
+/** Close any output fds */
+int Cdrfifo_close(struct CdrfifO *o, int flag);
+
+/** Close any output fds of o and its chain peers */
+int Cdrfifo_close_all(struct CdrfifO *o, int flag);
+
+int Cdrfifo_get_sizes(struct CdrfifO *o, int *chunk_size, int *buffer_size,
+ int flag);
+
+/** Set a speed limit for buffer output.
+ @param o The fifo object
+ @param bytes_per_second >0 catch up slowdowns over the whole run time
+ <0 catch up slowdowns only over one interval
+ =0 disable speed limit
+*/
+int Cdrfifo_set_speed_limit(struct CdrfifO *o, double bytes_per_second,
+ int flag);
+
+/** Set a fixed size for input in order to cut off any unwanted tail
+ @param o The fifo object
+ @param idx index for fds attached via Cdrfifo_attach_follow_up_fds(),
+ first attached is 0, <0 directs limit to active fd limit
+ (i.e. first track is -1, second track is 0, third is 1, ...)
+*/
+int Cdrfifo_set_fd_in_limit(struct CdrfifO *o, double fd_in_limit, int idx,
+ int flag);
+
+
+int Cdrfifo_set_fds(struct CdrfifO *o, int source_fd, int dest_fd, int flag);
+int Cdrfifo_get_fds(struct CdrfifO *o, int *source_fd, int *dest_fd, int flag);
+
+
+/** Attach a further pair of input and output fd which will use the same
+ fifo buffer when its predecessors are exhausted. Reading will start as
+ soon as reading of the predecessor encounters EOF. Writing will start
+ as soon as all pending predecessor data are written.
+ @return index number of new item + 1, <=0 indicates error
+*/
+int Cdrfifo_attach_follow_up_fds(struct CdrfifO *o, int source_fd, int dest_fd,
+ int flag);
+
+/** Attach a further fifo which shall be processed simultaneously with this
+ one by Cdrfifo_try_to_work() in fd-to-fd mode.
+*/
+int Cdrfifo_attach_peer(struct CdrfifO *o, struct CdrfifO *next, int flag);
+
+
+/** Obtain buffer state.
+ @param o The buffer object
+ @param fill Returns the number of pending payload bytes in the buffer
+ @param space Returns the number of unused buffer bytes
+ @param flag unused yet
+ @return -1=error , 0=inactive , 1=reading and writing ,
+ 2=reading ended (but still writing)
+*/
+int Cdrfifo_get_buffer_state(struct CdrfifO *o,int *fill,int *space,int flag);
+
+int Cdrfifo_get_counters(struct CdrfifO *o,
+ double *in_counter, double *out_counter, int flag);
+
+/** reads min_fill and begins measurement interval for next min_fill */
+int Cdrfifo_next_interval(struct CdrfifO *o, int *min_fill, int flag);
+
+int Cdrfifo_get_min_fill(struct CdrfifO *o, int *total_min_fill,
+ int *interval_min_fill, int flag);
+
+int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
+ double *put_counter, double *get_counter,
+ double *empty_counter, double *full_counter,
+ int flag);
+
+/** Inquire the eventually detected size of an eventual ISO-9660 file system
+ @return 0=no ISO resp. size detected, 1=size_in_bytes is valid
+*/
+int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes,int flag);
+
+
+/** Take over the eventually memorized blocks 16 to 31 of input (2 kB each).
+ The fifo forgets the blocks by this call. I.e. a second one will return 0.
+ After this call it is the responsibility of the caller to dispose the
+ retrieved memory via call free().
+ @param pt Will be filled either with NULL or a pointer to 32 kB of data
+ @return 0=nothing is buffered, 1=pt points to valid freeable data
+*/
+int Cdrfifo_adopt_iso_fs_descr(struct CdrfifO *o, char **pt, int flag);
+
+
+/** Check for pending data at the fifo's source file descriptor and wether the
+ fifo is ready to take them. Simultaneously check the buffer for existing
+ data and the destination fd for readiness to accept some. If so, a small
+ chunk of data is transfered to and/or from the fifo.
+ This is done for the given fifo object and all members of its next-chain.
+ The check and transactions are repeated until a given timespan has elapsed.
+ libburn applications call this function in the burn loop instead of sleep().
+ It may also be used instead of read(). Then it returns as soon as an output
+ transaction would be performed. See flag:bit2.
+ @param o The fifo object
+ @param wait_usec The time in microseconds after which the function shall
+ return.
+ @param reply_buffer with bit2: Returns write-ready buffer chunk and must
+ be able to take at least chunk_size bytes
+ @param reply_count with bit2: Returns number of writeable bytes in reply_pt
+ @param flag Bitfield for control purposes:
+ bit0= Enable debug pacifier (same with Cdrfifo_debuG)
+ bit1= Do not write, just fill buffer
+ bit2= fd-to-memory mode (else fd-to-fd mode):
+ Rather than writing a chunk return it and its size.
+ No simultaneous processing of chained fifos.
+ bit3= With bit2: do not check destination fd for readiness
+ @return <0 = error , 0 = idle , 1 = did some work , 2 = all work is done
+*/
+int Cdrfifo_try_to_work(struct CdrfifO *o, int wait_usec,
+ char *reply_buffer, int *reply_count, int flag);
+
+/** Fill the fifo as far as possible without writing to destination fd.
+ @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/cdrskin/cdrskin.1 b/cdrskin/cdrskin.1
new file mode 100644
index 0000000..1d4469b
--- /dev/null
+++ b/cdrskin/cdrskin.1
@@ -0,0 +1,1334 @@
+.\" 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 "May 10, 2008"
+.\" 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-RE 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-RE 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-RE.
+.br
+Burning of data or audio tracks 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 on DVD+R[/DL].
+.br
+Single session on DVD-RW or DVD-R (Disk-at-once).
+.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
+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 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
+Each track is initiated by one track source address argument, which may either
+be "-" for standard input or the address of a readable file. If no write mode
+is given explicitely then one will be chosen which matches the peculiarities
+of track sources and the state of the output media.
+.PP
+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
+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.
+These informations are 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
+resp. by music CD players. With DVD and BD there is only type data.
+.br
+If not explicitely 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 resp. 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 arbitray 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. 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 depicted by option
+.B -tao
+which needs no predicted track size and allows to make use of
+eventual multi-session capabilities.
+.br
+A more restrictive mode
+.B -sao
+(alias -dao) which usually demands a predictable track size and is not
+necessarily capable of multi-session. It may have advantages for some
+readers resp. players of the recorded tracks.
+.br
+If none of the options -dao, -tao or -sao is given then the program will
+try to choose a write mode which matches the defined recording job,
+the capabilities of the drive and the state of the present media.
+.br
+So the mentioning of write modes in the following paragraphs and in the
+examples is not so much a demand that the user shall choose one explicitely,
+but rather an illustration of what to expect with particular media types.
+.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 allows to use track sources of unpredictable length (like stdin) and
+allows to write further sessions to appendable media.
+-sao produces audio sessions with seamless tracks but needs predicted track
+sizes and cannot append sessions to media.
+.br
+CD-RW media can be blanked to make them re-usable for another
+round of overwriting. Usually
+.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.
+.SS
+.B Sequentially Recordable DVD Media:
+.br
+Currently DVD-RW, DVD-R and DVD+R[/DL] can be used for the Sequential recording
+model.
+.br
+This applies to DVD-RW only 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, allows no -multi and only a single track. The size of the
+track needs to be known in advance. So either its source has to be a disk file
+of recognizable size or the size has to be announced explicitely by options
+.B tsize=
+or
+.B tao_to_sao_tsize= .
+.br
+DAO is the only mode for media which do not offer feature 21h Incremental
+Streaming. DAO may also be selected explicitely by option
+.B -sao .
+Program growisofs uses DAO on sequential DVD-R[W] media for maximum
+DVD-ROM/-Video compatibility.
+.br
+The other mode, Incremental Streaming, is the default write mode if
+it is available and if the restrictions of DAO would prevent the job.
+Incremental Streaming may be selected explicitely by option
+.B -tao
+as it resembles much CD TAO by allowing track sources of
+unpredicted length and to keep media appendable by option
+.B -multi .
+The only restriction towards CD-R[W] is the lack of support for -audio tracks.
+Multiple tracks per session are permissible.
+.br
+The write modes for DVD+R[/DL] resemble those with DVD-R except that with +R
+each track gets wrapped in an own session. There is no -dummy writing with
+DVD+R[/DL].
+.br
+Quite deliberately write mode -sao insists in the tradition of a predicted
+track size and blank media, whereas -tao writes the tracks open ended and
+allows appendable media.
+.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 recognizeable end of overwriteable media.
+Therefore -multi is banned unless ISO-9660 images shall be expandable by help
+of option
+.B --grow_overwriteable_iso .
+Without this option or without an ISO-9660 filesystem image present
+on media, -toc does not return information about the media content and
+media get treated as blank regardless wether they hold data or not.
+.br
+Currently there is no difference between -sao and -tao. If ever, then -tao
+will be the mode which preserves the current behavior.
+.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, either CD burners or DVD 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.
+.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
+.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 on Linux consist of three
+numbers: Bus,Target,Lun. 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 on Linux: links to libburn-suitable device files,
+device files which have the same major and minor device number,
+and device files which have the same SCSI address parameters (e.g. /dev/sg0).
+.br
+.SS
+.B Emulated drives:
+.br
+Option
+.B --allow_emulated_drives
+enables addressing of pseudo-drives
+which get emulated on top of filesystem objects. Regular data files and
+block devices result in pseudo-drives which behave much like DVD-RAM.
+If the given address does not exist yet but its directory exists, then
+it gets created as regular file.
+Other file types like character devices or pipes result in pseudo-drives
+which behave much like blank DVD-R.
+The target file address is given after prefix "stdio:".
+.br
+E.g.: dev=stdio:/tmp/my_pseudo_drive
+.br
+Addresses of the form "stdio:/dev/fd/" are treated special. The
+number is read literally and used as open file descriptor. With
+dev="stdio:/dev/fd/1" the normal standard output of the program is
+redirected to stderr and the stream data of a burn run will appear on stdout.
+.br
+Not good for terminals ! Redirect it.
+.br
+Pseudo-drives allow -dummy. Their reply with --tell_media_space can be utopic.
+-dummy burn runs touch the file but do not modify its data content.
+.br
+Note: --allow_emulated_drives is restricted to stdio:/dev/null if cdrskin
+is run by the
+.B superuser
+or if it has changed user identity via the
+.B setuid
+bit of its access permissions. The ban for the superuser can be lifted by a
+skillfully created file. See section FILES below.
+.br
+.SH OPTIONS
+.TP
+.BI \-\-help
+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 explicitely by option -data, input files with suffix
+".wav" are examined wether 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-RE.
+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.
+.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 overwriteably 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 and BD-RE.
+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 allows 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-RE to reserve the default amount of spare blocks for
+defect management.
+.br
+The following format_defectmgt_* allow to submit user 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-RE to reserve a maximum number of spare blocks.
+.TP
+format_defectmgt_min
+Format DVD-RAM or BD-RE 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 seems not to have a speed increasing effect,
+though.
+.TP
+format_defectmgt_payload_
+Format DVD-RAM or BD-RE. 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 allows at least the given payload size.
+.TP
+format_by_index_
+Format DVD-RW, DVD+RW, DVD-RAM or BD-RE.
+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 \-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.
+.TP
+.BI dev= target
+Set the address of the drive to use. Valid are at least the
+addresses listed with option --devices,
+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 explicitely 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
+.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.
+.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 preceeded
+by further -isosize options, though. At least 15 blocks of padding will be
+added to each -isosize track. But be advised to rather use padsize=300k.
+.br
+This option can be performed on track sources which are regular files or block
+devices. For the first track of the session it can be performed on any type
+of source if there is a fifo of at least 64 kiB. See option fs= .
+.TP
+.BI -load
+Load the media and exit. Exit value is 0 if any kind of media was found, non
+zero else. Note: Option -eject will unload the media even if -load is given.
+.TP
+.BI -lock
+Like option -load but leave the drive's eject button disabled if there is any
+media found and not option -eject is given.
+.br
+Use program "eject" or cdrskin -eject to get the tray out of the drive.
+Runs of programs like cdrecord, growisofs, wodim, cdrskin will not be hampered
+and normally enable the drive's eject button when they are done.
+.TP
+.BI minbuf= percentage
+Equivalent to:
+.br
+modesty_on_drive=1:min_percent=:max_percent=95
+.br
+Percentage is permissible between 25 and 95.
+.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 or genisoimage. 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 the CD or unformatted DVD-R[W] 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. 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 \-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 \-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 \-raw96r
+Write CD in RAW/RAW96R mode. This mode allows to put more payload bytes
+into a CD sector but obviously at the cost of error correction. It can only
+be used for tracks of fixely predicted size. Some drives allow this mode but
+then behave strange or even go bad for the next few attempts to burn a CD.
+One should use it only if inavoidable.
+.TP
+.BI \-sao
+Write CD in Session At Once mode, a sequential DVD-R[W] in Disc-at-once
+(DAO) mode, or a DVD+R[/DL].
+.br
+With CD this mode is able to put several audio tracks on media without
+producing audible gaps between them.
+.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, BD or DVD+R[/DL] but actually
+only imposes restrictions without providing known advantages.
+.br
+-sao can only be used for tracks of fixely predicted size. This implies that
+track arguments which depict stdin or named pipes need to be preceeded by
+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 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 allows -multi.
+.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.
+.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 verbose 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 \-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 explicitely 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 \--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 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 fallback_program= command
+Set a command name to be executed if cdrskin encounters a known cdrecord
+option which it does not yet support. If a non-empty command is given with
+fallback_program=, and if no essential options are given which are specific
+to cdrskin, then cdrskin will delegate the job to said command.
+.br
+The natural commands to be given are cdrecord or wodim but one may well submit
+the address of an own program.
+.br
+The fallback programm will get all arguments of cdrskin which do not match
+the shell patterns --?* or *_*=* . This eventually suppresses path names of
+track sources which happen to match those patterns. The options from the
+startup files are not handed to the fallback program.
+.br
+Fallback program execution is disabled if cdrskin is run setuid and not
+option --allow_setuid is given. In general, the drive's device files and the
+involved programs should be set up so that each program runs under its advised
+conditions. (E.g. cdrskin as member of group floppy, cdrecord setuid root.)
+.br
+Two alias names for cdrskin are predefined with default fallback programs:
+.br
+.B unicord
+implies fallback_program=cdrecord
+.br
+.B codim
+implies fallback_program=wodim
+.TP
+.BI fifo_start_at= size
+Do not wait for full fifo but start burning as soon as the given number
+of bytes is read. This option may be helpful to bring the average throughput
+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 underun is as weak as the size of
+fifo_start_at= . So it is best if the drive offers hardware protection which
+is enabled automatically if not driveropts=noburnfree is given.
+.TP
+.BI \--grow_overwriteable_iso
+Enable emulation of multi-session writing on overwriteable media which
+contain an ISO-9660 filesystem. This emulation is learned from growisofs -M
+but adapted to the usage model of
+.br
+.B cdrskin -msinfo
+.br
+.B mkisofs -C -M | cdrskin -waiti [-multi] -
+.br
+--grow_overwriteable_iso does not hamper the use of true multi-session media.
+I.e. it is possible to use the same cdrskin options with both kinds of media
+and to achieve similar results if ISO-9660 filesystem images are to be written.
+This option implies option -isosize and therefore demands that the track
+source is a ISO-9660 filesystem image.
+.br
+With overwriteable media and no option blank=fast|all present it expands an
+eventual ISO-9660 filesystem on media. It is assumed that this image's inner
+size description points to the end of the valuable data.
+Overwriteable media with a recognizeable ISO-9660 size will be regarded as
+appendable rather than as blank. I.e. options -msinfo and -toc will work.
+-toc will always show a single session with its size increasing with
+every added mkisofs image.
+.br
+If not overriden by option write_start_address=, the track with the new image
+will be placed behind the end of the old one. One may use option
+assert_write_lba= to make sure that media state and mkisofs job do match.
+.br
+--grow_overwriteable_iso causes option blank=fast|all to invalidate an
+eventual ISO-9660 image by altering the first few bytes of block 16 on
+overwriteable media.
+Option -multi is tolerated in order not to hamper true multi-session media.
+.br
+An equivalent of growisofs -Z for overwriteable media is:
+.br
+.B mkisofs | cdrskin --grow_overwriteable_iso blank=fast [-multi] -
+.br
+With multi-session DVD, blank=fast will act like dvd+rw-format -blank=full .
+.br
+growisofs -dvd-compat is roughly equivalent to cdrskin without option -multi.
+.TP
+.BI \--list_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 \--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 \--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 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 allow no
+Incremental Streaming (-tao) resp. 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 allow blanking, though, and will measure space
+afterwards.
+.br
+It is not mandatory to give track sources but their nature may influence
+the available capacity. So for most realistic results one may set up
+the full burn session and add --tell_media_space. But if one has to expect
+a cdrskin version prior to 0.3.3 no track source should be given in order
+not to start an involuntary burn session.
+In this case set at least -sao or -tao explicitely.
+.br
+The result gets printed to standard output. It is 0 or empty if no writing
+is possible with the given options.
+This option redirects to stderr all message output except its own result
+string and eventual output of -msinfo.
+.TP
+.BI write_start_address= byte_offset
+Set the address on media where to start writing the track. With DVD+RW, 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.
+.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 applies to :
+.br
+Profile 0015h , DVD-R/DL Sequential (will not allow -multi).
+.br
+If you really test such media, then please report the outcome on
+libburn-hackers@pykix.org
+.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.
+Wether this leads to senseful behavior depends on operating system and kernel.
+.TP
+.BI drive_scsi_dev_family= sr | scd | sg
+Linux specific: Select a SCSI device file family to be used for drive command
+transactions. Normally this is /dev/sgN on kernel versions < 2.6 and /dev/srN
+on kernels >= 2.6 . This option allows to explicitely override that default
+in order to meet other programs at a common device file for each drive.
+On kernel 2.4 families sr and scd will find no drives.
+.br
+Device file family /dev/hdX on kernel >= 2.6 is not affected by this setting.
+.TP
+.BI \--drive_scsi_exclusive
+Linux specific:
+Try to exclusively reserve device files /dev/srN, /dev/scdM, /dev/sgK of drives.
+This would be helpful to protect against collisions with program growisofs.
+Regrettably on Linux kernel 2.4 with ide-scsi emulation this seems not to
+work. Wether it becomes helpful with new Linux systems has to be evaluated.
+.TP
+.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 modesty_on_drive= [:min_percent=][:max_percent=]
+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 max_percent. If this filling is
+exceeded then the program will wait until the filling is at most min_percent.
+.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
+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.
+.br
+Mode 0 disables this feature. Mode -1 keeps it unchanged. Default is:
+.br
+modesty_on_drive=0:min_percent=65:max_percent=95
+.br
+Percentages are permissible in the range of 25 to 100.
+.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 \--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 stream_recording="on"|"off"
+By setting "on" request that compliance to the desired speed setting is
+preferred over management of write errors. With DVD-RAM and BD-RE 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
+.SH EXAMPLES
+.SS
+.B Get an overview of drives and their addresses:
+.br
+cdrskin -scanbus
+.br
+cdrskin dev=ATA -scanbus
+.br
+cdrskin --devices
+.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 -toc
+.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):
+.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] or DVD+R[/DL]:
+.br
+cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 1.iso
+.br
+cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 2.iso
+.br
+cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 3.iso
+.br
+cdrskin dev=/dev/hdc -v padsize=300k -tao 4.iso
+.SS
+.B Get 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 -tao -multi run:
+.br
+x=$(cdrskin dev=/dev/sr0 -tao -multi \\
+.br
+--tell_media_space 2>/dev/null)
+.br
+echo "Available: $x blocks of 2048 data bytes"
+.SS
+.B Write audio tracks to CD:
+.br
+cdrskin -v dev=ATA:1,0,0 speed=48 -sao \\
+.br
+track1.wav track2.au -audio -swab track3.raw
+.br
+.SH FILES
+.SS
+Startup files:
+.br
+If not --no_rc is given as the first argument then cdrskin attempts on
+startup to read the arguments from the following files:
+.PP
+.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/cdrskin/cdrskin.c b/cdrskin/cdrskin.c
new file mode 100644
index 0000000..e50d87f
--- /dev/null
+++ b/cdrskin/cdrskin.c
@@ -0,0 +1,8292 @@
+
+/*
+ cdrskin.c , Copyright 2006-2008 Thomas Schmitt
+Provided under GPL version 2. See future commitment below.
+
+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 and/or
+BSD license.
+
+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" resp.
+ "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 "0.4.6"
+#endif
+
+/** The official libburn interface revision to use.
+ (May get changed further below)
+*/
+#ifndef Cdrskin_libburn_majoR
+#define Cdrskin_libburn_majoR 0
+#endif
+#ifndef Cdrskin_libburn_minoR
+#define Cdrskin_libburn_minoR 4
+#endif
+#ifndef Cdrskin_libburn_micrO
+#define Cdrskin_libburn_micrO 6
+#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
+
+/** use this to accomodate to the CVS version as of Feb 20, 2006
+#define Cdrskin_libburn_cvs_A60220_tS 1
+*/
+#ifdef Cdrskin_libburn_cvs_A60220_tS
+
+#define Cdrskin_libburn_versioN "0.2.tsA60220"
+#define Cdrskin_libburn_no_burn_preset_device_opeN 1
+#ifndef Cdrskin_oldfashioned_api_usE
+#define Cdrskin_oldfashioned_api_usE 1
+#endif
+
+#endif /* Cdrskin_libburn_cvs_A60220_tS */
+
+
+#ifdef Cdrskin_libburn_0_4_6
+#define Cdrskin_libburn_versioN "0.4.6"
+#define Cdrskin_libburn_from_pykix_svN 1
+#endif /* Cdrskin_libburn_0_4_6 */
+
+#ifdef Cdrskin_libburn_0_4_7
+#define Cdrskin_libburn_versioN "0.4.7"
+#define Cdrskin_libburn_from_pykix_svN 1
+
+/* Place novelty switch macros here.
+ Move them down to Cdrskin_libburn_from_pykix_svN on version leap
+*/
+
+/* there are no libburn novelties in 0.4.7 yet */
+
+#endif /* Cdrskin_libburn_0_4_7 */
+
+#ifndef Cdrskin_libburn_versioN
+#define Cdrskin_libburn_0_4_6
+#define Cdrskin_libburn_versioN "0.4.6"
+#define Cdrskin_libburn_from_pykix_svN 1
+#endif
+
+#ifdef Cdrskin_libburn_0_4_6
+#undef Cdrskin_libburn_majoR
+#undef Cdrskin_libburn_minoR
+#undef Cdrskin_libburn_micrO
+#define Cdrskin_libburn_majoR 0
+#define Cdrskin_libburn_minoR 4
+#define Cdrskin_libburn_micrO 6
+#endif
+#ifdef Cdrskin_libburn_0_4_7
+#undef Cdrskin_libburn_majoR
+#undef Cdrskin_libburn_minoR
+#undef Cdrskin_libburn_micrO
+#define Cdrskin_libburn_majoR 0
+#define Cdrskin_libburn_minoR 4
+#define Cdrskin_libburn_micrO 7
+#endif
+
+
+
+#ifdef Cdrskin_libburn_from_pykix_svN
+#ifndef Cdrskin_oldfashioned_api_usE
+
+/* 0.2.2 */
+#define Cdrskin_libburn_does_ejecT 1
+#define Cdrskin_libburn_has_drive_get_adR 1
+#define Cdrskin_progress_track_does_worK 1
+#define Cdrskin_is_erasable_on_load_does_worK 1
+#define Cdrskin_grab_abort_does_worK 1
+
+/* 0.2.4 */
+#define Cdrskin_allow_libburn_taO 1
+#define Cdrskin_libburn_has_is_enumerablE 1
+#define Cdrskin_libburn_has_convert_fs_adR 1
+#define Cdrskin_libburn_has_convert_scsi_adR 1
+#define Cdrskin_libburn_has_burn_msgS 1
+#define Cdrskin_libburn_has_burn_aborT 1
+#define Cdrskin_libburn_has_cleanup_handleR 1
+#define Cdrskin_libburn_has_audioxtR 1
+#define Cdrskin_libburn_has_get_start_end_lbA 1
+#define Cdrskin_libburn_has_burn_disc_unsuitablE 1
+#define Cdrskin_libburn_has_read_atiP 1
+#define Cdrskin_libburn_has_buffer_progresS 1
+
+/* 0.2.6 */
+#define Cdrskin_libburn_has_pretend_fulL 1
+#define Cdrskin_libburn_has_multI 1
+#define Cdrskin_libburn_has_buffer_min_filL 1
+
+/* 0.3.0 */
+#define Cdrskin_atip_speed_is_oK 1
+#define Cdrskin_libburn_has_get_profilE 1
+#define Cdrskin_libburn_has_set_start_bytE 1
+#define Cdrskin_libburn_has_wrote_welL 1
+#define Cdrskin_libburn_has_bd_formattinG 1
+#define Cdrskin_libburn_has_burn_disc_formaT 1
+
+/* 0.3.2 */
+#define Cdrskin_libburn_has_get_msc1 1
+#define Cdrskin_libburn_has_toc_entry_extensionS 1
+#define Cdrskin_libburn_has_get_multi_capS 1
+
+/* 0.3.4 */
+#define Cdrskin_libburn_has_set_filluP 1
+#define Cdrskin_libburn_has_get_spacE 1
+#define Cdrskin_libburn_write_mode_ruleS 1
+#define Cdrskin_libburn_has_allow_untested_profileS 1
+#define Cdrskin_libburn_has_set_forcE 1
+
+/* 0.3.6 */
+#define Cdrskin_libburn_preset_device_familY 1
+#define Cdrskin_libburn_has_track_set_sizE 1
+
+/* 0.3.8 */
+#define Cdrskin_libburn_has_set_waitinG 1
+#define Cdrskin_libburn_has_get_best_speeD 1
+
+/* 0.4.0 */
+#define Cdrskin_libburn_has_random_access_rW 1
+#define Cdrskin_libburn_has_get_drive_rolE 1
+#define Cdrskin_libburn_has_drive_equals_adR 1
+
+/* 0.4.2 */
+/* no novel libburn features but rather organizational changes */
+
+/* 0.4.4 */
+/* novel libburn features are transparent to cdrskin */
+
+/* 0.4.6 */
+#define Cdrskin_libburn_has_stream_recordinG 1
+
+
+#ifdef Cdrskin_new_api_tesT
+
+/* put macros under test caveat here */
+
+#endif /* Cdrskin_new_api_tesT */
+
+
+#endif /* ! Cdrskin_oldfashioned_api_usE */
+#endif /* Cdrskin_libburn_from_pykix_svN */
+
+
+/* These macros activate cdrskin workarounds for deficiencies resp.
+ problematic features of libburn which hopefully will change in
+ future. */
+
+/** Work around the fact that neither /dev/sg0 (kernel 2.4 + ide-scsi) nor
+ /dev/hdc (kernel 2.6) get ejected by icculus.org/burn */
+#ifndef Cdrskin_libburn_does_ejecT
+#define Cdrskin_burn_drive_eject_brokeN 1
+#endif
+
+/** Work around the fact that after loading media speed report is wrong */
+#ifndef Cdrskin_atip_speed_is_oK
+#define Cdrskin_atip_speed_brokeN 1
+#endif
+
+/** Work around the fact that burn_drive_get_status() always reports to do
+ track 0 in icculus.org/burn */
+#ifndef Cdrskin_progress_track_does_worK
+#define Cdrskin_progress_track_brokeN 1
+#endif
+
+/** Work around the fact that a drive interrupted at burn_drive_grab() never
+ leaves status BURN_DRIVE_GRABBING in icculus.org/burn */
+#ifndef Cdrskin_grab_abort_does_worK
+#define Cdrskin_grab_abort_brokeN 1
+#endif
+
+/** Work around the fact that a freshly loaded tray with media reports
+ arbitrary media erasability in icculuc.org/burn */
+#ifndef Cdrskin_is_erasable_on_load_does_worK
+#define Cdrskin_is_erasable_on_load_is_brokeN 1
+#endif
+
+/** http://libburnia-project.org/ticket/41 reports of big trouble without
+ padding any track to a full sector
+*/
+#define Cdrskin_all_tracks_with_sector_paD 1
+
+
+/** A macro which is able to eat up a function call like printf() */
+#ifdef Cdrskin_extra_leaN
+#define ClN(x)
+#else
+#define ClN(x) x
+#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"
+
+#ifdef Cdrskin_libburn_has_audioxtR
+#include "../libburn/libdax_audioxtr.h"
+#endif
+
+#ifdef Cdrskin_libburn_has_cleanup_handleR
+#define Cleanup_set_handlers burn_set_signal_handling
+#define Cleanup_app_handler_T burn_abort_handler_t
+#else
+#include "cleanup.h"
+#endif
+
+
+/** The size of a string buffer for pathnames and similar texts */
+#define Cdrskin_strleN 4096
+
+/** The maximum length +1 of a drive address */
+#ifndef Cdrskin_oldfashioned_api_usE
+#define Cdrskin_adrleN BURN_DRIVE_ADR_LEN
+#else
+#define Cdrskin_adrleN 80
+#endif
+
+
+/** 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 *) malloc((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);
+}
+
+
+/** 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 *) malloc(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 *) malloc(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 **) malloc(argcount*sizeof(char *));
+ *argidx= (int *) malloc(argcount*sizeof(int));
+ *arglno= (int *) malloc(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(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]= malloc(strlen(from_pt)+1);
+ trn->to_address[cnt]= malloc(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= Cdrskin_all_tracks_with_sector_paD;
+ o->track_type= BURN_MODE1;
+ o->sector_size= 2048.0;
+ o->track_type_by_default= 1;
+ o->swap_audio_bytes= 0;
+ 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;
+
+ 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->swap_audio_bytes),
+ 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_extra_leaN
+ Cdrfifo_destroy(&(track->fifo),0);
+#endif
+
+ if(track->libburn_track!=NULL)
+ burn_track_free(track->libburn_track);
+ if(track->iso_fs_descr!=NULL)
+ free((char *) track->iso_fs_descr);
+ 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)
+{
+
+ *size= track->fixed_size;
+ *padding= track->padding;
+ *use_data_image_size= track->use_data_image_size;
+#ifdef Cdrskin_allow_libburn_taO
+ if((flag&1) && track->libburn_track!=NULL) {
+ off_t readcounter= 0,writecounter= 0;
+
+ burn_track_get_counters(track->libburn_track,&readcounter,&writecounter);
+ *size= readcounter;
+ *padding= writecounter-readcounter;
+ } else if(flag&2)
+ *padding= track->tao_to_sao_tsize;
+
+#endif
+ *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);
+}
+
+
+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;
+#ifdef Cdrskin_libburn_has_audioxtR
+ struct libdax_audioxtr *xtr= NULL;
+ char *fmt,*fmt_info;
+ int num_channels,sample_rate,bits_per_sample,msb_first,ret;
+#endif
+
+ *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);
+ }
+
+#ifdef Cdrskin_libburn_has_audioxtR
+
+ 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);
+
+#else /* Cdrskin_libburn_has_audioxtR */
+
+ return(0);
+
+#endif
+}
+
+
+/* @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) {
+#ifdef Cdrskin_libburn_has_track_set_sizE
+ burn_track_set_size(track->libburn_track, (off_t) *size_used);
+#else
+ fprintf(stderr,
+ "cdrskin: SORRY : libburn version is too old for -isosize\n");
+ return(0);
+#endif
+ }
+ /* 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_extra_leaN
+ 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
+ @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;
+ off_t xtr_size= 0;
+ struct stat stbuf;
+#ifdef Cdrskin_libburn_has_convert_fs_adR
+ 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);
+#ifdef Cdrskin_libburn_has_drive_equals_adR
+ struct burn_drive *drive;
+#else
+ char adr[BURN_DRIVE_ADR_LEN];
+#endif
+#endif /* Cdrskin_libburn_has_convert_fs_adR */
+
+ 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;
+
+#ifdef Cdrskin_libburn_has_convert_fs_adR
+
+ Cdrskin_get_device_adr(track->boss,&device_adr,&raw_adr,
+ &no_convert_fs_adr,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"));
+
+#ifdef Cdrskin_libburn_has_drive_equals_adR
+
+ 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) {
+
+ {
+
+#else /* Cdrskin_libburn_has_drive_equals_adR */
+
+ if(burn_drive_convert_fs_adr(track->source_path,adr)>0) {
+
+/*
+ fprintf(stderr,"cdrskin: DEBUG : track source '%s' -> adr='%s'\n",
+ track->source_path,adr);
+*/
+ if(strcmp(device_adr,adr)==0) {
+
+#endif /* ! Cdrskin_libburn_has_drive_equals_adR */
+
+ 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);
+*/
+
+#endif /* Cdrskin_libburn_has_convert_fs_adR */
+
+ 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)
+ *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)
+ 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 */
+ }
+ }
+ }
+ }
+
+#ifdef Cdrskin_allow_libburn_taO
+
+ if(track->fixed_size < Cdrtrack_minimum_sizE * track->sector_size
+ && (track->fixed_size>0 || size_from_file) && !(flag&2)) {
+
+#else
+
+ if(track->fixed_size < Cdrtrack_minimum_sizE * track->sector_size &&
+ !(flag&2)) {
+
+#endif
+
+ 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;
+ }
+ }
+ track->source_fd= *fd;
+ return(*fd>=0);
+}
+
+
+#ifndef Cdrskin_extra_leaN
+
+/** 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);
+ 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,0);
+ 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);
+}
+
+
+/** Read data into the fifo until either it is full or the data source is
+ exhausted.
+ @return <=0 error, 1 success
+*/
+int Cdrtrack_fill_fifo(struct CdrtracK *track, int fifo_start_at, int flag)
+{
+ int ret,buffer_fill,buffer_space;
+ double data_image_size;
+
+ if(track->fifo==NULL || fifo_start_at==0)
+ 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= 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_extra_leaN */
+
+
+/** 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)
+*/
+{
+ struct burn_track *tr;
+ struct burn_source *src= NULL;
+ double padding,lib_padding;
+ int ret,sector_pad_up;
+ double fixed_size;
+ int source_fd;
+
+ track->trackno= trackno;
+ tr= burn_track_create();
+ track->libburn_track= tr;
+
+ /* Note: track->track_type may get set in here */
+ if(track->source_fd==-1) {
+ ret= Cdrtrack_open_source_path(track,&source_fd,(flag&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);
+ 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));
+ 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);
+
+ 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;}
+ }
+ burn_session_add_track(session,tr,BURN_POS_END);
+ ret= 1;
+ex:
+ 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);
+ 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);
+}
+
+
+#ifndef Cdrskin_libburn_write_mode_ruleS
+
+int Cdrtrack_activate_tao_tsize(struct CdrtracK *track, int flag)
+{
+ if(track->fixed_size<=0.0)
+ track->fixed_size= track->tao_to_sao_tsize;
+ return(track->fixed_size>0.0);
+}
+
+#endif /* ! Cdrskin_libburn_write_mode_ruleS */
+
+
+int Cdrtrack_get_sectors(struct CdrtracK *track, int flag)
+{
+ return(burn_track_get_sectors(track->libburn_track));
+}
+
+
+#ifndef Cdrskin_extra_leaN
+
+/** 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_extra_leaN */
+
+
+/* --------------------------------------------------------------------- */
+
+/** 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 transfered 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 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;
+#ifdef Cdrskin_libburn_has_convert_scsi_adR
+ o->old_pseudo_scsi_adr= 0;
+#else
+ o->old_pseudo_scsi_adr= 1;
+#endif
+ 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);
+#ifdef Cdrskin_libburn_has_burn_msgS
+ burn_msgs_set_severities(preskin->queue_severity, preskin->print_severity,
+ "cdrskin: ");
+#endif
+ return(1);
+}
+
+
+int Cdrpreskin_initialize_lib(struct CdrpreskiN *preskin, int flag)
+{
+ int ret, major, minor, micro;
+
+/* 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 */
+#endif /* Cdrskin_libburn_has_burn_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(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; i 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));
+
+#ifdef Cdrskin_libburn_has_convert_scsi_adR
+ } 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);
+
+#endif /* Cdrskin_libburn_has_convert_scsi_adR */
+ }
+ }
+ }
+ }
+ 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];
+
+#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)
+ 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;iabort_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(argv[i],"blank=help")==0 ||
+ strcmp(argv[i],"-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-RE\n");
+ fprintf(stderr,
+ "\tformat_defectmgt[_cert_on|_cert_off]\tcertification slow|quick\n");
+ fprintf(stderr,
+ "\tformat_defectmgt_payload_\tformat DVD-RAM or BD-RE\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) {
+#ifndef Cdrskin_extra_leaN
+ printf("Note: If this hangs for a while then there is a drive with\n");
+ printf(" unexpected problems (e.g. ill DMA).\n");
+ printf(" One may exclude such a device file by removing r- and w-\n");
+ printf(" permissions for all cdrskin users.\n");
+#endif /* ! Cdrskin_extra_leaN */
+
+ 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(argv[i],"-dev=",5)==0) {
+ value_pt= argv[i]+5;
+ goto set_dev;
+ } else if(strncmp(argv[i],"dev=",4)==0) {
+ value_pt= argv[i]+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(argv[i],"driveropts=help")==0 ||
+ strcmp(argv[i],"-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");
+#ifdef Cdrskin_libburn_has_get_best_speeD
+ printf(
+ " --adjust_speed_to_drive set only speeds offered by drive and media\n");
+#endif
+ 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(
+ " 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(
+ " 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");
+#ifdef Cdrskin_burn_drive_eject_brokeN
+ printf(
+ " eject_device= set the device address for command eject\n");
+#endif
+ 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");
+#ifdef Cdrskin_libburn_has_set_filluP
+ printf(" --fill_up_media cause the last track to have maximum size\n");
+#endif
+ 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(" --list_formats list format descriptors for loaded media.\n");
+ printf(" --list_ignored_options list all ignored cdrecord options.\n");
+#ifdef Cdrskin_libburn_has_set_waitinG
+ printf(" modesty_on_drive= no writing into full drive buffer\n");
+#endif
+ 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_rc as first argument: do not read startup files\n");
+ printf(" --old_pseudo_scsi_adr use and report literal Bus,Target,Lun\n");
+ printf(" rather than real SCSI and pseudo ATA.\n");
+ printf(" --prodvd_cli_compatible react on some DVD types more like\n");
+ printf(" cdrecord-ProDVD with blank= and -multi\n");
+ printf(
+ " --single_track accept only last argument as source_address\n");
+
+#ifdef Cdrskin_libburn_has_stream_recordinG
+ printf(
+ " stream_recording=\"on\"|\"off\" \"on\" requests to prefer speed\n");
+ printf(
+ " over write error management.\n");
+#endif
+
+#ifdef Cdrskin_allow_libburn_taO
+ 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");
+#else
+ printf(
+ " tao_to_sao_tsize= substitute -tao by -sao and eventually\n");
+ printf(" augment input from \"-\" by tsize=\n");
+ printf(" (set tao_to_sao_tsize=0 to disable it)\n");
+#endif
+
+#ifdef Cdrskin_libburn_has_get_spacE
+ printf(
+ " --tell_media_space prints maximum number of writeable data blocks\n");
+#endif
+
+ printf(
+ " write_start_address= write to given byte address (DVD+RW)\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 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");
+#ifdef Cdrskin_libburn_has_multI
+ 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");
+#endif
+ fprintf(stderr,"\t-toc\t\tretrieve and print TOC/PMA data\n");
+ fprintf(stderr,
+ "\t-atip\t\tretrieve media state, print \"Is *erasable\"\n");
+#ifdef Cdrskin_libburn_has_set_waitinG
+ fprintf(stderr,
+ "\tminbuf=percent\tset lower limit for drive buffer modesty\n");
+#endif
+#ifdef Cdrskin_libburn_has_multI
+ fprintf(stderr,
+ "\t-multi\t\tgenerate a TOC that allows multi session\n");
+#endif
+ 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");
+#ifdef Cdrskin_allow_libburn_taO
+ fprintf(stderr,"\t-tao\t\tWrite disk in TAO mode.\n");
+#endif
+ fprintf(stderr,"\t-dao\t\tWrite disk in SAO mode.\n");
+ fprintf(stderr,"\t-sao\t\tWrite disk in SAO mode.\n");
+ fprintf(stderr,"\t-raw96r\t\tWrite disk in RAW/RAW96R mode\n");
+ fprintf(stderr,"\ttsize=#\t\tannounces exact size of source data\n");
+ fprintf(stderr,"\tpadsize=#\tAmount of padding\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-isosize\tUse iso9660 file system size for next data track\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) {
+ 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");
+
+ } else if(strcmp(argv[i],"-raw96r")==0) {
+ strcpy(o->write_mode_name,"RAW/RAW96R");
+
+ } else if(strcmp(argv[i],"-sao")==0 || strcmp(argv[i],"-dao")==0) {
+ strcpy(o->write_mode_name,"SAO");
+
+ } else if(strcmp(argv[i],"-scanbus")==0) {
+ o->no_whitelist= 1;
+
+ } else if(strcmp(argv[i],"-tao")==0) {
+ strcpy(o->write_mode_name,"TAO");
+
+ } else if(strcmp(argv[i],"-v")==0 || strcmp(argv[i],"-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(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(argv[i],"-version")==0) {
+ int major, minor, micro;
+
+ printf(
+"Cdrecord 2.01-Emulation Copyright (C) 2006-2008, see libburnia-project.org\n");
+ 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);
+ 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 */
+ }
+ {ret= 2; goto ex;}
+
+ } else if(strcmp(argv[i],"-waiti")==0) {
+ o->do_waiti= 1;
+
+ }
+
+ }
+ ret= 1;
+final_checks:;
+ if(flag&1)
+ goto ex;
+
+ 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");
+ }
+
+#ifndef Cdrskin_libburn_no_burn_preset_device_opeN
+ burn_preset_device_open(o->drive_exclusive
+#ifdef Cdrskin_libburn_preset_device_familY
+ | (o->drive_scsi_dev_family<<2)
+ | ((!!o->drive_fcntl_f_setlk)<<5)
+#endif
+ ,
+ o->drive_blocking,
+ o->abort_on_busy_drive);
+#endif /* ! Cdrskin_libburn_no_burn_preset_device_opeN */
+
+ 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;
+ }
+ }
+
+#ifdef Cdrskin_libburn_has_convert_fs_adR
+
+ 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);
+ }
+ }
+
+#endif /* Cdrskin_libburn_has_convert_fs_adR */
+
+ }
+
+#ifdef Cdrskin_libburn_has_allow_untested_profileS
+ burn_allow_untested_profiles(!!o->allow_untested_media);
+#endif
+
+ /* 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:
+ - write mode which does not demand a track size in advance
+ - obtain minimum drive speed (for cdrskin -atip)
+ - obtain MMC profile of inserted media (for cdrskin -v -atip)
+ - a possibility to implement cdrskin -multi
+ - a possibilty to implement cdrskin -reset
+*/
+
+
+/** <<< Hopefully obsolete:
+ Limit to prevent int rollovers within libburn as long as not everything is
+ changed to 64 bit off_t : 2 GB minus 800 MB for eventual computations.
+#define Cdrskin_tracksize_maX 1308622848
+*/
+#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 accomodate to the slightley 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;
+ double x_speed;
+ int adjust_speed_to_drive;
+ int gracetime;
+ int dummy_mode;
+ int force_is_set;
+ int stream_recording_is_set;
+ int single_track;
+ int prodvd_cli_compatible;
+
+ int do_devices;
+
+ int do_scanbus;
+
+ int do_load;
+
+ int do_checkdrive;
+
+ int do_msinfo;
+ char msifile[Cdrskin_strleN];
+
+ int do_atip;
+ int do_list_formats;
+
+ 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= - reserved -
+ 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-RE
+ 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 RAW96/R). See libburn.
+ Controled by preskin->write_mode_name */
+ enum burn_write_types write_type;
+ int block_type;
+ int multi;
+ int modesty_on_drive;
+ 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;
+
+ /** 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;
+
+ 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;
+
+
+ /** 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;
+ int drive_is_busy; /* Whether drive was told to do something cancel-worthy */
+ struct burn_drive *grabbed_drive;
+
+#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->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->single_track= 0;
+ o->prodvd_cli_compatible= 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_formats= 0;
+ 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->modesty_on_drive= 0;
+ 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->track_type_by_default= 1;
+ for(i=0;itracklist[i]= NULL;
+ o->track_counter= 0;
+ o->supposed_track_idx= -1;
+ 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->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);
+
+#ifndef Cdrskin_extra_leaN
+ Cdradrtrn_destroy(&(skin->adr_trn),0);
+#endif /* ! Cdrskin_extra_leaN */
+
+ Cdrpreskin_destroy(&(skin->preskin),0);
+ if(skin->drives!=NULL)
+ burn_drive_info_free(skin->drives);
+ free((char *) skin);
+ *o= NULL;
+ 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)
+{
+ burn_drive_get_adr(&skin->drives[skin->driveno],skin->device_adr);
+ *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 || 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 *swap_audio_bytes, 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;
+ *swap_audio_bytes= skin->swap_audio_bytes;
+ 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);
+}
+
+
+/** 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;
+
+ 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);
+}
+
+
+/** 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. */
+#ifdef Cdrskin_libburn_has_get_best_speeD
+ k_speed= -1;
+#else
+ k_speed= Cdrskin_libburn_speed_factoR+Cdrskin_libburn_speed_addoN;
+#endif
+ } 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));
+
+#ifdef Cdrskin_libburn_has_get_best_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;
+ }
+ }
+#endif /* Cdrskin_libburn_has_get_best_speeD */
+
+ burn_drive_set_speed(skin->drives[skin->driveno].drive,k_speed,k_speed);
+
+#ifdef Cdrskin_libburn_has_set_waitinG
+ modesty= skin->modesty_on_drive;
+ burn_drive_set_buffer_waiting(skin->drives[skin->driveno].drive,
+ modesty, -1, -1, -1,
+ skin->min_buffer_percent,
+ skin->max_buffer_percent);
+#endif
+ return(1);
+}
+
+
+int Cdrskin_determine_media_caps(struct CdrskiN *skin, int flag)
+{
+#ifdef Cdrskin_libburn_has_get_multi_capS
+ 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)
+ return(0);
+ skin->media_is_overwriteable= !!caps->start_adr;
+ skin->media_does_multi= !!caps->multi_session;
+ return(1);
+#else /* Cdrskin_libburn_has_get_multi_capS */
+ return(-1);
+#endif
+}
+
+
+/** 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
+ @return <=0 error, 1 success
+*/
+int Cdrskin_grab_drive(struct CdrskiN *skin, int flag)
+{
+ int ret,i,profile_number;
+ struct burn_drive *drive;
+ char profile_name[80];
+ enum burn_disc_status s;
+#ifdef Cdrskin_grab_abort_brokeN
+ int restore_handler= 0;
+#endif
+
+ i= 0;/* as long as its use is conditional, so gcc -Wall does not complain */
+
+ if(skin->drive_is_grabbed)
+ Cdrskin_release_drive(skin,0);
+
+ if(flag&1) {
+ skin->driveno= 0;
+ drive= NULL;
+ skin->grabbed_drive= drive;
+ } else {
+ drive= skin->drives[skin->driveno].drive;
+ skin->grabbed_drive= drive;
+ }
+
+#ifdef Cdrskin_grab_abort_brokeN
+
+ /* There seems to be no way to get a drive out of status BURN_DRIVE_GRABBING
+ So try to block out signals if there is a signal handler installed */
+ if(skin->preskin->abort_handler==1 ||
+ skin->preskin->abort_handler==3 ||
+ skin->preskin->abort_handler==4) {
+ Cleanup_set_handlers(NULL,NULL,2);
+ restore_handler= 1;
+ }
+
+#endif /* ! Cdrskin_grab_abort_brokeN */
+
+#ifndef Cdrskin_oldfashioned_api_usE
+
+
+ if(flag&1) {
+ ret= burn_drive_scan_and_grab(&(skin->drives),skin->preskin->device_adr,
+ !(flag&2));
+ 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;in_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);
+ }
+
+ }
+
+#else
+
+ {
+
+#endif /* Cdrskin_oldfashioned_api_usE */
+
+ ret= burn_drive_grab(drive,!(flag&2));
+ if(ret==0) {
+ if(!(flag&4))
+ fprintf(stderr,"cdrskin: FATAL : unable to open drive %d\n",
+ skin->driveno);
+ goto ex;
+ }
+
+#ifdef Cdrskin_is_erasable_on_load_is_brokeN
+ /* RIP-14.5 + LITE-ON 48125S produce a false status if tray was unloaded */
+ /* Therefore the first grab was just for loading */
+ skin->drive_is_grabbed= 1; /* message to eventual abort handler */
+ burn_drive_release(drive,0);
+ skin->drive_is_grabbed= 0;
+
+ /* now grab the drive for real */
+ ret= burn_drive_grab(drive,!(flag&2));
+ if(ret==0) {
+ if(!(flag&4))
+ fprintf(stderr,"cdrskin: FATAL : unable to open drive %d\n",
+ skin->driveno);
+ goto ex;
+ }
+#endif /* ! Cdrskin_is_erasable_on_load_is_brokeN */
+
+ }
+ 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;
+#ifdef Cdrskin_libburn_has_get_profilE
+ 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;
+ }
+ }
+#endif /* Cdrskin_libburn_has_get_profilE */
+ 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:;
+
+#ifdef Cdrskin_grab_abort_brokeN
+ if(restore_handler) {
+ int Cdrskin_abort_handler(struct CdrskiN *, int, int);
+ Cleanup_set_handlers(skin,(Cleanup_app_handler_T) Cdrskin_abort_handler,4);
+ }
+#endif /* Cdrskin_grab_abort_brokeN */
+
+ 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)
+{
+
+#ifdef Cdrskin_libburn_has_burn_aborT
+
+ int ret;
+
+#else
+
+ int wait_grain= 100000,first_status= 1;
+ double start_time,last_time,current_time;
+
+#endif /* ! Cdrskin_libburn_has_burn_aborT */
+
+ struct burn_progress p;
+ enum burn_drive_status drive_status= BURN_DRIVE_GRABBING;
+
+ if(getpid()!=skin->control_pid) {
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "\ncdrskin_debug: ABORT : [%d] Thread rejected: pid=%d, signum=%d\n",
+ skin->control_pid,getpid(),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_extra_leaN
+ if(skin->fifo!=NULL)
+ Cdrfifo_close_all(skin->fifo,0);
+#endif
+
+#ifdef Cdrskin_libburn_has_burn_aborT
+
+ /* 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");
+ }
+
+ 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");
+ return(0);
+ }
+ fprintf(stderr,"\n");
+
+#else /* Cdrskin_libburn_has_burn_aborT */
+
+ if(skin->grabbed_drive!=NULL) {
+ drive_status= burn_drive_get_status(skin->grabbed_drive,&p);
+ if(drive_status!=BURN_DRIVE_IDLE && !skin->drive_is_grabbed)
+ skin->drive_is_grabbed= 2;
+ if(drive_status!=BURN_DRIVE_IDLE && !skin->drive_is_busy)
+ skin->drive_is_busy= 2;
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: ABORT : Drive status: %d\n",
+ (int) drive_status));
+ }
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "cdrskin_debug: ABORT : drive_is_grabbed=%d , drive_is_busy=%d (%X)\n",
+ skin->drive_is_grabbed,skin->drive_is_busy,
+ (unsigned int) skin->grabbed_drive));
+
+ if(skin->drive_is_grabbed) {
+ if(skin->drive_is_busy && skin->grabbed_drive!=NULL) {
+ if(drive_status==BURN_DRIVE_WRITING || drive_status==BURN_DRIVE_READING) {
+ fprintf(stderr,"cdrskin: ABORT : Trying to cancel drive operation.\n");
+ burn_drive_cancel(skin->grabbed_drive);
+ } else if(drive_status==BURN_DRIVE_GRABBING) {
+
+#ifndef Cdrskin_oldfashioned_api_usE
+ int ret;
+
+ fprintf(stderr,
+ "cdrskin: ABORT : Trying to close drive in process of grabbing\n");
+
+ /* >>> ??? rather inquire driveno from
+ skin->grabbed_drive->global_index ? */;
+
+ ret= burn_drive_info_forget(&(skin->drives[skin->driveno]),1);
+ if(ret<=0)
+ fprintf(stderr,
+ "cdrskin: ABORT : Attempt to close drive failed (ret= %d)\n",ret);
+ else {
+ skin->drive_is_grabbed= 0;
+ skin->grabbed_drive= NULL;
+ goto try_to_finish_lib;
+ }
+
+#else
+ /* >>> what to do in this state ? */;
+#endif /* Cdrskin_oldfashioned_api_usE */
+
+ } else if(drive_status!=BURN_DRIVE_IDLE) {
+ fprintf(stderr,
+ "cdrskin: ABORT : Will wait for current operation to end\n");
+ }
+ 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");
+ }
+ last_time= start_time= Sfile_microtime(0);
+ while(1) {
+ drive_status= burn_drive_get_status(skin->grabbed_drive,&p);
+ if(drive_status==BURN_DRIVE_IDLE)
+ break;
+ usleep(wait_grain);
+ current_time= Sfile_microtime(0);
+ if(current_time-last_time>=1.0) {
+ if(first_status)
+ fprintf(stderr,"\n");
+ first_status= 0;
+ fprintf(stderr,"\rcdrskin: ABORT : Status %d. Waiting for status %d since %d seconds (%d max)",
+ (int) drive_status, (int) BURN_DRIVE_IDLE,
+ (int) (current_time-start_time),skin->abort_max_wait);
+ last_time= current_time;
+ }
+ if(current_time-start_time>=skin->abort_max_wait) {
+ fprintf(stderr,
+ "\ncdrskin: ABORT : Cannot cancel burn session and release drive.\n");
+ return(0);
+ }
+ }
+ fprintf(stderr,"\ncdrskin: ABORT : Status %d.\n",(int) drive_status);
+ }
+ fprintf(stderr,"cdrskin: ABORT : Trying to release drive.\n");
+ Cdrskin_release_drive(skin,0);
+ }
+
+#ifndef Cdrskin_oldfashioned_api_usE
+try_to_finish_lib:;
+#endif
+
+ if(skin->lib_is_initialized) {
+ fprintf(stderr,"cdrskin: ABORT : Trying to finish libburn.\n");
+ burn_finish();
+ }
+
+#endif /* ! Cdrskin_libburn_has_burn_aborT */
+
+ 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");
+ return(1);
+}
+
+
+/** 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;in_drives;i++) {
+
+#ifdef Cdrskin_libburn_has_drive_get_adR
+ ret= burn_drive_get_adr(&(skin->drives[i]), adr);
+ if(ret<=0)
+ continue;
+#else
+ ret= 1; /* to please gcc -Wall */
+ strcpy(adr,skin->drives[i].location);
+#endif
+
+ 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((*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>skin->n_drives)
+ goto fallback;
+
+#ifdef Cdrskin_libburn_has_drive_get_adR
+ ret= burn_drive_get_adr(&(skin->drives[driveno]), adr);
+ if(ret<=0)
+ goto fallback;
+ loc= adr;
+#else
+ adr[0]= 0; /* to please gcc -Wall */
+ loc= skin->drives[driveno].location;
+ if(loc==NULL)
+ goto fallback;
+#endif
+
+#ifdef Cdrskin_libburn_has_get_drive_rolE
+ ret= burn_drive_get_drive_role(skin->drives[driveno].drive);
+ if(ret!=1) {
+ sprintf(btldev,"stdio:%s",adr);
+ {ret= 2; goto adr_translation;}
+ }
+#endif
+
+#ifdef Cdrskin_libburn_has_convert_scsi_adR
+ 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;
+ }
+ }
+#endif
+
+ 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)
+{
+#ifdef Cdrskin_libburn_has_random_access_rW
+ 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);
+
+#else /* Cdrskin_libburn_has_random_access_rW */
+ return(-1);
+#endif
+}
+
+
+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");
+
+#ifdef Cdrskin_libburn_has_burn_disc_unsuitablE
+
+ } 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");
+
+#endif /* Cdrskin_libburn_has_burn_disc_unsuitablE */
+
+ } else
+ printf("-unknown status code-\n");
+
+ if(flag&2)
+ return(1+pseudo_appendable);
+
+#ifdef Cdrskin_libburn_has_get_profilE
+ 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");
+ }
+#endif
+
+ return(1+pseudo_appendable);
+}
+
+
+/** Perform operations -scanbus or --devices
+ @param flag Bitfield for control purposes:
+ bit0= perform --devices rather than -scanbus
+ @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;
+ char shellsafe[5*Cdrskin_strleN+2],perms[40],btldev[Cdrskin_adrleN];
+ char adr[Cdrskin_adrleN],*raw_dev,*drives_shown= NULL;
+ struct stat stbuf;
+
+ drives_shown= malloc(skin->n_drives+1);
+ if(drives_shown==NULL)
+ {ret= -1; goto ex;}
+ for(i=0;in_drives;i++)
+ drives_shown[i]= 0;
+ if(flag&1) {
+ printf("cdrskin: Overview of accessible drives (%d found) :\n",
+ skin->n_drives);
+ printf("-----------------------------------------------------------------------------\n");
+ for(i=0;in_drives;i++) {
+
+#ifdef Cdrskin_libburn_has_drive_get_adR
+ ret= burn_drive_get_adr(&(skin->drives[i]), adr);
+ if(ret<=0) {
+ /* >>> one should massively complain */;
+ continue;
+ }
+#else
+ strcpy(adr,skin->drives[i].location);
+#endif
+
+ 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(strlen(adr)>=Cdrskin_strleN)
+ Text_shellsafe("failure:oversized string",shellsafe,0);
+ else
+ Text_shellsafe(adr,shellsafe,0);
+ printf("%d dev=%s %s : '%s' '%s'\n",
+ i,shellsafe,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(busno= 0;busno<=busmax;busno++) {
+ first_on_bus= 1;
+ for(i=0;in_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);
+ 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];
+
+ 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>=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 : ");
+#ifdef Cdrskin_libburn_has_get_drive_rolE
+ 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!=1)
+ printf("%s\n","Emulated (stdio-drive)");
+ else
+#endif
+ 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;}
+
+ printf("Driver flags : %s\n","BURNFREE");
+#ifdef Cdrskin_allow_libburn_taO
+
+ 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");
+ if((drive_info->raw_block_types & BURN_BLOCK_RAW96R) &&
+ strstr(profile_name,"DVD")!=profile_name &&
+ strstr(profile_name,"BD")!=profile_name)
+ printf(" RAW/RAW96R");
+ printf("\n");
+
+#else
+ printf("Supported modes: %s\n","SAO RAW/R96R");
+#endif
+ 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);
+ }
+#ifdef Cdrskin_libburn_has_multI
+ ret= burn_disc_track_lba_nwa(drive,o,0,&lba,nwa);
+#else
+ ret= 0;
+ lba= 0;/* silence gcc warning */
+#endif
+ if(o!=NULL)
+ burn_write_opts_free(o);
+ return(ret);
+}
+
+
+/** 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;
+ struct burn_drive *drive;
+ struct burn_disc *disc= NULL;
+ struct burn_session **sessions;
+ struct burn_track **tracks;
+ struct burn_toc_entry toc_entry;
+
+ drive= skin->drives[skin->driveno].drive;
+
+ 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");
+ return(1);
+ }
+ }
+ goto cannot_read;
+ }
+ sessions= burn_disc_get_sessions(disc,&num_sessions);
+ if(flag&1) {
+ for(session_no= 0; session_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_nodriveno));
+ 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;
+ } else if(s==BURN_DISC_EMPTY) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ printf("Current: none\n");
+ ret= 0; goto ex;
+ }
+
+
+#ifdef Cdrskin_atip_speed_brokeN
+
+ /* <<< terrible stunt to get correct media speed info */
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,
+ "cdrskin_debug: redoing startup for speed inquiry stabilization\n"));
+
+
+#ifndef Cdrskin_oldfashioned_api_usE
+
+ if(strlen(skin->preskin->device_adr)<=0)
+ burn_drive_get_adr(&(skin->drives[skin->driveno]),
+ skin->preskin->device_adr);
+
+ Cdrskin_release_drive(skin,0);
+ burn_finish();
+ if(!burn_initialize()) {
+ fflush(stdout);
+ fprintf(stderr,"cdrskin : FATAL : Re-initialization of libburn failed\n");
+ {ret= 0; goto ex;}
+ }
+#ifdef Cdrskin_libburn_has_allow_untested_profileS
+ burn_allow_untested_profiles(!!skin->preskin->allow_untested_media);
+#endif
+ ret= Cdrskin_grab_drive(skin,1); /* uses burn_drive_scan_and_grab() */
+ if(ret<=0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+
+#else /* ! Cdrskin_oldfashioned_api_usE */
+
+ Cdrskin_release_drive(skin,0);
+ burn_finish();
+ if(!burn_initialize()) {
+ fflush(stdout);
+ fprintf(stderr,"cdrskin : FATAL : Re-initialization of libburn failed\n");
+ {ret= 0; goto ex;}
+ }
+#ifdef Cdrskin_libburn_has_allow_untested_profileS
+ burn_allow_untested_profiles(!!skin->preskin->allow_untested_media);
+#endif
+ if(strlen(skin->preskin->device_adr)>0)
+ burn_drive_add_whitelist(skin->preskin->device_adr);
+ while(!burn_drive_scan(&(skin->drives),&(skin->n_drives)))
+ usleep(1002);
+ ret= Cdrskin_grab_drive(skin,0);
+ if(ret<=0)
+ return(ret);
+ drive= skin->drives[skin->driveno].drive;
+
+#endif /* Cdrskin_oldfashioned_api_usE */
+
+#endif /* Cdrskin_atip_speed_brokeN */
+
+ profile_name[0]= 0;
+#ifdef Cdrskin_libburn_has_get_profilE
+ ret= burn_disc_get_profile(drive,&profile_number,profile_name);
+ if(ret<=0) {
+ profile_number= 0;
+ strcpy(profile_name, "-unidentified-");
+ }
+#endif /* Cdrskin_libburn_has_get_profilE */
+
+ ret= Cdrskin_checkdrive(skin,profile_name,1);
+ if(ret<=0)
+ return(ret);
+
+#ifdef Cdrskin_libburn_has_read_atiP
+ 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;
+ }
+ }
+#endif
+
+#ifdef Cdrskin_libburn_has_burn_disc_unsuitablE
+ if(burn_disc_get_status(drive) == BURN_DISC_UNSUITABLE) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+#ifdef Cdrskin_libburn_has_get_profilE
+ if(profile_name[0])
+ printf("Current: %s\n",profile_name);
+ else
+ printf("Current: UNSUITABLE MEDIA (Profile %4.4Xh)\n",profile_number);
+#else
+ printf("Current: UNSUITABLE MEDIA\n");
+#endif
+ }
+ {ret= 0; goto ex;}
+ }
+#endif /* Cdrskin_libburn_has_burn_disc_unsuitablE */
+
+ 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(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");
+ }
+ 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.
+ */
+ 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");
+ }
+
+#ifdef Cdrskin_libburn_has_get_start_end_lbA
+ { int start_lba,end_lba,min,sec,fr;
+ 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,&min,&sec,&fr);
+ printf(" ATIP start of lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n",
+ end_lba,min,sec,fr);
+ }
+ }
+#endif /* Cdrskin_libburn_has_get_start_end_lbA */
+
+ printf(" 1T speed low: %.f 1T speed high: %.f\n",x_speed_min,x_speed_max);
+ }
+
+ ret= 1;
+ if(flag&1)
+ Cdrskin_toc(skin,1);/*cdrecord seems to ignore -toc errors if -atip is ok */
+ex:;
+ Cdrskin_release_drive(skin,0);
+
+ /* A61227 :
+ A kindof race condition with -atip on filled CD-RW and following grabs
+ under SuSE 9.3. Waiting seems to help. I suspect the media demon. */
+ usleep(200000);
+
+ 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;
+ off_t size;
+ unsigned dummy;
+ char status_text[80], profile_name[90];
+
+#ifdef Cdrskin_libburn_has_burn_disc_formaT
+
+ 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= 2; 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);
+
+ 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:;
+ Cdrskin_release_drive(skin,0);
+ return(ret);
+
+#else /* Cdrskin_libburn_has_burn_disc_formaT */
+
+ fprintf(stderr,
+ "cdrskin: SORRY: libburn is too old to obtain format list info\n");
+ return(2);
+
+#endif /* Cdrskin_libburn_has_burn_disc_formaT */
+}
+
+
+#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;
+
+#ifdef Cdrskin_libburn_has_get_spacE
+ 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;
+
+#endif /* Cdrskin_libburn_has_get_spacE */
+ 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(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;
+ off_t size;
+ unsigned dummy;
+ double start_time;
+ char *verb= "blank", *presperf="blanking", *fmt_text= "...";
+ char profile_name[80];
+ 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;
+#ifdef Cdrskin_libburn_has_get_profilE
+ if(skin->grabbed_drive)
+ burn_disc_get_profile(skin->grabbed_drive,&profile_number,profile_name);
+#endif
+
+ 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;
+
+#ifdef Cdrskin_libburn_has_pretend_fulL
+ 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);
+ s= burn_disc_get_status(drive);
+ } else
+ hint_force= 1;
+ }
+#endif /* Cdrskin_libburn_has_pretend_fulL */
+
+ 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 , if_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) { /* DVD-RAM , BD-RE */;
+#ifdef Cdrskin_libburn_has_burn_disc_formaT
+ 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;
+ }
+#endif
+ } 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 == 0x43)) {
+ fprintf(stderr,
+ "cdrskin: SORRY : blank=%s for now does DVD-RAM and BD-RE 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)) {
+ Cdrskin_release_drive(skin,0);
+ 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 */
+
+ skin->drive_is_busy= 1;
+ if(do_format==0 || do_format==2) {
+ burn_disc_erase(drive,skin->blank_fast);
+
+#ifdef Cdrskin_libburn_has_burn_disc_formaT
+ } 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);
+#endif
+
+ } 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);
+ 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;
+ fprintf(stderr,
+ "\rcdrskin: %s ( done %.1f%% , %lu seconds elapsed ) ",
+ presperf,percent,(unsigned long) (Sfile_microtime(0)-start_time));
+ }
+ sleep(1);
+ loop_counter++;
+ }
+blanking_done:;
+#ifdef Cdrskin_libburn_has_wrote_welL
+ wrote_well = burn_drive_wrote_well(drive);
+#endif
+ if(wrote_well && skin->verbosity>=Cdrskin_verbose_progresS) {
+ fprintf(stderr,
+ "\rcdrskin: %s done \n",
+ 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,
+ "\rcdrskin: %s failed \n",
+ presperf);
+ ret= !!(wrote_well);
+ex:;
+ skin->drive_is_busy= 0;
+ if(skin->drive_is_grabbed)
+ Cdrskin_release_drive(skin,0);
+ return(ret);
+}
+
+
+/** 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,
+ 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,written_bytes= 0.0,written_total_bytes= 0.0,buffer_size;
+ double fixed_size,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,space,advance_interval=0,new_mb,old_mb,time_to_tell;
+ int fs,bs,old_track_idx,buffer_fill,formatting= 0,use_data_image_size;
+ char fifo_text[80],mb_text[40];
+ char *debug_mark= ""; /* use this to prepend a marker text for experiments */
+
+ /* for debugging */
+ static double last_fifo_in= 0.0,last_fifo_out= 0.0,curr_fifo_in,curr_fifo_out;
+
+ 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 */
+
+#ifdef Cdrskin_libburn_has_bd_formattinG
+ if(drive_status==BURN_DRIVE_FORMATTING)
+ formatting= 1;
+#endif
+
+ if(drive_status==BURN_DRIVE_WRITING) {
+ ;
+ } else if(drive_status==BURN_DRIVE_WRITING_LEADIN
+
+#ifdef Cdrskin_allow_libburn_taO
+ || drive_status==BURN_DRIVE_WRITING_PREGAP
+#endif
+ || formatting) {
+ if(time_to_tell || skin->is_writing) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(skin->is_writing)
+ fprintf(stderr,"\n");
+ fprintf(stderr,
+ "\rcdrskin: %s (burning since %.f seconds) ",
+ (formatting?"formatting":"working pre-track"), elapsed_total_time);
+ }
+ skin->is_writing= 0;
+ advance_interval= 1;
+ }
+ {ret= 2; goto ex;}
+ } else if(drive_status==BURN_DRIVE_WRITING_LEADOUT
+
+#ifdef Cdrskin_allow_libburn_taO
+ || drive_status==BURN_DRIVE_CLOSING_TRACK
+ || drive_status==BURN_DRIVE_CLOSING_SESSION
+#endif
+
+ ) {
+
+#ifdef Cdrskin_allow_libburn_taO
+ if(drive_status==BURN_DRIVE_CLOSING_SESSION &&
+ skin->previous_drive_status!=drive_status)
+ {printf("\nFixating...\n"); fflush(stdout);}
+#endif
+
+ if(time_to_tell || skin->is_writing) {
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ if(skin->is_writing)
+ fprintf(stderr,"\n");
+ fprintf(stderr,
+ "\rcdrskin: working post-track (burning since %.f seconds) ",
+ elapsed_total_time);
+ }
+ skin->is_writing= 0;
+ advance_interval= 1;
+ }
+ {ret= 2; goto ex;}
+ } else
+ goto thank_you_for_patience;
+
+ old_track_idx= skin->supposed_track_idx;
+#ifdef Cdrskin_progress_track_brokeN
+ /* with libburn.0.2 there is always reported 0 as p->track */
+ if(written_bytes<0) { /* track hop ? */
+ if(skin->supposed_track_idx+1track_counter)
+ skin->supposed_track_idx++;
+ }
+ /* >>> ask eventual fifo about writing fd */;
+ if(p->track>0)
+ skin->supposed_track_idx= p->track;
+#else /* Cdrskin_progress_track_brokeN */
+ skin->supposed_track_idx= p->track;
+#endif /* ! Cdrskin_progress_track_brokeN */
+
+ if(old_track_idx>=0 && old_track_idxsupposed_track_idx) {
+ 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+1,fixed_size,fixed_size+padding,
+ (fixed_size+padding)/sector_size);
+ }
+
+ 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");
+ fprintf(stderr,
+ "\rcdrskin: thank you for being patient since %.f seconds ",
+ elapsed_total_time);
+ }
+ 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)
+ printf("%-78.78s\r","");
+ 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->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;
+ }
+ }
+ }
+ 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;
+#ifdef Cdrskin_libburn_has_buffer_progresS
+ if(p->buffer_capacity>0)
+ buffer_fill= (double) (p->buffer_capacity - p->buffer_available)*100.0
+ / (double) p->buffer_capacity;
+
+#endif /* Cdrskin_libburn_has_buffer_progresS */
+ if(buffer_fill<*min_buffer_fill)
+ *min_buffer_fill= buffer_fill;
+
+ printf("\r%sTrack %-2.2d: %s MB written %s[buf %3d%%] %4.1fx.",
+ debug_mark,skin->supposed_track_idx+1,mb_text,fifo_text,
+ buffer_fill,measured_speed/speed_factor);
+ 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)
+ printf("\n");
+ skin->is_writing= 1;
+ }
+ printf("\rTrack %-2.2d: %3d MB written ",
+ skin->supposed_track_idx+1,(int) (written_total_bytes/1024.0/1024.0));
+ fflush(stdout);
+ if(skin->is_writing==0)
+ printf("\n");
+
+#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);
+}
+
+
+#ifdef Cdrskin_libburn_write_mode_ruleS
+
+/** 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, current_is_cd= 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(profile_number!=0x09 && profile_number!=0x0a)
+ current_is_cd= 0;
+ 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;
+ if(wt==BURN_WRITE_RAW)
+ strcpy(skin->preskin->write_mode_name,"RAW/RAW96R");
+ else 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);
+ }
+ if(strcmp(skin->preskin->write_mode_name,"RAW/RAW96R")==0) {
+ skin->write_type= BURN_WRITE_RAW;
+ skin->block_type= BURN_BLOCK_RAW96R;
+ } else 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;
+ }
+ 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);
+}
+
+#else /* Cdrskin_libburn_write_mode_ruleS */
+
+/** Determines the effective write mode and checks whether the drive promises
+ to support it.
+ @param s state of target media, obtained from burn_disc_get_status(),
+ submit BURN_DISC_BLANK if no real state is available
+*/
+int Cdrskin_activate_write_mode(struct CdrskiN *skin, enum burn_disc_status s,
+ int flag)
+{
+ int ok, was_still_default= 0, block_type_demand,track_type,sector_size, i;
+ int profile_number= -1, track_type_1= 0, mixed_mode= 0, unpredicted_size= 0;
+ int might_do_tao= 0, might_do_sao= 1, allows_multi= 1, ret, current_is_cd= 1;
+ int use_data_image_size, current_is_overwriteable= 0;
+ struct burn_drive_info *drive_info = NULL;
+ char profile_name[80];
+ double fixed_size= 0.0, tao_to_sao_tsize= 0.0, dummy;
+#ifdef Cdrskin_libburn_has_get_multi_capS
+ struct burn_multi_caps *caps = NULL;
+#endif
+
+ profile_name[0]= 0;
+#ifdef Cdrskin_libburn_has_get_profilE
+ if(skin->grabbed_drive)
+ burn_disc_get_profile(skin->grabbed_drive,&profile_number,profile_name);
+ if(profile_number!=0x09 && profile_number!=0x0a)
+ current_is_cd= 0;
+#endif
+
+#ifdef Cdrskin_allow_libburn_taO
+ might_do_tao= 1;
+#endif
+#ifdef Cdrskin_libburn_has_get_multi_capS
+ ret = burn_disc_get_multi_caps(skin->grabbed_drive,BURN_WRITE_NONE,&caps,0);
+ if (ret<0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Cannot obtain write mode capabilities of drive\n");
+ return(0);
+ } else if(ret==0) {
+ fprintf(stderr,
+ "cdrskin: SORRY : Cannot find any suitable write mode for this media\n");
+ burn_disc_free_multi_caps(&caps);
+ return(0);
+ }
+ might_do_tao= caps->might_do_tao;
+ might_do_sao= caps->might_do_sao;
+ burn_disc_free_multi_caps(&caps);
+#endif
+
+ for(i=0;itrack_counter;i++) {
+ Cdrtrack_get_track_type(skin->tracklist[i],&track_type,§or_size,0);
+ if(i==0)
+ track_type_1= track_type;
+ else if(track_type_1!=track_type)
+ mixed_mode= 1;
+ Cdrtrack_get_size(skin->tracklist[i],&fixed_size,
+ &tao_to_sao_tsize,&dummy,&use_data_image_size,2);
+
+ /* <<< until CD-SAO does fill-up: filluped last CD track length undefined */
+ if(fixed_size<=0 &&
+ !(current_is_cd==0 && skin->fill_up_media && i==skin->track_counter-1))
+ unpredicted_size= 1+(tao_to_sao_tsize<=0);
+ }
+
+ if(strcmp(skin->preskin->write_mode_name,"DEFAULT")==0) {
+ was_still_default= 1;
+
+ if((s==BURN_DISC_APPENDABLE || mixed_mode ||
+ (current_is_cd && skin->fill_up_media) ) && might_do_tao) {
+ strcpy(skin->preskin->write_mode_name,"TAO");
+ was_still_default= 2; /* prevents trying of SAO if drive dislikes TAO*/
+ } else if(unpredicted_size && might_do_tao) {
+ strcpy(skin->preskin->write_mode_name,"TAO");
+ if(unpredicted_size>1)
+ was_still_default= 2; /* prevents trying of SAO */
+ } else if(s==BURN_DISC_BLANK && skin->track_counter==1 &&
+ skin->fill_up_media && might_do_sao && !current_is_cd) {
+ /* to avoid problems on my NEC with blank DVD-RW and TAO fill_up_media */
+ strcpy(skin->preskin->write_mode_name,"SAO");
+ } else if((profile_number==0x1a || profile_number==0x13 ||
+ profile_number==0x12 ||
+ profile_number==0x11 || profile_number==0x14 ||
+ profile_number==0x15 ||
+ profile_number==0x1b || profile_number==0x2b)
+ && might_do_tao) {
+ /* DVD+RW, DVD-RW Restricted Overwrite, DVD-RAM,
+ DVD-R[W][/DL] Sequential Recording, DVD+R[/DL] */
+ strcpy(skin->preskin->write_mode_name,"TAO");
+ } else {
+ strcpy(skin->preskin->write_mode_name,"SAO");
+ }
+ }
+ if(strcmp(skin->preskin->write_mode_name,"RAW/RAW96R")==0) {
+ skin->write_type= BURN_WRITE_RAW;
+ skin->block_type= BURN_BLOCK_RAW96R;
+
+#ifdef Cdrskin_allow_libburn_taO
+ } else if(strcmp(skin->preskin->write_mode_name,"TAO")==0) {
+ skin->write_type= BURN_WRITE_TAO;
+ skin->block_type= BURN_BLOCK_MODE1;
+#endif /* Cdrskin_allow_libburn_taO */
+
+ } else {
+ strcpy(skin->preskin->write_mode_name,"SAO");
+ skin->write_type= BURN_WRITE_SAO;
+ skin->block_type= BURN_BLOCK_SAO;
+ }
+
+ /* check whether desired type combination is available with drive */
+ if(skin->driveno<0 || skin->driveno>skin->n_drives) {
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(printf("cdrskin_debug: WARNING : No drive selected with Cdrskin_activate_write_mode\n"));
+ goto it_is_done;
+ }
+ drive_info= skin->drives+skin->driveno;
+
+ /* <<< this should become a libburn API function.The knowledge about TAO audio
+ track block type is quite inappropriate here. It refers to a habit of
+ spc_select_write_params() (and MMC-1 table 61). But the knowledge about
+ the tracklist is rather cdrskin realm. (ponder ...)
+ */
+check_with_drive:;
+ ok= 0;
+ if(strstr(profile_name,"DVD")==profile_name) {
+
+ /* >>> drive_info does not reflect DVD capabilities yet */
+
+ ok= 0;
+ if(skin->write_type==BURN_WRITE_SAO && might_do_sao)
+ ok= 1;
+ if(skin->write_type==BURN_WRITE_TAO && might_do_tao)
+ ok= 1;
+ } else if(skin->write_type==BURN_WRITE_RAW)
+ ok= !!(drive_info->raw_block_types & BURN_BLOCK_RAW96R);
+ else if(skin->write_type==BURN_WRITE_SAO && !mixed_mode)
+ ok= !!(drive_info->sao_block_types & BURN_BLOCK_SAO);
+ else if(skin->write_type==BURN_WRITE_TAO) {
+ block_type_demand= 0;
+ for(i=0;itrack_counter;i++) {
+ Cdrtrack_get_track_type(skin->tracklist[i],&track_type,§or_size,0);
+ if(track_type==BURN_AUDIO)
+ block_type_demand|= BURN_BLOCK_RAW0;
+ else
+ block_type_demand|= BURN_BLOCK_MODE1;
+ }
+ ok= ((drive_info->tao_block_types & block_type_demand)==block_type_demand);
+ }
+
+ if(skin->write_type==BURN_WRITE_SAO && mixed_mode) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Cannot write mix of data and audio in SAO mode\n");
+ if(might_do_tao)
+ fprintf(stderr,
+ "cdrskin: HINT : Try with option -tao resp. without -sao\n");
+ return(0);
+ }
+ if(skin->write_type==BURN_WRITE_SAO && unpredicted_size>1) {
+ fprintf(stderr,
+ "cdrskin: FATAL : At least one track has no predictable size.\n");
+ fprintf(stderr,
+ "cdrskin: HINT : Use tsize= or tao_to_sao_tsize= to announce the track size\n");
+ if(might_do_tao)
+ fprintf(stderr,
+ "cdrskin: HINT : or try with option -tao resp. without -sao\n");
+ return(0);
+ }
+ if(!ok) {
+ fprintf(stderr,
+ "cdrskin: %s : Drive indicated refusal for write mode %s.\n",
+ (skin->force_is_set || was_still_default==1?"WARNING":"FATAL"),
+ skin->preskin->write_mode_name);
+ if(! skin->force_is_set) {
+ if(was_still_default==1) {
+ was_still_default= 2; /* do not try more than once */
+ if((skin->write_type==BURN_WRITE_RAW ||
+ skin->write_type==BURN_WRITE_SAO) && might_do_tao) {
+ skin->write_type= BURN_WRITE_TAO;
+ skin->block_type= BURN_BLOCK_MODE1;
+ strcpy(skin->preskin->write_mode_name,"TAO");
+ goto check_with_drive;
+ } else if (might_do_sao) {
+ skin->write_type= BURN_WRITE_SAO;
+ skin->block_type= BURN_BLOCK_SAO;
+ strcpy(skin->preskin->write_mode_name,"SAO");
+ goto check_with_drive;
+ }
+ }
+ fprintf(stderr,"cdrskin: HINT : If you are certain that the drive will do, try option -force\n");
+ return(0);
+ }
+ }
+
+#ifdef Cdrskin_libburn_has_get_multi_capS
+ ret = burn_disc_get_multi_caps(skin->grabbed_drive,skin->write_type,&caps,0);
+ if (ret>0) {
+ current_is_overwriteable= caps->start_adr;
+ allows_multi= caps->multi_session || current_is_overwriteable;
+ }
+ burn_disc_free_multi_caps(&caps);
+#endif
+ if(skin->multi) {
+ if(!allows_multi) {
+ if(skin->prodvd_cli_compatible) {
+ skin->multi= 0;
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ fprintf(stderr, "cdrskin: NOTE : Ignored option -multi.\n");
+ } else {
+ fprintf(stderr,
+ "cdrskin: SORRY : Cannot keep this media appendable after write by -multi\n");
+ return(0);
+ } else if(current_is_overwriteable) {
+ skin->multi= 0;
+ if(!skin->use_data_image_size)
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ fprintf(stderr, "cdrskin: NOTE : -multi cannot leave a recognizeable end mark on this media.\n");
+ }
+ }
+
+it_is_done:;
+ if(skin->write_type==BURN_WRITE_SAO && unpredicted_size==1)
+ for(i= 0; itrack_counter; i++) {
+ Cdrtrack_get_size(skin->tracklist[i],&fixed_size,
+ &tao_to_sao_tsize,&dummy,2);
+ if(fixed_size<=0.0 && tao_to_sao_tsize>0.0) {
+ printf(
+ "cdrskin: NOTE : augmenting non-tao write mode by tao_to_sao_tsize\n");
+ printf("cdrskin: NOTE : fixed size : %.f\n",tao_to_sao_tsize);
+ Cdrtrack_activate_tao_tsize(skin->tracklist[i],0);
+ }
+ }
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ printf("cdrskin: write type : %s\n", skin->preskin->write_mode_name);
+ return(1);
+}
+
+#endif /* ! Cdrskin_libburn_write_mode_ruleS */
+
+
+#ifndef Cdrskin_extra_leaN
+
+int Cdrskin_announce_tracks(struct CdrskiN *skin, int flag)
+{
+ int i,mb,use_data_image_size;
+ double size,padding,sector_size= 2048.0;
+ double sectors;
+
+ if(skin->verbosity>=Cdrskin_verbose_progresS) {
+ 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+1,(sector_size==2048?"data ":"audio"));
+ } else {
+ mb= size/1024.0/1024.0;
+ printf("Track %-2.2d: %s %4d MB ",
+ i+1,(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;
+ 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 */
+
+
+#ifdef Cdrskin_libburn_has_random_access_rW
+
+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;
+ 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));
+ if(ret<=0)
+ goto ex;
+ }
+ buf= malloc(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,"\r%9.fk written ",((double) (i+chunksize))/1024.0);
+ }
+ fprintf(stderr,"\r%9.fk written \n",((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(skin->drive_is_grabbed)
+ Cdrskin_release_drive(skin,0);
+ if(buf!=NULL)
+ free(buf);
+ 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,*td,*md;
+ 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= track_descr+i*2048;
+ md= skin->overwriteable_iso_head+(16+i)*2048;
+ if(td[0] != -1)
+ break;
+ /* demand media descrN[0] == track descrN[0] */
+ if(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);
+}
+
+
+#endif /* Cdrskin_libburn_has_random_access_rW */
+
+
+/** 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;
+ struct burn_session *session;
+ struct burn_write_opts *o;
+ 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,fifo_percent,total_min_fill,min_buffer_fill= 101;
+ int use_data_image_size, needs_early_fifo_fill= 0,iso_size= -1;
+ double put_counter,get_counter,empty_counter,full_counter;
+ 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;
+ int source_fd, is_from_stdin;
+
+ 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);
+
+
+#ifndef Cdrskin_libburn_write_mode_ruleS
+
+#ifdef Cdrskin_allow_libburn_taO
+ if (s!=BURN_DISC_APPENDABLE && s!=BURN_DISC_BLANK) {
+#else
+ if (s!=BURN_DISC_BLANK) {
+#endif
+ Cdrskin_release_drive(skin,0);
+ fprintf(stderr,"cdrskin: FATAL : No writeable media detected.\n");
+ goto burn_failed;
+ }
+
+ ret= Cdrskin_activate_write_mode(skin,s,0);
+ if(ret<=0) {
+ fprintf(stderr,
+ "cdrskin: FATAL : Cannot activate the desired write mode\n");
+ goto burn_failed;
+ }
+
+#endif /* ! Cdrskin_libburn_write_mode_ruleS */
+
+
+ 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:;
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ printf("cdrskin: %s failed\n", doing);
+ fprintf(stderr,"cdrskin: FATAL : %s failed.\n", doing);
+ return(0);
+ }
+ skin->fixed_size= 0.0;
+ 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);
+ 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;
+ } else if(size>0)
+ skin->fixed_size+= size+padding;
+ else
+ skin->has_open_ended_track= 1;
+ }
+
+#ifndef Cdrskin_libburn_write_mode_ruleS
+ if (s==BURN_DISC_APPENDABLE) {
+#ifdef Cdrskin_allow_sao_for_appendablE
+ ;
+#else
+ if(skin->write_type!=BURN_WRITE_TAO) {
+ Cdrskin_release_drive(skin,0);
+ fprintf(stderr,"cdrskin: FATAL : For now only write mode -tao can be used with appendable disks\n");
+ goto burn_failed;
+ }
+#endif /* ! Cdrskin_allow_sao_for_appendablE */
+ }
+#endif /* ! Cdrskin_libburn_write_mode_ruleS */
+
+#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 */
+
+ skin->fixed_size= 0.0;
+ skin->has_open_ended_track= 0;
+ 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;
+ }
+
+ o= burn_write_opts_new(drive);
+ burn_write_opts_set_perform_opc(o, 0);
+
+#ifdef Cdrskin_libburn_has_set_start_bytE
+
+/* 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);
+
+#endif /* Cdrskin_libburn_has_set_start_bytE */
+
+#ifdef Cdrskin_libburn_has_multI
+ if(skin->media_is_overwriteable && skin->multi) {
+ if(skin->grow_overwriteable_iso<=0) {
+ fprintf(stderr, "cdrskin: FATAL : -multi cannot leave a recognizeable 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);
+#endif
+#ifdef Cdrskin_libburn_has_set_filluP
+ burn_write_opts_set_fillup(o, skin->fill_up_media);
+#endif
+#ifdef Cdrskin_libburn_has_set_forcE
+ burn_write_opts_set_force(o, !!skin->force_is_set);
+#endif
+#ifdef Cdrskin_libburn_has_stream_recordinG
+ burn_write_opts_set_stream_recording(o, !!skin->stream_recording_is_set);
+#endif
+
+ 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);
+
+#ifdef Cdrskin_libburn_write_mode_ruleS
+ ret= Cdrskin_activate_write_mode(skin,o,disc,0);
+ if(ret<=0)
+ goto burn_failed;
+#else /* Cdrskin_libburn_write_mode_ruleS */
+ burn_write_opts_set_write_type(o,skin->write_type,skin->block_type);
+#endif
+
+ 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,0);
+#endif
+
+ if(skin->tell_media_space || skin->track_counter<=0) {
+ /* write capacity estimation and return without actual burning */
+
+#ifdef Cdrskin_libburn_has_get_spacE
+ {
+ off_t free_space;
+ char msg[80];
+
+ free_space= burn_disc_available_space(drive,o);
+ sprintf(msg,"%d\n",(int) (free_space/(off_t) 2048));
+ if(skin->preskin->result_fd>=0) {
+ write(skin->preskin->result_fd,msg,strlen(msg));
+ } else
+ printf("%s",msg);
+ }
+#endif /* Cdrskin_libburn_has_get_spacE */
+
+ 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;}
+ }
+
+ Cdrskin_adjust_speed(skin,0);
+
+#ifndef Cdrskin_extra_leaN
+ Cdrskin_wait_before_action(skin,0);
+ if(needs_early_fifo_fill==1)
+ 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 */
+
+ if(skin->verbosity>=Cdrskin_verbose_progresS && nwa>=0)
+ printf("Starting new track at sector: %d\n",nwa);
+ skin->drive_is_busy= 1;
+ burn_disc_write(o, disc);
+ if(skin->preskin->abort_handler==-1)
+ Cleanup_set_handlers(skin,(Cleanup_app_handler_T) Cdrskin_abort_handler,4);
+ last_time= start_time= Sfile_microtime(0);
+
+ burn_write_opts_free(o);
+
+ 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_burn_pacifier(skin,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(skin->fifo==NULL || fifo_disabled) {
+ usleep(20000);
+ } else {
+ 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;
+ }
+ }
+#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");
+
+#ifdef Cdrskin_libburn_has_wrote_welL
+ wrote_well = burn_drive_wrote_well(drive);
+#endif
+
+#ifdef Cdrskin_libburn_has_random_access_rW
+ 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;
+ }
+#endif /* Cdrskin_libburn_has_random_access_rW */
+
+ if(max_track<0) {
+ printf("Track 01: Total bytes read/written: %.f/%.f (%.f sectors).\n",
+ 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);
+ printf("Track %-2.2d: Total bytes read/written: %.f/%.f (%.f sectors).\n",
+ max_track+1,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
+
+ 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);
+ }
+ drive_status= burn_drive_get_status(drive, &p);
+
+#ifdef Cdrskin_libburn_has_buffer_min_filL
+ /* cdrskin recorded its own coarse min_buffer_fill.
+ libburn's is finer - if enough bytes were processed so it is available.*/
+ 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));
+ Cdrskin_release_drive(skin,0);
+ for(i= 0;itrack_counter;i++)
+ Cdrtrack_cleanup(skin->tracklist[i],0);
+ burn_session_free(session);
+ burn_disc_free(disc);
+ return(ret);
+}
+
+
+/** 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;
+ 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) {
+
+#ifdef Cdrskin_libburn_has_get_msc1
+ /* No TOC available. Try to inquire directly. */
+ ret= burn_disc_get_msc1(drive,&lba);
+ if(ret>0)
+ goto obtain_nwa;
+#endif /* Cdrskin_libburn_has_get_msc1 */
+
+ fprintf(stderr,"cdrskin: FATAL : Cannot obtain info about CD content\n");
+ {ret= 0; goto ex;}
+ }
+ sessions= burn_disc_get_sessions(disc,&num_sessions);
+ for(session_no= 0; session_no0)
+ nwa= aux_lba+6900;
+ else
+ nwa= aux_lba+11400;
+ }
+
+put_out:;
+ if(skin->preskin->result_fd>=0) {
+ sprintf(msg,"%d,%d\n",lba,nwa);
+ write(skin->preskin->result_fd,msg,strlen(msg));
+ } else
+ printf("%d,%d\n",lba,nwa);
+
+ 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:;
+
+ /* must calm down my NEC ND-4570A afterwards */
+ if(skin->verbosity>=Cdrskin_verbose_debuG)
+ ClN(fprintf(stderr,"cdrskin_debug: doing extra release-grab cycle\n"));
+ Cdrskin_release_drive(skin,0);
+ Cdrskin_grab_drive(skin,0);
+
+ Cdrskin_release_drive(skin,0);
+ 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)
+{
+
+#ifndef Cdrskin_burn_drive_eject_brokeN
+
+#ifndef Cdrskin_oldfashioned_api_usE
+ int i,ret,max_try= 5;
+
+ if(!skin->do_eject)
+ return(1);
+
+ if(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);
+
+#else
+
+ if(!skin->do_eject)
+ return(1);
+ if(Cdrskin_grab_drive(skin,2|16)>0) {
+ Cdrskin_release_drive(skin,1);
+ } else {
+ fprintf(stderr,"cdrskin: SORRY : Failed to finally eject tray.\n");
+ return(0);
+ }
+ return(1);
+
+#endif
+
+#else /* Cdrskin_burn_drive_eject_brokeN */
+
+ int ret;
+ char adr[Cdrskin_adrleN];
+ char cmd[5*Cdrskin_strleN+16],shellsafe[5*Cdrskin_strleN+2];
+
+ if(!skin->do_eject)
+ return(1);
+ if(skin->verbosity>=Cdrskin_verbose_progresS)
+ printf("cdrskin: trying to eject media\n");
+ if(getuid()!=geteuid()) {
+ fprintf(stderr,
+ "cdrskin: SORRY : uid and euid differ. Will not start external eject.\n");
+ Cdrpreskin_consider_normal_user(0);
+ return(0);
+ }
+
+#ifdef Cdrskin_libburn_has_drive_get_adR
+ ret= burn_drive_get_adr(&(skin->drives[skin->driveno]), adr);
+ if(ret<=0)
+ adr[0]= 0;
+#else
+ strcpy(adr,skin->drives[skin->driveno].location);
+#endif
+
+ if(strlen(skin->eject_device)>0)
+ sprintf(cmd,"eject %s",Text_shellsafe(skin->eject_device,shellsafe,0));
+ else if(strcmp(adr,"/dev/sg0")==0)
+ sprintf(cmd,"eject /dev/sr0");
+ else
+ sprintf(cmd,"eject %s",Text_shellsafe(adr,shellsafe,0));
+ ret= system(cmd);
+ if(ret==0)
+ return(1);
+ return(0);
+
+#endif /* Cdrskin_burn_drive_eject_brokeN */
+
+}
+
+
+/** 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,source_has_size=0, idx= -1;
+ double value,grab_and_wait_value= -1.0;
+ char *cpt,*value_pt,adr[Cdrskin_adrleN],*blank_mode= "";
+ 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=", "mcn=", "isrc=", "index=", "textfile=",
+ "pktsize=", "cuefile=",
+ ""
+ };
+ static char ignored_full_options[][41]= {
+ "-d", "-Verbose", "-V", "-silent", "-s", "-setdropts", "-prcap",
+ "-reset", "-abort", "-overburn", "-ignsize", "-useinfo",
+ "-fix", "-nofix",
+ "-raw", "-raw96p", "-raw16",
+ "-clone", "-text", "-mode2", "-xa", "-xa1", "-xa2", "-xamix",
+ "-cdi", "-preemp", "-nopreemp", "-copy", "-nocopy",
+ "-scms", "-shorttrack", "-noshorttrack", "-packet", "-noclose",
+ "-media-info", "-minfo",
+ ""
+ };
+
+ /* 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;ipreskin->demands_cdrecord_caps= 1;
+ if(skin->preskin->fallback_program[0])
+ fprintf(stderr,"cdrskin: NOTE : Unimplemented option: '%s'\n",argv[i]);
+ else
+ fprintf(stderr,"cdrskin: NOTE : ignoring unimplemented option : '%s'\n",
+ argv[i]);
+ 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);
+ }
+
+#ifdef Cdrskin_libburn_has_get_best_speeD
+ } else if(strcmp(argv[i],"--adjust_speed_to_drive")==0) {
+ skin->adjust_speed_to_drive= 1;
+#endif
+
+ } 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(argv[i],"-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(argv[i],"-audio")==0) {
+ skin->track_type= BURN_AUDIO;
+ skin->track_type_by_default= 0;
+
+ } else if(strncmp(argv[i],"-blank=",7)==0) {
+ cpt= argv[i]+7;
+ goto set_blank;
+ } else if(strncmp(argv[i],"blank=",6)==0) {
+ cpt= argv[i]+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(strcmp(argv[i],"-checkdrive")==0) {
+ skin->do_checkdrive= 1;
+
+ } else if(strcmp(argv[i],"-data")==0) {
+
+ /* >>> !!! All Subsequent Tracks Option */
+
+ 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;
+
+#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(argv[i],"-dev=",5)==0) {
+ /* is handled in Cdrpreskin_setup() */;
+ } else if(strncmp(argv[i],"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(argv[i],"-driveropts=",12)==0) {
+ value_pt= argv[i]+12;
+ goto set_driveropts;
+ } else if(strncmp(argv[i],"driveropts=",11)==0) {
+ value_pt= argv[i]+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(argv[i]+11,"noburnfree")==0 ||
+ strcmp(argv[i]+11,"noburnproof")==0 ) {
+ skin->burnfree= 0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: burnfree : off\n"));
+ } else if(strcmp(argv[i]+11,"help")==0) {
+ /* handled in Cdrpreskin_setup() */;
+ } else
+ goto ignore_unknown;
+
+ } else if(strcmp(argv[i],"-dummy")==0) {
+ skin->dummy_mode= 1;
+
+ } else if(strcmp(argv[i],"-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)
+#ifdef Cdrskin_burn_drive_eject_brokeN
+ ClN(printf("cdrskin: eject_device : %s\n",skin->eject_device));
+#else
+ ClN(printf("cdrskin: ignoring obsolete eject_device=%s\n",
+ skin->eject_device));
+#endif
+
+
+#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 */
+
+#ifdef Cdrskin_libburn_has_set_filluP
+ } 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"));
+#endif
+
+ } else if(strcmp(argv[i],"-force")==0) {
+ skin->force_is_set= 1;
+
+ } else if(strcmp(argv[i],"-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"));
+
+#ifndef Cdrskin_extra_leaN
+
+ } else if(strncmp(argv[i],"-fs=",4)==0) {
+ value_pt= argv[i]+4;
+ goto fs_equals;
+ } else if(strncmp(argv[i],"fs=",3)==0) {
+ value_pt= argv[i]+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(argv[i],"-gracetime=",11)==0) {
+ value_pt= argv[i]+11;
+ goto gracetime_equals;
+ } else if(strncmp(argv[i],"gracetime=",10)==0) {
+ value_pt= argv[i]+10;
+gracetime_equals:;
+ sscanf(value_pt,"%d",&(skin->gracetime));
+
+#ifdef Cdrskin_libburn_has_get_multi_capS
+#ifdef Cdrskin_libburn_has_random_access_rW
+ } 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;
+#endif /* Cdrskin_libburn_has_random_access_rW */
+#endif /* Cdrskin_libburn_has_get_multi_capS */
+
+
+#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(argv[i],"-immed")==0) {
+#ifdef Cdrskin_libburn_has_set_waitinG
+ skin->modesty_on_drive= 1;
+ skin->min_buffer_percent= 75;
+ skin->max_buffer_percent= 95;
+#else
+ ;
+#endif /* Cdrskin_libburn_has_set_waitinG */
+
+ } else if(strcmp(argv[i],"-inq")==0) {
+ skin->do_checkdrive= 2;
+
+ } else if(strcmp(argv[i],"-isosize")==0) {
+ skin->use_data_image_size= 1;
+
+ } 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) {
+ char line[80];
+ /* is also handled in Cdrpreskin_setup() */;
+
+ line[0]= 0;
+ 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(strncmp(argv[i],"fallback_program=",17)==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"-load")==0) {
+ skin->do_load= 1;
+
+ } else if(strcmp(argv[i],"-lock")==0) {
+ skin->do_load= 2;
+
+ } else if(strncmp(argv[i],"-minbuf=",8)==0) {
+ value_pt= argv[i]+8;
+ goto minbuf_equals;
+ } else if(strncmp(argv[i],"minbuf=",7)==0) {
+ value_pt= argv[i]+7;
+minbuf_equals:;
+#ifdef Cdrskin_libburn_has_set_waitinG
+ 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
+ fprintf(stderr,
+ "cdrskin: SORRY : Option minbuf= is not available yet.\n");
+ return(0);
+#endif
+
+ } else if(strncmp(argv[i],"modesty_on_drive=",17)==0) {
+#ifdef Cdrskin_libburn_has_set_waitinG
+ value_pt= argv[i]+17;
+ if(*value_pt=='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') {
+ 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;
+ 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;
+ ClN(printf("cdrskin: modesty_on_drive : %d percent max buffer fill\n",
+ skin->max_buffer_percent));
+ } else {
+ fprintf(stderr,
+ "cdrskin: SORRY : modest_on_drive= unknown option code : %s\n",
+ value_pt);
+ }
+ }
+ skin->preskin->demands_cdrskin_caps= 1;
+#else
+ fprintf(stderr,
+ "cdrskin: SORRY : Option modesty_on_drive= is not available yet.\n");
+ return(0);
+#endif
+
+ } else if(strcmp(argv[i],"-multi")==0) {
+#ifdef Cdrskin_libburn_has_multI
+ skin->multi= 1;
+#else
+ fprintf(stderr,"cdrskin: SORRY : Option -multi is not available yet.\n");
+#endif
+
+ } else if(strncmp(argv[i],"-msifile=",9)==0) {
+ value_pt= argv[i]+9;
+ goto msifile_equals;
+ } else if(strncmp(argv[i],"msifile=",8)==0) {
+ value_pt= argv[i]+8;
+msifile_equals:;
+#ifdef Cdrskin_libburn_has_multI
+ 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
+ fprintf(stderr,
+ "cdrskin: SORRY : Option msifile= is not available.\n");
+ return(0);
+#endif
+
+ } else if(strcmp(argv[i],"-msinfo")==0) {
+#ifdef Cdrskin_libburn_has_multI
+ skin->do_msinfo= 1;
+#else
+ fprintf(stderr,"cdrskin: SORRY : Option -msinfo is not available.\n");
+ return(0);
+#endif
+
+ } 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_rc")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"-nopad")==0) {
+ skin->padding= 0.0;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: padding : off\n"));
+
+ } else if(strcmp(argv[i],"--old_pseudo_scsi_adr")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"-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(argv[i],"-padsize=",9)==0) {
+ value_pt= argv[i]+9;
+ goto set_padsize;
+ } else if(strncmp(argv[i],"padsize=",8)==0) {
+ value_pt= argv[i]+8;
+set_padsize:;
+ skin->padding= Scanf_io_size(argv[i]+8,0);
+ skin->set_by_padsize= 1;
+ if(skin->verbosity>=Cdrskin_verbose_cmD)
+ ClN(printf("cdrskin: padding : %.f\n",skin->padding));
+
+ } else if(strcmp(argv[i],"--prodvd_cli_compatible")==0) {
+ skin->prodvd_cli_compatible= 1;
+
+ } else if(strcmp(argv[i],"-raw96r")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"-sao")==0 || strcmp(argv[i],"-dao")==0) {
+ /* is handled in Cdrpreskin_setup() */;
+
+ } else if(strcmp(argv[i],"-scanbus")==0) {
+ skin->do_scanbus= 1;
+
+ } 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],"-speed=",7)==0) {
+ value_pt= argv[i]+7;
+ goto set_speed;
+ } else if(strncmp(argv[i],"speed=",6)==0) {
+ value_pt= argv[i]+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],"-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
+ skin->stream_recording_is_set= 0;
+
+ } else if(strcmp(argv[i],"-swab")==0) {
+ skin->swap_audio_bytes= 0;
+
+ } else if(strcmp(argv[i],"-tao")==0) {
+ /* is partly handled in Cdrpreskin_setup() */;
+
+#ifndef Cdrskin_allow_libburn_taO
+
+ if(skin->tao_to_sao_tsize<=0.0) {
+ fprintf(stderr,"cdrskin: FATAL : libburn does not support -tao yet.\n");
+ fprintf(stderr,"cdrskin: HINT : Try option tao_to_sao_tsize=650m\n");
+ return(0);
+ }
+ ClN(printf("cdrskin: NOTE : substituting mode -tao by mode -sao\n"));
+ strcpy(skin->preskin->write_mode_name,"SAO");
+
+#endif /* ! Cdrskin_allow_libburn_taO */
+
+ } 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)
+#ifdef Cdrskin_allow_libburn_taO
+ printf("cdrskin: size default for non-tao write modes: %.f\n",
+#else
+ printf("cdrskin: replace -tao by -sao with fixed size : %.f\n",
+#endif
+ skin->tao_to_sao_tsize);
+#endif /* ! Cdrskin_extra_leaN */
+
+#ifdef Cdrskin_libburn_has_get_spacE
+ } else if(strcmp(argv[i],"--tell_media_space")==0) {
+ skin->tell_media_space= 1;
+ skin->preskin->demands_cdrskin_caps= 1;
+#endif
+
+ } else if(strcmp(argv[i],"-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(argv[i],"-tsize=",7)==0) {
+ value_pt= argv[i]+7;
+ goto set_tsize;
+ } else if(strncmp(argv[i],"tsize=",6)==0) {
+ value_pt= argv[i]+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],"-v")==0 || strcmp(argv[i],"-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(argv[i],"-version")==0) {
+ /* is handled in Cdrpreskin_setup() and should really not get here */;
+
+ } else if(strcmp(argv[i],"-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( 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);
+ }
+ source_has_size= 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)
+ source_has_size= 1;
+ 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);
+ }
+ 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;
+ } 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) {
+
+#ifdef Cdrskin_libburn_has_drive_get_adR
+ ret= burn_drive_get_adr(&(skin->drives[skin->driveno]), adr);
+ if(ret<=0)
+ adr[0]= 0;
+#else
+ strcpy(adr,skin->drives[skin->driveno].location);
+#endif
+
+ 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; ktrack_counter>0) {
+ skin->do_burn= 1;
+
+#ifndef Cdrskin_extra_leaN
+ if(!skin->do_direct_write) {
+ ret= Cdrskin_attach_fifo(skin,0);
+ if(ret<=0)
+ return(ret);
+ }
+#endif /* ! Cdrskin_extra_leaN */
+
+ }
+ 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 Unused yet
+ @return <=0 error, 1 success
+*/
+int Cdrskin_create(struct CdrskiN **o, struct CdrpreskiN **preskin,
+ int *exit_value, int flag)
+{
+ int ret, stdio_drive= 0;
+ 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(skin,(Cleanup_app_handler_T) Cdrskin_abort_handler,4);
+ else if(skin->preskin->abort_handler==2)
+ Cleanup_set_handlers(skin,(Cleanup_app_handler_T) Cdrskin_abort_handler,2|8);
+
+ printf("cdrskin: scanning for devices ...\n");
+ fflush(stdout);
+
+ /* In cdrskin there is not much sense in queueing library messages.
+ It is done here only for testing it from time to time */
+ Cdrpreskin_queue_msgs(skin->preskin,1);
+
+
+#ifndef Cdrskin_oldfashioned_api_usE
+ if(stdio_drive) {
+ ret= burn_drive_scan_and_grab(&(skin->drives),skin->preskin->device_adr,0);
+ if(ret<=0) {
+ fprintf(stderr,"cdrskin: FATAL : Failed to grab emulated stdio-drive\n");
+ {*exit_value= 2; goto ex;}
+ }
+ skin->n_drives= 1;
+ burn_drive_release(skin->drives[0].drive, 0);
+ } else {
+#else
+ {
+#endif /* Cdrskin_oldfashioned_api_usE */
+
+ while (!burn_drive_scan(&(skin->drives), &(skin->n_drives))) {
+ usleep(20000);
+ /* >>> ??? set a timeout ? */
+ }
+ }
+
+ /* This prints the eventual queued messages */
+ Cdrpreskin_queue_msgs(skin->preskin,0);
+
+ 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;}
+ ret= Cdrskin_scanbus(skin,1);
+ 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;}
+ 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) {
+ 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) {
+ 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;}
+ 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;}
+ ret= Cdrskin_atip(skin,(skin->do_atip>1));
+ if(ret<=0)
+ {*exit_value= 7; goto ex;}
+ }
+ if(skin->do_list_formats) {
+ if(skin->n_drives<=0)
+ {*exit_value= 14; goto no_drive;}
+ ret= Cdrskin_list_formats(skin, 0);
+ if(ret<=0)
+ {*exit_value= 14; goto ex;}
+ }
+ if(skin->do_blank) {
+ if(skin->n_drives<=0)
+ {*exit_value= 8; goto no_drive;}
+ ret= Cdrskin_blank(skin,0);
+ if(ret<=0)
+ {*exit_value= 8; goto ex;}
+ }
+
+#ifdef Cdrskin_libburn_has_random_access_rW
+ if(skin->do_direct_write) {
+ skin->do_burn= 0;
+ ret= Cdrskin_direct_write(skin,0);
+ if(ret<=0)
+ {*exit_value= 13; goto ex;}
+ }
+#endif /* Cdrskin_libburn_has_random_access_rW */
+
+ if(skin->do_burn || skin->tell_media_space) {
+ if(skin->n_drives<=0)
+ {*exit_value= 10; goto no_drive;}
+ ret= Cdrskin_burn(skin,0);
+ if(ret<=0)
+ {*exit_value= 10; goto ex;}
+ }
+ex:;
+ 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;
+ 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; in_drives<=0) {
+ 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_oldfashioned_api_usE
+ ClN(fprintf(stderr,"cdrskin_debug: Compiled with option -oldfashioned\n"));
+#endif
+#ifdef Cdrskin_new_api_tesT
+ ClN(fprintf(stderr,"cdrskin_debug: Compiled with option -experimental\n"));
+#endif
+ }
+
+ Cdrskin_run(skin,&exit_value,0);
+
+ex:;
+ 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/cdrskin/cdrskin_eng.html b/cdrskin/cdrskin_eng.html
new file mode 100644
index 0000000..638a468
--- /dev/null
+++ b/cdrskin/cdrskin_eng.html
@@ -0,0 +1,500 @@
+
+
+
+
+
+
+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, DVD+R/DL, CD-RW, DVD-RW, DVD-RAM, DVD+RW, BD-RE
+
+
+This program system has been tested on Intel/AMD Linux systems only.
+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.)
+
+
+
+
+
+
+