Tagged libburn-0.4.6
This commit is contained in:
parent
efa3d7caaa
commit
7058c87020
@ -1,6 +0,0 @@
|
|||||||
Joe Neeman
|
|
||||||
Philippe Rouquier
|
|
||||||
Gabriel Craciunescu
|
|
||||||
George Danchev
|
|
||||||
Jean-Francois Wauthy
|
|
||||||
Lorenzo Taylor
|
|
280
COPYING
280
COPYING
@ -1,280 +0,0 @@
|
|||||||
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
|
|
18
COPYRIGHT
18
COPYRIGHT
@ -1,18 +0,0 @@
|
|||||||
Derek Foreman <derek@signalmarketing.com> and Ben Jansens <xor@orodu.net>
|
|
||||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
|
||||||
Mario Danic <mario.danic@gmail.com>, Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
Copyright (C) 2006-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
|
|
234
INSTALL
234
INSTALL
@ -1,234 +0,0 @@
|
|||||||
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.
|
|
||||||
|
|
202
Makefile.am
202
Makefile.am
@ -1,202 +0,0 @@
|
|||||||
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)
|
|
||||||
|
|
332
README
332
README
@ -1,332 +0,0 @@
|
|||||||
------------------------------------------------------------------------------
|
|
||||||
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 <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
Copyright (C) 2006-2008 Mario Danic, Thomas Schmitt
|
|
||||||
|
|
||||||
Still containing parts of
|
|
||||||
Libburn. By Derek Foreman <derek@signalmarketing.com> and
|
|
||||||
Ben Jansens <xor@orodu.net>
|
|
||||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
|
||||||
These parts are to be replaced by own code of above libburnia-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
|
|
||||||
|
|
22
acinclude.m4
22
acinclude.m4
@ -1,22 +0,0 @@
|
|||||||
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])
|
|
||||||
])
|
|
10
bootstrap
10
bootstrap
@ -1,10 +0,0 @@
|
|||||||
#!/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
|
|
481
cdrskin/README
481
cdrskin/README
@ -1,481 +0,0 @@
|
|||||||
------------------------------------------------------------------------------
|
|
||||||
libburnia-project.org scdbackup.sourceforge.net/cdrskin_eng.html
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
cdrskin. By Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
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 <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
Copyright (C) 2006-2008 Mario Danic, Thomas Schmitt
|
|
||||||
|
|
||||||
libburnia-project.org is inspired by and in other components still containing
|
|
||||||
parts of
|
|
||||||
Libburn. By Derek Foreman <derek@signalmarketing.com> and
|
|
||||||
Ben Jansens <xor@orodu.net>
|
|
||||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
|
||||||
See toplevel README for an overview of the current copyright situation in
|
|
||||||
libburnia-project.org.
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
cdrskin is currently copyright Thomas Schmitt only.
|
|
||||||
It adopts the following commitment by the toplevel copyright holders:
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
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
|
|
@ -1,244 +0,0 @@
|
|||||||
#!/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")
|
|
||||||
|
|
@ -1,245 +0,0 @@
|
|||||||
#!/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")
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
|||||||
#!/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 "$@"
|
|
||||||
|
|
||||||
|
|
1253
cdrskin/cdrfifo.c
1253
cdrskin/cdrfifo.c
File diff suppressed because it is too large
Load Diff
@ -1,171 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
cdrfifo.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
1334
cdrskin/cdrskin.1
1334
cdrskin/cdrskin.1
File diff suppressed because it is too large
Load Diff
8292
cdrskin/cdrskin.c
8292
cdrskin/cdrskin.c
File diff suppressed because it is too large
Load Diff
@ -1,500 +0,0 @@
|
|||||||
<HTML>
|
|
||||||
|
|
||||||
<HEAD>
|
|
||||||
<META NAME="description" CONTENT="cdrskin, a limited cdrecord compatibility wrapper for libburn">
|
|
||||||
<META NAME="keywords" CONTENT="cdrskin, libburn, libburnia, burn, CD, DVD, linux, recording, burning, CD-R, CD-RW, DVD-R, DVD-RW, DVD+RW, DVD+R, DVD+R/DL, DVD-RAM, BD-RE, cdrecord, compatible, scdbackup">
|
|
||||||
<META NAME="robots" CONTENT="follow">
|
|
||||||
<TITLE>cdrskin homepage english</TITLE>
|
|
||||||
</HEAD>
|
|
||||||
|
|
||||||
<BODY BGCOLOR="#F5DEB3" TEXT=#000000 LINK=#0000A0 VLINK=#800000>
|
|
||||||
<FONT SIZE=+1>
|
|
||||||
|
|
||||||
<CENTER>
|
|
||||||
<A HREF="http://en.wikipedia.org/wiki/D%C3%B6ner_kebab">
|
|
||||||
<IMG SRC="doener_150x200_tr_octx.png" BORDER=0
|
|
||||||
ALT="cdrskin logo: Doener mit Scharf">
|
|
||||||
</A>
|
|
||||||
<P><H2> Homepage of </H2>
|
|
||||||
<H1> cdrskin </H1>
|
|
||||||
|
|
||||||
<H2>Limited cdrecord compatibility wrapper for libburn</H2>
|
|
||||||
</CENTER>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
<H2>Purpose:</H2>
|
|
||||||
Burns preformatted data to CD, DVD, and BD media:<BR>
|
|
||||||
CD-R, DVD-R, DVD+R, DVD+R/DL, CD-RW, DVD-RW, DVD-RAM, DVD+RW, BD-RE
|
|
||||||
</P>
|
|
||||||
<P>
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<A HREF="#download">Direct hop to download links -></A>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
<H2>Hardware requirements:</H2>
|
|
||||||
A CD/DVD/BD recorder suitable for
|
|
||||||
<A HREF="http://libburnia-project.org">http://libburnia-project.org</A> <BR>
|
|
||||||
(SCSI , ATA , USB , or SATA writers compliant to standard MMC-3 for CD
|
|
||||||
and to MMC-5 for DVD or BD).
|
|
||||||
<BR>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
<H2>Software requirements :</H2>
|
|
||||||
<DL>
|
|
||||||
<DT>Linux with kernel 2.4 or higher (and libc, of course) :</DT>
|
|
||||||
<DD>With kernel 2.4 an ATA drive has to be under ide-scsi emulation.</DD>
|
|
||||||
<DD>With kernel 2.6 the drive should not be under ide-scsi.</DD>
|
|
||||||
<DT>libpthread</DT>
|
|
||||||
<DD>is supposed to be a standard system component.</DD>
|
|
||||||
</DL>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
<H2>
|
|
||||||
GPL software included:<BR>
|
|
||||||
</H2>
|
|
||||||
<DL>
|
|
||||||
<DT>libburn-0.4.6</DT>
|
|
||||||
<DD>(founded by Derek Foreman and Ben Jansens,
|
|
||||||
furthered by team of libburnia-project.org)</DD>
|
|
||||||
<DD>transfers data to CD and DVD</DD>
|
|
||||||
</DL>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
This program system has been tested on Intel/AMD Linux systems only.<BR>
|
|
||||||
Ports to other usable systems are appreciated. Reports are welcome.
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
<H2>Special features:</H2>
|
|
||||||
<UL>
|
|
||||||
<LI>Source code is independent of
|
|
||||||
<A HREF="http://cdrecord.berlios.de/old/private/cdrecord.html">cdrecord</A>
|
|
||||||
</LI>
|
|
||||||
</UL>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
<H2>Commands:</H2>
|
|
||||||
<DL>
|
|
||||||
<DT>The most common options of cdrecord for data and audio on CD media
|
|
||||||
are provided in a compatible way.<BR>
|
|
||||||
On all DVD media except DVD-R DL, cdrskin is able to perform any recording job
|
|
||||||
which is possible with cdrecord.
|
|
||||||
Other than with cdrecord, options -multi and -tao are supported with
|
|
||||||
most DVD types and with BD-RE.
|
|
||||||
</DT>
|
|
||||||
<BR><BR>
|
|
||||||
<DT>Get an overview of drives and their addresses</DT>
|
|
||||||
<DD>#<KBD> cdrskin -scanbus</KBD></DD>
|
|
||||||
<DD>#<KBD> cdrskin dev=ATA -scanbus</KBD></DD>
|
|
||||||
<DD>#<KBD> cdrskin --devices</KBD></DD>
|
|
||||||
<DT>Being superuser avoids permission problems with /dev/srN resp. /dev/hdX .
|
|
||||||
</DT>
|
|
||||||
<DT>Ordinary users should then get granted rw access to the /dev files
|
|
||||||
as listed by option --devices.</DT>
|
|
||||||
<DT> </DT>
|
|
||||||
|
|
||||||
<DT>Get info about a particular drive or loaded media:</DT>
|
|
||||||
<DD>$<KBD> cdrskin dev=0,1,0 -checkdrive</KBD></DD>
|
|
||||||
<DD>$<KBD> cdrskin dev=ATA:1,0,0 -v -atip</KBD></DD>
|
|
||||||
<DD>$<KBD> cdrskin dev=/dev/hdc -toc</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Prepare CD-RW or DVD-RW for re-use, DVD-RAM or BD-RE for first use:</DT>
|
|
||||||
<DD>$<KBD> cdrskin -v dev=/dev/sg1 blank=as_needed -eject</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Format DVD-RW to avoid need for blanking before re-use:</DT>
|
|
||||||
<DD>$<KBD> cdrskin -v dev=/dev/sr0 blank=format_overwrite</KBD></DD>
|
|
||||||
|
|
||||||
<DT>De-format DVD-RW to make it capable of multi-session again:</DT>
|
|
||||||
<DD>$<KBD> cdrskin -v dev=/dev/sr0 blank=deformat_sequential</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Write ISO-9660 filesystem image as only one to blank or formatted media:
|
|
||||||
</DT>
|
|
||||||
<DD>$<KBD> cdrskin -v dev=/dev/hdc speed=12 fs=8m \</KBD></DD>
|
|
||||||
<DD><KBD> blank=as_needed -eject padsize=300k my_image.iso</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Write compressed afio archive on-the-fly:</DT>
|
|
||||||
<DD>$<KBD> find . | afio -oZ - | \</KBD></DD>
|
|
||||||
<DD><KBD> cdrskin -v dev=0,1,0 fs=32m speed=8 \</KBD></DD>
|
|
||||||
<DD><KBD> blank=as_needed padsize=300k -</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Write several sessions to the same CD, DVD-R[W] or DVD+R[/DL]:</DT>
|
|
||||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 1.iso</KBD>
|
|
||||||
</DD>
|
|
||||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 2.iso</KBD>
|
|
||||||
</DD>
|
|
||||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 3.iso</KBD>
|
|
||||||
</DD>
|
|
||||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -tao 4.iso</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Get multi-session info for option -C of program mkisofs:</DT>
|
|
||||||
<DD>$<KBD> c_values=$(cdrskin dev=/dev/sr0 -msinfo 2>/dev/null)</KBD></DD>
|
|
||||||
<DD>$<KBD> mkisofs ... -C "$c_values" ...</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Inquire free space on media for a -tao -multi run:</DT>
|
|
||||||
<DD>$<KBD> x=$(cdrskin dev=/dev/sr0 -tao -multi \</KBD></DD>
|
|
||||||
<DD><KBD> --tell_media_space 2>/dev/null)</KBD></DD>
|
|
||||||
<DD>$<KBD> echo "Available: $x blocks of 2048 data bytes"</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Write audio tracks to CD:</DT>
|
|
||||||
<DD>$<KBD> cdrskin -v dev=ATA:1,0,0 speed=48 -sao \</KBD></DD>
|
|
||||||
<DD><KBD> track1.wav track2.au -audio -swab track3.raw</KBD></DD>
|
|
||||||
|
|
||||||
<DT>Get overview of the cdrecord compatible options:</DT>
|
|
||||||
<DD>$<KBD> <A HREF="cdrskin_help">cdrskin -help</A></KBD></DD>
|
|
||||||
|
|
||||||
<DT>Get overview of the non-cdrecord options:</DT>
|
|
||||||
<DD>$<KBD> <A HREF="cdrskin__help">cdrskin --help</A></KBD></DD>
|
|
||||||
|
|
||||||
<DT>Read the detailed manual page:</DT>
|
|
||||||
<DD>$<KBD> <A HREF="man_1_cdrskin.html">man cdrskin</A></KBD></DD>
|
|
||||||
</DL>
|
|
||||||
<DL>
|
|
||||||
<DT>Read about the standard for which cdrskin is striving:</DT>
|
|
||||||
<DD>$<KBD>
|
|
||||||
<A HREF="http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html">
|
|
||||||
man cdrecord</A></KBD></DD>
|
|
||||||
<DD><B>Do not bother Joerg Schilling with any cdrskin problems.</B>
|
|
||||||
(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
|
|
||||||
this "don't bother Joerg" demand.)
|
|
||||||
</DD>
|
|
||||||
</DL>
|
|
||||||
<DL>
|
|
||||||
<DT>Learn to know a more versatile way to burn ISO 9660 formatted data</DT>
|
|
||||||
<DD>
|
|
||||||
Standalone ISO 9660 multi-session CD/DVD tool
|
|
||||||
<A HREF="http://scdbackup.sourceforge.net/xorriso_eng.html">xorriso</A>.
|
|
||||||
</DD>
|
|
||||||
</DL>
|
|
||||||
|
|
||||||
Testers wanted who are willing to risk some DVD-R DL media
|
|
||||||
or to do experiments on BD-R media.
|
|
||||||
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<A NAME="download"></A>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
<DL>
|
|
||||||
<DT>Download as source code (see README):</DT>
|
|
||||||
<DD><A HREF="cdrskin-0.4.6.pl00.tar.gz">cdrskin-0.4.6.pl00.tar.gz</A>
|
|
||||||
(730 KB).
|
|
||||||
</DD>
|
|
||||||
<DD>
|
|
||||||
The cdrskin tarballs are source code identical with libburn releases
|
|
||||||
of the same version number.
|
|
||||||
They get produced via a different procedure, though.<BR>
|
|
||||||
cdrskin is part of libburn - full libburn is provided with cdrskin releases.
|
|
||||||
</DD>
|
|
||||||
|
|
||||||
<!-- This is not offered any more since spring 2008
|
|
||||||
<DD> </DD>
|
|
||||||
<DT>Download as single x86 binaries (untar and move to /usr/bin/cdrskin):</DT>
|
|
||||||
<DD><A HREF="cdrskin_0.4.2.pl00-x86-suse9_0.tar.gz">
|
|
||||||
cdrskin_0.4.2.pl00-x86-suse9_0.tar.gz</A>, (110 KB),
|
|
||||||
<DL>
|
|
||||||
<DD>runs on SuSE 9.0 (2.4.21) , RIP-14.4 (2.6.14) ,
|
|
||||||
Gentoo (2.6.15 x86_64 Athlon).</DD>
|
|
||||||
</DL>
|
|
||||||
<DD><A HREF="cdrskin_0.4.2.pl00-x86-suse9_0-static.tar.gz">
|
|
||||||
cdrskin_0.4.2.pl00-x86-suse9_0-static.tar.gz</A>, (310 KB), -static compiled,
|
|
||||||
<DL>
|
|
||||||
<DD>runs on SuSE 7.2 (2.4.4), and on the systems above.</DD>
|
|
||||||
</DL>
|
|
||||||
</DD>
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
</DL>
|
|
||||||
<DL><DT>Documentation:</DT>
|
|
||||||
<DD><A HREF="README_cdrskin">README</A> an introduction</DD>
|
|
||||||
<DD><A HREF="cdrskin__help">cdrskin --help</A> non-cdrecord options</DD>
|
|
||||||
<DD><A HREF="cdrskin_help">cdrskin -help</A> cdrecord compatible options</DD>
|
|
||||||
<DD><A HREF="man_1_cdrskin.html">man cdrskin</A> the manual page</DD>
|
|
||||||
<DD> </DD>
|
|
||||||
</DL>
|
|
||||||
<DL><DT>Contact:</DT>
|
|
||||||
<DD>Thomas Schmitt, <A HREF="mailto:scdbackup@gmx.net">scdbackup@gmx.net</A></DD>
|
|
||||||
<DD>libburn development mailing list,
|
|
||||||
<A HREF="mailto:libburn-hackers@pykix.org">libburn-hackers@pykix.org</A></DD>
|
|
||||||
</DL>
|
|
||||||
<DL><DT>License:</DT>
|
|
||||||
<DD><A HREF="COPYING_cdrskin">GPL</A>, an <A HREF="http://www.opensource.org/">Open Source</A> approved license</DD>
|
|
||||||
<DD> </DD>
|
|
||||||
</DL>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
Enhancements towards previous stable version cdrskin-0.4.4.pl00:
|
|
||||||
<UL>
|
|
||||||
<LI>Support for BD-RE media is now official</LI>
|
|
||||||
<LI>New option stream_recording=on can speed up DVD-RAM and BD-RE</LI>
|
|
||||||
<LI>New option --list_formats</LI>
|
|
||||||
<LI>New blank types for expert formatting of DVD-RAM and BD-RE</LI>
|
|
||||||
<LI>New blank type blank=as_needed for automatic handling
|
|
||||||
of media type and state</LI>
|
|
||||||
</UL>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Bug fixes towards cdrskin-0.4.4.pl00:
|
|
||||||
<UL>
|
|
||||||
<LI>none yet</LI>
|
|
||||||
</UL>
|
|
||||||
-->
|
|
||||||
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
<DL>
|
|
||||||
<DT><H3>Development snapshot, version 0.4.7 :</H3></DT>
|
|
||||||
<DD>Enhancements towards current stable version 0.4.6.pl00:
|
|
||||||
<UL>
|
|
||||||
<!--
|
|
||||||
-->
|
|
||||||
<LI>none yet</LI>
|
|
||||||
|
|
||||||
</UL>
|
|
||||||
</DD>
|
|
||||||
<DD> </DD>
|
|
||||||
<DD><A HREF="README_cdrskin_devel">README 0.4.7</A>
|
|
||||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.4.7 --help</A></DD>
|
|
||||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.4.7 -help</A></DD>
|
|
||||||
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.4.7)</A></DD>
|
|
||||||
<DD> </DD>
|
|
||||||
<DT>Maintainers of cdrskin unstable packages please use SVN of
|
|
||||||
<A HREF="http://libburnia-project.org"> libburnia-project.org</A></DT>
|
|
||||||
<DD>Download: <KBD><B>svn co http://svn.libburnia-project.org/libburn/trunk libburn</B>
|
|
||||||
</KBD></DD>
|
|
||||||
<DD>Build: <KBD><B>cd libburn ; ./bootstrap ; ./configure --prefix /usr ; make ; cdrskin/compile_cdrskin.sh</B>
|
|
||||||
</KBD></DD>
|
|
||||||
<DD>Build of SVN versions needs <A HREF="http://sources.redhat.com/autobook/">
|
|
||||||
autotools</A> of at least version 1.7 installed.
|
|
||||||
But after the run of <KBD>./bootstrap</KBD>, only
|
|
||||||
vanilla tools like make and gcc are needed.</DD>
|
|
||||||
</DD>
|
|
||||||
<DD> </DD>
|
|
||||||
<DT>The following download is intended for adventurous end users or
|
|
||||||
admins with full system souvereignty.</DT>
|
|
||||||
<DD>Source (./bootstrap is already applied, build tested, for more see
|
|
||||||
<A HREF="README_cdrskin_devel">upcoming README</A> ):
|
|
||||||
</DD>
|
|
||||||
<DD>
|
|
||||||
<A HREF="cdrskin-0.4.7.tar.gz">cdrskin-0.4.7.tar.gz</A>
|
|
||||||
(730 KB).
|
|
||||||
</DD>
|
|
||||||
|
|
||||||
<!-- This is not offered any more since spring 2008
|
|
||||||
|
|
||||||
<DT>The following downloads are intended for adventurous end users or
|
|
||||||
admins with full system souvereignty.</DT>
|
|
||||||
<DD>Binary (untar and move to /usr/bin/cdrskin):</DD>
|
|
||||||
<DD><A HREF="cdrskin_0.4.3-x86-suse9_0.tar.gz">
|
|
||||||
cdrskin_0.4.3-x86-suse9_0.tar.gz</A>, (110 KB).
|
|
||||||
</DD>
|
|
||||||
<DD><A HREF="cdrskin_0.4.3-x86-suse9_0-static.tar.gz">
|
|
||||||
cdrskin_0.4.3-x86-suse9_0-static.tar.gz</A>, (310 KB)
|
|
||||||
</DD>
|
|
||||||
-->
|
|
||||||
|
|
||||||
</DL>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<P>
|
|
||||||
Many thanks to Joerg Schilling for cdrecord,
|
|
||||||
<BR>
|
|
||||||
and to Derek Foreman and Ben Jansens for creating libburn.
|
|
||||||
<BR>
|
|
||||||
Historic versions based on Derek's and Ben's
|
|
||||||
<A HREF="http://icculus.org/burn">icculus.org/burn</A> :<BR>
|
|
||||||
<A HREF="cdrskin-0.1.2.0.2.ts.tar.gz">cdrskin-0.1.2.0.2.ts.tar.gz</A><BR>
|
|
||||||
<A HREF="cdrskin-0.1.3.0.2.ts.tar.gz">cdrskin-0.1.3.0.2.ts.tar.gz</A>
|
|
||||||
<BR>
|
|
||||||
Very special thanks to Andy Polyakov whose
|
|
||||||
<A HREF="http://fy.chalmers.se/~appro/linux/DVD+RW/tools">dvd+rw-tools</A>
|
|
||||||
provide libburn with invaluable examples on how to deal with DVD media.
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<A NAME="examples">
|
|
||||||
<P>
|
|
||||||
<DL>
|
|
||||||
<DT>Example for a setup of device permissions. To be done by the superuser:</DT>
|
|
||||||
<DT>(CD devices which offer no rw-permission are invisible to normal users.)
|
|
||||||
</DT>
|
|
||||||
<DD># <KBD><B>cdrskin --devices</B></KBD></DD>
|
|
||||||
<DD><KBD>...</KBD></DD>
|
|
||||||
<DD><KBD>0 dev='/dev/sr0' rwrwr- : 'TEAC' 'CD-ROM CD-532S'</KBD></DD>
|
|
||||||
<DD><KBD>1 dev='/dev/hdc' rwrw-- : 'LITE-ON' 'LTR-48125S'</KBD></DD>
|
|
||||||
<DD># <KBD><B>chmod a+rw /dev/sr0 /dev/hdc</B></KBD></DD>
|
|
||||||
</DL>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<A NAME="k3b">
|
|
||||||
<P>
|
|
||||||
<A HREF="k3b_on_cdrskin.html">
|
|
||||||
Example how to setup K3b to use cdrskin for burning data CD projects.
|
|
||||||
<A><BR>
|
|
||||||
(<A HREF="http://www.k3b.org">K3b</A>
|
|
||||||
is a GUI frontend which uses cdrecord for CD burning.)
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<A NAME="scdbackup">
|
|
||||||
<P>
|
|
||||||
<DL>
|
|
||||||
<DT>Example for a test session with a cdrecord based scdbackup installation:</DT>
|
|
||||||
<DD>$ <KBD><B>cdrskin -scanbus</B></KBD></DD>
|
|
||||||
<DD><KBD>...</KBD></DD>
|
|
||||||
<DD><KBD> 2,0,0 0) 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
|
|
||||||
<DD>$ <KBD><B>cdrskin -scanbus dev=ATA</B></KBD></DD>
|
|
||||||
<DD><KBD>...</KBD></DD>
|
|
||||||
<DD><KBD> 1,0,0 1) 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
|
|
||||||
<DD>$ <KBD><B>export SCDBACKUP_SCSI_ADR="ATA:1,0,0"</B></KBD></DD>
|
|
||||||
<DD>$ <KBD><B>export SCDBACKUP_CDRECORD="cdrskin -v -v"</B></KBD></DD>
|
|
||||||
<DD>$ <KBD><B>scdbackup_home</B></KBD></DD>
|
|
||||||
</DL>
|
|
||||||
<DL>
|
|
||||||
<DT>Example for a permanent configuration of cdrskin based scdbackup</DT>
|
|
||||||
<DD>$ <KBD><B>cd scdbackup-0.8.6/inst</B></KBD></DD>
|
|
||||||
<DD>$ <KBD><B>export SCDBACKUP_USE_CDRSKIN=1</B></KBD></DD>
|
|
||||||
<DD>$ <KBD><B>./CONFIGURE_CD</B></KBD></DD>
|
|
||||||
<DD><KBD>...</KBD></DD>
|
|
||||||
<DD><KBD>cdrskin 0.3.8 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
|
|
||||||
</DL>
|
|
||||||
If your system is stricken with some ill CD device then this can stall
|
|
||||||
and you will have to press <KBD>Ctrl+C</KBD> to abort.
|
|
||||||
In this case, you may execute
|
|
||||||
<KBD>export SCDBACKUP_NO_SCANBUS=1</KBD>
|
|
||||||
and try again.
|
|
||||||
<DL>
|
|
||||||
<DT></DT>
|
|
||||||
<DD><KBD> ------------------- SCSI devices. To be used like 0,0,0</KBD></DD>
|
|
||||||
<DD><KBD> 2,0,0 0) 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
|
|
||||||
<DD><KBD> ------------------- end of SCSI device list</KBD></DD>
|
|
||||||
<DD><KBD> ------------------- ATA devices. To be used like ATA:0,0,0
|
|
||||||
<DD><KBD> 1,0,0 1) 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
|
|
||||||
<DD><KBD>...</KBD></DD>
|
|
||||||
<DD><KBD> * Your cdrecord offers -driveropts=burnfree with your recorder.</KBD></DD>
|
|
||||||
<DD><KBD>...</KBD></DD>
|
|
||||||
<DD><KBD>scdbackup for CD 0.8.6 : First stage of installation done.</KBD></DD>
|
|
||||||
<DD><KBD>...</KBD></DD>
|
|
||||||
<DD><KBD>Now give it a try. Run : scdbackup_home</KBD></DD>
|
|
||||||
<DD>$ <KBD><B>unset SCDBACKUP_USE_CDRSKIN</B></KBD></DD>
|
|
||||||
</DL>
|
|
||||||
<DL>
|
|
||||||
<DT>To get back to using cdrecord :</DT>
|
|
||||||
<DD>$ <KBD><B>cd scdbackup-0.8.6/inst</B></KBD></DD>
|
|
||||||
<DD>$ <KBD><B>export SCDBACKUP_USE_CDRSKIN=0</B></KBD></DD>
|
|
||||||
<DD>$ <KBD><B>./CONFIGURE_CD</B></KBD></DD>
|
|
||||||
<DD><KBD>...</KBD></DD>
|
|
||||||
<DD>$ <KBD><B>unset SCDBACKUP_USE_CDRSKIN</B></KBD></DD>
|
|
||||||
</DL>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<A NAME="cdrecord">
|
|
||||||
<P>
|
|
||||||
<CENTER><H3>About the relationship of cdrecord and cdrskin</H3></CENTER>
|
|
||||||
First of all: this relationship is single sided, as cdrskin has to be aware of
|
|
||||||
cdrecord but not vice versa.
|
|
||||||
<BR>
|
|
||||||
<BR>
|
|
||||||
I am a long time user of cdrecord and it works fine for me.
|
|
||||||
Especially i do appreciate its write mode -tao which allows to pipe arbitrary
|
|
||||||
data on CD and CD-RW via stdin. cdrecord is reliable, versatile and well
|
|
||||||
maintained. So for me - there would be not problem with it.
|
|
||||||
<BR>
|
|
||||||
But the author of cdrecord and the Linux kernel people foster a very hostile
|
|
||||||
relationship. Ok, that's their business, not mine (or ours if you are with me).
|
|
||||||
One has to be aware, though, that this relationship might lead to a situation
|
|
||||||
where cdrecord is no longer available for certain Linux kernels.
|
|
||||||
<BR>
|
|
||||||
To have my own project prepared for such a time, i began to implement its
|
|
||||||
cdrecord gestures on top of libburn.
|
|
||||||
From now on i invite other interested users of cdrecord to teach cdrskin
|
|
||||||
the gestures necessary for their cdrecord applications.
|
|
||||||
Contact me. Let's see what we can achieve.
|
|
||||||
<BR>
|
|
||||||
<BR>
|
|
||||||
libburn and cdrskin are now mature enough to substitute cdrecord in its
|
|
||||||
major use cases of CD and DVD burning. It is possible to foist cdrskin on
|
|
||||||
various software packages if it gets falsely named "cdrecord".
|
|
||||||
I do not encourage this approach, but of course such a replacement
|
|
||||||
opportunity is the goal of a cdrecord compatibility wrapper.
|
|
||||||
<BR>
|
|
||||||
<BR>
|
|
||||||
It is very important to me that this project is not perceived as hostile
|
|
||||||
towards Joerg Schilling and his ongoing work.
|
|
||||||
I owe him much. For cdrecord, for mkisofs, for star. Chapeau.
|
|
||||||
<BR>
|
|
||||||
</P>
|
|
||||||
<HR>
|
|
||||||
|
|
||||||
<CENTER><FONT SIZE=+0>
|
|
||||||
<!-- <A NAME="bottom" HREF="main_ger.html#bottom">deutsch (german)</A>
|
|
||||||
<BR><BR>
|
|
||||||
-->
|
|
||||||
<A HREF="http://en.wikipedia.org/wiki/D%C3%B6ner_kebab">
|
|
||||||
<IMG SRC="doener_150x200_tr.png" BORDER=0
|
|
||||||
ALT="cdrskin logo: Doener mit Scharf"></A>
|
|
||||||
<BR><BR>
|
|
||||||
<FONT SIZE=+0>Enjoying free Open Source hosting by <A HREF="http://www.webframe.org">www.webframe.org</A><BR>
|
|
||||||
<A HREF="http://www.webframe.org">
|
|
||||||
<IMG SRC="msfree.gif" ALT="100 % Microsoft free" BORDER=0></A><BR>
|
|
||||||
and by <A HREF="http://sourceforge.net">sourceforge.net</A><BR>
|
|
||||||
<A href="http://sourceforge.net">
|
|
||||||
<IMG src="sflogo-88-1.png" BORDER="0" ALT="SourceForge Logo"></A>
|
|
||||||
<!-- on sourceforge use : <IMG src="http://sourceforge.net/sflogo.php?group_id=16010" width="88" height="31" border="0" alt="SourceForge Logo"></A> -->
|
|
||||||
</FONT></CENTER>
|
|
||||||
<HR>
|
|
||||||
<DL>
|
|
||||||
<DT>Links to my other published software projects :
|
|
||||||
<DD><A HREF="http://scdbackup.webframe.org/xorriso_eng.html">
|
|
||||||
xorriso, a standalone ISO 9660 multi-session CD/DVD burn tool.
|
|
||||||
No mkisofs needed.
|
|
||||||
<DL>
|
|
||||||
<DD>
|
|
||||||
<A HREF="http://scdbackup.sourceforge.net/xorriso_eng.html">
|
|
||||||
(a second source of above)</A>
|
|
||||||
</DD>
|
|
||||||
</DL>
|
|
||||||
</DD>
|
|
||||||
<DD><A HREF=http://scdbackup.webframe.org/main_eng.html>
|
|
||||||
scdbackup, multi volume CD backup</A>
|
|
||||||
<DL><DD><A HREF=http://scdbackup.sourceforge.net/main_eng.html>
|
|
||||||
(a second source of above)</A></DD></DL></DD>
|
|
||||||
<DD><A HREF=http://stic.sourceforge.net>Some Tools for Image Collectors</A>
|
|
||||||
</DD>
|
|
||||||
<DD><A HREF=http://scdbackup.webframe.org/pppoem>
|
|
||||||
pppoem, a DSL throughput monitor (mainly for Linux kernel 2.4)</A>
|
|
||||||
</DD>
|
|
||||||
</DL>
|
|
||||||
<BR><BR>
|
|
||||||
Legal statement: This website does not serve any commercial purpose.<BR>
|
|
||||||
</FONT>
|
|
||||||
</BODY>
|
|
||||||
</HTML>
|
|
@ -1 +0,0 @@
|
|||||||
#define Cdrskin_timestamP "2008.05.10.080001"
|
|
File diff suppressed because it is too large
Load Diff
@ -1,215 +0,0 @@
|
|||||||
/*
|
|
||||||
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
|
|
||||||
A signal handler which cleans up an application and exits.
|
|
||||||
|
|
||||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
cc -g -o cleanup -DCleanup_standalonE cleanup.c
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
typedef void (*sighandler_t)(int);
|
|
||||||
|
|
||||||
|
|
||||||
#include "cleanup.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef Cleanup_has_no_libburn_os_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "../libburn/os.h"
|
|
||||||
|
|
||||||
/* see os.h for name of particular os-*.h where this is defined */
|
|
||||||
static int signal_list[]= { BURN_OS_SIGNAL_MACRO_LIST , -1};
|
|
||||||
static char *signal_name_list[]= { BURN_OS_SIGNAL_NAME_LIST , "@"};
|
|
||||||
static int signal_list_count= BURN_OS_SIGNAL_COUNT;
|
|
||||||
static int non_signal_list[]= { BURN_OS_NON_SIGNAL_MACRO_LIST, -1};
|
|
||||||
static int non_signal_list_count= BURN_OS_NON_SIGNAL_COUNT;
|
|
||||||
|
|
||||||
|
|
||||||
#else /* ! Cleanup_has_no_libburn_os_H */
|
|
||||||
|
|
||||||
|
|
||||||
/* Outdated. Linux only. For backward compatibility with pre-libburn-0.2.3 */
|
|
||||||
|
|
||||||
/* Signals to be caught */
|
|
||||||
static int signal_list[]= {
|
|
||||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
|
|
||||||
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
|
|
||||||
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
|
|
||||||
SIGTTOU,
|
|
||||||
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
|
|
||||||
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
|
|
||||||
};
|
|
||||||
static char *signal_name_list[]= {
|
|
||||||
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
|
|
||||||
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
|
|
||||||
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
|
|
||||||
"SIGTTOU",
|
|
||||||
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
|
|
||||||
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
|
|
||||||
};
|
|
||||||
static int signal_list_count= 24;
|
|
||||||
|
|
||||||
/* Signals not to be caught */
|
|
||||||
static int non_signal_list[]= {
|
|
||||||
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH, -1
|
|
||||||
};
|
|
||||||
static int non_signal_list_count= 5;
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* Cleanup_has_no_libburn_os_H */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* run time dynamic part */
|
|
||||||
static char cleanup_msg[4096]= {""};
|
|
||||||
static int cleanup_exiting= 0;
|
|
||||||
static int cleanup_has_reported= -1234567890;
|
|
||||||
|
|
||||||
static void *cleanup_app_handle= NULL;
|
|
||||||
static Cleanup_app_handler_T cleanup_app_handler= NULL;
|
|
||||||
static int cleanup_perform_app_handler_first= 0;
|
|
||||||
|
|
||||||
|
|
||||||
static int Cleanup_handler_exit(int exit_value, int signum, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if(cleanup_msg[0]!=0 && cleanup_has_reported!=signum) {
|
|
||||||
fprintf(stderr,"\n%s\n",cleanup_msg);
|
|
||||||
cleanup_has_reported= signum;
|
|
||||||
}
|
|
||||||
if(cleanup_perform_app_handler_first)
|
|
||||||
if(cleanup_app_handler!=NULL) {
|
|
||||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
|
||||||
if(ret==2 || ret==-2)
|
|
||||||
return(2);
|
|
||||||
}
|
|
||||||
if(cleanup_exiting) {
|
|
||||||
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
|
|
||||||
getpid(),signum);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
cleanup_exiting= 1;
|
|
||||||
alarm(0);
|
|
||||||
if(!cleanup_perform_app_handler_first)
|
|
||||||
if(cleanup_app_handler!=NULL) {
|
|
||||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
|
||||||
if(ret==2 || ret==-2)
|
|
||||||
return(2);
|
|
||||||
}
|
|
||||||
exit(exit_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void Cleanup_handler_generic(int signum)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
sprintf(cleanup_msg,"UNIX-SIGNAL caught: %d errno= %d",signum,errno);
|
|
||||||
for(i= 0; i<signal_list_count; i++)
|
|
||||||
if(signum==signal_list[i]) {
|
|
||||||
sprintf(cleanup_msg,"UNIX-SIGNAL: %s errno= %d",
|
|
||||||
signal_name_list[i],errno);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Cleanup_handler_exit(1,signum,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
|
|
||||||
/*
|
|
||||||
bit0= set to default handlers
|
|
||||||
bit1= set to ignore
|
|
||||||
bit2= set cleanup_perform_app_handler_first
|
|
||||||
bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
int i,j,max_sig= -1,min_sig= 0x7fffffff;
|
|
||||||
sighandler_t sig_handler;
|
|
||||||
|
|
||||||
cleanup_msg[0]= 0;
|
|
||||||
cleanup_app_handle= handle;
|
|
||||||
cleanup_app_handler= handler;
|
|
||||||
|
|
||||||
/* <<< make cleanup_exiting thread safe to get rid of this */
|
|
||||||
if(flag&4)
|
|
||||||
cleanup_perform_app_handler_first= 1;
|
|
||||||
|
|
||||||
|
|
||||||
if(flag&1)
|
|
||||||
sig_handler= SIG_DFL;
|
|
||||||
else if(flag&2)
|
|
||||||
sig_handler= SIG_IGN;
|
|
||||||
else
|
|
||||||
sig_handler= Cleanup_handler_generic;
|
|
||||||
/* set all signal numbers between the lowest and highest in the list
|
|
||||||
except those in the non-signal list */
|
|
||||||
for(i= 0; i<signal_list_count; i++) {
|
|
||||||
if(signal_list[i]>max_sig)
|
|
||||||
max_sig= signal_list[i];
|
|
||||||
if(signal_list[i]<min_sig)
|
|
||||||
min_sig= signal_list[i];
|
|
||||||
}
|
|
||||||
for(i= min_sig; i<=max_sig; i++) {
|
|
||||||
for(j= 0; j<non_signal_list_count; j++)
|
|
||||||
if(i==non_signal_list[j])
|
|
||||||
break;
|
|
||||||
if(j>=non_signal_list_count) {
|
|
||||||
if(i==SIGABRT && (flag&8))
|
|
||||||
signal(i,Cleanup_handler_generic);
|
|
||||||
else
|
|
||||||
signal(i,sig_handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef Cleanup_standalonE
|
|
||||||
|
|
||||||
struct Demo_apP {
|
|
||||||
char *msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int Demo_app_handler(struct Demo_apP *demoapp, int signum, int flag)
|
|
||||||
{
|
|
||||||
printf("Handling exit of demo application on signal %d. msg=\"%s\"\n",
|
|
||||||
signum,demoapp->msg);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
{
|
|
||||||
struct Demo_apP demoapp;
|
|
||||||
|
|
||||||
demoapp.msg= "Good Bye";
|
|
||||||
Cleanup_set_handlers(&demoapp,(Cleanup_app_handler_T) Demo_app_handler,0);
|
|
||||||
|
|
||||||
if(1) { /* change to 0 in order to wait for external signals */
|
|
||||||
char *cpt= NULL,c;
|
|
||||||
printf("Intentionally provoking SIGSEGV ...\n");
|
|
||||||
c= *cpt;
|
|
||||||
} else {
|
|
||||||
printf("killme: %d\n",getpid());
|
|
||||||
sleep(3600);
|
|
||||||
}
|
|
||||||
|
|
||||||
Cleanup_set_handlers(NULL,NULL,1);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* Cleanup_standalonE */
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
|
|
||||||
A signal handler which cleans up an application and exits.
|
|
||||||
|
|
||||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef Cleanup_includeD
|
|
||||||
#define Cleanup_includeD 1
|
|
||||||
|
|
||||||
|
|
||||||
/** Layout of an application provided cleanup function using an application
|
|
||||||
provided handle as first argument and the signal number as second
|
|
||||||
argument. The third argument is a flag bit field with no defined bits yet.
|
|
||||||
If the handler returns 2 or -2 then it has delegated exit() to some other
|
|
||||||
instance and the Cleanup handler shall return rather than exit.
|
|
||||||
*/
|
|
||||||
typedef int (*Cleanup_app_handler_T)(void *, int, int);
|
|
||||||
|
|
||||||
|
|
||||||
/** Establish exiting signal handlers on (hopefully) all signals that are
|
|
||||||
not ignored by default or non-catchable.
|
|
||||||
@param handle Opaque object which knows how to cleanup application
|
|
||||||
@param handler Function which uses handle to perform application cleanup
|
|
||||||
@param flag Control Bitfield
|
|
||||||
bit0= reset to default signal handling
|
|
||||||
*/
|
|
||||||
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler,
|
|
||||||
int flag);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! Cleanup_includeD */
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# compile_cdrskin.sh
|
|
||||||
# Copyright 2005 - 2008 Thomas Schmitt, scdbackup@gmx.net, GPL version 2
|
|
||||||
# to be executed within ./libburn-* resp ./cdrskin-*
|
|
||||||
|
|
||||||
debug_opts="-O2"
|
|
||||||
def_opts=
|
|
||||||
largefile_opts="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1"
|
|
||||||
libvers="-DCdrskin_libburn_0_4_6"
|
|
||||||
cleanup_src_or_obj="libburn/cleanup.o"
|
|
||||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
|
||||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
|
||||||
do_strip=0
|
|
||||||
static_opts=
|
|
||||||
warn_opts="-Wall"
|
|
||||||
fifo_source="cdrskin/cdrfifo.c"
|
|
||||||
compile_cdrskin=1
|
|
||||||
compile_cdrfifo=0
|
|
||||||
compile_dewav=0
|
|
||||||
|
|
||||||
for i in "$@"
|
|
||||||
do
|
|
||||||
if test "$i" = "-compile_cdrfifo"
|
|
||||||
then
|
|
||||||
compile_cdrfifo=1
|
|
||||||
elif test "$i" = "-compile_dewav"
|
|
||||||
then
|
|
||||||
compile_dewav=1
|
|
||||||
elif test "$i" = "-cvs_A60220"
|
|
||||||
then
|
|
||||||
libvers="-DCdrskin_libburn_cvs_A60220_tS"
|
|
||||||
libdax_audioxtr_o=
|
|
||||||
libdax_msgs_o="libburn/message.o"
|
|
||||||
cleanup_src_or_obj="-DCleanup_has_no_libburn_os_H cdrskin/cleanup.c"
|
|
||||||
elif test "$i" = "-libburn_0_4_6"
|
|
||||||
then
|
|
||||||
libvers="-DCdrskin_libburn_0_4_6"
|
|
||||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
|
||||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
|
||||||
cleanup_src_or_obj="libburn/cleanup.o"
|
|
||||||
elif test "$i" = "-libburn_svn"
|
|
||||||
then
|
|
||||||
libvers="-DCdrskin_libburn_0_4_7"
|
|
||||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
|
||||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
|
||||||
cleanup_src_or_obj="libburn/cleanup.o"
|
|
||||||
elif test "$i" = "-newapi" -o "$i" = "-experimental"
|
|
||||||
then
|
|
||||||
def_opts="$def_opts -DCdrskin_new_api_tesT"
|
|
||||||
elif test "$i" = "-oldfashioned"
|
|
||||||
then
|
|
||||||
def_opts="$def_opts -DCdrskin_oldfashioned_api_usE"
|
|
||||||
cleanup_src_or_obj="-DCleanup_has_no_libburn_os_H cdrskin/cleanup.c"
|
|
||||||
elif test "$i" = "-no_largefile"
|
|
||||||
then
|
|
||||||
largefile_opts=
|
|
||||||
elif test "$i" = "-do_not_compile_cdrskin"
|
|
||||||
then
|
|
||||||
compile_cdrskin=0
|
|
||||||
elif test "$i" = "-do_diet"
|
|
||||||
then
|
|
||||||
fifo_source=
|
|
||||||
def_opts="$def_opts -DCdrskin_extra_leaN"
|
|
||||||
warn_opts=
|
|
||||||
elif test "$i" = "-do_strip"
|
|
||||||
then
|
|
||||||
do_strip=1
|
|
||||||
elif test "$i" = "-g"
|
|
||||||
then
|
|
||||||
debug_opts="-g"
|
|
||||||
elif test "$i" = "-help" -o "$i" = "--help" -o "$i" = "-h"
|
|
||||||
then
|
|
||||||
echo "cdrskin/compile_cdrskin.sh : to be executed within top level directory"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -compile_cdrfifo compile program cdrskin/cdrfifo."
|
|
||||||
echo " -compile_dewav compile program test/dewav without libburn."
|
|
||||||
echo " -cvs_A60220 set macro to match libburn-CVS of 20 Feb 2006."
|
|
||||||
echo " -libburn_0_4_6 set macro to match libburn-0.4.6."
|
|
||||||
echo " -libburn_svn set macro to match current libburn-SVN."
|
|
||||||
echo " -no_largefile do not use 64 bit off_t (must match libburn)."
|
|
||||||
echo " -do_not_compile_cdrskin omit compilation of cdrskin/cdrskin."
|
|
||||||
echo " -experimental use newly introduced libburn features."
|
|
||||||
echo " -oldfashioned use pre-0.2.2 libburn features only."
|
|
||||||
echo " -do_diet produce capability reduced lean version."
|
|
||||||
echo " -do_strip apply program strip to compiled programs."
|
|
||||||
echo " -g produce debuggable programm."
|
|
||||||
echo " -static compile with cc option -static."
|
|
||||||
exit 0
|
|
||||||
elif test "$i" = "-static"
|
|
||||||
then
|
|
||||||
static_opts="-static"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
|
|
||||||
echo "Version timestamp : $(sed -e 's/#define Cdrskin_timestamP "//' -e 's/"$//' cdrskin/cdrskin_timestamp.h)"
|
|
||||||
echo "Build timestamp : $timestamp"
|
|
||||||
|
|
||||||
if test "$compile_cdrskin"
|
|
||||||
then
|
|
||||||
echo "compiling program cdrskin/cdrskin.c $static_opts $debug_opts $libvers $def_opts $cleanup_src_or_obj"
|
|
||||||
cc -I. \
|
|
||||||
$warn_opts \
|
|
||||||
$static_opts \
|
|
||||||
$debug_opts \
|
|
||||||
$libvers \
|
|
||||||
$largefile_opts \
|
|
||||||
$def_opts \
|
|
||||||
\
|
|
||||||
-DCdrskin_build_timestamP='"'"$timestamp"'"' \
|
|
||||||
\
|
|
||||||
-o cdrskin/cdrskin \
|
|
||||||
\
|
|
||||||
cdrskin/cdrskin.c \
|
|
||||||
$fifo_source \
|
|
||||||
\
|
|
||||||
$cleanup_src_or_obj \
|
|
||||||
\
|
|
||||||
libburn/async.o \
|
|
||||||
libburn/debug.o \
|
|
||||||
libburn/drive.o \
|
|
||||||
libburn/file.o \
|
|
||||||
libburn/init.o \
|
|
||||||
libburn/options.o \
|
|
||||||
libburn/source.o \
|
|
||||||
libburn/structure.o \
|
|
||||||
\
|
|
||||||
libburn/sg.o \
|
|
||||||
libburn/write.o \
|
|
||||||
libburn/read.o \
|
|
||||||
$libdax_audioxtr_o \
|
|
||||||
$libdax_msgs_o \
|
|
||||||
\
|
|
||||||
libburn/mmc.o \
|
|
||||||
libburn/sbc.o \
|
|
||||||
libburn/spc.o \
|
|
||||||
libburn/util.o \
|
|
||||||
\
|
|
||||||
libburn/sector.o \
|
|
||||||
libburn/toc.o \
|
|
||||||
\
|
|
||||||
libburn/crc.o \
|
|
||||||
libburn/lec.o \
|
|
||||||
\
|
|
||||||
-lpthread
|
|
||||||
|
|
||||||
ret=$?
|
|
||||||
if test "$ret" = 0
|
|
||||||
then
|
|
||||||
dummy=dummy
|
|
||||||
else
|
|
||||||
echo >&2
|
|
||||||
echo "+++ FATAL : Compilation of cdrskin failed" >&2
|
|
||||||
echo >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$compile_cdrfifo" = 1
|
|
||||||
then
|
|
||||||
echo "compiling program cdrskin/cdrfifo.c $static_opts $debug_opts"
|
|
||||||
cc $static_opts $debug_opts \
|
|
||||||
-DCdrfifo_standalonE \
|
|
||||||
-o cdrskin/cdrfifo \
|
|
||||||
cdrskin/cdrfifo.c
|
|
||||||
|
|
||||||
ret=$?
|
|
||||||
if test "$ret" = 0
|
|
||||||
then
|
|
||||||
dummy=dummy
|
|
||||||
else
|
|
||||||
echo >&2
|
|
||||||
echo "+++ FATAL : Compilation of cdrfifo failed" >&2
|
|
||||||
echo >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$compile_dewav" = 1
|
|
||||||
then
|
|
||||||
echo "compiling program test/dewav.c -DDewav_without_libburN $static_opts $debug_opts"
|
|
||||||
cc $static_opts $debug_opts \
|
|
||||||
-DDewav_without_libburN \
|
|
||||||
-o test/dewav \
|
|
||||||
test/dewav.c \
|
|
||||||
libburn/libdax_audioxtr.o \
|
|
||||||
libburn/libdax_msgs.o \
|
|
||||||
\
|
|
||||||
-lpthread
|
|
||||||
|
|
||||||
ret=$?
|
|
||||||
if test "$ret" = 0
|
|
||||||
then
|
|
||||||
dummy=dummy
|
|
||||||
else
|
|
||||||
echo >&2
|
|
||||||
echo "+++ FATAL : Compilation of test/dewav failed" >&2
|
|
||||||
echo >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$do_strip" = 1
|
|
||||||
then
|
|
||||||
echo "stripping result cdrskin/cdrskin"
|
|
||||||
strip cdrskin/cdrskin
|
|
||||||
if test "$compile_cdrfifo" = 1
|
|
||||||
then
|
|
||||||
echo "stripping result cdrskin/cdrfifo"
|
|
||||||
strip cdrskin/cdrfifo
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo 'done.'
|
|
@ -1,78 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# convert_man_to_html.sh - ts A61214
|
|
||||||
#
|
|
||||||
# Generates a HTML version of man page cdrskin.1
|
|
||||||
#
|
|
||||||
# To be executed within the libburn toplevel directory (like ./libburn-0.2.7)
|
|
||||||
#
|
|
||||||
|
|
||||||
# set -x
|
|
||||||
|
|
||||||
man_dir=$(pwd)"/cdrskin"
|
|
||||||
export MANPATH="$man_dir"
|
|
||||||
manpage="cdrskin"
|
|
||||||
raw_html=$(pwd)/"cdrskin/raw_man_1_cdrskin.html"
|
|
||||||
htmlpage=$(pwd)/"cdrskin/man_1_cdrskin.html"
|
|
||||||
|
|
||||||
if test -r "$man_dir"/"$manpage".1
|
|
||||||
then
|
|
||||||
dummy=dummy
|
|
||||||
else
|
|
||||||
echo "Cannot find readable man page source $1" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -e "$man_dir"/man1
|
|
||||||
then
|
|
||||||
dummy=dummy
|
|
||||||
else
|
|
||||||
ln -s . "$man_dir"/man1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$1" = "-work_as_filter"
|
|
||||||
then
|
|
||||||
|
|
||||||
# set -x
|
|
||||||
|
|
||||||
sed \
|
|
||||||
-e 's/<meta name="generator" content="groff -Thtml, see www.gnu.org">/<meta name="generator" content="groff -Thtml, via man -H, via cdrskin\/convert_man_to_html.sh">/' \
|
|
||||||
-e 's/<meta name="Content-Style" content="text\/css">/<meta name="Content-Style" content="text\/css"><META NAME="description" CONTENT="man page of cdrskin"><META NAME="keywords" CONTENT="man cdrskin, manual, cdrskin, CD, CD-RW, CD-R, burning, cdrecord, compatible"><META NAME="robots" CONTENT="follow">/' \
|
|
||||||
-e 's/<title>CDRSKIN<\/title>/<title>man 1 cdrskin<\/title>/' \
|
|
||||||
-e 's/<h1 align=center>CDRSKIN<\/h1>/<h1 align=center>man 1 cdrskin<\/h1>/' \
|
|
||||||
-e 's/<body>/<body BGCOLOR="#F5DEB3" TEXT=#000000 LINK=#0000A0 VLINK=#800000>/' \
|
|
||||||
-e 's/<b>Overview of features:<\/b>/\ <BR><b>Overview of features:<\/b>/' \
|
|
||||||
-e 's/<b>General information paragraphs:<\/b>/\ <BR><b>General information paragraphs:<\/b>/' \
|
|
||||||
-e 's/<b>Track recording model:<\/b>/\ <BR><b>Track recording model:<\/b>/' \
|
|
||||||
-e 's/^In general there are two types of tracks: data and audio./\ <BR>In general there are two types of tracks: data and audio./' \
|
|
||||||
-e 's/^While audio tracks just contain a given/\ <BR>While audio tracks just contain a given/' \
|
|
||||||
-e 's/<b>Write mode selection:<\/b>/\ <BR><b>Write mode selection:<\/b>/' \
|
|
||||||
-e 's/<b>Recordable CD Media:<\/b>/\ <BR><b>Recordable CD Media:<\/b>/' \
|
|
||||||
-e 's/<b>Overwriteable DVD Media:<\/b>/\ <BR><b>Overwriteable DVD Media:<\/b>/' \
|
|
||||||
-e 's/<b>Sequentially Recordable DVD Media:<\/b>/\ <BR><b>Sequentially Recordable DVD Media:<\/b>/' \
|
|
||||||
-e 's/^The write modes for DVD+R/\ <BR>The write modes for DVD+R/' \
|
|
||||||
-e 's/<b>Drive preparation and addressing:<\/b>/\ <BR><b>Drive preparation and addressing:<\/b>/' \
|
|
||||||
-e 's/^If you only got one CD capable drive/\ <BR>If you only got one CD capable drive/' \
|
|
||||||
-e 's/<b>Emulated drives:<\/b>/\ <BR><b>Emulated drives:<\/b>/' \
|
|
||||||
-e 's/^Alphabetical list of options/\ <BR>Alphabetical list of options/' \
|
|
||||||
-e 's/<\/body>/<BR><HR><FONT SIZE=-1><CENTER>(HTML generated from '"$manpage"'.1 on '"$(date)"' by '$(basename "$0")' )<\/CENTER><\/FONT><\/body>/' \
|
|
||||||
-e 's/See section FILES/See section <A HREF="#FILES">FILES<\/A>/' \
|
|
||||||
-e 's/See section EXAMPLES/See section <A HREF="#EXAMPLES">EXAMPLES<\/A>/' \
|
|
||||||
<"$2" >"$htmlpage"
|
|
||||||
|
|
||||||
set +x
|
|
||||||
|
|
||||||
chmod u+rw,go+r,go-w "$htmlpage"
|
|
||||||
echo "Emerged file:"
|
|
||||||
ls -lL "$htmlpage"
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
export BROWSER='cp "%s" '"$raw_html"
|
|
||||||
man -H "$manpage"
|
|
||||||
"$0" -work_as_filter "$raw_html"
|
|
||||||
rm "$raw_html"
|
|
||||||
rm "$man_dir"/man1
|
|
||||||
|
|
||||||
fi
|
|
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.2 KiB |
@ -1,9 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Create version timestamp cdrskin/cdrskin_timestamp.h
|
|
||||||
# to be executed within ./libburn-* resp ./cdrskin-*
|
|
||||||
|
|
||||||
timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
|
|
||||||
echo "Version timestamp : $timestamp"
|
|
||||||
echo '#define Cdrskin_timestamP "'"$timestamp"'"' >cdrskin/cdrskin_timestamp.h
|
|
||||||
|
|
@ -1,318 +0,0 @@
|
|||||||
--------------------------------------------------------------------------
|
|
||||||
cdrskin Wiki - plain text copy
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
[[Image(source:/libburn/trunk/cdrskin/doener_150x200_tr.png)]] [http://en.wikipedia.org/wiki/D%C3%B6ner_kebab Doener]
|
|
||||||
|
|
||||||
'''cdrskin is the cdrecord compatibility middleware of libburn.'''
|
|
||||||
|
|
||||||
Its paragon, cdrecord, is a powerful GPL'ed burn program included in Joerg
|
|
||||||
Schilling's cdrtools. cdrskin strives to be a second source for the services
|
|
||||||
traditionally provided by cdrecord. Currently it does CD-R and CD-RW this way.
|
|
||||||
Overwriteable media DVD-RAM, DVD+RW, DVD-RW, and BD-RE are handled differently
|
|
||||||
than with cdrecord-ProDVD in order to offer TAO-like single track recording.
|
|
||||||
Sequential DVD-R[W], DVD+R, DVD+R DL are handled like CD-R[W] with TAO and
|
|
||||||
multi-session. Additionally cdrskin offers cdrecord-ProDVD-like mode DAO
|
|
||||||
with DVD-R[W].
|
|
||||||
|
|
||||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
|
||||||
Many bytes have been copied from the message output of cdrecord
|
|
||||||
runs, though. The most comprehensive technical overview of cdrskin
|
|
||||||
can be found in [http://libburnia-project.org/browser/libburn/trunk/cdrskin/README?format=txt cdrskin/README].
|
|
||||||
|
|
||||||
About libburn API for burning CD and DVD: http://api.libburnia-project.org
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
For yet unsupported media types see the advice to use dvd+rw-tools at
|
|
||||||
the end of this text.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
About the command line options of cdrskin:
|
|
||||||
|
|
||||||
They are described in detail in [http://scdbackup.sourceforge.net/man_1_cdrskin_devel.html#OPTIONS section OPTIONS] of
|
|
||||||
[http://scdbackup.sourceforge.net/man_1_cdrskin_devel.html man cdrskin]
|
|
||||||
|
|
||||||
There are two families of options: cdrecord-compatible ones and options
|
|
||||||
which are specific to cdrskin. The latter are mostly used to configure
|
|
||||||
cdrskin for its task to emulate cdrecord. There are some, nevertheless,
|
|
||||||
which provide rather exotic unique features of cdrskin.
|
|
||||||
|
|
||||||
The cdrecord-compatible options are listed in the output of
|
|
||||||
{{{
|
|
||||||
cdrskin -help
|
|
||||||
}}}
|
|
||||||
where the option "help" has *one* dash. Online: [http://scdbackup.sourceforge.net/cdrskin_help_devel cdrskin -help]
|
|
||||||
|
|
||||||
For these options you may expect program behavior that is roughly the
|
|
||||||
same as described in original man cdrecord .
|
|
||||||
|
|
||||||
Online: http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html
|
|
||||||
|
|
||||||
The cdrskin-specific options are listed by
|
|
||||||
{{{
|
|
||||||
cdrskin --help
|
|
||||||
}}}
|
|
||||||
where the option "help" has *two* dashes. Online: [http://scdbackup.sourceforge.net/cdrskin__help_devel cdrskin --help]
|
|
||||||
|
|
||||||
Some are very experimental and should only be
|
|
||||||
used in coordination with the libburnia developer team.
|
|
||||||
Some are of general user interest, though:
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--devices allows the sysadmin to scan the system for possible drives
|
|
||||||
and displays their detected properties.
|
|
||||||
The drives are listed one per line, with fields:
|
|
||||||
libburn-drive-number, sysadmin-device-file, permissions, vendor, type
|
|
||||||
{{{
|
|
||||||
0 dev='/dev/sr0' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
|
|
||||||
}}}
|
|
||||||
This feature is valuable since cdrskin -scanbus will not give you
|
|
||||||
the device file name and its current permissions.
|
|
||||||
cdrskin will accept of course the proposed dev= option as address
|
|
||||||
for any usage of the drive.
|
|
||||||
|
|
||||||
Different from cdrecord, cdrskin is intended to be run without special
|
|
||||||
privileges, i.e. no superuser setuid. It is intended that the sysadmin
|
|
||||||
controls drive accessability by rw-permissions of the drive rather than
|
|
||||||
by x-permission of the burn binary. To be usable with cdrskin, the drive
|
|
||||||
has to offer both, r- and w-permission.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
blank=as_needed applies the suitable blanking or formatting to make
|
|
||||||
any supported type of media ready for writing from scratch.
|
|
||||||
If this is not possible, e.g. because the media is written and not
|
|
||||||
re-usable, then the program run fails.
|
|
||||||
|
|
||||||
Option blank= offers several specialized blanking and formatting types,
|
|
||||||
which one may use for particular purposes on DVD-RW, DVD-RAM and BD-RE.
|
|
||||||
(See also below: blank=format_overwrite)
|
|
||||||
The drive offers a list of possible formats by cdrskin option --list_formats.
|
|
||||||
One should aquire MMC background information before making use of them.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
cdrskin does not only read from and write to optical drives which comply
|
|
||||||
to the MMC standard but also does the same with regular files or block
|
|
||||||
devices other than optical drives.
|
|
||||||
|
|
||||||
Because the power to alter a disk file might be a bad surprise for a
|
|
||||||
traditional user of cdrecord, it is necessary to give option
|
|
||||||
--allow_emulated_drives before an emulated drive may be addressed.
|
|
||||||
Eventually one of the startup files would be a good place for it.
|
|
||||||
See man page, section FILES.
|
|
||||||
|
|
||||||
The addresses of emulated drives begin with the prefix "stdio:".
|
|
||||||
{{{
|
|
||||||
dev=stdio:/tmp/pseudo_drive
|
|
||||||
dev=stdio:/dev/usbstick
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Regular files and block devices behave much like DVD-RAM.
|
|
||||||
|
|
||||||
Other file types may be valid targets for write-only operations.
|
|
||||||
This includes standard output, named pipes, character devices
|
|
||||||
{{{
|
|
||||||
dev=stdio:/dev/fd/1
|
|
||||||
dev=stdio:/tmp/named_pipe
|
|
||||||
dev=stdio:/dev/ptyxy
|
|
||||||
}}}
|
|
||||||
|
|
||||||
These files behave much like blank DVD-R.
|
|
||||||
|
|
||||||
All files used as pseudo-drives have to offer rw-permission.
|
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
The DVD capabilities of cdrskin differ from those of cdrecord-ProDVD. cdrskin
|
|
||||||
offers TAO-like multi-session with DVD-R[W], DVD+R[ DL] and TAO-like single
|
|
||||||
session with overwriteable DVD media. It also offers DAO on DVD-R[W] which is
|
|
||||||
probably the same as the traditional cdrecord-ProDVD write mode.
|
|
||||||
|
|
||||||
Non-cdrecord blank mode blank=format_overwrite brings a DVD-RW
|
|
||||||
disc from its initial profile "Sequential Recording" into profile state
|
|
||||||
"Restricted Overwrite".
|
|
||||||
{{{
|
|
||||||
cdrskin dev=/dev/sr0 -v blank=format_overwrite
|
|
||||||
}}}
|
|
||||||
|
|
||||||
DVD-RAM, DVD+RW, BD-RE and overwriteable DVD-RW appear to cdrskin as blank
|
|
||||||
media which are capable of taking only a single track. This track may be
|
|
||||||
positioned on a 32KiB aligned address, though.
|
|
||||||
{{{
|
|
||||||
cdrskin ... write_start_address=2412m ...
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Non-cdrecord blank mode blank=deformat_sequential brings an overwriteable
|
|
||||||
DVD-RW back into state "Sequential Recording" with the capability of doing
|
|
||||||
multi-session, if the drive is capable of "Incremental Streaming"
|
|
||||||
(MMC feature 21h).
|
|
||||||
|
|
||||||
Used sequential DVD-RW media may be blanked by blank=fast or blank=all which
|
|
||||||
normally both do full blanking. Thus sequential DVD-RW behave much like large
|
|
||||||
CD-RW with possibly more than 99 tracks.
|
|
||||||
|
|
||||||
blank=deformat_sequential does minimal blanking of DVD-RW which usually yields
|
|
||||||
media incapable of "Incremental Streaming".
|
|
||||||
|
|
||||||
Option --prodvd_cli_compatible activates blank=fast and blank=all for
|
|
||||||
overwriteable DVD-RW which normally ignore those two options. It also makes
|
|
||||||
option -multi tolerable with media and write modes which are not suitable for
|
|
||||||
multi-session. (The default behavior of cdrskin deems me to be preferrable.)
|
|
||||||
|
|
||||||
Option --grow_overwriteable_iso gives cdrskin ISO pseudo-multi-session
|
|
||||||
capabilities on DVD-RAM, DVD+RW, BD-RE similar to growisofs.
|
|
||||||
Associated options blank=, -multi, -msinfo and -toc are available in this case.
|
|
||||||
They either pretend a blank media (if there is no ISO 9660 image) or appendable
|
|
||||||
media with a single session and track on it. blank= invalidates ISO images.
|
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
assert_write_lba=<lba> allows to ensure that the start block address which
|
|
||||||
was used with the formatter program (e.g. mkisofs -C) matches the start block
|
|
||||||
address which will be used by the upcoming burn.
|
|
||||||
|
|
||||||
E.g. cdrskin aborts with an error message if
|
|
||||||
{{{
|
|
||||||
assert_write_lba=0
|
|
||||||
}}}
|
|
||||||
is given but an appendable media is to be burned which would start at
|
|
||||||
block 68432.
|
|
||||||
|
|
||||||
|
|
||||||
An ISO-9660 file system image must be prepared according to a particular
|
|
||||||
block address on media. If the prepared address and the real address on media
|
|
||||||
do not match then the filesystem will not be mountable or may even cause system
|
|
||||||
trouble.
|
|
||||||
|
|
||||||
A sequential archive format like afio or star will not necessarily need such
|
|
||||||
a coordination of addresses. It might nevertheless be confusing to a reader
|
|
||||||
if the archive does not start at block 0.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
fifo_start_at=<num> is a throughput enhancer for unsteady data streams
|
|
||||||
like they are produced by a compressing archiver program when piping to
|
|
||||||
CD on-the-fly. It makes better use of the general property of a FIFO
|
|
||||||
buffer to transport surplus bandwidth into the future. Yep. A time machine.
|
|
||||||
One-way, i fear.
|
|
||||||
|
|
||||||
FIFO originally was introduced by cdrecord's author Joerg Schilling in order
|
|
||||||
to protect mediocre burner hardware from suffering buffer underruns
|
|
||||||
and thus producing misburns (at 1x speed on CD-R media at the price of a
|
|
||||||
DVD-RAM nowadays). This purpose would not justify a fifo any more -
|
|
||||||
given the limited life time of burners and the seamless underrun protection
|
|
||||||
of contemporary consumer drives.
|
|
||||||
|
|
||||||
With an unsteady data stream the task of the buffer is to soak up peak
|
|
||||||
performance and to release it steadily at the drive's maximum speed.
|
|
||||||
The larger the buffer the more reserves can be built up and the longer
|
|
||||||
input drought can be compensated.
|
|
||||||
|
|
||||||
Original cdrecord has the historical property, though, to first wait until
|
|
||||||
the buffer is completely filled. Best practice for fighting drive
|
|
||||||
underruns, of course.
|
|
||||||
With a very fat fs=# buffer (128 MB for 12x CD is not unrealistic) this
|
|
||||||
can cause a big delay until burning finally starts and takes its due time.
|
|
||||||
|
|
||||||
fifo_start_at=<num> makes cdrskin start burning after the given number of bytes
|
|
||||||
is read rather than waiting for the FIFO to be completely full resp. the data
|
|
||||||
stream to end. It risks a few drive buffer underruns at the beginning of burn
|
|
||||||
- but modern drives stand this.
|
|
||||||
|
|
||||||
Usage examples:
|
|
||||||
{{{
|
|
||||||
cdrskin ... fs=128m fifo_start_at=20m ...
|
|
||||||
cdrskin ... fifo_start_at=0 ...
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Note: no FIFO can give you better average throughput than the average
|
|
||||||
throughput of the data source and the throughput of the burner.
|
|
||||||
It can be used, though, to bring the effective throughput very close
|
|
||||||
to the theoretical limit. Especially with high speed media.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
--no_rc allows you to surely ban influence from systemwide or user specific
|
|
||||||
default settings of cdrskin. Possible locations for such settings:
|
|
||||||
|
|
||||||
/etc/default/cdrskin
|
|
||||||
|
|
||||||
/etc/opt/cdrskin/rc
|
|
||||||
|
|
||||||
/etc/cdrskin/cdrskin.conf
|
|
||||||
|
|
||||||
$HOME/.cdrskinrc
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
dev_translation=<sep><from><sep><to> may be needed to foist cdrskin to
|
|
||||||
frontend programs of cdrecord which do *not* ask cdrecord -scanbus but
|
|
||||||
which make own assumptions and guesses about cdrecord's device addresses.
|
|
||||||
|
|
||||||
Normally, cdrskin understands all addresses which are suitable for cdrecord
|
|
||||||
under Linux. See cdrskin/README, "Pseudo-SCSI Adresses".
|
|
||||||
This option is mainly for (yet unknown) exotic configurations or very
|
|
||||||
stubborn frontend programs.
|
|
||||||
|
|
||||||
If a frontend refuses to work with cdrskin, look into the error protocol
|
|
||||||
of that frontend, look at the output of a run of cdrskin --devices and give
|
|
||||||
cdrskin the necessary hint.
|
|
||||||
Example: Your frontend insists in using "0,0,0" and --devices reported
|
|
||||||
dev='/dev/hdc' resp. cdrskin dev=ATA -scanbus reported "1,0,0" then this
|
|
||||||
would be the appropriate translation:
|
|
||||||
{{{
|
|
||||||
dev_translation=+0,0,0+/dev/hdc
|
|
||||||
}}}
|
|
||||||
The "+" character is a separator to be choosen by you.
|
|
||||||
Currently i am not aware of the need to choose any other than "+"
|
|
||||||
unless you get playful with custom translations like
|
|
||||||
{{{
|
|
||||||
dev_translation=-"cd+dvd"-1,0,0
|
|
||||||
}}}
|
|
||||||
See http://scdbackup.sourceforge.net/k3b_on_cdrskin.html
|
|
||||||
for an illustrated example with K3b 0.10 .
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
DVD advise:
|
|
||||||
|
|
||||||
For burning of DVD/BD media other than DVD-RAM, DVD+RW, DVD+R, DVD+R DL,
|
|
||||||
DVD-RW, DVD-R, BD-RE, the cdrskin project currently advises to use
|
|
||||||
Andy Polyakov's dvd+rw-tools which despite their historic name are
|
|
||||||
capable of all the media above and more, including BD discs.
|
|
||||||
|
|
||||||
http://fy.chalmers.se/~appro/linux/DVD+RW/tools
|
|
||||||
|
|
||||||
They are not compatible or related to cdrecord resp. cdrecord-ProDVD
|
|
||||||
(now obsoleted by original source cdrtools cdrecord with identical
|
|
||||||
capabilities besides the license key).
|
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Advanced multi-session use cases:
|
|
||||||
|
|
||||||
A special feature of dvd+rw-tools is growing of ISO-9660 filesystems on
|
|
||||||
overwriteable media. This is not the same as multi-session writing of cdrskin
|
|
||||||
with CD media, but retrieves additional information from the existing ISO
|
|
||||||
image and finally manipulates the start sectors of this existing image.
|
|
||||||
|
|
||||||
So, inspired by growisofs, cdrskin can offer DVD multi-session not only with
|
|
||||||
sequential DVD-R[W] and with DVD+R [DL], but also with DVD-RAM, DVD+RW, BD-RE
|
|
||||||
and even regular disk files or block devices other than CD/DVD writers.
|
|
||||||
This is enabled by option --grow_overwriteable_iso.
|
|
||||||
|
|
||||||
The libburnia project provides an integrated ISO-9660 multi-session tool
|
|
||||||
named [wiki:Xorriso xorriso] which tries to go one step beyond
|
|
||||||
growisofs. It uses [wiki:Libburn libburn] , [wiki:Libisofs libisofs]
|
|
||||||
and [wiki:Libisoburn libisoburn].
|
|
||||||
|
|
||||||
See [http://scdbackup.sourceforge.net/man_1_xorriso.html man xorriso].
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
|
||||||
|
|
181
configure.ac
181
configure.ac
@ -1,181 +0,0 @@
|
|||||||
AC_INIT([libburn], [0.4.6], [http://libburnia-project.org])
|
|
||||||
AC_PREREQ([2.50])
|
|
||||||
dnl AC_CONFIG_HEADER([config.h])
|
|
||||||
|
|
||||||
AC_CANONICAL_HOST
|
|
||||||
AC_CANONICAL_TARGET
|
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([subdir-objects])
|
|
||||||
|
|
||||||
dnl Notes by ts A71207 - A80126 :
|
|
||||||
dnl
|
|
||||||
dnl Regrettably the meaning of the various version types was misunderstood
|
|
||||||
dnl before version 0.4.1.
|
|
||||||
dnl
|
|
||||||
dnl In the past MAJOR.MINOR.MICRO versions led to the following SONAME numbers:
|
|
||||||
dnl 0.2.2 = 2 , 0.2.3 = 3 , 0.2.6 = 6
|
|
||||||
dnl 0.3.0 = 0 , 0.3.2 = 2 , 0.3.4 = 4 . 0.3.6 = 6 , 0.3.8 = 4
|
|
||||||
dnl 0.4.0 = 0 (also released as SONAME 4)
|
|
||||||
dnl
|
|
||||||
dnl Meanwhile the following schemes are maintained in parallel:
|
|
||||||
dnl
|
|
||||||
dnl BURN_MAJOR_VERSION , BURN_MINOR_VERSION , BURN_MICRO_VERSION
|
|
||||||
dnl are three small non-negative integers which describe the evolution
|
|
||||||
dnl steps of the library.
|
|
||||||
dnl Older applications are able to use younger libraries over
|
|
||||||
dnl quite a long range of such steps. Some day, nevertheless,
|
|
||||||
dnl compatibility might get terminated, after due notice.
|
|
||||||
dnl
|
|
||||||
dnl SONAME (libburn.so.4)
|
|
||||||
dnl is a small positive integer which marks a family of compatible
|
|
||||||
dnl evolution steps. Libraries with a particular SONAME allow a binary
|
|
||||||
dnl with the same SONAME to start up. Any further compatibility check is to
|
|
||||||
dnl be done by own runtime means. Especially *_version() calls in the API
|
|
||||||
dnl which return BURN_MAJOR_VERSION, BURN_MINOR_VERSION, BURN_MICRO_VERSION.
|
|
||||||
dnl See below.
|
|
||||||
dnl
|
|
||||||
dnl CURRENT, AGE, REVISION
|
|
||||||
dnl are three integers used by libtool. CURRENT is positive, the others
|
|
||||||
dnl non-negative. The use at runtime is not known yet. But libtool computes
|
|
||||||
dnl at build time SONAME = CURRENT - AGE.
|
|
||||||
dnl So this is a superspace of the SONAME version space. To avoid
|
|
||||||
dnl ill SONAME, the value of CURRENT must be larger than AGE.
|
|
||||||
dnl See also http://www.gnu.org/software/libtool/manual.html#Interfaces
|
|
||||||
dnl
|
|
||||||
dnl The name of the dynamic library will be libburn.so.$SONAME.$AGE.$REV .
|
|
||||||
dnl In the terminology of this file:
|
|
||||||
dnl CURRENT = LT_CURRENT
|
|
||||||
dnl AGE = LT_AGE
|
|
||||||
dnl REVISION= LT_REVISION
|
|
||||||
dnl
|
|
||||||
dnl Beginning with libburn-0.4.1 a rectified counting was introduced as
|
|
||||||
dnl CURRENT=10, REVISION=1, AGE=6
|
|
||||||
dnl This rectification declared that version to be binary compatible up
|
|
||||||
dnl from libburn-0.3.4.
|
|
||||||
dnl Real compatibility was given since libburn-0.3.2.
|
|
||||||
dnl Beware of libburn-0.2.6 which had SONAME=6 and is not binary compatible.
|
|
||||||
dnl Applications for libburn-0.2 to libburn-0.3.1 need recompilation but no
|
|
||||||
dnl source code changes.
|
|
||||||
dnl
|
|
||||||
dnl Neatly versioned stable releases meanwhile:
|
|
||||||
dnl 0.4.2 = libburn.so.4.7.0
|
|
||||||
dnl 0.4.4 = libburn.so.4.9.0
|
|
||||||
dnl 0.4.6 = libburn.so.4.11.0
|
|
||||||
dnl
|
|
||||||
dnl So LT_CURRENT, LT_REVISION and LT_AGE get set directly here.
|
|
||||||
dnl SONAME of the emerging library is LT_CURRENT - LT_AGE.
|
|
||||||
dnl The linker will do no finer checks. Especially no age range check for
|
|
||||||
dnl the application binary. If SONAME matches, then the couple starts.
|
|
||||||
dnl
|
|
||||||
dnl Therefore at run time info is provided by libburn function burn_version().
|
|
||||||
dnl It returns the major, minor and micro revision of the library.
|
|
||||||
dnl Before using any API feature, a program should check for age.
|
|
||||||
dnl
|
|
||||||
dnl The variables BURN_*_VERSION are mere copies for informing libtool.
|
|
||||||
dnl The true values which get issued and should be compared are macros
|
|
||||||
dnl defined in libburn/libburn.h .
|
|
||||||
dnl
|
|
||||||
dnl Normally one can allow a program to run with a library which passed the
|
|
||||||
dnl linker SONAME test and which is not older than the library it was
|
|
||||||
dnl developed for. Library2 is younger than library1 if:
|
|
||||||
dnl major2>major1 || (major2==major1 &&
|
|
||||||
dnl (minor2>minor1 || (minor2==minor1 && micro2 > micro1)))
|
|
||||||
dnl
|
|
||||||
dnl If BURN_*_VERSION changes, be sure to change AC_INIT above to match.
|
|
||||||
dnl
|
|
||||||
dnl As said: Only copies. Original in libburn/libburn.h : burn_header_version_*
|
|
||||||
BURN_MAJOR_VERSION=0
|
|
||||||
BURN_MINOR_VERSION=4
|
|
||||||
BURN_MICRO_VERSION=6
|
|
||||||
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
|
|
||||||
|
|
||||||
AC_SUBST(BURN_MAJOR_VERSION)
|
|
||||||
AC_SUBST(BURN_MINOR_VERSION)
|
|
||||||
AC_SUBST(BURN_MICRO_VERSION)
|
|
||||||
AC_SUBST(BURN_VERSION)
|
|
||||||
|
|
||||||
dnl Libtool versioning
|
|
||||||
LT_RELEASE=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
|
|
||||||
dnl
|
|
||||||
dnl ts A80510
|
|
||||||
dnl This is the release version libburn-0.4.6 = libburn.so.4.11.0
|
|
||||||
dnl ### This will be the development version after above release version
|
|
||||||
dnl LT_CURRENT++, LT_AGE++ has not yet happened.
|
|
||||||
dnl
|
|
||||||
dnl SONAME = 15 - 11 = 4 . Library name = libburn.so.4.11.0
|
|
||||||
LT_CURRENT=15
|
|
||||||
LT_REVISION=0
|
|
||||||
LT_AGE=11
|
|
||||||
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
|
|
||||||
|
|
||||||
AC_SUBST(LT_RELEASE)
|
|
||||||
AC_SUBST(LT_CURRENT)
|
|
||||||
AC_SUBST(LT_REVISION)
|
|
||||||
AC_SUBST(LT_AGE)
|
|
||||||
AC_SUBST(LT_CURRENT_MINUS_AGE)
|
|
||||||
|
|
||||||
dnl ts A71207: This is done only not to break any old components
|
|
||||||
BURN_INTERFACE_AGE=$LT_REVISION
|
|
||||||
BURN_BINARY_AGE=`expr $LT_AGE + $BURN_INTERFACE_AGE`
|
|
||||||
AC_SUBST(BURN_INTERFACE_AGE)
|
|
||||||
AC_SUBST(BURN_BINARY_AGE)
|
|
||||||
|
|
||||||
AC_PREFIX_DEFAULT([/usr/local])
|
|
||||||
test "$prefix" = "NONE" && prefix=$ac_default_prefix
|
|
||||||
|
|
||||||
AM_MAINTAINER_MODE
|
|
||||||
|
|
||||||
AM_PROG_CC_C_O
|
|
||||||
AC_C_CONST
|
|
||||||
AC_C_INLINE
|
|
||||||
AC_C_BIGENDIAN
|
|
||||||
|
|
||||||
dnl Large file support
|
|
||||||
AC_SYS_LARGEFILE
|
|
||||||
AC_FUNC_FSEEKO
|
|
||||||
AC_CHECK_FUNC([fseeko])
|
|
||||||
if test ! $ac_cv_func_fseeko; then
|
|
||||||
AC_ERROR([Libburn requires largefile support.])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_PROG_LIBTOOL
|
|
||||||
AC_SUBST(LIBTOOL_DEPS)
|
|
||||||
LIBTOOL="$LIBTOOL --silent"
|
|
||||||
|
|
||||||
AC_PROG_INSTALL
|
|
||||||
|
|
||||||
AC_CHECK_HEADERS()
|
|
||||||
|
|
||||||
THREAD_LIBS=-lpthread
|
|
||||||
AC_SUBST(THREAD_LIBS)
|
|
||||||
|
|
||||||
TARGET_SHIZZLE
|
|
||||||
AC_SUBST(ARCH)
|
|
||||||
AC_SUBST(LIBBURN_ARCH_LIBS)
|
|
||||||
|
|
||||||
dnl Add compiler-specific flags
|
|
||||||
|
|
||||||
dnl See if the user wants aggressive optimizations of the code
|
|
||||||
AC_ARG_ENABLE(debug,
|
|
||||||
[ --enable-debug Disable aggressive optimizations [default=yes]],
|
|
||||||
, enable_debug=yes)
|
|
||||||
if test x$enable_debug != xyes; then
|
|
||||||
if test x$GCC = xyes; then
|
|
||||||
CFLAGS="$CFLAGS -O3"
|
|
||||||
CFLAGS="$CFLAGS -fexpensive-optimizations"
|
|
||||||
fi
|
|
||||||
CFLAGS="$CFLAGS -DNDEBUG"
|
|
||||||
else
|
|
||||||
if test x$GCC = xyes; then
|
|
||||||
CFLAGS="$CFLAGS -g -pedantic -Wall"
|
|
||||||
fi
|
|
||||||
CFLAGS="$CFLAGS -DDEBUG"
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([
|
|
||||||
Makefile
|
|
||||||
doc/doxygen.conf
|
|
||||||
version.h
|
|
||||||
libburn-1.pc
|
|
||||||
])
|
|
||||||
AC_OUTPUT
|
|
@ -1,4 +0,0 @@
|
|||||||
all clean:
|
|
||||||
$(MAKE) -C .. -$(MAKEFLAGS) $@
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
180
doc/comments
180
doc/comments
@ -1,180 +0,0 @@
|
|||||||
/**
|
|
||||||
@author Mario Danic, Thomas Schmitt
|
|
||||||
|
|
||||||
@mainpage Libburnia Documentation Index
|
|
||||||
|
|
||||||
@section intro Introduction
|
|
||||||
|
|
||||||
Libburnia is an open-source project for reading, mastering and writing
|
|
||||||
optical discs.
|
|
||||||
For now this means CD-R, CD-RW, DVD-RAM, DVD+RW, DVD+R, DVD+R/DL, DVD-RW,
|
|
||||||
DVD-R, BD-RE.
|
|
||||||
|
|
||||||
Not supported yet are DVD-R/DL, HD-DVD, BD-R (blue ray). Testers for
|
|
||||||
DVD-R/DL are wanted, though. BD-R programming efforts would be made
|
|
||||||
if an interested tester contacts us.
|
|
||||||
|
|
||||||
The project comprises of several more or less interdependent parts which
|
|
||||||
together strive to be a usable foundation for application development.
|
|
||||||
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.
|
|
||||||
|
|
||||||
@subsection components The project components (list subject to growth, hopefully):
|
|
||||||
|
|
||||||
- libburn is the library by which preformatted data get onto optical media.
|
|
||||||
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
|
|
||||||
/dev/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/BD capabilities, where only -sao is
|
|
||||||
compatible with cdrecord.
|
|
||||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
|
||||||
Many bytes have been copied from the message output of cdrecord
|
|
||||||
runs, though.
|
|
||||||
See cdrskin/README for more.
|
|
||||||
|
|
||||||
- xorriso is an application of all three libraries which creates, loads,
|
|
||||||
manipulates and writes ISO 9660 filesystem images with
|
|
||||||
Rock Ridge extensions. Manipulation is not only adding or
|
|
||||||
overwriting of files but also deletion, renaming, and attribute
|
|
||||||
changing. An incremental backup feature is provided.
|
|
||||||
See xorriso/README for more
|
|
||||||
|
|
||||||
- "test" is a collection of application gestures and examples given by the
|
|
||||||
authors of the library features. The burn API example of libburn
|
|
||||||
is named test/libburner.c . The API for media information inquiry is
|
|
||||||
demonstrated in test/telltoc.c .
|
|
||||||
Explore these examples if you look for inspiration.
|
|
||||||
|
|
||||||
We strive to be a responsive upstream.
|
|
||||||
|
|
||||||
Our libraries are committed to maintain older feature sets in newer versions.
|
|
||||||
This applies to source code headers (API) as well as to linkable objects (ABI).
|
|
||||||
The only exception from this rule is about non-release versions x.y.*[13579]
|
|
||||||
which are allowed to introduce new features, change those new features in
|
|
||||||
any way and even may revoke such new features before the next release of
|
|
||||||
x.y.*[02468]. As soon as it is released, a feature is promised to persist.
|
|
||||||
|
|
||||||
SONAMES:
|
|
||||||
libburn.so.4 (since 0.3.4, March 2007),
|
|
||||||
libisofs.so.6 (since 0.6.2, February 2008),
|
|
||||||
libisoburn.so.1 (since 0.1.0, February 2008).
|
|
||||||
|
|
||||||
|
|
||||||
@section using Using the libraries
|
|
||||||
|
|
||||||
Our build system is based on autotools.
|
|
||||||
User experience tells us that you will need at least autotools version 1.7.
|
|
||||||
|
|
||||||
To build libburn and its subprojects it should be sufficient to go into
|
|
||||||
its toplevel directory and execute
|
|
||||||
|
|
||||||
- ./bootstrap (needed if you downloaded from SVN)
|
|
||||||
|
|
||||||
- ./configure
|
|
||||||
|
|
||||||
- make
|
|
||||||
|
|
||||||
To make the libraries accessible for running resp. developing applications
|
|
||||||
|
|
||||||
- make install
|
|
||||||
|
|
||||||
Both libraries are written in C language and get built by autotools.
|
|
||||||
Thus we expect them to be useable by a wide range of Linux-implemented
|
|
||||||
languages and development tools.
|
|
||||||
|
|
||||||
|
|
||||||
@section libburner Libburner
|
|
||||||
|
|
||||||
libburner is a minimal demo application for the library libburn
|
|
||||||
(see: libburn/libburn.h) as provided on http://libburnia-project.org .
|
|
||||||
It can list the available devices, can blank a CD-RW or DVD-RW and
|
|
||||||
can burn to recordable CD and recordable single layer DVD.
|
|
||||||
|
|
||||||
It's main purpose, nevertheless, is to show you how to use libburn and also
|
|
||||||
to serve the libburnia team as reference application. libburner does indeed
|
|
||||||
define the standard way how above three gestures can be implemented and
|
|
||||||
stay upward compatible for a good while.
|
|
||||||
|
|
||||||
@subsection libburner-help Libburner --help
|
|
||||||
<pre>
|
|
||||||
Usage: test/libburner
|
|
||||||
[--drive <address>|<driveno>|"-"] [--audio]
|
|
||||||
[--blank_fast|--blank_full|--format_overwrite]
|
|
||||||
[--try_to_simulate]
|
|
||||||
[--multi] [<one or more imagefiles>|"-"]
|
|
||||||
Examples
|
|
||||||
A bus scan (needs rw-permissions to see a drive):
|
|
||||||
test/libburner --drive -
|
|
||||||
Burn a file to drive chosen by number, leave appendable:
|
|
||||||
test/libburner --drive 0 --multi my_image_file
|
|
||||||
Burn a file to drive chosen by persistent address, close:
|
|
||||||
test/libburner --drive /dev/hdc my_image_file
|
|
||||||
Blank a used CD-RW (is combinable with burning in one run):
|
|
||||||
test/libburner --drive /dev/hdc --blank_fast
|
|
||||||
Blank a used DVD-RW (is combinable with burning in one run):
|
|
||||||
test/libburner --drive /dev/hdc --blank_full
|
|
||||||
Format a DVD-RW to avoid need for blanking before re-use:
|
|
||||||
test/libburner --drive /dev/hdc --format_overwrite
|
|
||||||
Burn two audio tracks (to CD only):
|
|
||||||
lame --decode -t /path/to/track1.mp3 track1.cd
|
|
||||||
test/dewav /path/to/track2.wav -o track2.cd
|
|
||||||
test/libburner --drive /dev/hdc --audio track1.cd track2.cd
|
|
||||||
Burn a compressed afio archive on-the-fly:
|
|
||||||
( cd my_directory ; find . -print | afio -oZ - ) | \
|
|
||||||
test/libburner --drive /dev/hdc -
|
|
||||||
To be read from *not mounted* media via: afio -tvZ /dev/hdc
|
|
||||||
</pre>
|
|
||||||
libburner has two companions, telltoc and dewav, which help to perform some
|
|
||||||
peripheral tasks of burning.
|
|
||||||
|
|
||||||
telltoc prints a table of content (sessions, tracks and leadouts), it tells
|
|
||||||
about type and state of media, and also is able to provide the necessary
|
|
||||||
multi-session information for program mkisofs option -C. Especially helpful
|
|
||||||
are its predictions with "Write multi" and "Write modes" where availability
|
|
||||||
of "TAO" indicates that tracks of unpredicted length can be written.
|
|
||||||
See: test/telltoc --help.
|
|
||||||
|
|
||||||
dewav extracts raw byte-swapped audio data from files of format .wav (MS WAVE)
|
|
||||||
or .au (SUN Audio). See example in libburner --help.
|
|
||||||
|
|
||||||
@subsection libburner-source Sourceode of libburner
|
|
||||||
|
|
||||||
Click on blue names of functions, structures, variables, etc in oder to
|
|
||||||
get to the according specs of libburn API or libburner sourcecode.
|
|
||||||
|
|
||||||
@include libburner.c
|
|
||||||
*/
|
|
1201
doc/cookbook.txt
1201
doc/cookbook.txt
File diff suppressed because it is too large
Load Diff
388
doc/ddlp.txt
388
doc/ddlp.txt
@ -1,388 +0,0 @@
|
|||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Users of modern desktop Linux installations report misburns with CD/DVD
|
|
||||||
recording due to concurrency problems.
|
|
||||||
|
|
||||||
This text describes two locking protocols which have been developed by our
|
|
||||||
best possible effort. But finally they rather serve as repelling example of
|
|
||||||
what would be needed in user space to achieve an insufficient partial solution.
|
|
||||||
|
|
||||||
Ted Ts'o was so friendly to help as critic with his own use cases. It turned
|
|
||||||
out that we cannot imagine a way in user space how to cover reliably the needs
|
|
||||||
of callers of libblkid and the needs of our burn programs.
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
Content:
|
|
||||||
|
|
||||||
The "Delicate Device Locking Protocol" shall demonstrate our sincere
|
|
||||||
consideration of the problem.
|
|
||||||
|
|
||||||
"What are the Stumble Stones ?" lists reasons why the effort finally failed.
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
Delicate Device Locking Protocol
|
|
||||||
(a joint sub project of cdrkit and libburnia)
|
|
||||||
(contact: scdbackup@gmx.net )
|
|
||||||
|
|
||||||
Our projects provide programs which allow recording of data on CD or DVD.
|
|
||||||
We encounter an increasing number of bug reports about spoiled burn runs and
|
|
||||||
wasted media which obviously have one common cause: interference by other
|
|
||||||
programs which access the drive's device files.
|
|
||||||
There is some riddling about which gestures exactly are dangerous for
|
|
||||||
ongoing recordings or can cause weirdly misformatted drive replies to MMC
|
|
||||||
commands.
|
|
||||||
We do know, nevertheless, that these effects do not occur if no other program
|
|
||||||
accesses a device file of the drive while our programs use it.
|
|
||||||
|
|
||||||
DDLP shall help to avoid collisions between programs in the process of
|
|
||||||
recording to a CD or DVD drive and other programs which access that drive.
|
|
||||||
The protocol intends to provide advisory locking. So any good-willing program
|
|
||||||
has to take some extra precautions to participate.
|
|
||||||
|
|
||||||
If a program does not feel vulnerable to disturbance, then the precautions
|
|
||||||
impose much less effort than if the program feels the need for protection.
|
|
||||||
|
|
||||||
Two locking strategies are specified:
|
|
||||||
DDLP-A operates on device files only. It is very Linux specific.
|
|
||||||
DDLP-B adds proxy lock files, inspired by FHS /var/lock standard.
|
|
||||||
|
|
||||||
|
|
||||||
DDLP-A
|
|
||||||
|
|
||||||
This protocol relies on the hardly documented feature open(O_EXCL | O_RDWR)
|
|
||||||
with Linux device files and on POSIX compliant fcntl(F_SETLK).
|
|
||||||
|
|
||||||
Other than the original meaning of O_EXCL with creating regular files, the
|
|
||||||
effect on device files is mutual exclusion of access. I.e. if one
|
|
||||||
filedescriptor is open on that combination of major-minor device number, then
|
|
||||||
no other open(O_EXCL) will succeed. But open() without O_EXCL would succeed.
|
|
||||||
So this is advisory and exclusive locking.
|
|
||||||
With kernel 2.6 it seems to work on all device drivers which might get used
|
|
||||||
to access a CD/DVD drive.
|
|
||||||
|
|
||||||
The vulnerable programs shall not start their operation before they occupied a
|
|
||||||
wide collection of drive representations.
|
|
||||||
Non-vulnerable programs shall take care to detect the occupation of _one_ such
|
|
||||||
representation.
|
|
||||||
|
|
||||||
So for Friendly Programs
|
|
||||||
|
|
||||||
A program which does not feel vulnerable to disturbance is urged to access
|
|
||||||
CD/DVD drives by opening a file descriptor which will uphold the lock
|
|
||||||
as long as it does not get closed. There are two alternative ways to achieve
|
|
||||||
this.
|
|
||||||
Very reliable is
|
|
||||||
|
|
||||||
open( some_path , O_EXCL | ...)
|
|
||||||
|
|
||||||
But O_EXCL imposes restrictions and interferences:
|
|
||||||
- O_EXCL | O_RDONLY does not succeed with /dev/sg* !
|
|
||||||
- O_EXCL cannot provide shared locks for programs which only want to lock
|
|
||||||
against burn programs but not against their own peers.
|
|
||||||
- O_EXCL keeps from obtaining information by harmless activities.
|
|
||||||
- O_EXCL already has a meaning with devices which are mounted as filesystems.
|
|
||||||
This priority meaning is more liberal than the one needed for CD/DV recording
|
|
||||||
protection.
|
|
||||||
|
|
||||||
So it may be necessary to use a cautious open() without O_EXCL and to aquire
|
|
||||||
a POSIX lock via fcntl(). "Cautious" means to add O_NDELAY to the flags of
|
|
||||||
open(), because this is declared to avoid side effects within open().
|
|
||||||
|
|
||||||
With this gesture it is important to use the paths expected by our burn
|
|
||||||
programs: /dev/sr[0..255] /dev/scd[0..255] /dev/sg[0..255] /dev/hd[a..z]
|
|
||||||
because fcntl(F_SETLK) does not lock the device but only a device-inode.
|
|
||||||
|
|
||||||
std_path = one of the standard device files:
|
|
||||||
/dev/sr[0..255] /dev/scd[0..255] /dev/sg[0..255] /dev/hd[a..z]
|
|
||||||
or a symbolic link pointing to one of them.
|
|
||||||
open( std_path , ... | O_NDELAY)
|
|
||||||
fcntl(F_SETLK) and close() on failure
|
|
||||||
... eventually disable O_NDELAY by fcntl(F_SETFL) ...
|
|
||||||
|
|
||||||
There is a pitfall mentioned in man 2 fcntl :
|
|
||||||
"locks are automatically released [...] if it closes any file descriptor
|
|
||||||
referring to a file on which locks are held. This is bad [...]"
|
|
||||||
So you may have to re-lock after some temporary fd got closed.
|
|
||||||
|
|
||||||
|
|
||||||
Vulnerable Programs
|
|
||||||
|
|
||||||
For programs which do feel vulnerable, O_EXCL would suffice for the /dev/hd*
|
|
||||||
device file family and their driver. But USB and SATA recorders appear with
|
|
||||||
at least two different major-minor combinations simultaneously.
|
|
||||||
One as /dev/sr* alias /dev/scd*, the other as /dev/sg*.
|
|
||||||
The same is true for ide-scsi or recorders attached to SCSI controllers.
|
|
||||||
|
|
||||||
So, in order to lock any access to the recorder, one has to open(O_EXCL)
|
|
||||||
not only the device file that is intended for accessing the recorder but also
|
|
||||||
a device file of any other major-minor representation of the recorder.
|
|
||||||
This is done via the SCSI address parameter vector (Host,Channel,Id,Lun)
|
|
||||||
and a search on standard device file paths /dev/sr* /dev/scd* /dev/sg*.
|
|
||||||
In this text the alternative device representations are called "siblings".
|
|
||||||
|
|
||||||
For finding them, it is necessary to apply open() to many device files which
|
|
||||||
might be occupied by delicate operations. On the other hand it is very
|
|
||||||
important to occupy all reasonable representations of the drive.
|
|
||||||
So the reading of the (Host,Channel,Id,Lun) parameters demands an
|
|
||||||
open(O_RDONLY | O_NDELAY) _without_ fcntl() in order to find the outmost
|
|
||||||
number of representations among the standard device files. Only ioctls
|
|
||||||
SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER are applied.
|
|
||||||
Hopefully this gesture is unable to cause harmful side effects on kernel 2.6.
|
|
||||||
|
|
||||||
At least one file of each class sr, scd and sg should be found to regard
|
|
||||||
the occupation as satisfying. Thus corresponding sr-scd-sg triplets should have
|
|
||||||
matching ownerships and access permissions.
|
|
||||||
One will have to help the sysadmins to find those triplets.
|
|
||||||
|
|
||||||
A spicy detail is that sr and scd may be distinct device files for the same
|
|
||||||
major-minor combination. In this case fcntl() locks on both are needed
|
|
||||||
but O_EXCL can only be applied to one of them.
|
|
||||||
|
|
||||||
|
|
||||||
An open and free implementation ddlpa.[ch] is provided as
|
|
||||||
http://libburnia.pykix.org/browser/libburn/trunk/libburn/ddlpa.h?format=txt
|
|
||||||
http://libburnia.pykix.org/browser/libburn/trunk/libburn/ddlpa.c?format=txt
|
|
||||||
The current version of this text is
|
|
||||||
http://libburnia.pykix.org/browser/libburn/trunk/doc/ddlp.txt?format=txt
|
|
||||||
|
|
||||||
Put ddlpa.h and ddlpa.c into the same directory and compile as test program by
|
|
||||||
cc -g -Wall -DDDLPA_C_STANDALONE -o ddlpa ddlpa.c
|
|
||||||
|
|
||||||
Use it to occupy a drive's representations for a given number of seconds
|
|
||||||
./ddlpa /dev/sr0 300
|
|
||||||
|
|
||||||
It should do no harm to any of your running activities.
|
|
||||||
If it does: Please, please alert us.
|
|
||||||
|
|
||||||
Your own programs should not be able to circumvent the occupation if they
|
|
||||||
obey above rules for Friendly Programs.
|
|
||||||
Of course ./ddlpa should be unable to circumvent itself.
|
|
||||||
|
|
||||||
A successfull occupation looks like
|
|
||||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/scd0") = "/dev/sr0"
|
|
||||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sr0"
|
|
||||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/scd0"
|
|
||||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sg0"
|
|
||||||
DDLPA_DEBUG: ddlpa_occupy() : '/dev/scd0'
|
|
||||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/sg0'
|
|
||||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/sr0'
|
|
||||||
---------------------------------------------- Lock gained
|
|
||||||
ddlpa: opened /dev/sr0
|
|
||||||
ddlpa: opened siblings: /dev/scd0 /dev/sg0
|
|
||||||
slept 1 seconds of 300
|
|
||||||
|
|
||||||
Now an attempt via device file alias /dev/NEC must fail:
|
|
||||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/NEC") = "/dev/sg0"
|
|
||||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sr0"
|
|
||||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/scd0"
|
|
||||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sg0"
|
|
||||||
Cannot exclusively open '/dev/sg0'
|
|
||||||
Reason given : Failed to open O_RDWR | O_NDELAY | O_EXCL : '/dev/sr0'
|
|
||||||
Error condition : 16 'Device or resource busy'
|
|
||||||
|
|
||||||
With hdc, of course, things are trivial
|
|
||||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/hdc") = "/dev/hdc"
|
|
||||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/hdc'
|
|
||||||
---------------------------------------------- Lock gained
|
|
||||||
ddlpa: opened /dev/hdc
|
|
||||||
slept 1 seconds of 1
|
|
||||||
|
|
||||||
|
|
||||||
Ted Ts'o provided program open-cd-excl which allows to explore open(2) on
|
|
||||||
device files with combinations of read-write, O_EXCL, and fcntl().
|
|
||||||
(This does not mean that Ted endorsed our project yet. He helps exploring.)
|
|
||||||
|
|
||||||
Friendly in the sense of DDLP-A would be any run which uses at least one of
|
|
||||||
the options -e (i.e. O_EXCL) or -f (i.e. F_SETLK, applied to a file
|
|
||||||
descriptor which was obtained from a standard device file path).
|
|
||||||
The code is available under GPL at
|
|
||||||
http://libburnia.pykix.org/browser/libburn/trunk/test/open-cd-excl.c?format=txt
|
|
||||||
To be compiled by
|
|
||||||
cc -g -Wall -o open-cd-excl open-cd-excl.c
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-e : open O_EXCL
|
|
||||||
-f : aquire lock by fcntl(F_SETLK) after sucessful open
|
|
||||||
-i : do not wait in case of success but exit 0 immediately
|
|
||||||
-r : open O_RDONLY , with -f use F_RDLCK
|
|
||||||
-w : open O_RDWR , with -f use F_WRLCK
|
|
||||||
plus the path of the devce file to open.
|
|
||||||
|
|
||||||
Friendly Programs would use gestures like:
|
|
||||||
./open-cd-excl -e -r /dev/sr0
|
|
||||||
./open-cd-excl -e -w /dev/sg1
|
|
||||||
./open-cd-excl -e -w /dev/black-drive
|
|
||||||
./open-cd-excl -f -r /dev/sg1
|
|
||||||
./open-cd-excl -e -f -w /dev/sr0
|
|
||||||
|
|
||||||
Ignorant programs would use and cause potential trouble by:
|
|
||||||
./open-cd-excl -r /dev/sr0
|
|
||||||
./open-cd-excl -w /dev/sg1
|
|
||||||
./open-cd-excl -f -w /dev/black-drive
|
|
||||||
where "/dev/black-drive" is _not_ a symbolic link to
|
|
||||||
any of /dev/sr* /dev/scd* /dev/sg* /dev/hd*, but has an own inode.
|
|
||||||
|
|
||||||
Prone to failure without further reason is:
|
|
||||||
./open-cd-excl -e -r /dev/sg1
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
DDLP-B
|
|
||||||
|
|
||||||
This protocol relies on proxy lock files in some filesystem directory. It can
|
|
||||||
be embedded into DDLP-A or it can be used be used standalone, outside DDLP-A.
|
|
||||||
|
|
||||||
DDLP-A shall be kept by DDLP-B from trying to access any device file which
|
|
||||||
might already be in use. There is a problematic gesture in DDLP-A when SCSI
|
|
||||||
address parameters are to be retrieved. For now this gesture seems to be
|
|
||||||
harmless. But one never knows.
|
|
||||||
Vice versa DDLP-B may get from DDLP-A the service to search for SCSI device
|
|
||||||
file siblings. So they are best as a couple.
|
|
||||||
|
|
||||||
But they are not perfect. Not even as couple. fcntl() locking is flawed.
|
|
||||||
|
|
||||||
|
|
||||||
There is a proxy file locking protocol described in FHS:
|
|
||||||
http://www.pathname.com/fhs/pub/fhs-2.3.html#VARLOCKLOCKFILES
|
|
||||||
|
|
||||||
But it has shortcommings (see below). Decisive obstacle for its usage are the
|
|
||||||
possibility for stale locks and the lack of shared locks.
|
|
||||||
|
|
||||||
DDLP-B rather defines a "path prefix" which is advised to be
|
|
||||||
/tmp/ddlpb-lock-
|
|
||||||
This prefix will get appended "device specific suffixes" and then form the path
|
|
||||||
of a "lockfile".
|
|
||||||
Not the existence of a lockfile but its occupation by an fcntl(F_SETLK) will
|
|
||||||
constitute a lock. Lockfiles may get prepared by the sysadmin in directories
|
|
||||||
where normal users are not allowed to create new files. Their rw-permissions
|
|
||||||
then act as additional access restriction to the device files.
|
|
||||||
The use of fcntl(F_SETLK) will prevent any stale locks after the process ended.
|
|
||||||
It will also allow to obtain shared locks as well as exclusive locks.
|
|
||||||
|
|
||||||
There are two classes of device specific suffixes:
|
|
||||||
|
|
||||||
- Device file path suffix. Absolute paths only. "/" gets replaced by "_-".
|
|
||||||
Eventual "_-" in path gets replaced by "_-_-". The leading group of "_-"
|
|
||||||
is always interpreted as a group of "/", though. E.g.:
|
|
||||||
/dev/sr0 <-> "_-dev_-sr0"
|
|
||||||
/mydevs/burner/nec <-> "_-mydevs_-burners_-nec"
|
|
||||||
/dev/rare_-name <-> "_-dev_-rare_-_-name"
|
|
||||||
///strange/dev/x <-> "_-_-_-strange_-dev_-x"
|
|
||||||
|
|
||||||
- st_rdev suffix. A hex representation of struct stat.st_rdev. Capital letters.
|
|
||||||
The number of characters is pare with at most one leading 0. I.e. bytewise
|
|
||||||
printf("%2.2X") beginning with the highest order byte that is not zero.
|
|
||||||
E.g. : "0B01", "2200", "01000000000004001"
|
|
||||||
|
|
||||||
If a lockfile does not exist and cannot be created then this shall not keep
|
|
||||||
a program from working on a device. But if a lockfile exists and if permissions
|
|
||||||
or locking state do not allow to obtain a lock of the appropirate type, then
|
|
||||||
this shall prevent any opening of device file in question resp. shall cause
|
|
||||||
immediate close(2) of an already opened device file.
|
|
||||||
|
|
||||||
The vulnerable programs shall not start their operation before they locked a
|
|
||||||
wide collection of drive representations.
|
|
||||||
|
|
||||||
Non-vulnerable programs shall take care to lock the suffix resulting from the
|
|
||||||
path they will be using and the suffix from the st_rdev from that path.
|
|
||||||
The latter is to be obtained by call stat(2).
|
|
||||||
|
|
||||||
Locks get upheld as long as their file descriptor is not closed or no other
|
|
||||||
incident as described in man 2 fcntl releases the lock.
|
|
||||||
|
|
||||||
So with shared locks there are no imandatory further activities after they
|
|
||||||
have been obtained.
|
|
||||||
|
|
||||||
In case of exclusive locks, the file has to have been opened for writing and
|
|
||||||
must be truncated to 0 bytes length immediately after obtaining the lock.
|
|
||||||
When releasing an exclusive lock it is a nice gesture to
|
|
||||||
already do this truncation.
|
|
||||||
Then a /var/lock/ compatible first line has to be written.
|
|
||||||
E.g. by: printf("%10u\n",(unsigned) getpid()) yielding " 1230\n".
|
|
||||||
|
|
||||||
Any further lines are optional. They shall have the form Name=Value and must
|
|
||||||
be printable cleartext. If such further lines exist, then the last one must
|
|
||||||
have the name "endmark".
|
|
||||||
Defined Names are:
|
|
||||||
hostid =hostname of the machine where the process number of line 1 is valid
|
|
||||||
start =start time of lock in seconds since 1970. E.g: 1177147634.592410
|
|
||||||
program =self chosen name of the program which obtained the lock
|
|
||||||
argv0 =argv[0] of that program
|
|
||||||
mainpath =device file path which will be used for operations by that program
|
|
||||||
path =device file path which lead to the lock
|
|
||||||
st_rdev =st_rdev suffix which is associated with path
|
|
||||||
scsi_hcil=eventual SCSI parameters Host,Channel,Id,Lun
|
|
||||||
scsi_bus =eventual SCSI parameter Bus
|
|
||||||
endmark =declares the info as complete.
|
|
||||||
Any undefined name or a line without "=" shall be handled as comment.
|
|
||||||
"=" in the value is allowed. Any line beginning with an "=" character is an
|
|
||||||
extension of the previous value.
|
|
||||||
|
|
||||||
If programs encounter an exclusive lock, they are invited to read the content
|
|
||||||
of the lockfile anyway. But they should be aware that the info might be in the
|
|
||||||
progress of emerging. There is a race condition possible in the short time
|
|
||||||
between obtaining the exclusive lock and erasing the file content.
|
|
||||||
If it is not crucial to obtain most accurate info then one may take the newline
|
|
||||||
of the first line as indicator of a valid process number and the "endmark"
|
|
||||||
name as indicator that the preceding lines are valid.
|
|
||||||
Very cautious readers should obtain the info twice with a decent waiting period
|
|
||||||
inbetween. Only if both results are identical they should be considered valid.
|
|
||||||
|
|
||||||
|
|
||||||
There is no implementation of DDLP-B yet.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
What are the Stumble Stones ?
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Any of the considered locking mechanisms has decisive shortcommings
|
|
||||||
which keeps it from being the solution to all known legitimate use cases.
|
|
||||||
|
|
||||||
The attempt has failed to compose a waterproof locking mechanism from means of
|
|
||||||
POSIX, FHS and from hardly documented Linux open(O_EXCL) on device files.
|
|
||||||
The resulting mechanisms would need about 1000 lines of code and still do
|
|
||||||
not close all gaps resp. cover the well motivated use cases.
|
|
||||||
This attempt you see above: DDLP-A and DDLP-B.
|
|
||||||
|
|
||||||
|
|
||||||
Summary of the reasons why the established locking mechanisms do not suffice:
|
|
||||||
|
|
||||||
None of the mechanisms can take care of the double device driver identity
|
|
||||||
sr versus sg. To deduce the one device file from the other involves the need
|
|
||||||
to open many other (possibly unrelated) device files with the risk to disturb
|
|
||||||
them.
|
|
||||||
This hard to solve problem is aggravated by the following facts.
|
|
||||||
|
|
||||||
Shortcommings of Linux specific open(O_EXCL) :
|
|
||||||
|
|
||||||
- O_EXCL | O_RDONLY does not succeed with /dev/sg*
|
|
||||||
- O_EXCL cannot provide shared locks for programs which only want to lock
|
|
||||||
against burn programs but not against their own peers.
|
|
||||||
- O_EXCL keeps from obtaining information by harmless activities.
|
|
||||||
- O_EXCL already has a meaning with devices which are mounted as filesystems.
|
|
||||||
This priority meaning is more liberal than the one needed for CD/DV recording
|
|
||||||
protection.
|
|
||||||
|
|
||||||
Shortcommings of POSIX fcntl(F_SETLK) :
|
|
||||||
|
|
||||||
- fcntl() demands an open file descriptor. open(2) might have side effects.
|
|
||||||
- fcntl() locks can be released inadvertedly by submodules which just open and
|
|
||||||
close the same file (inode ?) without refering to fcntl locks in any way.
|
|
||||||
See man 2 fcntl "This is bad:".
|
|
||||||
Stacking of software modules is a widely used design pattern. But fcntl()
|
|
||||||
cannot cope with that.
|
|
||||||
|
|
||||||
Shortcommings of FHS /var/lock/ :
|
|
||||||
|
|
||||||
- Stale locks are possible.
|
|
||||||
- It is necessary to create a file (using the _old_ meaning of O_EXCL flag ?)
|
|
||||||
but /var/lock/ might not be available early during system start and it often
|
|
||||||
has restrictive permission settings.
|
|
||||||
- There is no way to indicate a difference between exclusive and shared locks.
|
|
||||||
- The FHS prescription relies entirely on the basename of the device file path.
|
|
||||||
|
|
1300
doc/doxygen.conf.in
1300
doc/doxygen.conf.in
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
|||||||
prefix=@prefix@
|
|
||||||
exec_prefix=@exec_prefix@
|
|
||||||
libdir=@libdir@
|
|
||||||
includedir=@includedir@
|
|
||||||
|
|
||||||
Name: libburn
|
|
||||||
Description: Library to read/write optical discs
|
|
||||||
Version: @VERSION@
|
|
||||||
Requires:
|
|
||||||
Libs: -L${libdir} -lburn
|
|
||||||
Libs.private: @THREAD_LIBS@ @LIBBURN_ARCH_LIBS@
|
|
||||||
Cflags: -I${includedir}/libburn
|
|
@ -1,4 +0,0 @@
|
|||||||
all clean:
|
|
||||||
$(MAKE) -C .. -$(MAKEFLAGS) $@
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
@ -1,65 +0,0 @@
|
|||||||
pkgconfigdir=$(libdir)/pkgconfig
|
|
||||||
libincludedir=$(includedir)/libburn
|
|
||||||
|
|
||||||
lib_LTLIBRARIES = libburn.la
|
|
||||||
|
|
||||||
libburn_la_SOURCES = \
|
|
||||||
async.c \
|
|
||||||
async.h \
|
|
||||||
crc.c \
|
|
||||||
crc.h \
|
|
||||||
debug.c \
|
|
||||||
debug.h \
|
|
||||||
drive.c \
|
|
||||||
drive.h \
|
|
||||||
file.c \
|
|
||||||
file.h \
|
|
||||||
init.c \
|
|
||||||
init.h \
|
|
||||||
lec.c \
|
|
||||||
lec.h \
|
|
||||||
message.c \
|
|
||||||
message.h \
|
|
||||||
mmc.c \
|
|
||||||
mmc.h \
|
|
||||||
null.c \
|
|
||||||
null.h \
|
|
||||||
options.c \
|
|
||||||
options.h \
|
|
||||||
read.c \
|
|
||||||
read.h \
|
|
||||||
sbc.c \
|
|
||||||
sbc.h \
|
|
||||||
sector.c \
|
|
||||||
sector.h \
|
|
||||||
sg.c \
|
|
||||||
sg.h \
|
|
||||||
spc.c \
|
|
||||||
spc.h \
|
|
||||||
source.h \
|
|
||||||
source.c \
|
|
||||||
structure.c \
|
|
||||||
structure.h \
|
|
||||||
toc.c \
|
|
||||||
toc.h \
|
|
||||||
transport.h \
|
|
||||||
util.c \
|
|
||||||
util.h \
|
|
||||||
write.c \
|
|
||||||
write.h
|
|
||||||
|
|
||||||
libinclude_HEADERS = libburn.h
|
|
||||||
|
|
||||||
## ========================================================================= ##
|
|
||||||
indent_files = $(libburn_la_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
|
|
||||||
|
|
||||||
## ========================================================================= ##
|
|
@ -1,792 +0,0 @@
|
|||||||
List of assert() calls in libburn. 6 Oct 2006.
|
|
||||||
|
|
||||||
Format:
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Number) grep'ed line
|
|
||||||
(++ before number means: is fully done, + means is done so far )
|
|
||||||
function():
|
|
||||||
Description of abort condition.
|
|
||||||
|
|
||||||
Possible callers and their relation to the abort condition.
|
|
||||||
|
|
||||||
: Error Evaluation
|
|
||||||
=> Consequences
|
|
||||||
|
|
||||||
Eventual implementation timestamp
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 1) libburn/async.c: assert(a != NULL); /* wasn't found.. this should not be possible */
|
|
||||||
static remove_worker():
|
|
||||||
A thread describing structure (struct w_list) could not be found in
|
|
||||||
order to be released.
|
|
||||||
|
|
||||||
Called by API burn_drive_scan()
|
|
||||||
Called by static erase_worker_func() , thread under API burn_disc_erase()
|
|
||||||
Called by static write_disc_worker_func(), thread under API burn_disc_write()
|
|
||||||
All three want to clean up after they are done.
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> issue LIBDAX_MSGS_SEV_WARNING
|
|
||||||
|
|
||||||
ts A61006
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 2) libburn/async.c: assert(!(workers && workers->drive));
|
|
||||||
API burn_drive_scan():
|
|
||||||
Before spawning a thread, the function refuses work because another
|
|
||||||
drive activity is going on.
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> return -1; redefine @return in API , issue LIBDAX_MSGS_SEV_SORRY
|
|
||||||
|
|
||||||
ts A61006
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
+ 3) libburn/async.c: assert(workers == NULL);
|
|
||||||
API burn_drive_scan():
|
|
||||||
After thread is done and remover_worker() succeeded, there is still a
|
|
||||||
worker registered. Shall probably detect roguely appeared burn or
|
|
||||||
erase runs. (I consider to install a mutex shielded function for that.)
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> Same as 1)
|
|
||||||
|
|
||||||
ts A61006
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 4) libburn/async.c: assert(drive);
|
|
||||||
libburn/async.c: assert(!SCAN_GOING());
|
|
||||||
libburn/async.c: assert(!find_worker(drive));
|
|
||||||
API burn_disc_erase():
|
|
||||||
Wants to see a drive (assumes NULL == 0), wants to see no scan and
|
|
||||||
wants to see no other worker on that drive. I.e. this would tolerate
|
|
||||||
a parallel activity on another drive.
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> (no return value), issue LIBDAX_MSGS_SEV_SORRY
|
|
||||||
|
|
||||||
ts A61006
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 5) libburn/async.c: assert(!SCAN_GOING());
|
|
||||||
libburn/async.c: assert(!find_worker(opts->drive));
|
|
||||||
API burn_disc_write():
|
|
||||||
Same as 4)
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> Same as 4)
|
|
||||||
|
|
||||||
ts A61006
|
|
||||||
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 6) libburn/drive.c: assert(d->busy == BURN_DRIVE_IDLE);
|
|
||||||
API burn_drive_release():
|
|
||||||
A drive is not idle on release.
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> Same as 4)
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 7) libburn/drive.c: assert(d->released);
|
|
||||||
burn_wait_all()
|
|
||||||
A drive is found grabbed.
|
|
||||||
|
|
||||||
Called by burn_drive_scan_sync(), thread under API burn_drive_scan()
|
|
||||||
Called by API burn_finish
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> rename and redefine burn_wait_all() : now burn_drives_are_clear()
|
|
||||||
=> change all use of burn_wait_all()
|
|
||||||
=> Move tests up to burn_drive_scan()
|
|
||||||
=> There: return -1; issue LIBDAX_MSGS_SEV_SORRY
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 8) libburn/drive.c: assert(!d->released);
|
|
||||||
API burn_disc_get_status()
|
|
||||||
Attempt to read status of non-grabbed drive.
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> extend enum burn_disc_status by BURN_DISC_UNGRABBED
|
|
||||||
=> return BURN_DISC_UNGRABBED, issue LIBDAX_MSGS_SEV_SORRY
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 9) libburn/drive.c: assert( /* (write_type >= BURN_WRITE_PACKET) && */
|
|
||||||
burn_drive_get_block_types():
|
|
||||||
Will not work on BURN_WRITE below BURN_WRITE_RAW.
|
|
||||||
|
|
||||||
Called by -nobody- ?
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> inactivate unused function
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 10) libburn/drive.c: assert(d->idata);
|
|
||||||
libburn/drive.c: assert(d->mdata);
|
|
||||||
static drive_getcaps():
|
|
||||||
sg.c:enumerate_common() did not succeed in creating a proper struct burn_drive
|
|
||||||
Called by burn_drive_scan_sync()
|
|
||||||
|
|
||||||
: Severe System Error
|
|
||||||
=> This could possibly really stay an abort() because the reason is
|
|
||||||
a plain failure of the system's memory management.
|
|
||||||
=> Detect this failure already in enumerate_common(),
|
|
||||||
issue LIBDAX_MSGS_SEV_FATAL, return
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 11) libburn/drive.c: assert(burn_running);
|
|
||||||
burn_drive_scan_sync():
|
|
||||||
The library was not initialized.
|
|
||||||
|
|
||||||
Called as thread by API burn_drive_scan()
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> Move this test up to burn_drive_scan()
|
|
||||||
=> There: return -1; redefine @return in API , issue LIBDAX_MSGS_SEV_FATAL
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 12) libburn/drive.c: assert(d->released == 1);
|
|
||||||
burn_drive_scan_sync():
|
|
||||||
Inactivated
|
|
||||||
|
|
||||||
: (Severe Application Error)
|
|
||||||
=> throw out inactivated code
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 13) libburn/drive.c: assert(strlen(d->devname) < BURN_DRIVE_ADR_LEN);
|
|
||||||
burn_drive_raw_get_adr():
|
|
||||||
An enumerated device address is longer than the API's maximum length
|
|
||||||
|
|
||||||
Called by API burn_drive_get_adr()
|
|
||||||
Called by API burn_drive_obtain_scsi_adr()
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> return -1; in all three functions, enhance burn_drive_get_adr @return docs
|
|
||||||
=> issue LIBDAX_MSGS_SEV_SORRY
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 14) libburn/drive.c: assert(drive_info->drive!=NULL);
|
|
||||||
API burn_drive_get_adr():
|
|
||||||
Drive info has no drive attached.
|
|
||||||
|
|
||||||
: Severe Libburn Error (unlikely, will eventually SIGSEGV on NULL)
|
|
||||||
=> delete assert
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 15) libburn/init.c: assert(burn_running);
|
|
||||||
API burn_finish():
|
|
||||||
The library is not initialized
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> return (assume no msg system)
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 16) libburn/init.c: assert(burn_running);
|
|
||||||
API burn_preset_device_open():
|
|
||||||
The library is not initialized
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> return (assume no msg system)
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 17) libburn/mmc.c: assert(o->drive == d);
|
|
||||||
mmc_close_disc():
|
|
||||||
alias: struct burn_drive.close_disc()
|
|
||||||
Parameters struct burn_drive and struct burn_write_opts do not match
|
|
||||||
|
|
||||||
Called by -nobody- ?
|
|
||||||
|
|
||||||
( => Disable unused function ? )
|
|
||||||
=> removed redundant parameter struct burn_drive
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 18) libburn/mmc.c: assert(o->drive == d);
|
|
||||||
mmc_close_session():
|
|
||||||
Same as 17)
|
|
||||||
alias: struct burn_drive.close_session()
|
|
||||||
|
|
||||||
Called by -nobody- ?
|
|
||||||
|
|
||||||
( => Disable unused function ? )
|
|
||||||
=> removed redundant parameter struct burn_drive
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 19) libburn/mmc.c: assert(buf->bytes >= buf->sectors); /* can be == at 0... */
|
|
||||||
mmc_write_12():
|
|
||||||
- Unclear what .bytes and .sectors mean in struct buffer -
|
|
||||||
|
|
||||||
Called by -nobody- ?
|
|
||||||
|
|
||||||
=> problems with filling the write buffer have to be handled by callers
|
|
||||||
=> delete assert
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 20) libburn/mmc.c: assert(buf->bytes >= buf->sectors); /* can be == at 0... */
|
|
||||||
mmc_write():
|
|
||||||
- Unclear what .bytes and .sectors mean in struct buffer -
|
|
||||||
|
|
||||||
libburn/mmc.c: c.page->sectors = errorblock - start + 1;
|
|
||||||
mmc_read_sectors() by toc_find_modes() by mmc_read_toc() alias drive.read_toc()
|
|
||||||
by burn_drive_grab()
|
|
||||||
This seems to be unrelated to mmc_write().
|
|
||||||
|
|
||||||
libburn/sector.c: out->sectors++;
|
|
||||||
get_sector()
|
|
||||||
Seems to hand out sector start pointer in opts->drive->buffer
|
|
||||||
and to count reservation transactions as well as reserved bytes.
|
|
||||||
Ensures out->bytes >= out->sectors
|
|
||||||
|
|
||||||
|
|
||||||
libburn/mmc.c: c.page->bytes = s->count * 8;
|
|
||||||
mmc_send_cue_sheet()
|
|
||||||
Does not use mmc_write() but directly (sg_)issue_command()
|
|
||||||
|
|
||||||
libburn/sector.c: out->bytes += seclen;
|
|
||||||
get_sector()
|
|
||||||
See above
|
|
||||||
Ensures out->bytes >= out->sectors
|
|
||||||
|
|
||||||
libburn/spc.c: c.page->bytes = 8 + 2 + d->mdata->retry_page_length;
|
|
||||||
spc_select_error_params()
|
|
||||||
Does not use mmc_write() but directly (sg_)issue_command()
|
|
||||||
|
|
||||||
libburn/spc.c: c.page->bytes = 8 + 2 + d->mdata->write_page_length;
|
|
||||||
spc_select_error_params()
|
|
||||||
Does not use mmc_write() but directly (sg_)issue_command()
|
|
||||||
|
|
||||||
libburn/spc.c: c.page->bytes = 8 + 2 + 0x32;
|
|
||||||
spc_probe_write_modes()
|
|
||||||
Does not use mmc_write() but directly (sg_)issue_command()
|
|
||||||
|
|
||||||
alias struct burn_drive.write()
|
|
||||||
Called by static get_sector, by many
|
|
||||||
Called by burn_write_flush
|
|
||||||
Called by burn_write_track
|
|
||||||
|
|
||||||
=> problems with filling the write buffer have to be handled by callers
|
|
||||||
=> delete assert
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 21) libburn/mmc.c: assert(((dlen - 2) % 11) == 0);
|
|
||||||
mmc_read_toc():
|
|
||||||
- Is defunct -
|
|
||||||
|
|
||||||
=> :)
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 22) libburn/mmc.c: assert(len >= 0);
|
|
||||||
mmc_read_sectors():
|
|
||||||
Catches a bad parameter
|
|
||||||
|
|
||||||
alias: struct burn_drive.read_sectors()
|
|
||||||
Called by API burn_disc_read() , - is defunct -, one could catch the problem
|
|
||||||
Called by toc_find_modes(), problem cannot occur: mem.sectors = 1;
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
(=> in burn_disc_read() check page.sectors before d->read_sectors() )
|
|
||||||
=> :)
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 23) libburn/mmc.c: assert(d->busy);
|
|
||||||
mmc_read_sectors():
|
|
||||||
Catches use of a drive that is not marked as busy
|
|
||||||
|
|
||||||
alias: struct burn_drive.read_sectors()
|
|
||||||
Called by API burn_disc_read() , - is defunct -, busy = BURN_DRIVE_READING;
|
|
||||||
Called by toc_find_modes(), does the same assert. To be solved there.
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> :)
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 24) libburn/options.c: assert(0);
|
|
||||||
API burn_write_opts_set_write_type():
|
|
||||||
Detects unsuitable enum burn_write_types write_type and int block_type.
|
|
||||||
API promises return 0 on failure
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> issue LIBDAX_MSGS_SEV_SORRY
|
|
||||||
=> should also detect problem of 26) : wrong write_type,block_type combination
|
|
||||||
by calling sector_get_outmode() and checking for -1
|
|
||||||
=> should also detect problem of 41) : unknown block_type
|
|
||||||
by spc_block_type() and checking for -1
|
|
||||||
=> delete assert(0)
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 25) libburn/read.c: assert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));
|
|
||||||
libburn/read.c: assert(!d->busy);
|
|
||||||
libburn/read.c: assert(d->toc->valid);
|
|
||||||
libburn/read.c: assert(o->datafd != -1);
|
|
||||||
API burn_disc_read():
|
|
||||||
- ? -
|
|
||||||
|
|
||||||
burn_disc_read() is defunct
|
|
||||||
OPTIONS_VERSION does not occur outside this line
|
|
||||||
|
|
||||||
( => one would return )
|
|
||||||
( 22) => catch page.sectors<0 before d->read_sectors() )
|
|
||||||
( 37) => catch ! d->mdata->valid )
|
|
||||||
=> :)
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 26) libburn/sector.c: assert(0); /* return BURN_MODE_UNIMPLEMENTED :) */
|
|
||||||
static get_outmode():
|
|
||||||
burn_write_opts is wrongly programmed with .write_type and .block_type
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> This gets handled by burn_write_opts_set_write_type()
|
|
||||||
ts A61007 by new semi-public sector_get_outmode()
|
|
||||||
=> delete assert()
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 27) libburn/sector.c: assert(outlen >= inlen);
|
|
||||||
libburn/sector.c: assert(outmode & BURN_MODE_RAW);
|
|
||||||
libburn/sector.c: assert(offset != -1);
|
|
||||||
static convert_data():
|
|
||||||
Several unacceptable settings within struct burn_write_opts
|
|
||||||
|
|
||||||
Called by sector_toc() sector_pregap() sector_postgap() sector_lout()
|
|
||||||
sector_data()
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> change return type of convert_data()
|
|
||||||
=> all callers interpret return value and eventually return failure
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 28) libburn/sector.c: assert(0);
|
|
||||||
static char_to_isrc():
|
|
||||||
Called by subcode_user() with data set by API burn_track_set_isrc()
|
|
||||||
Some character conversion fails on wrong input
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> burn_track_set_isrc() has to make sure that only good data are set
|
|
||||||
=> char_to_isrc() returns 0 as default
|
|
||||||
=> delete assert()
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 29) libburn/sector.c: assert(qmode == 1 || qmode == 2 || qmode == 3);
|
|
||||||
subcode_user():
|
|
||||||
- can not happen -
|
|
||||||
|
|
||||||
: Unknown reason of assert()
|
|
||||||
=> remove assert()
|
|
||||||
|
|
||||||
ts A61010
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 30) libburn/sector.c: assert(modebyte == 1);
|
|
||||||
sector_headers():
|
|
||||||
Does only accept modes BURN_AUDIO, BURN_MODE1 or write_type BURN_WRITE_SAO
|
|
||||||
|
|
||||||
Called by sector_toc() sector_pregap() sector_postgap() sector_lout()
|
|
||||||
sector_data()
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> new functions sector_headers_is_ok(), burn_disc_write_is_ok()
|
|
||||||
help to catch problem in API burn_disc_write()
|
|
||||||
=> issue LIBDAX_MSGS_SEV_FATAL
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 31) libburn/sector.c: assert(0);
|
|
||||||
process_q()
|
|
||||||
- defunct -
|
|
||||||
|
|
||||||
=> :)
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 32) libburn/sg.c: assert("drive busy" == "non fatal");
|
|
||||||
sg_handle_busy_device():
|
|
||||||
Intentional abort preset by the app
|
|
||||||
|
|
||||||
=> change to abort()
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 33) libburn/sg.c: assert(fd != -1337);
|
|
||||||
sg_grab():
|
|
||||||
The drive device file could not be opened
|
|
||||||
|
|
||||||
:Severe External Problem
|
|
||||||
=> obsolete by normal drive open failure handling
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 34) libburn/sg.c: assert(!c->page);
|
|
||||||
sg_issue_command():
|
|
||||||
An SCSI command of direction NO_TRANSFER may not have a .page != NULL.
|
|
||||||
|
|
||||||
Since it is about exposing a libburn detail towards the sg driver, i believe
|
|
||||||
it is sufficient to just not use it.
|
|
||||||
|
|
||||||
: Libburn Error
|
|
||||||
=> enhance internal logics of sg_issue_command()
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 35) libburn/sg.c: assert(c->page->bytes > 0);
|
|
||||||
sg_issue_command():
|
|
||||||
An SCSI command of direction TO_DRIVE wants to transfer 0 bytes.
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> set command.error = 1 and return 0
|
|
||||||
|
|
||||||
ts A61010
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 36) libburn/sg.c: assert(err != -1);
|
|
||||||
sg_issue_command():
|
|
||||||
The transfer of the command via ioctl() failed
|
|
||||||
|
|
||||||
: Severe Transport Level Problem
|
|
||||||
=> close drive fd, set idle and released
|
|
||||||
=> set command.error = 1 and return -1
|
|
||||||
|
|
||||||
ts A61010
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 37) libburn/spc.c: assert(d->mdata->valid);
|
|
||||||
spc_select_error_params():
|
|
||||||
Drive was not properly programmed
|
|
||||||
|
|
||||||
alias struct burn_drive.send_parameters()
|
|
||||||
Called by burn_disc_read, - defunct -
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> moved up as mangled assert to burn_disc_read()
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 38) libburn/spc.c: assert(d->mdata->cdr_write || d->mdata->cdrw_write ||
|
|
||||||
spc_sense_write_params():
|
|
||||||
Drive does not offer write of any known media type
|
|
||||||
|
|
||||||
alias struct burn_drive.read_disc_info()
|
|
||||||
Called by API burn_drive_grab (assert test made there in soft)
|
|
||||||
|
|
||||||
: Severe Command Level Problem
|
|
||||||
=> remove assert()
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 39) libburn/spc.c: assert(o->drive == d);
|
|
||||||
spc_select_write_params():
|
|
||||||
Drive does not match struct burn_write_opts
|
|
||||||
|
|
||||||
alias struct burn_drive.send_write_parameters()
|
|
||||||
Called by mmc_close_disc() (-defunct- ?), mmc_close_session() (-defunct- ?),
|
|
||||||
burn_write_track() (d = o->drive;),
|
|
||||||
burn_disc_write_sync() d = (o->drive;)
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> remove assert()
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 40) libburn/spc.c: assert(d->mdata->valid);
|
|
||||||
spc_select_write_params():
|
|
||||||
Drive was not properly programmed
|
|
||||||
|
|
||||||
Called by (see 39)
|
|
||||||
burn_write_track() by burn_write_session() by burn_disc_write_sync()
|
|
||||||
burn_disc_write_sync() indirectly by API burn_disc_write()
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> caught in burn_disc_write() now
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 41) libburn/spc.c: assert(0);
|
|
||||||
spc_block_type():
|
|
||||||
Unknown value with enum burn_block_types
|
|
||||||
|
|
||||||
Called by spc_select_write_params, uses burn_write_opts.block_type,
|
|
||||||
set by API burn_write_opts_set_write_type()
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> catch in API burn_write_opts_set_write_type
|
|
||||||
by calling spc_block_type()
|
|
||||||
=> delete assert
|
|
||||||
|
|
||||||
ts A61007
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 42) libburn/structure.c: assert(!(pos > BURN_POS_END));\
|
|
||||||
macro RESIZE
|
|
||||||
An illegal list index is given by the app.
|
|
||||||
|
|
||||||
( TO->NEW##s obviusly means to append "s" to cpp result of TO->NEW )
|
|
||||||
Used by API burn_session_add_track() and API burn_disc_add_session()
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> replace assert by if-and-return-0
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 43) libburn/structure.c: assert(s->track != NULL);
|
|
||||||
API burn_session_remove_track()
|
|
||||||
An application supplied pointer is NULL
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> replace by if-and-return-0
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 44) libburn/structure.c: assert((country[i] >= '0' || country[i] < '9') &&
|
|
||||||
libburn/structure.c: assert((owner[i] >= '0' || owner[i] < '9') &&
|
|
||||||
libburn/structure.c: assert(year <= 99);
|
|
||||||
libburn/structure.c: assert(serial <= 99999);
|
|
||||||
API burn_track_set_isrc():
|
|
||||||
Illegal texts supplied by application.
|
|
||||||
The logical expression is always true !
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> issue LIBDAX_MSGS_SEV_SORRY and return
|
|
||||||
=> delete assert
|
|
||||||
=> delete assert 28) in char_to_isrc()
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 45) libburn/toc.c: assert(0); /* unhandled! find out ccd's
|
|
||||||
static write_clonecd2():
|
|
||||||
|
|
||||||
- defunct -, - unused -
|
|
||||||
|
|
||||||
=> mangle assert
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 46) libburn/toc.c: assert(d->busy);
|
|
||||||
toc_find_modes():
|
|
||||||
The drive to work on is not marked busy
|
|
||||||
|
|
||||||
Called by mmc_read_toc() alias read_toc() by ... burn_drive_grab()
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> to be prevented on the higher levels
|
|
||||||
=> delete assert
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 47) libburn/util.c: assert(s);
|
|
||||||
burn_strdup()
|
|
||||||
Abort on NULL string which would elsewise cause a SIGSEGV
|
|
||||||
|
|
||||||
Used once in enumerate_common() with a string that worked with open(2) before
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> delete assert
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 48) libburn/util.c: assert(s);
|
|
||||||
burn_strndup(): - unused -
|
|
||||||
Same as 47
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> return NULL
|
|
||||||
=> delete assert
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 49) libburn/util.c: assert(n > 0);
|
|
||||||
burn_strndup(): - unused -
|
|
||||||
Prevent problems by negative copy length
|
|
||||||
|
|
||||||
: Severe Libburn Error
|
|
||||||
=> return NULL
|
|
||||||
=> delete assert
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 50) libburn/write.c: assert(0);
|
|
||||||
static type_to_ctrl():
|
|
||||||
Unsuitable mode to be converted into "ctrl"
|
|
||||||
Called by static type_to_form() finally burn_create_toc_entries()
|
|
||||||
|
|
||||||
: Severe Application Error
|
|
||||||
=> to be caught in burn_track_define_data by calling for test type_to_form()
|
|
||||||
=> return -1;
|
|
||||||
|
|
||||||
ts A61008
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 51) libburn/write.c: assert(0);
|
|
||||||
libburn/write.c: assert(0); /* XXX someone's gonna want this sometime */
|
|
||||||
static type_to_form():
|
|
||||||
Does not like BURN_MODE0 or BURN_MODE2 but tolerates unknown modes
|
|
||||||
|
|
||||||
Called by static burn_create_toc_entries() by burn_disc_write_sync()
|
|
||||||
|
|
||||||
: Undocumented Libburn Restriction
|
|
||||||
=> set *form = -1 , *ctladr = 0xff , return
|
|
||||||
=> make function non-static
|
|
||||||
=> call for test in API burn_track_define_data()
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 52) libburn/write.c: assert(ptr);
|
|
||||||
static add_cue():
|
|
||||||
realloc() failed
|
|
||||||
|
|
||||||
Called by burn_create_toc_entries() by burn_disc_write_sync()
|
|
||||||
(burn_create_toc_entries is ignorant towards own potential memory problems)
|
|
||||||
(This could possibly really stay an abort() because the reason is
|
|
||||||
a plain failure of the system's memory management.)
|
|
||||||
|
|
||||||
: Severe System Error
|
|
||||||
=> change return type of add_cue to int
|
|
||||||
=> react on return -1 in burn_create_toc_entries, return NULL on failure
|
|
||||||
=> abort burn_disc_write_sync() on NULL return
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 53) libburn/write.c: assert(d->toc_entry == NULL);
|
|
||||||
burn_create_toc_entries():
|
|
||||||
Multiple usage of struct burn_drive.toc_entry
|
|
||||||
|
|
||||||
Called by burn_disc_write_sync()
|
|
||||||
This will probably trigger an abort with disc->sessions > 1
|
|
||||||
(disc->sessions is incremented in macro RESIZE() as "NEW##s")
|
|
||||||
|
|
||||||
: Design Problem
|
|
||||||
( => ? disallow multiple sessions ? )
|
|
||||||
=> replace assert by soft means and wait what happens
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
++ 54) libburn/write.c: assert(0);
|
|
||||||
burn_sector_length():
|
|
||||||
Only BURN_AUDIO, BURN_MODE_RAW, BURN_MODE1 are allowed
|
|
||||||
|
|
||||||
Called by get_sector(), convert_data(), ...
|
|
||||||
|
|
||||||
=> call burn_sector_length() for test in API burn_track_define_data()
|
|
||||||
=> replace assert by -1
|
|
||||||
|
|
||||||
ts A61009
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
545
libburn/async.c
545
libburn/async.c
@ -1,545 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A71019 */
|
|
||||||
|
|
||||||
/* Standard measure should be: Threads are created detached.
|
|
||||||
According to the man pages they should then care for disposing themselves.
|
|
||||||
|
|
||||||
>>> ??? It is yet unclear why the threads vanish from the process list
|
|
||||||
even if joinable and even if never joined.
|
|
||||||
|
|
||||||
To be activated after release of libburn-0.4.0
|
|
||||||
*/
|
|
||||||
#define Libburn_create_detached_threadS 1
|
|
||||||
|
|
||||||
/* Alternative : Threads are created joinable.
|
|
||||||
Threads get detached in remove_worker() and thus should dispose themselves.
|
|
||||||
|
|
||||||
#define Libburn_detach_done_workeR 1
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "transport.h"
|
|
||||||
#include "drive.h"
|
|
||||||
#include "write.h"
|
|
||||||
#include "options.h"
|
|
||||||
#include "async.h"
|
|
||||||
#include "init.h"
|
|
||||||
#include "file.h"
|
|
||||||
#include "back_hacks.h"
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <a ssert.h>
|
|
||||||
*/
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
#define SCAN_GOING() (workers && !workers->drive)
|
|
||||||
|
|
||||||
typedef void *(*WorkerFunc) (void *);
|
|
||||||
|
|
||||||
struct scan_opts
|
|
||||||
{
|
|
||||||
struct burn_drive_info **drives;
|
|
||||||
unsigned int *n_drives;
|
|
||||||
|
|
||||||
int done;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct erase_opts
|
|
||||||
{
|
|
||||||
struct burn_drive *drive;
|
|
||||||
int fast;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ts A61230 */
|
|
||||||
struct format_opts
|
|
||||||
{
|
|
||||||
struct burn_drive *drive;
|
|
||||||
off_t size;
|
|
||||||
int flag;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct write_opts
|
|
||||||
{
|
|
||||||
struct burn_drive *drive;
|
|
||||||
struct burn_write_opts *opts;
|
|
||||||
struct burn_disc *disc;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fifo_opts
|
|
||||||
{
|
|
||||||
struct burn_source *source;
|
|
||||||
int flag;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct w_list
|
|
||||||
{
|
|
||||||
struct burn_drive *drive;
|
|
||||||
pthread_t thread;
|
|
||||||
|
|
||||||
struct w_list *next;
|
|
||||||
|
|
||||||
union w_list_data
|
|
||||||
{
|
|
||||||
struct scan_opts scan;
|
|
||||||
struct erase_opts erase;
|
|
||||||
struct format_opts format;
|
|
||||||
struct write_opts write;
|
|
||||||
struct fifo_opts fifo;
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct w_list *workers = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
static struct w_list *find_worker(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct w_list *a;
|
|
||||||
|
|
||||||
for (a = workers; a; a = a->next)
|
|
||||||
if (a->drive == d)
|
|
||||||
return a;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_worker(struct burn_drive *d, WorkerFunc f, void *data)
|
|
||||||
{
|
|
||||||
struct w_list *a;
|
|
||||||
struct w_list *tmp;
|
|
||||||
pthread_attr_t *attr_pt = NULL;
|
|
||||||
|
|
||||||
#ifdef Libburn_create_detached_threadS
|
|
||||||
pthread_attr_t attr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
a = malloc(sizeof(struct w_list));
|
|
||||||
a->drive = d;
|
|
||||||
a->u = *(union w_list_data *)data;
|
|
||||||
|
|
||||||
/* insert at front of the list */
|
|
||||||
a->next = workers;
|
|
||||||
tmp = workers;
|
|
||||||
workers = a;
|
|
||||||
|
|
||||||
if (d != NULL)
|
|
||||||
d->busy = BURN_DRIVE_SPAWNING;
|
|
||||||
|
|
||||||
#ifdef Libburn_create_detached_threadS
|
|
||||||
/* ts A71019 :
|
|
||||||
Trying to start the threads detached to get rid of the zombies
|
|
||||||
which do neither react on pthread_join() nor on pthread_detach().
|
|
||||||
*/
|
|
||||||
pthread_attr_init(&attr);
|
|
||||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
||||||
attr_pt= &attr;
|
|
||||||
/*
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020158,
|
|
||||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_LOW,
|
|
||||||
"add_worker(): Creating detached thread.", 0, 0);
|
|
||||||
*/
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pthread_create(&a->thread, attr_pt, f, a)) {
|
|
||||||
free(a);
|
|
||||||
workers = tmp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void remove_worker(pthread_t th)
|
|
||||||
{
|
|
||||||
struct w_list *a, *l = NULL;
|
|
||||||
|
|
||||||
#ifdef Libburn_detach_done_workeR
|
|
||||||
int ret;
|
|
||||||
char msg[80];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (a = workers; a; l = a, a = a->next)
|
|
||||||
if (a->thread == th) {
|
|
||||||
if (l)
|
|
||||||
l->next = a->next;
|
|
||||||
else
|
|
||||||
workers = a->next;
|
|
||||||
|
|
||||||
#ifdef Libburn_detach_done_workeR
|
|
||||||
/* ts A71019 : burry dead puppy before forgetting it */
|
|
||||||
/* Alternative : threads get detached and thus should
|
|
||||||
dispose themselves.
|
|
||||||
*/
|
|
||||||
ret = pthread_detach(th);
|
|
||||||
/*
|
|
||||||
sprintf(msg,
|
|
||||||
"remove_workers(): pid= %lu pthread_detach(%lu)= %d",
|
|
||||||
(unsigned long) getpid(), (unsigned long) th, ret);
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020158,
|
|
||||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_LOW,
|
|
||||||
msg, 0, 0);
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endif /* Libburn_detach_done_workeR */
|
|
||||||
|
|
||||||
free(a);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61006 */
|
|
||||||
/* a ssert(a != NULL);/ * wasn't found.. this should not be possible */
|
|
||||||
if (a == NULL)
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
|
|
||||||
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"remove_worker() cannot find given worker item", 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *scan_worker_func(struct w_list *w)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = burn_drive_scan_sync(w->u.scan.drives, w->u.scan.n_drives, 1);
|
|
||||||
if (ret <= 0)
|
|
||||||
w->u.scan.done = -1;
|
|
||||||
else
|
|
||||||
w->u.scan.done = 1;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_drive_scan(struct burn_drive_info *drives[], unsigned int *n_drives)
|
|
||||||
{
|
|
||||||
struct scan_opts o;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* ts A61006 : moved up from burn_drive_scan_sync , former Assert */
|
|
||||||
if (!burn_running) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020109,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Library not running (on attempt to scan)", 0, 0);
|
|
||||||
*drives = NULL;
|
|
||||||
*n_drives = 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cant be anything working! */
|
|
||||||
|
|
||||||
/* ts A61006 */
|
|
||||||
/* a ssert(!(workers && workers->drive)); */
|
|
||||||
if (workers != NULL && workers->drive != NULL) {
|
|
||||||
drive_is_active:;
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020102,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"A drive operation is still going on (want to scan)",
|
|
||||||
0, 0);
|
|
||||||
*drives = NULL;
|
|
||||||
*n_drives = 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workers == NULL) {
|
|
||||||
/* start it */
|
|
||||||
|
|
||||||
/* ts A61007 : test moved up from burn_drive_scan_sync()
|
|
||||||
was burn_wait_all() */
|
|
||||||
/* ts A70907 : now demanding freed drives, not only released */
|
|
||||||
if (!burn_drives_are_clear(1))
|
|
||||||
goto drive_is_active;
|
|
||||||
*drives = NULL;
|
|
||||||
*n_drives = 0;
|
|
||||||
|
|
||||||
o.drives = drives;
|
|
||||||
o.n_drives = n_drives;
|
|
||||||
o.done = 0;
|
|
||||||
add_worker(NULL, (WorkerFunc) scan_worker_func, &o);
|
|
||||||
} else if (workers->u.scan.done) {
|
|
||||||
/* its done */
|
|
||||||
ret = workers->u.scan.done;
|
|
||||||
remove_worker(workers->thread);
|
|
||||||
|
|
||||||
/* ts A61006 */
|
|
||||||
/* a ssert(workers == NULL); */
|
|
||||||
if (workers != NULL) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
|
|
||||||
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"After scan a drive operation is still going on",
|
|
||||||
0, 0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* still going */
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *erase_worker_func(struct w_list *w)
|
|
||||||
{
|
|
||||||
burn_disc_erase_sync(w->u.erase.drive, w->u.erase.fast);
|
|
||||||
remove_worker(pthread_self());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_disc_erase(struct burn_drive *drive, int fast)
|
|
||||||
{
|
|
||||||
struct erase_opts o;
|
|
||||||
|
|
||||||
/* ts A61006 */
|
|
||||||
/* a ssert(drive); */
|
|
||||||
/* a ssert(!SCAN_GOING()); */
|
|
||||||
/* a ssert(!find_worker(drive)); */
|
|
||||||
if((drive == NULL)) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
|
||||||
0x00020104,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"NULL pointer caught in burn_disc_erase", 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((SCAN_GOING()) || find_worker(drive)) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
|
||||||
0x00020102,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"A drive operation is still going on (want to erase)",
|
|
||||||
0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* A70103 : will be set to 0 by burn_disc_erase_sync() */
|
|
||||||
drive->cancel = 1;
|
|
||||||
|
|
||||||
/* ts A70103 moved up from burn_disc_erase_sync() */
|
|
||||||
/* ts A60825 : allow on parole to blank appendable CDs */
|
|
||||||
/* ts A70131 : allow blanking of overwriteable DVD-RW (profile 0x13) */
|
|
||||||
/* ts A70216 : allow blanking of CD-RW or DVD-RW in any regular state
|
|
||||||
and of any kind of full media */
|
|
||||||
/* ts A70909 : the willingness to burn any BURN_DISC_FULL media is
|
|
||||||
inappropriate. One would rather need a -force option
|
|
||||||
Note: keep this in sync with mmc_read_disc_info() */
|
|
||||||
if ((drive->current_profile != 0x0a &&
|
|
||||||
drive->current_profile != 0x13 &&
|
|
||||||
drive->current_profile != 0x14 &&
|
|
||||||
drive->status != BURN_DISC_FULL)
|
|
||||||
||
|
|
||||||
(drive->status != BURN_DISC_FULL &&
|
|
||||||
drive->status != BURN_DISC_APPENDABLE &&
|
|
||||||
drive->status != BURN_DISC_BLANK)
|
|
||||||
||
|
|
||||||
(drive->drive_role != 1)
|
|
||||||
) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
|
||||||
0x00020130,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Drive and media state unsuitable for blanking",
|
|
||||||
0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
o.drive = drive;
|
|
||||||
o.fast = fast;
|
|
||||||
add_worker(drive, (WorkerFunc) erase_worker_func, &o);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61230 */
|
|
||||||
static void *format_worker_func(struct w_list *w)
|
|
||||||
{
|
|
||||||
burn_disc_format_sync(w->u.format.drive, w->u.format.size,
|
|
||||||
w->u.format.flag);
|
|
||||||
remove_worker(pthread_self());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61230 */
|
|
||||||
void burn_disc_format(struct burn_drive *drive, off_t size, int flag)
|
|
||||||
{
|
|
||||||
struct format_opts o;
|
|
||||||
int ok = 0;
|
|
||||||
char msg[160];
|
|
||||||
|
|
||||||
if ((SCAN_GOING()) || find_worker(drive)) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
|
||||||
0x00020102,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"A drive operation is still going on (want to format)",
|
|
||||||
0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (drive->drive_role != 1) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
|
||||||
0x00020146,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Drive is a virtual placeholder", 0, 0);
|
|
||||||
drive->cancel = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (flag & 128) /* application prescribed format type */
|
|
||||||
flag |= 16; /* enforce re-format */
|
|
||||||
|
|
||||||
if (drive->current_profile == 0x14)
|
|
||||||
ok = 1; /* DVD-RW sequential */
|
|
||||||
else if (drive->current_profile == 0x13 && (flag & 16))
|
|
||||||
ok = 1; /* DVD-RW Restricted Overwrite with force bit */
|
|
||||||
else if (drive->current_profile == 0x1a) {
|
|
||||||
ok = 1; /* DVD+RW */
|
|
||||||
size = 0;
|
|
||||||
flag &= ~(2|8); /* no insisting in size 0, no expansion */
|
|
||||||
flag |= 4; /* format up to maximum size */
|
|
||||||
} else if (drive->current_profile == 0x12) {
|
|
||||||
ok = 1; /* DVD-RAM */
|
|
||||||
} else if (drive->current_profile == 0x43) {
|
|
||||||
ok = 1; /* BD-RE */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
sprintf(msg,"Will not format media type %4.4Xh",
|
|
||||||
drive->current_profile);
|
|
||||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
|
||||||
0x00020129,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
msg, 0, 0);
|
|
||||||
drive->cancel = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
o.drive = drive;
|
|
||||||
o.size = size;
|
|
||||||
o.flag = flag;
|
|
||||||
add_worker(drive, (WorkerFunc) format_worker_func, &o);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void *write_disc_worker_func(struct w_list *w)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = w->u.write.drive;
|
|
||||||
|
|
||||||
d->thread_pid = getpid();
|
|
||||||
d->thread_pid_valid= 1;
|
|
||||||
burn_disc_write_sync(w->u.write.opts, w->u.write.disc);
|
|
||||||
d->thread_pid_valid= 0;
|
|
||||||
d->thread_pid = 0;
|
|
||||||
|
|
||||||
/* the options are refcounted, free out ref count which we added below
|
|
||||||
*/
|
|
||||||
burn_write_opts_free(w->u.write.opts);
|
|
||||||
|
|
||||||
remove_worker(pthread_self());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
|
||||||
{
|
|
||||||
struct write_opts o;
|
|
||||||
char reasons[BURN_REASONS_LEN+80];
|
|
||||||
|
|
||||||
/* ts A61006 */
|
|
||||||
/* a ssert(!SCAN_GOING()); */
|
|
||||||
/* a ssert(!find_worker(opts->drive)); */
|
|
||||||
if ((SCAN_GOING()) || find_worker(opts->drive)) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, opts->drive->global_index,
|
|
||||||
0x00020102,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"A drive operation is still going on (want to write)",
|
|
||||||
0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For the next lines any return indicates failure */
|
|
||||||
opts->drive->cancel = 1;
|
|
||||||
|
|
||||||
/* ts A70203 : people have been warned in API specs */
|
|
||||||
if (opts->write_type == BURN_WRITE_NONE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (opts->drive->drive_role == 0) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, opts->drive->global_index,
|
|
||||||
0x00020146,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Drive is a virtual placeholder (null-drive)", 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61007 : obsolete Assert in spc_select_write_params() */
|
|
||||||
if (opts->drive->drive_role == 1 && !opts->drive->mdata->valid) {
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
opts->drive->global_index, 0x00020113,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Drive capabilities not inquired yet", 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A70219 : intended to replace all further tests here and many
|
|
||||||
tests in burn_*_write_sync()
|
|
||||||
*/
|
|
||||||
strcpy(reasons, "Write job parameters are unsuitable:\n");
|
|
||||||
if (burn_precheck_write(opts, disc, reasons + strlen(reasons), 1)
|
|
||||||
== BURN_WRITE_NONE) {
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
opts->drive->global_index, 0x00020139,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
reasons, 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
opts->drive->cancel = 0; /* End of the return = failure area */
|
|
||||||
|
|
||||||
o.drive = opts->drive;
|
|
||||||
o.opts = opts;
|
|
||||||
o.disc = disc;
|
|
||||||
|
|
||||||
opts->refcount++;
|
|
||||||
|
|
||||||
add_worker(opts->drive, (WorkerFunc) write_disc_worker_func, &o);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void *fifo_worker_func(struct w_list *w)
|
|
||||||
{
|
|
||||||
burn_fifo_source_shoveller(w->u.fifo.source, w->u.fifo.flag);
|
|
||||||
remove_worker(pthread_self());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int burn_fifo_start(struct burn_source *source, int flag)
|
|
||||||
{
|
|
||||||
struct fifo_opts o;
|
|
||||||
struct burn_source_fifo *fs = source->data;
|
|
||||||
|
|
||||||
fs->is_started = -1;
|
|
||||||
|
|
||||||
/* create and set up ring buffer */;
|
|
||||||
fs->buf = calloc(fs->chunksize, fs->chunks);
|
|
||||||
if (fs->buf == NULL) {
|
|
||||||
/* >>> could not start ring buffer */;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
o.source = source;
|
|
||||||
o.flag = flag;
|
|
||||||
add_worker(NULL, (WorkerFunc) fifo_worker_func, &o);
|
|
||||||
fs->is_started = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef Libburn_has_burn_async_join_alL
|
|
||||||
|
|
||||||
/* ts A71019 : never used */
|
|
||||||
void burn_async_join_all(void)
|
|
||||||
{
|
|
||||||
void *ret;
|
|
||||||
|
|
||||||
while (workers)
|
|
||||||
pthread_join(workers->thread, &ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* Libburn_has_burn_async_join_alL */
|
|
||||||
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef BURN__ASYNC_H
|
|
||||||
#define BURN__ASYNC_H
|
|
||||||
|
|
||||||
void burn_async_join_all(void);
|
|
||||||
struct burn_write_opts;
|
|
||||||
|
|
||||||
/* ts A70930 */
|
|
||||||
/* To be called when the first read() call comes to a fifo */
|
|
||||||
int burn_fifo_start(struct burn_source *source, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* BURN__ASYNC_H */
|
|
@ -1,54 +0,0 @@
|
|||||||
/**
|
|
||||||
|
|
||||||
This file bundles variables which disable changes in libburn which are
|
|
||||||
not yet completely accepted.
|
|
||||||
|
|
||||||
The use of these variables is *strongly discouraged* unless you have sincere
|
|
||||||
reason and are willing to share your gained knowledge with the libburn
|
|
||||||
developers.
|
|
||||||
|
|
||||||
Do *not silently rely* on these variables with your application. Tell us
|
|
||||||
that you needed one or more of them. They are subject to removal as soon
|
|
||||||
as consense has been found about correctness of the change they revoke.
|
|
||||||
|
|
||||||
Value 0 means that the new behavior is enabled. Any other value enables
|
|
||||||
the described old time behavior.
|
|
||||||
|
|
||||||
If you doubt one of the changes here broke your application, then do
|
|
||||||
*in your application*, *not here* :
|
|
||||||
|
|
||||||
- #include "libburn/back_hacks.h" like you include "libburn/libburn.h"
|
|
||||||
|
|
||||||
- Set the libburn_back_hack_* variable of your choice to 1.
|
|
||||||
In your app. Not here.
|
|
||||||
|
|
||||||
- Then start and use libburn as usual. Watch out for results.
|
|
||||||
|
|
||||||
- If you believe to have detected a flaw in our change, come forward
|
|
||||||
and report it to the libburn developers. Thanks in advance. :)
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Do not define this macro in your application. Only libburn/init.c is
|
|
||||||
entitled to set it.
|
|
||||||
*/
|
|
||||||
#ifdef BURN_BACK_HACKS_INIT
|
|
||||||
|
|
||||||
|
|
||||||
/** Corresponds to http://libburn.pykix.org/ticket/42
|
|
||||||
Reinstates the old ban not to blank appendable CD-RW. We see no reason
|
|
||||||
for this ban yet. It appears unusual. But maybe it patches a bug.
|
|
||||||
*/
|
|
||||||
int libburn_back_hack_42= 0;
|
|
||||||
|
|
||||||
|
|
||||||
#else /* BURN_BACK_HACKS_INIT */
|
|
||||||
|
|
||||||
/* Note: no application programmer info beyond this point */
|
|
||||||
|
|
||||||
|
|
||||||
extern int libburn_back_hack_42;
|
|
||||||
|
|
||||||
#endif /* ! BURN_BACK_HACKS_INIT */
|
|
||||||
|
|
||||||
|
|
@ -1,215 +0,0 @@
|
|||||||
/*
|
|
||||||
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
|
|
||||||
A signal handler which cleans up an application and exits.
|
|
||||||
|
|
||||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
cc -g -o cleanup -DCleanup_standalonE cleanup.c
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
typedef void (*sighandler_t)(int);
|
|
||||||
|
|
||||||
|
|
||||||
#include "cleanup.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef Cleanup_has_no_libburn_os_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "../libburn/os.h"
|
|
||||||
|
|
||||||
/* see os.h for name of particular os-*.h where this is defined */
|
|
||||||
static int signal_list[]= { BURN_OS_SIGNAL_MACRO_LIST , -1};
|
|
||||||
static char *signal_name_list[]= { BURN_OS_SIGNAL_NAME_LIST , "@"};
|
|
||||||
static int signal_list_count= BURN_OS_SIGNAL_COUNT;
|
|
||||||
static int non_signal_list[]= { BURN_OS_NON_SIGNAL_MACRO_LIST, -1};
|
|
||||||
static int non_signal_list_count= BURN_OS_NON_SIGNAL_COUNT;
|
|
||||||
|
|
||||||
|
|
||||||
#else /* ! Cleanup_has_no_libburn_os_H */
|
|
||||||
|
|
||||||
|
|
||||||
/* Outdated. Linux only. For backward compatibility with pre-libburn-0.2.3 */
|
|
||||||
|
|
||||||
/* Signals to be caught */
|
|
||||||
static int signal_list[]= {
|
|
||||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
|
|
||||||
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
|
|
||||||
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
|
|
||||||
SIGTTOU,
|
|
||||||
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
|
|
||||||
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
|
|
||||||
};
|
|
||||||
static char *signal_name_list[]= {
|
|
||||||
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
|
|
||||||
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
|
|
||||||
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
|
|
||||||
"SIGTTOU",
|
|
||||||
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
|
|
||||||
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
|
|
||||||
};
|
|
||||||
static int signal_list_count= 24;
|
|
||||||
|
|
||||||
/* Signals not to be caught */
|
|
||||||
static int non_signal_list[]= {
|
|
||||||
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH, -1
|
|
||||||
};
|
|
||||||
static int non_signal_list_count= 5;
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* Cleanup_has_no_libburn_os_H */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* run time dynamic part */
|
|
||||||
static char cleanup_msg[4096]= {""};
|
|
||||||
static int cleanup_exiting= 0;
|
|
||||||
static int cleanup_has_reported= -1234567890;
|
|
||||||
|
|
||||||
static void *cleanup_app_handle= NULL;
|
|
||||||
static Cleanup_app_handler_T cleanup_app_handler= NULL;
|
|
||||||
static int cleanup_perform_app_handler_first= 0;
|
|
||||||
|
|
||||||
|
|
||||||
static int Cleanup_handler_exit(int exit_value, int signum, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if(cleanup_msg[0]!=0 && cleanup_has_reported!=signum) {
|
|
||||||
fprintf(stderr,"\n%s\n",cleanup_msg);
|
|
||||||
cleanup_has_reported= signum;
|
|
||||||
}
|
|
||||||
if(cleanup_perform_app_handler_first)
|
|
||||||
if(cleanup_app_handler!=NULL) {
|
|
||||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
|
||||||
if(ret==2 || ret==-2)
|
|
||||||
return(2);
|
|
||||||
}
|
|
||||||
if(cleanup_exiting) {
|
|
||||||
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
|
|
||||||
getpid(),signum);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
cleanup_exiting= 1;
|
|
||||||
alarm(0);
|
|
||||||
if(!cleanup_perform_app_handler_first)
|
|
||||||
if(cleanup_app_handler!=NULL) {
|
|
||||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
|
||||||
if(ret==2 || ret==-2)
|
|
||||||
return(2);
|
|
||||||
}
|
|
||||||
exit(exit_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void Cleanup_handler_generic(int signum)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
sprintf(cleanup_msg,"UNIX-SIGNAL caught: %d errno= %d",signum,errno);
|
|
||||||
for(i= 0; i<signal_list_count; i++)
|
|
||||||
if(signum==signal_list[i]) {
|
|
||||||
sprintf(cleanup_msg,"UNIX-SIGNAL: %s errno= %d",
|
|
||||||
signal_name_list[i],errno);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Cleanup_handler_exit(1,signum,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
|
|
||||||
/*
|
|
||||||
bit0= set to default handlers
|
|
||||||
bit1= set to ignore
|
|
||||||
bit2= set cleanup_perform_app_handler_first
|
|
||||||
bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
int i,j,max_sig= -1,min_sig= 0x7fffffff;
|
|
||||||
sighandler_t sig_handler;
|
|
||||||
|
|
||||||
cleanup_msg[0]= 0;
|
|
||||||
cleanup_app_handle= handle;
|
|
||||||
cleanup_app_handler= handler;
|
|
||||||
|
|
||||||
/* <<< make cleanup_exiting thread safe to get rid of this */
|
|
||||||
if(flag&4)
|
|
||||||
cleanup_perform_app_handler_first= 1;
|
|
||||||
|
|
||||||
|
|
||||||
if(flag&1)
|
|
||||||
sig_handler= SIG_DFL;
|
|
||||||
else if(flag&2)
|
|
||||||
sig_handler= SIG_IGN;
|
|
||||||
else
|
|
||||||
sig_handler= Cleanup_handler_generic;
|
|
||||||
/* set all signal numbers between the lowest and highest in the list
|
|
||||||
except those in the non-signal list */
|
|
||||||
for(i= 0; i<signal_list_count; i++) {
|
|
||||||
if(signal_list[i]>max_sig)
|
|
||||||
max_sig= signal_list[i];
|
|
||||||
if(signal_list[i]<min_sig)
|
|
||||||
min_sig= signal_list[i];
|
|
||||||
}
|
|
||||||
for(i= min_sig; i<=max_sig; i++) {
|
|
||||||
for(j= 0; j<non_signal_list_count; j++)
|
|
||||||
if(i==non_signal_list[j])
|
|
||||||
break;
|
|
||||||
if(j>=non_signal_list_count) {
|
|
||||||
if(i==SIGABRT && (flag&8))
|
|
||||||
signal(i,Cleanup_handler_generic);
|
|
||||||
else
|
|
||||||
signal(i,sig_handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef Cleanup_standalonE
|
|
||||||
|
|
||||||
struct Demo_apP {
|
|
||||||
char *msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int Demo_app_handler(struct Demo_apP *demoapp, int signum, int flag)
|
|
||||||
{
|
|
||||||
printf("Handling exit of demo application on signal %d. msg=\"%s\"\n",
|
|
||||||
signum,demoapp->msg);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
{
|
|
||||||
struct Demo_apP demoapp;
|
|
||||||
|
|
||||||
demoapp.msg= "Good Bye";
|
|
||||||
Cleanup_set_handlers(&demoapp,(Cleanup_app_handler_T) Demo_app_handler,0);
|
|
||||||
|
|
||||||
if(1) { /* change to 0 in order to wait for external signals */
|
|
||||||
char *cpt= NULL,c;
|
|
||||||
printf("Intentionally provoking SIGSEGV ...\n");
|
|
||||||
c= *cpt;
|
|
||||||
} else {
|
|
||||||
printf("killme: %d\n",getpid());
|
|
||||||
sleep(3600);
|
|
||||||
}
|
|
||||||
|
|
||||||
Cleanup_set_handlers(NULL,NULL,1);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* Cleanup_standalonE */
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
|
|
||||||
A signal handler which cleans up an application and exits.
|
|
||||||
|
|
||||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef Cleanup_includeD
|
|
||||||
#define Cleanup_includeD 1
|
|
||||||
|
|
||||||
|
|
||||||
/** Layout of an application provided cleanup function using an application
|
|
||||||
provided handle as first argument and the signal number as second
|
|
||||||
argument. The third argument is a flag bit field with no defined bits yet.
|
|
||||||
If the handler returns 2 or -2 then it has delegated exit() to some other
|
|
||||||
instance and the Cleanup handler shall return rather than exit.
|
|
||||||
*/
|
|
||||||
typedef int (*Cleanup_app_handler_T)(void *, int, int);
|
|
||||||
|
|
||||||
|
|
||||||
/** Establish exiting signal handlers on (hopefully) all signals that are
|
|
||||||
not ignored by default or non-catchable.
|
|
||||||
@param handle Opaque object which knows how to cleanup application
|
|
||||||
@param handler Function which uses handle to perform application cleanup
|
|
||||||
@param flag Control Bitfield
|
|
||||||
bit0= reset to default signal handling
|
|
||||||
*/
|
|
||||||
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler,
|
|
||||||
int flag);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! Cleanup_includeD */
|
|
||||||
|
|
122
libburn/crc.c
122
libburn/crc.c
@ -1,122 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#include "crc.h"
|
|
||||||
|
|
||||||
static unsigned short ccitt_table[256] = {
|
|
||||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
|
||||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
|
||||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
|
||||||
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
|
||||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
|
||||||
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
|
||||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
|
||||||
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
|
||||||
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
|
||||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
|
||||||
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
|
||||||
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
|
||||||
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
|
||||||
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
|
||||||
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
|
||||||
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
|
||||||
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
|
||||||
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
|
||||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
|
||||||
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
|
||||||
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
|
||||||
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
|
||||||
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
|
||||||
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
|
||||||
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
|
||||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
|
||||||
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
|
||||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
|
||||||
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
|
||||||
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
|
||||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
|
||||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned long crc32_table[256] = {
|
|
||||||
0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
|
|
||||||
0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
|
|
||||||
0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
|
|
||||||
0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
|
|
||||||
0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
|
|
||||||
0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
|
|
||||||
0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
|
|
||||||
0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
|
|
||||||
0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
|
|
||||||
0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
|
|
||||||
0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
|
|
||||||
0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
|
|
||||||
0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
|
|
||||||
0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
|
|
||||||
0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
|
|
||||||
0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
|
|
||||||
0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
|
|
||||||
0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
|
|
||||||
0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
|
|
||||||
0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
|
|
||||||
0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
|
|
||||||
0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
|
|
||||||
0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
|
|
||||||
0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
|
|
||||||
0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
|
|
||||||
0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
|
|
||||||
0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
|
|
||||||
0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
|
|
||||||
0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
|
|
||||||
0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
|
|
||||||
0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
|
|
||||||
0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
|
|
||||||
0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
|
|
||||||
0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
|
|
||||||
0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
|
|
||||||
0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
|
|
||||||
0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
|
|
||||||
0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
|
|
||||||
0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
|
|
||||||
0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
|
|
||||||
0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
|
|
||||||
0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
|
|
||||||
0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
|
|
||||||
0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
|
|
||||||
0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
|
|
||||||
0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
|
|
||||||
0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
|
|
||||||
0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
|
|
||||||
0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
|
|
||||||
0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
|
|
||||||
0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
|
|
||||||
0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
|
|
||||||
0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
|
|
||||||
0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
|
|
||||||
0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
|
|
||||||
0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
|
|
||||||
0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
|
|
||||||
0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
|
|
||||||
0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
|
|
||||||
0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
|
|
||||||
0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
|
|
||||||
0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
|
|
||||||
0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
|
|
||||||
0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned short crc_ccitt(unsigned char *q, int len)
|
|
||||||
{
|
|
||||||
unsigned short crc = 0;
|
|
||||||
|
|
||||||
while (len-- > 0)
|
|
||||||
crc = ccitt_table[(crc >> 8 ^ *q++) & 0xff] ^ (crc << 8);
|
|
||||||
return ~crc;
|
|
||||||
}
|
|
||||||
unsigned int crc_32(unsigned char *data, int len)
|
|
||||||
{
|
|
||||||
unsigned int crc = 0;
|
|
||||||
|
|
||||||
while (len-- > 0)
|
|
||||||
crc = crc32_table[(crc ^ *data++) & 0xffL] ^ (crc >> 8);
|
|
||||||
return crc;
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef BURN__CRC_H
|
|
||||||
#define BURN__CRC_H
|
|
||||||
|
|
||||||
unsigned short crc_ccitt(unsigned char *, int len);
|
|
||||||
unsigned int crc_32(unsigned char *, int len);
|
|
||||||
|
|
||||||
#endif /* BURN__CRC_H */
|
|
614
libburn/ddlpa.c
614
libburn/ddlpa.c
@ -1,614 +0,0 @@
|
|||||||
|
|
||||||
/* ddlpa
|
|
||||||
Implementation of Delicate Device Locking Protocol level A.
|
|
||||||
Copyright (C) 2007 Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
Provided under any of the following licenses: GPL, LGPL, BSD. Choose one.
|
|
||||||
|
|
||||||
|
|
||||||
Compile as test program:
|
|
||||||
|
|
||||||
cc -g -Wall \
|
|
||||||
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
|
|
||||||
-DDDLPA_C_STANDALONE -o ddlpa ddlpa.c
|
|
||||||
|
|
||||||
The system macros enable 64-bit off_t and open(2) flag O_LARGEFILE, which
|
|
||||||
are not absolutely necessary but explicitely take into respect that
|
|
||||||
our devices can offer more than 2 GB of addressable data.
|
|
||||||
|
|
||||||
Run test program:
|
|
||||||
|
|
||||||
./ddlpa /dev/sr0 15
|
|
||||||
./ddlpa 0,0,0 15
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <scsi/scsi.h>
|
|
||||||
|
|
||||||
|
|
||||||
/* All callers of ddlpa must do this */
|
|
||||||
#include "ddlpa.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* 1 = Enable progress message on stderr, 0 = normal silent operation */
|
|
||||||
static int ddlpa_debug_mode = 1;
|
|
||||||
|
|
||||||
|
|
||||||
/* #define _GNU_SOURCE or _LARGEFILE64_SOURCE to get real O_LARGEFILE */
|
|
||||||
#ifndef O_LARGEFILE
|
|
||||||
#define O_LARGEFILE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------- private -------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_new(struct ddlpa_lock **lck, int o_flags, int ddlpa_flags)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
struct ddlpa_lock *o;
|
|
||||||
|
|
||||||
o = *lck = (struct ddlpa_lock *) malloc(sizeof(struct ddlpa_lock));
|
|
||||||
if (o == NULL)
|
|
||||||
return ENOMEM;
|
|
||||||
for (i = 0; i < sizeof(struct ddlpa_lock); i++)
|
|
||||||
((char *) o)[i] = 0;
|
|
||||||
o->path = NULL;
|
|
||||||
o->fd = -1;
|
|
||||||
for (i = 0; i < DDLPA_MAX_SIBLINGS; i++)
|
|
||||||
o->sibling_fds[i] = -1;
|
|
||||||
o->errmsg = NULL;
|
|
||||||
|
|
||||||
o->o_flags = o_flags;
|
|
||||||
o->ddlpa_flags = ddlpa_flags;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_enumerate(struct ddlpa_lock *o, int *idx,
|
|
||||||
char path[DDLPA_MAX_STD_LEN + 1])
|
|
||||||
{
|
|
||||||
if (*idx < 0)
|
|
||||||
*idx = 0;
|
|
||||||
|
|
||||||
if (*idx < 26)
|
|
||||||
sprintf(path, "/dev/hd%c", 'a' + *idx);
|
|
||||||
else if (*idx < 256 + 26)
|
|
||||||
sprintf(path, "/dev/sr%d", *idx - 26);
|
|
||||||
else if (*idx < 2 * 256 + 26)
|
|
||||||
sprintf(path, "/dev/scd%d", *idx - 256 - 26);
|
|
||||||
else if (*idx < 3 * 256 + 26)
|
|
||||||
sprintf(path, "/dev/sg%d", *idx - 2 * 256 - 26);
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
(*idx)++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_std_by_rdev(struct ddlpa_lock *o)
|
|
||||||
{
|
|
||||||
int idx = 0;
|
|
||||||
char try_path[DDLPA_MAX_STD_LEN+1];
|
|
||||||
struct stat path_stbuf, try_stbuf;
|
|
||||||
|
|
||||||
if (!o->path_is_valid)
|
|
||||||
return EFAULT;
|
|
||||||
if (stat(o->path, &path_stbuf) == -1)
|
|
||||||
return errno;
|
|
||||||
|
|
||||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
|
||||||
if (stat(try_path, &try_stbuf) == -1)
|
|
||||||
continue;
|
|
||||||
if (path_stbuf.st_rdev != try_stbuf.st_rdev)
|
|
||||||
continue;
|
|
||||||
strcpy(o->std_path, try_path);
|
|
||||||
|
|
||||||
if (ddlpa_debug_mode)
|
|
||||||
fprintf(stderr,
|
|
||||||
"DDLPA_DEBUG: ddlpa_std_by_rdev(\"%s\") = \"%s\"\n",
|
|
||||||
o->path, o->std_path);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Caution : these tests are valid only with standard paths */
|
|
||||||
|
|
||||||
static int ddlpa_is_scsi(struct ddlpa_lock *o, char *path)
|
|
||||||
{
|
|
||||||
return (strncmp(path, "/dev/s", 6) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ddlpa_is_sg(struct ddlpa_lock *o, char *path)
|
|
||||||
{
|
|
||||||
return (strncmp(path, "/dev/sg", 7) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ddlpa_is_sr(struct ddlpa_lock *o, char *path)
|
|
||||||
{
|
|
||||||
return (strncmp(path, "/dev/sr", 7) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ddlpa_is_scd(struct ddlpa_lock *o, char *path)
|
|
||||||
{
|
|
||||||
return (strncmp(path, "/dev/scd", 8) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_fcntl_lock(struct ddlpa_lock *o, int fd, int l_type)
|
|
||||||
{
|
|
||||||
struct flock lockthing;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
memset(&lockthing, 0, sizeof(lockthing));
|
|
||||||
lockthing.l_type = l_type;
|
|
||||||
lockthing.l_whence = SEEK_SET;
|
|
||||||
lockthing.l_start = 0;
|
|
||||||
lockthing.l_len = 0;
|
|
||||||
ret = fcntl(fd, F_SETLK, &lockthing);
|
|
||||||
if (ret == -1)
|
|
||||||
return EBUSY;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_occupy(struct ddlpa_lock *o, char *path, int *fd,
|
|
||||||
int no_o_excl)
|
|
||||||
{
|
|
||||||
int ret, o_flags, o_rw, l_type;
|
|
||||||
char *o_rwtext;
|
|
||||||
|
|
||||||
o_flags = o->o_flags | O_NDELAY;
|
|
||||||
if(!no_o_excl)
|
|
||||||
o_flags |= O_EXCL;
|
|
||||||
o_rw = (o_flags) & (O_RDONLY | O_WRONLY | O_RDWR);
|
|
||||||
o_rwtext = (o_rw == O_RDONLY ? "O_RDONLY" :
|
|
||||||
(o_rw == O_WRONLY ? "O_WRONLY" :
|
|
||||||
(o_rw == O_RDWR ? "O_RDWR " : "O_?rw-mode?")));
|
|
||||||
|
|
||||||
*fd = open(path, o_flags);
|
|
||||||
if (*fd == -1) {
|
|
||||||
o->errmsg = malloc(strlen(path)+160);
|
|
||||||
if (o->errmsg)
|
|
||||||
sprintf(o->errmsg,
|
|
||||||
"Failed to open %s | O_NDELAY %s: '%s'",
|
|
||||||
o_rwtext,
|
|
||||||
(o_flags & O_EXCL ? "| O_EXCL " : ""), path);
|
|
||||||
return (errno ? errno : EBUSY);
|
|
||||||
}
|
|
||||||
if (o_rw == O_RDWR || o_rw == O_WRONLY)
|
|
||||||
l_type = F_WRLCK;
|
|
||||||
else
|
|
||||||
l_type = F_RDLCK;
|
|
||||||
ret = ddlpa_fcntl_lock(o, *fd, l_type);
|
|
||||||
if (ret) {
|
|
||||||
o->errmsg = malloc(strlen(path)+160);
|
|
||||||
if (o->errmsg)
|
|
||||||
sprintf(o->errmsg,
|
|
||||||
"Failed to lock fcntl(F_WRLCK) : '%s'",path);
|
|
||||||
close(*fd);
|
|
||||||
*fd = -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (ddlpa_debug_mode)
|
|
||||||
fprintf(stderr, "DDLPA_DEBUG: ddlpa_occupy() %s %s: '%s'\n",
|
|
||||||
o_rwtext,
|
|
||||||
(no_o_excl ? " " : "O_EXCL "), path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_obtain_scsi_adr(struct ddlpa_lock *o, char *path,
|
|
||||||
int *bus, int *host, int *channel, int *id, int *lun)
|
|
||||||
{
|
|
||||||
int fd, ret, open_mode = O_RDONLY | O_NDELAY;
|
|
||||||
struct my_scsi_idlun {
|
|
||||||
int x;
|
|
||||||
int host_unique_id;
|
|
||||||
};
|
|
||||||
struct my_scsi_idlun idlun;
|
|
||||||
|
|
||||||
fd = open(path, open_mode);
|
|
||||||
if (fd == -1)
|
|
||||||
return (errno ? errno : EBUSY);
|
|
||||||
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, bus) == -1)
|
|
||||||
*bus = -1;
|
|
||||||
ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
|
|
||||||
close(fd);
|
|
||||||
if (ret == -1)
|
|
||||||
return (errno ? errno : EIO);
|
|
||||||
*host = (idlun.x >> 24) & 255;
|
|
||||||
*channel = (idlun.x >> 16) & 255;
|
|
||||||
*id = (idlun.x) & 255;
|
|
||||||
*lun = (idlun.x >> 8 ) & 255;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_collect_siblings(struct ddlpa_lock *o)
|
|
||||||
{
|
|
||||||
int idx = 0, ret, have_sg = 0, have_sr = 0, have_scd = 0;
|
|
||||||
dev_t path_dev;
|
|
||||||
ino_t path_inode;
|
|
||||||
struct stat stbuf;
|
|
||||||
char *path, try_path[DDLPA_MAX_STD_LEN+1];
|
|
||||||
int t_bus, t_host, t_channel, t_id, t_lun;
|
|
||||||
|
|
||||||
if (o->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
|
||||||
path = o->path;
|
|
||||||
else
|
|
||||||
path = o->std_path;
|
|
||||||
if (path[0] == 0 || o->num_siblings != 0)
|
|
||||||
return EFAULT;
|
|
||||||
if (!ddlpa_is_scsi(o, o->std_path))
|
|
||||||
return EFAULT;
|
|
||||||
|
|
||||||
if (stat(path, &stbuf) == -1)
|
|
||||||
return errno;
|
|
||||||
path_inode = stbuf.st_ino;
|
|
||||||
path_dev = stbuf.st_dev;
|
|
||||||
o->rdev = stbuf.st_rdev;
|
|
||||||
o->dev = stbuf.st_dev;
|
|
||||||
o->ino = stbuf.st_ino;
|
|
||||||
ret = ddlpa_obtain_scsi_adr(o, path,
|
|
||||||
&(o->bus), &(o->host), &(o->channel),
|
|
||||||
&(o->id), &(o->lun));
|
|
||||||
if (ret) {
|
|
||||||
o->errmsg = strdup(
|
|
||||||
"Cannot obtain SCSI parameters host,channel,id,lun");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
o->hcilb_is_valid = 1;
|
|
||||||
|
|
||||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
|
||||||
if (!ddlpa_is_scsi(o, try_path))
|
|
||||||
continue;
|
|
||||||
if (stat(try_path, &stbuf) == -1)
|
|
||||||
continue;
|
|
||||||
ret = ddlpa_obtain_scsi_adr(o, try_path,
|
|
||||||
&t_bus, &t_host, &t_channel, &t_id, &t_lun);
|
|
||||||
if (ret) {
|
|
||||||
|
|
||||||
/* >>> interpret error, memorize busy, no permission */
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (t_host != o->host || t_channel != o->channel ||
|
|
||||||
t_id != o->id || t_lun != o->lun)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (o->num_siblings >= DDLPA_MAX_SIBLINGS) {
|
|
||||||
o->errmsg =
|
|
||||||
strdup("Too many matching device files found");
|
|
||||||
return ERANGE;
|
|
||||||
}
|
|
||||||
if (ddlpa_is_sg(o, try_path))
|
|
||||||
have_sg = 1;
|
|
||||||
else if (ddlpa_is_sr(o, try_path))
|
|
||||||
have_sr = 1;
|
|
||||||
else if (ddlpa_is_scd(o, try_path))
|
|
||||||
have_scd = 1;
|
|
||||||
strcpy(o->sibling_paths[o->num_siblings], try_path);
|
|
||||||
o->sibling_rdevs[o->num_siblings] = stbuf.st_rdev;
|
|
||||||
o->sibling_devs[o->num_siblings] = stbuf.st_dev;
|
|
||||||
o->sibling_inodes[o->num_siblings] = stbuf.st_ino;
|
|
||||||
|
|
||||||
if (ddlpa_debug_mode)
|
|
||||||
fprintf(stderr,
|
|
||||||
"DDLPA_DEBUG: ddlpa_collect_siblings() found \"%s\"\n",
|
|
||||||
try_path);
|
|
||||||
|
|
||||||
(o->num_siblings)++;
|
|
||||||
}
|
|
||||||
if (have_sg && have_sr && have_scd)
|
|
||||||
return 0;
|
|
||||||
if (o->ddlpa_flags & DDLPA_ALLOW_MISSING_SGRCD)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
o->errmsg = strdup("Did not find enough siblings");
|
|
||||||
|
|
||||||
/* >>> add more info about busy and forbidden paths */
|
|
||||||
|
|
||||||
return EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_std_by_btl(struct ddlpa_lock *o)
|
|
||||||
{
|
|
||||||
int idx = 0, ret;
|
|
||||||
char try_path[DDLPA_MAX_STD_LEN+1];
|
|
||||||
int t_bus, t_host, t_channel, t_id, t_lun;
|
|
||||||
|
|
||||||
if (!o->inbtl_is_valid)
|
|
||||||
return EFAULT;
|
|
||||||
|
|
||||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
|
||||||
if (!ddlpa_is_sr(o, try_path))
|
|
||||||
continue;
|
|
||||||
ret = ddlpa_obtain_scsi_adr(o, try_path,
|
|
||||||
&t_bus, &t_host, &t_channel, &t_id, &t_lun);
|
|
||||||
if (ret) {
|
|
||||||
|
|
||||||
/* >>> interpret error, memorize busy, no permission */
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (t_bus != o->in_bus || t_id != o->in_target ||
|
|
||||||
t_lun != o->in_lun)
|
|
||||||
continue;
|
|
||||||
strcpy(o->std_path, try_path);
|
|
||||||
|
|
||||||
if (ddlpa_debug_mode)
|
|
||||||
fprintf(stderr,
|
|
||||||
"DDLPA_DEBUG: ddlpa_std_by_btl(%d,%d,%d) = \"%s\"\n",
|
|
||||||
t_bus, t_id, t_lun, o->std_path);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* >>> add more info about busy and forbidden paths */
|
|
||||||
|
|
||||||
return ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ddlpa_open_all(struct ddlpa_lock *o)
|
|
||||||
{
|
|
||||||
int i, j, ret, no_o_excl;
|
|
||||||
|
|
||||||
if (ddlpa_is_scsi(o, o->std_path)) {
|
|
||||||
ret = ddlpa_collect_siblings(o);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
for (i = 0; i < o->num_siblings; i++) {
|
|
||||||
|
|
||||||
/* Watch out for the main personality of the drive. */
|
|
||||||
/* No need to occupy identical path or softlink path */
|
|
||||||
if (o->sibling_devs[i] == o->dev &&
|
|
||||||
o->sibling_inodes[i] == o->ino)
|
|
||||||
continue;
|
|
||||||
/* There may be the same rdev but different inode. */
|
|
||||||
no_o_excl = (o->sibling_rdevs[i] == o->rdev);
|
|
||||||
|
|
||||||
/* Look for multiply registered device drivers with
|
|
||||||
distinct inodes. */
|
|
||||||
for (j = 0; j < i; j++) {
|
|
||||||
if (o->sibling_devs[j] == o->sibling_devs[i] &&
|
|
||||||
o->sibling_inodes[j] == o->sibling_inodes[i])
|
|
||||||
break;
|
|
||||||
if (o->sibling_rdevs[j] == o->sibling_rdevs[i])
|
|
||||||
no_o_excl = 1;
|
|
||||||
}
|
|
||||||
if (j < i)
|
|
||||||
continue; /* inode is already occupied */
|
|
||||||
|
|
||||||
ret = ddlpa_occupy(o, o->sibling_paths[i],
|
|
||||||
&(o->sibling_fds[i]), no_o_excl);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
|
||||||
ret = ddlpa_occupy(o, o->path, &(o->fd), 0);
|
|
||||||
else
|
|
||||||
ret = ddlpa_occupy(o, o->std_path, &(o->fd), 0);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* >>> use fcntl() to adjust O_NONBLOCK */;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------- public -------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
int ddlpa_destroy(struct ddlpa_lock **lockbundle)
|
|
||||||
{
|
|
||||||
struct ddlpa_lock *o;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
o= *lockbundle;
|
|
||||||
if (o == NULL)
|
|
||||||
return 0;
|
|
||||||
for (i = 0; i < o->num_siblings; i++)
|
|
||||||
if (o->sibling_fds[i] != -1)
|
|
||||||
close(o->sibling_fds[i]);
|
|
||||||
if(o->fd != -1)
|
|
||||||
close(o->fd);
|
|
||||||
if (o->path != NULL)
|
|
||||||
free(o->path);
|
|
||||||
if (o->errmsg != NULL)
|
|
||||||
free(o->errmsg);
|
|
||||||
free((char *) o);
|
|
||||||
*lockbundle = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int ddlpa_lock_path(char *path, int o_flags, int ddlpa_flags,
|
|
||||||
struct ddlpa_lock **lockbundle, char **errmsg)
|
|
||||||
{
|
|
||||||
struct ddlpa_lock *o;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
*errmsg = NULL;
|
|
||||||
if (ddlpa_new(&o, o_flags, ddlpa_flags))
|
|
||||||
return ENOMEM;
|
|
||||||
*lockbundle = o;
|
|
||||||
|
|
||||||
o->path = strdup(path);
|
|
||||||
if (o->path == NULL)
|
|
||||||
return ENOMEM;
|
|
||||||
o->path_is_valid = 1;
|
|
||||||
|
|
||||||
ret = ddlpa_std_by_rdev(o);
|
|
||||||
if (ret) {
|
|
||||||
*errmsg = strdup(
|
|
||||||
"Cannot find equivalent of given path among standard paths");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
ret = ddlpa_open_all(o);
|
|
||||||
if (ret) {
|
|
||||||
*errmsg = o->errmsg;
|
|
||||||
o->errmsg = NULL;
|
|
||||||
ddlpa_destroy(&o);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int ddlpa_lock_btl(int bus, int target, int lun,
|
|
||||||
int o_flags, int ddlpa_flags,
|
|
||||||
struct ddlpa_lock **lockbundle, char **errmsg)
|
|
||||||
{
|
|
||||||
struct ddlpa_lock *o;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
*errmsg = NULL;
|
|
||||||
ddlpa_flags &= ~DDLPA_OPEN_GIVEN_PATH;
|
|
||||||
if (ddlpa_new(&o, o_flags, ddlpa_flags))
|
|
||||||
return ENOMEM;
|
|
||||||
*lockbundle = o;
|
|
||||||
|
|
||||||
o->in_bus = bus;
|
|
||||||
o->in_target = target;
|
|
||||||
o->in_lun = lun;
|
|
||||||
o->inbtl_is_valid = 1;
|
|
||||||
ret = ddlpa_std_by_btl(o);
|
|
||||||
if (ret) {
|
|
||||||
*errmsg = strdup(
|
|
||||||
"Cannot find /dev/sr* with given Bus,Target,Lun");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
ret = ddlpa_open_all(o);
|
|
||||||
if (ret) {
|
|
||||||
*errmsg = o->errmsg;
|
|
||||||
o->errmsg = NULL;
|
|
||||||
ddlpa_destroy(&o);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DDLPA_C_STANDALONE
|
|
||||||
|
|
||||||
/* ----------------------------- Test / Demo -------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
struct ddlpa_lock *lck = NULL;
|
|
||||||
char *errmsg = NULL, *opened_path = NULL, *my_path = NULL;
|
|
||||||
int i, ret, fd = -1, duration = -1, bus = -1, target = -1, lun = -1;
|
|
||||||
|
|
||||||
if (argc < 3) {
|
|
||||||
usage:;
|
|
||||||
fprintf(stderr, "usage: %s device_path duration\n", argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
my_path = argv[1];
|
|
||||||
sscanf(argv[2], "%d", &duration);
|
|
||||||
if (duration < 0)
|
|
||||||
goto usage;
|
|
||||||
|
|
||||||
|
|
||||||
/* For our purpose, only O_RDWR is a suitable access mode.
|
|
||||||
But in order to allow experiments, o_flags are freely adjustable.
|
|
||||||
|
|
||||||
Warning: Do _not_ set an own O_EXCL flag with the following calls !
|
|
||||||
|
|
||||||
(This freedom to fail may get removed in a final version.)
|
|
||||||
*/
|
|
||||||
if (my_path[0] != '/' && my_path[0] != '.' &&
|
|
||||||
strchr(my_path, ',') != NULL) {
|
|
||||||
/*
|
|
||||||
cdrecord style dev=Bus,Target,Lun
|
|
||||||
*/
|
|
||||||
|
|
||||||
sscanf(my_path, "%d,%d,%d", &bus, &target, &lun);
|
|
||||||
ret = ddlpa_lock_btl(bus, target, lun, O_RDWR | O_LARGEFILE,
|
|
||||||
0, &lck, &errmsg);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
This substitutes for:
|
|
||||||
fd = open(my_path, O_RDWR | O_EXCL | O_LARGEFILE);
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
ret = ddlpa_lock_path(my_path, O_RDWR | O_LARGEFILE,
|
|
||||||
0, &lck, &errmsg);
|
|
||||||
}
|
|
||||||
if (ret) {
|
|
||||||
fprintf(stderr, "Cannot exclusively open '%s'\n", my_path);
|
|
||||||
if (errmsg != NULL)
|
|
||||||
fprintf(stderr, "Reason given : %s\n",
|
|
||||||
errmsg);
|
|
||||||
free(errmsg);
|
|
||||||
fprintf(stderr, "Error condition : %d '%s'\n",
|
|
||||||
ret, strerror(ret));
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
fd = lck->fd;
|
|
||||||
|
|
||||||
printf("---------------------------------------------- Lock gained\n");
|
|
||||||
|
|
||||||
|
|
||||||
/* Use fd for the usual operations on the device depicted by my_path.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* This prints an overview of the impact of the lock */
|
|
||||||
if (lck->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
|
||||||
opened_path = lck->path;
|
|
||||||
else
|
|
||||||
opened_path = lck->std_path;
|
|
||||||
printf("ddlpa: opened %s", opened_path);
|
|
||||||
|
|
||||||
if (strcmp(opened_path, lck->std_path) != 0)
|
|
||||||
printf(" (an alias of '%s')", lck->std_path);
|
|
||||||
printf("\n");
|
|
||||||
if (lck->num_siblings > 0) {
|
|
||||||
printf("ddlpa: opened siblings:");
|
|
||||||
for (i = 0; i < lck->num_siblings; i++)
|
|
||||||
if (lck->sibling_fds[i] != -1)
|
|
||||||
printf(" %s", lck->sibling_paths[i]);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This example waits a while. So other lock candidates can collide. */
|
|
||||||
for (i = 0; i < duration; i++) {
|
|
||||||
sleep(1);
|
|
||||||
fprintf(stderr, "\rslept %d seconds of %d", i + 1, duration);
|
|
||||||
}
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
|
|
||||||
|
|
||||||
/* When finally done with the drive, this substitutes for:
|
|
||||||
close(fd);
|
|
||||||
*/
|
|
||||||
if (ddlpa_destroy(&lck)) {
|
|
||||||
/* Well, man 2 close says it can fail. */
|
|
||||||
exit(3);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* DDLPA_C_STANDALONE */
|
|
||||||
|
|
107
libburn/ddlpa.h
107
libburn/ddlpa.h
@ -1,107 +0,0 @@
|
|||||||
|
|
||||||
/* ddlpa
|
|
||||||
Implementation of Delicate Device Locking Protocol level A.
|
|
||||||
Copyright (C) 2007 Thomas Schmitt <scdbackup@gmx.net>
|
|
||||||
Provided under any of the following licenses: GPL, LGPL, BSD. Choose one.
|
|
||||||
|
|
||||||
See ../doc/ddlp.txt for a description of the protocol.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DDLPA_H_INCLUDED
|
|
||||||
#define DDLPA_H_INCLUDED 1
|
|
||||||
|
|
||||||
|
|
||||||
/* An upper limit for the length of standard paths and sibling paths */
|
|
||||||
#define DDLPA_MAX_STD_LEN 15
|
|
||||||
|
|
||||||
/* An upper limit for the number of siblings */
|
|
||||||
#define DDLPA_MAX_SIBLINGS 5
|
|
||||||
|
|
||||||
struct ddlpa_lock {
|
|
||||||
|
|
||||||
/* Recorded input parameters of locking call */
|
|
||||||
char *path;
|
|
||||||
int path_is_valid;
|
|
||||||
int in_bus, in_target, in_lun;
|
|
||||||
int inbtl_is_valid;
|
|
||||||
int ddlpa_flags;
|
|
||||||
int o_flags;
|
|
||||||
|
|
||||||
/* Result of locking call */
|
|
||||||
char std_path[DDLPA_MAX_STD_LEN + 1];
|
|
||||||
int fd;
|
|
||||||
dev_t rdev;
|
|
||||||
dev_t dev;
|
|
||||||
ino_t ino;
|
|
||||||
int host, channel, id, lun, bus;
|
|
||||||
int hcilb_is_valid;
|
|
||||||
int num_siblings;
|
|
||||||
char sibling_paths[DDLPA_MAX_SIBLINGS][DDLPA_MAX_STD_LEN + 1];
|
|
||||||
int sibling_fds[DDLPA_MAX_SIBLINGS];
|
|
||||||
dev_t sibling_rdevs[DDLPA_MAX_SIBLINGS];
|
|
||||||
dev_t sibling_devs[DDLPA_MAX_SIBLINGS];
|
|
||||||
ino_t sibling_inodes[DDLPA_MAX_SIBLINGS];
|
|
||||||
|
|
||||||
/* Is NULL if all goes well. Else it may contain a text message. */
|
|
||||||
char *errmsg;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Lock a recorder by naming a device file path. Allocate a new container.
|
|
||||||
@param path Gives the file system path of the recorder
|
|
||||||
as known to the calling program.
|
|
||||||
@param o_flags flags for open(2). Do not use O_EXCL here because this
|
|
||||||
is done automatically whenever appropriate.
|
|
||||||
Advised is O_RDWR | O_LARGEFILE, eventually | O_NDELAY.
|
|
||||||
@param ddlpa_flags 0 = default behavior: the standard path will be opened
|
|
||||||
and treated by fcntl(F_SETLK)
|
|
||||||
DDLPA_OPEN_GIVEN_PATH causes the input parameter "path"
|
|
||||||
to be used with open(2) and fcntl(2).
|
|
||||||
DDLPA_ALLOW_MISSING_SGRCD allows to grant a lock
|
|
||||||
although not all three, a sg, a sr and a scd device
|
|
||||||
file have been found during sibling search. Normally
|
|
||||||
this is counted as failure due to EBUSY.
|
|
||||||
@param lockbundle gets allocated and then represents the locking state
|
|
||||||
@param errmsg if *errmsg is not NULL after the call, it contains an
|
|
||||||
error message. Then to be released by free(3).
|
|
||||||
It is NULL in case of success or lack of memory.
|
|
||||||
@return 0=success , else an errno compatible error number
|
|
||||||
*/
|
|
||||||
int ddlpa_lock_path(char *path, int o_flags, int ddlpa_flags,
|
|
||||||
struct ddlpa_lock **lockbundle, char **errmsg);
|
|
||||||
|
|
||||||
|
|
||||||
/** Lock a recorder by naming a Bus,Target,Lun number triple.
|
|
||||||
Allocate a new container.
|
|
||||||
@param bus parameter to match ioctl(SCSI_IOCTL_GET_BUS_NUMBER)
|
|
||||||
@param target parameter to match ioctl(SCSI_IOCTL_GET_IDLUN) &0xff
|
|
||||||
@param lun parameter to match ioctl(SCSI_IOCTL_GET_IDLUN) &0xff00
|
|
||||||
@param o_flags see ddlpa_lock_path().
|
|
||||||
@param ddlpa_flags see ddlpa_lock_path(). Flag DDLPA_OPEN_GIVEN_PATH
|
|
||||||
will be ignored.
|
|
||||||
@param lockbundle see ddlpa_lock_path().
|
|
||||||
@param errmsg see ddlpa_lock_path().
|
|
||||||
@return 0=success , else an errno compatible error number
|
|
||||||
*/
|
|
||||||
int ddlpa_lock_btl(int bus, int target, int lun,
|
|
||||||
int o_flags, int ddlpa_flags,
|
|
||||||
struct ddlpa_lock **lockbundle, char **errmsg);
|
|
||||||
|
|
||||||
|
|
||||||
/** Release the lock by closing all filedescriptors and freeing memory.
|
|
||||||
@param lockbundle the lock which is to be released.
|
|
||||||
*lockbundle will be set to NULL by this call.
|
|
||||||
@return 0=success , 1=failure
|
|
||||||
*/
|
|
||||||
int ddlpa_destroy(struct ddlpa_lock **lockbundle);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Definitions of macros used in above functions */
|
|
||||||
|
|
||||||
#define DDLPA_OPEN_GIVEN_PATH 1
|
|
||||||
#define DDLPA_ALLOW_MISSING_SGRCD 2
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* DDLPA_H_INCLUDED */
|
|
@ -1,35 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
static int burn_verbosity = 0;
|
|
||||||
|
|
||||||
void burn_set_verbosity(int v)
|
|
||||||
{
|
|
||||||
burn_verbosity = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_print(int level, const char *a, ...)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
char debug_string_data[256];
|
|
||||||
#endif
|
|
||||||
va_list vl;
|
|
||||||
|
|
||||||
if (level <= burn_verbosity) {
|
|
||||||
va_start(vl, a);
|
|
||||||
#ifdef WIN32
|
|
||||||
vsprintf(debug_string_data, a, vl);
|
|
||||||
OutputDebugString(debug_string_data);
|
|
||||||
#else
|
|
||||||
vfprintf(stderr, a, vl);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef BURN__DEBUG_H
|
|
||||||
#define BURN__DEBUG_H
|
|
||||||
|
|
||||||
void burn_print(int level, const char *a, ...);
|
|
||||||
|
|
||||||
#endif /* BURN__DEBUG_H */
|
|
2469
libburn/drive.c
2469
libburn/drive.c
File diff suppressed because it is too large
Load Diff
128
libburn/drive.h
128
libburn/drive.h
@ -1,128 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __DRIVE
|
|
||||||
#define __DRIVE
|
|
||||||
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "toc.h"
|
|
||||||
#include "structure.h"
|
|
||||||
|
|
||||||
struct burn_drive;
|
|
||||||
struct command;
|
|
||||||
struct mempage;
|
|
||||||
struct scsi_mode_data;
|
|
||||||
struct burn_speed_descriptor;
|
|
||||||
|
|
||||||
#define LEAD_IN 1
|
|
||||||
#define GAP 2
|
|
||||||
#define USER_DATA 3
|
|
||||||
#define LEAD_OUT 4
|
|
||||||
#define SYNC 5
|
|
||||||
|
|
||||||
#define SESSION_LEADOUT_ENTRY(d,s) (d)->toc->session[(s)].leadout_entry
|
|
||||||
|
|
||||||
#define CURRENT_SESSION_START(d) \
|
|
||||||
burn_msf_to_lba(d->toc->session[d->currsession].start_m, \
|
|
||||||
d->toc->session[d->currsession].start_s, \
|
|
||||||
d->toc->session[d->currsession].start_f)
|
|
||||||
|
|
||||||
#define SESSION_END(d,s) \
|
|
||||||
TOC_ENTRY_PLBA((d)->toc, SESSION_LEADOUT_ENTRY((d), (s)))
|
|
||||||
|
|
||||||
#define PREVIOUS_SESSION_END(d) \
|
|
||||||
TOC_ENTRY_PLBA((d)->toc, SESSION_LEADOUT_ENTRY((d), (d)->currsession-1))
|
|
||||||
|
|
||||||
#define LAST_SESSION_END(d) \
|
|
||||||
TOC_ENTRY_PLBA((d)->toc, \
|
|
||||||
SESSION_LEADOUT_ENTRY((d), (d)->toc->sessions-1))
|
|
||||||
|
|
||||||
struct burn_drive *burn_drive_register(struct burn_drive *);
|
|
||||||
int burn_drive_unregister(struct burn_drive *d);
|
|
||||||
|
|
||||||
unsigned int burn_drive_count(void);
|
|
||||||
|
|
||||||
/* ts A61007 */
|
|
||||||
/* void burn_wait_all(void); */
|
|
||||||
/* @param flag bit0= demand freed drives (else released drives) */
|
|
||||||
int burn_drives_are_clear(int flag);
|
|
||||||
|
|
||||||
int burn_sector_length_write(struct burn_drive *d);
|
|
||||||
int burn_track_control(struct burn_drive *d, int);
|
|
||||||
void burn_write_empty_sector(int fd);
|
|
||||||
void burn_write_empty_subcode(int fd);
|
|
||||||
void burn_drive_free(struct burn_drive *d);
|
|
||||||
void burn_drive_free_all(void);
|
|
||||||
|
|
||||||
/* @param flag bit0= reset global drive list */
|
|
||||||
int burn_drive_scan_sync(struct burn_drive_info *drives[],
|
|
||||||
unsigned int *n_drives, int flag);
|
|
||||||
|
|
||||||
void burn_disc_erase_sync(struct burn_drive *d, int fast);
|
|
||||||
int burn_drive_get_block_types(struct burn_drive *d,
|
|
||||||
enum burn_write_types write_type);
|
|
||||||
|
|
||||||
int burn_drive_is_open(struct burn_drive *d);
|
|
||||||
int burn_drive_is_occupied(struct burn_drive *d);
|
|
||||||
int burn_drive_forget(struct burn_drive *d, int force);
|
|
||||||
int burn_drive_convert_fs_adr_sub(char *path, char adr[], int *rec_count);
|
|
||||||
|
|
||||||
/* ts A61021 : the unspecific part of sg.c:enumerate_common()
|
|
||||||
*/
|
|
||||||
int burn_setup_drive(struct burn_drive *d, char *fname);
|
|
||||||
|
|
||||||
/* ts A61021 : after-setup activities from sg.c:enumerate_common()
|
|
||||||
*/
|
|
||||||
struct burn_drive *burn_drive_finish_enum(struct burn_drive *d);
|
|
||||||
|
|
||||||
/* ts A61125 : media status aspects of burn_drive_grab() */
|
|
||||||
int burn_drive_inquire_media(struct burn_drive *d);
|
|
||||||
|
|
||||||
/* ts A61125 : model aspects of burn_drive_release */
|
|
||||||
int burn_drive_mark_unready(struct burn_drive *d);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61226 */
|
|
||||||
int burn_speed_descriptor_new(struct burn_speed_descriptor **s,
|
|
||||||
struct burn_speed_descriptor *prev,
|
|
||||||
struct burn_speed_descriptor *next, int flag);
|
|
||||||
|
|
||||||
/* ts A61226 */
|
|
||||||
/* @param flag bit0= destroy whole next-chain of descriptors */
|
|
||||||
int burn_speed_descriptor_destroy(struct burn_speed_descriptor **s, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61226 : free dynamically allocated sub data of struct scsi_mode_data */
|
|
||||||
int burn_mdata_free_subs(struct scsi_mode_data *m);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61230 */
|
|
||||||
void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70207 : evaluate write mode related peculiarities of a disc */
|
|
||||||
struct burn_disc_mode_demands {
|
|
||||||
int multi_session;
|
|
||||||
int multi_track;
|
|
||||||
int unknown_track_size; /* 0=known, 1=unknown, 2=unknown+defaulted */
|
|
||||||
int mixed_mode;
|
|
||||||
int audio;
|
|
||||||
int exotic_track;
|
|
||||||
int block_types;
|
|
||||||
int will_append; /* because of media state or multi session disc */
|
|
||||||
};
|
|
||||||
int burn_disc_get_write_mode_demands(struct burn_disc *disc,
|
|
||||||
struct burn_write_opts *opts,
|
|
||||||
struct burn_disc_mode_demands *result, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70924 : convert a special stdio address into fd number.
|
|
||||||
@return >0 is a valid fd , -1 indicates unsuitable address string.
|
|
||||||
*/
|
|
||||||
int burn_drive__fd_from_special_adr(char *adr);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70929 : Find the drive which is being worked on by pid */
|
|
||||||
int burn_drive_find_by_thread_pid(struct burn_drive **d, pid_t pid);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __DRIVE */
|
|
@ -1,8 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode; t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __ERROR_H
|
|
||||||
#define __ERROR_H
|
|
||||||
|
|
||||||
#define BE_CANCELLED 1
|
|
||||||
|
|
||||||
#endif /* __ERROR_H */
|
|
542
libburn/file.c
542
libburn/file.c
@ -1,542 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include "source.h"
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "file.h"
|
|
||||||
#include "async.h"
|
|
||||||
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
|
|
||||||
/* main channel data can be padded on read, but 0 padding the subs will make
|
|
||||||
an unreadable disc */
|
|
||||||
|
|
||||||
|
|
||||||
/* This is a generic OS oriented function wrapper which compensates
|
|
||||||
shortcommings of read() in respect to a guaranteed amount of return data.
|
|
||||||
See man 2 read , paragraph "RETURN VALUE".
|
|
||||||
Possibly libburn/file.c is not the right storage location for this.
|
|
||||||
To make it ready for a move, this function is not declared static.
|
|
||||||
*/
|
|
||||||
static int read_full_buffer(int fd, unsigned char *buffer, int size)
|
|
||||||
{
|
|
||||||
int ret,summed_ret = 0;
|
|
||||||
|
|
||||||
/* make safe against partial buffer returns */
|
|
||||||
while (1) {
|
|
||||||
ret = read(fd, buffer + summed_ret, size - summed_ret);
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
summed_ret += ret;
|
|
||||||
if (summed_ret >= size)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ret < 0) /* error encountered. abort immediately */
|
|
||||||
return ret;
|
|
||||||
return summed_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int file_read(struct burn_source *source,
|
|
||||||
unsigned char *buffer,
|
|
||||||
int size)
|
|
||||||
{
|
|
||||||
struct burn_source_file *fs = source->data;
|
|
||||||
|
|
||||||
return read_full_buffer(fs->datafd, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int file_read_sub(struct burn_source *source,
|
|
||||||
unsigned char *buffer,
|
|
||||||
int size)
|
|
||||||
{
|
|
||||||
struct burn_source_file *fs = source->data;
|
|
||||||
|
|
||||||
return read_full_buffer(fs->subfd, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void file_free(struct burn_source *source)
|
|
||||||
{
|
|
||||||
struct burn_source_file *fs = source->data;
|
|
||||||
|
|
||||||
close(fs->datafd);
|
|
||||||
if (source->read_sub)
|
|
||||||
close(fs->subfd);
|
|
||||||
free(fs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static off_t file_size(struct burn_source *source)
|
|
||||||
{
|
|
||||||
struct stat buf;
|
|
||||||
struct burn_source_file *fs = source->data;
|
|
||||||
|
|
||||||
if (fs->fixed_size > 0)
|
|
||||||
return fs->fixed_size;
|
|
||||||
if (fstat(fs->datafd, &buf) == -1)
|
|
||||||
return (off_t) 0;
|
|
||||||
return (off_t) buf.st_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70125 */
|
|
||||||
static int file_set_size(struct burn_source *source, off_t size)
|
|
||||||
{
|
|
||||||
struct burn_source_file *fs = source->data;
|
|
||||||
|
|
||||||
fs->fixed_size = size;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct burn_source *burn_file_source_new(const char *path, const char *subpath)
|
|
||||||
{
|
|
||||||
struct burn_source_file *fs;
|
|
||||||
struct burn_source *src;
|
|
||||||
int fd1 = -1, fd2 = -1;
|
|
||||||
|
|
||||||
if (!path)
|
|
||||||
return NULL;
|
|
||||||
fd1 = open(path, O_RDONLY);
|
|
||||||
if (fd1 == -1)
|
|
||||||
return NULL;
|
|
||||||
if (subpath != NULL) {
|
|
||||||
fd2 = open(subpath, O_RDONLY);
|
|
||||||
if (fd2 == -1) {
|
|
||||||
close(fd1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fs = malloc(sizeof(struct burn_source_file));
|
|
||||||
|
|
||||||
/* ts A70825 */
|
|
||||||
if (fs == NULL) {
|
|
||||||
failure:;
|
|
||||||
close(fd1);
|
|
||||||
if (fd2 >= 0)
|
|
||||||
close(fd2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs->datafd = fd1;
|
|
||||||
fs->subfd = fd2;
|
|
||||||
|
|
||||||
/* ts A70125 */
|
|
||||||
fs->fixed_size = 0;
|
|
||||||
|
|
||||||
src = burn_source_new();
|
|
||||||
|
|
||||||
/* ts A70825 */
|
|
||||||
if (src == NULL) {
|
|
||||||
free((char *) fs);
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
src->read = file_read;
|
|
||||||
if (subpath)
|
|
||||||
src->read_sub = file_read_sub;
|
|
||||||
|
|
||||||
src->get_size = file_size;
|
|
||||||
src->set_size = file_set_size;
|
|
||||||
src->free_data = file_free;
|
|
||||||
src->data = fs;
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70126 : removed class burn_source_fd in favor of burn_source_file */
|
|
||||||
|
|
||||||
struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size)
|
|
||||||
{
|
|
||||||
struct burn_source_file *fs;
|
|
||||||
struct burn_source *src;
|
|
||||||
|
|
||||||
if (datafd == -1)
|
|
||||||
return NULL;
|
|
||||||
fs = malloc(sizeof(struct burn_source_file));
|
|
||||||
if (fs == NULL) /* ts A70825 */
|
|
||||||
return NULL;
|
|
||||||
fs->datafd = datafd;
|
|
||||||
fs->subfd = subfd;
|
|
||||||
fs->fixed_size = size;
|
|
||||||
|
|
||||||
src = burn_source_new();
|
|
||||||
|
|
||||||
/* ts A70825 */
|
|
||||||
if (src == NULL) {
|
|
||||||
free((char *) fs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
src->read = file_read;
|
|
||||||
if(subfd != -1)
|
|
||||||
src->read_sub = file_read_sub;
|
|
||||||
src->get_size = file_size;
|
|
||||||
src->set_size = file_set_size;
|
|
||||||
src->free_data = file_free;
|
|
||||||
src->data = fs;
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A71003 */
|
|
||||||
/* ------------------------------ fifo --------------------------- */
|
|
||||||
|
|
||||||
/* The fifo mechanism consists of a burn_source proxy which is here,
|
|
||||||
a thread management team which is located in async.c,
|
|
||||||
and a synchronous shoveller which is here.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int fifo_sleep(int flag)
|
|
||||||
{
|
|
||||||
static struct timespec sleeptime = { 0, 50000000}; /* 50 ms */
|
|
||||||
|
|
||||||
return nanosleep(&sleeptime, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int fifo_read(struct burn_source *source,
|
|
||||||
unsigned char *buffer,
|
|
||||||
int size)
|
|
||||||
{
|
|
||||||
struct burn_source_fifo *fs = source->data;
|
|
||||||
int ret, todo, rpos, bufsize, diff;
|
|
||||||
|
|
||||||
if (fs->end_of_consumption) {
|
|
||||||
/* ??? msg: reading has been ended already */;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (fs->is_started == 0) {
|
|
||||||
ret = burn_fifo_start(source, 0);
|
|
||||||
if (ret <= 0) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020152,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Cannot start fifo thread", 0, 0);
|
|
||||||
fs->end_of_consumption = 1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fs->is_started = 1;
|
|
||||||
}
|
|
||||||
if (size == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Reading from the ring buffer */
|
|
||||||
|
|
||||||
/* This needs no mutex because each volatile variable has one thread
|
|
||||||
which may write and the other which only reads and is aware of
|
|
||||||
volatility.
|
|
||||||
The feeder of the ringbuffer is in burn_fifo_source_shoveller().
|
|
||||||
*/
|
|
||||||
todo = size;
|
|
||||||
bufsize = fs->chunksize * fs->chunks;
|
|
||||||
while (todo > 0) {
|
|
||||||
/* readpos is not volatile here , writepos is volatile */
|
|
||||||
rpos = fs->buf_readpos;
|
|
||||||
while (rpos == fs->buf_writepos) {
|
|
||||||
if (fs->end_of_input)
|
|
||||||
break;
|
|
||||||
if (fs->input_error) {
|
|
||||||
if (todo < size) /* deliver partial buffer */
|
|
||||||
break;
|
|
||||||
fs->end_of_consumption = 1;
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1,
|
|
||||||
0x00020154,
|
|
||||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Forwarded input error ends output", 0, 0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fifo_sleep(0);
|
|
||||||
}
|
|
||||||
diff = fs->buf_writepos - rpos; /* read volatile only once */
|
|
||||||
if (diff == 0)
|
|
||||||
break;
|
|
||||||
if (diff > 0)
|
|
||||||
/* diff bytes are available */;
|
|
||||||
else
|
|
||||||
/* at least (bufsize - rpos) bytes are available */
|
|
||||||
diff = bufsize - rpos;
|
|
||||||
if (diff > todo)
|
|
||||||
diff = todo;
|
|
||||||
memcpy(buffer, fs->buf+(size-todo)+rpos, diff);
|
|
||||||
fs->buf_readpos += diff;
|
|
||||||
if (fs->buf_readpos >= bufsize)
|
|
||||||
fs->buf_readpos = 0;
|
|
||||||
todo -= diff;
|
|
||||||
}
|
|
||||||
if (size - todo <= 0)
|
|
||||||
fs->end_of_consumption = 1;
|
|
||||||
else
|
|
||||||
fs->out_counter += size - todo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
fprintf(stderr,
|
|
||||||
"libburn_EXPERIMENTAL: read= %d , pos= %d , out_count= %.f\n",
|
|
||||||
(size - todo), fs->buf_readpos, (double) fs->out_counter);
|
|
||||||
*/
|
|
||||||
|
|
||||||
return (size - todo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static off_t fifo_get_size(struct burn_source *source)
|
|
||||||
{
|
|
||||||
struct burn_source_fifo *fs = source->data;
|
|
||||||
|
|
||||||
return fs->inp->get_size(fs->inp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int fifo_set_size(struct burn_source *source, off_t size)
|
|
||||||
{
|
|
||||||
struct burn_source_fifo *fs = source->data;
|
|
||||||
|
|
||||||
return fs->inp->set_size(fs->inp, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void fifo_free(struct burn_source *source)
|
|
||||||
{
|
|
||||||
struct burn_source_fifo *fs = source->data;
|
|
||||||
|
|
||||||
if (fs->inp != NULL)
|
|
||||||
burn_source_free(fs->inp);
|
|
||||||
if (fs->buf != NULL)
|
|
||||||
free(fs->buf);
|
|
||||||
free((char *) fs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int burn_fifo_source_shoveller(struct burn_source *source, int flag)
|
|
||||||
{
|
|
||||||
struct burn_source_fifo *fs = source->data;
|
|
||||||
int ret, bufsize, diff, wpos, rpos, trans_end, free_bytes;
|
|
||||||
char *bufpt;
|
|
||||||
|
|
||||||
fs->thread_pid = getpid();
|
|
||||||
fs->thread_pid_valid = 1;
|
|
||||||
|
|
||||||
bufsize = fs->chunksize * fs->chunks;
|
|
||||||
while (!fs->end_of_consumption) {
|
|
||||||
|
|
||||||
/* wait for enough buffer space available */
|
|
||||||
wpos = fs->buf_writepos;
|
|
||||||
while (1) {
|
|
||||||
rpos = fs->buf_readpos;
|
|
||||||
diff = rpos - wpos;
|
|
||||||
trans_end = 0;
|
|
||||||
if (diff == 0)
|
|
||||||
free_bytes = bufsize - 1;
|
|
||||||
else if (diff > 0)
|
|
||||||
free_bytes = diff - 1;
|
|
||||||
else {
|
|
||||||
free_bytes = (bufsize - wpos) + rpos - 1;
|
|
||||||
if (bufsize - wpos < fs->chunksize)
|
|
||||||
trans_end = 1;
|
|
||||||
}
|
|
||||||
if (free_bytes >= fs->chunksize)
|
|
||||||
break;
|
|
||||||
fifo_sleep(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prepare the receiving memory */
|
|
||||||
bufpt = fs->buf + wpos;
|
|
||||||
if (trans_end) {
|
|
||||||
bufpt = calloc(fs->chunksize, 1);
|
|
||||||
if (bufpt == NULL) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1,
|
|
||||||
0x00000003,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Out of virtual memory", 0, 0);
|
|
||||||
fs->input_error = ENOMEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain next chunk */
|
|
||||||
if (fs->inp->read != NULL)
|
|
||||||
ret = fs->inp->read(fs->inp,
|
|
||||||
(unsigned char *) bufpt, fs->chunksize);
|
|
||||||
else
|
|
||||||
ret = fs->inp->read_xt( fs->inp,
|
|
||||||
(unsigned char *) bufpt, fs->chunksize);
|
|
||||||
if (ret > 0)
|
|
||||||
fs->in_counter += ret;
|
|
||||||
else if (ret == 0)
|
|
||||||
break; /* EOF */
|
|
||||||
else {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020153,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Read error on fifo input", errno, 0);
|
|
||||||
fs->input_error = errno;
|
|
||||||
if(errno == 0)
|
|
||||||
fs->input_error = EIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* activate read chunk */
|
|
||||||
if (ret > fs->chunksize) /* beware of ill custom burn_source */
|
|
||||||
ret = fs->chunksize;
|
|
||||||
if (trans_end) {
|
|
||||||
/* copy to end of buffer */
|
|
||||||
memcpy(fs->buf + wpos, bufpt, bufsize - wpos);
|
|
||||||
/* copy to start of buffer */
|
|
||||||
memcpy(fs->buf, bufpt + (bufsize - wpos),
|
|
||||||
fs->chunksize - (bufsize - wpos));
|
|
||||||
free(bufpt);
|
|
||||||
if (ret >= bufsize - wpos)
|
|
||||||
fs->buf_writepos = ret - (bufsize - wpos);
|
|
||||||
else
|
|
||||||
fs->buf_writepos += ret;
|
|
||||||
} else if (fs->buf_writepos + ret == bufsize)
|
|
||||||
fs->buf_writepos = 0;
|
|
||||||
else
|
|
||||||
fs->buf_writepos += ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
fprintf(stderr, "[%2.2d%%] ",
|
|
||||||
(int) (100.0 - 100.0 * ((double) free_bytes) /
|
|
||||||
(double) bufsize));
|
|
||||||
fprintf(stderr,
|
|
||||||
"libburn_EXPERIMENTAL: writepos= %d ,in_count = %.f\n",
|
|
||||||
fs->buf_writepos, (double) fs->in_counter);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
if (!fs->end_of_consumption)
|
|
||||||
fs->end_of_input = 1;
|
|
||||||
|
|
||||||
/* wait for end of reading by consumer */;
|
|
||||||
while (fs->buf_readpos != fs->buf_writepos && !fs->end_of_consumption)
|
|
||||||
fifo_sleep(0);
|
|
||||||
|
|
||||||
/* destroy ring buffer */;
|
|
||||||
if (!fs->end_of_consumption)
|
|
||||||
fs->end_of_consumption = 2; /* Claim stop of consumption */
|
|
||||||
|
|
||||||
/* This is not prone to race conditions because either the consumer
|
|
||||||
indicated hangup by fs->end_of_consumption = 1 or the consumer set
|
|
||||||
fs->buf_readpos to a value indicating the buffer is empty.
|
|
||||||
So in both cases the consumer is aware that reading is futile
|
|
||||||
or even fatal.
|
|
||||||
*/
|
|
||||||
free(fs->buf); /* Give up fifo buffer. Next fifo might start soon. */
|
|
||||||
fs->buf = NULL;
|
|
||||||
|
|
||||||
return (fs->input_error == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int burn_fifo_cancel(struct burn_source *source)
|
|
||||||
{
|
|
||||||
struct burn_source_fifo *fs = source->data;
|
|
||||||
|
|
||||||
burn_source_cancel(fs->inp);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct burn_source *burn_fifo_source_new(struct burn_source *inp,
|
|
||||||
int chunksize, int chunks, int flag)
|
|
||||||
{
|
|
||||||
struct burn_source_fifo *fs;
|
|
||||||
struct burn_source *src;
|
|
||||||
|
|
||||||
if (((double) chunksize) * ((double) chunks) > 1024.0*1024.0*1024.0) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020155,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Desired fifo buffer too large (> 1GB)", 0, 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (chunksize < 1 || chunks < 2) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020156,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Desired fifo buffer too small", 0, 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
fs = malloc(sizeof(struct burn_source_fifo));
|
|
||||||
if (fs == NULL)
|
|
||||||
return NULL;
|
|
||||||
fs->is_started = 0;
|
|
||||||
fs->thread_pid = 0;
|
|
||||||
fs->thread_pid_valid = 0;
|
|
||||||
fs->inp = NULL; /* set later */
|
|
||||||
fs->chunksize = chunksize;
|
|
||||||
fs->chunks = chunks;
|
|
||||||
fs->buf = NULL;
|
|
||||||
fs->buf_writepos = fs->buf_readpos = 0;
|
|
||||||
fs->end_of_input = 0;
|
|
||||||
fs->input_error = 0;
|
|
||||||
fs->end_of_consumption = 0;
|
|
||||||
fs->in_counter = fs->out_counter = 0;
|
|
||||||
|
|
||||||
src = burn_source_new();
|
|
||||||
if (src == NULL) {
|
|
||||||
free((char *) fs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
src->read = NULL;
|
|
||||||
src->read_sub = NULL;
|
|
||||||
src->get_size = fifo_get_size;
|
|
||||||
src->set_size = fifo_set_size;
|
|
||||||
src->free_data = fifo_free;
|
|
||||||
src->data = fs;
|
|
||||||
src->version= 1;
|
|
||||||
src->read_xt = fifo_read;
|
|
||||||
src->cancel= burn_fifo_cancel;
|
|
||||||
fs->inp = inp;
|
|
||||||
inp->refcount++; /* make sure inp lives longer than src */
|
|
||||||
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A71003 : API */
|
|
||||||
int burn_fifo_inquire_status(struct burn_source *source,
|
|
||||||
int *size, int *free_bytes, char **status_text)
|
|
||||||
{
|
|
||||||
struct burn_source_fifo *fs = source->data;
|
|
||||||
int ret = 0, diff, wpos, rpos;
|
|
||||||
static char *(states[8]) = {
|
|
||||||
"standby", "active", "ending", "failing",
|
|
||||||
"unused", "abandoned", "ended", "aborted"};
|
|
||||||
|
|
||||||
*status_text = NULL;
|
|
||||||
*size = 0;
|
|
||||||
|
|
||||||
if (source->free_data != fifo_free) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020157,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"burn_source is not a fifo object", 0, 0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*size = fs->chunksize * fs->chunks;
|
|
||||||
rpos = fs->buf_readpos;
|
|
||||||
wpos = fs->buf_writepos;
|
|
||||||
diff = rpos - wpos;
|
|
||||||
if (diff == 0)
|
|
||||||
*free_bytes = *size - 1;
|
|
||||||
else if (diff > 0)
|
|
||||||
*free_bytes = diff - 1;
|
|
||||||
else
|
|
||||||
*free_bytes = (*size - wpos) + rpos - 1;
|
|
||||||
ret = 0;
|
|
||||||
if (fs->end_of_consumption > 0)
|
|
||||||
ret |= 4;
|
|
||||||
if (fs->input_error)
|
|
||||||
ret |= 3;
|
|
||||||
else if (fs->end_of_input)
|
|
||||||
ret |= 2;
|
|
||||||
else if(fs->buf != NULL)
|
|
||||||
ret |= 1;
|
|
||||||
*status_text = states[ret];
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef BURN__FILE_H
|
|
||||||
#define BURN__FILE_H
|
|
||||||
|
|
||||||
struct burn_source_file
|
|
||||||
{
|
|
||||||
char magic[4];
|
|
||||||
|
|
||||||
int datafd;
|
|
||||||
int subfd;
|
|
||||||
off_t fixed_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ts A70126 : burn_source_file obsoleted burn_source_fd */
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70930 */
|
|
||||||
struct burn_source_fifo {
|
|
||||||
char magic[4];
|
|
||||||
|
|
||||||
/* The fifo stays inactive and unequipped with eventual resources
|
|
||||||
until its read() method is called for the first time.
|
|
||||||
Only then burn_fifo_start() gets called, allocates the complete
|
|
||||||
resources, starts a thread with burn_fifo_source_shuffler()
|
|
||||||
which shuffles data and finally destroys the resources.
|
|
||||||
This late start is to stay modest in case of multiple tracks
|
|
||||||
in one disc.
|
|
||||||
*/
|
|
||||||
int is_started;
|
|
||||||
|
|
||||||
int thread_pid;
|
|
||||||
int thread_pid_valid;
|
|
||||||
|
|
||||||
/* the burn_source for which this fifo is acting as proxy */
|
|
||||||
struct burn_source *inp;
|
|
||||||
|
|
||||||
/* <<< up to now it was only a pipe. This is on its way out. */
|
|
||||||
int outlet[2];
|
|
||||||
|
|
||||||
/* The ring buffer mechanism */
|
|
||||||
int chunksize;
|
|
||||||
int chunks;
|
|
||||||
char *buf;
|
|
||||||
volatile int buf_writepos;
|
|
||||||
volatile int buf_readpos;
|
|
||||||
volatile int end_of_input;
|
|
||||||
volatile int input_error;
|
|
||||||
volatile int end_of_consumption;
|
|
||||||
|
|
||||||
off_t in_counter;
|
|
||||||
off_t out_counter;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** The worker behind the fifo thread.
|
|
||||||
Gets started from burn_fifo_start() in async.c
|
|
||||||
*/
|
|
||||||
int burn_fifo_source_shoveller(struct burn_source *source, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* LIBBURN__FILE_H */
|
|
416
libburn/init.c
416
libburn/init.c
@ -1,416 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
/* ts A61007 */
|
|
||||||
/* #include <a ssert.h> */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* ts A70928 : init.h is for others, not for init .c
|
|
||||||
#include "init.h"
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "sg.h"
|
|
||||||
#include "error.h"
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "drive.h"
|
|
||||||
#include "transport.h"
|
|
||||||
|
|
||||||
/* ts A60825 : The storage location for back_hacks.h variables. */
|
|
||||||
#define BURN_BACK_HACKS_INIT 1
|
|
||||||
#include "back_hacks.h"
|
|
||||||
|
|
||||||
/* ts A60924 : a new message handling facility */
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
struct libdax_msgs *libdax_messenger= NULL;
|
|
||||||
|
|
||||||
|
|
||||||
int burn_running = 0;
|
|
||||||
|
|
||||||
/* ts A60813 : Linux: wether to use O_EXCL on open() of device files */
|
|
||||||
int burn_sg_open_o_excl = 1;
|
|
||||||
|
|
||||||
/* ts A70403 : Linux: wether to use fcntl(,F_SETLK,)
|
|
||||||
after open() of device files */
|
|
||||||
int burn_sg_fcntl_f_setlk = 1;
|
|
||||||
|
|
||||||
/* ts A70314 : Linux: what device family to use :
|
|
||||||
0= default family
|
|
||||||
1= sr
|
|
||||||
2= scd
|
|
||||||
(3= st)
|
|
||||||
4= sg
|
|
||||||
*/
|
|
||||||
int burn_sg_use_family = 0;
|
|
||||||
|
|
||||||
/* O_NONBLOCK was hardcoded in enumerate_ata() which i hardly use.
|
|
||||||
For enumerate_sg() it seems ok.
|
|
||||||
So it should stay default mode until enumerate_ata() without O_NONBLOCK
|
|
||||||
has been thoroughly tested. */
|
|
||||||
int burn_sg_open_o_nonblock = 1;
|
|
||||||
|
|
||||||
/* wether to take a busy drive as an error */
|
|
||||||
/* Caution: this is implemented by a rough hack and eventually leads
|
|
||||||
to unconditional abort of the process */
|
|
||||||
int burn_sg_open_abort_busy = 0;
|
|
||||||
|
|
||||||
/* ts A61002 */
|
|
||||||
|
|
||||||
#include "cleanup.h"
|
|
||||||
|
|
||||||
/* Parameters for builtin abort handler */
|
|
||||||
static char abort_message_prefix[81] = {"libburn : "};
|
|
||||||
static pid_t abort_control_pid= 0;
|
|
||||||
volatile int burn_global_abort_level= 0;
|
|
||||||
int burn_global_abort_signum= 0;
|
|
||||||
void *burn_global_signal_handle = NULL;
|
|
||||||
burn_abort_handler_t burn_global_signal_handler = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70223 : wether implemented untested profiles are supported */
|
|
||||||
int burn_support_untested_profiles = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60925 : ticket 74 */
|
|
||||||
/** Create the messenger object for libburn. */
|
|
||||||
int burn_msgs_initialize(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if(libdax_messenger == NULL) {
|
|
||||||
ret = libdax_msgs_new(&libdax_messenger,0);
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
libdax_msgs_set_severities(libdax_messenger, LIBDAX_MSGS_SEV_NEVER,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, "libburn: ", 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A60924 : ticket 74 : Added use of global libdax_messenger */
|
|
||||||
int burn_initialize(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (burn_running)
|
|
||||||
return 1;
|
|
||||||
burn_support_untested_profiles = 0;
|
|
||||||
ret = burn_msgs_initialize();
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
burn_running = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_finish(void)
|
|
||||||
{
|
|
||||||
/* ts A61007 : assume no messageing system */
|
|
||||||
/* a ssert(burn_running); */
|
|
||||||
if (!burn_running)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* ts A61007 */
|
|
||||||
/* burn_wait_all(); */
|
|
||||||
if (!burn_drives_are_clear(0)) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020107,
|
|
||||||
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"A drive is still busy on shutdown of library", 0, 0);
|
|
||||||
usleep(1000001);
|
|
||||||
burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A60904 : ticket 62, contribution by elmom : name addon "_all" */
|
|
||||||
burn_drive_free_all();
|
|
||||||
|
|
||||||
/* ts A60924 : ticket 74 */
|
|
||||||
libdax_msgs_destroy(&libdax_messenger,0);
|
|
||||||
|
|
||||||
burn_running = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60813 */
|
|
||||||
/** API function. See libburn.h */
|
|
||||||
void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy)
|
|
||||||
{
|
|
||||||
/* ts A61007 */
|
|
||||||
/* a ssert(burn_running); */
|
|
||||||
if (!burn_running)
|
|
||||||
return;
|
|
||||||
burn_sg_open_o_excl = exclusive & 3;
|
|
||||||
burn_sg_fcntl_f_setlk = !!(exclusive & 32);
|
|
||||||
burn_sg_use_family = (exclusive >> 2) & 7;
|
|
||||||
burn_sg_open_o_nonblock = !blocking;
|
|
||||||
burn_sg_open_abort_busy = !!abort_on_busy;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60924 : ticket 74 */
|
|
||||||
/** Control queueing and stderr printing of messages from libburn.
|
|
||||||
Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
|
||||||
"NOTE", "UPDATE", "DEBUG", "ALL".
|
|
||||||
@param queue_severity Gives the minimum limit for messages to be queued.
|
|
||||||
Default: "NEVER". If you queue messages then you
|
|
||||||
must consume them by burn_msgs_obtain().
|
|
||||||
@param print_severity Does the same for messages to be printed directly
|
|
||||||
to stderr.
|
|
||||||
@param print_id A text prefix to be printed before the message.
|
|
||||||
@return >0 for success, <=0 for error
|
|
||||||
|
|
||||||
*/
|
|
||||||
int burn_msgs_set_severities(char *queue_severity,
|
|
||||||
char *print_severity, char *print_id)
|
|
||||||
{
|
|
||||||
int ret, queue_sevno, print_sevno;
|
|
||||||
|
|
||||||
ret = libdax_msgs__text_to_sev(queue_severity, &queue_sevno, 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
ret = libdax_msgs__text_to_sev(print_severity, &print_sevno, 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
ret = libdax_msgs_set_severities(libdax_messenger, queue_sevno,
|
|
||||||
print_sevno, print_id, 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60924 : ticket 74 */
|
|
||||||
#define BURM_MSGS_MESSAGE_LEN 4096
|
|
||||||
|
|
||||||
/** Obtain the oldest pending libburn message from the queue which has at
|
|
||||||
least the given minimum_severity. This message and any older message of
|
|
||||||
lower severity will get discarded from the queue and is then lost forever.
|
|
||||||
Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
|
||||||
"NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
|
|
||||||
will discard the whole queue.
|
|
||||||
@param error_code Will become a unique error code as liste in
|
|
||||||
libburn/libdax_msgs.h
|
|
||||||
@param msg_text Must provide at least BURM_MSGS_MESSAGE_LEN bytes.
|
|
||||||
@param os_errno Will become the eventual errno related to the message
|
|
||||||
@param severity Will become the severity related to the message and
|
|
||||||
should provide at least 80 bytes.
|
|
||||||
@return 1 if a matching item was found, 0 if not, <0 for severe errors
|
|
||||||
*/
|
|
||||||
int burn_msgs_obtain(char *minimum_severity,
|
|
||||||
int *error_code, char msg_text[], int *os_errno,
|
|
||||||
char severity[])
|
|
||||||
{
|
|
||||||
int ret, minimum_sevno, sevno, priority;
|
|
||||||
char *textpt, *sev_name;
|
|
||||||
struct libdax_msgs_item *item = NULL;
|
|
||||||
|
|
||||||
ret = libdax_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
if (libdax_messenger == NULL)
|
|
||||||
return 0;
|
|
||||||
ret = libdax_msgs_obtain(libdax_messenger, &item, minimum_sevno,
|
|
||||||
LIBDAX_MSGS_PRIO_ZERO, 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
goto ex;
|
|
||||||
ret = libdax_msgs_item_get_msg(item, error_code, &textpt, os_errno, 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
goto ex;
|
|
||||||
strncpy(msg_text, textpt, BURM_MSGS_MESSAGE_LEN-1);
|
|
||||||
if(strlen(textpt) >= BURM_MSGS_MESSAGE_LEN)
|
|
||||||
msg_text[BURM_MSGS_MESSAGE_LEN-1] = 0;
|
|
||||||
|
|
||||||
severity[0]= 0;
|
|
||||||
ret = libdax_msgs_item_get_rank(item, &sevno, &priority, 0);
|
|
||||||
if(ret <= 0)
|
|
||||||
goto ex;
|
|
||||||
ret = libdax_msgs__sev_to_text(sevno, &sev_name, 0);
|
|
||||||
if(ret <= 0)
|
|
||||||
goto ex;
|
|
||||||
strcpy(severity,sev_name);
|
|
||||||
|
|
||||||
ret = 1;
|
|
||||||
ex:
|
|
||||||
libdax_msgs_destroy_item(libdax_messenger, &item, 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70922 : API */
|
|
||||||
int burn_msgs_submit(int error_code, char msg_text[], int os_errno,
|
|
||||||
char severity[], struct burn_drive *d)
|
|
||||||
{
|
|
||||||
int ret, sevno, global_index = -1;
|
|
||||||
|
|
||||||
ret = libdax_msgs__text_to_sev(severity, &sevno, 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
sevno = LIBDAX_MSGS_SEV_ALL;
|
|
||||||
if (error_code <= 0) {
|
|
||||||
switch(sevno) {
|
|
||||||
case LIBDAX_MSGS_SEV_ABORT: error_code = 0x00040000;
|
|
||||||
break; case LIBDAX_MSGS_SEV_FATAL: error_code = 0x00040001;
|
|
||||||
break; case LIBDAX_MSGS_SEV_SORRY: error_code = 0x00040002;
|
|
||||||
break; case LIBDAX_MSGS_SEV_WARNING: error_code = 0x00040003;
|
|
||||||
break; case LIBDAX_MSGS_SEV_HINT: error_code = 0x00040004;
|
|
||||||
break; case LIBDAX_MSGS_SEV_NOTE: error_code = 0x00040005;
|
|
||||||
break; case LIBDAX_MSGS_SEV_UPDATE: error_code = 0x00040006;
|
|
||||||
break; case LIBDAX_MSGS_SEV_DEBUG: error_code = 0x00040007;
|
|
||||||
break; default: error_code = 0x00040008;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d != NULL)
|
|
||||||
global_index = d->global_index;
|
|
||||||
ret = libdax_msgs_submit(libdax_messenger, global_index, error_code,
|
|
||||||
sevno, LIBDAX_MSGS_PRIO_HIGH, msg_text, os_errno, 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A71016 API */
|
|
||||||
int burn_text_to_sev(char *severity_name, int *sevno, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = libdax_msgs__text_to_sev(severity_name, sevno, 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A80202 API */
|
|
||||||
int burn_sev_to_text(int severity_number, char **severity_name, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = libdax_msgs__sev_to_text(severity_number, severity_name, 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int burn_builtin_abort_handler(void *handle, int signum, int flag)
|
|
||||||
{
|
|
||||||
|
|
||||||
#define Libburn_new_thread_signal_handleR 1
|
|
||||||
/*
|
|
||||||
#define Libburn_signal_handler_verbouS 1
|
|
||||||
*/
|
|
||||||
int ret;
|
|
||||||
struct burn_drive *d;
|
|
||||||
|
|
||||||
#ifdef Libburn_signal_handler_verbouS
|
|
||||||
fprintf(stderr,
|
|
||||||
"libburn_ABORT: pid = %d , abort_control_pid = %d , sig= %d\n",
|
|
||||||
getpid(), abort_control_pid, signum);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ts A70928:
|
|
||||||
Must be quick. Allowed to coincide with other thread and to share
|
|
||||||
the increment with that one. It must not decrease, though, and
|
|
||||||
yield at least 1 if any thread calls this function.
|
|
||||||
*/
|
|
||||||
burn_global_abort_level++;
|
|
||||||
burn_global_abort_signum= signum;
|
|
||||||
|
|
||||||
if(getpid() != abort_control_pid) {
|
|
||||||
|
|
||||||
#ifdef Libburn_new_thread_signal_handleR
|
|
||||||
|
|
||||||
ret = burn_drive_find_by_thread_pid(&d, getpid());
|
|
||||||
if (ret > 0 && d->busy == BURN_DRIVE_WRITING) {
|
|
||||||
/* This is an active writer thread */
|
|
||||||
|
|
||||||
#ifdef Libburn_signal_handler_verbouS
|
|
||||||
fprintf(stderr, "libburn_ABORT: pid %d found drive busy with writing, (level= %d)\n", (int) getpid(), burn_global_abort_level);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
d->sync_cache(d);
|
|
||||||
|
|
||||||
/* >>> perform a more qualified end of burn process */;
|
|
||||||
|
|
||||||
d->busy = BURN_DRIVE_IDLE;
|
|
||||||
|
|
||||||
if (burn_global_abort_level > 0) {
|
|
||||||
/* control process did not show up yet */
|
|
||||||
#ifdef Libburn_signal_handler_verbouS
|
|
||||||
fprintf(stderr, "libburn_ABORT: pid %d sending signum %d to pid %d\n", (int) getpid(), (int) signum, (int) abort_control_pid);
|
|
||||||
#endif
|
|
||||||
kill(abort_control_pid, signum);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Libburn_signal_handler_verbouS
|
|
||||||
fprintf(stderr, "libburn_ABORT: pid %d signum %d returning -2\n", (int) getpid(), (int) signum);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return -2;
|
|
||||||
} else {
|
|
||||||
usleep(1000000); /* calm down */
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
usleep(1000000); /* calm down */
|
|
||||||
return -2;
|
|
||||||
#endif /* ! Libburn_new_thread_signal_handleR */
|
|
||||||
|
|
||||||
}
|
|
||||||
burn_global_abort_level = -1;
|
|
||||||
Cleanup_set_handlers(NULL, NULL, 2);
|
|
||||||
fprintf(stderr,"%sABORT : Trying to shut down drive and library\n",
|
|
||||||
abort_message_prefix);
|
|
||||||
fprintf(stderr,
|
|
||||||
"%sABORT : Wait the normal burning time before any kill -9\n",
|
|
||||||
abort_message_prefix);
|
|
||||||
close(0); /* somehow stdin as input blocks abort until EOF */
|
|
||||||
|
|
||||||
burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
|
|
||||||
abort_message_prefix);
|
|
||||||
burn_global_abort_level = -2;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
|
|
||||||
int mode)
|
|
||||||
{
|
|
||||||
if(handler == NULL && mode == 0) {
|
|
||||||
handler = burn_builtin_abort_handler;
|
|
||||||
/*
|
|
||||||
fprintf(stderr, "libburn_experimental: activated burn_builtin_abort_handler() with handle '%s'\n",(handle==NULL ? "libburn : " : (char *) handle));
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
strcpy(abort_message_prefix, "libburn : ");
|
|
||||||
if(handle != NULL)
|
|
||||||
strncpy(abort_message_prefix, (char *) handle,
|
|
||||||
sizeof(abort_message_prefix)-1);
|
|
||||||
abort_message_prefix[sizeof(abort_message_prefix)-1] = 0;
|
|
||||||
abort_control_pid = getpid();
|
|
||||||
Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler, mode|4);
|
|
||||||
burn_global_signal_handle = handle;
|
|
||||||
burn_global_signal_handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70223 : API */
|
|
||||||
void burn_allow_untested_profiles(int yes)
|
|
||||||
{
|
|
||||||
burn_support_untested_profiles = !!yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70915 : API */
|
|
||||||
int burn_set_messenger(void *messenger)
|
|
||||||
{
|
|
||||||
struct libdax_msgs *pt;
|
|
||||||
|
|
||||||
if (libdax_msgs_refer(&pt, messenger, 0) <= 0)
|
|
||||||
return 0;
|
|
||||||
libdax_msgs_destroy(&libdax_messenger, 0);
|
|
||||||
libdax_messenger = (struct libdax_msgs *) pt;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef BURN__INIT_H
|
|
||||||
#define BURN__INIT_H
|
|
||||||
|
|
||||||
extern int burn_running;
|
|
||||||
|
|
||||||
/** Indicator for burn_drive_get_status() wether a signal hit parts of the
|
|
||||||
thread team.
|
|
||||||
0= all works well ,
|
|
||||||
1 to 5 = waiting for eventual signal on control thread
|
|
||||||
> 5 = do abort now
|
|
||||||
-1 = control thread has been informed
|
|
||||||
*/
|
|
||||||
extern volatile int burn_global_abort_level;
|
|
||||||
extern int burn_global_abort_signum;
|
|
||||||
extern void *burn_global_signal_handle;
|
|
||||||
extern burn_abort_handler_t burn_global_signal_handler;
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* BURN__INIT_H */
|
|
451
libburn/lec.c
451
libburn/lec.c
@ -1,451 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
/* borrowed HEAVILY from cdrdao */
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "lec.h"
|
|
||||||
|
|
||||||
#define LEC_HEADER_OFFSET 12
|
|
||||||
#define LEC_MODE1_P_PARITY_OFFSET 2076
|
|
||||||
#define LEC_MODE1_Q_PARITY_OFFSET 2248
|
|
||||||
|
|
||||||
static unsigned char gf8_ilog[255] = {
|
|
||||||
1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76,
|
|
||||||
152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96,
|
|
||||||
192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119,
|
|
||||||
238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186,
|
|
||||||
105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94,
|
|
||||||
188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187,
|
|
||||||
107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217,
|
|
||||||
175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103,
|
|
||||||
206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197,
|
|
||||||
151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79,
|
|
||||||
158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85,
|
|
||||||
170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99,
|
|
||||||
198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227,
|
|
||||||
219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87,
|
|
||||||
174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224,
|
|
||||||
221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195,
|
|
||||||
155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244,
|
|
||||||
245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125,
|
|
||||||
250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142,
|
|
||||||
};
|
|
||||||
static unsigned char gf8_log[256] = {
|
|
||||||
0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100,
|
|
||||||
224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113,
|
|
||||||
5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18,
|
|
||||||
130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9,
|
|
||||||
120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253,
|
|
||||||
226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143,
|
|
||||||
150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182,
|
|
||||||
163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61,
|
|
||||||
202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115,
|
|
||||||
243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222,
|
|
||||||
237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124,
|
|
||||||
17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188,
|
|
||||||
207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211,
|
|
||||||
171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31,
|
|
||||||
45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12,
|
|
||||||
111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134,
|
|
||||||
177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11,
|
|
||||||
245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231,
|
|
||||||
173, 232, 116, 214, 244, 234, 168, 80, 88, 175,
|
|
||||||
};
|
|
||||||
static unsigned char gf8_q_coeffs[2][45] = {
|
|
||||||
{97, 251, 133, 60, 82, 160, 155, 201, 8, 112, 246, 11, 21, 42, 157,
|
|
||||||
169, 80, 174, 232, 230, 172, 211, 241, 18, 68, 216, 44, 121, 9, 200,
|
|
||||||
75, 103, 221, 252, 96, 176, 88, 167, 114, 76, 199, 26, 1, 0, 0},
|
|
||||||
{190, 96, 250, 132, 59, 81, 159, 154, 200, 7, 111, 245, 10, 20, 41,
|
|
||||||
156, 168, 79, 173, 231, 229, 171, 210, 240, 17, 67, 215, 43, 120, 8,
|
|
||||||
199, 74, 102, 220, 251, 95, 175, 87, 166, 113, 75, 198, 25, 0, 0}
|
|
||||||
};
|
|
||||||
static unsigned char gf8_p_coeffs[2][26] = {
|
|
||||||
{230, 172, 211, 241, 18, 68, 216, 44, 121, 9, 200, 75, 103, 221, 252,
|
|
||||||
96, 176, 88, 167, 114, 76, 199, 26, 1, 0, 0},
|
|
||||||
{231, 229, 171, 210, 240, 17, 67, 215, 43, 120, 8, 199, 74, 102, 220,
|
|
||||||
251, 95, 175, 87, 166, 113, 75, 198, 25, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
static unsigned char yellowbook_scrambler[2340] = {
|
|
||||||
1, 128, 0, 96, 0, 40, 0, 30, 128, 8, 96, 6, 168, 2, 254, 129, 128, 96,
|
|
||||||
96, 40, 40, 30, 158,
|
|
||||||
136, 104, 102, 174, 170, 252, 127, 1, 224, 0, 72, 0, 54, 128, 22, 224,
|
|
||||||
14, 200, 4, 86, 131, 126, 225,
|
|
||||||
224, 72, 72, 54, 182, 150, 246, 238, 198, 204, 82, 213, 253, 159, 1,
|
|
||||||
168, 0, 126, 128, 32, 96, 24, 40,
|
|
||||||
10, 158, 135, 40, 98, 158, 169, 168, 126, 254, 160, 64, 120, 48, 34,
|
|
||||||
148, 25, 175, 74, 252, 55, 1, 214,
|
|
||||||
128, 94, 224, 56, 72, 18, 182, 141, 182, 229, 182, 203, 54, 215, 86,
|
|
||||||
222, 190, 216, 112, 90, 164, 59, 59,
|
|
||||||
83, 83, 125, 253, 225, 129, 136, 96, 102, 168, 42, 254, 159, 0, 104, 0,
|
|
||||||
46, 128, 28, 96, 9, 232, 6,
|
|
||||||
206, 130, 212, 97, 159, 104, 104, 46, 174, 156, 124, 105, 225, 238,
|
|
||||||
200, 76, 86, 181, 254, 247, 0, 70, 128,
|
|
||||||
50, 224, 21, 136, 15, 38, 132, 26, 227, 75, 9, 247, 70, 198, 178, 210,
|
|
||||||
245, 157, 135, 41, 162, 158, 249,
|
|
||||||
168, 66, 254, 177, 128, 116, 96, 39, 104, 26, 174, 139, 60, 103, 81,
|
|
||||||
234, 188, 79, 49, 244, 20, 71, 79,
|
|
||||||
114, 180, 37, 183, 91, 54, 187, 86, 243, 126, 197, 224, 83, 8, 61, 198,
|
|
||||||
145, 146, 236, 109, 141, 237, 165,
|
|
||||||
141, 187, 37, 179, 91, 53, 251, 87, 3, 126, 129, 224, 96, 72, 40, 54,
|
|
||||||
158, 150, 232, 110, 206, 172, 84,
|
|
||||||
125, 255, 97, 128, 40, 96, 30, 168, 8, 126, 134, 160, 98, 248, 41, 130,
|
|
||||||
158, 225, 168, 72, 126, 182, 160,
|
|
||||||
118, 248, 38, 194, 154, 209, 171, 28, 127, 73, 224, 54, 200, 22, 214,
|
|
||||||
142, 222, 228, 88, 75, 122, 183, 99,
|
|
||||||
54, 169, 214, 254, 222, 192, 88, 80, 58, 188, 19, 49, 205, 212, 85,
|
|
||||||
159, 127, 40, 32, 30, 152, 8, 106,
|
|
||||||
134, 175, 34, 252, 25, 129, 202, 224, 87, 8, 62, 134, 144, 98, 236, 41,
|
|
||||||
141, 222, 229, 152, 75, 42, 183,
|
|
||||||
95, 54, 184, 22, 242, 142, 197, 164, 83, 59, 125, 211, 97, 157, 232,
|
|
||||||
105, 142, 174, 228, 124, 75, 97, 247,
|
|
||||||
104, 70, 174, 178, 252, 117, 129, 231, 32, 74, 152, 55, 42, 150, 159,
|
|
||||||
46, 232, 28, 78, 137, 244, 102, 199,
|
|
||||||
106, 210, 175, 29, 188, 9, 177, 198, 244, 82, 199, 125, 146, 161, 173,
|
|
||||||
184, 125, 178, 161, 181, 184, 119, 50,
|
|
||||||
166, 149, 186, 239, 51, 12, 21, 197, 207, 19, 20, 13, 207, 69, 148, 51,
|
|
||||||
47, 85, 220, 63, 25, 208, 10,
|
|
||||||
220, 7, 25, 194, 138, 209, 167, 28, 122, 137, 227, 38, 201, 218, 214,
|
|
||||||
219, 30, 219, 72, 91, 118, 187, 102,
|
|
||||||
243, 106, 197, 239, 19, 12, 13, 197, 197, 147, 19, 45, 205, 221, 149,
|
|
||||||
153, 175, 42, 252, 31, 1, 200, 0,
|
|
||||||
86, 128, 62, 224, 16, 72, 12, 54, 133, 214, 227, 30, 201, 200, 86, 214,
|
|
||||||
190, 222, 240, 88, 68, 58, 179,
|
|
||||||
83, 53, 253, 215, 1, 158, 128, 104, 96, 46, 168, 28, 126, 137, 224,
|
|
||||||
102, 200, 42, 214, 159, 30, 232, 8,
|
|
||||||
78, 134, 180, 98, 247, 105, 134, 174, 226, 252, 73, 129, 246, 224, 70,
|
|
||||||
200, 50, 214, 149, 158, 239, 40, 76,
|
|
||||||
30, 181, 200, 119, 22, 166, 142, 250, 228, 67, 11, 113, 199, 100, 82,
|
|
||||||
171, 125, 191, 97, 176, 40, 116, 30,
|
|
||||||
167, 72, 122, 182, 163, 54, 249, 214, 194, 222, 209, 152, 92, 106, 185,
|
|
||||||
239, 50, 204, 21, 149, 207, 47, 20,
|
|
||||||
28, 15, 73, 196, 54, 211, 86, 221, 254, 217, 128, 90, 224, 59, 8, 19,
|
|
||||||
70, 141, 242, 229, 133, 139, 35,
|
|
||||||
39, 89, 218, 186, 219, 51, 27, 85, 203, 127, 23, 96, 14, 168, 4, 126,
|
|
||||||
131, 96, 97, 232, 40, 78, 158,
|
|
||||||
180, 104, 119, 110, 166, 172, 122, 253, 227, 1, 137, 192, 102, 208, 42,
|
|
||||||
220, 31, 25, 200, 10, 214, 135, 30,
|
|
||||||
226, 136, 73, 166, 182, 250, 246, 195, 6, 209, 194, 220, 81, 153, 252,
|
|
||||||
106, 193, 239, 16, 76, 12, 53, 197,
|
|
||||||
215, 19, 30, 141, 200, 101, 150, 171, 46, 255, 92, 64, 57, 240, 18,
|
|
||||||
196, 13, 147, 69, 173, 243, 61, 133,
|
|
||||||
209, 163, 28, 121, 201, 226, 214, 201, 158, 214, 232, 94, 206, 184, 84,
|
|
||||||
114, 191, 101, 176, 43, 52, 31, 87,
|
|
||||||
72, 62, 182, 144, 118, 236, 38, 205, 218, 213, 155, 31, 43, 72, 31,
|
|
||||||
118, 136, 38, 230, 154, 202, 235, 23,
|
|
||||||
15, 78, 132, 52, 99, 87, 105, 254, 174, 192, 124, 80, 33, 252, 24, 65,
|
|
||||||
202, 176, 87, 52, 62, 151, 80,
|
|
||||||
110, 188, 44, 113, 221, 228, 89, 139, 122, 231, 99, 10, 169, 199, 62,
|
|
||||||
210, 144, 93, 172, 57, 189, 210, 241,
|
|
||||||
157, 132, 105, 163, 110, 249, 236, 66, 205, 241, 149, 132, 111, 35,
|
|
||||||
108, 25, 237, 202, 205, 151, 21, 174, 143,
|
|
||||||
60, 100, 17, 235, 76, 79, 117, 244, 39, 7, 90, 130, 187, 33, 179, 88,
|
|
||||||
117, 250, 167, 3, 58, 129, 211,
|
|
||||||
32, 93, 216, 57, 154, 146, 235, 45, 143, 93, 164, 57, 187, 82, 243,
|
|
||||||
125, 133, 225, 163, 8, 121, 198, 162,
|
|
||||||
210, 249, 157, 130, 233, 161, 142, 248, 100, 66, 171, 113, 191, 100,
|
|
||||||
112, 43, 100, 31, 107, 72, 47, 118, 156,
|
|
||||||
38, 233, 218, 206, 219, 20, 91, 79, 123, 116, 35, 103, 89, 234, 186,
|
|
||||||
207, 51, 20, 21, 207, 79, 20, 52,
|
|
||||||
15, 87, 68, 62, 179, 80, 117, 252, 39, 1, 218, 128, 91, 32, 59, 88, 19,
|
|
||||||
122, 141, 227, 37, 137, 219,
|
|
||||||
38, 219, 90, 219, 123, 27, 99, 75, 105, 247, 110, 198, 172, 82, 253,
|
|
||||||
253, 129, 129, 160, 96, 120, 40, 34,
|
|
||||||
158, 153, 168, 106, 254, 175, 0, 124, 0, 33, 192, 24, 80, 10, 188, 7,
|
|
||||||
49, 194, 148, 81, 175, 124, 124,
|
|
||||||
33, 225, 216, 72, 90, 182, 187, 54, 243, 86, 197, 254, 211, 0, 93, 192,
|
|
||||||
57, 144, 18, 236, 13, 141, 197,
|
|
||||||
165, 147, 59, 45, 211, 93, 157, 249, 169, 130, 254, 225, 128, 72, 96,
|
|
||||||
54, 168, 22, 254, 142, 192, 100, 80,
|
|
||||||
43, 124, 31, 97, 200, 40, 86, 158, 190, 232, 112, 78, 164, 52, 123, 87,
|
|
||||||
99, 126, 169, 224, 126, 200, 32,
|
|
||||||
86, 152, 62, 234, 144, 79, 44, 52, 29, 215, 73, 158, 182, 232, 118,
|
|
||||||
206, 166, 212, 122, 223, 99, 24, 41,
|
|
||||||
202, 158, 215, 40, 94, 158, 184, 104, 114, 174, 165, 188, 123, 49, 227,
|
|
||||||
84, 73, 255, 118, 192, 38, 208, 26,
|
|
||||||
220, 11, 25, 199, 74, 210, 183, 29, 182, 137, 182, 230, 246, 202, 198,
|
|
||||||
215, 18, 222, 141, 152, 101, 170, 171,
|
|
||||||
63, 63, 80, 16, 60, 12, 17, 197, 204, 83, 21, 253, 207, 1, 148, 0, 111,
|
|
||||||
64, 44, 48, 29, 212, 9,
|
|
||||||
159, 70, 232, 50, 206, 149, 148, 111, 47, 108, 28, 45, 201, 221, 150,
|
|
||||||
217, 174, 218, 252, 91, 1, 251, 64,
|
|
||||||
67, 112, 49, 228, 20, 75, 79, 119, 116, 38, 167, 90, 250, 187, 3, 51,
|
|
||||||
65, 213, 240, 95, 4, 56, 3,
|
|
||||||
82, 129, 253, 160, 65, 184, 48, 114, 148, 37, 175, 91, 60, 59, 81, 211,
|
|
||||||
124, 93, 225, 249, 136, 66, 230,
|
|
||||||
177, 138, 244, 103, 7, 106, 130, 175, 33, 188, 24, 113, 202, 164, 87,
|
|
||||||
59, 126, 147, 96, 109, 232, 45, 142,
|
|
||||||
157, 164, 105, 187, 110, 243, 108, 69, 237, 243, 13, 133, 197, 163, 19,
|
|
||||||
57, 205, 210, 213, 157, 159, 41, 168,
|
|
||||||
30, 254, 136, 64, 102, 176, 42, 244, 31, 7, 72, 2, 182, 129, 182, 224,
|
|
||||||
118, 200, 38, 214, 154, 222, 235,
|
|
||||||
24, 79, 74, 180, 55, 55, 86, 150, 190, 238, 240, 76, 68, 53, 243, 87,
|
|
||||||
5, 254, 131, 0, 97, 192, 40,
|
|
||||||
80, 30, 188, 8, 113, 198, 164, 82, 251, 125, 131, 97, 161, 232, 120,
|
|
||||||
78, 162, 180, 121, 183, 98, 246, 169,
|
|
||||||
134, 254, 226, 192, 73, 144, 54, 236, 22, 205, 206, 213, 148, 95, 47,
|
|
||||||
120, 28, 34, 137, 217, 166, 218, 250,
|
|
||||||
219, 3, 27, 65, 203, 112, 87, 100, 62, 171, 80, 127, 124, 32, 33, 216,
|
|
||||||
24, 90, 138, 187, 39, 51, 90,
|
|
||||||
149, 251, 47, 3, 92, 1, 249, 192, 66, 208, 49, 156, 20, 105, 207, 110,
|
|
||||||
212, 44, 95, 93, 248, 57, 130,
|
|
||||||
146, 225, 173, 136, 125, 166, 161, 186, 248, 115, 2, 165, 193, 187, 16,
|
|
||||||
115, 76, 37, 245, 219, 7, 27, 66,
|
|
||||||
139, 113, 167, 100, 122, 171, 99, 63, 105, 208, 46, 220, 28, 89, 201,
|
|
||||||
250, 214, 195, 30, 209, 200, 92, 86,
|
|
||||||
185, 254, 242, 192, 69, 144, 51, 44, 21, 221, 207, 25, 148, 10, 239,
|
|
||||||
71, 12, 50, 133, 213, 163, 31, 57,
|
|
||||||
200, 18, 214, 141, 158, 229, 168, 75, 62, 183, 80, 118, 188, 38, 241,
|
|
||||||
218, 196, 91, 19, 123, 77, 227, 117,
|
|
||||||
137, 231, 38, 202, 154, 215, 43, 30, 159, 72, 104, 54, 174, 150, 252,
|
|
||||||
110, 193, 236, 80, 77, 252, 53, 129,
|
|
||||||
215, 32, 94, 152, 56, 106, 146, 175, 45, 188, 29, 177, 201, 180, 86,
|
|
||||||
247, 126, 198, 160, 82, 248, 61, 130,
|
|
||||||
145, 161, 172, 120, 125, 226, 161, 137, 184, 102, 242, 170, 197, 191,
|
|
||||||
19, 48, 13, 212, 5, 159, 67, 40, 49,
|
|
||||||
222, 148, 88, 111, 122, 172, 35, 61, 217, 209, 154, 220, 107, 25, 239,
|
|
||||||
74, 204, 55, 21, 214, 143, 30, 228,
|
|
||||||
8, 75, 70, 183, 114, 246, 165, 134, 251, 34, 195, 89, 145, 250, 236,
|
|
||||||
67, 13, 241, 197, 132, 83, 35, 125,
|
|
||||||
217, 225, 154, 200, 107, 22, 175, 78, 252, 52, 65, 215, 112, 94, 164,
|
|
||||||
56, 123, 82, 163, 125, 185, 225, 178,
|
|
||||||
200, 117, 150, 167, 46, 250, 156, 67, 41, 241, 222, 196, 88, 83, 122,
|
|
||||||
189, 227, 49, 137, 212, 102, 223, 106,
|
|
||||||
216, 47, 26, 156, 11, 41, 199, 94, 210, 184, 93, 178, 185, 181, 178,
|
|
||||||
247, 53, 134, 151, 34, 238, 153, 140,
|
|
||||||
106, 229, 239, 11, 12, 7, 69, 194, 179, 17, 181, 204, 119, 21, 230,
|
|
||||||
143, 10, 228, 7, 11, 66, 135, 113,
|
|
||||||
162, 164, 121, 187, 98, 243, 105, 133, 238, 227, 12, 73, 197, 246, 211,
|
|
||||||
6, 221, 194, 217, 145, 154, 236, 107,
|
|
||||||
13, 239, 69, 140, 51, 37, 213, 219, 31, 27, 72, 11, 118, 135, 102, 226,
|
|
||||||
170, 201, 191, 22, 240, 14, 196,
|
|
||||||
4, 83, 67, 125, 241, 225, 132, 72, 99, 118, 169, 230, 254, 202, 192,
|
|
||||||
87, 16, 62, 140, 16, 101, 204, 43,
|
|
||||||
21, 223, 79, 24, 52, 10, 151, 71, 46, 178, 156, 117, 169, 231, 62, 202,
|
|
||||||
144, 87, 44, 62, 157, 208, 105,
|
|
||||||
156, 46, 233, 220, 78, 217, 244, 90, 199, 123, 18, 163, 77, 185, 245,
|
|
||||||
178, 199, 53, 146, 151, 45, 174, 157,
|
|
||||||
188, 105, 177, 238, 244, 76, 71, 117, 242, 167, 5, 186, 131, 51, 33,
|
|
||||||
213, 216, 95, 26, 184, 11, 50, 135,
|
|
||||||
85, 162, 191, 57, 176, 18, 244, 13, 135, 69, 162, 179, 57, 181, 210,
|
|
||||||
247, 29, 134, 137, 162, 230, 249, 138,
|
|
||||||
194, 231, 17, 138, 140, 103, 37, 234, 155, 15, 43, 68, 31, 115, 72, 37,
|
|
||||||
246, 155, 6, 235, 66, 207, 113,
|
|
||||||
148, 36, 111, 91, 108, 59, 109, 211, 109, 157, 237, 169, 141, 190, 229,
|
|
||||||
176, 75, 52, 55, 87, 86, 190, 190,
|
|
||||||
240, 112, 68, 36, 51, 91, 85, 251, 127, 3, 96, 1, 232, 0, 78, 128, 52,
|
|
||||||
96, 23, 104, 14, 174, 132,
|
|
||||||
124, 99, 97, 233, 232, 78, 206, 180, 84, 119, 127, 102, 160, 42, 248,
|
|
||||||
31, 2, 136, 1, 166, 128, 122, 224,
|
|
||||||
35, 8, 25, 198, 138, 210, 231, 29, 138, 137, 167, 38, 250, 154, 195,
|
|
||||||
43, 17, 223, 76, 88, 53, 250, 151,
|
|
||||||
3, 46, 129, 220, 96, 89, 232, 58, 206, 147, 20, 109, 207, 109, 148, 45,
|
|
||||||
175, 93, 188, 57, 177, 210, 244,
|
|
||||||
93, 135, 121, 162, 162, 249, 185, 130, 242, 225, 133, 136, 99, 38, 169,
|
|
||||||
218, 254, 219, 0, 91, 64, 59, 112,
|
|
||||||
19, 100, 13, 235, 69, 143, 115, 36, 37, 219, 91, 27, 123, 75, 99, 119,
|
|
||||||
105, 230, 174, 202, 252, 87, 1,
|
|
||||||
254, 128, 64, 96, 48, 40, 20, 30, 143, 72, 100, 54, 171, 86, 255, 126,
|
|
||||||
192, 32, 80, 24, 60, 10, 145,
|
|
||||||
199, 44, 82, 157, 253, 169, 129, 190, 224, 112, 72, 36, 54, 155, 86,
|
|
||||||
235, 126, 207, 96, 84, 40, 63, 94,
|
|
||||||
144, 56, 108, 18, 173, 205, 189, 149, 177, 175, 52, 124, 23, 97, 206,
|
|
||||||
168, 84, 126, 191, 96, 112, 40, 36,
|
|
||||||
30, 155, 72, 107, 118, 175, 102, 252, 42, 193, 223, 16, 88, 12, 58,
|
|
||||||
133, 211, 35, 29, 217, 201, 154, 214,
|
|
||||||
235, 30, 207, 72, 84, 54, 191, 86, 240, 62, 196, 16, 83, 76, 61, 245,
|
|
||||||
209, 135, 28, 98, 137, 233, 166,
|
|
||||||
206, 250, 212, 67, 31, 113, 200, 36, 86, 155, 126, 235, 96, 79, 104,
|
|
||||||
52, 46, 151, 92, 110, 185, 236, 114,
|
|
||||||
205, 229, 149, 139, 47, 39, 92, 26, 185, 203, 50, 215, 85, 158, 191,
|
|
||||||
40, 112, 30, 164, 8, 123, 70, 163,
|
|
||||||
114, 249, 229, 130, 203, 33, 151, 88, 110, 186, 172, 115, 61, 229, 209,
|
|
||||||
139, 28, 103, 73, 234, 182, 207, 54,
|
|
||||||
212, 22, 223, 78, 216, 52, 90, 151, 123, 46, 163, 92, 121, 249, 226,
|
|
||||||
194, 201, 145, 150, 236, 110, 205, 236,
|
|
||||||
85, 141, 255, 37, 128, 27, 32, 11, 88, 7, 122, 130, 163, 33, 185, 216,
|
|
||||||
114, 218, 165, 155, 59, 43, 83,
|
|
||||||
95, 125, 248, 33, 130, 152, 97, 170, 168, 127, 62, 160, 16, 120, 12,
|
|
||||||
34, 133, 217, 163, 26, 249, 203, 2,
|
|
||||||
215, 65, 158, 176, 104, 116, 46, 167, 92, 122, 185, 227, 50, 201, 213,
|
|
||||||
150, 223, 46, 216, 28, 90, 137, 251,
|
|
||||||
38, 195, 90, 209, 251, 28, 67, 73, 241, 246, 196, 70, 211, 114, 221,
|
|
||||||
229, 153,
|
|
||||||
};
|
|
||||||
|
|
||||||
void scramble(unsigned char *inout)
|
|
||||||
{
|
|
||||||
unsigned char *r = inout + 12;
|
|
||||||
unsigned char *s = yellowbook_scrambler;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 2340; i; i--) {
|
|
||||||
*r++ ^= *s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate the P parities for the sector.
|
|
||||||
* The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
|
|
||||||
*/
|
|
||||||
void parity_p(unsigned char *sector)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
unsigned char p0_msb, p1_msb;
|
|
||||||
unsigned char p0_lsb, p1_lsb;
|
|
||||||
unsigned char *p_msb_start, *p_lsb_start;
|
|
||||||
unsigned char *p_msb, *p_lsb;
|
|
||||||
unsigned char *coeffs0, *coeffs1;
|
|
||||||
unsigned char *p0, *p1;
|
|
||||||
unsigned char d;
|
|
||||||
unsigned short c;
|
|
||||||
|
|
||||||
p_lsb_start = sector + LEC_HEADER_OFFSET;
|
|
||||||
p_msb_start = sector + LEC_HEADER_OFFSET + 1;
|
|
||||||
|
|
||||||
p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
|
|
||||||
p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
|
|
||||||
|
|
||||||
for (i = 0; i <= 42; i++) {
|
|
||||||
p_lsb = p_lsb_start;
|
|
||||||
p_msb = p_msb_start;
|
|
||||||
|
|
||||||
coeffs0 = gf8_p_coeffs[0];
|
|
||||||
coeffs1 = gf8_p_coeffs[1];
|
|
||||||
|
|
||||||
p0_lsb = p1_lsb = p0_msb = p1_msb = 0;
|
|
||||||
|
|
||||||
for (j = 0; j <= 23; j++) {
|
|
||||||
d = *p_lsb;
|
|
||||||
|
|
||||||
if (d != 0) {
|
|
||||||
c = gf8_log[d] + *coeffs0;
|
|
||||||
if (c >= 255)
|
|
||||||
c -= 255;
|
|
||||||
p0_lsb ^= gf8_ilog[c];
|
|
||||||
|
|
||||||
c = gf8_log[d] + *coeffs1;
|
|
||||||
if (c >= 255)
|
|
||||||
c -= 255;
|
|
||||||
p1_lsb ^= gf8_ilog[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
d = *p_msb;
|
|
||||||
|
|
||||||
if (d != 0) {
|
|
||||||
c = gf8_log[d] + *coeffs0;
|
|
||||||
if (c >= 255)
|
|
||||||
c -= 255;
|
|
||||||
p0_msb ^= gf8_ilog[c];
|
|
||||||
|
|
||||||
c = gf8_log[d] + *coeffs1;
|
|
||||||
if (c >= 255)
|
|
||||||
c -= 255;
|
|
||||||
p1_msb ^= gf8_ilog[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
coeffs0++;
|
|
||||||
coeffs1++;
|
|
||||||
|
|
||||||
p_lsb += 2 * 43;
|
|
||||||
p_msb += 2 * 43;
|
|
||||||
}
|
|
||||||
|
|
||||||
*p0 = p0_lsb;
|
|
||||||
*(p0 + 1) = p0_msb;
|
|
||||||
|
|
||||||
*p1 = p1_lsb;
|
|
||||||
*(p1 + 1) = p1_msb;
|
|
||||||
|
|
||||||
p0 += 2;
|
|
||||||
p1 += 2;
|
|
||||||
|
|
||||||
p_lsb_start += 2;
|
|
||||||
p_msb_start += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate the Q parities for the sector.
|
|
||||||
* The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
|
|
||||||
*/
|
|
||||||
void parity_q(unsigned char *sector)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
unsigned char q0_msb, q1_msb;
|
|
||||||
unsigned char q0_lsb, q1_lsb;
|
|
||||||
unsigned char *q_msb_start, *q_lsb_start;
|
|
||||||
unsigned char *q_msb, *q_lsb;
|
|
||||||
unsigned char *coeffs0, *coeffs1;
|
|
||||||
unsigned char *q0, *q1, *q_start;
|
|
||||||
unsigned char d;
|
|
||||||
unsigned short c;
|
|
||||||
|
|
||||||
q_lsb_start = sector + LEC_HEADER_OFFSET;
|
|
||||||
q_msb_start = sector + LEC_HEADER_OFFSET + 1;
|
|
||||||
|
|
||||||
q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
|
|
||||||
q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
|
|
||||||
q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
|
|
||||||
|
|
||||||
for (i = 0; i <= 25; i++) {
|
|
||||||
q_lsb = q_lsb_start;
|
|
||||||
q_msb = q_msb_start;
|
|
||||||
|
|
||||||
coeffs0 = gf8_q_coeffs[0];
|
|
||||||
coeffs1 = gf8_q_coeffs[1];
|
|
||||||
|
|
||||||
q0_lsb = q1_lsb = q0_msb = q1_msb = 0;
|
|
||||||
|
|
||||||
for (j = 0; j <= 42; j++) {
|
|
||||||
d = *q_lsb;
|
|
||||||
|
|
||||||
if (d != 0) {
|
|
||||||
c = gf8_log[d] + *coeffs0;
|
|
||||||
if (c >= 255)
|
|
||||||
c -= 255;
|
|
||||||
q0_lsb ^= gf8_ilog[c];
|
|
||||||
|
|
||||||
c = gf8_log[d] + *coeffs1;
|
|
||||||
if (c >= 255)
|
|
||||||
c -= 255;
|
|
||||||
q1_lsb ^= gf8_ilog[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
d = *q_msb;
|
|
||||||
|
|
||||||
if (d != 0) {
|
|
||||||
c = gf8_log[d] + *coeffs0;
|
|
||||||
if (c >= 255)
|
|
||||||
c -= 255;
|
|
||||||
q0_msb ^= gf8_ilog[c];
|
|
||||||
|
|
||||||
c = gf8_log[d] + *coeffs1;
|
|
||||||
if (c >= 255)
|
|
||||||
c -= 255;
|
|
||||||
q1_msb ^= gf8_ilog[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
coeffs0++;
|
|
||||||
coeffs1++;
|
|
||||||
|
|
||||||
q_lsb += 2 * 44;
|
|
||||||
q_msb += 2 * 44;
|
|
||||||
|
|
||||||
if (q_lsb >= q_start) {
|
|
||||||
q_msb -= 2 * 1118;
|
|
||||||
q_lsb -= 2 * 1118;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*q0 = q0_lsb;
|
|
||||||
*(q0 + 1) = q0_msb;
|
|
||||||
|
|
||||||
*q1 = q1_lsb;
|
|
||||||
*(q1 + 1) = q1_msb;
|
|
||||||
|
|
||||||
q0 += 2;
|
|
||||||
q1 += 2;
|
|
||||||
|
|
||||||
q_lsb_start += 2 * 43;
|
|
||||||
q_msb_start += 2 * 43;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __LEC
|
|
||||||
#define __LEC
|
|
||||||
|
|
||||||
#define RS_L12_BITS 8
|
|
||||||
|
|
||||||
void scramble(unsigned char *);
|
|
||||||
void parity_p(unsigned char *in);
|
|
||||||
void parity_q(unsigned char *in);
|
|
||||||
|
|
||||||
#endif /* __LEC */
|
|
2369
libburn/libburn.h
2369
libburn/libburn.h
File diff suppressed because it is too large
Load Diff
@ -1,326 +0,0 @@
|
|||||||
|
|
||||||
/* libdax_audioxtr
|
|
||||||
Audio track data extraction facility of libdax and libburn.
|
|
||||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
|
|
||||||
/* Only this single source module is entitled to do this */
|
|
||||||
#define LIBDAX_AUDIOXTR_H_INTERNAL 1
|
|
||||||
|
|
||||||
/* All clients of the extraction facility must do this */
|
|
||||||
#include "libdax_audioxtr.h"
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_audioxtr_new(struct libdax_audioxtr **xtr, char *path, int flag)
|
|
||||||
{
|
|
||||||
int ret= -1;
|
|
||||||
struct libdax_audioxtr *o;
|
|
||||||
|
|
||||||
o= *xtr= (struct libdax_audioxtr *) malloc(sizeof(struct libdax_audioxtr));
|
|
||||||
if(o==NULL)
|
|
||||||
return(-1);
|
|
||||||
strncpy(o->path,path,LIBDAX_AUDIOXTR_STRLEN-1);
|
|
||||||
o->path[LIBDAX_AUDIOXTR_STRLEN-1]= 0;
|
|
||||||
o->fd= -1;
|
|
||||||
strcpy(o->fmt,"unidentified");
|
|
||||||
o->fmt_info[0]= 0;
|
|
||||||
o->data_size= 0;
|
|
||||||
o->extract_count= 0;
|
|
||||||
|
|
||||||
o->num_channels= 0;
|
|
||||||
o->sample_rate= 0;
|
|
||||||
o->bits_per_sample= 0;
|
|
||||||
o->msb_first= 0;
|
|
||||||
|
|
||||||
o->wav_subchunk2_size= 0;
|
|
||||||
|
|
||||||
o->au_data_location= 0;
|
|
||||||
o->au_data_size= 0xffffffff;
|
|
||||||
|
|
||||||
ret= libdax_audioxtr_open(o,0);
|
|
||||||
if(ret<=0)
|
|
||||||
{ret= -2*(ret<0); goto failure;}
|
|
||||||
|
|
||||||
return(1);
|
|
||||||
failure:
|
|
||||||
libdax_audioxtr_destroy(xtr,0);
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_audioxtr_destroy(struct libdax_audioxtr **xtr, int flag)
|
|
||||||
{
|
|
||||||
struct libdax_audioxtr *o;
|
|
||||||
|
|
||||||
o= *xtr;
|
|
||||||
if(o==NULL)
|
|
||||||
return(0);
|
|
||||||
if(o->fd>=0 && strcmp(o->path,"-")!=0)
|
|
||||||
close(o->fd);
|
|
||||||
free((char *) o);
|
|
||||||
*xtr= NULL;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int libdax_audioxtr_open(struct libdax_audioxtr *o, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
char msg[LIBDAX_AUDIOXTR_STRLEN+80];
|
|
||||||
|
|
||||||
if(strcmp(o->path,"-")==0)
|
|
||||||
o->fd= 0;
|
|
||||||
else
|
|
||||||
o->fd= open(o->path, O_RDONLY);
|
|
||||||
if(o->fd<0) {
|
|
||||||
sprintf(msg,"Cannot open audio source file : %s",o->path);
|
|
||||||
libdax_msgs_submit(libdax_messenger,-1,0x00020200,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
msg, errno, 0);
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
ret= libdax_audioxtr_identify(o,0);
|
|
||||||
if(ret<=0) {
|
|
||||||
sprintf(msg,"Audio source file has unsuitable format : %s",o->path);
|
|
||||||
libdax_msgs_submit(libdax_messenger,-1,0x00020201,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
msg, 0, 0);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
ret= libdax_audioxtr_init_reading(o,0);
|
|
||||||
if(ret<=0) {
|
|
||||||
sprintf(msg,"Failed to prepare reading of audio data : %s",o->path);
|
|
||||||
libdax_msgs_submit(libdax_messenger,-1,0x00020202,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
msg, 0, 0);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int libdax_audioxtr_identify_wav(struct libdax_audioxtr *o, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
char buf[45];
|
|
||||||
|
|
||||||
/* check wether this is a MS WAVE file .wav */
|
|
||||||
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
|
|
||||||
|
|
||||||
if(o->fd!=0) {
|
|
||||||
ret= lseek(o->fd,0,SEEK_SET);
|
|
||||||
if(ret==-1)
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
ret= read(o->fd, buf, 44);
|
|
||||||
if(ret<44)
|
|
||||||
return(0);
|
|
||||||
buf[44]= 0; /* as stopper for any string operations */
|
|
||||||
|
|
||||||
if(strncmp(buf,"RIFF",4)!=0) /* ChunkID */
|
|
||||||
return(0);
|
|
||||||
if(strncmp(buf+8,"WAVE",4)!=0) /* Format */
|
|
||||||
return(0);
|
|
||||||
if(strncmp(buf+12,"fmt ",4)!=0) /* Subchunk1ID */
|
|
||||||
return(0);
|
|
||||||
if(buf[16]!=16 || buf[17]!=0 || buf[18]!=0 || buf[19]!=0) /* Subchunk1Size */
|
|
||||||
return(0);
|
|
||||||
if(buf[20]!=1 || buf[21]!=0) /* AudioFormat must be 1 (Linear quantization) */
|
|
||||||
return(0);
|
|
||||||
|
|
||||||
strcpy(o->fmt,".wav");
|
|
||||||
o->msb_first= 0;
|
|
||||||
o->num_channels= libdax_audioxtr_to_int(o,(unsigned char *) buf+22,2,0);
|
|
||||||
o->sample_rate= libdax_audioxtr_to_int(o,(unsigned char *) buf+24,4,0);
|
|
||||||
o->bits_per_sample= libdax_audioxtr_to_int(o,(unsigned char *)buf+34,2,0);
|
|
||||||
sprintf(o->fmt_info,
|
|
||||||
".wav , num_channels=%d , sample_rate=%d , bits_per_sample=%d",
|
|
||||||
o->num_channels,o->sample_rate,o->bits_per_sample);
|
|
||||||
o->wav_subchunk2_size= libdax_audioxtr_to_int(o,(unsigned char *)buf+40,4,0);
|
|
||||||
o->data_size= o->wav_subchunk2_size;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int libdax_audioxtr_identify_au(struct libdax_audioxtr *o, int flag)
|
|
||||||
{
|
|
||||||
int ret,encoding;
|
|
||||||
char buf[24];
|
|
||||||
|
|
||||||
/* Check wether this is a Sun Audio, .au file */
|
|
||||||
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
|
|
||||||
|
|
||||||
if(o->fd!=0) {
|
|
||||||
ret= lseek(o->fd,0,SEEK_SET);
|
|
||||||
if(ret==-1)
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
ret= read(o->fd, buf, 24);
|
|
||||||
if(ret<24)
|
|
||||||
return(0);
|
|
||||||
|
|
||||||
if(strncmp(buf,".snd",4)!=0)
|
|
||||||
return(0);
|
|
||||||
strcpy(o->fmt,".au");
|
|
||||||
o->msb_first= 1;
|
|
||||||
o->au_data_location= libdax_audioxtr_to_int(o,(unsigned char *)buf+4,4,1);
|
|
||||||
o->au_data_size= libdax_audioxtr_to_int(o,(unsigned char *)buf+8,4,1);
|
|
||||||
encoding= libdax_audioxtr_to_int(o,(unsigned char *)buf+12,4,1);
|
|
||||||
if(encoding==2)
|
|
||||||
o->bits_per_sample= 8;
|
|
||||||
else if(encoding==3)
|
|
||||||
o->bits_per_sample= 16;
|
|
||||||
else if(encoding==4)
|
|
||||||
o->bits_per_sample= 24;
|
|
||||||
else if(encoding==5)
|
|
||||||
o->bits_per_sample= 32;
|
|
||||||
else
|
|
||||||
o->bits_per_sample= -encoding;
|
|
||||||
o->sample_rate= libdax_audioxtr_to_int(o,(unsigned char *)buf+16,4,1);
|
|
||||||
o->num_channels= libdax_audioxtr_to_int(o,(unsigned char *)buf+20,4,1);
|
|
||||||
if(o->au_data_size!=0xffffffff)
|
|
||||||
o->data_size= o->au_data_size;
|
|
||||||
else
|
|
||||||
o->data_size= 0;
|
|
||||||
sprintf(o->fmt_info,
|
|
||||||
".au , num_channels=%d , sample_rate=%d , bits_per_sample=%d",
|
|
||||||
o->num_channels,o->sample_rate,o->bits_per_sample);
|
|
||||||
|
|
||||||
/* <<< for testing only */;
|
|
||||||
return(1);
|
|
||||||
|
|
||||||
return(o->bits_per_sample>0); /* Audio format must be linear PCM */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int libdax_audioxtr_identify(struct libdax_audioxtr *o, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret= libdax_audioxtr_identify_wav(o, 0);
|
|
||||||
if(ret!=0)
|
|
||||||
return(ret);
|
|
||||||
if(o->fd==0) /* cannot rewind stdin */
|
|
||||||
return(0);
|
|
||||||
ret= libdax_audioxtr_identify_au(o, 0);
|
|
||||||
if(ret!=0)
|
|
||||||
return(ret);
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* @param flag bit0=msb_first */
|
|
||||||
static unsigned libdax_audioxtr_to_int(struct libdax_audioxtr *o,
|
|
||||||
unsigned char *bytes, int len, int flag)
|
|
||||||
{
|
|
||||||
unsigned int ret= 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if(flag&1)
|
|
||||||
for(i= 0; i<len; i++)
|
|
||||||
ret= ret*256+bytes[i];
|
|
||||||
else
|
|
||||||
for(i= len-1; i>=0; i--)
|
|
||||||
ret= ret*256+bytes[i];
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int libdax_audioxtr_init_reading(struct libdax_audioxtr *o, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
|
|
||||||
/* currently this only works for MS WAVE files .wav and Sun .au*/;
|
|
||||||
if(o->fd==0) /* stdin: hope no read came after libdax_audioxtr_identify() */
|
|
||||||
return(1);
|
|
||||||
|
|
||||||
o->extract_count= 0;
|
|
||||||
if(strcmp(o->fmt,".wav")==0)
|
|
||||||
ret= lseek(o->fd,44,SEEK_SET);
|
|
||||||
else if(strcmp(o->fmt,".au")==0)
|
|
||||||
ret= lseek(o->fd,o->au_data_location,SEEK_SET);
|
|
||||||
else
|
|
||||||
ret= -1;
|
|
||||||
if(ret==-1)
|
|
||||||
return(0);
|
|
||||||
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_audioxtr_get_id(struct libdax_audioxtr *o,
|
|
||||||
char **fmt, char **fmt_info,
|
|
||||||
int *num_channels, int *sample_rate, int *bits_per_sample,
|
|
||||||
int *msb_first, int flag)
|
|
||||||
{
|
|
||||||
*fmt= o->fmt;
|
|
||||||
*fmt_info= o->fmt_info;
|
|
||||||
*num_channels= o->num_channels;
|
|
||||||
*sample_rate= o->sample_rate;
|
|
||||||
*bits_per_sample= o->bits_per_sample;
|
|
||||||
*msb_first= o->msb_first;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_audioxtr_get_size(struct libdax_audioxtr *o, off_t *size, int flag)
|
|
||||||
{
|
|
||||||
*size= o->data_size;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_audioxtr_read(struct libdax_audioxtr *o,
|
|
||||||
char buffer[], int buffer_size, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if(buffer_size<=0 || o->fd<0)
|
|
||||||
return(-2);
|
|
||||||
if(o->data_size>0 && !(flag&1))
|
|
||||||
if(buffer_size > o->data_size - o->extract_count)
|
|
||||||
buffer_size= o->data_size - o->extract_count;
|
|
||||||
if(buffer_size<=0)
|
|
||||||
return(0);
|
|
||||||
ret= read(o->fd,buffer,buffer_size);
|
|
||||||
if(ret>0)
|
|
||||||
o->extract_count+= ret;
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_audioxtr_detach_fd(struct libdax_audioxtr *o, int *fd, int flag)
|
|
||||||
{
|
|
||||||
if(o->fd<0)
|
|
||||||
return(-1);
|
|
||||||
if(strcmp(o->fmt,".wav")!=0 && strcmp(o->fmt,".au")!=0)
|
|
||||||
return(0);
|
|
||||||
if(flag&1) {
|
|
||||||
*fd= o->fd;
|
|
||||||
} else {
|
|
||||||
*fd= dup(o->fd);
|
|
||||||
if(*fd>=0 && strcmp(o->path,"-")!=0)
|
|
||||||
close(o->fd);
|
|
||||||
}
|
|
||||||
if(*fd>=0) {
|
|
||||||
o->fd= -1;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
@ -1,229 +0,0 @@
|
|||||||
|
|
||||||
/* libdax_audioxtr
|
|
||||||
Audio track data extraction facility of libdax and libburn.
|
|
||||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIBDAX_AUDIOXTR_H_INCLUDED
|
|
||||||
#define LIBDAX_AUDIOXTR_H_INCLUDED 1
|
|
||||||
|
|
||||||
/* Public Macros */
|
|
||||||
|
|
||||||
/* Maximum size for address paths and fmt_info strings */
|
|
||||||
#define LIBDAX_AUDIOXTR_STRLEN 4096
|
|
||||||
|
|
||||||
|
|
||||||
/* Public Opaque Handles */
|
|
||||||
|
|
||||||
/** Extractor object encapsulating intermediate states of extraction.
|
|
||||||
The clients of libdax_audioxtr shall only allocate pointers to this
|
|
||||||
struct and get a storage object via libdax_audioxtr_new().
|
|
||||||
Appropriate initial value for the pointer is NULL.
|
|
||||||
*/
|
|
||||||
struct libdax_audioxtr;
|
|
||||||
|
|
||||||
|
|
||||||
/* Public Functions */
|
|
||||||
|
|
||||||
/* Calls initiated from inside libdax/libburn */
|
|
||||||
|
|
||||||
|
|
||||||
/* Calls from applications (to be forwarded by libdax/libburn) */
|
|
||||||
|
|
||||||
|
|
||||||
/** Open an audio file, check wether suitable, create extractor object.
|
|
||||||
@param xtr Opaque handle to extractor. Gets attached extractor object.
|
|
||||||
@param path Address of the audio file to extract. "-" is stdin (but might
|
|
||||||
be not suitable for all futurely supported formats).
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return >0 success
|
|
||||||
0 unsuitable format
|
|
||||||
-1 severe error
|
|
||||||
-2 path not found
|
|
||||||
*/
|
|
||||||
int libdax_audioxtr_new(struct libdax_audioxtr **xtr, char *path, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Obtain identification parameters of opened audio source.
|
|
||||||
@param xtr Opaque handle to extractor
|
|
||||||
@param fmt Gets pointed to the audio file format id text: ".wav" , ".au"
|
|
||||||
@param fmt_info Gets pointed to a format info text telling parameters
|
|
||||||
@param num_channels e.g. 1=mono, 2=stereo, etc
|
|
||||||
@param sample_rate e.g. 11025, 44100
|
|
||||||
@param bits_per_sample e.g. 8= 8 bits per sample, 16= 16 bits ...
|
|
||||||
@param msb_first Byte order of samples: 0=Intel 1=Motorola
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return >0 success, <=0 failure
|
|
||||||
*/
|
|
||||||
int libdax_audioxtr_get_id(struct libdax_audioxtr *xtr,
|
|
||||||
char **fmt, char **fmt_info,
|
|
||||||
int *num_channels, int *sample_rate,
|
|
||||||
int *bits_per_sample, int *msb_first, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Obtain a prediction about the extracted size based on internal information
|
|
||||||
of the formatted file.
|
|
||||||
@param xtr Opaque handle to extractor
|
|
||||||
@param size Gets filled with the predicted size
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 prediction was possible , 0 no prediction could be made
|
|
||||||
*/
|
|
||||||
int libdax_audioxtr_get_size(struct libdax_audioxtr *o, off_t *size, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Obtain next buffer full of extracted data in desired format (only raw audio
|
|
||||||
for now).
|
|
||||||
@param xtr Opaque handle to extractor
|
|
||||||
@param buffer Gets filled with extracted data
|
|
||||||
@param buffer_size Maximum number of bytes to be filled into buffer
|
|
||||||
@param flag Bitfield for control purposes
|
|
||||||
bit0= do not stop at predicted end of data
|
|
||||||
@return >0 number of valid buffer bytes,
|
|
||||||
0 End of file
|
|
||||||
-1 operating system reports error
|
|
||||||
-2 usage error by application
|
|
||||||
*/
|
|
||||||
int libdax_audioxtr_read(struct libdax_audioxtr *xtr,
|
|
||||||
char buffer[], int buffer_size, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Try to obtain a file descriptor which will deliver extracted data
|
|
||||||
to normal calls of read(2). This may fail because the format is
|
|
||||||
unsuitable for that, but ".wav" is ok. If this call succeeds the xtr
|
|
||||||
object will have forgotten its file descriptor and libdax_audioxtr_read()
|
|
||||||
will return a usage error. One may use *fd after libdax_audioxtr_destroy()
|
|
||||||
and will have to close it via close(2) when done with it.
|
|
||||||
@param xtr Opaque handle to extractor
|
|
||||||
@param fd Eventually returns the file descriptor number
|
|
||||||
@param flag Bitfield for control purposes
|
|
||||||
bit0= do not dup(2) and close(2) but hand out original fd
|
|
||||||
@return 1 success, 0 cannot hand out fd , -1 severe error
|
|
||||||
*/
|
|
||||||
int libdax_audioxtr_detach_fd(struct libdax_audioxtr *o, int *fd, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Clean up after extraction and destroy extractor object.
|
|
||||||
@param xtr Opaque handle to extractor, *xtr is allowed to be NULL,
|
|
||||||
*xtr is set to NULL by this function
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 = destroyed object, 0 = was already destroyed
|
|
||||||
*/
|
|
||||||
int libdax_audioxtr_destroy(struct libdax_audioxtr **xtr, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef LIDBAX_AUDIOXTR________________
|
|
||||||
|
|
||||||
|
|
||||||
-- place documentation text here ---
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* LIDBAX_AUDIOXTR_________________ */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
*Never* set this macro outside libdax_audioxtr.c !
|
|
||||||
The entrails of this facility are not to be seen by
|
|
||||||
the other library components or the applications.
|
|
||||||
*/
|
|
||||||
#ifdef LIBDAX_AUDIOXTR_H_INTERNAL
|
|
||||||
|
|
||||||
/* Internal Structures */
|
|
||||||
|
|
||||||
/** Extractor object encapsulating intermediate states of extraction */
|
|
||||||
struct libdax_audioxtr {
|
|
||||||
|
|
||||||
/* Source of the encoded audio data */
|
|
||||||
char path[LIBDAX_AUDIOXTR_STRLEN];
|
|
||||||
|
|
||||||
/* File descriptor to path. Anything else than 0 must be lseek-able */
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
/* Format identifier. E.g. ".wav" */
|
|
||||||
char fmt[80];
|
|
||||||
|
|
||||||
/* Format parameter info text */
|
|
||||||
char fmt_info[LIBDAX_AUDIOXTR_STRLEN];
|
|
||||||
|
|
||||||
/* 1= mono, 2= stereo, etc. */
|
|
||||||
int num_channels;
|
|
||||||
|
|
||||||
/* 8000, 44100, etc. */
|
|
||||||
int sample_rate;
|
|
||||||
|
|
||||||
/* 8 bits = 8, 16 bits = 16, etc. */
|
|
||||||
int bits_per_sample;
|
|
||||||
|
|
||||||
/* Byte order of samples: 0=Intel 1=Motorola */
|
|
||||||
int msb_first;
|
|
||||||
|
|
||||||
/* Number of bytes to extract (0= unknown/unlimited) */
|
|
||||||
off_t data_size;
|
|
||||||
|
|
||||||
/* Number of extracted data bytes */
|
|
||||||
off_t extract_count;
|
|
||||||
|
|
||||||
|
|
||||||
/* Format dependent parameters */
|
|
||||||
|
|
||||||
/* MS WAVE Format */
|
|
||||||
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
|
|
||||||
|
|
||||||
/* == NumSamples * NumChannels * BitsPerSample/8
|
|
||||||
This is the number of bytes in the data. */
|
|
||||||
unsigned wav_subchunk2_size;
|
|
||||||
|
|
||||||
|
|
||||||
/* Sun Audio, .au */
|
|
||||||
/* info used: http://www.opengroup.org/public/pubs/external/auformat.html */
|
|
||||||
|
|
||||||
/* Number of bytes in non-payload header part */
|
|
||||||
unsigned au_data_location;
|
|
||||||
|
|
||||||
/* Number of payload bytes or 0xffffffff */
|
|
||||||
unsigned au_data_size;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Internal Functions */
|
|
||||||
|
|
||||||
/** Open the audio source pointed to by .path and evaluate suitability.
|
|
||||||
@return -1 failure to open, 0 unsuitable format, 1 success
|
|
||||||
*/
|
|
||||||
static int libdax_audioxtr_open(struct libdax_audioxtr *o, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Identify format and evaluate suitability.
|
|
||||||
@return 0 unsuitable format, 1 format is suitable
|
|
||||||
*/
|
|
||||||
static int libdax_audioxtr_identify(struct libdax_audioxtr *o, int flag);
|
|
||||||
|
|
||||||
/** Specialized identifier for .wav */
|
|
||||||
static int libdax_audioxtr_identify_wav(struct libdax_audioxtr *o, int flag);
|
|
||||||
/** Specialized identifier for .au */
|
|
||||||
static int libdax_audioxtr_identify_au(struct libdax_audioxtr *o, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Convert a byte string into a number (currently only little endian)
|
|
||||||
@param flag Bitfield for control purposes
|
|
||||||
bit0=msb_first
|
|
||||||
@return The resulting number
|
|
||||||
*/
|
|
||||||
static unsigned libdax_audioxtr_to_int(struct libdax_audioxtr *o,
|
|
||||||
unsigned char *bytes, int len, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Prepare for reading of first buffer.
|
|
||||||
@return 0 error, 1 success
|
|
||||||
*/
|
|
||||||
static int libdax_audioxtr_init_reading(struct libdax_audioxtr *o, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* LIBDAX_AUDIOXTR_H_INTERNAL */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! LIBDAX_AUDIOXTR_H_INCLUDED */
|
|
||||||
|
|
@ -1,439 +0,0 @@
|
|||||||
|
|
||||||
/* libdax_msgs
|
|
||||||
Message handling facility of libdax.
|
|
||||||
Copyright (C) 2006 - 2008 Thomas Schmitt <scdbackup@gmx.net>,
|
|
||||||
provided under GPL version 2
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
/* Only this single source module is entitled to do this */
|
|
||||||
#define LIBDAX_MSGS_H_INTERNAL 1
|
|
||||||
|
|
||||||
/* All participants in the messaging system must do this */
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------- libdax_msgs_item ------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
static int libdax_msgs_item_new(struct libdax_msgs_item **item,
|
|
||||||
struct libdax_msgs_item *link, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct libdax_msgs_item *o;
|
|
||||||
struct timeval tv;
|
|
||||||
struct timezone tz;
|
|
||||||
|
|
||||||
(*item)= o=
|
|
||||||
(struct libdax_msgs_item *) malloc(sizeof(struct libdax_msgs_item));
|
|
||||||
if(o==NULL)
|
|
||||||
return(-1);
|
|
||||||
o->timestamp= 0.0;
|
|
||||||
ret= gettimeofday(&tv,&tz);
|
|
||||||
if(ret==0)
|
|
||||||
o->timestamp= tv.tv_sec+0.000001*tv.tv_usec;
|
|
||||||
o->process_id= getpid();
|
|
||||||
o->origin= -1;
|
|
||||||
o->severity= LIBDAX_MSGS_SEV_ALL;
|
|
||||||
o->priority= LIBDAX_MSGS_PRIO_ZERO;
|
|
||||||
o->error_code= 0;
|
|
||||||
o->msg_text= NULL;
|
|
||||||
o->os_errno= 0;
|
|
||||||
o->prev= link;
|
|
||||||
o->next= NULL;
|
|
||||||
if(link!=NULL) {
|
|
||||||
if(link->next!=NULL) {
|
|
||||||
link->next->prev= o;
|
|
||||||
o->next= link->next;
|
|
||||||
}
|
|
||||||
link->next= o;
|
|
||||||
}
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Detaches item from its queue and eventually readjusts start, end pointers
|
|
||||||
of the queue */
|
|
||||||
int libdax_msgs_item_unlink(struct libdax_msgs_item *o,
|
|
||||||
struct libdax_msgs_item **chain_start,
|
|
||||||
struct libdax_msgs_item **chain_end, int flag)
|
|
||||||
{
|
|
||||||
if(o->prev!=NULL)
|
|
||||||
o->prev->next= o->next;
|
|
||||||
if(o->next!=NULL)
|
|
||||||
o->next->prev= o->prev;
|
|
||||||
if(chain_start!=NULL)
|
|
||||||
if(*chain_start == o)
|
|
||||||
*chain_start= o->next;
|
|
||||||
if(chain_end!=NULL)
|
|
||||||
if(*chain_end == o)
|
|
||||||
*chain_end= o->prev;
|
|
||||||
o->next= o->prev= NULL;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_item_destroy(struct libdax_msgs_item **item,
|
|
||||||
int flag)
|
|
||||||
{
|
|
||||||
struct libdax_msgs_item *o;
|
|
||||||
|
|
||||||
o= *item;
|
|
||||||
if(o==NULL)
|
|
||||||
return(0);
|
|
||||||
libdax_msgs_item_unlink(o,NULL,NULL,0);
|
|
||||||
if(o->msg_text!=NULL)
|
|
||||||
free((char *) o->msg_text);
|
|
||||||
free((char *) o);
|
|
||||||
*item= NULL;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
|
|
||||||
int *error_code, char **msg_text, int *os_errno,
|
|
||||||
int flag)
|
|
||||||
{
|
|
||||||
*error_code= item->error_code;
|
|
||||||
*msg_text= item->msg_text;
|
|
||||||
*os_errno= item->os_errno;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
|
|
||||||
double *timestamp, pid_t *process_id, int *origin,
|
|
||||||
int flag)
|
|
||||||
{
|
|
||||||
*timestamp= item->timestamp;
|
|
||||||
*process_id= item->process_id;
|
|
||||||
*origin= item->origin;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_item_get_rank(struct libdax_msgs_item *item,
|
|
||||||
int *severity, int *priority, int flag)
|
|
||||||
{
|
|
||||||
*severity= item->severity;
|
|
||||||
*priority= item->priority;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------- libdax_msgs ---------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_new(struct libdax_msgs **m, int flag)
|
|
||||||
{
|
|
||||||
struct libdax_msgs *o;
|
|
||||||
|
|
||||||
(*m)= o= (struct libdax_msgs *) malloc(sizeof(struct libdax_msgs));
|
|
||||||
if(o==NULL)
|
|
||||||
return(-1);
|
|
||||||
o->refcount= 1;
|
|
||||||
o->oldest= NULL;
|
|
||||||
o->youngest= NULL;
|
|
||||||
o->count= 0;
|
|
||||||
o->queue_severity= LIBDAX_MSGS_SEV_ALL;
|
|
||||||
o->print_severity= LIBDAX_MSGS_SEV_NEVER;
|
|
||||||
strcpy(o->print_id,"libdax: ");
|
|
||||||
|
|
||||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
|
||||||
pthread_mutex_init(&(o->lock_mutex),NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int libdax_msgs_lock(struct libdax_msgs *m, int flag)
|
|
||||||
{
|
|
||||||
|
|
||||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret= pthread_mutex_lock(&(m->lock_mutex));
|
|
||||||
if(ret!=0)
|
|
||||||
return(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int libdax_msgs_unlock(struct libdax_msgs *m, int flag)
|
|
||||||
{
|
|
||||||
|
|
||||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret= pthread_mutex_unlock(&(m->lock_mutex));
|
|
||||||
if(ret!=0)
|
|
||||||
return(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_destroy(struct libdax_msgs **m, int flag)
|
|
||||||
{
|
|
||||||
struct libdax_msgs *o;
|
|
||||||
struct libdax_msgs_item *item, *next_item;
|
|
||||||
|
|
||||||
o= *m;
|
|
||||||
if(o==NULL)
|
|
||||||
return(0);
|
|
||||||
if(o->refcount > 1) {
|
|
||||||
if(libdax_msgs_lock(*m,0)<=0)
|
|
||||||
return(-1);
|
|
||||||
o->refcount--;
|
|
||||||
libdax_msgs_unlock(*m,0);
|
|
||||||
*m= NULL;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
|
||||||
if(pthread_mutex_destroy(&(o->lock_mutex))!=0) {
|
|
||||||
pthread_mutex_unlock(&(o->lock_mutex));
|
|
||||||
pthread_mutex_destroy(&(o->lock_mutex));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(item= o->oldest; item!=NULL; item= next_item) {
|
|
||||||
next_item= item->next;
|
|
||||||
libdax_msgs_item_destroy(&item,0);
|
|
||||||
}
|
|
||||||
free((char *) o);
|
|
||||||
*m= NULL;
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_refer(struct libdax_msgs **pt, struct libdax_msgs *m, int flag)
|
|
||||||
{
|
|
||||||
if(libdax_msgs_lock(m,0)<=0)
|
|
||||||
return(0);
|
|
||||||
m->refcount++;
|
|
||||||
*pt= m;
|
|
||||||
libdax_msgs_unlock(m,0);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
|
|
||||||
int print_severity, char *print_id, int flag)
|
|
||||||
{
|
|
||||||
if(libdax_msgs_lock(m,0)<=0)
|
|
||||||
return(0);
|
|
||||||
m->queue_severity= queue_severity;
|
|
||||||
m->print_severity= print_severity;
|
|
||||||
strncpy(m->print_id,print_id,80);
|
|
||||||
m->print_id[80]= 0;
|
|
||||||
libdax_msgs_unlock(m,0);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs__text_to_sev(char *severity_name, int *severity,
|
|
||||||
int flag)
|
|
||||||
{
|
|
||||||
if(strncmp(severity_name,"NEVER",5)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_NEVER;
|
|
||||||
else if(strncmp(severity_name,"ABORT",5)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_ABORT;
|
|
||||||
else if(strncmp(severity_name,"FATAL",5)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_FATAL;
|
|
||||||
else if(strncmp(severity_name,"FAILURE",7)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_FAILURE;
|
|
||||||
else if(strncmp(severity_name,"MISHAP",6)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_MISHAP;
|
|
||||||
else if(strncmp(severity_name,"SORRY",5)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_SORRY;
|
|
||||||
else if(strncmp(severity_name,"WARNING",7)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_WARNING;
|
|
||||||
else if(strncmp(severity_name,"HINT",4)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_HINT;
|
|
||||||
else if(strncmp(severity_name,"NOTE",4)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_NOTE;
|
|
||||||
else if(strncmp(severity_name,"UPDATE",6)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_UPDATE;
|
|
||||||
else if(strncmp(severity_name,"DEBUG",5)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_DEBUG;
|
|
||||||
else if(strncmp(severity_name,"ERRFILE",7)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_ERRFILE;
|
|
||||||
else if(strncmp(severity_name,"ALL",3)==0)
|
|
||||||
*severity= LIBDAX_MSGS_SEV_ALL;
|
|
||||||
else {
|
|
||||||
*severity= LIBDAX_MSGS_SEV_ALL;
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs__sev_to_text(int severity, char **severity_name,
|
|
||||||
int flag)
|
|
||||||
{
|
|
||||||
if(flag&1) {
|
|
||||||
*severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nMISHAP\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL";
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
*severity_name= "";
|
|
||||||
if(severity>=LIBDAX_MSGS_SEV_NEVER)
|
|
||||||
*severity_name= "NEVER";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_ABORT)
|
|
||||||
*severity_name= "ABORT";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_FATAL)
|
|
||||||
*severity_name= "FATAL";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_FAILURE)
|
|
||||||
*severity_name= "FAILURE";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_MISHAP)
|
|
||||||
*severity_name= "MISHAP";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_SORRY)
|
|
||||||
*severity_name= "SORRY";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_WARNING)
|
|
||||||
*severity_name= "WARNING";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_HINT)
|
|
||||||
*severity_name= "HINT";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_NOTE)
|
|
||||||
*severity_name= "NOTE";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_UPDATE)
|
|
||||||
*severity_name= "UPDATE";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
|
|
||||||
*severity_name= "DEBUG";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_ERRFILE)
|
|
||||||
*severity_name= "ERRFILE";
|
|
||||||
else if(severity>=LIBDAX_MSGS_SEV_ALL)
|
|
||||||
*severity_name= "ALL";
|
|
||||||
else {
|
|
||||||
*severity_name= "";
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_submit(struct libdax_msgs *m, int origin, int error_code,
|
|
||||||
int severity, int priority, char *msg_text,
|
|
||||||
int os_errno, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
char *textpt,*sev_name,sev_text[81];
|
|
||||||
struct libdax_msgs_item *item= NULL;
|
|
||||||
|
|
||||||
if(severity >= m->print_severity) {
|
|
||||||
if(msg_text==NULL)
|
|
||||||
textpt= "";
|
|
||||||
else
|
|
||||||
textpt= msg_text;
|
|
||||||
sev_text[0]= 0;
|
|
||||||
ret= libdax_msgs__sev_to_text(severity,&sev_name,0);
|
|
||||||
if(ret>0)
|
|
||||||
sprintf(sev_text,"%s : ",sev_name);
|
|
||||||
|
|
||||||
fprintf(stderr,"%s%s%s\n",m->print_id,sev_text,textpt);
|
|
||||||
if(os_errno!=0) {
|
|
||||||
ret= libdax_msgs_lock(m,0);
|
|
||||||
if(ret<=0)
|
|
||||||
return(-1);
|
|
||||||
fprintf(stderr,"%s( Most recent system error: %d '%s' )\n",
|
|
||||||
m->print_id,os_errno,strerror(os_errno));
|
|
||||||
libdax_msgs_unlock(m,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if(severity < m->queue_severity)
|
|
||||||
return(0);
|
|
||||||
|
|
||||||
ret= libdax_msgs_lock(m,0);
|
|
||||||
if(ret<=0)
|
|
||||||
return(-1);
|
|
||||||
ret= libdax_msgs_item_new(&item,m->youngest,0);
|
|
||||||
if(ret<=0)
|
|
||||||
goto failed;
|
|
||||||
item->origin= origin;
|
|
||||||
item->error_code= error_code;
|
|
||||||
item->severity= severity;
|
|
||||||
item->priority= priority;
|
|
||||||
if(msg_text!=NULL) {
|
|
||||||
item->msg_text= malloc(strlen(msg_text)+1);
|
|
||||||
if(item->msg_text==NULL)
|
|
||||||
goto failed;
|
|
||||||
strcpy(item->msg_text,msg_text);
|
|
||||||
}
|
|
||||||
item->os_errno= os_errno;
|
|
||||||
if(m->oldest==NULL)
|
|
||||||
m->oldest= item;
|
|
||||||
m->youngest= item;
|
|
||||||
m->count++;
|
|
||||||
libdax_msgs_unlock(m,0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
fprintf(stderr,"libdax_experimental: message submitted to queue (now %d)\n",
|
|
||||||
m->count);
|
|
||||||
*/
|
|
||||||
|
|
||||||
return(1);
|
|
||||||
failed:;
|
|
||||||
libdax_msgs_item_destroy(&item,0);
|
|
||||||
libdax_msgs_unlock(m,0);
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_obtain(struct libdax_msgs *m, struct libdax_msgs_item **item,
|
|
||||||
int severity, int priority, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct libdax_msgs_item *im, *next_im= NULL;
|
|
||||||
|
|
||||||
*item= NULL;
|
|
||||||
ret= libdax_msgs_lock(m,0);
|
|
||||||
if(ret<=0)
|
|
||||||
return(-1);
|
|
||||||
for(im= m->oldest; im!=NULL; im= next_im) {
|
|
||||||
for(; im!=NULL; im= next_im) {
|
|
||||||
next_im= im->next;
|
|
||||||
if(im->severity>=severity)
|
|
||||||
break;
|
|
||||||
libdax_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
|
|
||||||
libdax_msgs_item_destroy(&im,0); /* severity too low: delete */
|
|
||||||
}
|
|
||||||
if(im==NULL)
|
|
||||||
break;
|
|
||||||
if(im->priority>=priority)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(im==NULL)
|
|
||||||
{ret= 0; goto ex;}
|
|
||||||
libdax_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
|
|
||||||
*item= im;
|
|
||||||
ret= 1;
|
|
||||||
ex:;
|
|
||||||
libdax_msgs_unlock(m,0);
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int libdax_msgs_destroy_item(struct libdax_msgs *m,
|
|
||||||
struct libdax_msgs_item **item, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret= libdax_msgs_lock(m,0);
|
|
||||||
if(ret<=0)
|
|
||||||
return(-1);
|
|
||||||
ret= libdax_msgs_item_destroy(item,0);
|
|
||||||
libdax_msgs_unlock(m,0);
|
|
||||||
return(ret);
|
|
||||||
}
|
|
||||||
|
|
@ -1,682 +0,0 @@
|
|||||||
|
|
||||||
/* libdax_msgs
|
|
||||||
Message handling facility of libdax.
|
|
||||||
Copyright (C) 2006-2008 Thomas Schmitt <scdbackup@gmx.net>,
|
|
||||||
provided under GPL version 2
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
*Never* set this macro outside libdax_msgs.c !
|
|
||||||
The entrails of the message handling facility are not to be seen by
|
|
||||||
the other library components or the applications.
|
|
||||||
*/
|
|
||||||
#ifdef LIBDAX_MSGS_H_INTERNAL
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
struct libdax_msgs_item {
|
|
||||||
|
|
||||||
double timestamp;
|
|
||||||
pid_t process_id;
|
|
||||||
int origin;
|
|
||||||
|
|
||||||
int severity;
|
|
||||||
int priority;
|
|
||||||
|
|
||||||
/* Apply for your developer's error code range at
|
|
||||||
libburn-hackers@pykix.org
|
|
||||||
Report introduced codes in the list below. */
|
|
||||||
int error_code;
|
|
||||||
|
|
||||||
char *msg_text;
|
|
||||||
int os_errno;
|
|
||||||
|
|
||||||
struct libdax_msgs_item *prev,*next;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct libdax_msgs {
|
|
||||||
|
|
||||||
int refcount;
|
|
||||||
|
|
||||||
struct libdax_msgs_item *oldest;
|
|
||||||
struct libdax_msgs_item *youngest;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
int queue_severity;
|
|
||||||
int print_severity;
|
|
||||||
char print_id[81];
|
|
||||||
|
|
||||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
|
||||||
pthread_mutex_t lock_mutex;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* LIBDAX_MSGS_H_INTERNAL */
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef LIBDAX_MSGS_H_INCLUDED
|
|
||||||
#define LIBDAX_MSGS_H_INCLUDED 1
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef LIBDAX_MSGS_H_INTERNAL
|
|
||||||
|
|
||||||
|
|
||||||
/* Architectural aspects */
|
|
||||||
/*
|
|
||||||
libdax_msgs is designed to serve in libraries which want to offer their
|
|
||||||
applications a way to control the output of library messages. It shall be
|
|
||||||
incorporated by an owner, i.e. a software entity which encloses the code
|
|
||||||
of the .c file.
|
|
||||||
|
|
||||||
Owner of libdax_msgs is libburn. A fully compatible variant named libiso_msgs
|
|
||||||
is owned by libisofs and can get generated by a script of the libburn
|
|
||||||
project: libburn/libdax_msgs_to_xyz_msgs.sh .
|
|
||||||
|
|
||||||
Reason: One cannot link two owners of the same variant together because
|
|
||||||
both would offer the same functions to the linker. For that situation one
|
|
||||||
has to create a compatible variant as it is done for libisofs.
|
|
||||||
|
|
||||||
Compatible variants may get plugged together by call combinations like
|
|
||||||
burn_set_messenger(iso_get_messenger());
|
|
||||||
A new variant would demand a _set_messenger() function if it has to work
|
|
||||||
with libisofs. If only libburn is planned as link partner then a simple
|
|
||||||
_get_messenger() does suffice.
|
|
||||||
Take care to shutdown libburn before its provider of the *_msgs object
|
|
||||||
gets shut down.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Public Opaque Handles */
|
|
||||||
|
|
||||||
/** A pointer to this is a opaque handle to a message handling facility */
|
|
||||||
struct libdax_msgs;
|
|
||||||
|
|
||||||
/** A pointer to this is a opaque handle to a single message item */
|
|
||||||
struct libdax_msgs_item;
|
|
||||||
|
|
||||||
#endif /* ! LIBDAX_MSGS_H_INTERNAL */
|
|
||||||
|
|
||||||
|
|
||||||
/* Public Macros */
|
|
||||||
|
|
||||||
|
|
||||||
/* Registered Severities */
|
|
||||||
|
|
||||||
/* It is well advisable to let applications select severities via strings and
|
|
||||||
forwarded functions libdax_msgs__text_to_sev(), libdax_msgs__sev_to_text().
|
|
||||||
These macros are for use by the owner of libdax_msgs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Use this to get messages of any severity. Do not use for submitting.
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_ALL 0x00000000
|
|
||||||
|
|
||||||
|
|
||||||
/** Messages of this severity shall transport plain disk file paths
|
|
||||||
whenever an event of severity SORRY or above is related with an
|
|
||||||
individual disk file.
|
|
||||||
No message text shall be added to the file path. The ERRFILE message
|
|
||||||
shall be issued before the human readable message which carries the
|
|
||||||
true event severity. That message should contain the file path so it
|
|
||||||
can be found by strstr(message, path)!=NULL.
|
|
||||||
The error code shall be the same as with the human readable message.
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_ERRFILE 0x08000000
|
|
||||||
|
|
||||||
|
|
||||||
/** Debugging messages not to be visible to normal users by default
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_DEBUG 0x10000000
|
|
||||||
|
|
||||||
/** Update of a progress report about long running actions
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_UPDATE 0x20000000
|
|
||||||
|
|
||||||
/** Not so usual events which were gracefully handled
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_NOTE 0x30000000
|
|
||||||
|
|
||||||
/** Possibilities to achieve a better result
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_HINT 0x40000000
|
|
||||||
|
|
||||||
/** Warnings about problems which could not be handled optimally
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_WARNING 0x50000000
|
|
||||||
|
|
||||||
|
|
||||||
/** Non-fatal error messages indicating that parts of an action failed but
|
|
||||||
processing may go on if one accepts deviations from the desired result.
|
|
||||||
|
|
||||||
SORRY may also be the severity for incidents which are severe enough
|
|
||||||
for FAILURE but happen within already started irrevocable actions,
|
|
||||||
like ISO image generation. A precondition for such a severity ease is
|
|
||||||
that the action can be continued after the incident.
|
|
||||||
See below MISHAP for what xorriso would need instead of this kind of SORRY
|
|
||||||
and generates for itself in case of libisofs image generation.
|
|
||||||
|
|
||||||
E.g.: A pattern yields no result.
|
|
||||||
A speed setting cannot be made.
|
|
||||||
A libisofs input file is inaccessible during image generation.
|
|
||||||
|
|
||||||
After SORRY a function should try to go on if that makes any sense
|
|
||||||
and if no threshold prescribes abort on SORRY. The function should
|
|
||||||
nevertheless indicate some failure in its return value.
|
|
||||||
It should - but it does not have to.
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_SORRY 0x60000000
|
|
||||||
|
|
||||||
|
|
||||||
/** A FAILURE (see below) which can be tolerated during long lasting
|
|
||||||
operations just because they cannot simply be stopped or revoked.
|
|
||||||
|
|
||||||
xorriso converts libisofs SORRY messages issued during image generation
|
|
||||||
into MISHAP messages in order to allow its evaluators to distinguish
|
|
||||||
image generation problems from minor image composition problems.
|
|
||||||
E.g.:
|
|
||||||
A libisofs input file is inaccessible during image generation.
|
|
||||||
|
|
||||||
After a MISHAP a function should behave like after SORRY.
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_MISHAP 0x64000000
|
|
||||||
|
|
||||||
|
|
||||||
/** Non-fatal error indicating that an important part of an action failed and
|
|
||||||
that only a new setup of preconditions will give hope for sufficient
|
|
||||||
success.
|
|
||||||
|
|
||||||
E.g.: No media is inserted in the output drive.
|
|
||||||
No write mode can be found for inserted media.
|
|
||||||
A libisofs input file is inaccessible during grafting.
|
|
||||||
|
|
||||||
After FAILURE a function should end with a return value indicating failure.
|
|
||||||
It is at the discretion of the function whether it ends immediately in any
|
|
||||||
case or whether it tries to go on if the eventual threshold allows.
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_FAILURE 0x68000000
|
|
||||||
|
|
||||||
|
|
||||||
/** An error message which puts the whole operation of the program in question
|
|
||||||
|
|
||||||
E.g.: Not enough memory for essential temporary objects.
|
|
||||||
Irregular errors from resources.
|
|
||||||
Programming errors (soft assert).
|
|
||||||
|
|
||||||
After FATAL a function should end very soon with a return value
|
|
||||||
indicating severe failure.
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_FATAL 0x70000000
|
|
||||||
|
|
||||||
|
|
||||||
/** A message from an abort handler which will finally finish libburn
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_ABORT 0x71000000
|
|
||||||
|
|
||||||
/** A severity to exclude resp. discard any possible message.
|
|
||||||
Do not use this severity for submitting.
|
|
||||||
*/
|
|
||||||
#define LIBDAX_MSGS_SEV_NEVER 0x7fffffff
|
|
||||||
|
|
||||||
|
|
||||||
/* Registered Priorities */
|
|
||||||
|
|
||||||
/* Priorities are to be selected by the programmers and not by the user. */
|
|
||||||
|
|
||||||
#define LIBDAX_MSGS_PRIO_ZERO 0x00000000
|
|
||||||
#define LIBDAX_MSGS_PRIO_LOW 0x10000000
|
|
||||||
#define LIBDAX_MSGS_PRIO_MEDIUM 0x20000000
|
|
||||||
#define LIBDAX_MSGS_PRIO_HIGH 0x30000000
|
|
||||||
#define LIBDAX_MSGS_PRIO_TOP 0x7ffffffe
|
|
||||||
|
|
||||||
/* Do not use this priority for submitting */
|
|
||||||
#define LIBDAX_MSGS_PRIO_NEVER 0x7fffffff
|
|
||||||
|
|
||||||
|
|
||||||
/* Origin numbers of libburn drives may range from 0 to 1048575 */
|
|
||||||
#define LIBDAX_MSGS_ORIGIN_DRIVE_BASE 0
|
|
||||||
#define LIBDAX_MSGS_ORIGIN_DRIVE_TOP 0xfffff
|
|
||||||
|
|
||||||
/* Origin numbers of libisofs images may range from 1048575 to 2097152 */
|
|
||||||
#define LIBDAX_MSGS_ORIGIN_IMAGE_BASE 0x100000
|
|
||||||
#define LIBDAX_MSGS_ORIGIN_IMAGE_TOP 0x1fffff
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Public Functions */
|
|
||||||
|
|
||||||
/* Calls initiated from inside the direct owner (e.g. from libburn) */
|
|
||||||
|
|
||||||
|
|
||||||
/** Create new empty message handling facility with queue and issue a first
|
|
||||||
official reference to it.
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return >0 success, <=0 failure
|
|
||||||
*/
|
|
||||||
int libdax_msgs_new(struct libdax_msgs **m, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Destroy a message handling facility and all its eventual messages.
|
|
||||||
The submitted pointer gets set to NULL.
|
|
||||||
Actually only the last destroy call of all offical references to the object
|
|
||||||
will really dispose it. All others just decrement the reference counter.
|
|
||||||
Call this function only with official reference pointers obtained by
|
|
||||||
libdax_msgs_new() or libdax_msgs_refer(), and only once per such pointer.
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 for success, 0 for pointer to NULL, -1 for fatal error
|
|
||||||
*/
|
|
||||||
int libdax_msgs_destroy(struct libdax_msgs **m, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Create an official reference to an existing libdax_msgs object. The
|
|
||||||
references keep the object alive at least until it is released by
|
|
||||||
a matching number of destroy calls. So each reference MUST be revoked
|
|
||||||
by exactly one call to libdax_msgs_destroy().
|
|
||||||
@param pt The pointer to be set and registered
|
|
||||||
@param m A pointer to the existing object
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 for success, 0 for failure
|
|
||||||
*/
|
|
||||||
int libdax_msgs_refer(struct libdax_msgs **pt, struct libdax_msgs *o, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Submit a message to a message handling facility.
|
|
||||||
@param origin program specific identification number of the originator of
|
|
||||||
a message. E.g. drive number. Programs should have an own
|
|
||||||
range of origin numbers. See above LIBDAX_MSGS_ORIGIN_*_BASE
|
|
||||||
Use -1 if no number is known.
|
|
||||||
@param error_code Unique error code. Use only registered codes. See below.
|
|
||||||
The same unique error_code may be issued at different
|
|
||||||
occasions but those should be equivalent out of the view
|
|
||||||
of a libdax_msgs application. (E.g. "cannot open ATA drive"
|
|
||||||
versus "cannot open SCSI drive" would be equivalent.)
|
|
||||||
@param severity The LIBDAX_MSGS_SEV_* of the event.
|
|
||||||
@param priority The LIBDAX_MSGS_PRIO_* number of the event.
|
|
||||||
@param msg_text Printable and human readable message text.
|
|
||||||
@param os_errno Eventual error code from operating system (0 if none)
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 on success, 0 on rejection, <0 for severe errors
|
|
||||||
*/
|
|
||||||
int libdax_msgs_submit(struct libdax_msgs *m, int origin, int error_code,
|
|
||||||
int severity, int priority, char *msg_text,
|
|
||||||
int os_errno, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Calls from applications (to be forwarded by direct owner) */
|
|
||||||
|
|
||||||
|
|
||||||
/** Convert a registered severity number into a severity name
|
|
||||||
@param flag Bitfield for control purposes:
|
|
||||||
bit0= list all severity names in a newline separated string
|
|
||||||
@return >0 success, <=0 failure
|
|
||||||
*/
|
|
||||||
int libdax_msgs__sev_to_text(int severity, char **severity_name,
|
|
||||||
int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Convert a severity name into a severity number,
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return >0 success, <=0 failure
|
|
||||||
*/
|
|
||||||
int libdax_msgs__text_to_sev(char *severity_name, int *severity,
|
|
||||||
int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Set minimum severity for messages to be queued (default
|
|
||||||
LIBDAX_MSGS_SEV_ALL) and for messages to be printed directly to stderr
|
|
||||||
(default LIBDAX_MSGS_SEV_NEVER).
|
|
||||||
@param print_id A text of at most 80 characters to be printed before
|
|
||||||
any eventually printed message (default is "libdax: ").
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return always 1 for now
|
|
||||||
*/
|
|
||||||
int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
|
|
||||||
int print_severity, char *print_id, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Obtain a message item that has at least the given severity and priority.
|
|
||||||
Usually all older messages of lower severity are discarded then. If no
|
|
||||||
item of sufficient severity was found, all others are discarded from the
|
|
||||||
queue.
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 if a matching item was found, 0 if not, <0 for severe errors
|
|
||||||
*/
|
|
||||||
int libdax_msgs_obtain(struct libdax_msgs *m, struct libdax_msgs_item **item,
|
|
||||||
int severity, int priority, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Destroy a message item obtained by libdax_msgs_obtain(). The submitted
|
|
||||||
pointer gets set to NULL.
|
|
||||||
Caution: Copy eventually obtained msg_text before destroying the item,
|
|
||||||
if you want to use it further.
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 for success, 0 for pointer to NULL, <0 for severe errors
|
|
||||||
*/
|
|
||||||
int libdax_msgs_destroy_item(struct libdax_msgs *m,
|
|
||||||
struct libdax_msgs_item **item, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Obtain from a message item the three application oriented components as
|
|
||||||
submitted with the originating call of libdax_msgs_submit().
|
|
||||||
Caution: msg_text becomes a pointer into item, not a copy.
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 on success, 0 on invalid item, <0 for servere errors
|
|
||||||
*/
|
|
||||||
int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
|
|
||||||
int *error_code, char **msg_text, int *os_errno,
|
|
||||||
int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Obtain from a message item the submitter identification submitted
|
|
||||||
with the originating call of libdax_msgs_submit().
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 on success, 0 on invalid item, <0 for servere errors
|
|
||||||
*/
|
|
||||||
int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
|
|
||||||
double *timestamp, pid_t *process_id, int *origin,
|
|
||||||
int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Obtain from a message item severity and priority as submitted
|
|
||||||
with the originating call of libdax_msgs_submit().
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 on success, 0 on invalid item, <0 for servere errors
|
|
||||||
*/
|
|
||||||
int libdax_msgs_item_get_rank(struct libdax_msgs_item *item,
|
|
||||||
int *severity, int *priority, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef LIDBAX_MSGS_________________
|
|
||||||
|
|
||||||
|
|
||||||
/* Registered Error Codes */
|
|
||||||
|
|
||||||
|
|
||||||
Format: error_code (LIBDAX_MSGS_SEV_*,LIBDAX_MSGS_PRIO_*) = explanation
|
|
||||||
If no severity or priority are fixely associated, use "(,)".
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Range "libdax_msgs" : 0x00000000 to 0x0000ffff
|
|
||||||
|
|
||||||
0x00000000 (ALL,ZERO) = Initial setting in new libdax_msgs_item
|
|
||||||
0x00000001 (DEBUG,ZERO) = Test error message
|
|
||||||
0x00000002 (DEBUG,ZERO) = Debugging message
|
|
||||||
0x00000003 (FATAL,HIGH) = Out of virtual memory
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Range "elmom" : 0x00010000 to 0x0001ffff
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Range "scdbackup" : 0x00020000 to 0x0002ffff
|
|
||||||
|
|
||||||
Acessing and defending drives:
|
|
||||||
|
|
||||||
0x00020001 (SORRY,LOW) = Cannot open busy device
|
|
||||||
0x00020002 (SORRY,HIGH) = Encountered error when closing drive
|
|
||||||
0x00020003 (SORRY,HIGH) = Could not grab drive
|
|
||||||
0x00020004 (NOTE,HIGH) = Opened O_EXCL scsi sibling
|
|
||||||
0x00020005 (SORRY,HIGH) = Failed to open device
|
|
||||||
0x00020006 (FATAL,HIGH) = Too many scsi siblings
|
|
||||||
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
|
|
||||||
0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock
|
|
||||||
0x00020009 (SORRY,HIGH) = Neither stdio-path nor its directory exist
|
|
||||||
|
|
||||||
General library operations:
|
|
||||||
|
|
||||||
0x00020101 (WARNING,HIGH) = Cannot find given worker item
|
|
||||||
0x00020102 (SORRY,HIGH) = A drive operation is still going on
|
|
||||||
0x00020103 (WARNING,HIGH) = After scan a drive operation is still going on
|
|
||||||
0x00020104 (SORRY,HIGH) = NULL pointer caught
|
|
||||||
0x00020105 (SORRY,HIGH) = Drive is already released
|
|
||||||
0x00020106 (SORRY,HIGH) = Drive is busy on attempt to close
|
|
||||||
0x00020107 (WARNING,HIGH) = A drive is still busy on shutdown of library
|
|
||||||
0x00020108 (SORRY,HIGH) = Drive is not grabbed on disc status inquiry
|
|
||||||
0x00020108 (FATAL,HIGH) = Could not allocate new drive object
|
|
||||||
0x00020109 (FATAL,HIGH) = Library not running
|
|
||||||
0x0002010a (FATAL,HIGH) = Unsuitable track mode
|
|
||||||
0x0002010b (FATAL,HIGH) = Burn run failed
|
|
||||||
0x0002010c (FATAL,HIGH) = Failed to transfer command to drive
|
|
||||||
0x0002010d (DEBUG,HIGH) = Could not inquire TOC
|
|
||||||
0x0002010e (FATAL,HIGH) = Attempt to read ATIP from ungrabbed drive
|
|
||||||
0x0002010f (DEBUG,HIGH) = SCSI error condition on command
|
|
||||||
0x00020110 (FATAL,HIGH) = Persistent drive address too long
|
|
||||||
0x00020111 (FATAL,HIGH) = Could not allocate new auxiliary object
|
|
||||||
0x00020112 (SORRY,HIGH) = Bad combination of write_type and block_type
|
|
||||||
0x00020113 (FATAL,HIGH) = Drive capabilities not inquired yet
|
|
||||||
0x00020114 (SORRY,HIGH) = Attempt to set ISRC with bad data
|
|
||||||
0x00020115 (SORRY,HIGH) = Attempt to set track mode to unusable value
|
|
||||||
0x00020116 (FATAL,HIGH) = Track mode has unusable value
|
|
||||||
0x00020117 (FATAL,HIGH) = toc_entry of drive is already in use
|
|
||||||
0x00020118 (DEBUG,HIGH) = Closing track
|
|
||||||
0x00020119 (DEBUG,HIGH) = Closing session
|
|
||||||
0x0002011a (NOTE,HIGH) = Padding up track to minimum size
|
|
||||||
0x0002011b (FATAL,HIGH) = Attempt to read track info from ungrabbed drive
|
|
||||||
0x0002011c (FATAL,HIGH) = Attempt to read track info from busy drive
|
|
||||||
0x0002011d (FATAL,HIGH) = SCSI error on write
|
|
||||||
0x0002011e (SORRY,HIGH) = Unsuitable media detected
|
|
||||||
0x0002011f (SORRY,HIGH) = Burning is restricted to a single track
|
|
||||||
0x00020120 (NOTE,HIGH) = FORMAT UNIT ignored
|
|
||||||
0x00020121 (FATAL,HIGH) = Write preparation setup failed
|
|
||||||
0x00020122 (FATAL,HIGH) = SCSI error on format_unit
|
|
||||||
0x00020123 (SORRY,HIGH) = DVD Media are unsuitable for desired track type
|
|
||||||
0x00020124 (SORRY,HIGH) = SCSI error on set_streaming
|
|
||||||
0x00020125 (SORRY,HIGH) = Write start address not supported
|
|
||||||
0x00020126 (SORRY,HIGH) = Write start address not properly aligned
|
|
||||||
0x00020127 (NOTE,HIGH) = Write start address is ...
|
|
||||||
0x00020128 (FATAL,HIGH) = Unsupported inquiry_type with mmc_get_performance
|
|
||||||
0x00020129 (SORRY,HIGH) = Will not format media type
|
|
||||||
0x0002012a (FATAL,HIGH) = Cannot inquire write mode capabilities
|
|
||||||
0x0002012b (FATAL,HIGH) = Drive offers no suitable write mode with this job
|
|
||||||
0x0002012c (SORRY,HIGH) = Too many logical tracks recorded
|
|
||||||
0x0002012d (FATAL,HIGH) = Exceeding range of permissible write addresses
|
|
||||||
0x0002012e (NOTE,HIGH) = Activated track default size
|
|
||||||
0x0002012f (SORRY,HIGH) = SAO is restricted to single fixed size session
|
|
||||||
0x00020130 (SORRY,HIGH) = Drive and media state unsuitable for blanking
|
|
||||||
0x00020131 (SORRY,HIGH) = No suitable formatting type offered by drive
|
|
||||||
0x00020132 (SORRY,HIGH) = Selected format is not suitable for libburn
|
|
||||||
0x00020133 (SORRY,HIGH) = Cannot mix data and audio in SAO mode
|
|
||||||
0x00020134 (NOTE,HIGH) = Defaulted TAO to DAO
|
|
||||||
0x00020135 (SORRY,HIGH) = Cannot perform TAO, job unsuitable for DAO
|
|
||||||
0x00020136 (SORRY,HIGH) = DAO burning restricted to single fixed size track
|
|
||||||
0x00020137 (HINT,HIGH) = TAO would be possible
|
|
||||||
0x00020138 (FATAL,HIGH) = Cannot reserve track
|
|
||||||
0x00020139 (SORRY,HIGH) = Write job parameters are unsuitable
|
|
||||||
0x0002013a (FATAL,HIGH) = No suitable media detected
|
|
||||||
0x0002013b (DEBUG,HIGH) = SCSI command indicates host or driver error
|
|
||||||
0x0002013c (SORRY,HIGH) = Malformed capabilities page 2Ah received
|
|
||||||
0x0002013d (DEBUG,LOW) = Waiting for free buffer space takes long time
|
|
||||||
0x0002013e (SORRY,HIGH) = Timeout with waiting for free buffer. Now disabled
|
|
||||||
0x0002013f (DEBUG,LOW) = Reporting total time spent with waiting for buffer
|
|
||||||
0x00020140 (FATAL,HIGH) = Drive is busy on attempt to write random access
|
|
||||||
0x00020141 (SORRY,HIGH) = Write data count not properly aligned
|
|
||||||
0x00020142 (FATAL,HIGH) = Drive is not grabbed on random access write
|
|
||||||
0x00020143 (SORRY,HIGH) = Read start address not properly aligned
|
|
||||||
0x00020144 (SORRY,HIGH) = SCSI error on read
|
|
||||||
0x00020145 (FATAL,HIGH) = Drive is busy on attempt to read data
|
|
||||||
0x00020146 (FATAL,HIGH) = Drive is a virtual placeholder
|
|
||||||
0x00020147 (SORRY,HIGH) = Cannot address start byte
|
|
||||||
0x00020148 (SORRY,HIGH) = Cannot write desired amount of data
|
|
||||||
0x00020149 (SORRY,HIGH) = Unsuitable filetype for pseudo-drive
|
|
||||||
0x0002014a (SORRY,HIGH) = Cannot read desired amount of data
|
|
||||||
0x0002014b (SORRY,HIGH) = Drive is already registered resp. scanned
|
|
||||||
0x0002014c (FATAL,HIGH) = Emulated drive caught in SCSI function
|
|
||||||
0x0002014d (SORRY,HIGH) = Asynchromous SCSI error
|
|
||||||
0x0002014f (SORRY,HIGH) = Timeout with asynchromous SCSI command
|
|
||||||
0x00020150 (DEBUG,LOW) = Reporting asynchronous waiting time
|
|
||||||
0x00020151 (FATAL,HIGH) = Read attempt on write-only drive
|
|
||||||
0x00020152 (FATAL,HIGH) = Cannot start fifo thread
|
|
||||||
0x00020153 (SORRY,HIGH) = Read error on fifo input
|
|
||||||
0x00020154 (NOTE,HIGH) = Forwarded input error ends output
|
|
||||||
0x00020155 (SORRY,HIGH) = Desired fifo buffer too large
|
|
||||||
0x00020156 (SORRY,HIGH) = Desired fifo buffer too small
|
|
||||||
0x00020157 (FATAL,HIGH) = burn_source is not a fifo object
|
|
||||||
0x00020158 (DEBUG,LOW) = Reporting thread disposal precautions
|
|
||||||
0x00020159 (DEBUG,HIGH) = TOC Format 0 returns inconsistent data
|
|
||||||
|
|
||||||
libdax_audioxtr:
|
|
||||||
0x00020200 (SORRY,HIGH) = Cannot open audio source file
|
|
||||||
0x00020201 (SORRY,HIGH) = Audio source file has unsuitable format
|
|
||||||
0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Range "vreixo" : 0x00030000 to 0x0003ffff
|
|
||||||
|
|
||||||
0x0003ffff (FAILURE,HIGH) = Operation canceled
|
|
||||||
0x0003fffe (FATAL,HIGH) = Unknown or unexpected fatal error
|
|
||||||
0x0003fffd (FAILURE,HIGH) = Unknown or unexpected error
|
|
||||||
0x0003fffc (FATAL,HIGH) = Internal programming error
|
|
||||||
0x0003fffb (FAILURE,HIGH) = NULL pointer where NULL not allowed
|
|
||||||
0x0003fffa (FATAL,HIGH) = Memory allocation error
|
|
||||||
0x0003fff9 (FATAL,HIGH) = Interrupted by a signal
|
|
||||||
0x0003fff8 (FAILURE,HIGH) = Invalid parameter value
|
|
||||||
0x0003fff7 (FATAL,HIGH) = Cannot create a needed thread
|
|
||||||
0x0003fff6 (FAILURE,HIGH) = Write error
|
|
||||||
0x0003fff5 (FAILURE,HIGH) = Buffer read error
|
|
||||||
0x0003ffc0 (FAILURE,HIGH) = Trying to add a node already added to another dir
|
|
||||||
0x0003ffbf (FAILURE,HIGH) = Node with same name already exist
|
|
||||||
0x0003ffbe (FAILURE,HIGH) = Trying to remove a node that was not added to dir
|
|
||||||
0x0003ffbd (FAILURE,HIGH) = A requested node does not exist
|
|
||||||
0x0003ffbc (FAILURE,HIGH) = Image already bootable
|
|
||||||
0x0003ffbb (FAILURE,HIGH) = Trying to use an invalid file as boot image
|
|
||||||
0x0003ff80 (FAILURE,HIGH) = Error on file operation
|
|
||||||
0x0003ff7f (FAILURE,HIGH) = Trying to open an already openned file
|
|
||||||
0x0003ff7e (FAILURE,HIGH) = Access to file is not allowed
|
|
||||||
0x0003ff7d (FAILURE,HIGH) = Incorrect path to file
|
|
||||||
0x0003ff7c (FAILURE,HIGH) = The file does not exist in the filesystem
|
|
||||||
0x0003ff7b (FAILURE,HIGH) = Trying to read or close a file not openned
|
|
||||||
0x0003ff7a (FAILURE,HIGH) = Directory used where no dir is expected
|
|
||||||
0x0003ff79 (FAILURE,HIGH) = File read error
|
|
||||||
0x0003ff78 (FAILURE,HIGH) = Not dir used where a dir is expected
|
|
||||||
0x0003ff77 (FAILURE,HIGH) = Not symlink used where a symlink is expected
|
|
||||||
0x0003ff76 (FAILURE,HIGH) = Cannot seek to specified location
|
|
||||||
0x0003ff75 (HINT,MEDIUM) = File not supported in ECMA-119 tree and ignored
|
|
||||||
0x0003ff74 (HINT,MEDIUM) = File bigger than supported by used standard
|
|
||||||
0x0003ff73 (MISHAP,HIGH) = File read error during image creation
|
|
||||||
0x0003ff72 (HINT,MEDIUM) = Cannot convert filename to requested charset
|
|
||||||
0x0003ff71 (SORRY,HIGH) = File cannot be added to the tree
|
|
||||||
0x0003ff70 (HINT,MEDIUM) = File path breaks specification constraints
|
|
||||||
0x0003ff00 (FAILURE,HIGH) = Charset conversion error
|
|
||||||
0x0003feff (FAILURE,HIGH) = Too much files to mangle
|
|
||||||
0x0003fec0 (FAILURE,HIGH) = Wrong or damaged Primary Volume Descriptor
|
|
||||||
0x0003febf (SORRY,HIGH) = Wrong or damaged RR entry
|
|
||||||
0x0003febe (SORRY,HIGH) = Unsupported RR feature
|
|
||||||
0x0003febd (FAILURE,HIGH) = Wrong or damaged ECMA-119
|
|
||||||
0x0003febc (FAILURE,HIGH) = Unsupported ECMA-119 feature
|
|
||||||
0x0003febb (SORRY,HIGH) = Wrong or damaged El-Torito catalog
|
|
||||||
0x0003feba (SORRY,HIGH) = Unsupported El-Torito feature
|
|
||||||
0x0003feb9 (SORRY,HIGH) = Cannot patch isolinux boot image
|
|
||||||
0x0003feb8 (SORRY,HIGH) = Unsupported SUSP feature
|
|
||||||
0x0003feb7 (WARNING,HIGH) = Error on a RR entry that can be ignored
|
|
||||||
0x0003feb6 (HINT,MEDIUM) = Error on a RR entry that can be ignored
|
|
||||||
0x0003feb5 (WARNING,HIGH) = Multiple ER SUSP entries found
|
|
||||||
0x0003feb4 (HINT,MEDIUM) = Unsupported volume descriptor found
|
|
||||||
0x0003feb3 (WARNING,HIGH) = El-Torito related warning
|
|
||||||
0x0003feb2 (MISHAP,HIGH) = Image write cancelled
|
|
||||||
0x0003feb1 (WARNING,HIGH) = El-Torito image is hidden
|
|
||||||
|
|
||||||
Outdated codes which may not be re-used for other purposes than
|
|
||||||
re-instating them, if ever:
|
|
||||||
|
|
||||||
X 0x00031001 (SORRY,HIGH) = Cannot read file (ignored)
|
|
||||||
X 0x00031002 (FATAL,HIGH) = Cannot read file (operation canceled)
|
|
||||||
X 0x00031000 (FATAL,HIGH) = Unsupported ISO-9660 image
|
|
||||||
X 0x00031001 (HINT,MEDIUM) = Unsupported Vol Desc that will be ignored
|
|
||||||
X 0x00031002 (FATAL,HIGH) = Damaged ISO-9660 image
|
|
||||||
X 0x00031003 (SORRY,HIGH) = Cannot read previous image file
|
|
||||||
X 0x00030101 (HINT,MEDIUM) = Unsupported SUSP entry that will be ignored
|
|
||||||
X 0x00030102 (SORRY,HIGH) = Wrong/damaged SUSP entry
|
|
||||||
X 0x00030103 (WARNING,MEDIUM)= Multiple SUSP ER entries where found
|
|
||||||
X 0x00030111 (SORRY,HIGH) = Unsupported RR feature
|
|
||||||
X 0x00030112 (SORRY,HIGH) = Error in a Rock Ridge entry
|
|
||||||
X 0x00030201 (HINT,MEDIUM) = Unsupported Boot Vol Desc that will be ignored
|
|
||||||
X 0x00030202 (SORRY,HIGH) = Wrong El-Torito catalog
|
|
||||||
X 0x00030203 (HINT,MEDIUM) = Unsupported El-Torito feature
|
|
||||||
X 0x00030204 (SORRY,HIGH) = Invalid file to be an El-Torito image
|
|
||||||
X 0x00030205 (WARNING,MEDIUM)= Cannot properly patch isolinux image
|
|
||||||
X 0x00030206 (WARNING,MEDIUM)= Copying El-Torito from a previous image without
|
|
||||||
X enought info about it
|
|
||||||
X 0x00030301 (NOTE,MEDIUM) = Unsupported file type for Joliet tree
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Range "application" : 0x00040000 to 0x0004ffff
|
|
||||||
|
|
||||||
0x00040000 (ABORT,HIGH) : Application supplied message
|
|
||||||
0x00040001 (FATAL,HIGH) : Application supplied message
|
|
||||||
0x00040002 (SORRY,HIGH) : Application supplied message
|
|
||||||
0x00040003 (WARNING,HIGH) : Application supplied message
|
|
||||||
0x00040004 (HINT,HIGH) : Application supplied message
|
|
||||||
0x00040005 (NOTE,HIGH) : Application supplied message
|
|
||||||
0x00040006 (UPDATE,HIGH) : Application supplied message
|
|
||||||
0x00040007 (DEBUG,HIGH) : Application supplied message
|
|
||||||
0x00040008 (*,HIGH) : Application supplied message
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Range "libisofs-xorriso" : 0x00050000 to 0x0005ffff
|
|
||||||
|
|
||||||
This is an alternative representation of libisofs.so.6 error codes in xorriso.
|
|
||||||
If values returned by iso_error_get_code() do not fit into 0x30000 to 0x3ffff
|
|
||||||
then they get truncated to 16 bit and mapped into this range.
|
|
||||||
(This should never need to happen, of course.)
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Range "libisoburn" : 0x00060000 to 0x00006ffff
|
|
||||||
|
|
||||||
0x00060000 (*,*) : Message which shall be attributed to libisoburn
|
|
||||||
|
|
||||||
>>> the messages of libisoburn need to be registered individually
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#endif /* LIDBAX_MSGS_________________ */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef LIBDAX_MSGS_H_INTERNAL
|
|
||||||
|
|
||||||
/* Internal Functions */
|
|
||||||
|
|
||||||
|
|
||||||
/** Lock before doing side effect operations on m */
|
|
||||||
static int libdax_msgs_lock(struct libdax_msgs *m, int flag);
|
|
||||||
|
|
||||||
/** Unlock after effect operations on m are done */
|
|
||||||
static int libdax_msgs_unlock(struct libdax_msgs *m, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
/** Create new empty message item.
|
|
||||||
@param link Previous item in queue
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return >0 success, <=0 failure
|
|
||||||
*/
|
|
||||||
static int libdax_msgs_item_new(struct libdax_msgs_item **item,
|
|
||||||
struct libdax_msgs_item *link, int flag);
|
|
||||||
|
|
||||||
/** Destroy a message item obtained by libdax_msgs_obtain(). The submitted
|
|
||||||
pointer gets set to NULL.
|
|
||||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
|
||||||
@return 1 for success, 0 for pointer to NULL
|
|
||||||
*/
|
|
||||||
static int libdax_msgs_item_destroy(struct libdax_msgs_item **item, int flag);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* LIBDAX_MSGS_H_INTERNAL */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! LIBDAX_MSGS_H_INCLUDED */
|
|
@ -1,37 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# libdax_msgs_to_iso_msgs.sh
|
|
||||||
# generates ${xyz}_msgs.[ch] from libdax_msgs.[ch]
|
|
||||||
# To be executed within ./libburn-* resp ./cdrskin-*
|
|
||||||
|
|
||||||
# The module name for the generated sourcecode in several
|
|
||||||
# uppercase-lowercase forms
|
|
||||||
xyz="libiso"
|
|
||||||
Xyz="Libiso"
|
|
||||||
XYZ="LIBISO"
|
|
||||||
|
|
||||||
# The project name for which the generated code shall serve
|
|
||||||
project="libisofs"
|
|
||||||
|
|
||||||
|
|
||||||
for i in libburn/libdax_msgs.[ch]
|
|
||||||
do
|
|
||||||
target_adr=$(echo "$i" | sed -e "s/libdax_/${xyz}_/")
|
|
||||||
|
|
||||||
echo "$target_adr"
|
|
||||||
|
|
||||||
sed \
|
|
||||||
-e "s/^\/\* libdax_msgs/\/* ${xyz}_msgs (generated from XYZ_msgs : $(date))/" \
|
|
||||||
-e "s/Message handling facility of libdax/Message handling facility of ${project}/" \
|
|
||||||
-e "s/libdax_/${xyz}_/g" \
|
|
||||||
-e "s/libdax:/${xyz}:/g" \
|
|
||||||
-e "s/Libdax_/${Xyz}_/g" \
|
|
||||||
-e "s/LIBDAX_/${XYZ}_/g" \
|
|
||||||
-e "s/generated from XYZ_msgs/generated from libdax_msgs/" \
|
|
||||||
-e "s/${xyz}_msgs is designed to serve in libraries/libdax_msgs is designed to serve in libraries/" \
|
|
||||||
-e "s/Owner of ${xyz}_msgs is libburn/Owner of libdax_msgs is libburn/" \
|
|
||||||
\
|
|
||||||
<"$i" >"$target_adr"
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
3494
libburn/mmc.c
3494
libburn/mmc.c
File diff suppressed because it is too large
Load Diff
@ -1,80 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __MMC
|
|
||||||
#define __MMC
|
|
||||||
|
|
||||||
struct burn_drive;
|
|
||||||
struct burn_write_opts;
|
|
||||||
struct command;
|
|
||||||
struct buffer;
|
|
||||||
struct cue_sheet;
|
|
||||||
|
|
||||||
/* MMC commands */
|
|
||||||
|
|
||||||
void mmc_read(struct burn_drive *);
|
|
||||||
|
|
||||||
/* ts A61009 : removed redundant parameter d in favor of o->drive */
|
|
||||||
/* void mmc_close_session(struct burn_drive *, struct burn_write_opts *); */
|
|
||||||
/* void mmc_close_disc(struct burn_drive *, struct burn_write_opts *); */
|
|
||||||
void mmc_close_session(struct burn_write_opts *o);
|
|
||||||
void mmc_close_disc(struct burn_write_opts *o);
|
|
||||||
|
|
||||||
void mmc_close(struct burn_drive *, int session, int track);
|
|
||||||
void mmc_get_event(struct burn_drive *);
|
|
||||||
int mmc_write(struct burn_drive *, int start, struct buffer *buf);
|
|
||||||
void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf);
|
|
||||||
void mmc_sync_cache(struct burn_drive *);
|
|
||||||
void mmc_load(struct burn_drive *);
|
|
||||||
void mmc_eject(struct burn_drive *);
|
|
||||||
void mmc_erase(struct burn_drive *, int);
|
|
||||||
void mmc_read_toc(struct burn_drive *);
|
|
||||||
void mmc_read_disc_info(struct burn_drive *);
|
|
||||||
void mmc_read_atip(struct burn_drive *);
|
|
||||||
void mmc_read_sectors(struct burn_drive *,
|
|
||||||
int,
|
|
||||||
int, const struct burn_read_opts *, struct buffer *);
|
|
||||||
void mmc_set_speed(struct burn_drive *, int, int);
|
|
||||||
void mmc_read_lead_in(struct burn_drive *, struct buffer *);
|
|
||||||
void mmc_perform_opc(struct burn_drive *);
|
|
||||||
void mmc_get_configuration(struct burn_drive *);
|
|
||||||
|
|
||||||
/* ts A61110 : added parameters trackno, lba, nwa. Redefined return value.
|
|
||||||
@return 1=nwa is valid , 0=nwa is not valid , -1=error */
|
|
||||||
int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa);
|
|
||||||
|
|
||||||
void mmc_send_cue_sheet(struct burn_drive *, struct cue_sheet *);
|
|
||||||
|
|
||||||
/* ts A61023 : get size and free space of drive buffer */
|
|
||||||
int mmc_read_buffer_capacity(struct burn_drive *d);
|
|
||||||
|
|
||||||
/* ts A61021 : the mmc specific part of sg.c:enumerate_common()
|
|
||||||
*/
|
|
||||||
int mmc_setup_drive(struct burn_drive *d);
|
|
||||||
|
|
||||||
/* ts A61219 : learned much from dvd+rw-tools-7.0: plus_rw_format()
|
|
||||||
and mmc5r03c.pdf, 6.5 FORMAT UNIT */
|
|
||||||
int mmc_format_unit(struct burn_drive *d, off_t size, int flag);
|
|
||||||
|
|
||||||
/* ts A61225 : obtain write speed descriptors via ACh GET PERFORMANCE */
|
|
||||||
int mmc_get_write_performance(struct burn_drive *d);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61229 : outsourced from spc_select_write_params() */
|
|
||||||
/* Note: Page data is not zeroed here to allow preset defaults. Thus
|
|
||||||
memset(pd, 0, 2 + d->mdata->write_page_length);
|
|
||||||
is the eventual duty of the caller.
|
|
||||||
*/
|
|
||||||
int mmc_compose_mode_page_5(struct burn_drive *d,
|
|
||||||
const struct burn_write_opts *o,
|
|
||||||
unsigned char *pd);
|
|
||||||
|
|
||||||
/* ts A70812 : return 0 = ok , return BE_CANCELLED = error occured */
|
|
||||||
int mmc_read_10(struct burn_drive *d, int start, int amount,
|
|
||||||
struct buffer *buf);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* mmc5r03c.pdf 4.3.4.4.1 d) "The maximum number of RZones is 2 302." */
|
|
||||||
#define BURN_MMC_FAKE_TOC_MAX_SIZE 2302
|
|
||||||
|
|
||||||
#endif /*__MMC*/
|
|
@ -1,31 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#include "null.h"
|
|
||||||
#include "libburn.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
int null_read(struct burn_source *source, unsigned char *buffer, int size)
|
|
||||||
{
|
|
||||||
memset(buffer, 0, size);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct burn_source *burn_null_source_new(void)
|
|
||||||
{
|
|
||||||
struct burn_source *src;
|
|
||||||
|
|
||||||
src = malloc(sizeof(struct burn_source));
|
|
||||||
src->refcount = 1;
|
|
||||||
src->read = null_read;
|
|
||||||
src->read_sub = NULL;
|
|
||||||
|
|
||||||
src->get_size = 0;
|
|
||||||
|
|
||||||
/* ts A70126 */
|
|
||||||
src->set_size = NULL;
|
|
||||||
|
|
||||||
src->free_data = NULL;
|
|
||||||
src->data = NULL;
|
|
||||||
return src;
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef BURN__NULL_H
|
|
||||||
#define BURN__NULL_H
|
|
||||||
|
|
||||||
struct burn_source;
|
|
||||||
int null_read(struct burn_source *source, unsigned char *buffer, int size);
|
|
||||||
struct burn_source *burn_null_source_new(void);
|
|
||||||
|
|
||||||
#endif /* LIBBURN__NULL_H */
|
|
@ -1,447 +0,0 @@
|
|||||||
#include "libburn.h"
|
|
||||||
#include "options.h"
|
|
||||||
#include "drive.h"
|
|
||||||
#include "transport.h"
|
|
||||||
|
|
||||||
/* ts A61007 */
|
|
||||||
/* #include <a ssert.h> */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
|
|
||||||
struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive)
|
|
||||||
{
|
|
||||||
struct burn_write_opts *opts;
|
|
||||||
|
|
||||||
opts = malloc(sizeof(struct burn_write_opts));
|
|
||||||
if (opts == NULL) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Could not allocate new auxiliary object", 0, 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
opts->drive = drive;
|
|
||||||
opts->refcount = 1;
|
|
||||||
opts->write_type = BURN_WRITE_TAO;
|
|
||||||
opts->block_type = BURN_BLOCK_MODE1;
|
|
||||||
opts->toc_entry = NULL;
|
|
||||||
opts->toc_entries = 0;
|
|
||||||
opts->simulate = 0;
|
|
||||||
opts->underrun_proof = drive->mdata->underrun_proof;
|
|
||||||
opts->perform_opc = 1;
|
|
||||||
opts->obs = -1;
|
|
||||||
opts->obs_pad = 0;
|
|
||||||
opts->start_byte = -1;
|
|
||||||
opts->fill_up_media = 0;
|
|
||||||
opts->force_is_set = 0;
|
|
||||||
opts->do_stream_recording = 0;
|
|
||||||
opts->has_mediacatalog = 0;
|
|
||||||
opts->format = BURN_CDROM;
|
|
||||||
opts->multi = 0;
|
|
||||||
opts->control = 0;
|
|
||||||
return opts;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_write_opts_free(struct burn_write_opts *opts)
|
|
||||||
{
|
|
||||||
if (--opts->refcount <= 0)
|
|
||||||
free(opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct burn_read_opts *burn_read_opts_new(struct burn_drive *drive)
|
|
||||||
{
|
|
||||||
struct burn_read_opts *opts;
|
|
||||||
|
|
||||||
opts = malloc(sizeof(struct burn_read_opts));
|
|
||||||
opts->drive = drive;
|
|
||||||
opts->refcount = 1;
|
|
||||||
opts->raw = 0;
|
|
||||||
opts->c2errors = 0;
|
|
||||||
opts->subcodes_audio = 0;
|
|
||||||
opts->subcodes_data = 0;
|
|
||||||
opts->hardware_error_recovery = 0;
|
|
||||||
opts->report_recovered_errors = 0;
|
|
||||||
opts->transfer_damaged_blocks = 0;
|
|
||||||
opts->hardware_error_retries = 3;
|
|
||||||
|
|
||||||
return opts;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_read_opts_free(struct burn_read_opts *opts)
|
|
||||||
{
|
|
||||||
if (--opts->refcount <= 0)
|
|
||||||
free(opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_write_opts_set_write_type(struct burn_write_opts *opts,
|
|
||||||
enum burn_write_types write_type,
|
|
||||||
int block_type)
|
|
||||||
{
|
|
||||||
int sector_get_outmode(enum burn_write_types write_type,
|
|
||||||
enum burn_block_types block_type);
|
|
||||||
int spc_block_type(enum burn_block_types b);
|
|
||||||
|
|
||||||
/* ts A61007 */
|
|
||||||
if (! ( (write_type == BURN_WRITE_SAO && block_type == BURN_BLOCK_SAO)
|
|
||||||
|| (opts->drive->block_types[write_type] & block_type) ) ) {
|
|
||||||
bad_combination:;
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020112,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Bad combination of write_type and block_type", 0, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* ts A61007 : obsoleting Assert in sector.c:get_outmode() */
|
|
||||||
if (sector_get_outmode(write_type, (enum burn_block_types) block_type)
|
|
||||||
== -1)
|
|
||||||
goto bad_combination;
|
|
||||||
/* ts A61007 : obsoleting Assert in spc.c:spc_block_type() */
|
|
||||||
if (spc_block_type((enum burn_block_types) block_type) == -1)
|
|
||||||
goto bad_combination;
|
|
||||||
|
|
||||||
opts->write_type = write_type;
|
|
||||||
opts->block_type = block_type;
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* a ssert(0); */
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_write_opts_set_toc_entries(struct burn_write_opts *opts, int count,
|
|
||||||
struct burn_toc_entry *toc_entries)
|
|
||||||
{
|
|
||||||
opts->toc_entries = count;
|
|
||||||
opts->toc_entry = malloc(count * sizeof(struct burn_toc_entry));
|
|
||||||
memcpy(opts->toc_entry, &toc_entries,
|
|
||||||
sizeof(struct burn_toc_entry) * count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_write_opts_set_format(struct burn_write_opts *opts, int format)
|
|
||||||
{
|
|
||||||
opts->format = format;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_write_opts_set_simulate(struct burn_write_opts *opts, int sim)
|
|
||||||
{
|
|
||||||
/* <<< ts A70529 :
|
|
||||||
One cannot predict the ability to simulate from page 05h
|
|
||||||
information alone. This check is now done later in
|
|
||||||
function burn_write_opts_auto_write_type().
|
|
||||||
|
|
||||||
if (opts->drive->mdata->simulate) {
|
|
||||||
opts->simulate = sim;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
*/
|
|
||||||
opts->simulate = !!sim;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_write_opts_set_underrun_proof(struct burn_write_opts *opts,
|
|
||||||
int underrun_proof)
|
|
||||||
{
|
|
||||||
if (!opts->drive->mdata->valid)
|
|
||||||
return 0;
|
|
||||||
if (opts->drive->mdata->underrun_proof) {
|
|
||||||
opts->underrun_proof = underrun_proof;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_write_opts_set_perform_opc(struct burn_write_opts *opts, int opc)
|
|
||||||
{
|
|
||||||
opts->perform_opc = opc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_write_opts_set_has_mediacatalog(struct burn_write_opts *opts,
|
|
||||||
int has_mediacatalog)
|
|
||||||
{
|
|
||||||
opts->has_mediacatalog = has_mediacatalog;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_write_opts_set_mediacatalog(struct burn_write_opts *opts,
|
|
||||||
unsigned char mediacatalog[13])
|
|
||||||
{
|
|
||||||
memcpy(opts->mediacatalog, &mediacatalog, 13);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61106 */
|
|
||||||
void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi)
|
|
||||||
{
|
|
||||||
opts->multi = !!multi;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61222 */
|
|
||||||
void burn_write_opts_set_start_byte(struct burn_write_opts *opts, off_t value)
|
|
||||||
{
|
|
||||||
opts->start_byte = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70207 API */
|
|
||||||
/** @param flag Bitfield for control purposes:
|
|
||||||
bit0= do not choose type but check the one that is already set
|
|
||||||
bit1= do not issue error messages via burn_msgs queue
|
|
||||||
*/
|
|
||||||
enum burn_write_types burn_write_opts_auto_write_type(
|
|
||||||
struct burn_write_opts *opts, struct burn_disc *disc,
|
|
||||||
char reasons[BURN_REASONS_LEN], int flag)
|
|
||||||
{
|
|
||||||
struct burn_multi_caps *caps = NULL;
|
|
||||||
struct burn_drive *d = opts->drive;
|
|
||||||
struct burn_disc_mode_demands demands;
|
|
||||||
enum burn_write_types wt;
|
|
||||||
int ret, would_do_sao = 0;
|
|
||||||
char *reason_pt;
|
|
||||||
|
|
||||||
reasons[0] = 0;
|
|
||||||
|
|
||||||
if (d->status != BURN_DISC_BLANK &&
|
|
||||||
d->status != BURN_DISC_APPENDABLE){
|
|
||||||
if (d->status == BURN_DISC_FULL)
|
|
||||||
strcat(reasons, "MEDIA: closed or not recordable, ");
|
|
||||||
else
|
|
||||||
strcat(reasons,"MEDIA: no writeable media detected, ");
|
|
||||||
if (!(flag & 3))
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x0002013a,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"No suitable media detected", 0, 0);
|
|
||||||
return BURN_WRITE_NONE;
|
|
||||||
}
|
|
||||||
ret = burn_disc_get_write_mode_demands(disc, opts, &demands,
|
|
||||||
!!opts->fill_up_media);
|
|
||||||
if (ret <= 0) {
|
|
||||||
strcat(reasons, "cannot recognize job demands, ");
|
|
||||||
{wt = BURN_WRITE_NONE; goto ex;}
|
|
||||||
}
|
|
||||||
if (demands.exotic_track && !d->current_is_cd_profile) {
|
|
||||||
if (demands.audio)
|
|
||||||
strcat(reasons, "audio track prohibited by non-CD, ");
|
|
||||||
else
|
|
||||||
strcat(reasons, "exotic track prohibited by non-CD, ");
|
|
||||||
{wt = BURN_WRITE_NONE; goto ex;}
|
|
||||||
}
|
|
||||||
if ((flag & 1) && opts->write_type != BURN_WRITE_SAO)
|
|
||||||
goto try_tao;
|
|
||||||
reason_pt = reasons + strlen(reasons);
|
|
||||||
strcat(reasons, "SAO: ");
|
|
||||||
if (d->status != BURN_DISC_BLANK) {
|
|
||||||
strcat(reasons, "write type SAO works only on blank media, ");
|
|
||||||
goto try_tao;
|
|
||||||
}
|
|
||||||
burn_disc_free_multi_caps(&caps);
|
|
||||||
ret = burn_disc_get_multi_caps(d, BURN_WRITE_SAO, &caps, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
no_caps:;
|
|
||||||
strcat(reasons, "cannot inquire write mode capabilities, ");
|
|
||||||
{wt = BURN_WRITE_NONE; goto ex;}
|
|
||||||
} else if (ret == 0) {
|
|
||||||
strcat(reasons, "no SAO offered by drive and media, ");
|
|
||||||
goto no_sao;
|
|
||||||
}
|
|
||||||
if ((opts->multi || demands.multi_session) &&
|
|
||||||
!caps->multi_session)
|
|
||||||
strcat(reasons, "multi session capability lacking, ");
|
|
||||||
if (demands.will_append)
|
|
||||||
strcat(reasons, "appended session capability lacking, ");
|
|
||||||
if (demands.multi_track && !caps->multi_track)
|
|
||||||
strcat(reasons, "multi track capability lacking, ");
|
|
||||||
if (demands.unknown_track_size == 1 &&
|
|
||||||
(caps->might_do_sao == 1 || caps->might_do_sao == 3))
|
|
||||||
strcat(reasons, "track size unpredictable, ");
|
|
||||||
if (demands.mixed_mode)
|
|
||||||
strcat(reasons, "tracks of different modes mixed, ");
|
|
||||||
if (demands.exotic_track && !d->current_is_cd_profile)
|
|
||||||
strcat(reasons, "non-data track on non-cd, ");
|
|
||||||
else if (d->current_is_cd_profile)
|
|
||||||
if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
|
|
||||||
demands.block_types)
|
|
||||||
strcat(reasons, "drive dislikes block type, ");
|
|
||||||
if (d->current_is_cd_profile && opts->fill_up_media)
|
|
||||||
strcat(reasons, "cd sao cannot do media fill up yet, ");
|
|
||||||
if (strcmp(reason_pt, "SAO: ") != 0)
|
|
||||||
goto no_sao;
|
|
||||||
would_do_sao = 1;
|
|
||||||
if (demands.unknown_track_size == 2 && (!(flag & 1)) &&
|
|
||||||
(caps->might_do_sao == 1 || caps->might_do_sao == 3)) {
|
|
||||||
strcat(reasons, "would have to use default track sizes, ");
|
|
||||||
goto no_sao;
|
|
||||||
} else if (caps->might_do_sao >= 3 && !(flag & 1))
|
|
||||||
goto try_tao;
|
|
||||||
do_sao:;
|
|
||||||
if (caps->might_simulate == 0 && opts->simulate && !opts->force_is_set)
|
|
||||||
goto no_simulate;
|
|
||||||
if (!(flag & 1))
|
|
||||||
burn_write_opts_set_write_type(
|
|
||||||
opts, BURN_WRITE_SAO, BURN_BLOCK_SAO);
|
|
||||||
{wt = BURN_WRITE_SAO; goto ex;}
|
|
||||||
no_sao:;
|
|
||||||
try_tao:;
|
|
||||||
if ((flag & 1) && opts->write_type != BURN_WRITE_TAO)
|
|
||||||
goto try_raw;
|
|
||||||
reason_pt = reasons + strlen(reasons);
|
|
||||||
strcat(reasons, "TAO: ");
|
|
||||||
burn_disc_free_multi_caps(&caps);
|
|
||||||
ret = burn_disc_get_multi_caps(d, BURN_WRITE_TAO, &caps, 0);
|
|
||||||
if (ret < 0)
|
|
||||||
goto no_caps;
|
|
||||||
if (ret == 0) {
|
|
||||||
strcat(reasons, "no TAO offered by drive and media, ");
|
|
||||||
goto no_tao;
|
|
||||||
}
|
|
||||||
if ((opts->multi || demands.multi_session) && !caps->multi_session)
|
|
||||||
strcat(reasons, "multi session capability lacking, ");
|
|
||||||
if (demands.multi_track && !caps->multi_track)
|
|
||||||
strcat(reasons, "multi track capability lacking, ");
|
|
||||||
if (demands.exotic_track && !d->current_is_cd_profile)
|
|
||||||
strcat(reasons, "non-data track on non-cd, ");
|
|
||||||
if (d->current_is_cd_profile && !opts->force_is_set)
|
|
||||||
if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
|
|
||||||
demands.block_types)
|
|
||||||
strcat(reasons, "drive dislikes block type, ");
|
|
||||||
if (strcmp(reason_pt, "TAO: ") != 0)
|
|
||||||
goto no_tao;
|
|
||||||
/* ( TAO data/audio block size will be handled automatically ) */
|
|
||||||
if (caps->might_simulate == 0 && opts->simulate && !opts->force_is_set)
|
|
||||||
goto no_simulate;
|
|
||||||
if (!(flag & 1))
|
|
||||||
burn_write_opts_set_write_type(
|
|
||||||
opts, BURN_WRITE_TAO, BURN_BLOCK_MODE1);
|
|
||||||
{wt = BURN_WRITE_TAO; goto ex;}
|
|
||||||
no_tao:;
|
|
||||||
if (would_do_sao && !(flag & 1))
|
|
||||||
goto do_sao;
|
|
||||||
if (!d->current_is_cd_profile)
|
|
||||||
goto no_write_mode;
|
|
||||||
try_raw:;
|
|
||||||
if ((flag & 1) && opts->write_type != BURN_WRITE_RAW)
|
|
||||||
goto no_write_mode;
|
|
||||||
|
|
||||||
if (!(flag & 1)) /* For now: no automatic raw write modes */
|
|
||||||
goto no_write_mode;
|
|
||||||
|
|
||||||
reason_pt = reasons + strlen(reasons);
|
|
||||||
strcat(reasons, "RAW: ");
|
|
||||||
if (!d->current_is_cd_profile)
|
|
||||||
strcat(reasons, "write type RAW prohibited by non-cd, ");
|
|
||||||
else if (d->status != BURN_DISC_BLANK)
|
|
||||||
strcat(reasons, "write type RAW works only on blank media, ");
|
|
||||||
else if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
|
|
||||||
demands.block_types)
|
|
||||||
strcat(reasons, "drive dislikes block type, ");
|
|
||||||
if (strcmp(reason_pt, "RAW: ") != 0)
|
|
||||||
goto no_write_mode;
|
|
||||||
if (!opts->force_is_set)
|
|
||||||
goto no_simulate;
|
|
||||||
|
|
||||||
/* For now: no setting of raw write modes */
|
|
||||||
|
|
||||||
{wt = BURN_WRITE_RAW; goto ex;}
|
|
||||||
|
|
||||||
no_write_mode:;
|
|
||||||
{wt = BURN_WRITE_NONE; goto ex;}
|
|
||||||
|
|
||||||
no_simulate:;
|
|
||||||
strcat(reasons,
|
|
||||||
"simulation of write job not supported by drive and media, ");
|
|
||||||
{wt = BURN_WRITE_NONE; goto ex;}
|
|
||||||
|
|
||||||
ex:;
|
|
||||||
burn_disc_free_multi_caps(&caps);
|
|
||||||
if (wt == BURN_WRITE_NONE && !(flag & 3)) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x0002012b,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Drive offers no suitable write mode with this job",
|
|
||||||
0, 0);
|
|
||||||
}
|
|
||||||
return wt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70213 : new API function */
|
|
||||||
void burn_write_opts_set_fillup(struct burn_write_opts *opts,int fill_up_media)
|
|
||||||
{
|
|
||||||
opts->fill_up_media = !!fill_up_media;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70303: API */
|
|
||||||
void burn_write_opts_set_force(struct burn_write_opts *opts, int use_force)
|
|
||||||
{
|
|
||||||
opts->force_is_set = !!use_force;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A80412: API */
|
|
||||||
void burn_write_opts_set_stream_recording(struct burn_write_opts *opts,
|
|
||||||
int value)
|
|
||||||
{
|
|
||||||
opts->do_stream_recording = !!value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70901: API */
|
|
||||||
struct burn_drive *burn_write_opts_get_drive(struct burn_write_opts *opts)
|
|
||||||
{
|
|
||||||
return opts->drive;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void burn_read_opts_set_raw(struct burn_read_opts *opts, int raw)
|
|
||||||
{
|
|
||||||
opts->raw = raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_read_opts_set_c2errors(struct burn_read_opts *opts, int c2errors)
|
|
||||||
{
|
|
||||||
opts->c2errors = c2errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_read_opts_read_subcodes_audio(struct burn_read_opts *opts,
|
|
||||||
int subcodes_audio)
|
|
||||||
{
|
|
||||||
opts->subcodes_audio = subcodes_audio;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_read_opts_read_subcodes_data(struct burn_read_opts *opts,
|
|
||||||
int subcodes_data)
|
|
||||||
{
|
|
||||||
opts->subcodes_data = subcodes_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_read_opts_set_hardware_error_recovery(struct burn_read_opts *opts,
|
|
||||||
int hardware_error_recovery)
|
|
||||||
{
|
|
||||||
opts->hardware_error_recovery = hardware_error_recovery;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_read_opts_report_recovered_errors(struct burn_read_opts *opts,
|
|
||||||
int report_recovered_errors)
|
|
||||||
{
|
|
||||||
opts->report_recovered_errors = report_recovered_errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_read_opts_transfer_damaged_blocks(struct burn_read_opts *opts,
|
|
||||||
int transfer_damaged_blocks)
|
|
||||||
{
|
|
||||||
opts->transfer_damaged_blocks = transfer_damaged_blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_read_opts_set_hardware_error_retries(struct burn_read_opts *opts,
|
|
||||||
unsigned char
|
|
||||||
hardware_error_retries)
|
|
||||||
{
|
|
||||||
opts->hardware_error_retries = hardware_error_retries;
|
|
||||||
}
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
|||||||
#ifndef BURN__OPTIONS_H
|
|
||||||
#define BURN__OPTIONS_H
|
|
||||||
|
|
||||||
#include "libburn.h"
|
|
||||||
|
|
||||||
/** Options for disc writing operations. This should be created with
|
|
||||||
burn_write_opts_new() and freed with burn_write_opts_free(). */
|
|
||||||
struct burn_write_opts
|
|
||||||
{
|
|
||||||
/** Drive the write opts are good for */
|
|
||||||
struct burn_drive *drive;
|
|
||||||
|
|
||||||
/** For internal use. */
|
|
||||||
int refcount;
|
|
||||||
|
|
||||||
/** The method/style of writing to use. */
|
|
||||||
enum burn_write_types write_type;
|
|
||||||
/** format of the data to send to the drive */
|
|
||||||
enum burn_block_types block_type;
|
|
||||||
|
|
||||||
/** Number of toc entries. if this is 0, they will be auto generated*/
|
|
||||||
int toc_entries;
|
|
||||||
/** Toc entries for the disc */
|
|
||||||
struct burn_toc_entry *toc_entry;
|
|
||||||
|
|
||||||
/** Simulate the write so that the disc is not actually written */
|
|
||||||
unsigned int simulate:1;
|
|
||||||
/** If available, enable a drive feature which prevents buffer
|
|
||||||
underruns if not enough data is available to keep up with the
|
|
||||||
drive. */
|
|
||||||
unsigned int underrun_proof:1;
|
|
||||||
/** Perform calibration of the drive's laser before beginning the
|
|
||||||
write. */
|
|
||||||
unsigned int perform_opc:1;
|
|
||||||
|
|
||||||
/* ts A61219 : Output block size to trigger buffer flush if hit.
|
|
||||||
-1 with CD, 32 kB with DVD */
|
|
||||||
int obs;
|
|
||||||
int obs_pad; /* 1=pad up last block to obs */
|
|
||||||
|
|
||||||
/* ts A61222 : Start address for media which allow a choice */
|
|
||||||
off_t start_byte;
|
|
||||||
|
|
||||||
/* ts A70213 : Wether to fill up the available space on media */
|
|
||||||
int fill_up_media;
|
|
||||||
|
|
||||||
/* ts A70303 : Wether to override conformance checks:
|
|
||||||
- the check wether CD write+block type is supported by the drive
|
|
||||||
*/
|
|
||||||
int force_is_set;
|
|
||||||
|
|
||||||
/* ts A80412 : whether to use WRITE12 with Streaming bit set
|
|
||||||
rather than WRITE10. Speeds up DVD-RAM. Might help with BD-RE.
|
|
||||||
This gets transferred to burn_drive.do_stream_recording */
|
|
||||||
int do_stream_recording;
|
|
||||||
|
|
||||||
/** A disc can have a media catalog number */
|
|
||||||
int has_mediacatalog;
|
|
||||||
unsigned char mediacatalog[13];
|
|
||||||
/** Session format */
|
|
||||||
int format;
|
|
||||||
/* internal use only */
|
|
||||||
unsigned char control;
|
|
||||||
unsigned char multi;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Options for disc reading operations. This should be created with
|
|
||||||
burn_read_opts_new() and freed with burn_read_opts_free(). */
|
|
||||||
struct burn_read_opts
|
|
||||||
{
|
|
||||||
/** Drive the read opts are good for */
|
|
||||||
struct burn_drive *drive;
|
|
||||||
|
|
||||||
/** For internal use. */
|
|
||||||
int refcount;
|
|
||||||
|
|
||||||
/** Read in raw mode, so that everything in the data tracks on the
|
|
||||||
disc is read, including headers. Not needed if just reading a
|
|
||||||
filesystem off a disc, but it should usually be used when making a
|
|
||||||
disc image or copying a disc. */
|
|
||||||
unsigned int raw:1;
|
|
||||||
/** Report c2 errors. Useful for statistics reporting */
|
|
||||||
unsigned int c2errors:1;
|
|
||||||
/** Read subcodes from audio tracks on the disc */
|
|
||||||
unsigned int subcodes_audio:1;
|
|
||||||
/** Read subcodes from data tracks on the disc */
|
|
||||||
unsigned int subcodes_data:1;
|
|
||||||
/** Have the drive recover errors if possible */
|
|
||||||
unsigned int hardware_error_recovery:1;
|
|
||||||
/** Report errors even when they were recovered from */
|
|
||||||
unsigned int report_recovered_errors:1;
|
|
||||||
/** Read blocks even when there are unrecoverable errors in them */
|
|
||||||
unsigned int transfer_damaged_blocks:1;
|
|
||||||
|
|
||||||
/** The number of retries the hardware should make to correct
|
|
||||||
errors. */
|
|
||||||
unsigned char hardware_error_retries;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* BURN__OPTIONS_H */
|
|
@ -1,61 +0,0 @@
|
|||||||
|
|
||||||
/* os-freebsd.h
|
|
||||||
Operating system specific libburn definitions and declarations. Included
|
|
||||||
by os.h in case of compilation for
|
|
||||||
FreeBSD with CAM
|
|
||||||
|
|
||||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** List of all signals which shall be caught by signal handlers and trigger
|
|
||||||
a graceful abort of libburn. (See man 7 signal.)
|
|
||||||
*/
|
|
||||||
/* Once as system defined macros */
|
|
||||||
#define BURN_OS_SIGNAL_MACRO_LIST \
|
|
||||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, \
|
|
||||||
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, \
|
|
||||||
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN, \
|
|
||||||
SIGTTOU, \
|
|
||||||
SIGBUS, SIGPROF, SIGSYS, SIGTRAP, \
|
|
||||||
SIGVTALRM, SIGXCPU, SIGXFSZ
|
|
||||||
|
|
||||||
/* Once as text 1:1 list of strings for messages and interpreters */
|
|
||||||
#define BURN_OS_SIGNAL_NAME_LIST \
|
|
||||||
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT", \
|
|
||||||
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM", \
|
|
||||||
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN", \
|
|
||||||
"SIGTTOU", \
|
|
||||||
"SIGBUS", "SIGPROF", "SIGSYS", "SIGTRAP", \
|
|
||||||
"SIGVTALRM", "SIGXCPU", "SIGXFSZ"
|
|
||||||
|
|
||||||
/* The number of above list items */
|
|
||||||
#define BURN_OS_SIGNAL_COUNT 23
|
|
||||||
|
|
||||||
/** To list all signals which shall surely not be caught */
|
|
||||||
#define BURN_OS_NON_SIGNAL_MACRO_LIST \
|
|
||||||
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
|
|
||||||
|
|
||||||
/* The number of above list items */
|
|
||||||
#define BURN_OS_NON_SIGNAL_COUNT 5
|
|
||||||
|
|
||||||
|
|
||||||
/* The maximum size for a (SCSI) i/o transaction */
|
|
||||||
/* Important : MUST be at least 32768 ! */
|
|
||||||
#define BURN_OS_TRANSPORT_BUFFER_SIZE 32768
|
|
||||||
|
|
||||||
|
|
||||||
/** To hold all state information of BSD device enumeration
|
|
||||||
which are now local in sg_enumerate() . So that sg_give_next_adr()
|
|
||||||
can work in BSD and sg_enumerate() can use it.
|
|
||||||
*/
|
|
||||||
#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
|
|
||||||
struct burn_drive_enumeration_state; \
|
|
||||||
typedef struct burn_drive_enumeration_state *burn_drive_enumerator_t;
|
|
||||||
|
|
||||||
|
|
||||||
/* The list of operating system dependent elements in struct burn_drive.
|
|
||||||
To be initialized and used within sg-*.c .
|
|
||||||
*/
|
|
||||||
#define BURN_OS_TRANSPORT_DRIVE_ELEMENTS \
|
|
||||||
struct cam_device* cam;
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
|||||||
|
|
||||||
/* os-linux.h
|
|
||||||
Operating system specific libburn definitions and declarations. Included
|
|
||||||
by os.h in case of compilation for
|
|
||||||
Linux kernels 2.4 and 2.6 with Linux SCSI Generic (sg)
|
|
||||||
|
|
||||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** List of all signals which shall be caught by signal handlers and trigger
|
|
||||||
a graceful abort of libburn. (See man 7 signal.)
|
|
||||||
*/
|
|
||||||
/* Once as system defined macros */
|
|
||||||
#define BURN_OS_SIGNAL_MACRO_LIST \
|
|
||||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, \
|
|
||||||
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, \
|
|
||||||
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN, \
|
|
||||||
SIGTTOU, \
|
|
||||||
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP, \
|
|
||||||
SIGVTALRM, SIGXCPU, SIGXFSZ
|
|
||||||
|
|
||||||
/* Once as text 1:1 list of strings for messages and interpreters */
|
|
||||||
#define BURN_OS_SIGNAL_NAME_LIST \
|
|
||||||
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT", \
|
|
||||||
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM", \
|
|
||||||
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN", \
|
|
||||||
"SIGTTOU", \
|
|
||||||
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP", \
|
|
||||||
"SIGVTALRM", "SIGXCPU", "SIGXFSZ"
|
|
||||||
|
|
||||||
/* The number of above list items */
|
|
||||||
#define BURN_OS_SIGNAL_COUNT 24
|
|
||||||
|
|
||||||
/** To list all signals which shall surely not be caught */
|
|
||||||
#define BURN_OS_NON_SIGNAL_MACRO_LIST \
|
|
||||||
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
|
|
||||||
|
|
||||||
/* The number of above list items */
|
|
||||||
#define BURN_OS_NON_SIGNAL_COUNT 5
|
|
||||||
|
|
||||||
|
|
||||||
/* The maximum size for a (SCSI) i/o transaction */
|
|
||||||
/* Important : MUST be at least 32768 ! */
|
|
||||||
/* ts A70523 : >32k seems not good with kernel 2.4 USB drivers and audio
|
|
||||||
#define BURN_OS_TRANSPORT_BUFFER_SIZE 32768
|
|
||||||
*/
|
|
||||||
/* ts A80414 : curbed in write.c CD media to Libburn_cd_obS = 32 kiB
|
|
||||||
re-enlarged transport to 64 kiB for BD-RE experiments
|
|
||||||
*/
|
|
||||||
#define BURN_OS_TRANSPORT_BUFFER_SIZE 65536
|
|
||||||
|
|
||||||
|
|
||||||
/* To hold the index number of the most recently delivered address from
|
|
||||||
device enumeration.
|
|
||||||
*/
|
|
||||||
#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
|
|
||||||
typedef int burn_drive_enumerator_t;
|
|
||||||
|
|
||||||
|
|
||||||
/* Parameters for sibling list. See sibling_fds, sibling_fnames */
|
|
||||||
#define BURN_OS_SG_MAX_SIBLINGS 5
|
|
||||||
#define BURN_OS_SG_MAX_NAMELEN 16
|
|
||||||
|
|
||||||
/* The list of operating system dependent elements in struct burn_drive.
|
|
||||||
Usually they are initialized in sg-*.c:enumerate_common().
|
|
||||||
*/
|
|
||||||
#define BURN_OS_TRANSPORT_DRIVE_ELEMENTS \
|
|
||||||
int fd; \
|
|
||||||
\
|
|
||||||
/* ts A60926 : trying to lock against growisofs /dev/srN, /dev/scdN */ \
|
|
||||||
int sibling_count; \
|
|
||||||
int sibling_fds[BURN_OS_SG_MAX_SIBLINGS]; \
|
|
||||||
/* ts A70409 : DDLP */ \
|
|
||||||
char sibling_fnames[BURN_OS_SG_MAX_SIBLINGS][BURN_OS_SG_MAX_NAMELEN];
|
|
||||||
|
|
34
libburn/os.h
34
libburn/os.h
@ -1,34 +0,0 @@
|
|||||||
|
|
||||||
/* os.h
|
|
||||||
Operating system specific libburn definitions and declarations.
|
|
||||||
The macros defined here are used by libburn modules in order to
|
|
||||||
avoid own system dependent case distinctions.
|
|
||||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BURN_OS_H_INCLUDED
|
|
||||||
#define BURN_OS_H_INCLUDED 1
|
|
||||||
|
|
||||||
/*
|
|
||||||
Operating system case distinction
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------- FreeBSD with CAM -------------------------- */
|
|
||||||
#include "os-freebsd.h"
|
|
||||||
|
|
||||||
|
|
||||||
#else /* operating system case distinction */
|
|
||||||
|
|
||||||
|
|
||||||
/* --------- Linux kernels 2.4 and 2.6 with Linux SCSI Generic (sg) -------- */
|
|
||||||
#include "os-linux.h"
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* End of operating system case distinction */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! BURN_OS_H_INCLUDED */
|
|
||||||
|
|
490
libburn/read.c
490
libburn/read.c
@ -1,490 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
/* #include <m alloc.h> ts A61013 : not in Linux man 3 malloc */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
/* ts A61007 */
|
|
||||||
/* #include <a ssert.h> */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "sector.h"
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "drive.h"
|
|
||||||
#include "transport.h"
|
|
||||||
|
|
||||||
/* ts A60925 : obsoleted by libdax_msgs.h
|
|
||||||
#include "message.h"
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "crc.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "init.h"
|
|
||||||
#include "lec.h"
|
|
||||||
#include "toc.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "sg.h"
|
|
||||||
#include "read.h"
|
|
||||||
#include "options.h"
|
|
||||||
|
|
||||||
/* ts A70812 */
|
|
||||||
#include "error.h"
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
|
|
||||||
void burn_disc_read(struct burn_drive *d, const struct burn_read_opts *o)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
int i, end, maxsects, finish;
|
|
||||||
int seclen;
|
|
||||||
int drive_lba;
|
|
||||||
unsigned short crc;
|
|
||||||
unsigned char fakesub[96];
|
|
||||||
struct buffer page;
|
|
||||||
int speed;
|
|
||||||
|
|
||||||
/* ts A61007 : if this function gets revived, then these
|
|
||||||
tests have to be done more graceful */
|
|
||||||
a ssert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));
|
|
||||||
a ssert(!d->busy);
|
|
||||||
a ssert(d->toc->valid);
|
|
||||||
a ssert(o->datafd != -1);
|
|
||||||
|
|
||||||
/* moved up from spc_select_error_params alias d->send_parameters() */
|
|
||||||
a ssert(d->mdata->valid);
|
|
||||||
|
|
||||||
/* XXX not sure this is a good idea. copy it? */
|
|
||||||
/* XXX also, we have duplicated data now, do we remove the fds from struct
|
|
||||||
drive, or only store a subset of the _opts structs in drives */
|
|
||||||
|
|
||||||
/* set the speed on the drive */
|
|
||||||
speed = o->speed > 0 ? o->speed : d->mdata->max_read_speed;
|
|
||||||
d->set_speed(d, speed, 0);
|
|
||||||
|
|
||||||
d->params.retries = o->hardware_error_retries;
|
|
||||||
|
|
||||||
d->send_parameters(d, o);
|
|
||||||
|
|
||||||
d->cancel = 0;
|
|
||||||
d->busy = BURN_DRIVE_READING;
|
|
||||||
d->currsession = 0;
|
|
||||||
/* drive_lba = 232000;
|
|
||||||
d->currtrack = 18;
|
|
||||||
*/
|
|
||||||
d->currtrack = 0;
|
|
||||||
drive_lba = 0;
|
|
||||||
/* XXX removal of this line obviously breaks *
|
|
||||||
d->track_end = burn_track_end(d, d->currsession, d->currtrack);*/
|
|
||||||
printf("track ends at %d\n", d->track_end);
|
|
||||||
page.sectors = 0;
|
|
||||||
page.bytes = 0;
|
|
||||||
|
|
||||||
if (o->subfd != -1) {
|
|
||||||
memset(fakesub, 0xFF, 12);
|
|
||||||
memset(fakesub + 12, 0, 84);
|
|
||||||
fakesub[13] = 1;
|
|
||||||
fakesub[14] = 1;
|
|
||||||
fakesub[20] = 2;
|
|
||||||
fakesub[12] = (d->toc->toc_entry[0].control << 4) +
|
|
||||||
d->toc->toc_entry[0].adr;
|
|
||||||
crc = crc_ccitt(fakesub + 12, 10);
|
|
||||||
fakesub[22] = crc >> 8;
|
|
||||||
fakesub[23] = crc & 0xFF;
|
|
||||||
write(o->subfd, fakesub, 96);
|
|
||||||
}
|
|
||||||
while (1) {
|
|
||||||
seclen = burn_sector_length_read(d, o);
|
|
||||||
|
|
||||||
burn_print(12, "received %d blocks\n", page.sectors);
|
|
||||||
for (i = 0; i < page.sectors; i++) {
|
|
||||||
burn_packet_process(d, page.data + seclen * i, o);
|
|
||||||
d->track_end--;
|
|
||||||
drive_lba++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((d->cancel) || (drive_lba == LAST_SESSION_END(d))) {
|
|
||||||
burn_print(1, "finished or cancelled\n");
|
|
||||||
d->busy = BURN_DRIVE_IDLE;
|
|
||||||
if (!d->cancel)
|
|
||||||
d->toc->complete = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* XXX: removal of this line obviously breaks *
|
|
||||||
end = burn_track_end(d, d->currsession, d->currtrack); */
|
|
||||||
|
|
||||||
if (drive_lba == end) {
|
|
||||||
d->currtrack++;
|
|
||||||
if (d->currtrack >
|
|
||||||
d->toc->session[d->currsession].lasttrack) {
|
|
||||||
d->currsession++;
|
|
||||||
burn_print(12, "session switch to %d\n",
|
|
||||||
d->currsession);
|
|
||||||
burn_print(12, "skipping a lead out\n");
|
|
||||||
drive_lba = CURRENT_SESSION_START(d);
|
|
||||||
burn_print(12, "new lba %d\n", drive_lba);
|
|
||||||
/* XXX more of the same
|
|
||||||
end = burn_track_end(d, d->currsession,
|
|
||||||
d->currtrack);
|
|
||||||
*/ }
|
|
||||||
burn_print(12, "track switch to %d\n", d->currtrack);
|
|
||||||
}
|
|
||||||
|
|
||||||
page.sectors = 0;
|
|
||||||
page.bytes = 0;
|
|
||||||
|
|
||||||
maxsects = BUFFER_SIZE / seclen;
|
|
||||||
finish = end - drive_lba;
|
|
||||||
|
|
||||||
d->track_end = finish;
|
|
||||||
|
|
||||||
page.sectors = (finish < maxsects) ? finish : maxsects;
|
|
||||||
printf("reading %d sectors from %d\n", page.sectors,
|
|
||||||
drive_lba);
|
|
||||||
|
|
||||||
/* >>> ts A61009 : ensure page.sectors >= 0 before calling */
|
|
||||||
d->r ead_sectors(d, drive_lba, page.sectors, o, &page);
|
|
||||||
|
|
||||||
printf("Read %d\n", page.sectors);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
int burn_sector_length_read(struct burn_drive *d,
|
|
||||||
const struct burn_read_opts *o)
|
|
||||||
{
|
|
||||||
int dlen = 2352;
|
|
||||||
int data;
|
|
||||||
|
|
||||||
/*XXX how do we handle this crap now?*/
|
|
||||||
/* data = d->toc->track[d->currtrack].toc_entry->control & 4;*/
|
|
||||||
data = 1;
|
|
||||||
if (o->report_recovered_errors)
|
|
||||||
dlen += 294;
|
|
||||||
if ((o->subcodes_data) && data)
|
|
||||||
dlen += 96;
|
|
||||||
if ((o->subcodes_audio) && !data)
|
|
||||||
dlen += 96;
|
|
||||||
return dlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bitcount(unsigned char *data, int n)
|
|
||||||
{
|
|
||||||
int i, j, count = 0;
|
|
||||||
unsigned char tem;
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
tem = data[i];
|
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
count += tem & 1;
|
|
||||||
tem >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_packet_process(struct burn_drive *d, unsigned char *data,
|
|
||||||
const struct burn_read_opts *o)
|
|
||||||
{
|
|
||||||
unsigned char sub[96];
|
|
||||||
unsigned short crc;
|
|
||||||
int ptr = 2352, i, j, code, fb;
|
|
||||||
int audio = 1;
|
|
||||||
|
|
||||||
if (o->c2errors) {
|
|
||||||
fb = bitcount(data + ptr, 294);
|
|
||||||
if (fb) {
|
|
||||||
burn_print(1, "%d damaged bits\n",
|
|
||||||
bitcount(data + ptr, 294));
|
|
||||||
burn_print(1, "sending error on %s %s\n",
|
|
||||||
d->idata->vendor, d->idata->product);
|
|
||||||
/* XXX send a burn_message! burn_message_error(d,
|
|
||||||
something); */
|
|
||||||
}
|
|
||||||
ptr += 294;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if (d->toc->track[d->currtrack].mode == BURN_MODE_UNINITIALIZED) {
|
|
||||||
if ((d->toc->track[d->currtrack].toc_entry->control & 4) == 0)
|
|
||||||
d->toc->track[d->currtrack].mode = BURN_MODE_AUDIO;
|
|
||||||
else
|
|
||||||
switch (data[15]) {
|
|
||||||
case 0:
|
|
||||||
d->toc->track[d->currtrack].mode = BURN_MODE0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
d->toc->track[d->currtrack].mode = BURN_MODE1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
d->toc->track[d->currtrack].mode =
|
|
||||||
BURN_MODE2_FORMLESS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if ((audio && o->subcodes_audio)
|
|
||||||
|| (!audio && o->subcodes_data)) {
|
|
||||||
memset(sub, 0, sizeof(sub));
|
|
||||||
for (i = 0; i < 12; i++) {
|
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
for (code = 0; code < 8; code++) {
|
|
||||||
sub[code * 12 + i] <<= 1;
|
|
||||||
if (data[ptr + j + i * 8] &
|
|
||||||
(1 << (7 - code)))
|
|
||||||
sub[code * 12 + i]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
crc = (*(sub + 22) << 8) + *(sub + 23);
|
|
||||||
if (crc != crc_ccitt(sub + 12, 10)) {
|
|
||||||
burn_print(1, "sending error on %s %s\n",
|
|
||||||
d->idata->vendor, d->idata->product);
|
|
||||||
/* e = burn_error();
|
|
||||||
e->drive = d;
|
|
||||||
*/
|
|
||||||
burn_print(1, "crc mismatch in Q\n");
|
|
||||||
}
|
|
||||||
/* else process_q(d, sub + 12); */
|
|
||||||
/*
|
|
||||||
if (o->subfd != -1) write(o->subfd, sub, 96); */
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if ((d->track_end <= 150)
|
|
||||||
&& (drive_lba + 150 < CURRENT_SESSION_END(d))
|
|
||||||
&& (TOC_ENTRY(d->toc, d->currtrack).control == 4)
|
|
||||||
&& (TOC_ENTRY(d->toc, d->currtrack + 1).control == 0)) {
|
|
||||||
burn_print(12, "pregap : %d\n", d->track_end);
|
|
||||||
write(o->binfd, zeros, 2352);
|
|
||||||
|
|
||||||
#warning XXX WHERE ARE MY SUBCODES
|
|
||||||
} else
|
|
||||||
*//* write(o->datafd, data, 2352); */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* so yeah, when you uncomment these, make them write zeros insted of crap
|
|
||||||
static void write_empty_sector(int fd)
|
|
||||||
{
|
|
||||||
char sec[2352];
|
|
||||||
|
|
||||||
burn_print(1, "writing an 'empty' sector\n");
|
|
||||||
write(fd, sec, 2352);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_empty_subcode(int fd)
|
|
||||||
{
|
|
||||||
char sub[96];
|
|
||||||
|
|
||||||
write(fd, sub, 96);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flipq(unsigned char *sub)
|
|
||||||
{
|
|
||||||
*(sub + 12 + 10) = ~*(sub + 12 + 10);
|
|
||||||
*(sub + 12 + 11) = ~*(sub + 12 + 11);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70904 */
|
|
||||||
/** @param flag bit0=be silent on data shortage */
|
|
||||||
int burn_stdio_read(int fd, char *buf, int bufsize, struct burn_drive *d,
|
|
||||||
int flag)
|
|
||||||
{
|
|
||||||
int todo, count = 0;
|
|
||||||
|
|
||||||
for(todo = bufsize; todo > 0; ) {
|
|
||||||
count = read(fd, buf + (bufsize - todo), todo);
|
|
||||||
if(count <= 0)
|
|
||||||
break;
|
|
||||||
todo -= count;
|
|
||||||
}
|
|
||||||
if(todo > 0 && !(flag & 1)) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x0002014a,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Cannot read desired amount of data", errno, 0);
|
|
||||||
}
|
|
||||||
if (count < 0)
|
|
||||||
return -1;
|
|
||||||
return (bufsize - todo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70812 : API function */
|
|
||||||
int burn_read_data(struct burn_drive *d, off_t byte_address,
|
|
||||||
char data[], off_t data_size, off_t *data_count, int flag)
|
|
||||||
{
|
|
||||||
int alignment = 2048, start, upto, chunksize = 1, err, cpy_size, i;
|
|
||||||
int sose_mem = 0, fd = -1, ret;
|
|
||||||
char msg[81], *wpt;
|
|
||||||
struct buffer buf;
|
|
||||||
|
|
||||||
/*
|
|
||||||
#define Libburn_read_data_adr_logginG 1
|
|
||||||
*/
|
|
||||||
#ifdef Libburn_read_data_adr_logginG
|
|
||||||
static FILE *log_fp= NULL;
|
|
||||||
|
|
||||||
if(log_fp == NULL)
|
|
||||||
log_fp = fopen("/tmp/burn_read_data_log", "a");
|
|
||||||
if(log_fp!=NULL)
|
|
||||||
fprintf(log_fp, "%d\n", (int) (byte_address / 2048));
|
|
||||||
#endif /* Libburn_read_data_logginG */
|
|
||||||
|
|
||||||
|
|
||||||
*data_count = 0;
|
|
||||||
sose_mem = d->silent_on_scsi_error;
|
|
||||||
|
|
||||||
if (d->released) {
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
d->global_index, 0x00020142,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Drive is not grabbed on random access read", 0, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (d->drive_role == 0) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x00020146,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Drive is a virtual placeholder (null-drive)", 0, 0);
|
|
||||||
return 0;
|
|
||||||
} else if (d->drive_role == 3) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x00020151,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Read attempt on write-only drive", 0, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((byte_address % alignment) != 0) {
|
|
||||||
sprintf(msg,
|
|
||||||
"Read start address not properly aligned (%d bytes)",
|
|
||||||
alignment);
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x00020143,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
msg, 0, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->busy != BURN_DRIVE_IDLE) {
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
d->global_index, 0x00020145,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Drive is busy on attempt to read data", 0, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->drive_role != 1) {
|
|
||||||
|
|
||||||
/* <<< We need _LARGEFILE64_SOURCE defined by the build system.
|
|
||||||
*/
|
|
||||||
#ifndef O_LARGEFILE
|
|
||||||
#define O_LARGEFILE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fd = d->stdio_fd;
|
|
||||||
if (fd < 0)
|
|
||||||
d->stdio_fd = fd =
|
|
||||||
open(d->devname, O_RDONLY | O_LARGEFILE);
|
|
||||||
if (fd == -1) {
|
|
||||||
if (errno != ENOENT || !(flag & 2))
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
d->global_index,
|
|
||||||
0x00020005,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Failed to open device (a pseudo-drive) for reading",
|
|
||||||
errno, 0);
|
|
||||||
ret = 0; goto ex;
|
|
||||||
}
|
|
||||||
if (lseek(fd, byte_address, SEEK_SET) == -1) {
|
|
||||||
if (!(flag & 2))
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
d->global_index,
|
|
||||||
0x00020147,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Cannot address start byte", errno, 0);
|
|
||||||
ret = 0; goto ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
d->busy = BURN_DRIVE_READING_SYNC;
|
|
||||||
d->buffer = &buf;
|
|
||||||
|
|
||||||
start = byte_address / 2048;
|
|
||||||
upto = start + data_size / 2048;
|
|
||||||
if (data_size % 2048)
|
|
||||||
upto++;
|
|
||||||
wpt = data;
|
|
||||||
for (; start < upto; start += chunksize) {
|
|
||||||
chunksize = upto - start;
|
|
||||||
if (chunksize > 16) {
|
|
||||||
chunksize = 16;
|
|
||||||
cpy_size = 16 * 2048;
|
|
||||||
} else
|
|
||||||
cpy_size = data_size - *data_count;
|
|
||||||
if (flag & 2)
|
|
||||||
d->silent_on_scsi_error = 1;
|
|
||||||
if (d->drive_role == 1) {
|
|
||||||
err = d->read_10(d, start, chunksize, d->buffer);
|
|
||||||
} else {
|
|
||||||
ret = burn_stdio_read(fd, (char *) d->buffer->data,
|
|
||||||
cpy_size, d, !!(flag & 2));
|
|
||||||
err = 0;
|
|
||||||
if (ret <= 0)
|
|
||||||
err = BE_CANCELLED;
|
|
||||||
}
|
|
||||||
if (flag & 2)
|
|
||||||
d->silent_on_scsi_error = sose_mem;
|
|
||||||
if (err == BE_CANCELLED) {
|
|
||||||
/* Try to read a smaller part of the chunk */
|
|
||||||
for (i = 0; i < chunksize - 1; i++) {
|
|
||||||
if (flag & 2)
|
|
||||||
d->silent_on_scsi_error = 1;
|
|
||||||
if (d->drive_role == 1) {
|
|
||||||
err = d->read_10(d, start + i, 1,
|
|
||||||
d->buffer);
|
|
||||||
} else {
|
|
||||||
ret = burn_stdio_read(fd,
|
|
||||||
(char *) d->buffer->data,
|
|
||||||
2048, d, 1);
|
|
||||||
if (ret <= 0)
|
|
||||||
err = BE_CANCELLED;
|
|
||||||
}
|
|
||||||
if (flag & 2)
|
|
||||||
d->silent_on_scsi_error = sose_mem;
|
|
||||||
if (err == BE_CANCELLED)
|
|
||||||
break;
|
|
||||||
memcpy(wpt, d->buffer->data, 2048);
|
|
||||||
wpt += 2048;
|
|
||||||
*data_count += 2048;
|
|
||||||
}
|
|
||||||
if (!(flag & 2))
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
d->global_index,
|
|
||||||
0x00020000,
|
|
||||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"burn_read_data() returns 0",
|
|
||||||
0, 0);
|
|
||||||
ret = 0; goto ex;
|
|
||||||
}
|
|
||||||
memcpy(wpt, d->buffer->data, cpy_size);
|
|
||||||
wpt += cpy_size;
|
|
||||||
*data_count += cpy_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 1;
|
|
||||||
ex:;
|
|
||||||
/* <<< let it open until drive is given up or writing shall happen
|
|
||||||
if (fd != -1)
|
|
||||||
close(fd);
|
|
||||||
*/
|
|
||||||
d->buffer = NULL;
|
|
||||||
d->busy = BURN_DRIVE_IDLE;
|
|
||||||
return ret;
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __LIBBURN_READ
|
|
||||||
#define __LIBBURN_READ
|
|
||||||
|
|
||||||
struct burn_drive;
|
|
||||||
struct burn_read_opts;
|
|
||||||
|
|
||||||
int burn_sector_length_read(struct burn_drive *d,
|
|
||||||
const struct burn_read_opts *o);
|
|
||||||
void burn_packet_process(struct burn_drive *d, unsigned char *data,
|
|
||||||
const struct burn_read_opts *o);
|
|
||||||
|
|
||||||
#endif /* __LIBBURN_READ */
|
|
114
libburn/sbc.c
114
libburn/sbc.c
@ -1,114 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
/* scsi block commands */
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "transport.h"
|
|
||||||
#include "sbc.h"
|
|
||||||
#include "spc.h"
|
|
||||||
#include "options.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70910
|
|
||||||
debug: for tracing calls which might use open drive fds
|
|
||||||
or for catching SCSI usage of emulated drives. */
|
|
||||||
int mmc_function_spy(struct burn_drive *d, char * text);
|
|
||||||
|
|
||||||
|
|
||||||
/* spc command set */
|
|
||||||
static unsigned char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
|
|
||||||
static unsigned char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
|
|
||||||
static unsigned char SBC_START_UNIT[] = { 0x1b, 0, 0, 0, 1, 0 };
|
|
||||||
|
|
||||||
void sbc_load(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "load") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SBC_LOAD, sizeof(SBC_LOAD));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SBC_LOAD, sizeof(SBC_LOAD));
|
|
||||||
c.oplen = sizeof(SBC_LOAD);
|
|
||||||
c.page = NULL;
|
|
||||||
*/
|
|
||||||
c.retry = 1;
|
|
||||||
|
|
||||||
/* ts A70921 : Had to revoke Immed because of LG GSA-4082B */
|
|
||||||
/* c.opcode[1] |= 1; / * ts A70918 : Immed */
|
|
||||||
|
|
||||||
c.dir = NO_TRANSFER;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
if (c.error)
|
|
||||||
return;
|
|
||||||
/* ts A70923 : Needed regardless of Immed bit. Was once 1 minute, now
|
|
||||||
5 minutes for loading. If this does not suffice then other commands
|
|
||||||
shall fail righteously. */
|
|
||||||
spc_wait_unit_attention(d, 300, "waiting after START UNIT (+ LOAD)",0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sbc_eject(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "eject") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SBC_UNLOAD, sizeof(SBC_UNLOAD));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SBC_UNLOAD, sizeof(SBC_UNLOAD));
|
|
||||||
c.oplen = sizeof(SBC_UNLOAD);
|
|
||||||
c.page = NULL;
|
|
||||||
*/
|
|
||||||
|
|
||||||
c.opcode[1] |= 1; /* ts A70918 : Immed */
|
|
||||||
|
|
||||||
c.page = NULL;
|
|
||||||
c.dir = NO_TRANSFER;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
if (c.error)
|
|
||||||
return;
|
|
||||||
/* ts A70918 : Wait long. A late eject could surprise or hurt user. */
|
|
||||||
spc_wait_unit_attention(d, 1800, "STOP UNIT (+ EJECT)", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61118 : is it necessary to tell the drive to get ready for use ? */
|
|
||||||
int sbc_start_unit(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "start_unit") <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SBC_START_UNIT, sizeof(SBC_START_UNIT));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SBC_START_UNIT, sizeof(SBC_START_UNIT));
|
|
||||||
c.oplen = sizeof(SBC_START_UNIT);
|
|
||||||
c.page = NULL;
|
|
||||||
*/
|
|
||||||
c.retry = 1;
|
|
||||||
|
|
||||||
c.opcode[1] |= 1; /* ts A70918 : Immed */
|
|
||||||
|
|
||||||
c.dir = NO_TRANSFER;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
if (c.error)
|
|
||||||
return 0;
|
|
||||||
/* ts A70918 : now asynchronous */
|
|
||||||
return spc_wait_unit_attention(d, 1800, "START UNIT", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61021 : the sbc specific part of sg.c:enumerate_common()
|
|
||||||
*/
|
|
||||||
int sbc_setup_drive(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
d->eject = sbc_eject;
|
|
||||||
d->load = sbc_load;
|
|
||||||
d->start_unit = sbc_start_unit;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __SBC
|
|
||||||
#define __SBC
|
|
||||||
|
|
||||||
struct burn_drive;
|
|
||||||
|
|
||||||
void sbc_load(struct burn_drive *);
|
|
||||||
void sbc_eject(struct burn_drive *);
|
|
||||||
|
|
||||||
/* ts A61118 */
|
|
||||||
int sbc_start_unit(struct burn_drive *);
|
|
||||||
|
|
||||||
/* ts A61021 : the sbc specific part of sg.c:enumerate_common()
|
|
||||||
*/
|
|
||||||
int sbc_setup_drive(struct burn_drive *d);
|
|
||||||
|
|
||||||
#endif /* __SBC */
|
|
846
libburn/sector.c
846
libburn/sector.c
@ -1,846 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/* ts A61010 */
|
|
||||||
/* #include <a ssert.h> */
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "error.h"
|
|
||||||
#include "options.h"
|
|
||||||
#include "transport.h"
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "drive.h"
|
|
||||||
#include "sector.h"
|
|
||||||
#include "crc.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "lec.h"
|
|
||||||
#include "toc.h"
|
|
||||||
#include "write.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef Libburn_log_in_and_out_streaM
|
|
||||||
/* <<< ts A61031 */
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#endif /* Libburn_log_in_and_out_streaM */
|
|
||||||
|
|
||||||
|
|
||||||
/*static unsigned char isrc[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";*/
|
|
||||||
|
|
||||||
#define sector_common(X) d->alba++; d->rlba X;
|
|
||||||
|
|
||||||
static void uncook_subs(unsigned char *dest, unsigned char *source)
|
|
||||||
{
|
|
||||||
int i, j, code;
|
|
||||||
|
|
||||||
memset(dest, 0, 96);
|
|
||||||
|
|
||||||
for (i = 0; i < 12; i++) {
|
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
for (code = 0; code < 8; code++) {
|
|
||||||
if (source[code * 12 + i] & 0x80)
|
|
||||||
dest[j + i * 8] |= (1 << (7 - code));
|
|
||||||
source[code * 12 + i] <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @return >=0 : valid , <0 invalid */
|
|
||||||
int sector_get_outmode(enum burn_write_types write_type,
|
|
||||||
enum burn_block_types block_type)
|
|
||||||
{
|
|
||||||
/* ts A61103 : extended SAO condition to TAO */
|
|
||||||
if (write_type == BURN_WRITE_SAO || write_type == BURN_WRITE_TAO)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
switch (block_type) {
|
|
||||||
case BURN_BLOCK_RAW0:
|
|
||||||
return BURN_MODE_RAW;
|
|
||||||
case BURN_BLOCK_RAW16:
|
|
||||||
return BURN_MODE_RAW | BURN_SUBCODE_P16;
|
|
||||||
case BURN_BLOCK_RAW96P:
|
|
||||||
return BURN_MODE_RAW | BURN_SUBCODE_P96;
|
|
||||||
case BURN_BLOCK_RAW96R:
|
|
||||||
return BURN_MODE_RAW | BURN_SUBCODE_R96;
|
|
||||||
case BURN_BLOCK_MODE1:
|
|
||||||
return BURN_MODE1;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61007 : now handled in burn_write_opts_set_write_type() */
|
|
||||||
/* a ssert(0); */ /* return BURN_MODE_UNIMPLEMENTED :) */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 0 means "same as inmode" */
|
|
||||||
static int get_outmode(struct burn_write_opts *o)
|
|
||||||
{
|
|
||||||
/* ts A61007 */
|
|
||||||
return sector_get_outmode(o->write_type, o->block_type);
|
|
||||||
|
|
||||||
/* -1 is prevented by check in burn_write_opts_set_write_type() */
|
|
||||||
/* a ssert(0); */ /* return BURN_MODE_UNIMPLEMENTED :) */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void get_bytes(struct burn_track *track, int count, unsigned char *data)
|
|
||||||
{
|
|
||||||
int valid, shortage, curr, i, tr;
|
|
||||||
|
|
||||||
#ifdef Libburn_log_in_and_out_streaM
|
|
||||||
/* <<< ts A61031 */
|
|
||||||
static int tee_fd= -1;
|
|
||||||
if(tee_fd==-1)
|
|
||||||
tee_fd= open("/tmp/libburn_sg_readin",
|
|
||||||
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
|
|
||||||
#endif /* Libburn_log_in_and_out_streaM */
|
|
||||||
|
|
||||||
|
|
||||||
/* no track pointer means we're just generating 0s */
|
|
||||||
if (!track) {
|
|
||||||
memset(data, 0, count);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first we use up any offset */
|
|
||||||
valid = track->offset - track->offsetcount;
|
|
||||||
if (valid > count)
|
|
||||||
valid = count;
|
|
||||||
|
|
||||||
if (valid) {
|
|
||||||
track->offsetcount += valid;
|
|
||||||
memset(data, 0, valid);
|
|
||||||
}
|
|
||||||
shortage = count - valid;
|
|
||||||
|
|
||||||
if (!shortage)
|
|
||||||
goto ex;
|
|
||||||
|
|
||||||
/* Next we use source data */
|
|
||||||
curr = valid;
|
|
||||||
if (!track->eos) {
|
|
||||||
if (track->source->read != NULL)
|
|
||||||
valid = track->source->read(track->source,
|
|
||||||
data + curr, count - curr);
|
|
||||||
else
|
|
||||||
valid = track->source->read_xt(track->source,
|
|
||||||
data + curr, count - curr);
|
|
||||||
} else valid = 0;
|
|
||||||
|
|
||||||
if (valid <= 0) { /* ts A61031 : extended from (valid == -1) */
|
|
||||||
track->eos = 1;
|
|
||||||
valid = 0;
|
|
||||||
}
|
|
||||||
track->sourcecount += valid;
|
|
||||||
|
|
||||||
#ifdef Libburn_log_in_and_out_streaM
|
|
||||||
/* <<< ts A61031 */
|
|
||||||
if(tee_fd!=-1 && valid>0) {
|
|
||||||
write(tee_fd, data + curr, valid);
|
|
||||||
}
|
|
||||||
#endif /* Libburn_log_in_and_out_streaM */
|
|
||||||
|
|
||||||
curr += valid;
|
|
||||||
shortage = count - curr;
|
|
||||||
|
|
||||||
if (!shortage)
|
|
||||||
goto ex;
|
|
||||||
|
|
||||||
/* Before going to the next track, we run through any tail */
|
|
||||||
|
|
||||||
valid = track->tail - track->tailcount;
|
|
||||||
if (valid > count - curr)
|
|
||||||
valid = count - curr;
|
|
||||||
|
|
||||||
if (valid) {
|
|
||||||
track->tailcount += valid;
|
|
||||||
memset(data + curr, 0, valid);
|
|
||||||
}
|
|
||||||
curr += valid;
|
|
||||||
shortage -= valid;
|
|
||||||
|
|
||||||
if (!shortage)
|
|
||||||
goto ex;
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
if (shortage >= count)
|
|
||||||
track->track_data_done = 1;
|
|
||||||
if (track->open_ended)
|
|
||||||
goto ex;
|
|
||||||
|
|
||||||
/* If we're still short, and there's a "next" pointer, we pull from that.
|
|
||||||
if that depletes, we'll just fill with 0s.
|
|
||||||
*/
|
|
||||||
if (track->source->next) {
|
|
||||||
struct burn_source *src;
|
|
||||||
printf("pulling from next track\n");
|
|
||||||
src = track->source->next;
|
|
||||||
valid = src->read(src, data + curr, shortage);
|
|
||||||
if (valid > 0) {
|
|
||||||
shortage -= valid;
|
|
||||||
curr += valid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ex:;
|
|
||||||
/* ts A61024 : general finalizing processing */
|
|
||||||
if(shortage)
|
|
||||||
memset(data + curr, 0, shortage); /* this is old icculus.org */
|
|
||||||
if (track->swap_source_bytes == 1) {
|
|
||||||
for (i = 1; i < count; i += 2) {
|
|
||||||
tr = data[i];
|
|
||||||
data[i] = data[i-1];
|
|
||||||
data[i-1] = tr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61009 : seems to hand out sector start pointer in opts->drive->buffer
|
|
||||||
and to count hand outs as well as reserved bytes */
|
|
||||||
/* ts A61101 : added parameter track for counting written bytes */
|
|
||||||
static unsigned char *get_sector(struct burn_write_opts *opts,
|
|
||||||
struct burn_track *track, int inmode)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = opts->drive;
|
|
||||||
struct buffer *out = d->buffer;
|
|
||||||
int outmode;
|
|
||||||
int seclen;
|
|
||||||
unsigned char *ret;
|
|
||||||
|
|
||||||
outmode = get_outmode(opts);
|
|
||||||
if (outmode == 0)
|
|
||||||
outmode = inmode;
|
|
||||||
|
|
||||||
/* ts A61009 : react on eventual failure of burn_sector_length()
|
|
||||||
(should not happen if API tested properly).
|
|
||||||
Ensures out->bytes >= out->sectors */
|
|
||||||
seclen = burn_sector_length(outmode);
|
|
||||||
if (seclen <= 0)
|
|
||||||
return NULL;
|
|
||||||
seclen += burn_subcode_length(outmode);
|
|
||||||
|
|
||||||
/* ts A61219 : opts->obs is eventually a 32k trigger for DVD */
|
|
||||||
if (out->bytes + seclen > BUFFER_SIZE ||
|
|
||||||
(opts->obs > 0 && out->bytes + seclen > opts->obs)) {
|
|
||||||
int err;
|
|
||||||
err = d->write(d, d->nwa, out);
|
|
||||||
if (err == BE_CANCELLED)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* ts A61101 */
|
|
||||||
if(track != NULL) {
|
|
||||||
track->writecount += out->bytes;
|
|
||||||
track->written_sectors += out->sectors;
|
|
||||||
}
|
|
||||||
/* ts A61119 */
|
|
||||||
d->progress.buffered_bytes += out->bytes;
|
|
||||||
|
|
||||||
d->nwa += out->sectors;
|
|
||||||
out->bytes = 0;
|
|
||||||
out->sectors = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = out->data + out->bytes;
|
|
||||||
out->bytes += seclen;
|
|
||||||
out->sectors++;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
/* Revoke the counting of the most recent sector handed out by get_sector() */
|
|
||||||
static void unget_sector(struct burn_write_opts *opts, int inmode)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = opts->drive;
|
|
||||||
struct buffer *out = d->buffer;
|
|
||||||
int outmode;
|
|
||||||
int seclen;
|
|
||||||
|
|
||||||
outmode = get_outmode(opts);
|
|
||||||
if (outmode == 0)
|
|
||||||
outmode = inmode;
|
|
||||||
|
|
||||||
/* ts A61009 : react on eventual failure of burn_sector_length()
|
|
||||||
(should not happen if API tested properly).
|
|
||||||
Ensures out->bytes >= out->sectors */
|
|
||||||
seclen = burn_sector_length(outmode);
|
|
||||||
if (seclen <= 0)
|
|
||||||
return;
|
|
||||||
seclen += burn_subcode_length(outmode);
|
|
||||||
|
|
||||||
out->bytes -= seclen;
|
|
||||||
out->sectors--;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* either inmode == outmode, or outmode == raw. anything else is bad news */
|
|
||||||
/* ts A61010 : changed type to int in order to propagate said bad news */
|
|
||||||
/** @return 1 is ok, <= 0 is failure */
|
|
||||||
static int convert_data(struct burn_write_opts *o, struct burn_track *track,
|
|
||||||
int inmode, unsigned char *data)
|
|
||||||
{
|
|
||||||
int outlen, inlen;
|
|
||||||
int offset = -1;
|
|
||||||
int outmode;
|
|
||||||
|
|
||||||
outmode = get_outmode(o);
|
|
||||||
if (outmode == 0)
|
|
||||||
outmode = inmode;
|
|
||||||
|
|
||||||
outlen = burn_sector_length(outmode);
|
|
||||||
inlen = burn_sector_length(inmode);
|
|
||||||
|
|
||||||
/* ts A61010 */
|
|
||||||
/* a ssert(outlen >= inlen); */
|
|
||||||
if (outlen < inlen)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if ((outmode & BURN_MODE_BITS) == (inmode & BURN_MODE_BITS)) {
|
|
||||||
get_bytes(track, inlen, data);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61010 */
|
|
||||||
/* a ssert(outmode & BURN_MODE_RAW); */
|
|
||||||
if (!(outmode & BURN_MODE_RAW))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (inmode & BURN_MODE1)
|
|
||||||
offset = 16;
|
|
||||||
if (inmode & BURN_MODE_RAW)
|
|
||||||
offset = 0;
|
|
||||||
if (inmode & BURN_AUDIO)
|
|
||||||
offset = 0;
|
|
||||||
|
|
||||||
/* ts A61010 */
|
|
||||||
/* a ssert(offset != -1); */
|
|
||||||
if (offset == -1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
get_bytes(track, inlen, data + offset);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void convert_subs(struct burn_write_opts *o, int inmode,
|
|
||||||
unsigned char *subs, unsigned char *sector)
|
|
||||||
{
|
|
||||||
unsigned char *out;
|
|
||||||
int outmode;
|
|
||||||
|
|
||||||
outmode = get_outmode(o);
|
|
||||||
if (outmode == 0)
|
|
||||||
outmode = inmode;
|
|
||||||
sector += burn_sector_length(outmode);
|
|
||||||
/* XXX for sao with subs, we'd need something else... */
|
|
||||||
|
|
||||||
switch (o->block_type) {
|
|
||||||
case BURN_BLOCK_RAW96R:
|
|
||||||
uncook_subs(sector, subs);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BURN_BLOCK_RAW16:
|
|
||||||
memcpy(sector, subs + 12, 12);
|
|
||||||
out = sector + 12;
|
|
||||||
out[0] = 0;
|
|
||||||
out[1] = 0;
|
|
||||||
out[2] = 0;
|
|
||||||
/*XXX find a better way to deal with partially damaged P channels*/
|
|
||||||
if (subs[2] != 0)
|
|
||||||
out[3] = 0x80;
|
|
||||||
else
|
|
||||||
out[3] = 0;
|
|
||||||
out = sector + 10;
|
|
||||||
|
|
||||||
out[0] = ~out[0];
|
|
||||||
out[1] = ~out[1];
|
|
||||||
break;
|
|
||||||
/* ts A61119 : to silence compiler warnings */
|
|
||||||
default:;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void subcode_toc(struct burn_drive *d, int mode, unsigned char *data)
|
|
||||||
{
|
|
||||||
unsigned char *q;
|
|
||||||
int track;
|
|
||||||
int crc;
|
|
||||||
int min, sec, frame;
|
|
||||||
|
|
||||||
track = d->toc_temp / 3;
|
|
||||||
memset(data, 0, 96);
|
|
||||||
q = data + 12;
|
|
||||||
|
|
||||||
burn_lba_to_msf(d->rlba, &min, &sec, &frame);
|
|
||||||
/*XXX track numbers are BCD
|
|
||||||
a0 - 1st track ctrl
|
|
||||||
a1 - last track ctrl
|
|
||||||
a2 - lout ctrl
|
|
||||||
*/
|
|
||||||
q[0] = (d->toc_entry[track].control << 4) + 1;
|
|
||||||
q[1] = 0;
|
|
||||||
if (d->toc_entry[track].point < 100)
|
|
||||||
q[2] = dec_to_bcd(d->toc_entry[track].point);
|
|
||||||
else
|
|
||||||
q[2] = d->toc_entry[track].point;
|
|
||||||
q[3] = dec_to_bcd(min);
|
|
||||||
q[4] = dec_to_bcd(sec);
|
|
||||||
q[5] = dec_to_bcd(frame);
|
|
||||||
q[6] = 0;
|
|
||||||
q[7] = dec_to_bcd(d->toc_entry[track].pmin);
|
|
||||||
q[8] = dec_to_bcd(d->toc_entry[track].psec);
|
|
||||||
q[9] = dec_to_bcd(d->toc_entry[track].pframe);
|
|
||||||
crc = crc_ccitt(q, 10);
|
|
||||||
q[10] = crc >> 8;
|
|
||||||
q[11] = crc & 0xFF;
|
|
||||||
d->toc_temp++;
|
|
||||||
d->toc_temp %= (d->toc_entries * 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sector_toc(struct burn_write_opts *o, int mode)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = o->drive;
|
|
||||||
unsigned char *data;
|
|
||||||
unsigned char subs[96];
|
|
||||||
|
|
||||||
data = get_sector(o, NULL, mode);
|
|
||||||
if (data == NULL)
|
|
||||||
return 0;
|
|
||||||
/* ts A61010 */
|
|
||||||
if (convert_data(o, NULL, mode, data) <= 0)
|
|
||||||
return 0;
|
|
||||||
subcode_toc(d, mode, subs);
|
|
||||||
convert_subs(o, mode, subs, data);
|
|
||||||
sector_headers(o, data, mode, 1);
|
|
||||||
sector_common(++)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sector_pregap(struct burn_write_opts *o,
|
|
||||||
unsigned char tno, unsigned char control, int mode)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = o->drive;
|
|
||||||
unsigned char *data;
|
|
||||||
unsigned char subs[96];
|
|
||||||
|
|
||||||
data = get_sector(o, NULL, mode);
|
|
||||||
if (data == NULL)
|
|
||||||
return 0;
|
|
||||||
/* ts A61010 */
|
|
||||||
if (convert_data(o, NULL, mode, data) <= 0)
|
|
||||||
return 0;
|
|
||||||
subcode_user(o, subs, tno, control, 0, NULL, 1);
|
|
||||||
convert_subs(o, mode, subs, data);
|
|
||||||
sector_headers(o, data, mode, 0);
|
|
||||||
sector_common(--)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sector_postgap(struct burn_write_opts *o,
|
|
||||||
unsigned char tno, unsigned char control, int mode)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = o->drive;
|
|
||||||
unsigned char subs[96];
|
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
data = get_sector(o, NULL, mode);
|
|
||||||
if (data == NULL)
|
|
||||||
return 0;
|
|
||||||
/* ts A61010 */
|
|
||||||
if (convert_data(o, NULL, mode, data) <= 0)
|
|
||||||
return 0;;
|
|
||||||
/* use last index in track */
|
|
||||||
subcode_user(o, subs, tno, control, 1, NULL, 1);
|
|
||||||
convert_subs(o, mode, subs, data);
|
|
||||||
sector_headers(o, data, mode, 0);
|
|
||||||
sector_common(++)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void subcode_lout(struct burn_write_opts *o, unsigned char control,
|
|
||||||
unsigned char *data)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = o->drive;
|
|
||||||
unsigned char *q;
|
|
||||||
int crc;
|
|
||||||
int rmin, min, rsec, sec, rframe, frame;
|
|
||||||
|
|
||||||
memset(data, 0, 96);
|
|
||||||
q = data + 12;
|
|
||||||
|
|
||||||
burn_lba_to_msf(d->alba, &min, &sec, &frame);
|
|
||||||
burn_lba_to_msf(d->rlba, &rmin, &rsec, &rframe);
|
|
||||||
|
|
||||||
if (((rmin == 0) && (rsec == 0) && (rframe == 0)) ||
|
|
||||||
((rsec >= 2) && !((rframe / 19) % 2)))
|
|
||||||
memset(data, 0xFF, 12);
|
|
||||||
q[0] = (control << 4) + 1;
|
|
||||||
q[1] = 0xAA;
|
|
||||||
q[2] = 0x01;
|
|
||||||
q[3] = dec_to_bcd(rmin);
|
|
||||||
q[4] = dec_to_bcd(rsec);
|
|
||||||
q[5] = dec_to_bcd(rframe);
|
|
||||||
q[6] = 0;
|
|
||||||
q[7] = dec_to_bcd(min);
|
|
||||||
q[8] = dec_to_bcd(sec);
|
|
||||||
q[9] = dec_to_bcd(frame);
|
|
||||||
crc = crc_ccitt(q, 10);
|
|
||||||
q[10] = crc >> 8;
|
|
||||||
q[11] = crc & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char char_to_isrc(char c)
|
|
||||||
{
|
|
||||||
if (c >= '0' && c <= '9')
|
|
||||||
return c - '0';
|
|
||||||
if (c >= 'A' && c <= 'Z')
|
|
||||||
return 0x11 + (c - 'A');
|
|
||||||
if (c >= 'a' && c <= 'z')
|
|
||||||
return 0x11 + (c - 'a');
|
|
||||||
|
|
||||||
/* ts A61008 : obsoleted by test in burn_track_set_isrc() */
|
|
||||||
/* a ssert(0); */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void subcode_user(struct burn_write_opts *o, unsigned char *subcodes,
|
|
||||||
unsigned char tno, unsigned char control,
|
|
||||||
unsigned char indx, struct isrc *isrc, int psub)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = o->drive;
|
|
||||||
unsigned char *p, *q;
|
|
||||||
int crc;
|
|
||||||
int m, s, f, c, qmode; /* 1, 2 or 3 */
|
|
||||||
|
|
||||||
memset(subcodes, 0, 96);
|
|
||||||
|
|
||||||
p = subcodes;
|
|
||||||
if ((tno == 1) && (d->rlba == -150))
|
|
||||||
memset(p, 0xFF, 12);
|
|
||||||
|
|
||||||
if (psub)
|
|
||||||
memset(p, 0xFF, 12);
|
|
||||||
q = subcodes + 12;
|
|
||||||
|
|
||||||
qmode = 1;
|
|
||||||
/* every 1 in 10 we can do something different */
|
|
||||||
if (d->rlba % 10 == 0) {
|
|
||||||
/* each of these can occur 1 in 100 */
|
|
||||||
if ((d->rlba / 10) % 10 == 0) {
|
|
||||||
if (o->has_mediacatalog)
|
|
||||||
qmode = 2;
|
|
||||||
} else if ((d->rlba / 10) % 10 == 1) {
|
|
||||||
if (isrc && isrc->has_isrc)
|
|
||||||
qmode = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61010 : this cannot happen. Assert for fun ? */
|
|
||||||
/* a ssert(qmode == 1 || qmode == 2 || qmode == 3); */
|
|
||||||
|
|
||||||
switch (qmode) {
|
|
||||||
case 1:
|
|
||||||
q[1] = dec_to_bcd(tno); /* track number */
|
|
||||||
q[2] = dec_to_bcd(indx); /* index XXX read this shit
|
|
||||||
from the track array */
|
|
||||||
burn_lba_to_msf(d->rlba, &m, &s, &f);
|
|
||||||
q[3] = dec_to_bcd(m); /* rel min */
|
|
||||||
q[4] = dec_to_bcd(s); /* rel sec */
|
|
||||||
q[5] = dec_to_bcd(f); /* rel frame */
|
|
||||||
q[6] = 0; /* zero */
|
|
||||||
burn_lba_to_msf(d->alba, &m, &s, &f);
|
|
||||||
q[7] = dec_to_bcd(m); /* abs min */
|
|
||||||
q[8] = dec_to_bcd(s); /* abs sec */
|
|
||||||
q[9] = dec_to_bcd(f); /* abs frame */
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
/* media catalog number */
|
|
||||||
q[1] = (o->mediacatalog[0] << 4) + o->mediacatalog[1];
|
|
||||||
q[2] = (o->mediacatalog[2] << 4) + o->mediacatalog[3];
|
|
||||||
q[3] = (o->mediacatalog[4] << 4) + o->mediacatalog[5];
|
|
||||||
q[4] = (o->mediacatalog[6] << 4) + o->mediacatalog[7];
|
|
||||||
q[5] = (o->mediacatalog[8] << 4) + o->mediacatalog[9];
|
|
||||||
q[6] = (o->mediacatalog[10] << 4) + o->mediacatalog[11];
|
|
||||||
q[7] = o->mediacatalog[12] << 4;
|
|
||||||
|
|
||||||
q[8] = 0;
|
|
||||||
burn_lba_to_msf(d->alba, &m, &s, &f);
|
|
||||||
q[9] = dec_to_bcd(f); /* abs frame */
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
c = char_to_isrc(isrc->country[0]);
|
|
||||||
/* top 6 bits of [1] is the first country code */
|
|
||||||
q[1] = c << 2;
|
|
||||||
c = char_to_isrc(isrc->country[1]);
|
|
||||||
/* bottom 2 bits of [1] is part of the second country code */
|
|
||||||
q[1] += (c >> 4);
|
|
||||||
/* top 4 bits if [2] is the rest of the second country code */
|
|
||||||
q[2] = c << 4;
|
|
||||||
|
|
||||||
c = char_to_isrc(isrc->owner[0]);
|
|
||||||
/* bottom 4 bits of [2] is part of the first owner code */
|
|
||||||
q[2] += (c >> 2);
|
|
||||||
/* top 2 bits of [3] is the rest of the first owner code */
|
|
||||||
q[3] = c << 6;
|
|
||||||
c = char_to_isrc(isrc->owner[1]);
|
|
||||||
/* bottom 6 bits of [3] is the entire second owner code */
|
|
||||||
q[3] += c;
|
|
||||||
c = char_to_isrc(isrc->owner[2]);
|
|
||||||
/* top 6 bits of [4] are the third owner code */
|
|
||||||
q[4] = c << 2;
|
|
||||||
|
|
||||||
/* [5] is the year in 2 BCD numbers */
|
|
||||||
q[5] = dec_to_bcd(isrc->year % 100);
|
|
||||||
/* [6] is the first 2 digits in the serial */
|
|
||||||
q[6] = dec_to_bcd(isrc->serial % 100);
|
|
||||||
/* [7] is the next 2 digits in the serial */
|
|
||||||
q[7] = dec_to_bcd((isrc->serial / 100) % 100);
|
|
||||||
/* the top 4 bits of [8] is the last serial digit, the rest is
|
|
||||||
zeros */
|
|
||||||
q[8] = dec_to_bcd((isrc->serial / 10000) % 10) << 4;
|
|
||||||
burn_lba_to_msf(d->alba, &m, &s, &f);
|
|
||||||
q[9] = dec_to_bcd(f); /* abs frame */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
q[0] = (control << 4) + qmode;
|
|
||||||
|
|
||||||
crc = crc_ccitt(q, 10);
|
|
||||||
q[10] = crc >> 8;
|
|
||||||
q[11] = crc & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sector_lout(struct burn_write_opts *o, unsigned char control, int mode)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = o->drive;
|
|
||||||
unsigned char subs[96];
|
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
data = get_sector(o, NULL, mode);
|
|
||||||
if (!data)
|
|
||||||
return 0;
|
|
||||||
/* ts A61010 */
|
|
||||||
if (convert_data(o, NULL, mode, data) <= 0)
|
|
||||||
return 0;
|
|
||||||
subcode_lout(o, control, subs);
|
|
||||||
convert_subs(o, mode, subs, data);
|
|
||||||
sector_headers(o, data, mode, 0);
|
|
||||||
sector_common(++)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sector_data(struct burn_write_opts *o, struct burn_track *t, int psub)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = o->drive;
|
|
||||||
unsigned char subs[96];
|
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
data = get_sector(o, t, t->mode);
|
|
||||||
if (!data)
|
|
||||||
return 0;
|
|
||||||
/* ts A61010 */
|
|
||||||
if (convert_data(o, t, t->mode, data) <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
if (t->open_ended && t->track_data_done) {
|
|
||||||
unget_sector(o, t->mode);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61219 : allow track without .entry */
|
|
||||||
if (t->entry == NULL)
|
|
||||||
;
|
|
||||||
else if (!t->source->read_sub)
|
|
||||||
subcode_user(o, subs, t->entry->point,
|
|
||||||
t->entry->control, 1, &t->isrc, psub);
|
|
||||||
else if (!t->source->read_sub(t->source, subs, 96))
|
|
||||||
subcode_user(o, subs, t->entry->point,
|
|
||||||
t->entry->control, 1, &t->isrc, psub);
|
|
||||||
convert_subs(o, t->mode, subs, data);
|
|
||||||
|
|
||||||
sector_headers(o, data, t->mode, 0);
|
|
||||||
sector_common(++)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_msf_to_lba(int m, int s, int f)
|
|
||||||
{
|
|
||||||
if (m < 90)
|
|
||||||
return (m * 60 + s) * 75 + f - 150;
|
|
||||||
else
|
|
||||||
return (m * 60 + s) * 75 + f - 450150;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_lba_to_msf(int lba, int *m, int *s, int *f)
|
|
||||||
{
|
|
||||||
if (lba >= -150) {
|
|
||||||
*m = (lba + 150) / (60 * 75);
|
|
||||||
*s = (lba + 150 - *m * 60 * 75) / 75;
|
|
||||||
*f = lba + 150 - *m * 60 * 75 - *s * 75;
|
|
||||||
} else {
|
|
||||||
*m = (lba + 450150) / (60 * 75);
|
|
||||||
*s = (lba + 450150 - *m * 60 * 75) / 75;
|
|
||||||
*f = lba + 450150 - *m * 60 * 75 - *s * 75;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int dec_to_bcd(int d)
|
|
||||||
{
|
|
||||||
int top, bottom;
|
|
||||||
|
|
||||||
top = d / 10;
|
|
||||||
bottom = d - (top * 10);
|
|
||||||
return (top << 4) + bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sector_headers_is_ok(struct burn_write_opts *o, int mode)
|
|
||||||
{
|
|
||||||
if (mode & BURN_AUDIO) /* no headers for "audio" */
|
|
||||||
return 1;
|
|
||||||
if (o->write_type == BURN_WRITE_SAO)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
if (o->write_type == BURN_WRITE_TAO)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (mode & BURN_MODE1)
|
|
||||||
return 2;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sector_headers(struct burn_write_opts *o, unsigned char *out,
|
|
||||||
int mode, int leadin)
|
|
||||||
{
|
|
||||||
struct burn_drive *d = o->drive;
|
|
||||||
unsigned int crc;
|
|
||||||
int min, sec, frame;
|
|
||||||
int modebyte = -1;
|
|
||||||
|
|
||||||
/* ts A61009 */
|
|
||||||
#if 1
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = sector_headers_is_ok(o, mode);
|
|
||||||
if (ret != 2)
|
|
||||||
return;
|
|
||||||
modebyte = 1;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
if (mode & BURN_AUDIO) /* no headers for "audio" */
|
|
||||||
return;
|
|
||||||
if (o->write_type == BURN_WRITE_SAO)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
if (o->write_type == BURN_WRITE_TAO)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mode & BURN_MODE1)
|
|
||||||
modebyte = 1;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ts A61009 : now ensured by burn_disc_write_is_ok() */
|
|
||||||
/* a ssert(modebyte == 1); */
|
|
||||||
|
|
||||||
out[0] = 0;
|
|
||||||
memset(out + 1, 0xFF, 10); /* sync */
|
|
||||||
out[11] = 0;
|
|
||||||
|
|
||||||
if (leadin) {
|
|
||||||
burn_lba_to_msf(d->rlba, &min, &sec, &frame);
|
|
||||||
out[12] = dec_to_bcd(min) + 0xA0;
|
|
||||||
out[13] = dec_to_bcd(sec);
|
|
||||||
out[14] = dec_to_bcd(frame);
|
|
||||||
out[15] = modebyte;
|
|
||||||
} else {
|
|
||||||
burn_lba_to_msf(d->alba, &min, &sec, &frame);
|
|
||||||
out[12] = dec_to_bcd(min);
|
|
||||||
out[13] = dec_to_bcd(sec);
|
|
||||||
out[14] = dec_to_bcd(frame);
|
|
||||||
out[15] = modebyte;
|
|
||||||
}
|
|
||||||
if (mode & BURN_MODE1) {
|
|
||||||
crc = crc_32(out, 2064);
|
|
||||||
out[2064] = crc & 0xFF;
|
|
||||||
crc >>= 8;
|
|
||||||
out[2065] = crc & 0xFF;
|
|
||||||
crc >>= 8;
|
|
||||||
out[2066] = crc & 0xFF;
|
|
||||||
crc >>= 8;
|
|
||||||
out[2067] = crc & 0xFF;
|
|
||||||
}
|
|
||||||
if (mode & BURN_MODE1) {
|
|
||||||
memset(out + 2068, 0, 8);
|
|
||||||
parity_p(out);
|
|
||||||
parity_q(out);
|
|
||||||
}
|
|
||||||
scramble(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void process_q(struct burn_drive *d, unsigned char *q)
|
|
||||||
{
|
|
||||||
unsigned char i[5];
|
|
||||||
int mode;
|
|
||||||
|
|
||||||
mode = q[0] & 0xF;
|
|
||||||
/* burn_print(12, "mode: %d : ", mode);*/
|
|
||||||
switch (mode) {
|
|
||||||
case 1:
|
|
||||||
/* burn_print(12, "tno = %d : ", q[1]);
|
|
||||||
burn_print(12, "index = %d\n", q[2]);
|
|
||||||
*/
|
|
||||||
/* q[1] is the track number (starting at 1) q[2] is the index
|
|
||||||
number (starting at 0) */
|
|
||||||
#warning this is totally bogus
|
|
||||||
if (q[1] - 1 > 99)
|
|
||||||
break;
|
|
||||||
if (q[2] > d->toc->track[q[1] - 1].indices) {
|
|
||||||
burn_print(12, "new index at %d\n", d->alba);
|
|
||||||
d->toc->track[q[1] - 1].index[q[2]] = d->alba;
|
|
||||||
d->toc->track[q[1] - 1].indices++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
/* XXX dont ignore these */
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
/* burn_print(12, "ISRC data in mode 3 q\n");*/
|
|
||||||
i[0] = isrc[(q[1] << 2) >> 2];
|
|
||||||
/* burn_print(12, "0x%x 0x%x 0x%x 0x%x 0x%x\n", q[1], q[2], q[3], q[4], q[5]);
|
|
||||||
burn_print(12, "ISRC - %c%c%c%c%c\n", i[0], i[1], i[2], i[3], i[4]);
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
|
|
||||||
/* ts A61009 : if reactivated then witout Assert */
|
|
||||||
a ssert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* this needs more info. subs in the data? control/adr? */
|
|
||||||
|
|
||||||
/* ts A61119 : One should not use inofficial compiler extensions.
|
|
||||||
>>> Some day this function needs to be implemented. At least for now
|
|
||||||
the result does not match the "mode" of cdrecord -toc.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
#warning sector_identify needs to be written
|
|
||||||
*/
|
|
||||||
int sector_identify(unsigned char *data)
|
|
||||||
{
|
|
||||||
scramble(data);
|
|
||||||
/*
|
|
||||||
check mode byte for 1 or 2
|
|
||||||
test parity to see if it's a valid sector
|
|
||||||
if invalid, return BURN_MODE_AUDIO;
|
|
||||||
else return mode byte (what about mode 2 formless? heh)
|
|
||||||
*/
|
|
||||||
return BURN_MODE1;
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __SECTOR
|
|
||||||
#define __SECTOR
|
|
||||||
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "transport.h"
|
|
||||||
|
|
||||||
struct burn_drive;
|
|
||||||
struct isrc;
|
|
||||||
|
|
||||||
int dec_to_bcd(int);
|
|
||||||
|
|
||||||
int sector_toc(struct burn_write_opts *, int mode);
|
|
||||||
int sector_pregap(struct burn_write_opts *, unsigned char tno,
|
|
||||||
unsigned char control, int mode);
|
|
||||||
int sector_postgap(struct burn_write_opts *, unsigned char tno,
|
|
||||||
unsigned char control, int mode);
|
|
||||||
int sector_lout(struct burn_write_opts *, unsigned char control, int mode);
|
|
||||||
int sector_data(struct burn_write_opts *, struct burn_track *t, int psub);
|
|
||||||
|
|
||||||
/* ts A61009 */
|
|
||||||
int sector_headers_is_ok(struct burn_write_opts *o, int mode);
|
|
||||||
|
|
||||||
void sector_headers(struct burn_write_opts *, unsigned char *,
|
|
||||||
int mode, int leadin);
|
|
||||||
void subcode_user(struct burn_write_opts *, unsigned char *s,
|
|
||||||
unsigned char tno, unsigned char control,
|
|
||||||
unsigned char index, struct isrc *isrc, int psub);
|
|
||||||
|
|
||||||
int sector_identify(unsigned char *);
|
|
||||||
|
|
||||||
void process_q(struct burn_drive *d, unsigned char *q);
|
|
||||||
|
|
||||||
#endif /* __SECTOR */
|
|
@ -1,631 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
This is the main operating system dependent SCSI part of libburn. It implements
|
|
||||||
the transport level aspects of SCSI control and command i/o.
|
|
||||||
|
|
||||||
Present implementation: FreeBSD CAM (untested)
|
|
||||||
|
|
||||||
|
|
||||||
PORTING:
|
|
||||||
|
|
||||||
Porting libburn typically will consist of adding a new operating system case
|
|
||||||
to the following switcher files:
|
|
||||||
os.h Operating system specific libburn definitions and declarations.
|
|
||||||
sg.c Operating system dependent transport level modules.
|
|
||||||
and of deriving the following system specific files from existing examples:
|
|
||||||
os-*.h Included by os.h. You will need some general system knowledge
|
|
||||||
about signals and knowledge about the storage object needs of your
|
|
||||||
transport level module sg-*.c.
|
|
||||||
|
|
||||||
sg-*.c This source module. You will need special system knowledge about
|
|
||||||
how to detect all potentially available drives, how to open them,
|
|
||||||
eventually how to exclusively reserve them, how to perform
|
|
||||||
SCSI transactions, how to inquire the (pseudo-)SCSI driver.
|
|
||||||
You will not need to care about CD burning, MMC or other high-level
|
|
||||||
SCSI aspects.
|
|
||||||
|
|
||||||
Said sg-*.c operations are defined by a public function interface, which has
|
|
||||||
to be implemented in a way that provides libburn with the desired services:
|
|
||||||
|
|
||||||
sg_give_next_adr() iterates over the set of potentially useful drive
|
|
||||||
address strings.
|
|
||||||
|
|
||||||
scsi_enumerate_drives() brings all available, not-whitelist-banned, and
|
|
||||||
accessible drives into libburn's list of drives.
|
|
||||||
|
|
||||||
sg_drive_is_open() tells wether libburn has the given drive in use.
|
|
||||||
|
|
||||||
sg_grab() opens the drive for SCSI commands and ensures
|
|
||||||
undisturbed access.
|
|
||||||
|
|
||||||
sg_release() closes a drive opened by sg_grab()
|
|
||||||
|
|
||||||
sg_issue_command() sends a SCSI command to the drive, receives reply,
|
|
||||||
and evaluates wether the command succeeded or shall
|
|
||||||
be retried or finally failed.
|
|
||||||
|
|
||||||
sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
|
|
||||||
|
|
||||||
burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
|
|
||||||
|
|
||||||
|
|
||||||
Porting hints are marked by the text "PORTING:".
|
|
||||||
Send feedback to libburn-hackers@pykix.org .
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/** PORTING : ------- OS dependent headers and definitions ------ */
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <camlib.h>
|
|
||||||
#include <cam/scsi/scsi_message.h>
|
|
||||||
#include <cam/scsi/scsi_pass.h>
|
|
||||||
|
|
||||||
#include <err.h> /* XXX */
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70909 : >>> untestet yet wether this compiles */
|
|
||||||
#include <sys/statvfs.h>
|
|
||||||
|
|
||||||
|
|
||||||
/** PORTING : ------ libburn portable headers and definitions ----- */
|
|
||||||
|
|
||||||
#include "transport.h"
|
|
||||||
#include "drive.h"
|
|
||||||
#include "sg.h"
|
|
||||||
#include "spc.h"
|
|
||||||
#include "mmc.h"
|
|
||||||
#include "sbc.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "toc.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
|
|
||||||
/* is in portable part of libburn */
|
|
||||||
int burn_drive_is_banned(char *device_address);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
|
||||||
/* ts A61115: Private functions. Port only if needed by public functions */
|
|
||||||
/* (Public functions are listed below) */
|
|
||||||
/* ------------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
|
|
||||||
/* Helper function for scsi_give_next_adr() */
|
|
||||||
static int sg_init_enumerator(burn_drive_enumerator_t *idx)
|
|
||||||
{
|
|
||||||
idx->skip_device = 0;
|
|
||||||
|
|
||||||
if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
|
|
||||||
warn("couldn't open %s", XPT_DEVICE);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bzero(&(idx->ccb), sizeof(union ccb));
|
|
||||||
|
|
||||||
idx->ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
|
|
||||||
idx->ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
|
|
||||||
idx->ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
|
|
||||||
|
|
||||||
idx->ccb.ccb_h.func_code = XPT_DEV_MATCH;
|
|
||||||
idx->bufsize = sizeof(struct dev_match_result) * 100;
|
|
||||||
idx->ccb.cdm.match_buf_len = idx->bufsize;
|
|
||||||
idx->ccb.cdm.matches = (struct dev_match_result *)malloc(idx->bufsize);
|
|
||||||
if (idx->ccb.cdm.matches == NULL) {
|
|
||||||
warnx("can't malloc memory for matches");
|
|
||||||
close(idx->fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
idx->ccb.cdm.num_matches = 0;
|
|
||||||
idx->i = idx->ccb.cdm.num_matches; /* to trigger buffer load */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We fetch all nodes, since we display most of them in the default
|
|
||||||
* case, and all in the verbose case.
|
|
||||||
*/
|
|
||||||
idx->ccb.cdm.num_patterns = 0;
|
|
||||||
idx->ccb.cdm.pattern_buf_len = 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Helper function for scsi_give_next_adr() */
|
|
||||||
static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We do the ioctl multiple times if necessary, in case there are
|
|
||||||
* more than 100 nodes in the EDT.
|
|
||||||
*/
|
|
||||||
if (ioctl(idx->fd, CAMIOCOMMAND, &(idx->ccb)) == -1) {
|
|
||||||
warn("error sending CAMIOCOMMAND ioctl");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((idx->ccb.ccb_h.status != CAM_REQ_CMP)
|
|
||||||
|| ((idx->ccb.cdm.status != CAM_DEV_MATCH_LAST)
|
|
||||||
&& (idx->ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
|
|
||||||
warnx("got CAM error %#x, CDM error %d\n",
|
|
||||||
idx->ccb.ccb_h.status, idx->ccb.cdm.status);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int sg_close_drive(struct burn_drive * d)
|
|
||||||
{
|
|
||||||
if (d->cam != NULL) {
|
|
||||||
cam_close_device(d->cam);
|
|
||||||
d->cam = NULL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* PORTING: Private functions which contain publicly needed functionality. */
|
|
||||||
/* Their portable part must be performed. So it is probably best */
|
|
||||||
/* to replace the non-portable part and to call these functions */
|
|
||||||
/* in your port, too. */
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
|
|
||||||
/** Wraps a detected drive into libburn structures and hands it over to
|
|
||||||
libburn drive list.
|
|
||||||
*/
|
|
||||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
|
||||||
int channel_no, int target_no, int lun_no)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct burn_drive out;
|
|
||||||
|
|
||||||
/* General libburn drive setup */
|
|
||||||
burn_setup_drive(&out, fname);
|
|
||||||
|
|
||||||
/* This transport adapter uses SCSI-family commands and models
|
|
||||||
(seems the adapter would know better than its boss, if ever) */
|
|
||||||
ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
|
|
||||||
target_no, lun_no, 0);
|
|
||||||
if (ret<=0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* PORTING: ------------------- non portable part --------------- */
|
|
||||||
|
|
||||||
/* Operating system adapter is CAM */
|
|
||||||
/* Adapter specific handles and data */
|
|
||||||
out.cam = NULL;
|
|
||||||
|
|
||||||
/* PORTING: ---------------- end of non portable part ------------ */
|
|
||||||
|
|
||||||
/* Adapter specific functions with standardized names */
|
|
||||||
out.grab = sg_grab;
|
|
||||||
out.release = sg_release;
|
|
||||||
out.drive_is_open = sg_drive_is_open;
|
|
||||||
out.issue_command = sg_issue_command;
|
|
||||||
/* Finally register drive and inquire drive information */
|
|
||||||
burn_drive_finish_enum(&out);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61115 */
|
|
||||||
/* ------------------------------------------------------------------------ */
|
|
||||||
/* PORTING: Public functions. These MUST be ported. */
|
|
||||||
/* ------------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
|
|
||||||
/** Returns the next index number and the next enumerated drive address.
|
|
||||||
The enumeration has to cover all available and accessible drives. It is
|
|
||||||
allowed to return addresses of drives which are not available but under
|
|
||||||
some (even exotic) circumstances could be available. It is on the other
|
|
||||||
hand allowed, only to hand out addresses which can really be used right
|
|
||||||
in the moment of this call. (This implementation chooses the latter.)
|
|
||||||
@param idx An opaque handle. Make no own theories about it.
|
|
||||||
@param adr Takes the reply
|
|
||||||
@param adr_size Gives maximum size of reply including final 0
|
|
||||||
@param initialize 1 = start new,
|
|
||||||
0 = continue, use no other values for now
|
|
||||||
-1 = finish
|
|
||||||
@return 1 = reply is a valid address , 0 = no further address available
|
|
||||||
-1 = severe error (e.g. adr_size too small)
|
|
||||||
*/
|
|
||||||
int sg_give_next_adr(burn_drive_enumerator_t *idx,
|
|
||||||
char adr[], int adr_size, int initialize)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (initialize == 1) {
|
|
||||||
ret = sg_init_enumerator(idx);
|
|
||||||
if (ret<=0)
|
|
||||||
return ret;
|
|
||||||
} else if (initialize == -1) {
|
|
||||||
if(idx->fd != -1)
|
|
||||||
close(idx->fd);
|
|
||||||
idx->fd = -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try_item:; /* This spaghetti loop keeps the number of tabs small */
|
|
||||||
|
|
||||||
/* Loop content from old scsi_enumerate_drives() */
|
|
||||||
|
|
||||||
while (idx->i >= idx->ccb.cdm.num_matches) {
|
|
||||||
ret = sg_next_enumeration_buffer(idx);
|
|
||||||
if (ret<=0)
|
|
||||||
return -1;
|
|
||||||
if (!((idx->ccb.ccb_h.status == CAM_REQ_CMP)
|
|
||||||
&& (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE)) )
|
|
||||||
return 0;
|
|
||||||
idx->i = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (idx->ccb.cdm.matches[idx->i].type) {
|
|
||||||
case DEV_MATCH_BUS:
|
|
||||||
break;
|
|
||||||
case DEV_MATCH_DEVICE: {
|
|
||||||
struct device_match_result* result;
|
|
||||||
|
|
||||||
result = &(idx->ccb.cdm.matches[i].result.device_result);
|
|
||||||
if (result->flags & DEV_RESULT_UNCONFIGURED)
|
|
||||||
idx->skip_device = 1;
|
|
||||||
else
|
|
||||||
idx->skip_device = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DEV_MATCH_PERIPH: {
|
|
||||||
struct periph_match_result* result;
|
|
||||||
char buf[64];
|
|
||||||
|
|
||||||
result = &(idx->ccb.cdm.matches[i].result.periph_result);
|
|
||||||
if (idx->skip_device ||
|
|
||||||
strcmp(result->periph_name, "pass") == 0)
|
|
||||||
break;
|
|
||||||
snprintf(buf, sizeof (buf), "/dev/%s%d",
|
|
||||||
result->periph_name, result->unit_number);
|
|
||||||
if(adr_size <= strlen(buf)
|
|
||||||
return -1;
|
|
||||||
strcpy(adr, buf);
|
|
||||||
|
|
||||||
/* Found next enumerable address */
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
/* printf(stderr, "unknown match type\n"); */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
(idx->i)++;
|
|
||||||
goto try_item; /* Regular function exit is return 1 above */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Brings all available, not-whitelist-banned, and accessible drives into
|
|
||||||
libburn's list of drives.
|
|
||||||
*/
|
|
||||||
int scsi_enumerate_drives(void)
|
|
||||||
{
|
|
||||||
burn_drive_enumerator_t idx;
|
|
||||||
int initialize = 1;
|
|
||||||
char buf[64];
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
|
||||||
initialize = 0;
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
if (burn_drive_is_banned(buf))
|
|
||||||
continue;
|
|
||||||
enumerate_common(buf, idx.result->path_id, idx.result->path_id,
|
|
||||||
0, idx.result->target_id,
|
|
||||||
idx.result->target_lun);
|
|
||||||
}
|
|
||||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Tells wether libburn has the given drive in use or exclusively reserved.
|
|
||||||
If it is "open" then libburn will eventually call sg_release() on it when
|
|
||||||
it is time to give up usage resp. reservation.
|
|
||||||
*/
|
|
||||||
/** Published as burn_drive.drive_is_open() */
|
|
||||||
int sg_drive_is_open(struct burn_drive * d)
|
|
||||||
{
|
|
||||||
return (d->cam != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Opens the drive for SCSI commands and - if burn activities are prone
|
|
||||||
to external interference on your system - obtains an exclusive access lock
|
|
||||||
on the drive. (Note: this is not physical tray locking.)
|
|
||||||
A drive that has been opened with sg_grab() will eventually be handed
|
|
||||||
over to sg_release() for closing and unreserving.
|
|
||||||
*/
|
|
||||||
int sg_grab(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
struct cam_device *cam;
|
|
||||||
|
|
||||||
if(d->cam != NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
cam = cam_open_device(d->devname, O_RDWR);
|
|
||||||
if (cam == NULL) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x00020003,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Could not grab drive", 0/*os_errno*/, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
d->cam = cam;
|
|
||||||
fcntl(cam->fd, F_SETOWN, getpid());
|
|
||||||
d->released = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** PORTING: Is mainly about the call to sg_close_drive() and wether it
|
|
||||||
implements the demanded functionality.
|
|
||||||
*/
|
|
||||||
/** Gives up the drive for SCSI commands and releases eventual access locks.
|
|
||||||
(Note: this is not physical tray locking.)
|
|
||||||
*/
|
|
||||||
int sg_release(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
if (d->cam == NULL) {
|
|
||||||
burn_print(1, "release an ungrabbed drive. die\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
sg_close_drive(d);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Sends a SCSI command to the drive, receives reply and evaluates wether
|
|
||||||
the command succeeded or shall be retried or finally failed.
|
|
||||||
Returned SCSI errors shall not lead to a return value indicating failure.
|
|
||||||
The callers get notified by c->error. An SCSI failure which leads not to
|
|
||||||
a retry shall be notified via scsi_notify_error().
|
|
||||||
The Libburn_log_sg_commandS facility might be of help when problems with
|
|
||||||
a drive have to be examined. It shall stay disabled for normal use.
|
|
||||||
@return: 1 success , <=0 failure
|
|
||||||
*/
|
|
||||||
int sg_issue_command(struct burn_drive *d, struct command *c)
|
|
||||||
{
|
|
||||||
int done = 0;
|
|
||||||
int err;
|
|
||||||
union ccb *ccb;
|
|
||||||
|
|
||||||
if (d->cam == NULL) {
|
|
||||||
c->error = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->error = 0;
|
|
||||||
|
|
||||||
ccb = cam_getccb(d->cam);
|
|
||||||
cam_fill_csio(&ccb->csio,
|
|
||||||
1, /* retries */
|
|
||||||
NULL, /* cbfncp */
|
|
||||||
CAM_DEV_QFRZDIS, /* flags */
|
|
||||||
MSG_SIMPLE_Q_TAG, /* tag_action */
|
|
||||||
NULL, /* data_ptr */
|
|
||||||
0, /* dxfer_len */
|
|
||||||
sizeof (ccb->csio.sense_data), /* sense_len */
|
|
||||||
0, /* cdb_len */
|
|
||||||
30*1000); /* timeout */
|
|
||||||
switch (c->dir) {
|
|
||||||
case TO_DRIVE:
|
|
||||||
ccb->csio.ccb_h.flags |= CAM_DIR_OUT;
|
|
||||||
break;
|
|
||||||
case FROM_DRIVE:
|
|
||||||
ccb->csio.ccb_h.flags |= CAM_DIR_IN;
|
|
||||||
break;
|
|
||||||
case NO_TRANSFER:
|
|
||||||
ccb->csio.ccb_h.flags |= CAM_DIR_NONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ccb->csio.cdb_len = c->oplen;
|
|
||||||
memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen);
|
|
||||||
|
|
||||||
memset(&ccb->csio.sense_data, 0, sizeof (ccb->csio.sense_data));
|
|
||||||
|
|
||||||
if (c->page) {
|
|
||||||
ccb->csio.data_ptr = c->page->data;
|
|
||||||
if (c->dir == FROM_DRIVE) {
|
|
||||||
ccb->csio.dxfer_len = BUFFER_SIZE;
|
|
||||||
/* touch page so we can use valgrind */
|
|
||||||
memset(c->page->data, 0, BUFFER_SIZE);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* ts A61115: removed a ssert() */
|
|
||||||
if(c->page->bytes <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ccb->csio.dxfer_len = c->page->bytes;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ccb->csio.data_ptr = NULL;
|
|
||||||
ccb->csio.dxfer_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
err = cam_send_ccb(d->cam, ccb);
|
|
||||||
if (err == -1) {
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
d->global_index, 0x0002010c,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Failed to transfer command to drive",
|
|
||||||
errno, 0);
|
|
||||||
cam_freeccb(ccb);
|
|
||||||
sg_close_drive(d);
|
|
||||||
d->released = 1;
|
|
||||||
d->busy = BURN_DRIVE_IDLE;
|
|
||||||
c->error = 1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* XXX */
|
|
||||||
memcpy(c->sense, &ccb->csio.sense_data, ccb->csio.sense_len);
|
|
||||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
|
||||||
if (!c->retry) {
|
|
||||||
c->error = 1;
|
|
||||||
cam_freeccb(ccb);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
switch (scsi_error(d, c->sense, 0)) {
|
|
||||||
case RETRY:
|
|
||||||
done = 0;
|
|
||||||
break;
|
|
||||||
case FAIL:
|
|
||||||
done = 1;
|
|
||||||
c->error = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
} while (!done);
|
|
||||||
cam_freeccb(ccb);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Tries to obtain SCSI address parameters.
|
|
||||||
@return 1 is success , 0 is failure
|
|
||||||
*/
|
|
||||||
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|
||||||
int *target_no, int *lun_no)
|
|
||||||
{
|
|
||||||
burn_drive_enumerator_t idx;
|
|
||||||
int initialize = 1;
|
|
||||||
char buf[64];
|
|
||||||
struct periph_match_result* result;
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
|
||||||
initialize = 0;
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
if (strcmp(adr, buf) != 0)
|
|
||||||
continue;
|
|
||||||
result = &(idx->ccb.cdm.matches[i].result.periph_result);
|
|
||||||
*bus_no = result->path_id;
|
|
||||||
*host_no = result->path_id;
|
|
||||||
*channel_no = 0;
|
|
||||||
*target_no = result->target_id
|
|
||||||
*lun_no = result->target_lun;
|
|
||||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Tells wether a text is a persistent address as listed by the enumeration
|
|
||||||
functions.
|
|
||||||
*/
|
|
||||||
int sg_is_enumerable_adr(char* adr)
|
|
||||||
{
|
|
||||||
burn_drive_enumerator_t idx;
|
|
||||||
int initialize = 1;
|
|
||||||
char buf[64];
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
|
||||||
initialize = 0;
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
if (strcmp(adr, buf) == 0) {
|
|
||||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70909 */
|
|
||||||
/** Estimate the potential payload capacity of a file address.
|
|
||||||
@param path The address of the file to be examined. If it does not
|
|
||||||
exist yet, then the directory will be inquired.
|
|
||||||
@param bytes This value gets modified if an estimation is possible
|
|
||||||
@return -2 = cannot perform necessary operations on file object
|
|
||||||
-1 = neither path nor dirname of path exist
|
|
||||||
0 = could not estimate size capacity of file object
|
|
||||||
1 = estimation has been made, bytes was set
|
|
||||||
*/
|
|
||||||
int burn_os_stdio_capacity(char *path, off_t *bytes)
|
|
||||||
{
|
|
||||||
struct stat stbuf;
|
|
||||||
struct statvfs vfsbuf;
|
|
||||||
char testpath[4096], *cpt;
|
|
||||||
long blocks;
|
|
||||||
int open_mode = O_RDWR, fd, ret;
|
|
||||||
off_t add_size = 0;
|
|
||||||
|
|
||||||
testpath[0] = 0;
|
|
||||||
blocks = *bytes / 512;
|
|
||||||
if (stat(path, &stbuf) == -1) {
|
|
||||||
strcpy(testpath, path);
|
|
||||||
cpt = strrchr(testpath, '/');
|
|
||||||
if(cpt == NULL)
|
|
||||||
strcpy(testpath, ".");
|
|
||||||
else if(cpt == testpath)
|
|
||||||
testpath[1] = 0;
|
|
||||||
else
|
|
||||||
*cpt = 0;
|
|
||||||
if (stat(testpath, &stbuf) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#ifdef Libburn_if_this_was_linuX
|
|
||||||
|
|
||||||
} else if(S_ISBLK(stbuf.st_mode)) {
|
|
||||||
if(burn_sg_open_o_excl)
|
|
||||||
open_mode |= O_EXCL;
|
|
||||||
fd = open(path, open_mode);
|
|
||||||
if (fd == -1)
|
|
||||||
return -2;
|
|
||||||
ret = ioctl(fd, BLKGETSIZE, &blocks);
|
|
||||||
close(fd);
|
|
||||||
if (ret == -1)
|
|
||||||
return -2;
|
|
||||||
*bytes = ((off_t) blocks) * (off_t) 512;
|
|
||||||
|
|
||||||
#endif /* Libburn_if_this_was_linuX */
|
|
||||||
|
|
||||||
|
|
||||||
} else if(S_ISREG(stbuf.st_mode)) {
|
|
||||||
add_size = stbuf.st_blocks * (off_t) 512;
|
|
||||||
strcpy(testpath, path);
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (testpath[0]) {
|
|
||||||
if (statvfs(testpath, &vfsbuf) == -1)
|
|
||||||
return -2;
|
|
||||||
*bytes = add_size + ((off_t) vfsbuf.f_bsize) *
|
|
||||||
(off_t) vfsbuf.f_bavail;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
@ -1,673 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <camlib.h>
|
|
||||||
#include <cam/scsi/scsi_message.h>
|
|
||||||
#include <cam/scsi/scsi_pass.h>
|
|
||||||
|
|
||||||
#include <err.h> /* XXX */
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70909 : >>> untestet yet wether this compiles */
|
|
||||||
#include <sys/statvfs.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "transport.h"
|
|
||||||
#include "drive.h"
|
|
||||||
#include "sg.h"
|
|
||||||
#include "spc.h"
|
|
||||||
#include "mmc.h"
|
|
||||||
#include "sbc.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "toc.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
struct burn_drive_enumeration_state {
|
|
||||||
int fd;
|
|
||||||
union ccb ccb;
|
|
||||||
unsigned int i;
|
|
||||||
int skip_device;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
|
||||||
int channel_no, int target_no, int lun_no);
|
|
||||||
|
|
||||||
/* ts A51221 */
|
|
||||||
int burn_drive_is_banned(char *device_address);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60821
|
|
||||||
debug: for tracing calls which might use open drive fds
|
|
||||||
or for catching SCSI usage of emulated drives. */
|
|
||||||
int mmc_function_spy(struct burn_drive *d, char * text);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61021 : Moved most code from scsi_enumerate_drives under
|
|
||||||
sg_give_next_adr() */
|
|
||||||
/* Some helper functions for scsi_give_next_adr() */
|
|
||||||
|
|
||||||
static int sg_init_enumerator(burn_drive_enumerator_t *idx_)
|
|
||||||
{
|
|
||||||
struct burn_drive_enumeration_state *idx;
|
|
||||||
int bufsize;
|
|
||||||
|
|
||||||
idx = malloc(sizeof(*idx));
|
|
||||||
if (idx == NULL) {
|
|
||||||
warnx("can't malloc memory for enumerator");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
idx->skip_device = 0;
|
|
||||||
|
|
||||||
if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
|
|
||||||
warn("couldn't open %s", XPT_DEVICE);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bzero(&(idx->ccb), sizeof(union ccb));
|
|
||||||
|
|
||||||
idx->ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
|
|
||||||
idx->ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
|
|
||||||
idx->ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
|
|
||||||
|
|
||||||
idx->ccb.ccb_h.func_code = XPT_DEV_MATCH;
|
|
||||||
bufsize = sizeof(struct dev_match_result) * 100;
|
|
||||||
idx->ccb.cdm.match_buf_len = bufsize;
|
|
||||||
idx->ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
|
|
||||||
if (idx->ccb.cdm.matches == NULL) {
|
|
||||||
warnx("can't malloc memory for matches");
|
|
||||||
close(idx->fd);
|
|
||||||
free(idx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
idx->ccb.cdm.num_matches = 0;
|
|
||||||
idx->i = idx->ccb.cdm.num_matches; /* to trigger buffer load */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We fetch all nodes, since we display most of them in the default
|
|
||||||
* case, and all in the verbose case.
|
|
||||||
*/
|
|
||||||
idx->ccb.cdm.num_patterns = 0;
|
|
||||||
idx->ccb.cdm.pattern_buf_len = 0;
|
|
||||||
|
|
||||||
*idx_ = idx;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sg_destroy_enumerator(burn_drive_enumerator_t *idx_)
|
|
||||||
{
|
|
||||||
struct burn_drive_enumeration_state *idx = *idx_;
|
|
||||||
|
|
||||||
if(idx->fd != -1)
|
|
||||||
close(idx->fd);
|
|
||||||
|
|
||||||
free(idx->ccb.cdm.matches);
|
|
||||||
free(idx);
|
|
||||||
|
|
||||||
*idx_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx_)
|
|
||||||
{
|
|
||||||
struct burn_drive_enumeration_state *idx = *idx_;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We do the ioctl multiple times if necessary, in case there are
|
|
||||||
* more than 100 nodes in the EDT.
|
|
||||||
*/
|
|
||||||
if (ioctl(idx->fd, CAMIOCOMMAND, &(idx->ccb)) == -1) {
|
|
||||||
warn("error sending CAMIOCOMMAND ioctl");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((idx->ccb.ccb_h.status != CAM_REQ_CMP)
|
|
||||||
|| ((idx->ccb.cdm.status != CAM_DEV_MATCH_LAST)
|
|
||||||
&& (idx->ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
|
|
||||||
warnx("got CAM error %#x, CDM error %d\n",
|
|
||||||
idx->ccb.ccb_h.status, idx->ccb.cdm.status);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Returns the next index number and the next enumerated drive address.
|
|
||||||
@param idx An opaque handle. Make no own theories about it.
|
|
||||||
@param adr Takes the reply
|
|
||||||
@param adr_size Gives maximum size of reply including final 0
|
|
||||||
@param initialize 1 = start new,
|
|
||||||
0 = continue, use no other values for now
|
|
||||||
-1 = finish
|
|
||||||
@return 1 = reply is a valid address , 0 = no further address available
|
|
||||||
-1 = severe error (e.g. adr_size too small)
|
|
||||||
*/
|
|
||||||
int sg_give_next_adr(burn_drive_enumerator_t *idx_,
|
|
||||||
char adr[], int adr_size, int initialize)
|
|
||||||
{
|
|
||||||
struct burn_drive_enumeration_state *idx;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (initialize == 1) {
|
|
||||||
ret = sg_init_enumerator(idx_);
|
|
||||||
if (ret<=0)
|
|
||||||
return ret;
|
|
||||||
} else if (initialize == -1) {
|
|
||||||
sg_destroy_enumerator(idx_);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = *idx_;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (idx->i >= idx->ccb.cdm.num_matches) {
|
|
||||||
ret = sg_next_enumeration_buffer(idx_);
|
|
||||||
if (ret<=0)
|
|
||||||
return -1;
|
|
||||||
idx->i = 0;
|
|
||||||
} else
|
|
||||||
(idx->i)++;
|
|
||||||
|
|
||||||
while (idx->i < idx->ccb.cdm.num_matches) {
|
|
||||||
switch (idx->ccb.cdm.matches[idx->i].type) {
|
|
||||||
case DEV_MATCH_BUS:
|
|
||||||
break;
|
|
||||||
case DEV_MATCH_DEVICE: {
|
|
||||||
struct device_match_result* result;
|
|
||||||
|
|
||||||
result = &(idx->ccb.cdm.matches[idx->i].result.device_result);
|
|
||||||
if (result->flags & DEV_RESULT_UNCONFIGURED)
|
|
||||||
idx->skip_device = 1;
|
|
||||||
else
|
|
||||||
idx->skip_device = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DEV_MATCH_PERIPH: {
|
|
||||||
struct periph_match_result* result;
|
|
||||||
|
|
||||||
result = &(idx->ccb.cdm.matches[idx->i].result.periph_result);
|
|
||||||
if (idx->skip_device ||
|
|
||||||
strcmp(result->periph_name, "pass") == 0)
|
|
||||||
break;
|
|
||||||
ret = snprintf(adr, adr_size, "/dev/%s%d",
|
|
||||||
result->periph_name, result->unit_number);
|
|
||||||
if(ret >= adr_size)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Found next enumerable address */
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
/* printf(stderr, "unknown match type\n"); */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
(idx->i)++;
|
|
||||||
}
|
|
||||||
} while ((idx->ccb.ccb_h.status == CAM_REQ_CMP)
|
|
||||||
&& (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int sg_is_enumerable_adr(char* adr)
|
|
||||||
{
|
|
||||||
burn_drive_enumerator_t idx;
|
|
||||||
int ret;
|
|
||||||
char buf[64];
|
|
||||||
|
|
||||||
ret = sg_init_enumerator(&idx);
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
while(1) {
|
|
||||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
if (strcmp(adr, buf) == 0) {
|
|
||||||
sg_destroy_enumerator(&idx);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sg_destroy_enumerator(&idx);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Try to obtain SCSI address parameters.
|
|
||||||
@return 1 is success , 0 is failure
|
|
||||||
*/
|
|
||||||
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|
||||||
int *target_no, int *lun_no)
|
|
||||||
{
|
|
||||||
burn_drive_enumerator_t idx;
|
|
||||||
int ret;
|
|
||||||
char buf[64];
|
|
||||||
struct periph_match_result* result;
|
|
||||||
|
|
||||||
ret = sg_init_enumerator(&idx);
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
while(1) {
|
|
||||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
if (strcmp(path, buf) == 0) {
|
|
||||||
result = &(idx->ccb.cdm.matches[idx->i].result.periph_result);
|
|
||||||
*bus_no = result->path_id;
|
|
||||||
*host_no = result->path_id;
|
|
||||||
*channel_no = 0;
|
|
||||||
*target_no = result->target_id;
|
|
||||||
*lun_no = result->target_lun;
|
|
||||||
sg_destroy_enumerator(&idx);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sg_destroy_enumerator(&idx);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int sg_close_drive(struct burn_drive * d)
|
|
||||||
{
|
|
||||||
if (d->cam != NULL) {
|
|
||||||
cam_close_device(d->cam);
|
|
||||||
d->cam = NULL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sg_drive_is_open(struct burn_drive * d)
|
|
||||||
{
|
|
||||||
return (d->cam != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int scsi_enumerate_drives(void)
|
|
||||||
{
|
|
||||||
burn_drive_enumerator_t idx;
|
|
||||||
int ret;
|
|
||||||
char buf[64];
|
|
||||||
struct periph_match_result* result;
|
|
||||||
|
|
||||||
ret = sg_init_enumerator(&idx);
|
|
||||||
if (ret <= 0)
|
|
||||||
return 0;
|
|
||||||
while(1) {
|
|
||||||
ret = sg_give_next_adr(&idx, buf, sizeof(buf), 0);
|
|
||||||
if (ret <= 0)
|
|
||||||
break;
|
|
||||||
if (burn_drive_is_banned(buf))
|
|
||||||
continue;
|
|
||||||
result = &idx->ccb.cdm.matches[idx->i].result.periph_result;
|
|
||||||
enumerate_common(buf, result->path_id, result->path_id,
|
|
||||||
0, result->target_id,
|
|
||||||
result->target_lun);
|
|
||||||
}
|
|
||||||
sg_destroy_enumerator(&idx);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef Scsi_freebsd_make_own_enumeratE
|
|
||||||
|
|
||||||
/* ts A61021: The old version which mixes SCSI and operating system adapter
|
|
||||||
*/
|
|
||||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
|
||||||
int channel_no, int target_no, int lun_no)
|
|
||||||
{
|
|
||||||
struct burn_drive *t;
|
|
||||||
struct burn_drive out;
|
|
||||||
|
|
||||||
/* ts A60923 */
|
|
||||||
out.bus_no = bus_no;
|
|
||||||
out.host = host_no;
|
|
||||||
out.id = target_no;
|
|
||||||
out.channel = channel_no;
|
|
||||||
out.lun = lun_no;
|
|
||||||
|
|
||||||
out.devname = burn_strdup(fname);
|
|
||||||
out.cam = NULL;
|
|
||||||
|
|
||||||
out.start_lba= -2000000000;
|
|
||||||
out.end_lba= -2000000000;
|
|
||||||
out.read_atip = mmc_read_atip;
|
|
||||||
|
|
||||||
out.grab = sg_grab;
|
|
||||||
out.release = sg_release;
|
|
||||||
out.drive_is_open= sg_drive_is_open;
|
|
||||||
out.issue_command = sg_issue_command;
|
|
||||||
out.getcaps = spc_getcaps;
|
|
||||||
out.released = 1;
|
|
||||||
out.status = BURN_DISC_UNREADY;
|
|
||||||
|
|
||||||
out.eject = sbc_eject;
|
|
||||||
out.load = sbc_load;
|
|
||||||
out.lock = spc_prevent;
|
|
||||||
out.unlock = spc_allow;
|
|
||||||
out.read_disc_info = spc_sense_write_params;
|
|
||||||
out.get_erase_progress = spc_get_erase_progress;
|
|
||||||
out.test_unit_ready = spc_test_unit_ready;
|
|
||||||
out.probe_write_modes = spc_probe_write_modes;
|
|
||||||
out.read_toc = mmc_read_toc;
|
|
||||||
out.write = mmc_write;
|
|
||||||
out.erase = mmc_erase;
|
|
||||||
out.read_sectors = mmc_read_sectors;
|
|
||||||
out.perform_opc = mmc_perform_opc;
|
|
||||||
out.set_speed = mmc_set_speed;
|
|
||||||
out.send_parameters = spc_select_error_params;
|
|
||||||
out.send_write_parameters = spc_select_write_params;
|
|
||||||
out.send_cue_sheet = mmc_send_cue_sheet;
|
|
||||||
out.sync_cache = mmc_sync_cache;
|
|
||||||
out.get_nwa = mmc_get_nwa;
|
|
||||||
out.close_disc = mmc_close_disc;
|
|
||||||
out.close_session = mmc_close_session;
|
|
||||||
out.close_track_session = mmc_close;
|
|
||||||
out.read_buffer_capacity = mmc_read_buffer_capacity;
|
|
||||||
out.idata = malloc(sizeof(struct burn_scsi_inquiry_data));
|
|
||||||
out.idata->valid = 0;
|
|
||||||
out.mdata = malloc(sizeof(struct scsi_mode_data));
|
|
||||||
out.mdata->valid = 0;
|
|
||||||
if (out.idata == NULL || out.mdata == NULL) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020108,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Could not allocate new drive object", 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memset(&out.params, 0, sizeof(struct params));
|
|
||||||
t = burn_drive_register(&out);
|
|
||||||
|
|
||||||
/* ts A60821
|
|
||||||
<<< debug: for tracing calls which might use open drive fds */
|
|
||||||
mmc_function_spy(NULL, "enumerate_common : -------- doing grab");
|
|
||||||
|
|
||||||
/* try to get the drive info */
|
|
||||||
if (t->grab(t)) {
|
|
||||||
burn_print(2, "getting drive info\n");
|
|
||||||
t->getcaps(t);
|
|
||||||
t->unlock(t);
|
|
||||||
t->released = 1;
|
|
||||||
} else {
|
|
||||||
burn_print(2, "unable to grab new located drive\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A60821
|
|
||||||
<<< debug: for tracing calls which might use open drive fds */
|
|
||||||
mmc_function_spy(NULL, "enumerate_common : ----- would release ");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* Scsi_freebsd_make_own_enumeratE */
|
|
||||||
|
|
||||||
/* The new, more concise version of enumerate_common */
|
|
||||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
|
||||||
int channel_no, int target_no, int lun_no)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct burn_drive out;
|
|
||||||
|
|
||||||
/* General libburn drive setup */
|
|
||||||
burn_setup_drive(&out, fname);
|
|
||||||
|
|
||||||
/* This transport adapter uses SCSI-family commands and models
|
|
||||||
(seems the adapter would know better than its boss, if ever) */
|
|
||||||
ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
|
|
||||||
target_no, lun_no, 0);
|
|
||||||
if (ret<=0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Operating system adapter is CAM */
|
|
||||||
/* Adapter specific handles and data */
|
|
||||||
out.cam = NULL;
|
|
||||||
/* Adapter specific functions */
|
|
||||||
out.grab = sg_grab;
|
|
||||||
out.release = sg_release;
|
|
||||||
out.drive_is_open = sg_drive_is_open;
|
|
||||||
out.issue_command = sg_issue_command;
|
|
||||||
|
|
||||||
/* Finally register drive and inquire drive information */
|
|
||||||
burn_drive_finish_enum(&out);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* ! Scsi_freebsd_make_own_enumeratE */
|
|
||||||
|
|
||||||
/* ts A61021: do not believe this:
|
|
||||||
we use the sg reference count to decide whether we can use the
|
|
||||||
drive or not.
|
|
||||||
if refcount is not one, drive is open somewhere else.
|
|
||||||
*/
|
|
||||||
int sg_grab(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
struct cam_device *cam;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "sg_grab") <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (burn_drive_is_open(d)) {
|
|
||||||
d->released = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cam = cam_open_device(d->devname, O_RDWR);
|
|
||||||
if (cam == NULL) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Could not grab drive", 0/*os_errno*/, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
|
|
||||||
count = 1;
|
|
||||||
if (1 == count) {
|
|
||||||
d->cam = cam;
|
|
||||||
fcntl(cam->fd, F_SETOWN, getpid());
|
|
||||||
d->released = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
burn_print(1, "could not acquire drive - already open\n");
|
|
||||||
sg_close_drive(d);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
non zero return means you still have the drive and it's not
|
|
||||||
in a state to be released? (is that even possible?)
|
|
||||||
*/
|
|
||||||
|
|
||||||
int sg_release(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
if (mmc_function_spy(d, "sg_release") <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (d->cam == NULL) {
|
|
||||||
burn_print(1, "release an ungrabbed drive. die\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mmc_function_spy(NULL, "sg_release ----------- closing.");
|
|
||||||
|
|
||||||
sg_close_drive(d);
|
|
||||||
d->released = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sg_issue_command(struct burn_drive *d, struct command *c)
|
|
||||||
{
|
|
||||||
int done = 0;
|
|
||||||
int err;
|
|
||||||
union ccb *ccb;
|
|
||||||
|
|
||||||
char buf[161];
|
|
||||||
snprintf(buf, sizeof (buf), "sg_issue_command d->cam=%p d->released=%d",
|
|
||||||
(void*)d->cam, d->released);
|
|
||||||
mmc_function_spy(NULL, buf);
|
|
||||||
|
|
||||||
if (d->cam == NULL) {
|
|
||||||
c->error = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->error = 0;
|
|
||||||
|
|
||||||
ccb = cam_getccb(d->cam);
|
|
||||||
cam_fill_csio(&ccb->csio,
|
|
||||||
1, /* retries */
|
|
||||||
NULL, /* cbfncp */
|
|
||||||
CAM_DEV_QFRZDIS, /* flags */
|
|
||||||
MSG_SIMPLE_Q_TAG, /* tag_action */
|
|
||||||
NULL, /* data_ptr */
|
|
||||||
0, /* dxfer_len */
|
|
||||||
sizeof (ccb->csio.sense_data), /* sense_len */
|
|
||||||
0, /* cdb_len */
|
|
||||||
30*1000); /* timeout */
|
|
||||||
switch (c->dir) {
|
|
||||||
case TO_DRIVE:
|
|
||||||
ccb->csio.ccb_h.flags |= CAM_DIR_OUT;
|
|
||||||
break;
|
|
||||||
case FROM_DRIVE:
|
|
||||||
ccb->csio.ccb_h.flags |= CAM_DIR_IN;
|
|
||||||
break;
|
|
||||||
case NO_TRANSFER:
|
|
||||||
ccb->csio.ccb_h.flags |= CAM_DIR_NONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ccb->csio.cdb_len = c->oplen;
|
|
||||||
memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen);
|
|
||||||
|
|
||||||
memset(&ccb->csio.sense_data, 0, sizeof (ccb->csio.sense_data));
|
|
||||||
|
|
||||||
if (c->page) {
|
|
||||||
ccb->csio.data_ptr = c->page->data;
|
|
||||||
if (c->dir == FROM_DRIVE) {
|
|
||||||
ccb->csio.dxfer_len = BUFFER_SIZE;
|
|
||||||
/* touch page so we can use valgrind */
|
|
||||||
memset(c->page->data, 0, BUFFER_SIZE);
|
|
||||||
} else {
|
|
||||||
assert(c->page->bytes > 0);
|
|
||||||
ccb->csio.dxfer_len = c->page->bytes;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ccb->csio.data_ptr = NULL;
|
|
||||||
ccb->csio.dxfer_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
err = cam_send_ccb(d->cam, ccb);
|
|
||||||
if (err == -1) {
|
|
||||||
libdax_msgs_submit(libdax_messenger,
|
|
||||||
d->global_index, 0x0002010c,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Failed to transfer command to drive",
|
|
||||||
errno, 0);
|
|
||||||
cam_freeccb(ccb);
|
|
||||||
sg_close_drive(d);
|
|
||||||
d->released = 1;
|
|
||||||
d->busy = BURN_DRIVE_IDLE;
|
|
||||||
c->error = 1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* XXX */
|
|
||||||
memcpy(c->sense, &ccb->csio.sense_data, ccb->csio.sense_len);
|
|
||||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
|
||||||
if (!c->retry) {
|
|
||||||
c->error = 1;
|
|
||||||
cam_freeccb(ccb);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
switch (scsi_error(d, c->sense, 0)) {
|
|
||||||
case RETRY:
|
|
||||||
done = 0;
|
|
||||||
break;
|
|
||||||
case FAIL:
|
|
||||||
done = 1;
|
|
||||||
c->error = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
} while (!done);
|
|
||||||
cam_freeccb(ccb);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70909 */
|
|
||||||
/** Estimate the potential payload capacity of a file address.
|
|
||||||
@param path The address of the file to be examined. If it does not
|
|
||||||
exist yet, then the directory will be inquired.
|
|
||||||
@param bytes This value gets modified if an estimation is possible
|
|
||||||
@return -2 = cannot perform necessary operations on file object
|
|
||||||
-1 = neither path nor dirname of path exist
|
|
||||||
0 = could not estimate size capacity of file object
|
|
||||||
1 = estimation has been made, bytes was set
|
|
||||||
*/
|
|
||||||
int burn_os_stdio_capacity(char *path, off_t *bytes)
|
|
||||||
{
|
|
||||||
struct stat stbuf;
|
|
||||||
struct statvfs vfsbuf;
|
|
||||||
char testpath[4096], *cpt;
|
|
||||||
long blocks;
|
|
||||||
int open_mode = O_RDWR, fd, ret;
|
|
||||||
off_t add_size = 0;
|
|
||||||
|
|
||||||
testpath[0] = 0;
|
|
||||||
blocks = *bytes / 512;
|
|
||||||
if (stat(path, &stbuf) == -1) {
|
|
||||||
strcpy(testpath, path);
|
|
||||||
cpt = strrchr(testpath, '/');
|
|
||||||
if(cpt == NULL)
|
|
||||||
strcpy(testpath, ".");
|
|
||||||
else if(cpt == testpath)
|
|
||||||
testpath[1] = 0;
|
|
||||||
else
|
|
||||||
*cpt = 0;
|
|
||||||
if (stat(testpath, &stbuf) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#ifdef Libburn_if_this_was_linuX
|
|
||||||
|
|
||||||
} else if(S_ISBLK(stbuf.st_mode)) {
|
|
||||||
if(burn_sg_open_o_excl)
|
|
||||||
open_mode |= O_EXCL;
|
|
||||||
fd = open(path, open_mode);
|
|
||||||
if (fd == -1)
|
|
||||||
return -2;
|
|
||||||
ret = ioctl(fd, BLKGETSIZE, &blocks);
|
|
||||||
close(fd);
|
|
||||||
if (ret == -1)
|
|
||||||
return -2;
|
|
||||||
*bytes = ((off_t) blocks) * (off_t) 512;
|
|
||||||
|
|
||||||
#endif /* Libburn_if_this_was_linuX */
|
|
||||||
|
|
||||||
|
|
||||||
} else if(S_ISREG(stbuf.st_mode)) {
|
|
||||||
add_size = stbuf.st_blocks * (off_t) 512;
|
|
||||||
strcpy(testpath, path);
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (testpath[0]) {
|
|
||||||
if (statvfs(testpath, &vfsbuf) == -1)
|
|
||||||
return -2;
|
|
||||||
*bytes = add_size + ((off_t) vfsbuf.f_bsize) *
|
|
||||||
(off_t) vfsbuf.f_bavail;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
1444
libburn/sg-linux.c
1444
libburn/sg-linux.c
File diff suppressed because it is too large
Load Diff
17
libburn/sg.c
17
libburn/sg.c
@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
/* sg.c
|
|
||||||
Switcher for operating system dependent transport level modules of libburn.
|
|
||||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
|
|
||||||
#include "sg-freebsd.c"
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include "sg-linux.c"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
36
libburn/sg.h
36
libburn/sg.h
@ -1,36 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __SG
|
|
||||||
#define __SG
|
|
||||||
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* see os.h for name of particular os-*.h where this is defined */
|
|
||||||
BURN_OS_DEFINE_DRIVE_ENUMERATOR_T
|
|
||||||
|
|
||||||
|
|
||||||
struct burn_drive;
|
|
||||||
struct command;
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60922 ticket 33 */
|
|
||||||
int sg_give_next_adr(burn_drive_enumerator_t *enm_context,
|
|
||||||
char adr[], int adr_size, int initialize);
|
|
||||||
int sg_is_enumerable_adr(char *adr);
|
|
||||||
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|
||||||
int *target_no, int *lun_no);
|
|
||||||
|
|
||||||
int sg_grab(struct burn_drive *);
|
|
||||||
int sg_release(struct burn_drive *);
|
|
||||||
int sg_issue_command(struct burn_drive *, struct command *);
|
|
||||||
|
|
||||||
/* ts A61115 : formerly sg_enumerate();ata_enumerate() */
|
|
||||||
int scsi_enumerate_drives(void);
|
|
||||||
|
|
||||||
int sg_drive_is_open(struct burn_drive * d);
|
|
||||||
|
|
||||||
int burn_os_stdio_capacity(char *path, off_t *bytes);
|
|
||||||
|
|
||||||
#endif /* __SG */
|
|
@ -1,55 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "source.h"
|
|
||||||
#include "structure.h"
|
|
||||||
|
|
||||||
void burn_source_free(struct burn_source *src)
|
|
||||||
{
|
|
||||||
if (--src->refcount < 1) {
|
|
||||||
if (src->free_data)
|
|
||||||
src->free_data(src);
|
|
||||||
free(src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum burn_source_status burn_track_set_source(struct burn_track *t,
|
|
||||||
struct burn_source *s)
|
|
||||||
{
|
|
||||||
s->refcount++;
|
|
||||||
t->source = s;
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
t->open_ended = (s->get_size(s) <= 0);
|
|
||||||
|
|
||||||
return BURN_SOURCE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct burn_source *burn_source_new(void)
|
|
||||||
{
|
|
||||||
struct burn_source *out;
|
|
||||||
|
|
||||||
out = calloc(1, sizeof(struct burn_source));
|
|
||||||
|
|
||||||
/* ts A70825 */
|
|
||||||
if (out == NULL)
|
|
||||||
return NULL;
|
|
||||||
memset((char *) out, 0, sizeof(struct burn_source));
|
|
||||||
|
|
||||||
out->refcount = 1;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A71223 */
|
|
||||||
int burn_source_cancel(struct burn_source *src)
|
|
||||||
{
|
|
||||||
if(src->read == NULL)
|
|
||||||
if(src->version > 0)
|
|
||||||
if(src->cancel != NULL)
|
|
||||||
src->cancel(src);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __SOURCE
|
|
||||||
#define __SOURCE
|
|
||||||
|
|
||||||
struct burn_source *burn_source_new(void);
|
|
||||||
|
|
||||||
int burn_source_cancel(struct burn_source *src);
|
|
||||||
|
|
||||||
#endif /*__SOURCE*/
|
|
997
libburn/spc.c
997
libburn/spc.c
@ -1,997 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
/* scsi primary commands */
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* #include <a ssert.h> */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "transport.h"
|
|
||||||
#include "spc.h"
|
|
||||||
#include "mmc.h"
|
|
||||||
#include "sbc.h"
|
|
||||||
#include "drive.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "options.h"
|
|
||||||
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
/* ts A70910
|
|
||||||
debug: for tracing calls which might use open drive fds
|
|
||||||
or for catching SCSI usage of emulated drives. */
|
|
||||||
int mmc_function_spy(struct burn_drive *d, char * text);
|
|
||||||
|
|
||||||
|
|
||||||
/* spc command set */
|
|
||||||
/* ts A70519 : allocation length byte 3+4 was 0,255 */
|
|
||||||
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 36, 0 };
|
|
||||||
|
|
||||||
/*static char SPC_TEST[]={0,0,0,0,0,0};*/
|
|
||||||
static unsigned char SPC_PREVENT[] = { 0x1e, 0, 0, 0, 1, 0 };
|
|
||||||
static unsigned char SPC_ALLOW[] = { 0x1e, 0, 0, 0, 0, 0 };
|
|
||||||
static unsigned char SPC_MODE_SENSE[] = { 0x5a, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
|
|
||||||
static unsigned char SPC_MODE_SELECT[] =
|
|
||||||
{ 0x55, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
static unsigned char SPC_REQUEST_SENSE[] = { 0x03, 0, 0, 0, 18, 0 };
|
|
||||||
static unsigned char SPC_TEST_UNIT_READY[] = { 0x00, 0, 0, 0, 0, 0 };
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70519 : An initializer for the abstract SCSI command structure */
|
|
||||||
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen)
|
|
||||||
{
|
|
||||||
if (oplen > 16)
|
|
||||||
return 0;
|
|
||||||
memcpy(c->opcode, opcode, oplen);
|
|
||||||
c->oplen = oplen;
|
|
||||||
c->dir = NO_TRANSFER;
|
|
||||||
c->dxfer_len = -1;
|
|
||||||
memset(c->sense, 0, sizeof(c->sense));
|
|
||||||
c->error = 0;
|
|
||||||
c->retry = 0;
|
|
||||||
c->page = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq)
|
|
||||||
{
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "test_unit_ready") <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_TEST_UNIT_READY,sizeof(SPC_TEST_UNIT_READY));
|
|
||||||
/*
|
|
||||||
c.oplen = sizeof(SPC_TEST_UNIT_READY);
|
|
||||||
memcpy(c.opcode, SPC_TEST_UNIT_READY, sizeof(SPC_TEST_UNIT_READY));
|
|
||||||
c.page = NULL;
|
|
||||||
*/
|
|
||||||
c.retry = 0;
|
|
||||||
c.dir = NO_TRANSFER;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
if (c.error) {
|
|
||||||
*key= c.sense[2];
|
|
||||||
*asc= c.sense[12];
|
|
||||||
*ascq= c.sense[13];
|
|
||||||
return (c.sense[2] & 0xF) == 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int spc_test_unit_ready(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
int key,asc,ascq;
|
|
||||||
|
|
||||||
return spc_test_unit_ready_r(d, &key, &asc, &ascq);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70315 */
|
|
||||||
/** @param flag bit0=do not wait 0.1 seconds before first test unit ready */
|
|
||||||
/** Wait until the drive state becomes clear or until max_usec elapsed */
|
|
||||||
int spc_wait_unit_attention(struct burn_drive *d, int max_sec, char *cmd_text,
|
|
||||||
int flag)
|
|
||||||
{
|
|
||||||
int i, ret = 1, key = 0, asc = 0, ascq = 0;
|
|
||||||
char msg[160];
|
|
||||||
|
|
||||||
if (!(flag & 1))
|
|
||||||
usleep(100000);
|
|
||||||
for(i = !(flag & 1); i < max_sec * 10; i++) {
|
|
||||||
ret = spc_test_unit_ready_r(d, &key, &asc, &ascq);
|
|
||||||
|
|
||||||
/* <<<
|
|
||||||
fprintf(stderr,
|
|
||||||
"libburn_EXPERIMENTAL: i= %d ret= %d key= %X asc= %2.2X ascq= %2.2X\n",
|
|
||||||
i, ret, (unsigned) key, (unsigned) asc, (unsigned) ascq);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(ret > 0) /* ready */
|
|
||||||
break;
|
|
||||||
if(key!=0x2 || asc!=0x4) {
|
|
||||||
if (key == 0x2 && asc == 0x3A) {
|
|
||||||
ret = 1; /* medium not present = ok */
|
|
||||||
/* <<<
|
|
||||||
ts A70912 :
|
|
||||||
My LG GSA-4082B on asynchronous load:
|
|
||||||
first it reports no media 2,3A,00,
|
|
||||||
then it reports not ready 2,04,00,
|
|
||||||
further media inquiry retrieves wrong data
|
|
||||||
|
|
||||||
if(i<=100)
|
|
||||||
goto slumber;
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (key == 0x6 && asc == 0x28 && ascq == 0x00)
|
|
||||||
/* media change notice = try again */
|
|
||||||
goto slumber;
|
|
||||||
|
|
||||||
sprintf(msg,
|
|
||||||
"Asynchromous SCSI error on %s: key=%X asc=%2.2Xh ascq=%2.2Xh",
|
|
||||||
cmd_text, (unsigned) key, (unsigned) asc,
|
|
||||||
(unsigned) ascq);
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x0002014d,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
msg, 0, 0);
|
|
||||||
d->cancel = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
slumber:;
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(msg, "Async %s %s after %d.%d seconds",
|
|
||||||
cmd_text, (ret > 0 ? "succeeded" : "failed"), i / 10, i % 10);
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020150,
|
|
||||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_LOW, msg, 0, 0);
|
|
||||||
|
|
||||||
if (i < max_sec * 10)
|
|
||||||
return (ret > 0);
|
|
||||||
|
|
||||||
sprintf(msg, "Timeout (%d s) with asynchronous SCSI command %s\n",
|
|
||||||
max_sec, cmd_text);
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002014f,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void spc_request_sense(struct burn_drive *d, struct buffer *buf)
|
|
||||||
{
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "request_sense") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
|
|
||||||
c.retry = 0;
|
|
||||||
/*
|
|
||||||
c.oplen = sizeof(SPC_REQUEST_SENSE);
|
|
||||||
memcpy(c.opcode, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
|
|
||||||
*/
|
|
||||||
c.dxfer_len= c.opcode[4];
|
|
||||||
c.retry = 0;
|
|
||||||
c.page = buf;
|
|
||||||
c.page->sectors = 0;
|
|
||||||
c.page->bytes = 0;
|
|
||||||
c.dir = FROM_DRIVE;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
}
|
|
||||||
|
|
||||||
int spc_get_erase_progress(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct buffer b;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "get_erase_progress") <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
spc_request_sense(d, &b);
|
|
||||||
return (b.data[16] << 8) | b.data[17];
|
|
||||||
}
|
|
||||||
|
|
||||||
void spc_inquiry(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct buffer buf;
|
|
||||||
struct burn_scsi_inquiry_data *id;
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "inquiry") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_INQUIRY, sizeof(SPC_INQUIRY));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_INQUIRY, sizeof(SPC_INQUIRY));
|
|
||||||
c.oplen = sizeof(SPC_INQUIRY);
|
|
||||||
*/
|
|
||||||
c.dxfer_len= (c.opcode[3] << 8) | c.opcode[4];
|
|
||||||
c.retry = 1;
|
|
||||||
c.page = &buf;
|
|
||||||
c.page->bytes = 0;
|
|
||||||
c.page->sectors = 0;
|
|
||||||
c.dir = FROM_DRIVE;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
id = (struct burn_scsi_inquiry_data *)d->idata;
|
|
||||||
memset(id->vendor, 0, 9);
|
|
||||||
memset(id->product, 0, 17);
|
|
||||||
memset(id->revision, 0, 5);
|
|
||||||
if (c.error) {
|
|
||||||
id->valid = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(id->vendor, c.page->data + 8, 8);
|
|
||||||
memcpy(id->product, c.page->data + 16, 16);
|
|
||||||
memcpy(id->revision, c.page->data + 32, 4);
|
|
||||||
id->valid = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spc_prevent(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "prevent") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_PREVENT, sizeof(SPC_PREVENT));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_PREVENT, sizeof(SPC_PREVENT));
|
|
||||||
c.oplen = sizeof(SPC_PREVENT);
|
|
||||||
c.page = NULL;
|
|
||||||
*/
|
|
||||||
c.retry = 1;
|
|
||||||
c.dir = NO_TRANSFER;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void spc_allow(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "allow") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_ALLOW, sizeof(SPC_ALLOW));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_ALLOW, sizeof(SPC_ALLOW));
|
|
||||||
c.oplen = sizeof(SPC_ALLOW);
|
|
||||||
c.page = NULL;
|
|
||||||
*/
|
|
||||||
c.retry = 1;
|
|
||||||
c.dir = NO_TRANSFER;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
ts A70518 : Do not call with *alloc_len < 8
|
|
||||||
*/
|
|
||||||
/** flag&1= do only inquire alloc_len */
|
|
||||||
static int spc_sense_caps_al(struct burn_drive *d, int *alloc_len, int flag)
|
|
||||||
{
|
|
||||||
struct buffer buf;
|
|
||||||
struct scsi_mode_data *m;
|
|
||||||
int size, page_length, num_write_speeds = 0, i, speed, ret;
|
|
||||||
int old_alloc_len, was_error = 0;
|
|
||||||
unsigned char *page;
|
|
||||||
struct command c;
|
|
||||||
struct burn_speed_descriptor *sd;
|
|
||||||
|
|
||||||
/* ts A61225 : 1 = report about post-MMC-1 speed descriptors */
|
|
||||||
static int speed_debug = 0;
|
|
||||||
|
|
||||||
if (*alloc_len < 8)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
|
||||||
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
|
||||||
c.oplen = sizeof(SPC_MODE_SENSE);
|
|
||||||
*/
|
|
||||||
c.dxfer_len = *alloc_len;
|
|
||||||
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
|
|
||||||
c.opcode[8] = c.dxfer_len & 0xff;
|
|
||||||
c.retry = 1;
|
|
||||||
c.opcode[2] = 0x2A;
|
|
||||||
c.page = &buf;
|
|
||||||
c.page->bytes = 0;
|
|
||||||
c.page->sectors = 0;
|
|
||||||
c.dir = FROM_DRIVE;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
if (c.error) {
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
|
||||||
d->mdata->valid = -1;
|
|
||||||
was_error = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = c.page->data[0] * 256 + c.page->data[1];
|
|
||||||
m = d->mdata;
|
|
||||||
page = c.page->data + 8;
|
|
||||||
|
|
||||||
/* ts A61225 :
|
|
||||||
Although MODE SENSE indeed belongs to SPC, the returned code page
|
|
||||||
2Ah is part of MMC-1 to MMC-3. In MMC-1 5.2.3.4. it has 22 bytes,
|
|
||||||
in MMC-3 6.3.11 there are at least 28 bytes plus a variable length
|
|
||||||
set of speed descriptors. In MMC-5 E.11 it is declared "legacy".
|
|
||||||
*/
|
|
||||||
page_length = page[1];
|
|
||||||
old_alloc_len = *alloc_len;
|
|
||||||
*alloc_len = page_length + 8;
|
|
||||||
if (flag & 1)
|
|
||||||
return !was_error;
|
|
||||||
if (page_length + 8 > old_alloc_len)
|
|
||||||
page_length = old_alloc_len - 8;
|
|
||||||
if (page_length < 22)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
m->valid = 0;
|
|
||||||
burn_mdata_free_subs(m);
|
|
||||||
|
|
||||||
m->buffer_size = page[12] * 256 + page[13];
|
|
||||||
m->dvdram_read = page[2] & 32;
|
|
||||||
m->dvdram_write = page[3] & 32;
|
|
||||||
m->dvdr_read = page[2] & 16;
|
|
||||||
m->dvdr_write = page[3] & 16;
|
|
||||||
m->dvdrom_read = page[2] & 8;
|
|
||||||
m->simulate = page[3] & 4;
|
|
||||||
m->cdrw_read = page[2] & 2;
|
|
||||||
m->cdrw_write = page[3] & 2;
|
|
||||||
m->cdr_read = page[2] & 1;
|
|
||||||
m->cdr_write = page[3] & 1;
|
|
||||||
|
|
||||||
m->c2_pointers = page[5] & 16;
|
|
||||||
m->underrun_proof = page[4] & 128;
|
|
||||||
|
|
||||||
/* ts A61021 : these fields are marked obsolete in MMC 3 */
|
|
||||||
m->max_read_speed = page[8] * 256 + page[9];
|
|
||||||
m->cur_read_speed = page[14] * 256 + page[15];
|
|
||||||
|
|
||||||
m->max_write_speed = page[18] * 256 + page[19];
|
|
||||||
m->cur_write_speed = page[20] * 256 + page[21];
|
|
||||||
|
|
||||||
/* ts A61021 : New field to be set by atip (or following MMC-3 info) */
|
|
||||||
m->min_write_speed = m->max_write_speed;
|
|
||||||
|
|
||||||
/* ts A61225 : for ACh GET PERFORMANCE, Type 03h */
|
|
||||||
m->min_end_lba = 0x7fffffff;
|
|
||||||
m->max_end_lba = 0;
|
|
||||||
|
|
||||||
m->valid = 1;
|
|
||||||
|
|
||||||
mmc_get_configuration(d);
|
|
||||||
|
|
||||||
/* ts A61225 : end of MMC-1 , begin of MMC-3 */
|
|
||||||
if (page_length < 32) /* no write speed descriptors ? */
|
|
||||||
goto try_mmc_get_performance;
|
|
||||||
|
|
||||||
m->cur_write_speed = page[28] * 256 + page[29];
|
|
||||||
|
|
||||||
if (speed_debug)
|
|
||||||
fprintf(stderr, "LIBBURN_DEBUG: cur_write_speed = %d\n",
|
|
||||||
m->cur_write_speed);
|
|
||||||
|
|
||||||
num_write_speeds = page[30] * 256 + page[31];
|
|
||||||
m->max_write_speed = m->min_write_speed = m->cur_write_speed;
|
|
||||||
|
|
||||||
if (32 + 4 * num_write_speeds > page_length + 2) {
|
|
||||||
char msg[161];
|
|
||||||
|
|
||||||
sprintf(msg, "Malformed capabilities page 2Ah received (len=%d, #speeds=%d)", page_length, num_write_speeds);
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x0002013c,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
msg, 0, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < num_write_speeds; i++) {
|
|
||||||
speed = page[32 + 4*i + 2] * 256 + page[32 + 4*i + 3];
|
|
||||||
|
|
||||||
if (speed_debug)
|
|
||||||
fprintf(stderr,
|
|
||||||
"LIBBURN_DEBUG: write speed #%d = %d kB/s (rc %d)\n",
|
|
||||||
i, speed, page[32 + 4*i +1] & 7);
|
|
||||||
|
|
||||||
/* ts A61226 */
|
|
||||||
ret = burn_speed_descriptor_new(&(d->mdata->speed_descriptors),
|
|
||||||
NULL, d->mdata->speed_descriptors, 0);
|
|
||||||
if (ret > 0) {
|
|
||||||
sd = d->mdata->speed_descriptors;
|
|
||||||
sd->source = 1;
|
|
||||||
if (d->current_profile > 0) {
|
|
||||||
sd->profile_loaded = d->current_profile;
|
|
||||||
strcpy(sd->profile_name,
|
|
||||||
d->current_profile_text);
|
|
||||||
}
|
|
||||||
sd->wrc = (( page[32 + 4*i +1] & 7 ) == 1 );
|
|
||||||
sd->write_speed = speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (speed > m->max_write_speed)
|
|
||||||
m->max_write_speed = speed;
|
|
||||||
if (speed < m->min_write_speed)
|
|
||||||
m->min_write_speed = speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (speed_debug)
|
|
||||||
fprintf(stderr,
|
|
||||||
"LIBBURN_DEBUG: 5Ah,2Ah min_write_speed = %d , max_write_speed = %d\n",
|
|
||||||
m->min_write_speed, m->max_write_speed);
|
|
||||||
|
|
||||||
try_mmc_get_performance:;
|
|
||||||
ret = mmc_get_write_performance(d);
|
|
||||||
|
|
||||||
if (ret > 0 && speed_debug)
|
|
||||||
fprintf(stderr,
|
|
||||||
"LIBBURN_DEBUG: ACh min_write_speed = %d , max_write_speed = %d\n",
|
|
||||||
m->min_write_speed, m->max_write_speed);
|
|
||||||
return !was_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void spc_sense_caps(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
int alloc_len, start_len = 22, ret;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "sense_caps") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* first command execution to learn Allocation Length */
|
|
||||||
alloc_len = start_len;
|
|
||||||
ret = spc_sense_caps_al(d, &alloc_len, 1);
|
|
||||||
/*
|
|
||||||
fprintf(stderr,"LIBBURN_DEBUG: 5Ah alloc_len = %d , ret = %d\n",
|
|
||||||
alloc_len, ret);
|
|
||||||
*/
|
|
||||||
if (alloc_len >= start_len && ret > 0)
|
|
||||||
/* second execution with announced length */
|
|
||||||
spc_sense_caps_al(d, &alloc_len, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void spc_sense_error_params(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct buffer buf;
|
|
||||||
struct scsi_mode_data *m;
|
|
||||||
int size, alloc_len = 12 ;
|
|
||||||
unsigned char *page;
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "sense_error_params") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
|
||||||
c.oplen = sizeof(SPC_MODE_SENSE);
|
|
||||||
*/
|
|
||||||
c.dxfer_len = alloc_len;
|
|
||||||
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
|
|
||||||
c.opcode[8] = c.dxfer_len & 0xff;
|
|
||||||
c.retry = 1;
|
|
||||||
c.opcode[2] = 0x01;
|
|
||||||
c.page = &buf;
|
|
||||||
c.page->bytes = 0;
|
|
||||||
c.page->sectors = 0;
|
|
||||||
c.dir = FROM_DRIVE;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
|
|
||||||
size = c.page->data[0] * 256 + c.page->data[1];
|
|
||||||
m = d->mdata;
|
|
||||||
page = c.page->data + 8;
|
|
||||||
d->params.retries = page[3];
|
|
||||||
m->retry_page_length = page[1];
|
|
||||||
m->retry_page_valid = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spc_select_error_params(struct burn_drive *d,
|
|
||||||
const struct burn_read_opts *o)
|
|
||||||
{
|
|
||||||
struct buffer buf;
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "select_error_params") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
|
||||||
c.oplen = sizeof(SPC_MODE_SELECT);
|
|
||||||
*/
|
|
||||||
c.retry = 1;
|
|
||||||
c.opcode[8] = 8 + 2 + d->mdata->retry_page_length;
|
|
||||||
c.page = &buf;
|
|
||||||
c.page->bytes = 0;
|
|
||||||
c.page->sectors = 0;
|
|
||||||
|
|
||||||
/* ts A61007 : moved up to only caller burn_disc_read() */
|
|
||||||
/* a ssert(d->mdata->valid); */
|
|
||||||
|
|
||||||
memset(c.page->data, 0, 8 + 2 + d->mdata->retry_page_length);
|
|
||||||
c.page->bytes = 8 + 2 + d->mdata->retry_page_length;
|
|
||||||
c.page->data[8] = 1;
|
|
||||||
c.page->data[9] = d->mdata->retry_page_length;
|
|
||||||
if (o->transfer_damaged_blocks)
|
|
||||||
c.page->data[10] |= 32;
|
|
||||||
if (o->report_recovered_errors)
|
|
||||||
c.page->data[10] |= 4;
|
|
||||||
if (!o->hardware_error_recovery)
|
|
||||||
c.page->data[10] |= 1;
|
|
||||||
/*burn_print(1, "error parameter 0x%x\n", c->page->data[10]);*/
|
|
||||||
c.page->data[11] = d->params.retries;
|
|
||||||
c.dir = TO_DRIVE;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void spc_sense_write_params(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct buffer buf;
|
|
||||||
struct scsi_mode_data *m;
|
|
||||||
int size, dummy, alloc_len = 10;
|
|
||||||
unsigned char *page;
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "sense_write_params") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* ts A61007 : Done in soft at only caller burn_drive_grab() */
|
|
||||||
/* a ssert(d->mdata->cdr_write || d->mdata->cdrw_write ||
|
|
||||||
d->mdata->dvdr_write || d->mdata->dvdram_write); */
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
|
||||||
c.oplen = sizeof(SPC_MODE_SENSE);
|
|
||||||
*/
|
|
||||||
c.dxfer_len = alloc_len;
|
|
||||||
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
|
|
||||||
c.opcode[8] = c.dxfer_len & 0xff;
|
|
||||||
c.retry = 1;
|
|
||||||
c.opcode[2] = 0x05;
|
|
||||||
c.page = &buf;
|
|
||||||
c.page->bytes = 0;
|
|
||||||
c.page->sectors = 0;
|
|
||||||
c.dir = FROM_DRIVE;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
|
|
||||||
/* ts A71128 : do not interpret reply if error */
|
|
||||||
m = d->mdata;
|
|
||||||
if(!c.error) {
|
|
||||||
size = c.page->data[0] * 256 + c.page->data[1];
|
|
||||||
page = c.page->data + 8;
|
|
||||||
burn_print(1, "write page length 0x%x\n", page[1]);
|
|
||||||
m->write_page_length = page[1];
|
|
||||||
m->write_page_valid = 1;
|
|
||||||
} else
|
|
||||||
m->write_page_valid = 0;
|
|
||||||
mmc_read_disc_info(d);
|
|
||||||
|
|
||||||
/* ts A70212 : try to setup d->media_capacity_remaining */
|
|
||||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
|
||||||
d->current_profile == 0x12 || d->current_profile == 0x43)
|
|
||||||
d->read_format_capacities(d, -1);
|
|
||||||
else if (d->status == BURN_DISC_BLANK ||
|
|
||||||
(d->current_is_cd_profile && d->status == BURN_DISC_APPENDABLE)) {
|
|
||||||
d->get_nwa(d, -1, &dummy, &dummy);
|
|
||||||
}
|
|
||||||
/* others are hopefully up to date from mmc_read_disc_info() */
|
|
||||||
|
|
||||||
/*
|
|
||||||
fprintf(stderr, "LIBBURN_DEBUG: media_capacity_remaining = %.f\n",
|
|
||||||
(double) d->media_capacity_remaining);
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* remark ts A61104 :
|
|
||||||
Although command MODE SELECT is SPC, the content of the
|
|
||||||
Write Parameters Mode Page (05h) is MMC (Table 108 in MMC-1).
|
|
||||||
Thus the filling of the mode page is done by mmc_compose_mode_page_5().
|
|
||||||
*/
|
|
||||||
void spc_select_write_params(struct burn_drive *d,
|
|
||||||
const struct burn_write_opts *o)
|
|
||||||
{
|
|
||||||
struct buffer buf;
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "select_write_params") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* ts A61007 : All current callers are safe. */
|
|
||||||
/* a ssert(o->drive == d); */
|
|
||||||
|
|
||||||
/* <<< A61030
|
|
||||||
fprintf(stderr,"libburn_debug: write_type=%d multi=%d control=%d\n",
|
|
||||||
o->write_type,o->multi,o->control);
|
|
||||||
fprintf(stderr,"libburn_debug: block_type=%d spc_block_type=%d\n",
|
|
||||||
o->block_type,spc_block_type(o->block_type));
|
|
||||||
*/
|
|
||||||
|
|
||||||
scsi_init_command(&c, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
|
||||||
c.oplen = sizeof(SPC_MODE_SELECT);
|
|
||||||
*/
|
|
||||||
c.retry = 1;
|
|
||||||
c.opcode[8] = 8 + 2 + d->mdata->write_page_length;
|
|
||||||
c.page = &buf;
|
|
||||||
c.page->bytes = 0;
|
|
||||||
c.page->sectors = 0;
|
|
||||||
|
|
||||||
/* ts A61007 : moved up to burn_disc_write() */
|
|
||||||
/* a ssert(d->mdata->valid); */
|
|
||||||
|
|
||||||
memset(c.page->data, 0, 8 + 2 + d->mdata->write_page_length);
|
|
||||||
c.page->bytes = 8 + 2 + d->mdata->write_page_length;
|
|
||||||
|
|
||||||
burn_print(12, "using write page length %d (valid %d)\n",
|
|
||||||
d->mdata->write_page_length, d->mdata->write_page_valid);
|
|
||||||
|
|
||||||
/* ts A61229 */
|
|
||||||
if (mmc_compose_mode_page_5(d, o, c.page->data + 8) <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
c.dir = TO_DRIVE;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void spc_getcaps(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
if (mmc_function_spy(d, "getcaps") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
spc_inquiry(d);
|
|
||||||
spc_sense_caps(d);
|
|
||||||
spc_sense_error_params(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
don't check totally stupid modes (raw/raw0)
|
|
||||||
some drives say they're ok, and they're not.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void spc_probe_write_modes(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct buffer buf;
|
|
||||||
int try_write_type = 1;
|
|
||||||
int try_block_type = 0;
|
|
||||||
int key, asc, ascq, useable_write_type = -1, useable_block_type = -1;
|
|
||||||
int last_try = 0;
|
|
||||||
struct command c;
|
|
||||||
|
|
||||||
if (mmc_function_spy(d, "spc_probe_write_modes") <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* ts A70213 : added pseudo try_write_type 4 to set a suitable mode */
|
|
||||||
while (try_write_type != 5) {
|
|
||||||
burn_print(9, "trying %d, %d\n", try_write_type,
|
|
||||||
try_block_type);
|
|
||||||
|
|
||||||
/* ts A70213 */
|
|
||||||
if (try_write_type == 4) {
|
|
||||||
/* Pseudo write type NONE . Set a useable write mode */
|
|
||||||
if (useable_write_type == -1)
|
|
||||||
break;
|
|
||||||
try_write_type = useable_write_type;
|
|
||||||
try_block_type = useable_block_type;
|
|
||||||
last_try= 1;
|
|
||||||
}
|
|
||||||
scsi_init_command(&c, SPC_MODE_SELECT,sizeof(SPC_MODE_SELECT));
|
|
||||||
/*
|
|
||||||
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
|
||||||
c.oplen = sizeof(SPC_MODE_SELECT);
|
|
||||||
*/
|
|
||||||
c.retry = 1;
|
|
||||||
c.opcode[8] = 8 + 2 + 0x32;
|
|
||||||
c.page = &buf;
|
|
||||||
|
|
||||||
memset(c.page->data, 0, 8 + 2 + 0x32);
|
|
||||||
c.page->bytes = 8 + 2 + 0x32;
|
|
||||||
|
|
||||||
c.page->data[8] = 5;
|
|
||||||
c.page->data[9] = 0x32;
|
|
||||||
c.page->data[10] = try_write_type;
|
|
||||||
if (try_block_type > 4)
|
|
||||||
c.page->data[11] = 4;
|
|
||||||
else
|
|
||||||
c.page->data[11] = 0;
|
|
||||||
c.page->data[12] = try_block_type;
|
|
||||||
c.page->data[23] = 150;
|
|
||||||
c.dir = TO_DRIVE;
|
|
||||||
|
|
||||||
d->silent_on_scsi_error = 1;
|
|
||||||
d->issue_command(d, &c);
|
|
||||||
d->silent_on_scsi_error = 0;
|
|
||||||
|
|
||||||
if (last_try)
|
|
||||||
break;
|
|
||||||
|
|
||||||
key = c.sense[2];
|
|
||||||
asc = c.sense[12];
|
|
||||||
ascq = c.sense[13];
|
|
||||||
|
|
||||||
if (key)
|
|
||||||
burn_print(7, "%d not supported\n", try_block_type);
|
|
||||||
else {
|
|
||||||
burn_print(7, "%d:%d SUPPORTED MODE!\n",
|
|
||||||
try_write_type, try_block_type);
|
|
||||||
if (try_write_type == 2) /* sao */
|
|
||||||
d->block_types[try_write_type] =
|
|
||||||
BURN_BLOCK_SAO;
|
|
||||||
else
|
|
||||||
d->block_types[try_write_type] |=
|
|
||||||
1 << try_block_type;
|
|
||||||
|
|
||||||
/* ts A70213 */
|
|
||||||
if ((useable_write_type < 0 && try_write_type > 0) ||
|
|
||||||
(try_write_type == 1 && try_block_type == 8)) {
|
|
||||||
/* Packet is not supported yet.
|
|
||||||
Prefer TAO MODE_1. */
|
|
||||||
useable_write_type = try_write_type;
|
|
||||||
useable_block_type = try_block_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (try_block_type) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
try_block_type++;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
try_block_type = 8;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
case 9:
|
|
||||||
case 10:
|
|
||||||
case 11:
|
|
||||||
case 12:
|
|
||||||
try_block_type++;
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
try_block_type = 0;
|
|
||||||
try_write_type++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ( ts A61229 : shouldn't this go to mmc.c too ?) */
|
|
||||||
|
|
||||||
/** @return -1 = error */
|
|
||||||
int spc_block_type(enum burn_block_types b)
|
|
||||||
{
|
|
||||||
switch (b) {
|
|
||||||
case BURN_BLOCK_SAO:
|
|
||||||
return 0; /* ignored bitz */
|
|
||||||
case BURN_BLOCK_RAW0:
|
|
||||||
return 0;
|
|
||||||
case BURN_BLOCK_RAW16:
|
|
||||||
return 1;
|
|
||||||
case BURN_BLOCK_RAW96P:
|
|
||||||
return 2;
|
|
||||||
case BURN_BLOCK_RAW96R:
|
|
||||||
return 3;
|
|
||||||
case BURN_BLOCK_MODE1:
|
|
||||||
return 8;
|
|
||||||
case BURN_BLOCK_MODE2R:
|
|
||||||
return 9;
|
|
||||||
case BURN_BLOCK_MODE2_PATHETIC:
|
|
||||||
return 10;
|
|
||||||
case BURN_BLOCK_MODE2_LAME:
|
|
||||||
return 11;
|
|
||||||
case BURN_BLOCK_MODE2_OBSCURE:
|
|
||||||
return 12;
|
|
||||||
case BURN_BLOCK_MODE2_OK:
|
|
||||||
return 13;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* ts A61007 : already prevented in burn_write_opts_set_write_type() */
|
|
||||||
/* a ssert(0); */;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
|
|
||||||
*/
|
|
||||||
int spc_setup_drive(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
d->getcaps = spc_getcaps;
|
|
||||||
d->lock = spc_prevent;
|
|
||||||
d->unlock = spc_allow;
|
|
||||||
d->read_disc_info = spc_sense_write_params;
|
|
||||||
d->get_erase_progress = spc_get_erase_progress;
|
|
||||||
d->test_unit_ready = spc_test_unit_ready;
|
|
||||||
d->probe_write_modes = spc_probe_write_modes;
|
|
||||||
d->send_parameters = spc_select_error_params;
|
|
||||||
d->send_write_parameters = spc_select_write_params;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61021 : the general SCSI specific part of sg.c:enumerate_common()
|
|
||||||
@param flag Bitfiled for control purposes
|
|
||||||
bit0= do not setup spc/sbc/mmc
|
|
||||||
*/
|
|
||||||
int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
|
||||||
int channel_no, int target_no, int lun_no, int flag)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* ts A60923 */
|
|
||||||
d->bus_no = bus_no;
|
|
||||||
d->host = host_no;
|
|
||||||
d->id = target_no;
|
|
||||||
d->channel = channel_no;
|
|
||||||
d->lun = lun_no;
|
|
||||||
|
|
||||||
/* ts A61106 */
|
|
||||||
d->silent_on_scsi_error = 0;
|
|
||||||
|
|
||||||
|
|
||||||
d->idata = calloc(1, sizeof(struct burn_scsi_inquiry_data));
|
|
||||||
d->mdata = calloc(1, sizeof(struct scsi_mode_data));
|
|
||||||
|
|
||||||
/* ts A61007 : obsolete Assert in drive_getcaps() */
|
|
||||||
if(d->idata == NULL || d->mdata == NULL) {
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020108,
|
|
||||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Could not allocate new drive object", 0, 0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
d->idata->valid = 0;
|
|
||||||
d->mdata->valid = 0;
|
|
||||||
d->mdata->speed_descriptors = NULL;
|
|
||||||
if(!(flag & 1)) {
|
|
||||||
ret = spc_setup_drive(d);
|
|
||||||
if (ret<=0)
|
|
||||||
return ret;
|
|
||||||
ret = sbc_setup_drive(d);
|
|
||||||
if (ret<=0)
|
|
||||||
return ret;
|
|
||||||
ret = mmc_setup_drive(d);
|
|
||||||
if (ret<=0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61122 */
|
|
||||||
enum response scsi_error_msg(struct burn_drive *d, unsigned char *sense,
|
|
||||||
int senselen, char msg[161],
|
|
||||||
int *key, int *asc, int *ascq)
|
|
||||||
{
|
|
||||||
*key= *asc= *ascq= -1;
|
|
||||||
|
|
||||||
if (senselen<=0 || senselen>2)
|
|
||||||
*key = sense[2];
|
|
||||||
if (senselen<=0 || senselen>12)
|
|
||||||
*asc = sense[12];
|
|
||||||
if (senselen<=0 || senselen>13)
|
|
||||||
*ascq = sense[13];
|
|
||||||
|
|
||||||
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
|
|
||||||
*key, *asc, *ascq, d->idata->vendor, d->idata->product);
|
|
||||||
|
|
||||||
switch (*asc) {
|
|
||||||
case 0:
|
|
||||||
sprintf(msg, "(no error reported by SCSI transaction)");
|
|
||||||
return RETRY;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
sprintf(msg, "not ready");
|
|
||||||
return RETRY;
|
|
||||||
case 4:
|
|
||||||
sprintf(msg,
|
|
||||||
"logical unit is in the process of becoming ready");
|
|
||||||
return RETRY;
|
|
||||||
case 0x20:
|
|
||||||
if (*key == 5)
|
|
||||||
sprintf(msg, "bad opcode");
|
|
||||||
return FAIL;
|
|
||||||
case 0x21:
|
|
||||||
sprintf(msg, "invalid address");
|
|
||||||
return FAIL;
|
|
||||||
case 0x24:
|
|
||||||
if (*key == 5)
|
|
||||||
sprintf(msg, "invalid field in cdb");
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
return FAIL;
|
|
||||||
case 0x26:
|
|
||||||
if (*key == 5 )
|
|
||||||
sprintf(msg, "invalid field in parameter list" );
|
|
||||||
return FAIL;
|
|
||||||
case 0x28:
|
|
||||||
if (*key == 6)
|
|
||||||
sprintf(msg, "Medium may have changed");
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
return RETRY;
|
|
||||||
case 0x3A:
|
|
||||||
sprintf(msg, "Medium not present");
|
|
||||||
d->status = BURN_DISC_EMPTY;
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
sprintf(msg,
|
|
||||||
"Failure. See mmc3r10g.pdf: Sense Key %X ASC %2.2X ASCQ %2.2X",
|
|
||||||
*key, *asc, *ascq);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61115 moved from sg-*.c */
|
|
||||||
/* ts A61122 made it frontend to scsi_error_msg() */
|
|
||||||
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
|
|
||||||
int senselen)
|
|
||||||
{
|
|
||||||
int key, asc, ascq;
|
|
||||||
char msg[160];
|
|
||||||
enum response resp;
|
|
||||||
|
|
||||||
resp = scsi_error_msg(d, sense, senselen, msg, &key, &asc, &ascq);
|
|
||||||
if (asc == 0 || asc == 0x3A)
|
|
||||||
burn_print(12, "%s\n", msg);
|
|
||||||
else
|
|
||||||
burn_print(1, "%s\n", msg);
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61030 - A61115 */
|
|
||||||
/* @param flag bit0=do report conditions which are considered not an error */
|
|
||||||
int scsi_notify_error(struct burn_drive *d, struct command *c,
|
|
||||||
unsigned char *sense, int senselen, int flag)
|
|
||||||
{
|
|
||||||
int key= -1, asc= -1, ascq= -1, ret;
|
|
||||||
char msg[320],scsi_msg[160];
|
|
||||||
|
|
||||||
if (d->silent_on_scsi_error)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
strcpy(scsi_msg, " \"");
|
|
||||||
scsi_error_msg(d, sense, senselen, scsi_msg + strlen(scsi_msg),
|
|
||||||
&key, &asc, &ascq);
|
|
||||||
strcat(scsi_msg, "\"");
|
|
||||||
|
|
||||||
if(!(flag & 1)) {
|
|
||||||
/* SPC : TEST UNIT READY command */
|
|
||||||
if (c->opcode[0] == 0)
|
|
||||||
return 1;
|
|
||||||
/* MMC : READ DISC INFORMATION command */
|
|
||||||
if (c->opcode[0] == 0x51)
|
|
||||||
if (key == 0x2 && asc == 0x3A &&
|
|
||||||
ascq>=0 && ascq <= 0x02) /* MEDIUM NOT PRESENT */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(msg,"SCSI error condition on command %2.2Xh :", c->opcode[0]);
|
|
||||||
if (key>=0)
|
|
||||||
sprintf(msg+strlen(msg), " key=%Xh", key);
|
|
||||||
if (asc>=0)
|
|
||||||
sprintf(msg+strlen(msg), " asc=%2.2Xh", asc);
|
|
||||||
if (ascq>=0)
|
|
||||||
sprintf(msg+strlen(msg), " ascq=%2.2Xh", ascq);
|
|
||||||
ret = libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010f,
|
|
||||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
ret = libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010f,
|
|
||||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
scsi_msg,0,0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __SPC
|
|
||||||
#define __SPC
|
|
||||||
|
|
||||||
#include "libburn.h"
|
|
||||||
|
|
||||||
void spc_inquiry(struct burn_drive *);
|
|
||||||
void spc_prevent(struct burn_drive *);
|
|
||||||
void spc_allow(struct burn_drive *);
|
|
||||||
void spc_sense_caps(struct burn_drive *);
|
|
||||||
void spc_sense_error_params(struct burn_drive *);
|
|
||||||
void spc_select_error_params(struct burn_drive *,
|
|
||||||
const struct burn_read_opts *);
|
|
||||||
void spc_getcaps(struct burn_drive *d);
|
|
||||||
void spc_sense_write_params(struct burn_drive *);
|
|
||||||
void spc_select_write_params(struct burn_drive *,
|
|
||||||
const struct burn_write_opts *);
|
|
||||||
void spc_probe_write_modes(struct burn_drive *);
|
|
||||||
void spc_request_sense(struct burn_drive *d, struct buffer *buf);
|
|
||||||
int spc_block_type(enum burn_block_types b);
|
|
||||||
int spc_get_erase_progress(struct burn_drive *d);
|
|
||||||
|
|
||||||
/* ts A70315 : test_unit_ready with result parameters */
|
|
||||||
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq);
|
|
||||||
|
|
||||||
int spc_test_unit_ready(struct burn_drive *d);
|
|
||||||
|
|
||||||
/* ts A70315 */
|
|
||||||
/** Wait until the drive state becomes clear in or until max_sec elapsed */
|
|
||||||
int spc_wait_unit_attention(struct burn_drive *d, int max_sec, char *cmd_text,
|
|
||||||
int flag);
|
|
||||||
|
|
||||||
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
|
|
||||||
*/
|
|
||||||
int spc_setup_drive(struct burn_drive *d);
|
|
||||||
|
|
||||||
/* ts A61021 : the general SCSI specific part of sg.c:enumerate_common()
|
|
||||||
@param flag Bitfield for control purposes
|
|
||||||
bit0= do not setup spc/sbc/mmc
|
|
||||||
*/
|
|
||||||
int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
|
||||||
int channel_no, int target_no, int lun_no, int flag);
|
|
||||||
|
|
||||||
/* ts A61115 moved from sg-*.h */
|
|
||||||
enum response { RETRY, FAIL };
|
|
||||||
enum response scsi_error(struct burn_drive *, unsigned char *, int);
|
|
||||||
|
|
||||||
/* ts A61122 */
|
|
||||||
enum response scsi_error_msg(struct burn_drive *d, unsigned char *sense,
|
|
||||||
int senselen, char msg[161],
|
|
||||||
int *key, int *asc, int *ascq);
|
|
||||||
|
|
||||||
/* ts A61030 */
|
|
||||||
/* @param flag bit0=do report conditions which are considered not an error */
|
|
||||||
int scsi_notify_error(struct burn_drive *, struct command *c,
|
|
||||||
unsigned char *sense, int senselen, int flag);
|
|
||||||
|
|
||||||
/* ts A70519 */
|
|
||||||
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen);
|
|
||||||
|
|
||||||
#endif /*__SPC*/
|
|
@ -1,517 +0,0 @@
|
|||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* #include <a ssert.h> */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "structure.h"
|
|
||||||
#include "write.h"
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#include "libdax_msgs.h"
|
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61008 : replaced Assert by if and return 0 */
|
|
||||||
/* a ssert(!(pos > BURN_POS_END)); */
|
|
||||||
|
|
||||||
#define RESIZE(TO, NEW, pos) {\
|
|
||||||
void *tmp;\
|
|
||||||
\
|
|
||||||
if (pos > BURN_POS_END)\
|
|
||||||
return 0;\
|
|
||||||
if (pos == BURN_POS_END)\
|
|
||||||
pos = TO->NEW##s;\
|
|
||||||
if (pos > TO->NEW##s)\
|
|
||||||
return 0;\
|
|
||||||
\
|
|
||||||
tmp = realloc(TO->NEW, sizeof(struct NEW *) * (TO->NEW##s + 1));\
|
|
||||||
if (!tmp)\
|
|
||||||
return 0;\
|
|
||||||
TO->NEW = tmp;\
|
|
||||||
memmove(TO->NEW + pos + 1, TO->NEW + pos,\
|
|
||||||
sizeof(struct NEW *) * (TO->NEW##s - pos));\
|
|
||||||
TO->NEW##s++;\
|
|
||||||
}
|
|
||||||
|
|
||||||
struct burn_disc *burn_disc_create(void)
|
|
||||||
{
|
|
||||||
struct burn_disc *d;
|
|
||||||
d = calloc(1, sizeof(struct burn_disc));
|
|
||||||
if (d == NULL) /* ts A70825 */
|
|
||||||
return NULL;
|
|
||||||
d->refcnt = 1;
|
|
||||||
d->sessions = 0;
|
|
||||||
d->session = NULL;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_disc_free(struct burn_disc *d)
|
|
||||||
{
|
|
||||||
d->refcnt--;
|
|
||||||
if (d->refcnt == 0) {
|
|
||||||
/* dec refs on all elements */
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < d->sessions; i++)
|
|
||||||
burn_session_free(d->session[i]);
|
|
||||||
free(d->session);
|
|
||||||
free(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct burn_session *burn_session_create(void)
|
|
||||||
{
|
|
||||||
struct burn_session *s;
|
|
||||||
s = calloc(1, sizeof(struct burn_session));
|
|
||||||
if (s == NULL) /* ts A70825 */
|
|
||||||
return NULL;
|
|
||||||
s->refcnt = 1;
|
|
||||||
s->tracks = 0;
|
|
||||||
s->track = NULL;
|
|
||||||
s->hidefirst = 0;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_session_hide_first_track(struct burn_session *s, int onoff)
|
|
||||||
{
|
|
||||||
s->hidefirst = onoff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_session_free(struct burn_session *s)
|
|
||||||
{
|
|
||||||
s->refcnt--;
|
|
||||||
if (s->refcnt == 0) {
|
|
||||||
/* dec refs on all elements */
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < s->tracks; i++)
|
|
||||||
burn_track_free(s->track[i]);
|
|
||||||
free(s->track);
|
|
||||||
free(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_disc_add_session(struct burn_disc *d, struct burn_session *s,
|
|
||||||
unsigned int pos)
|
|
||||||
{
|
|
||||||
RESIZE(d, session, pos);
|
|
||||||
d->session[pos] = s;
|
|
||||||
s->refcnt++;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct burn_track *burn_track_create(void)
|
|
||||||
{
|
|
||||||
struct burn_track *t;
|
|
||||||
t = calloc(1, sizeof(struct burn_track));
|
|
||||||
if (t == NULL) /* ts A70825 */
|
|
||||||
return NULL;
|
|
||||||
t->refcnt = 1;
|
|
||||||
t->indices = 0;
|
|
||||||
t->offset = 0;
|
|
||||||
t->offsetcount = 0;
|
|
||||||
t->tail = 0;
|
|
||||||
t->tailcount = 0;
|
|
||||||
t->mode = BURN_MODE1;
|
|
||||||
t->isrc.has_isrc = 0;
|
|
||||||
t->pad = 1;
|
|
||||||
|
|
||||||
/* ts A70213 */
|
|
||||||
t->fill_up_media = 0;
|
|
||||||
/* ts A70218 */
|
|
||||||
t->default_size = 0;
|
|
||||||
|
|
||||||
t->entry = NULL;
|
|
||||||
t->source = NULL;
|
|
||||||
t->eos = 0;
|
|
||||||
|
|
||||||
/* ts A61101 */
|
|
||||||
t->sourcecount = 0;
|
|
||||||
t->writecount = 0;
|
|
||||||
t->written_sectors = 0;
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
t->open_ended = 0;
|
|
||||||
t->track_data_done = 0;
|
|
||||||
|
|
||||||
t->postgap = 0;
|
|
||||||
t->pregap1 = 0;
|
|
||||||
t->pregap2 = 0;
|
|
||||||
|
|
||||||
/* ts A61024 */
|
|
||||||
t->swap_source_bytes = 0;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_track_free(struct burn_track *t)
|
|
||||||
{
|
|
||||||
t->refcnt--;
|
|
||||||
if (t->refcnt == 0) {
|
|
||||||
/* dec refs on all elements */
|
|
||||||
if (t->source)
|
|
||||||
burn_source_free(t->source);
|
|
||||||
free(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_session_add_track(struct burn_session *s, struct burn_track *t,
|
|
||||||
unsigned int pos)
|
|
||||||
{
|
|
||||||
RESIZE(s, track, pos);
|
|
||||||
s->track[pos] = t;
|
|
||||||
t->refcnt++;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_session_remove_track(struct burn_session *s, struct burn_track *t)
|
|
||||||
{
|
|
||||||
struct burn_track **tmp;
|
|
||||||
int i, pos = -1;
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* a ssert(s->track != NULL); */
|
|
||||||
if (s->track == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
burn_track_free(t);
|
|
||||||
|
|
||||||
/* Find the position */
|
|
||||||
for (i = 0; i < s->tracks; i++) {
|
|
||||||
if (t == s->track[i]) {
|
|
||||||
pos = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos == -1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Is it the last track? */
|
|
||||||
if (pos != s->tracks - 1) {
|
|
||||||
memmove(&s->track[pos], &s->track[pos + 1],
|
|
||||||
sizeof(struct burn_track *) * (s->tracks - (pos + 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
s->tracks--;
|
|
||||||
tmp = realloc(s->track, sizeof(struct burn_track *) * s->tracks);
|
|
||||||
if (tmp)
|
|
||||||
s->track = tmp;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_structure_print_disc(struct burn_disc *d)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
burn_print(12, "This disc has %d sessions\n", d->sessions);
|
|
||||||
for (i = 0; i < d->sessions; i++) {
|
|
||||||
burn_structure_print_session(d->session[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void burn_structure_print_session(struct burn_session *s)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
burn_print(12, " Session has %d tracks\n", s->tracks);
|
|
||||||
for (i = 0; i < s->tracks; i++) {
|
|
||||||
burn_structure_print_track(s->track[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void burn_structure_print_track(struct burn_track *t)
|
|
||||||
{
|
|
||||||
burn_print(12, "(%p) track size %d sectors\n", t,
|
|
||||||
burn_track_get_sectors(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_track_define_data(struct burn_track *t, int offset, int tail,
|
|
||||||
int pad, int mode)
|
|
||||||
{
|
|
||||||
int type_to_form(int mode, unsigned char *ctladr, int *form);
|
|
||||||
int burn_sector_length(int tracktype);
|
|
||||||
unsigned char ctladr;
|
|
||||||
int form = -1; /* unchanged form will be considered an error too */
|
|
||||||
|
|
||||||
type_to_form(mode, &ctladr, &form);
|
|
||||||
if (form == -1 || burn_sector_length(mode) <= 0) {
|
|
||||||
char msg[160];
|
|
||||||
|
|
||||||
sprintf(msg, "Attempt to set track mode to unusable value %d",
|
|
||||||
mode);
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020115,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
msg, 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
t->offset = offset;
|
|
||||||
t->pad = pad;
|
|
||||||
t->mode = mode;
|
|
||||||
t->tail = tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61024 */
|
|
||||||
int burn_track_set_byte_swap(struct burn_track *t, int swap_source_bytes)
|
|
||||||
{
|
|
||||||
if(swap_source_bytes!=0 && swap_source_bytes!=1)
|
|
||||||
return 0;
|
|
||||||
t->swap_source_bytes = swap_source_bytes;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void burn_track_set_isrc(struct burn_track *t, char *country, char *owner,
|
|
||||||
unsigned char year, unsigned int serial)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 2; ++i) {
|
|
||||||
|
|
||||||
/* ts A61008 : This is always true */
|
|
||||||
/* a ssert((country[i] >= '0' || country[i] < '9') &&
|
|
||||||
(country[i] >= 'a' || country[i] < 'z') &&
|
|
||||||
(country[i] >= 'A' || country[i] < 'Z')); */
|
|
||||||
/* ts A61008 : now coordinated with sector.c: char_to_isrc() */
|
|
||||||
if (! ((country[i] >= '0' && country[i] <= '9') ||
|
|
||||||
(country[i] >= 'a' && country[i] <= 'z') ||
|
|
||||||
(country[i] >= 'A' && country[i] <= 'Z') ) )
|
|
||||||
goto is_not_allowed;
|
|
||||||
|
|
||||||
t->isrc.country[i] = country[i];
|
|
||||||
}
|
|
||||||
for (i = 0; i < 3; ++i) {
|
|
||||||
|
|
||||||
/* ts A61008 : This is always true */
|
|
||||||
/* a ssert((owner[i] >= '0' || owner[i] < '9') &&
|
|
||||||
(owner[i] >= 'a' || owner[i] < 'z') &&
|
|
||||||
(owner[i] >= 'A' || owner[i] < 'Z')); */
|
|
||||||
/* ts A61008 : now coordinated with sector.c: char_to_isrc() */
|
|
||||||
if (! ((owner[i] >= '0' && owner[i] <= '9') ||
|
|
||||||
(owner[i] >= 'a' && owner[i] <= 'z') ||
|
|
||||||
(owner[i] >= 'A' && owner[i] <= 'Z') ) )
|
|
||||||
goto is_not_allowed;
|
|
||||||
|
|
||||||
t->isrc.owner[i] = owner[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* a ssert(year <= 99); */
|
|
||||||
if (year > 99)
|
|
||||||
goto is_not_allowed;
|
|
||||||
|
|
||||||
t->isrc.year = year;
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* a ssert(serial <= 99999); */
|
|
||||||
if (serial > 99999)
|
|
||||||
goto is_not_allowed;
|
|
||||||
|
|
||||||
t->isrc.serial = serial;
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
t->isrc.has_isrc = 1;
|
|
||||||
return;
|
|
||||||
is_not_allowed:;
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020114,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Attempt to set ISRC with bad data", 0, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_track_clear_isrc(struct burn_track *t)
|
|
||||||
{
|
|
||||||
t->isrc.has_isrc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_track_get_sectors(struct burn_track *t)
|
|
||||||
{
|
|
||||||
/* ts A70125 : was int */
|
|
||||||
off_t size;
|
|
||||||
int sectors, seclen;
|
|
||||||
|
|
||||||
seclen = burn_sector_length(t->mode);
|
|
||||||
size = t->offset + t->source->get_size(t->source) + t->tail;
|
|
||||||
sectors = size / seclen;
|
|
||||||
if (size % seclen)
|
|
||||||
sectors++;
|
|
||||||
burn_print(1, "%d sectors of %d length\n", sectors, seclen);
|
|
||||||
return sectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70125 */
|
|
||||||
int burn_track_set_sectors(struct burn_track *t, int sectors)
|
|
||||||
{
|
|
||||||
off_t size, seclen;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
seclen = burn_sector_length(t->mode);
|
|
||||||
size = seclen * (off_t) sectors - (off_t) t->offset - (off_t) t->tail;
|
|
||||||
if (size < 0)
|
|
||||||
return 0;
|
|
||||||
ret = t->source->set_size(t->source, size);
|
|
||||||
t->open_ended = (t->source->get_size(t->source) <= 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70218 , API since A70328 */
|
|
||||||
int burn_track_set_size(struct burn_track *t, off_t size)
|
|
||||||
{
|
|
||||||
if (t->source == NULL)
|
|
||||||
return 0;
|
|
||||||
if (t->source->set_size == NULL)
|
|
||||||
return 0;
|
|
||||||
t->open_ended = (size <= 0);
|
|
||||||
return t->source->set_size(t->source, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70213 */
|
|
||||||
int burn_track_set_fillup(struct burn_track *t, int fill_up_media)
|
|
||||||
{
|
|
||||||
t->fill_up_media = fill_up_media;
|
|
||||||
if (fill_up_media)
|
|
||||||
t->open_ended = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70213 */
|
|
||||||
/**
|
|
||||||
@param flag bit0= force new size even if existing track size is larger
|
|
||||||
*/
|
|
||||||
int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag)
|
|
||||||
{
|
|
||||||
int max_sectors, ret = 2;
|
|
||||||
char msg[160];
|
|
||||||
|
|
||||||
if (t->fill_up_media <= 0)
|
|
||||||
return 2;
|
|
||||||
max_sectors = max_size / 2048;
|
|
||||||
if (burn_track_get_sectors(t) < max_sectors || (flag & 1)) {
|
|
||||||
sprintf(msg, "Setting total track size to %ds (payload %ds)\n",
|
|
||||||
max_sectors, (int) (t->source->get_size(t->source)/2048));
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
|
||||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
|
||||||
msg, 0, 0);
|
|
||||||
ret = burn_track_set_sectors(t, max_sectors);
|
|
||||||
t->open_ended = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
int burn_track_is_open_ended(struct burn_track *t)
|
|
||||||
{
|
|
||||||
return !!t->open_ended;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70218 : API */
|
|
||||||
int burn_track_set_default_size(struct burn_track *t, off_t size)
|
|
||||||
{
|
|
||||||
t->default_size = size;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70218 */
|
|
||||||
off_t burn_track_get_default_size(struct burn_track *t)
|
|
||||||
{
|
|
||||||
return t->default_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61101 : API function */
|
|
||||||
int burn_track_get_counters(struct burn_track *t,
|
|
||||||
off_t *read_bytes, off_t *written_bytes)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
fprintf(stderr, "libburn_experimental: sizeof(off_t)=%d\n",
|
|
||||||
sizeof(off_t));
|
|
||||||
*/
|
|
||||||
*read_bytes = t->sourcecount;
|
|
||||||
*written_bytes = t->writecount;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
int burn_track_is_data_done(struct burn_track *t)
|
|
||||||
{
|
|
||||||
return !!t->track_data_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_track_get_shortage(struct burn_track *t)
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
int seclen;
|
|
||||||
|
|
||||||
seclen = burn_sector_length(t->mode);
|
|
||||||
size = t->offset + t->source->get_size(t->source) + t->tail;
|
|
||||||
if (size % seclen)
|
|
||||||
return seclen - size % seclen;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_session_get_sectors(struct burn_session *s)
|
|
||||||
{
|
|
||||||
int sectors = 0, i;
|
|
||||||
|
|
||||||
for (i = 0; i < s->tracks; i++)
|
|
||||||
sectors += burn_track_get_sectors(s->track[i]);
|
|
||||||
return sectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_disc_get_sectors(struct burn_disc *d)
|
|
||||||
{
|
|
||||||
int sectors = 0, i;
|
|
||||||
|
|
||||||
for (i = 0; i < d->sessions; i++)
|
|
||||||
sectors += burn_session_get_sectors(d->session[i]);
|
|
||||||
return sectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_track_get_entry(struct burn_track *t, struct burn_toc_entry *entry)
|
|
||||||
{
|
|
||||||
if (t->entry == NULL)
|
|
||||||
memset(entry, 0, sizeof(struct burn_toc_entry));
|
|
||||||
else
|
|
||||||
memcpy(entry, t->entry, sizeof(struct burn_toc_entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_session_get_leadout_entry(struct burn_session *s,
|
|
||||||
struct burn_toc_entry *entry)
|
|
||||||
{
|
|
||||||
if (s->leadout_entry == NULL)
|
|
||||||
memset(entry, 0, sizeof(struct burn_toc_entry));
|
|
||||||
else
|
|
||||||
memcpy(entry, s->leadout_entry, sizeof(struct burn_toc_entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct burn_session **burn_disc_get_sessions(struct burn_disc *d, int *num)
|
|
||||||
{
|
|
||||||
*num = d->sessions;
|
|
||||||
return d->session;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct burn_track **burn_session_get_tracks(struct burn_session *s, int *num)
|
|
||||||
{
|
|
||||||
*num = s->tracks;
|
|
||||||
return s->track;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_track_get_mode(struct burn_track *track)
|
|
||||||
{
|
|
||||||
return track->mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int burn_session_get_hidefirst(struct burn_session *session)
|
|
||||||
{
|
|
||||||
return session->hidefirst;
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
#ifndef BURN__STRUCTURE_H
|
|
||||||
#define BURN__STRUCTURE_H
|
|
||||||
|
|
||||||
struct isrc
|
|
||||||
{
|
|
||||||
int has_isrc;
|
|
||||||
char country[2]; /* each must be 0-9, A-Z */
|
|
||||||
char owner[3]; /* each must be 0-9, A-Z */
|
|
||||||
unsigned char year; /* must be 0-99 */
|
|
||||||
unsigned int serial; /* must be 0-99999 */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct burn_track
|
|
||||||
{
|
|
||||||
int refcnt;
|
|
||||||
struct burn_toc_entry *entry;
|
|
||||||
unsigned char indices;
|
|
||||||
/* lba address of the index */
|
|
||||||
unsigned int index[99];
|
|
||||||
/** number of 0 bytes to write before data */
|
|
||||||
int offset;
|
|
||||||
/** how much offset has been used */
|
|
||||||
int offsetcount;
|
|
||||||
/** Number of zeros to write after data */
|
|
||||||
int tail;
|
|
||||||
/** how much tail has been used */
|
|
||||||
int tailcount;
|
|
||||||
/** 1 means Pad with zeros, 0 means start reading the next track */
|
|
||||||
int pad;
|
|
||||||
|
|
||||||
/* ts A70213 : wether to expand this track to full available media */
|
|
||||||
int fill_up_media;
|
|
||||||
|
|
||||||
/* ts A70218 : a track size to use if it is mandarory to have some */
|
|
||||||
off_t default_size;
|
|
||||||
|
|
||||||
/** Data source */
|
|
||||||
struct burn_source *source;
|
|
||||||
/** End of Source flag */
|
|
||||||
int eos;
|
|
||||||
|
|
||||||
/* ts A61101 */
|
|
||||||
off_t sourcecount;
|
|
||||||
off_t writecount;
|
|
||||||
off_t written_sectors;
|
|
||||||
|
|
||||||
/* ts A61031 */
|
|
||||||
/** Source is of undefined length */
|
|
||||||
int open_ended;
|
|
||||||
/** End of open ended track flag : offset+payload+tail are delivered */
|
|
||||||
int track_data_done;
|
|
||||||
|
|
||||||
/** The audio/data mode for the entry. Derived from control and
|
|
||||||
possibly from reading the track's first sector. */
|
|
||||||
int mode;
|
|
||||||
/** The track contains interval one of a pregap */
|
|
||||||
int pregap1;
|
|
||||||
/** The track contains interval two of a pregap */
|
|
||||||
int pregap2;
|
|
||||||
/** The track contains a postgap */
|
|
||||||
int postgap;
|
|
||||||
struct isrc isrc;
|
|
||||||
|
|
||||||
/* ts A61024 */
|
|
||||||
/** Byte swapping on source data stream : 0=none , 1=pairwise */
|
|
||||||
int swap_source_bytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct burn_session
|
|
||||||
{
|
|
||||||
unsigned char firsttrack;
|
|
||||||
unsigned char lasttrack;
|
|
||||||
int hidefirst;
|
|
||||||
unsigned char start_m;
|
|
||||||
unsigned char start_s;
|
|
||||||
unsigned char start_f;
|
|
||||||
struct burn_toc_entry *leadout_entry;
|
|
||||||
|
|
||||||
int tracks;
|
|
||||||
struct burn_track **track;
|
|
||||||
int refcnt;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct burn_disc
|
|
||||||
{
|
|
||||||
int sessions;
|
|
||||||
struct burn_session **session;
|
|
||||||
int refcnt;
|
|
||||||
};
|
|
||||||
|
|
||||||
int burn_track_get_shortage(struct burn_track *t);
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A61031 : might go to libburn.h */
|
|
||||||
int burn_track_is_open_ended(struct burn_track *t);
|
|
||||||
int burn_track_is_data_done(struct burn_track *t);
|
|
||||||
|
|
||||||
/* ts A70125 : sets overall sectors of a track: offset+payload+padding */
|
|
||||||
int burn_track_set_sectors(struct burn_track *t, int sectors);
|
|
||||||
|
|
||||||
/* ts A70218 : sets the payload size alone */
|
|
||||||
int burn_track_set_size(struct burn_track *t, off_t size);
|
|
||||||
|
|
||||||
/* ts A70213 */
|
|
||||||
int burn_track_set_fillup(struct burn_track *t, int fill_up_media);
|
|
||||||
int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag);
|
|
||||||
|
|
||||||
/* ts A70218 */
|
|
||||||
off_t burn_track_get_default_size(struct burn_track *t);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* BURN__STRUCTURE_H */
|
|
141
libburn/toc.c
141
libburn/toc.c
@ -1,141 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* #include <a ssert.h> */
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "toc.h"
|
|
||||||
#include "transport.h"
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "sector.h"
|
|
||||||
#include "options.h"
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void write_clonecd2(volatile struct toc *toc, int f);
|
|
||||||
|
|
||||||
static void write_clonecd2(volatile struct toc *toc, int f)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* header */
|
|
||||||
dprintf(f, "[CloneCD]\r\n");
|
|
||||||
dprintf(f, "Version=2\r\n");
|
|
||||||
dprintf(f, "\r\n");
|
|
||||||
|
|
||||||
/* disc data */
|
|
||||||
dprintf(f, "[Disc]\r\n");
|
|
||||||
|
|
||||||
dprintf(f, "TocEntries=%d\r\n", toc->toc_entries);
|
|
||||||
dprintf(f, "Sessions=%d\r\n", toc->sessions);
|
|
||||||
dprintf(f, "DataTracksScrambled=%d\r\n", toc->datatracksscrambled);
|
|
||||||
dprintf(f, "CDTextLength=%d\r\n", toc->cdtextlength);
|
|
||||||
dprintf(f, "\r\n");
|
|
||||||
|
|
||||||
/* session data */
|
|
||||||
for (i = 0; i < toc->sessions; ++i) {
|
|
||||||
dprintf(f, "[Session %d]\r\n", i + 1);
|
|
||||||
|
|
||||||
{
|
|
||||||
int m;
|
|
||||||
|
|
||||||
switch (toc->session[i].track[0]->mode) {
|
|
||||||
case BURN_MODE_RAW_DATA:
|
|
||||||
case BURN_MODE_AUDIO:
|
|
||||||
m = 0;
|
|
||||||
break;
|
|
||||||
case BURN_MODE0:
|
|
||||||
m = 1;
|
|
||||||
break;
|
|
||||||
case BURN_MODE1:
|
|
||||||
case BURN_MODE2_FORMLESS:
|
|
||||||
case BURN_MODE2_FORM1:
|
|
||||||
case BURN_MODE2_FORM2:
|
|
||||||
case BURN_MODE_UNINITIALIZED:
|
|
||||||
|
|
||||||
/* ts A61008 : do this softly without Assert */
|
|
||||||
|
|
||||||
a ssert(0); /* unhandled! find out ccd's
|
|
||||||
value for these modes! */
|
|
||||||
}
|
|
||||||
dprintf(f, "PreGapMode=%d\r\n", m);
|
|
||||||
}
|
|
||||||
dprintf(f, "\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < toc->toc_entries; ++i) {
|
|
||||||
dprintf(f, "[Entry %d]\r\n", i);
|
|
||||||
|
|
||||||
dprintf(f, "Session=%d\r\n", toc->toc_entry[i].session);
|
|
||||||
dprintf(f, "Point=0x%02x\r\n", toc->toc_entry[i].point);
|
|
||||||
dprintf(f, "ADR=0x%02x\r\n", toc->toc_entry[i].adr);
|
|
||||||
dprintf(f, "Control=0x%02x\r\n", toc->toc_entry[i].control);
|
|
||||||
dprintf(f, "TrackNo=%d\r\n", toc->toc_entry[i].tno);
|
|
||||||
dprintf(f, "AMin=%d\r\n", toc->toc_entry[i].min);
|
|
||||||
dprintf(f, "ASec=%d\r\n", toc->toc_entry[i].sec);
|
|
||||||
dprintf(f, "AFrame=%d\r\n", toc->toc_entry[i].frame);
|
|
||||||
dprintf(f, "ALBA=%d\r\n",
|
|
||||||
burn_msf_to_lba(toc->toc_entry[i].min,
|
|
||||||
toc->toc_entry[i].sec,
|
|
||||||
toc->toc_entry[i].frame));
|
|
||||||
dprintf(f, "Zero=%d\r\n", toc->toc_entry[i].zero);
|
|
||||||
dprintf(f, "PMin=%d\r\n", toc->toc_entry[i].pmin);
|
|
||||||
dprintf(f, "PSec=%d\r\n", toc->toc_entry[i].psec);
|
|
||||||
dprintf(f, "PFrame=%d\r\n", toc->toc_entry[i].pframe);
|
|
||||||
dprintf(f, "PLBA=%d\r\n",
|
|
||||||
burn_msf_to_lba(toc->toc_entry[i].pmin,
|
|
||||||
toc->toc_entry[i].psec,
|
|
||||||
toc->toc_entry[i].pframe));
|
|
||||||
dprintf(f, "\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void toc_find_modes(struct burn_drive *d)
|
|
||||||
{
|
|
||||||
struct burn_read_opts o;
|
|
||||||
int lba;
|
|
||||||
int i, j;
|
|
||||||
struct buffer mem;
|
|
||||||
struct burn_toc_entry *e;
|
|
||||||
|
|
||||||
/* ts A61008 : to be prevented on the higher levels */
|
|
||||||
/* a ssert(d->busy); */
|
|
||||||
|
|
||||||
mem.bytes = 0;
|
|
||||||
mem.sectors = 1;
|
|
||||||
o.raw = 1;
|
|
||||||
o.c2errors = 0;
|
|
||||||
o.subcodes_audio = 1;
|
|
||||||
o.subcodes_data = 1;
|
|
||||||
o.hardware_error_recovery = 1;
|
|
||||||
o.report_recovered_errors = 0;
|
|
||||||
o.transfer_damaged_blocks = 1;
|
|
||||||
o.hardware_error_retries = 1;
|
|
||||||
|
|
||||||
for (i = 0; i < d->disc->sessions; i++)
|
|
||||||
for (j = 0; j < d->disc->session[i]->tracks; j++) {
|
|
||||||
struct burn_track *t = d->disc->session[i]->track[j];
|
|
||||||
|
|
||||||
e = t->entry;
|
|
||||||
if (!e)
|
|
||||||
lba = 0;
|
|
||||||
else
|
|
||||||
lba = burn_msf_to_lba(e->pmin, e->psec,
|
|
||||||
e->pframe);
|
|
||||||
/* XXX | in the subcodes if appropriate! */
|
|
||||||
if (e && !(e->control & 4)) {
|
|
||||||
t->mode = BURN_AUDIO;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
t->mode = BURN_MODE1;
|
|
||||||
/* ts A70519 : this does not work with Linux 2.4 USB because one cannot
|
|
||||||
predict the exact dxfer_size without knowing the sector type.
|
|
||||||
mem.sectors = 1;
|
|
||||||
d->read_sectors(d, lba, mem.sectors, &o, &mem);
|
|
||||||
t->mode = sector_identify(mem.data);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __TOC_H
|
|
||||||
#define __TOC_H
|
|
||||||
|
|
||||||
struct command;
|
|
||||||
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "structure.h"
|
|
||||||
|
|
||||||
/* return if a given entry refers to a track position */
|
|
||||||
#define TOC_ENTRY_IS_TRACK(drive, entrynum) \
|
|
||||||
((drive)->toc_entry[entrynum].point < 100)
|
|
||||||
|
|
||||||
/* return if a given entry is in audio or data format */
|
|
||||||
#define TOC_ENTRY_IS_AUDIO(drive, entrynum) \
|
|
||||||
(~(drive)->toc_entry[entrynum].control & 4)
|
|
||||||
|
|
||||||
/* return the point value for a given entry number */
|
|
||||||
#define TOC_POINT(drive, entrynum) ((drive)->toc_entry[entrynum].point)
|
|
||||||
|
|
||||||
/* return the track struct for a given entry number */
|
|
||||||
#define TOC_TRACK(drive, entrynum) \
|
|
||||||
((drive)->track[TOC_POINT(drive, entrynum) - 1])
|
|
||||||
|
|
||||||
/* return the lba of a toc entry */
|
|
||||||
#define TOC_ENTRY_PLBA(drive, entrynum) \
|
|
||||||
burn_msf_to_lba((drive)->toc_entry[(entrynum)].pmin, \
|
|
||||||
(drive)->toc_entry[(entrynum)].psec, \
|
|
||||||
(drive)->toc_entry[(entrynum)].pframe)
|
|
||||||
|
|
||||||
/* flags for the q subchannel control field */
|
|
||||||
#define TOC_CONTROL_AUDIO (0)
|
|
||||||
#define TOC_CONTROL_DATA (1 << 2)
|
|
||||||
#define TOC_CONTROL_AUDIO_TWO_CHANNELS (0)
|
|
||||||
#define TOC_CONTROL_AUDIO_FOUR_CHANNELS (1 << 3)
|
|
||||||
#define TOC_CONTROL_AUDIO_PRE_EMPHASIS (1 << 0)
|
|
||||||
#define TOC_CONTROL_DATA_RECORDED_UNINTERRUPTED (0)
|
|
||||||
#define TOC_CONTROL_DATA_RECORDED_INCREMENT (1 << 0)
|
|
||||||
#define TOC_CONTROL_COPY_PROHIBITED (0)
|
|
||||||
#define TOC_CONTROL_COPY_PERMITTED (1 << 1)
|
|
||||||
|
|
||||||
/** read a sector from each track on disc to determine modes
|
|
||||||
@param d The drive.
|
|
||||||
*/
|
|
||||||
void toc_find_modes(struct burn_drive *d);
|
|
||||||
|
|
||||||
#endif /*__TOC_H*/
|
|
@ -1,361 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef __TRANSPORT
|
|
||||||
#define __TRANSPORT
|
|
||||||
|
|
||||||
#include "libburn.h"
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
/* sg data structures */
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
|
|
||||||
/* see os.h for name of particular os-*.h where this is defined */
|
|
||||||
#define BUFFER_SIZE BURN_OS_TRANSPORT_BUFFER_SIZE
|
|
||||||
|
|
||||||
|
|
||||||
enum transfer_direction
|
|
||||||
{ TO_DRIVE, FROM_DRIVE, NO_TRANSFER };
|
|
||||||
|
|
||||||
/* end of sg data structures */
|
|
||||||
|
|
||||||
/* generic 'drive' data structures */
|
|
||||||
|
|
||||||
struct cue_sheet
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
unsigned char *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct params
|
|
||||||
{
|
|
||||||
int speed;
|
|
||||||
int retries;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct buffer
|
|
||||||
{
|
|
||||||
/* ts A61219:
|
|
||||||
Added 4096 bytes reserve against possible buffer overflows.
|
|
||||||
(Changed in sector.c buffer flush test from >= to > BUFFER_SIZE .
|
|
||||||
This can at most cause a 1 sector overlap. Sometimes an offset
|
|
||||||
of 16 byte is applied to the output data (in some RAW mode). ) */
|
|
||||||
unsigned char data[BUFFER_SIZE + 4096];
|
|
||||||
int sectors;
|
|
||||||
int bytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct command
|
|
||||||
{
|
|
||||||
unsigned char opcode[16];
|
|
||||||
int oplen;
|
|
||||||
int dir;
|
|
||||||
int dxfer_len;
|
|
||||||
unsigned char sense[128];
|
|
||||||
int error;
|
|
||||||
int retry;
|
|
||||||
struct buffer *page;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct burn_scsi_inquiry_data
|
|
||||||
{
|
|
||||||
char vendor[9];
|
|
||||||
char product[17];
|
|
||||||
char revision[5];
|
|
||||||
int valid;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct scsi_mode_data
|
|
||||||
{
|
|
||||||
int buffer_size;
|
|
||||||
int dvdram_read;
|
|
||||||
int dvdram_write;
|
|
||||||
int dvdr_read;
|
|
||||||
int dvdr_write;
|
|
||||||
int dvdrom_read;
|
|
||||||
int cdrw_read;
|
|
||||||
int cdrw_write;
|
|
||||||
int cdr_read;
|
|
||||||
int cdr_write;
|
|
||||||
int simulate;
|
|
||||||
int max_read_speed;
|
|
||||||
int max_write_speed;
|
|
||||||
|
|
||||||
/* ts A61021 */
|
|
||||||
int min_write_speed;
|
|
||||||
|
|
||||||
/* ts A61225 : Results from ACh GET PERFORMANCE, Type 03h
|
|
||||||
Speed values go into *_*_speed */
|
|
||||||
int min_end_lba;
|
|
||||||
int max_end_lba;
|
|
||||||
struct burn_speed_descriptor *speed_descriptors;
|
|
||||||
|
|
||||||
int cur_read_speed;
|
|
||||||
int cur_write_speed;
|
|
||||||
int retry_page_length;
|
|
||||||
int retry_page_valid;
|
|
||||||
int write_page_length;
|
|
||||||
int write_page_valid;
|
|
||||||
int c2_pointers;
|
|
||||||
int valid;
|
|
||||||
int underrun_proof;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70112 : represents a single Formattable Capacity Descriptor as of
|
|
||||||
mmc5r03c.pdf 6.24.3.3 . There can at most be 32 of them. */
|
|
||||||
struct burn_format_descr {
|
|
||||||
/* format type: e.g 0x00 is "Full", 0x15 is "Quick" */
|
|
||||||
int type;
|
|
||||||
|
|
||||||
/* the size in bytes derived from Number of Blocks */
|
|
||||||
off_t size;
|
|
||||||
|
|
||||||
/* the Type Dependent Parameter (usually the write alignment size) */
|
|
||||||
unsigned int tdp;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** Gets initialized in enumerate_common() and burn_drive_register() */
|
|
||||||
struct burn_drive
|
|
||||||
{
|
|
||||||
/* ts A70902:
|
|
||||||
0=null-emulation
|
|
||||||
1=MMC drive ,
|
|
||||||
2=stdio random read-write
|
|
||||||
3=stdio sequential write-only
|
|
||||||
*/
|
|
||||||
int drive_role;
|
|
||||||
|
|
||||||
int bus_no;
|
|
||||||
int host;
|
|
||||||
int id;
|
|
||||||
int channel;
|
|
||||||
int lun;
|
|
||||||
char *devname;
|
|
||||||
|
|
||||||
/* ts A70302: mmc5r03c.pdf 5.3.2 Physical Interface Standard */
|
|
||||||
int phys_if_std; /* 1=SCSI, 2=ATAPI, 3,4,6=FireWire, 7=SATA, 8=USB */
|
|
||||||
char phys_if_name[80]; /* MMC-5 5.3.2 table 91 , e.g. "SCSI Family" */
|
|
||||||
|
|
||||||
/* see os.h for name of particular os-*.h where this is defined */
|
|
||||||
BURN_OS_TRANSPORT_DRIVE_ELEMENTS
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60904 : ticket 62, contribution by elmom */
|
|
||||||
/**
|
|
||||||
Tells the index in scanned burn_drive_info array.
|
|
||||||
-1 if fallen victim to burn_drive_info_forget()
|
|
||||||
*/
|
|
||||||
int global_index;
|
|
||||||
|
|
||||||
pthread_mutex_t access_lock;
|
|
||||||
|
|
||||||
enum burn_disc_status status;
|
|
||||||
int erasable;
|
|
||||||
|
|
||||||
/* ts A61201 from 46h GET CONFIGURATION */
|
|
||||||
int current_profile;
|
|
||||||
char current_profile_text[80];
|
|
||||||
int current_is_cd_profile;
|
|
||||||
int current_is_supported_profile;
|
|
||||||
|
|
||||||
/* ts A70128 : MMC-to-MMC feature info from 46h for DVD-RW.
|
|
||||||
Quite internal. Regard as opaque :)
|
|
||||||
*/
|
|
||||||
/* 1 = incremental recording available, 0 = not available */
|
|
||||||
int current_has_feat21h;
|
|
||||||
|
|
||||||
/* Link Size item number 0 from feature 0021h descriptor */
|
|
||||||
int current_feat21h_link_size;
|
|
||||||
|
|
||||||
/* Flags from feature 002Fh feature descriptor mmc5r03c.pdf 5.3.25 :
|
|
||||||
bit1= DVD-RW supported
|
|
||||||
bit2= Test Write available
|
|
||||||
bit3= DVD-R DL supported
|
|
||||||
bit6= Buffer Under-run Free recording available (page 05h BUFE)
|
|
||||||
Value -1 indicates that no 002Fh was current in the features list.
|
|
||||||
*/
|
|
||||||
int current_feat2fh_byte4;
|
|
||||||
|
|
||||||
/* ts A70114 : whether a DVD-RW media holds an incomplete session
|
|
||||||
(which could need closing after write) */
|
|
||||||
int needs_close_session;
|
|
||||||
/* ts A71003 : whether a random write operation was done and no
|
|
||||||
synchronize chache has happened yet */
|
|
||||||
int needs_sync_cache;
|
|
||||||
|
|
||||||
/* ts A80412 : whether to use WRITE12 with Streaming bit set
|
|
||||||
rather than WRITE10. Speeds up DVD-RAM. Might help
|
|
||||||
with BD-RE */
|
|
||||||
int do_stream_recording;
|
|
||||||
|
|
||||||
/* ts A61218 from 51h READ DISC INFORMATION */
|
|
||||||
int bg_format_status; /* 0=needs format start, 1=needs format restart*/
|
|
||||||
|
|
||||||
/* ts A70108 from 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24 */
|
|
||||||
int format_descr_type; /* 1=unformatted, 2=formatted, 3=unclear */
|
|
||||||
off_t format_curr_max_size; /* meaning depends on format_descr_type */
|
|
||||||
unsigned int format_curr_blsas; /* dito */
|
|
||||||
int best_format_type;
|
|
||||||
off_t best_format_size;
|
|
||||||
|
|
||||||
/* The complete list of format descriptors as read with 23h */
|
|
||||||
int num_format_descr;
|
|
||||||
struct burn_format_descr format_descriptors[32];
|
|
||||||
|
|
||||||
|
|
||||||
volatile int released;
|
|
||||||
|
|
||||||
/* ts A61106 */
|
|
||||||
int silent_on_scsi_error;
|
|
||||||
|
|
||||||
int stdio_fd;
|
|
||||||
|
|
||||||
int nwa; /* next writeable address */
|
|
||||||
int alba; /* absolute lba */
|
|
||||||
int rlba; /* relative lba in section */
|
|
||||||
int start_lba;
|
|
||||||
int end_lba;
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A70131 : from 51h READ DISC INFORMATION Number of Sessions (-1)*/
|
|
||||||
int complete_sessions;
|
|
||||||
/* ts A70129 :
|
|
||||||
from 51h READ DISC INFORMATION Last Track Number in Last Session */
|
|
||||||
int last_track_no;
|
|
||||||
/* ts A70212 : from various sources : free space on media (in bytes)
|
|
||||||
With CD this might change after particular write
|
|
||||||
parameters have been set and nwa has been inquired.
|
|
||||||
(e.g. by d->send_write_parameters() ; d->get_nwa()).
|
|
||||||
*/
|
|
||||||
off_t media_capacity_remaining;
|
|
||||||
/* ts A70215 : if > 0 : first lba on media that is too high for write*/
|
|
||||||
int media_lba_limit;
|
|
||||||
|
|
||||||
|
|
||||||
int toc_temp;
|
|
||||||
struct burn_disc *disc; /* disc structure */
|
|
||||||
int block_types[4];
|
|
||||||
struct buffer *buffer;
|
|
||||||
struct burn_progress progress;
|
|
||||||
|
|
||||||
/* ts A70711 : keeping an eye on the drive buffer */
|
|
||||||
off_t pessimistic_buffer_free;
|
|
||||||
int pbf_altered;
|
|
||||||
int wait_for_buffer_free;
|
|
||||||
int nominal_write_speed;
|
|
||||||
unsigned int wfb_min_usec;
|
|
||||||
unsigned int wfb_max_usec;
|
|
||||||
unsigned int wfb_timeout_sec;
|
|
||||||
unsigned int wfb_min_percent;
|
|
||||||
unsigned int wfb_max_percent;
|
|
||||||
unsigned int pessimistic_writes;
|
|
||||||
unsigned int waited_writes;
|
|
||||||
unsigned int waited_tries;
|
|
||||||
unsigned int waited_usec;
|
|
||||||
|
|
||||||
volatile int cancel;
|
|
||||||
volatile enum burn_drive_status busy;
|
|
||||||
|
|
||||||
/* ts A70929 */
|
|
||||||
pid_t thread_pid;
|
|
||||||
int thread_pid_valid;
|
|
||||||
|
|
||||||
|
|
||||||
/* transport functions */
|
|
||||||
int (*grab) (struct burn_drive *);
|
|
||||||
int (*release) (struct burn_drive *);
|
|
||||||
|
|
||||||
/* ts A61021 */
|
|
||||||
int (*drive_is_open) (struct burn_drive *);
|
|
||||||
|
|
||||||
int (*issue_command) (struct burn_drive *, struct command *);
|
|
||||||
|
|
||||||
/* lower level functions */
|
|
||||||
void (*erase) (struct burn_drive *, int);
|
|
||||||
void (*getcaps) (struct burn_drive *);
|
|
||||||
|
|
||||||
/* ts A61021 */
|
|
||||||
void (*read_atip) (struct burn_drive *);
|
|
||||||
|
|
||||||
int (*write) (struct burn_drive *, int, struct buffer *);
|
|
||||||
void (*read_toc) (struct burn_drive *);
|
|
||||||
void (*lock) (struct burn_drive *);
|
|
||||||
void (*unlock) (struct burn_drive *);
|
|
||||||
void (*eject) (struct burn_drive *);
|
|
||||||
void (*load) (struct burn_drive *);
|
|
||||||
int (*start_unit) (struct burn_drive *);
|
|
||||||
void (*read_disc_info) (struct burn_drive *);
|
|
||||||
void (*read_sectors) (struct burn_drive *,
|
|
||||||
int start,
|
|
||||||
int len,
|
|
||||||
const struct burn_read_opts *, struct buffer *);
|
|
||||||
void (*perform_opc) (struct burn_drive *);
|
|
||||||
void (*set_speed) (struct burn_drive *, int, int);
|
|
||||||
void (*send_parameters) (struct burn_drive *,
|
|
||||||
const struct burn_read_opts *);
|
|
||||||
void (*send_write_parameters) (struct burn_drive *,
|
|
||||||
const struct burn_write_opts *);
|
|
||||||
void (*send_cue_sheet) (struct burn_drive *, struct cue_sheet *);
|
|
||||||
|
|
||||||
/* ts A70205 : Announce size of a DVD-R[W] DAO session. */
|
|
||||||
int (*reserve_track) (struct burn_drive *d, off_t size);
|
|
||||||
|
|
||||||
void (*sync_cache) (struct burn_drive *);
|
|
||||||
int (*get_erase_progress) (struct burn_drive *);
|
|
||||||
int (*get_nwa) (struct burn_drive *, int trackno, int *lba, int *nwa);
|
|
||||||
|
|
||||||
/* ts A70131 : obtain (possibly fake) TOC number and start lba of
|
|
||||||
first track in last complete session */
|
|
||||||
int (*read_multi_session_c1)(struct burn_drive *d,
|
|
||||||
int *trackno, int *start);
|
|
||||||
|
|
||||||
/* ts A61009 : removed d in favor of o->drive */
|
|
||||||
/* void (*close_disc) (struct burn_drive * d,
|
|
||||||
struct burn_write_opts * o);
|
|
||||||
void (*close_session) (struct burn_drive * d,
|
|
||||||
struct burn_write_opts * o);
|
|
||||||
*/
|
|
||||||
void (*close_disc) (struct burn_write_opts * o);
|
|
||||||
void (*close_session) ( struct burn_write_opts * o);
|
|
||||||
|
|
||||||
/* ts A61029 */
|
|
||||||
void (*close_track_session) ( struct burn_drive *d,
|
|
||||||
int session, int track);
|
|
||||||
|
|
||||||
int (*test_unit_ready) (struct burn_drive * d);
|
|
||||||
void (*probe_write_modes) (struct burn_drive * d);
|
|
||||||
struct params params;
|
|
||||||
struct burn_scsi_inquiry_data *idata;
|
|
||||||
struct scsi_mode_data *mdata;
|
|
||||||
int toc_entries;
|
|
||||||
struct burn_toc_entry *toc_entry;
|
|
||||||
|
|
||||||
/* ts A61023 : get size and free space of drive buffer */
|
|
||||||
int (*read_buffer_capacity) (struct burn_drive *d);
|
|
||||||
|
|
||||||
/* ts A61220 : format media (e.g. DVD+RW) */
|
|
||||||
int (*format_unit) (struct burn_drive *d, off_t size, int flag);
|
|
||||||
|
|
||||||
/* ts A70108 */
|
|
||||||
/* mmc5r03c.pdf 6.24 : get list of available formats */
|
|
||||||
int (*read_format_capacities) (struct burn_drive *d, int top_wanted);
|
|
||||||
|
|
||||||
/* ts A70812 */
|
|
||||||
/* mmc5r03c.pdf 6.15 : read data sectors (start and amount in LBA) */
|
|
||||||
int (*read_10) (struct burn_drive *d, int start, int amount,
|
|
||||||
struct buffer *buf);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* end of generic 'drive' data structures */
|
|
||||||
|
|
||||||
/* ts A80422 : centralizing this setting for debugging purposes
|
|
||||||
*/
|
|
||||||
int burn_drive_set_media_capacity_remaining(struct burn_drive *d, off_t value);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __TRANSPORT */
|
|
@ -1,60 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* #include <a ssert.h> */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "../version.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "libburn.h"
|
|
||||||
|
|
||||||
char *burn_strdup(char *s)
|
|
||||||
{
|
|
||||||
char *ret;
|
|
||||||
int l;
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* a ssert(s); */
|
|
||||||
if (s == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
l = strlen(s) + 1;
|
|
||||||
ret = malloc(l);
|
|
||||||
memcpy(ret, s, l);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *burn_strndup(char *s, int n)
|
|
||||||
{
|
|
||||||
char *ret;
|
|
||||||
int l;
|
|
||||||
|
|
||||||
/* ts A61008 */
|
|
||||||
/* a ssert(s); */
|
|
||||||
/* a ssert(n > 0); */
|
|
||||||
if (s == NULL || n <= 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
l = strlen(s);
|
|
||||||
ret = malloc(l < n ? l : n);
|
|
||||||
|
|
||||||
memcpy(ret, s, l < n - 1 ? l : n - 1);
|
|
||||||
ret[n - 1] = '\0';
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void burn_version(int *major, int *minor, int *micro)
|
|
||||||
{
|
|
||||||
/* ts A80408 : switched from configure.ac versioning to libburn.h versioning */
|
|
||||||
#ifdef burn_header_version_major
|
|
||||||
*major = burn_header_version_major;
|
|
||||||
*minor = burn_header_version_minor;
|
|
||||||
*micro = burn_header_version_micro;
|
|
||||||
#else
|
|
||||||
*major = BURN_MAJOR_VERSION;
|
|
||||||
*minor = BURN_MINOR_VERSION;
|
|
||||||
*micro = BURN_MICRO_VERSION;
|
|
||||||
#endif
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#ifndef __UTIL
|
|
||||||
#define __UTIL
|
|
||||||
|
|
||||||
char *burn_strdup(char *s);
|
|
||||||
|
|
||||||
char *burn_strndup(char *s, int n);
|
|
||||||
|
|
||||||
#endif
|
|
2334
libburn/write.c
2334
libburn/write.c
File diff suppressed because it is too large
Load Diff
@ -1,48 +0,0 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
||||||
|
|
||||||
#ifndef BURN__WRITE_H
|
|
||||||
#define BURN__WRITE_H
|
|
||||||
|
|
||||||
struct cue_sheet;
|
|
||||||
struct burn_session;
|
|
||||||
struct burn_write_opts;
|
|
||||||
struct burn_disc;
|
|
||||||
|
|
||||||
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
|
||||||
struct burn_session *session,
|
|
||||||
int nwa);
|
|
||||||
int burn_sector_length(int trackmode);
|
|
||||||
int burn_subcode_length(int trackmode);
|
|
||||||
|
|
||||||
/* ts A61009 */
|
|
||||||
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc,
|
|
||||||
int flag);
|
|
||||||
|
|
||||||
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc);
|
|
||||||
int burn_write_leadin(struct burn_write_opts *o,
|
|
||||||
struct burn_session *s, int first);
|
|
||||||
int burn_write_leadout(struct burn_write_opts *o,
|
|
||||||
int first, unsigned char control, int mode);
|
|
||||||
int burn_write_session(struct burn_write_opts *o, struct burn_session *s);
|
|
||||||
int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
|
|
||||||
int tnum);
|
|
||||||
int burn_write_flush(struct burn_write_opts *o, struct burn_track *track);
|
|
||||||
|
|
||||||
/* ts A61030 : necessary for TAO */
|
|
||||||
int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
|
|
||||||
int tnum);
|
|
||||||
int burn_write_close_session(struct burn_write_opts *o,struct burn_session *s);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* mmc5r03c.pdf 6.3.3.3.3: DVD-R DL: Close Function 010b: Close Session
|
|
||||||
"When the recording mode is Incremental Recording,
|
|
||||||
the disc is single session."
|
|
||||||
Enable this macro to get away from growisofs which uses Close Session
|
|
||||||
but also states "// DVD-R DL Seq has no notion of multi-session".
|
|
||||||
|
|
||||||
#define Libburn_dvd_r_dl_multi_no_close_sessioN 1
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endif /* BURN__WRITE_H */
|
|
1503
libcevap/cgen.c
1503
libcevap/cgen.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user