Compare commits

...

101 Commits

Author SHA1 Message Date
9ab5290059 Testing tarball versioning 2006-12-19 05:04:01 +00:00
ec1aa0c49a Backported manpage to libburn-0.2.6.1 -> libburn-0.2.6.2 2006-12-16 09:39:29 +00:00
80639a7749 Started preparing libburn 0.6.2 release 2006-12-15 22:05:51 +00:00
8c82e3c437 Tagged libburn point release 2006-11-24 01:23:21 +00:00
de02cc26f9 Version leap to 0.2.6 2006-11-23 10:26:18 +00:00
35a1a1f7d7 Removed obsolete test programs 2006-11-23 09:10:03 +00:00
54d3702513 Last cdrskin-0.2.5 cycle 2006-11-23 07:20:53 +00:00
c3f9764e0a Made doc system buildable 2006-11-22 22:40:32 +00:00
ab4096e720 Switched to 0.2.6 cycle before release 2006-11-22 22:28:14 +00:00
26fa325ee4 Coordinated scsi_notify_error() and scsi_error() 2006-11-22 12:25:16 +00:00
314027631a Updated in respect to multi-session 2006-11-20 14:39:25 +00:00
6e09b56c29 Implemented new option fifo_start_at= 2006-11-20 13:30:01 +00:00
08f541a7a8 Next cdrskin-0.2.5 cycle 2006-11-20 13:25:27 +00:00
26412b4793 Removed a redundant d->start_unit() of revision 419 2006-11-20 09:07:47 +00:00
9ea689d7e4 Silenced compiler warnings 2006-11-20 09:06:30 +00:00
f3b994f845 Fixed missing brackets from revison 421 2006-11-19 16:40:53 +00:00
46906c7f65 Avoided self contradiction with "Min drive buffer fill" 2006-11-19 16:32:09 +00:00
4daed7c4a9 Implemented libburn builtin fine granulated drive buffer min-fill recording 2006-11-19 11:47:34 +00:00
ebb94ee212 Test wether SCSI 1Bh START UNIT would be helpful with ticket 90 2006-11-18 19:49:18 +00:00
18a592ad28 Shifted a comma 2006-11-17 21:30:25 +00:00
ba48efbc52 Shifted a comma 2006-11-17 21:29:19 +00:00
0513a4eb2f Obsoleted old test program 2006-11-17 20:15:14 +00:00
254852ee36 Enabled multi-session with libburner 2006-11-17 19:51:51 +00:00
ef6d76c22d Created info retrieval companion for libburner 2006-11-17 19:38:28 +00:00
66c3ead5d6 Updated help text of libburner 2006-11-16 16:53:42 +00:00
908a6b336b Obsoleted --stdin_size by automatic TAO. Cared for non-plain track files 2006-11-16 16:38:23 +00:00
373e401671 Polished porting hints 2006-11-16 14:21:27 +00:00
06d008d6c6 Polished porting hints and self-compliance to newly established specs 2006-11-16 13:40:21 +00:00
11c9444b6c Made consolidaed operating system adapters for ease of porting 2006-11-16 11:18:44 +00:00
ff284b3f51 Made consolidaed operating system adapters for ease of porting 2006-11-16 11:17:55 +00:00
628e935fe5 Narrowed system specific part of enumerate_common() 2006-11-15 20:49:27 +00:00
13641fcbae Made portability clarifications 2006-11-15 17:10:12 +00:00
595b877a24 Adjusted some texts to new multi-session situation 2006-11-15 09:14:17 +00:00
17d1d2e8a6 Enhanced optional SCSI command logging 2006-11-15 09:11:57 +00:00
c1b3d3341e Prepared tests for eventual drive which might support SAO to appendable CD 2006-11-15 09:05:06 +00:00
725b6515ff Fixed a wrong name in API description 2006-11-14 16:38:01 +00:00
61a535f3ac Implemented try to find on restricted drives a suitable write mode as default 2006-11-14 10:41:06 +00:00
7c312a33d9 Corrected a typo reported by George Danchev 2006-11-14 08:33:34 +00:00
b7d369dbb6 Changed references to libisofs 2006-11-14 08:32:32 +00:00
16cbb18f15 Removed remaining signs of libisofs in libburn tree 2006-11-14 00:52:32 +00:00
4f83818ff8 Removed references to libisofs 2006-11-13 15:00:42 +00:00
9e383a3b9e Adjusted description of write mode default 2006-11-13 13:23:34 +00:00
a9b7d8250e Next cdrskin-0.2.5 cycle 2006-11-13 13:04:38 +00:00
1ec94d9226 Refered to both libburn and libisofs in SVN description, updated history 2006-11-13 11:58:57 +00:00
c1607eeac4 Changed SVN URLs to reflect new structure 2006-11-13 08:33:21 +00:00
8927e3df9f Started logical separation of libisofs and libburn 2006-11-13 00:13:21 +00:00
7458223cc0 Made -toc on blank CD exit with value 0 (rather than 7 with no media) 2006-11-12 18:51:59 +00:00
5a0b597e3f Reacted on error condition during write operation 2006-11-12 15:28:09 +00:00
bf20758906 Made SAO preferrable default write mode, kept TAO as default where needed 2006-11-12 11:34:58 +00:00
1bfd7b5a5f Made speed 0 in burn_drive_set_speed() really maximum speed (i.e. FFFFh) 2006-11-12 08:56:46 +00:00
aa813303a4 Updated docs about multi-session 2006-11-11 16:33:23 +00:00
9baf20e907 Prepared next cdrskin-0.2.5 cycle 2006-11-11 16:12:52 +00:00
1947c3a25d Generally enabled -multi, -msinfo and writing to appendable CDs in TAO mode 2006-11-11 15:27:40 +00:00
6b22dadcdd Demanded (for now) -tao for writing to appendable CDs 2006-11-11 15:19:08 +00:00
4efccd15b3 Implemented handling of unsuitable disk states with -msinfo 2006-11-11 13:46:22 +00:00
496fb67c29 Reacted on some warnings of gcc -O2 2006-11-11 12:39:49 +00:00
bc97bdfa71 Reacted on some warnings of gcc -O2 2006-11-11 12:39:08 +00:00
68784d8703 Implemented not so provisory -msinfo 2006-11-11 12:31:13 +00:00
10c01ebc83 Implemented not so provisory -msinfo 2006-11-11 12:27:43 +00:00
6c22b98235 New API function burn_disc_track_lba_nwa() 2006-11-11 12:22:53 +00:00
62bd5963d0 Read -msinfo from first track of last session and not from last track 2006-11-10 18:50:56 +00:00
726cd2664d Made it work with fifos and other non-plain files as track sources 2006-11-10 18:39:35 +00:00
5378638ba7 Provisory -msinfo (very verbous on stderr) 2006-11-10 17:21:08 +00:00
347aa3fe0c Expressing more self-confidence 2006-11-10 09:37:48 +00:00
c9478cc15e Experimentally enabled burning to BURN_DISC_APPENDABLE (tested with TAO only) 2006-11-09 19:29:39 +00:00
ce0d783e82 Corrected first speed measurement report in TAO mode (which was random) 2006-11-09 15:13:33 +00:00
5057fe48ab Silenced SCSI error (debugging) messages about missing media 2006-11-09 11:36:38 +00:00
fcc755a5b8 Check desired write and block type with burn_drive_info.*_block_types 2006-11-09 11:27:51 +00:00
ab8127f980 Prepared next cdrskin-0.2.5 upload cycle 2006-11-08 18:08:03 +00:00
dad50348db Made track write counter of SAO count rather too much than too few bytes 2006-11-08 17:28:56 +00:00
140ff9ade4 Mentioned bug fix about trailing trash 2006-11-08 17:27:27 +00:00
2a64a0d3b1 Avoided error message and nonzero exit with trailing trash on .wav 2006-11-08 16:56:16 +00:00
82983cd7c1 Updated documentation about TAO 2006-11-07 15:22:06 +00:00
b31e882582 Updated documentation about TAO 2006-11-07 14:58:38 +00:00
dd80b2fc88 Prepared next cdrskin-0.2.5 upload cycle 2006-11-07 13:14:24 +00:00
3051fc1987 Made -tao default for single track or stdin, -sao for any other multi-track 2006-11-07 11:45:10 +00:00
e54be83b27 Cared for some SCSI error conditions which were ignored up to now 2006-11-06 19:58:24 +00:00
448aac8880 Made CD with unclosed track blankable (by -force) 2006-11-06 15:52:45 +00:00
db4522bbdc Make -toc on multiple sessions more compatible 2006-11-06 12:14:10 +00:00
d7c34f05e4 New API burn_write_opts_set_multi(). (But libburn cannot burn next session yet) 2006-11-06 11:42:21 +00:00
b96fbd5bd8 Adapted documentation to reflect experimental TAO mode 2006-11-06 08:34:21 +00:00
25d5a2afe4 Enabled audio tracks with TAO 2006-11-04 09:27:50 +00:00
66515523c1 Enabled TAO for multiple -data tracks (-audio still ends after 0 bytes) 2006-11-03 20:22:54 +00:00
684cfd0cd2 Installed decent abort behavior with TAO 2006-11-03 15:10:24 +00:00
a0e745c54a Removed some obsolete debugging messages 2006-11-03 06:31:51 +00:00
a239d54bd7 Changed status report during blanking (there are no "sectors") 2006-11-03 06:30:18 +00:00
c98dd9b0a7 Installed status communications about closing session ("Fixating") 2006-11-02 21:17:32 +00:00
193d674852 Mentioned -tao and experimental compile 2006-11-02 12:21:14 +00:00
15e37555ae Repaired broken macro settings during Linux build 2006-11-01 17:19:37 +00:00
d337722920 dapted cdrskin pacifier to possibly unknown track size 2006-11-01 16:39:07 +00:00
5af92d13fe Made single track TAO work without fixed size (compile -experimental) 2006-10-31 18:48:18 +00:00
114307a679 Made single track TAO work (sector i/o still wants fixed size, though) 2006-10-31 11:55:51 +00:00
99ca953b1d Made MMC command CLOSE TRACK/SESSION available to struct burn_drive 2006-10-30 11:18:36 +00:00
b837cc134d Deleted from to EXTRA_DIST libburn/sg-*.h 2006-10-29 08:17:49 +00:00
d3ee0b72e4 Added to EXTRA_DIST libburn/sg-*.[ch] 2006-10-29 08:13:01 +00:00
6914e2f7e2 Added to EXTRA_DIST cdrskin/cleanup.[ch] 2006-10-29 07:47:24 +00:00
37017119b0 Copied missing file from libburn-0.2.2 2006-10-29 07:26:35 +00:00
447d2365c7 Corrected bug which made every track from file an audio track 2006-10-28 15:27:30 +00:00
ece61a1860 Corrected misnaming of my development directory 2006-10-28 12:49:28 +00:00
acc6bdd95c Performed cdrskin version leap to cdrskin-0.2.5 2006-10-28 12:31:46 +00:00
559811e8ef Performed cdrskin version leap to cdrskin-0.2.5 2006-10-28 11:52:49 +00:00
80 changed files with 5244 additions and 6184 deletions

2
CONTRIBUTORS Normal file
View File

@ -0,0 +1,2 @@
Joe Neeman
Philippe Rouquier

View File

@ -1,7 +1,7 @@
pkgconfigdir=$(libdir)/pkgconfig
libincludedir=$(includedir)/libburn
lib_LTLIBRARIES = libburn/libburn.la libisofs/libisofs.la
lib_LTLIBRARIES = libburn/libburn.la
## ========================================================================= ##
@ -39,6 +39,7 @@ libburn_libburn_la_SOURCES = \
libburn/null.h \
libburn/options.c \
libburn/options.h \
libburn/os.h \
libburn/read.c \
libburn/read.h \
libburn/sbc.c \
@ -64,44 +65,18 @@ libburn_libburn_la_SOURCES = \
## libburn/sg-@ARCH@.c \
libisofs_libisofs_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
libisofs_libisofs_la_SOURCES = \
libisofs/tree.h \
libisofs/tree.c \
libisofs/volume.h \
libisofs/volume.c \
libisofs/util.h \
libisofs/util.c \
libisofs/ecma119.c \
libisofs/ecma119.h \
libisofs/ecma119_tree.c \
libisofs/ecma119_tree.h \
libisofs/susp.h \
libisofs/susp.c \
libisofs/rockridge.h \
libisofs/rockridge.c \
libisofs/joliet.c \
libisofs/joliet.h \
libisofs/exclude.c \
libisofs/exclude.h \
libisofs/hash.h \
libisofs/hash.c
libinclude_HEADERS = \
libburn/libburn.h \
libisofs/libisofs.h
libburn/libburn.h
## ========================================================================= ##
## Build test applications
noinst_PROGRAMS = \
test/libburner \
test/telltoc \
test/dewav \
test/fake_au \
test/iso \
test/poll \
test/toc \
test/structest
bin_PROGRAMS = \
@ -110,6 +85,9 @@ bin_PROGRAMS = \
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
@ -119,22 +97,15 @@ 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_toc_CPPFLAGS = -Ilibburn
test_toc_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
test_toc_SOURCES = test/toc.c
test_structest_CPPFLAGS = -Ilibburn
test_structest_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
test_structest_SOURCES = test/structest.c
test_iso_CPPFLAGS = -Ilibisofs
test_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_iso_SOURCES = test/iso.c
## cdrskin construction site - ts A60816
cdrskin_cdrskin_CPPFLAGS = -Ilibburn
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_2_3
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_2_6
cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cdrskin_timestamp.h
## cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cleanup.c cdrskin/cleanup.h cdrskin/cdrskin_timestamp.h
##
## Open questions: how to compute $timestamp and express -DX="$timestamp"
##
@ -174,13 +145,9 @@ uninstall-local:
# Indent source files
indent_files = \
$(libisofs_libisofs_la_SOURCES) \
$(libburn_libburn_la_SOURCES) \
$(test_libburner_SOURCES) \
$(test_poll_SOURCES) \
$(test_toc_SOURCES) \
$(test_structest_SOURCES) \
$(test_iso_SOURCES)
$(test_structest_SOURCES)
indent: $(indent_files)
@ -196,12 +163,13 @@ indent: $(indent_files)
# Extra things
nodist_pkgconfig_DATA = \
libburn-1.pc \
libisofs-1.pc
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 \
libisofs-1.pc.in \
version.h.in \
doc/comments \
doc/doxygen.conf.in \
@ -215,5 +183,12 @@ EXTRA_DIST = \
cdrskin/changelog.txt \
cdrskin/cdrskin_eng.html \
cdrskin/wiki_plain.txt \
COPYING
cdrskin/cleanup.h \
cdrskin/cleanup.c \
libburn/os-freebsd.h \
libburn/os-linux.h \
libburn/sg-freebsd.c \
libburn/sg-linux.c \
COPYING \
$(man_MANS)

33
README
View File

@ -27,8 +27,8 @@ This libburn.pykix.org toplevel README (C) 2006 Thomas Schmitt
Our build system is based on autotools. For preparing the build of a SVN
snapshot you will need autotools of at least version 1.7.
Check out from SVN by
svn co http://libburn-svn.pykix.org/trunk libburn_pykix
and apply autotools by
svn co http://libburn-svn.pykix.org/libburn/trunk libburn_pykix
go into directory libburn_pykix and apply autotools by
./bootstrap
Alternatively you may unpack a release tarball for which you do not need
@ -42,22 +42,29 @@ into its toplevel directory (here: "libburn_pykix") and execute
To make the libraries accessible for running resp. developing applications
make install
The other half of the project, libisofs, is hosted in the libburn SVN, too:
svn co http://libburn-svn.pykix.org/libisofs/trunk libisofs_pykix
See README file there.
------------------------------------------------------------------------------
Overview of libburn.pykix.org
libburn.pykix.org is an open-source library for reading, mastering and writing
optical discs. For now this means only CD-R and CD-RW.
libburn.pykix.org is an open-source software project for reading, mastering and
writing optical discs. For now this means only CD-R and CD-RW.
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 and we will have a hard time to widen
this for now, because of our history. The project could need advise from or
membership of skilled kernel people and people who know how to talk CD/DVD
drives into doing things.
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 do have a workable code base for burning data CDs, though. The burn API is
quite comprehensively documented and can be used to build a presentable
@ -152,6 +159,16 @@ Project history as far as known to me:
- 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.
------------------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify

View File

@ -3,5 +3,8 @@
aclocal
libtoolize --copy --force
autoconf
autoheader
# ts A61101 : libburn is not prepared for config.h
# autoheader
automake --foreign --add-missing --copy --include-deps

View File

@ -26,12 +26,12 @@ following possible.
cdrskin. By Thomas Schmitt <scdbackup@gmx.net>
Integrated sub project of libburn.pykix.org but also published via:
http://scdbackup.sourceforge.net/cdrskin_eng.html
http://scdbackup.sourceforge.net/cdrskin-0.2.3.tar.gz
http://scdbackup.sourceforge.net/cdrskin-0.2.6.pl01.tar.gz
Copyright (C) 2006 Thomas Schmitt
------------------------------------------------------------------------------
On top of libburn there is implemented cdrskin 0.2.3, a limited cdrecord
On top of libburn there is implemented cdrskin 0.2.6, a limited cdrecord
compatibility wrapper which allows to use some libburn features from
the command line.
Interested users of cdrecord are invited to participate in the development
@ -59,16 +59,16 @@ systems, including 64 bit systems. (Further reports are welcome.)
Compilation, First Glimpse, Installation
Obtain cdrskin-0.2.3.tar.gz , take it to a directory of your choice and do:
Obtain cdrskin-0.2.6.pl02.tar.gz, take it to a directory of your choice and do:
tar xzf cdrskin-0.2.3.tar.gz
cd cdrskin-0.2.3
tar xzf cdrskin-0.2.6.pl02.tar.gz
cd cdrskin-0.2.6
Or obtain a libburn.pykix.org SVN snapshot,
go into the toplevel directory of the snapshot (e.g. cd libburn_pykix ),
and execute the autotools script ./bootstrap . Use autools version >= 1.7 .
Within that toplevel directory of either cdrskin-0.2.3 or libburn then execute:
Within that toplevel directory of either cdrskin-0.2.6 or libburn then execute:
./configure
make
@ -86,10 +86,11 @@ In order to surely get a standalone binary, execute
cdrskin/compile_cdrskin.sh
Version identification an help texts available afterwards:
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:
If cdrskin was already installed by a previous version, or by "make install"
@ -108,6 +109,10 @@ 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
Usage
@ -169,8 +174,8 @@ Burn image file my_image.iso to CD
-eject my_image.iso
Burn a compressed afio archive to CD on-the-fly
find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 -sao \
driveropts=burnfree padsize=300k tsize=650m -
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.
Anything except .wav or .au files has to be converted into raw format first.
@ -181,7 +186,7 @@ See below "Audio CD" for specifications.
madplay -o raw:track04.cd /path/to/track4.mp3
mppdec --raw-le /path/to/track5.mpc track05.cd
cdrskin dev=0,1,0 blank=fast -eject speed=48 \
cdrskin -v dev=0,1,0 blank=fast -eject speed=48 -sao \
-audio -swab track0[1-5].cd /path/to/track6.wav
@ -198,7 +203,7 @@ or a device file address as listed by --devices with an accessible drive :
Set usage of cdrskin with appropriate options rather than cdrecord :
export SCDBACKUP_CDRECORD="cdrskin -v -v tao_to_sao_tsize=650m"
export SCDBACKUP_CDRECORD="cdrskin -v -v"
Run a backup :
@ -207,12 +212,11 @@ Run a backup :
Restrictions
The convenient burn mode TAO is not available with libburn yet.
Therefore it has to be defaulted to mode SAO which needs to know the track
size in advance. non-cdrecord option tao_to_sao_tsize=650m causes each CD
to get burned up to 650 MB regardless of the payload size.
The major restrictions are lifted now: audio, TAO, multi-session do work.
Many cdrecord options are still unsupported, though.
If you have use cases for them, please report your wishes and expectations.
No multi session yet ... Please report your wishes.
Inspiration and Standard
@ -324,7 +328,7 @@ will be the right one to replace "1,0,0" in above example.
If not --no_rc is the first argument then cdrskin attempts on startup to read
arguments from the following three files:
/etc/defaults/cdrskin
/etc/default/cdrskin
/etc/opt/cdrskin/rc
$HOME/.cdrskinrc
The files are read in the sequence given above.

View File

@ -0,0 +1,206 @@
#!/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.
#
# libburn version used: http://libburn.pykix.org
# Downloaded by:
# $ svn co http://libburn-svn.pykix.org/trunk libburn_pykix
# packed up in a tarball just to save it from inadverted changes by
# $ tar czf libburn_svn.tgz libburn_pykix
original="./libburn_svn.tgz"
# Historic moments:
# original="./libburn_svn_A60815.tgz"
# original="./libburn_cdrskin_A60819.tgz"
# The top level directory in that snapshot is named
intermediate="./libburn_pykix"
# My changes are in libburn-0.2.3.ts.develop , mainly in ./cdrskin
changes="./libburn-0.2.3.ts.develop"
skin_release="0.2.6"
patch_level=".pl01"
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"
bintarget_dynamic="cdrskin_${skin_rev}-x86-suse9_0"
bintarget_static="$bintarget_dynamic"-static
if test -d "$changes"
then
dummy=dummy
else
echo "$0 : FATAL : no directory $changes" >&2
exit 1
fi
for i in "$target" "$intermediate"
do
if test -e "$i"
then
echo "$0 : FATAL : already existing $i" >&2
exit 2
fi
done
if test -f "$original"
then
dummy=dummy
else
echo "$0 : FATAL : no file $original" >&2
exit 3
fi
# Unpack SVN snapshot.
tar xzf "$original"
# Rename the directory to the cdrskin name
mv "$intermediate" "$target"
# Copy the changes from the development tree
#
cdrskin_dir="$changes"/cdrskin
libburn_dir="$changes"/libburn
cdrskin_target="$target"/cdrskin
libburn_target="$target"/libburn
# Create version timestamp
timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
echo "$timestamp"
echo '#define Cdrskin_timestamP "'"$timestamp"'"' >"$cdrskin_dir"/cdrskin_timestamp.h
# Add the cdrskin files
if test -e "$cdrskin_target"
then
rm -rf "$cdrskin_target"
fi
cp -a "$cdrskin_dir" "$cdrskin_target"
# Remove copied binaries
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
for i in .deps .dirstamp .libs
do
if test -e "$cdrskin_target"/"$i"
then
rm -rf "$cdrskin_target"/"$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
## No more : Add own libburn-README in toplevel
# cp -a "$changes"/README "$target"
## No more : Add modified Makefile.am
# cp -a "$changes"/Makefile.am "$target"
# 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
# Pack it up to the new libburn+cdrskin-tarball
tar czf "$cdrskin_tarball" "$target"
# Produce a static and a dynamic binary
(
cd "$compile_dir" || exit 1
./configure
make
$compile_cmd -do_strip
cp "$compile_result" "../$bintarget_dynamic"
if test -n "$compile_static_opts"
then
$compile_cmd $compile_static_opts -do_strip
cp "$compile_result" "../$bintarget_static"
fi
)
# 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"

View File

@ -22,7 +22,7 @@ set -x
#
# libburn version used: http://libburn.pykix.org
# Downloaded by:
# $ svn co http://libburn-svn.pykix.org/trunk libburn_pykix
# $ svn co http://libburn-svn.pykix.org/libburn/trunk libburn_pykix
# packed up in a tarball just to save it from inadverted changes by
# $ tar czf libburn_svn.tgz libburn_pykix
original="./libburn_svn.tgz"
@ -36,7 +36,7 @@ intermediate="./libburn_pykix"
# My changes are in libburn-0.2.3.ts.develop , mainly in ./cdrskin
changes="./libburn-0.2.3.ts.develop"
skin_rev="0.2.3"
skin_rev="0.2.7"
# The result directory and the name of the result tarballs
target="./cdrskin-${skin_rev}"
@ -108,12 +108,24 @@ fi
cp -a "$cdrskin_dir" "$cdrskin_target"
# Remove copied binaries
rm "$cdrskin_target"/*.o
rm "$cdrskin_target"/cdrfifo
rm "$cdrskin_target"/cdrskin
rm "$cdrskin_target"/cleanup
rm "$cdrskin_target"/cdrskin_std
rm "$cdrskin_target"/cdrskin_new
rm "$cdrskin_target"/*.o
for i in std new make old
do
if test -e "$cdrskin_target"/cdrskin_"$i"
then
rm "$cdrskin_target"/cdrskin_"$i"
fi
done
for i in .deps .dirstamp .libs
do
if test -e "$cdrskin_target"/"$i"
then
rm -rf "$cdrskin_target"/"$i"
fi
done
# Remove unwanted SVN stuff (TODO: avoid downloading it)
for i in "$target"/.svn "$target"/*/.svn

View File

@ -48,6 +48,9 @@ struct CdrfifO {
int source_fd;
double in_counter;
double fd_in_counter;
double fd_in_limit;
char *buffer;
int buffer_size;
int buffer_is_full;
@ -72,17 +75,27 @@ struct CdrfifO {
double empty_counter;
double full_counter;
/* (sequential) fd chaining */
/* fds: 0=source, 1=dest */
int follow_up_fds[Cdrfifo_ffd_maX][2];
/* index of first byte in buffer which does not belong to predecessor fd */
int follow_up_eop[Cdrfifo_ffd_maX];
/* index of first byte in buffer which belongs to [this] fd pair */
int follow_up_sod[Cdrfifo_ffd_maX];
/* values for fd_in_limit */
double follow_up_in_limits[Cdrfifo_ffd_maX];
/* number of defined follow-ups */
int follow_up_fd_counter;
/* index of currently active (i.e. reading) follow-up */
int follow_up_fd_idx;
/* (simultaneous) peer chaining */
struct CdrfifO *next;
struct CdrfifO *prev;
@ -117,6 +130,8 @@ int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
buffer_size+= chunk_size-(buffer_size%chunk_size);
o->source_fd= source_fd;
o->in_counter= 0.0;
o->fd_in_counter= 0;
o->fd_in_limit= -1.0;
o->buffer= NULL;
o->buffer_is_full= 0;
o->buffer_size= buffer_size;
@ -140,6 +155,7 @@ int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
for(i= 0; i<Cdrfifo_ffd_maX; i++) {
o->follow_up_fds[i][0]= o->follow_up_fds[i][1]= -1;
o->follow_up_eop[i]= o->follow_up_sod[i]= -1;
o->follow_up_in_limits[i]= -1.0;
}
o->follow_up_fd_counter= 0;
o->follow_up_fd_idx= -1;
@ -224,6 +240,26 @@ int Cdrfifo_set_speed_limit(struct CdrfifO *o, double bytes_per_second,
}
/** Set a fixed size for input in order to cut off any unwanted tail
@param o The fifo object
@param idx index for fds attached via Cdrfifo_attach_follow_up_fds(),
first attached is 0, <0 directs limit to active fd limit
(i.e. first track is -1, second track is 0, third is 1, ...)
*/
int Cdrfifo_set_fd_in_limit(struct CdrfifO *o, double fd_in_limit, int idx,
int flag)
{
if(idx<0) {
o->fd_in_limit= fd_in_limit;
return(1);
}
if(idx >= o->follow_up_fd_counter)
return(0);
o->follow_up_in_limits[idx]= fd_in_limit;
return(1);
}
int Cdrfifo_set_fds(struct CdrfifO *o, int source_fd, int dest_fd, int flag)
{
o->source_fd= source_fd;
@ -244,6 +280,7 @@ int Cdrfifo_get_fds(struct CdrfifO *o, int *source_fd, int *dest_fd, int flag)
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)
@ -253,7 +290,7 @@ int Cdrfifo_attach_follow_up_fds(struct CdrfifO *o, int source_fd, int dest_fd,
o->follow_up_fds[o->follow_up_fd_counter][0]= source_fd;
o->follow_up_fds[o->follow_up_fd_counter][1]= dest_fd;
o->follow_up_fd_counter++;
return(1);
return(o->follow_up_fd_counter);
}
@ -567,7 +604,12 @@ after_write:;
can_read= o->chunk_size;
if(o->write_idx<o->read_idx && o->write_idx+can_read > o->read_idx)
can_read= o->read_idx - o->write_idx;
ret= read(o->source_fd,o->buffer+o->write_idx,can_read);
if(o->fd_in_limit>=0.0)
if(can_read > o->fd_in_limit - o->fd_in_counter)
can_read= o->fd_in_limit - o->fd_in_counter;
ret= 0;
if(can_read>0)
ret= read(o->source_fd,o->buffer+o->write_idx,can_read);
if(ret==-1) {
/* >>> handle input error */;
@ -599,6 +641,8 @@ after_write:;
sod= 0;
o->follow_up_sod[idx]= sod;
o->write_idx= sod;
o->fd_in_counter= 0;
o->fd_in_limit= o->follow_up_in_limits[idx];
if(Cdrfifo_debuG || (flag&1))
fprintf(stderr,"\ncdrfio: new fifo source fd : %d\n",o->source_fd);
} else {
@ -608,6 +652,7 @@ after_write:;
did_work= 1;
o->put_counter++;
o->in_counter+= ret;
o->fd_in_counter+= ret;
o->write_idx+= ret;
if(o->write_idx>=o->buffer_size)
o->write_idx= 0;
@ -751,7 +796,7 @@ ex:;
/** Fill the fifo as far as possible without writing to destination fd */
int Cdrfifo_fill(struct CdrfifO *o, int flag)
int Cdrfifo_fill(struct CdrfifO *o, int size, int flag)
{
int ret,fill= 0,space,state;
@ -765,6 +810,8 @@ int Cdrfifo_fill(struct CdrfifO *o, int flag)
} else if(state!=1)
break;
if(space<=0)
break;
if(size>=0 && fill>=size)
break;
ret= Cdrfifo_try_to_work(o,100000,NULL,NULL,2);
if(ret<0) {

View File

@ -15,7 +15,7 @@
/** The fifo buffer which will smoothen the data stream from data provider
to data consumer. Although this is not a mandatory lifesavier for modern
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.).
@ -64,6 +64,16 @@ int Cdrfifo_get_sizes(struct CdrfifO *o, int *chunk_size, int *buffer_size,
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);
@ -72,6 +82,7 @@ int Cdrfifo_get_fds(struct CdrfifO *o, int *source_fd, int *dest_fd, int flag);
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);
@ -134,10 +145,11 @@ int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
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
/** 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 flag);
int Cdrfifo_fill(struct CdrfifO *o, int size, int flag);
#endif /* Cdrfifo_headerfile_includeD */

600
cdrskin/cdrskin.1 Normal file
View File

@ -0,0 +1,600 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH CDRSKIN 1 "December 13, 2006"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
cdrskin \- burns preformatted data to CD-R or CD-RW via libburn.
.SH SYNOPSIS
.B cdrskin
.RI [ options | track_source_addresses ]
.br
.SH DESCRIPTION
.PP
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
.PP
\fBcdrskin\fP is a program that provides some of cdrecord's options in a compatible way.
You don't need to be root to use it.
.PP
.B Overview of features:
.br
Blanking of CD-RW.
.br
Burning of data or audio tracks to CD.
.br
Either in versatile Track at Once mode (TAO)
.br
or in Session at Once mode for seamless tracks.
.br
Multi session (follow-up sessions in TAO only).
.br
Bus scan, burnfree, speed options, retrieving media info, padding, fifo.
.br
See section EXAMPLES at the end of this text.
.PP
.B Known deficiencies:
.br
No DVD support yet.
.PP
.B Track recording model:
.br
The input-output entities which get processed are called tracks.
A track stores a stream of bytes.
.br
Each track is initiated by one track source address argument, which may either
be "-" for standard input or the address of a readable file. If no write mode
is given explicitely then one will be chosen which matches the peculiarities
of track source and the state of the output media.
.PP
There can be more than one track burned by a single run of cdrskin.
CDs can be kept appendable so that further tracks can
be written to them in subsequent runs of cdrskin (see option -multi).
Info about the addresses of burned tracks is kept in a table of
content (TOC) on media and can be retrieved via cdrskin option -toc.
These informations are also used by the operating systems' CD-ROM read drivers.
.PP
In general there are two types of tracks: data and audio. They differ in
sector size, throughput and readability via the systems' CD-ROM drivers
resp. by music CD players.
.br
If not explicitely option -audio is given, then any track is burned as data
unless the track source is a file with suffix ".wav" or ".au" and has a
header part which identifies it as MS-WAVE resp. SUN Audio with suitable
parameters. Such files are burned as audio tracks by default.
.PP
While audio tracks just contain a given time span of acoustic vibrations,
data tracks may have an arbitray meaning. Nevertheless, ISO-9660 filesystems
are established as a format which can represent a tree of directories and
data files on all major operating systems. Such filesystem images can be
produced by programs mkisofs or genisoimage. They can also be extended by
follow-up tracks if prepared properly. See the man pages of said programs.
cdrskin is able to fulfill the needs about their option -C.
.br
Another type of data track content are archive formats which originally
have been developed for magnetic tapes. Only formats which mark a detectable
end-of-archive in their data are suitable with CD, though. Well tested are
the archivers afio and star. Not suitable seems GNU tar.
.PP
.B Recordable CD Media:
.br
CD-R can be initially written only once and eventually extended until they
get closed (or are spoiled because they are overly full). After that they are
read-only.
.br
CD-RW media can be blanked to make them re-usable for another
round of overwriting. Blanking damages the previous content but does not
make it completely unreadable. It is no effective privacy precaution.
Multiple cycles of blanking and overwriting with random numbers might be.
.br
.SH OPTIONS
.TP
.BI \-\-help
Show non-cdrecord compatible options.
.TP
.BI \-help
Show cdrecord compatible options.
.TP
.BI \-version
Print cdrskin id line, compatibility lure line, libburn version, cdrskin
version, version timestamp, build timestamp (if available), and then exit.
.PP
Alphabetical list of options which are intended to be compatible with
original cdrecord by Joerg Schilling:
.TP
.BI \-atip
Retrieve some info about media state. With CD-RW print "Is erasable".
.TP
.BI \-audio
Announces that the subsequent tracks are to be burned as audio.
The source is supposed to be uncompressed headerless PCM, 44100 Hz, 16 bit,
stereo. For little-endian byte order (which is usual on PCs) use option
-swab. Input files with suffix .wav are examined wether they have a header
in MS-WAVE format confirming those parameters and eventually raw audio data
get extracted automatically. Same is done for suffix .au and SUN Audio.
.TP
.BI blank= type
Blank a CD-RW disc. This is combinable with burning in the same run of cdrskin.
The type given with blank= selects the particular behavior:
.RS
.TP
help
Print this list of blanking types.
.TP
all
Blank the entire disk.
.TP
fast
Minimally blank the entire disk.
.RE
.TP
.BI \-checkdrive
Retrieve some info about the addressed drive.
Exits with non-zero value if the drive cannot be found and opened.
.TP
.BI \-dao
Alias for option -sao. Write disk in Session at Once mode.
.TP
.BI \-data
Subsequent tracks are data tracks. This option is default and only needed
to mark the end of the range of an eventual option -audio.
.TP
.BI dev= target
Sets the (pseudo-)SCSI address of the drive to use. Valid are at least the
X,Y,Z addresses listed with option -scanbus, ATA:X,Y,Z addresses listed with
options dev=ATA -scanbus, the device file addresses listed with
option --devices , volatile libburn drive numbers (numbering starts at "0").
Other device file addresses which lead to the same drive might work too.
.br
If no dev= is given, volatile address "dev=0" is assumed. That is the first
drive found being available. Better avoid this on multi-drive systems.
.br
The special target "help" lists hints about available addressing formats.
Be aware that option --old_pseudo_scsi_adr changes the meaning of
Bus,Target,Lun addresses.
.TP
.BI driveropts= opt
Set "driveropts=burnfree" to enable the drive's eventual protection mechanism
against temporary lack of source data (i.e. buffer underrun).
It is not an error to do this with a drive that has no such capabilities.
.TP
.BI \-dummy
Try to perform the drive operations without actually affecting the inserted
media. There is no guarantee that this will work with a particular drive
in a particular write mode. Blanking is prevented reliably, though.
.TP
.BI \-eject
Eject the disk after work is done.
.TP
.BI \-force
Assume that the user knows better in situations when cdrskin or libburn are
insecure about drive or media state. This includes the attempt to blank
media which are classified as unknown or unsuitable, and the attempt to use
write modes which libburn believes they are not supported by the drive.
.br
Use this only when in urgent need.
.TP
.BI fs= size
Set the fifo size to the given value. The value may have appended letters which
multiply the preceding number:
.br
"k" or "K" = 1024 , "m" or "M" = 1024k , "g" or "G" = 1024m , "s" or "S" = 2048
.br
Set size to 0 in order to disable the fifo (default is "4m").
.br
The fifo buffers an eventual temporary surplus of track source data in order to
provide the drive with a steady stream during times of temporary lack of track
source supply.
The larger the fifo, the longer periods of poor source supply can be
compensated.
But a large fifo needs substantial time to fill up if not curbed via
option fifo_start_at=size.
.TP
.BI gracetime= seconds
Set the grace time before starting to write. (Default is 0)
.TP
.BI \-msinfo
Retrieve multi-session info for preparing a follow-up session by option -C
of programs mkisofs or genisoimage. Print result to standard output.
This option redirects to stderr all
message output besides its own result string, which consists of two numbers.
The result string shall be used as argument of option -C with said programs.
It gives the start address of the most recent session and the predicted
start address of the next session to be appended. The string is empty if
the most recent session was not written with option -multi.
.TP
.BI \-multi
This option keeps the CD appendable after the current session has been written.
Without it the disk gets closed and may not be written any more - unless it
is a CD-RW and gets blanked which causes loss of its content.
.br
The following sessions can only be written in -tao mode.
.br
In order to have all filesystem content accessible, the eventual ISO-9660
filesystem of a follow-up
session needs to be prepared in a special way by the filesystem formatter
program. mkisofs and genisoimage expect particular info about the situation
which can be retrieved by cdrskin option -msinfo.
.br
To retrieve an archive file which was written as follow-up session,
you may use option -toc to learn about the "lba" of the desired track number.
.TP
.BI \-nopad
Do not add trailing zeros to the data stream. Nevertheless, since there seems
to be no use for audio tracks with incomplete last sector, this option applies
only to data tracks. There it is default.
.TP
.BI \-pad
Add 30 kB of trailing zeros to each data track. (This is not sufficient to
avoid problems with various CD-ROM read drivers.)
.TP
.BI padsize= size
Add the given amount of trailing zeros to the next data track. This option
gets reset to padsize=0 after that next track is written. It may be set
again before the next track argument. About size specifiers, see option fs=.
.TP
.BI \-raw96r
Write disk in RAW/RAW96R mode. This mode allows to put more payload bytes
into a CD sector but obviously at the cost of error correction. It can only
be used for tracks of fixely predicted size. Some drives allow this mode but
then behave strange or even go bad for the next few attempts to burn a CD.
One should use it only if inavoidable.
.TP
.BI \-sao
Write disk in Session At Once mode. This mode is able to put several audio
tracks on CD without producing audible gaps between them. It can only
be used for tracks of fixely predicted size. This implies that track arguments
which depict stdin or named pipes need to be preceeded by option tsize= or
by option tao_to_sao_tsize=.
.TP
.BI \-scanbus
Scan the system for drives. On Linux the drives at /dev/s* and at /dev/hd*
are to be scanned by two separate runs. One without dev= for /dev/s* and
one with dev=ATA for /dev/hd* devices. (Option --drives lists all available
drives in a single run.)
.br
Drives which are busy or which offer no rw-permission to the user of cdrskin
are not listed. Busy drives get reported in form of warning messages.
.br
The useful fields in a result line are:
.br
Bus,Target,Lun Number) 'Vendor' 'Mode' 'Revision'
.TP
.BI speed= number
Set speed of drive. With data CD, 1x speed corresponds to a throughput of
150 kB/s. It is not an error to set a speed higher than is suitable for drive
and media. One should stay within a realistic speed range, though.
.TP
.BI \-swab
Announce that the raw audio data source of subsequent tracks is byte swapped
versus the expectations of cdrecord. This option is suitable for audio where
the least significant byte of a 16 bit word is first (little-endian, Intel).
Most raw audio data on PC systems are available in this byte order.
Less guesswork is needed if track sources are in format MS-WAVE in a file with
suffix ".wav".
.TP
.BI \-tao
Write disk in Track At Once (TAO) mode. This mode can be used with track
sources of unpredictable size, like standard input or named pipes. It is
also the only mode that can be used for writing to appendable CD which
already hold data.
.TP
.BI \-toc
Print the table of content (TOC) which describes the tracks recorded on CD.
The output contains all info from option -atip plus lines which begin with
"track: " followed by the track number, the word "lba:" and a number which
gives the start address of the track. Addresses are counted in CD sectors which
with data tracks hold 2048 bytes each.
.RS
.TP
Example. Retrieve an afio archive from track number 2:
.br
tracknumber=2
.br
lba=$(cdrskin dev=/dev/cdrom -toc 2>&1 | \\
.br
grep '^track: [ 0-9][0-9]' | \\
.br
tail +"$tracknumber" | head -1 | \\
.br
awk '{ print $4}' )
.br
dd if=/dev/cdrom bs=2048 skip="$lba" | \\
.br
afio -t - | less
.RE
.TP
.BI tsize= size
Announces the exact size of the next track source. This is necessary with any
write mode other than -tao if the track source is not a regular disk file, but
e.g. "-" (standard input) or a named pipe.
About size specifiers, see option fs=.
.br
If the track source does not deliver the predicted amount of bytes, the
remainder of the track is padded with zeros. This is not considered an error.
If on the other hand the track source delivers more than the announced bytes
then the track on CD gets truncated to the predicted size and cdrskin exits
with non-zero value.
.TP
.BI \-v
Increment verbose level by one. Startlevel is 0 with only few messages.
Level 1 prints progress report with long running operations and also causes
some extra lines to be put out with info retrieval options.
Level 2 additionally reports about option settings derived from arguments or
startup files. Level 3 is for debugging and useful mainly in conjunction with
somebody who had a look into the program sourcecode.
.PP
Alphabetical list of options which are genuine to cdrskin and intended for
normal use:
.TP
.BI \--allow_setuid
Disable the program abort triggered by an insecure discrepance between
login user and
effective user which indicates application of chmod u+s to the program binary.
One should not do this chmod u+s , but it is an old cdrecord tradition.
.TP
.BI \--any_track
Allow source_addresses to begin with "-" (plus further characters) or to
contain a "=" character.
By default such arguments are seen as misspelled options. It is nevertheless
not possible to use one of the options of cdrecord-2.01.
.TP
.BI \--demand_a_drive
Exit with a nonzero value if no drive can be found during a bus scan.
.TP
.BI \--devices
List the device file addresses of all accessible drives. In order to get
listed a drive has to offer rw-permission for the cdrskin user and it may
not be busy.
Busy drives are reported as "SORRY" messages on standard error.
.br
Each available drive gets listed by a line containing the following fields:
.br
Number dev='Devicefile' rw-Permissions : 'Vendor' 'Model'
.br
Number and Devicefile can both be used with option dev=, but number is
volatile (numbering changes if drives become busy).
Normal users might not see all drives unless the superuser enabled access
by chmod o+rw
after using cdrskin --devices to get an overview of the situation.
That's why current rw-Permissions are listed.
.TP
.BI fifo_start_at= size
Do not wait for full fifo but start burning as soon as the given number
of bytes is read. This option may be helpful to bring the average throughput
near to the maximum throughput of a drive. A large fs= and a small
fifo_start_at= combine a quick burn start and a large savings buffer to
compensate for temporary lack of source data. At the beginning of burning,
the software protection against buffer underun is as weak as the size of
fifo_start_at= . So it is best if the drive offers hardware protection which
has to be enabled by driveropts=burnfree.
.TP
.BI \--no_rc
Only if used as first command line argument this option prevents reading and
interpretation of eventual startup files. See section FILES below.
.TP
.BI \--single_track
Accept only the last argument of the command line as track source address.
.PP
Alphabetical list of options which are only intended for very special
situations and not for normal use:
.TP
.BI \--abort_handler
Establish default signal handling not to leave a drive in busy state
but rather to shut it down and to wait until it has ended the final operations.
This option is only needed for revoking eventual --ignore_signals or
--no_abort_handler.
.TP
.BI dev_translation= <sep><from><sep><to>
Set drive address alias. This was necessary before cdrskin-0.2.4 to manually
translate cdrecord addresses into cdrskin addresses.
.br
<sep> is a single character which may not occur in the address string
<from>. <from> is an address as expected to be given by the user via option
dev=. <to> is the address to be used instead whenever <from> is given.
More than one translation instruction can be given in one cdrskin run.
.br
E.g.: dev_translation=+ATA:1,0,0+/dev/sg1 dev_translation=+ATA:1,1,0+/dev/sg2
.TP
.BI \--drive_abort_on_busy
Linux specific: Abort process if a busy drive is encountered.
.TP
.BI \--drive_blocking
Linux specific: Try to wait for a busy drive to become free.
This is not guaranteed to work with all drivers. Some need nonblocking i/o.
.TP
.BI \--drive_not_exclusive
Linux specific: Do not ask the operating system to prevent opening busy drives.
Wether this leads to senseful behavior depends on operating system and kernel.
.TP
.BI \--drive_scsi_exclusive
Linux specific:
Try to exclusively reserve device files /dev/srN, /dev/scdM, /dev/stK of drive.
this would be helpful to protect against collisions with program growisofs.
Regrettably on Linux kernel 2.4 with ide-scsi emulation this seems not to
work. Wether it becomes helpful with new Linux systems has to be evaluated.
.TP
.BI \--fifo_disable
Disable fifo despite any fs=.
.TP
.BI \--fifo_per_track
Use a separate fifo for each track.
.TP
.BI grab_drive_and_wait= seconds
Open the addressed drive, wait the given number of seconds, release the drive,
and do normal work as indicated by the other options used. This option helps
to explore the program behavior when faced with busy drives. Just start a
second cdrskin with option --devices while grab_drive_and_wait= is still
active.
.TP
.BI \--ignore_signals
Try to ignore any signals rather than to abort the program. This is not a
very good idea. You might end up waiting a very long time for cdrskin
to finish.
.TP
.BI \--no_abort_handler
On signals exit even if the drive is in busy state. This is not a very good
idea. You might end up with a stuck drive that refuses to hand out the media.
.TP
.BI \--no_blank_appendable
Refuse to blank appendable CD-RW. This is a feature that was once builtin with
libburn. No information available for what use case it was needed.
.TP
.BI \--no_convert_fs_adr
Do only literal translations of dev=. This prevents cdrskin from test-opening
device files in order to find one that matches the given dev= specifier.
.br
Partly Linux specific:
Such opening is needed for Bus,Target,Lun addresses unless option
--old_pseudo_scsi_adr is given. It is also needed to resolve device file
addresses which are not listed with cdrskin --devices but nevertheless point
to a usable drive. (Like /dev/sr0 using the same SCSI address as /dev/sg0.)
.TP
.BI \--old_pseudo_scsi_adr
Linux specific:
Use and report literal Bus,Target,Lun addresses rather than real SCSI and
pseudo ATA addresses. This method is outdated and was never compatible with
original cdrecord.
.TP
.BI tao_to_sao_tsize= size
Set an exact fixed size for the next track to be in effect only if the track
source cannot deliver a size prediction and no tsize= was specified.
This is the fallback from bad old times when cdrskin was unable to burn
in mode -tao.
.br
.SH EXAMPLES
.SS
.B Get an overview of drives:
.br
cdrskin -scanbus
.br
cdrskin dev=ATA -scanbus
.br
cdrskin --devices
.SS
.B Get info about a particular drive or loaded media:
.br
cdrskin dev=0,1,0 -checkdrive
.br
cdrskin dev=ATA:1,0,0 -atip
.br
cdrskin dev=/dev/hdc -toc
.SS
.B Make used CD-RW writable again:
.br
cdrskin -v dev=/dev/sg1 blank=all -eject
.br
cdrskin -v dev=/dev/dvd blank=fast -eject
.SS
.B Write ISO-9660 filesystem image:
.br
cdrskin -v dev=/dev/hdc speed=12 fs=8m \\
.br
driveropts=burnfree -sao -eject \\
.br
padsize=300k my_image.iso
.SS
.B Write compressed afio archive on-the-fly:
.br
find . | afio -oZ - | \\
.br
cdrskin -v dev=0,1,0 fs=32m speed=8 driveropts=burnfree \\
.br
padsize=300k -tao -
.SS
.B Write several sessions to the same CD:
.br
cdrskin dev=/dev/hdc padsize=300k -multi 1.iso
.br
cdrskin dev=/dev/hdc padsize=300k -multi -tao 2.afio
.br
cdrskin dev=/dev/hdc padsize=300k -multi -tao 3.afio
.br
cdrskin dev=/dev/hdc padsize=300k -tao 4.afio
.SS
.B Get the multi-session info for option -C of program mkisofs:
.br
c_values=$(cdrskin dev=/dev/sr0 -msinfo 2>/dev/null)
.br
mkisofs ... -C "$c_values" ...
.SS
.B Write audio tracks:
.br
cdrskin -v dev=ATA:1,0,0 speed=48 \\
.br
driveropts=burnfree -sao \\
.br
track1.wav track2.au -audio -swab track3.raw
.br
.SH FILES
If not --no_rc is given as the first argument then cdrskin attempts on
startup to read the arguments from the following files:
.PP
.br
.B /etc/default/cdrskin
.br
.B /etc/opt/cdrskin/rc
.br
.B $HOME/.cdrskinrc
.br
.PP
The files are read in the sequence given above, but none of them is
required for cdrskin to function properly. Each readable line is treated
as one single argument. No extra blanks.
A first character '#' marks a comment, empty lines are ignored.
.SS
.B Example content of a startup file:
.br
# This is the default device
.br
dev=0,1,0
.br
# To accomodate to remnant cdrskin-0.2.2 addresses
.br
dev_translation=+1,0,0+0,1,0
.br
# Some more options
.br
fifo_start_at=0
.br
fs=16m
.br
.SH SEE ALSO
.TP
Formatting track sources for cdrskin:
.br
.BR mkisofs (8),
.BR genisoimage (8),
.BR afio (1),
.BR star (1)
.br
.TP
Other CD burn programs:
.br
.BR cdrecord (1),
.BR wodim (1)
.br
.TP
For DVD burning:
.br
.BR growisofs (1)
.br
.SH AUTHOR
cdrskin was written by Thomas Schmitt <scdbackup@gmx.net>.
.PP
This manual page was written by George Danchev <danchev@spnet.net> and
Thomas Schmitt, for the Debian project and for all others.

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@ A CD recorder suitable for
GPL software included:<BR>
</H2>
<DL>
<DT>libburn-0.2.2</DT>
<DT>libburn-0.2.6</DT>
<DD>(by Derek Foreman, Ben Jansens, and team of libburn.pykix.org)</DD>
<DD>transfers data to CD</DD>
</DL>
@ -80,10 +80,31 @@ Ports to other usable systems are appreciated. Reports are welcome.
This has been achieved quite sufficiently for the needs of backup tool
<A HREF="http://scdbackup.sourceforge.net/main_eng.html">scdbackup</A>
and for data CD projects of <A HREF="http://www.k3b.org">K3b</A>
(see <A HREF="#examples">examples</A>).<BR>
(see <A HREF="#examples">examples</A>).
Suitability for audio CD frontends has been improved much and is now being
evaluated.<BR>
Further enhancements depend on people who can describe and discuss their
wishes as well as on the development of libburn.</DT>
<BR><BR>
<DT>Get an overview of drives:</DT>
<DD>$ cdrskin -scanbus</DD>
<DD>$ cdrskin dev=ATA -scanbus</DD>
<DD>$ cdrskin --devices</DD>
<DT>Get info about a particular drive or loaded media:</DT>
<DD>$ cdrskin dev=0,1,0 -checkdrive</DD>
<DD>$ cdrskin dev=ATA:1,0,0 -atip</DD>
<DD>$ cdrskin dev=/dev/hdc -toc</DD>
<DT>Make used CD-RW writable again:</DT>
<DD>$ cdrskin -v dev=/dev/sg1 blank=all -eject</DD>
<DD>$ cdrskin -v dev=/dev/dvd blank=fast -eject</DD>
<DT>Write ISO-9660 filesystem image:</DT>
<DD>$ cdrskin -v dev=/dev/hdc speed=12 fs=8m driveropts=burnfree -sao -eject padsize=300k my_image.iso</DD>
<DT>Write compressed afio archive on-the-fly :</DT>
<DD>$ find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 driveropts=burnfree padsize=300k -tao -</DD>
<DT>Write audio tracks:</DT>
<DD>$ cdrskin -v dev=ATA:1,0,0 speed=48 driveropts=burnfree -sao track1.wav track2.au -audio -swab track3.raw
<DD>
<BR>
<DT><A HREF="cdrskin_help">cdrskin -help</A></DT>
<DD>reports the cdrecord compatible options</DD>
<DT><A HREF="cdrskin__help">cdrskin --help</A></DT>
@ -94,15 +115,6 @@ wishes as well as on the development of libburn.</DT>
(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
this "don't bother Joerg" demand.)
</DD>
<DT>Currently (and sparsely) supported gestures :</DT>
<DD>$ cdrskin -scanbus</DD>
<DD>$ cdrskin dev=1,1,0 -checkdrive</DD>
<DD>$ cdrskin dev=1,1,0 -atip</DD>
<DD>$ cdrskin -v dev=1,1,0 blank=all -eject</DD>
<DD>$ cdrskin -v dev=1,1,0 blank=fast -eject</DD>
<DD>$ cdrskin -v dev=1,1,0 speed=12 fs=8m -sao driveropts=burnfree -eject padsize=300k my_image.iso</DD>
<DD>$ cdrskin -v dev=1,1,0 ... ... track_1.iso padsize=300k track_2.afio</DD>
<DD>$ find . | afio -oZ - | cdrskin -v dev=1,1,0 fs=32m speed=8 -sao driveropts=burnfree padsize=300k tsize=650m -</DD>
</DL>
</P>
@ -111,17 +123,7 @@ wishes as well as on the development of libburn.</DT>
<UL>
<DT></DT>
<LI>
Option -audio is enabled but by default not advertised via option -help,
because no beheading of .au or .wav files takes place yet.
<BR>Note: In development version 0.2.3 there is automatic extraction of
.wav and .au. So -audio is fully supported.
</LI>
<LI>
Burns only a single closed session. No -multi option yet.
</LI>
<LI>
No TAO mode and therefore no writing on-the-fly without a predefined
source size.
Appending sessions to unclosed media is restricted to write mode TAO.
</LI>
<LI>
cdrskin -scanbus or --devices hangs for quite a while if there is
@ -143,9 +145,10 @@ rw-permissions and retry the bus scan as non-superuser.
<P>
<DL>
<DT>Download as source code (see README):</DT>
<DD><A HREF="cdrskin-0.2.2.tar.gz">cdrskin-0.2.2.tar.gz</A>
(450 KB).
<DD><A HREF="cdrskin-0.2.6.pl02.tar.gz">cdrskin-0.2.6.pl02.tar.gz</A>
(510 KB).
</DD>
<DD>(Most recent patch: backported man page from cdrskin-0.2.7)</DD>
<DD>
The "stable" cdrskin tarballs are source code identical with "stable"
libburn releases or with "stabilized" libburn SVN snapshots. They get
@ -154,19 +157,18 @@ cdrskin is part of libburn - full libburn is provided with cdrskin releases.
</DD>
<DD>&nbsp;</DD>
<DT>Download as single x86 binaries (untar and move to /usr/bin/cdrskin):</DT>
<DD><A HREF="cdrskin_0.2.2-x86-suse9_0.tar.gz">
cdrskin_0.2.2-x86-suse9_0.tar.gz</A>, (60 KB),
<DD><A HREF="cdrskin_0.2.6.pl01-x86-suse9_0.tar.gz">
cdrskin_0.2.6.pl01-x86-suse9_0.tar.gz</A>, (60 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.2.2-x86-suse9_0-static.tar.gz">
cdrskin_0.2.2-x86-suse9_0-static.tar.gz</A>, (250 KB), -static compiled,
<DD><A HREF="cdrskin_0.2.6.pl01-x86-suse9_0-static.tar.gz">
cdrskin_0.2.6.pl01-x86-suse9_0-static.tar.gz</A>, (260 KB), -static compiled,
<DL>
<DD>runs on SuSE 7.2 (2.4.4), and on the systems above.</DD>
</DL>
</DD>
<DD>&nbsp;</DD>
</DL>
<DL><DT>Documentation:</DT>
<DD><A HREF="README_cdrskin">README</A> a short introduction</DD>
@ -185,34 +187,43 @@ cdrskin_0.2.2-x86-suse9_0-static.tar.gz</A>, (250 KB), -static compiled,
<HR>
<P>
Enhancements towards previous stable version cdrskin-0.2.4:
<UL>
<LI>Option <KBD><B>-tao</B></KBD> is fully enabled.<BR>
SAO is still the preferred default but TAO is default if a track of
unpredicted size is present (stdin, named pipe, ...) or if a follow-up
session is written to an appendable CD.
(This is an intentional deviation from cdrecord defaults which themselves
have changed with the newest cdrecord versions.)
</LI>
<LI>Status report during blank, preparation and finalization improved.</LI>
<LI>Bug fixed: Trailing trash appended to .wav files caused error message
and, if exceeding fifo size, could even stall a burn.
(Workaround: disable fifo by <KBD><B>fs=0</B></KBD>)</LI>
<LI>Bug fixed: False speed with first pacifier cycle. Potential program
abort by floating point exception (NaN).</LI>
<LI>multi-session CDs: <KBD><B>-multi</B></KBD>, <KBD><B>-msinfo</B></KBD>,
writing to appendable CDs (for now restricted to write mode TAO).</LI>
</UL>
</P>
<HR>
<P>
<DL>
<DT>Development snapshot, version 0.2.3 :</DT>
<DT><H3>Development snapshot, version 0.2.7 :</H3></DT>
<DD>Enhancements towards stable version 0.2.6:
(none yet)
</DD>
<DD>&nbsp;</DD>
<DD>Contains non-critical bug fix about failure to eject.</DD>
<DD>&nbsp;</DD>
<DD>Enhancements towards stable version:
<UL>
<LI>cdrecord compatibility with addresses of form [ATA:]Bus,Target,Lun.</LI>
<LI>Drives adressable via links and device siblings (/dev/cdrom , /dev/scd0).
</LI>
<LI>Automatic -audio extraction with .wav files and .au files.
<BR>&nbsp;$ cdrskin -v dev=1,1,0 track1.wav track2.au -audio -swab track3.raw
</LI>
<LI>Comments and empty lines allowed in startup files.</LI>
<LI>Options -scanbus and --devices print SORRY messages about busy drives.
</LI>
<LI>Drive buffer fill indicator reports realistic percentage numbers.</LI>
<LI>Option -toc is supported, drive firmware revision gets displayed.</LI>
</UL></DD>
<DD>&nbsp;</DD>
<DD><A HREF="README_cdrskin_devel">README 0.2.3</A>
<DD><A HREF="cdrskin__help_devel">cdrskin_0.2.3 --help</A></DD>
<DD><A HREF="cdrskin_help_devel">cdrskin_0.2.3 -help</A></DD>
<DD><A HREF="README_cdrskin_devel">README 0.2.7</A>
<DD><A HREF="cdrskin__help_devel">cdrskin_0.2.7 --help</A></DD>
<DD><A HREF="cdrskin_help_devel">cdrskin_0.2.7 -help</A></DD>
<DD>&nbsp;</DD>
<DT>Maintainers of cdrskin unstable packages please use SVN of
<A HREF="http://libburn.pykix.org"> libburn.pykix.org</A></DT>
<DD>Download: <KBD><B>svn co http://libburn-svn.pykix.org/trunk libburn_pykix</B>
<DD>Download: <KBD><B>svn co http://libburn-svn.pykix.org/libburn/trunk libburn_pykix</B>
</KBD></DD>
<DD>Build: <KBD><B>cd libburn_pykix ; ./bootstrap ; ./configure ; make</B>
</KBD></DD>
@ -228,15 +239,15 @@ admins with full system souvereignty.</DT>
<A HREF="README_cdrskin_devel">upcoming README</A> ):
</DD>
<DD>
<A HREF="cdrskin-0.2.3.tar.gz">cdrskin-0.2.3.tar.gz</A>
<A HREF="cdrskin-0.2.7.tar.gz">cdrskin-0.2.7.tar.gz</A>
(500 KB).
</DD>
<DD>Binary (untar and move to /usr/bin/cdrskin):</DD>
<DD><A HREF="cdrskin_0.2.3-x86-suse9_0.tar.gz">
cdrskin_0.2.3-x86-suse9_0.tar.gz</A>, (60 KB).
<DD><A HREF="cdrskin_0.2.7-x86-suse9_0.tar.gz">
cdrskin_0.2.7-x86-suse9_0.tar.gz</A>, (60 KB).
</DD>
<DD><A HREF="cdrskin_0.2.3-x86-suse9_0-static.tar.gz">
cdrskin_0.2.3-x86-suse9_0-static.tar.gz</A>, (260 KB)
<DD><A HREF="cdrskin_0.2.7-x86-suse9_0-static.tar.gz">
cdrskin_0.2.7-x86-suse9_0-static.tar.gz</A>, (260 KB)
</DD>
</DL>
</P>
@ -288,24 +299,12 @@ is a GUI frontend which uses cdrecord for CD burning.)
<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>scsibus1:</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; 1,0,0 &nbsp;&nbsp; 0)&nbsp; 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
<DD><KBD>scsibus2:</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; 2,2,0 &nbsp;&nbsp; 1)&nbsp; 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
<DD>$ <KBD><B>export SCDBACKUP_SCSI_ADR="2,2,0"</B></KBD></DD>
<!-- 0.2.4
<DD><KBD>...</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; 2,0,0 &nbsp;&nbsp; 0)&nbsp; '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>&nbsp;&nbsp;&nbsp; 1,0,0 &nbsp;&nbsp; 1)&nbsp; '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 tao_to_sao_tsize=650m"</B></KBD></DD>
<DD>$ <KBD><B>scdbackup_home</B></KBD></DD>
</DL>
@ -313,12 +312,9 @@ is a GUI frontend which uses cdrecord for CD burning.)
<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>export SCDBACKUP_EJECT_ADR=/dev/cdrecorder</B></KBD></DD>
<DD>$ <KBD><B>./CONFIGURE_CD</B></KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>cdrskin 0.2.2 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD> ------------------- SCSI devices. To be used like &nbsp;&nbsp; 0,0,0</KBD></DD>
<DD><KBD>cdrskin 0.2.6 : 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.
@ -327,26 +323,18 @@ In this case, you may execute
and try again.
<DL>
<DT></DT>
<DD><KBD>&nbsp;&nbsp;&nbsp; 1,0,0 &nbsp;&nbsp; 0)&nbsp; 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; 2,2,0 &nbsp;&nbsp; 1)&nbsp; 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
<DD><KBD>------------------- end of SCSI device list</KBD></DD>
<!-- 0.2.4
<DD><KBD> ------------------- SCSI devices. To be used like &nbsp;&nbsp; 0,0,0</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; 2,0,0 &nbsp;&nbsp; 0)&nbsp; '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>&nbsp;&nbsp;&nbsp; 1,0,0 &nbsp;&nbsp; 1)&nbsp; 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
-->
<DD><KBD>...</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; * 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 SCDBACKUP_EJECT_ADR</B></KBD></DD>
<DD>$ <KBD><B>unset SCDBACKUP_USE_CDRSKIN</B></KBD></DD>
</DL>
<DL>
<DT>To get back to using cdrecord :</DT>

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2006.10.24.165610"
#define Cdrskin_timestamP "2006.12.16.090001"

View File

@ -1,5 +1,23 @@
------------------------------------------------------------------------------
libburn.pykix.org scdbackup.sourceforge.net/cdrskin
------------------------------------------------------------------------------
Deliberate deviations of cdrskin from cdrecord compatibility:
+ cdrskin does drive operations (on its drive 0) without a dev= option
+ gracetime=0 is allowed and set by default
+ -pad is always set for audio tracks
+ -sao is default where possible, -tao is default where needed
(Note: cdrecord write mode defaults have changed in cdrtools-2.01.01a20)
+ premature end of source is not an error and leads to full announced tracksize
+ -msinfo pushes all other messages to stderr. It works independent of
other options which would prevent it with cdrecord (-atip, -scanbus, ...)
------------------------------------------------------------------------------
Changelog
------------------------------------------------------------------------------
@ -742,6 +760,7 @@ libburn/sg.h
libburn/sg.c
libburn/libdax_msgs.h
cdrskin/cdrskin.c
Disabled but did not discarded failed attempt to lock against growisofs
2006.09.27.120656 [234]
libburn/drive.h
@ -934,7 +953,6 @@ libburn/transport.h
cdrskin/cleanup.c
Made libburn and cdrskin build on my Linux again
2006.10.13.114554 [271]
cdrskin/cdrskin.c
libburn/write.c
@ -942,7 +960,6 @@ libburn/sg-linux.c
libburn/libdax_msgs.h
Removed bug in burn_disc_write_sync(): BURN_DRIVE_IDLE, then d->sync_cache()
2006.10.14.105224 [272]
libburn/sg.h
libburn/sg-freebsd.c
@ -954,7 +971,6 @@ Introduced burn_drive_enumerator_t to allow more complete sg-freebsd implementat
cdrskin/cdrskin.c
Changed ambigous include statement of libburn.h
15 Oct 2006 2006 [275]
Makefile.am
libburn/libdax_msgs.h
@ -1027,25 +1043,715 @@ cdrskin/cdrskin.c
cdrskin/compile_cdrskin.sh
Made cdrskin use libburn/cleanup.[oh] by default (not cdrskin/cleanup.[ch])
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.19
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.19.105730
2006.10.19.162254 [294]
cdrskin/cdrskin.c
cdrskin/cdrskin_eng.html
cdrskin/changelog.txt
Updated documentation about cdrskin-0.2.3
2006.10.19.164742 [295]
cdrskin/cdrskin.c
Corrected -help text
2006.10.20.113421 [297]
libburn/libburn.h
libburn/mmc.c
libburn/sg-linux.c
libburn/sg-freebsd.c
libburn/drive.c
cdrskin/cdrskin.c
Made cdrskin produce "ATIP start of lead" (on non-blank media for now)
20 Oct 2006 [298]
doc/comments
Updated help text of libburner
2006.10.20.151602 [299]
libburn/libburn.h
libburn/drive.c
libburn/mmc.c
libburn/libdax_msgs.h
cdrskin/cdrskin.c
Classified media with TOC read error as unsuitable (rather than as blank)
2006.10.21.103352 [300]
libburn/libburn.h
libburn/transport.h
libburn/drive.c
libburn/mmc.c
libburn/spc.c
libburn/sg-linux.c
libburn/sg-freebsd.c
libburn/libdax_msgs.h
cdrskin/cdrskin.c
Implemented some ATIP functionality
2006.10.21.103653 [301] [302]
libburn/libburn.h
Clarified relation of burn_disc_read_atip() and burn_drive_get_start_end_lba()
2006.10.21.185102 [303]
libburn/sg.h
libburn/mmc.h
libburn/mmc.c
libburn/sbc.h
libburn/sbc.c
libburn/spc.h
libburn/spc.c
libburn/drive.h
libburn/drive.c
libburn/transport.h
libburn/sg-linux.c
libburn/sg-freebsd.c
Split enumerate_common() into logic-layer, command-layer, transport-layer
2006.10.22.130341 [304]
libburn/libburn.h
libburn/mmc.c
libburn/drive.c
libburn/cleanup.c
cdrskin/cleanup.c
cdrskin/cdrskin.c
Implemented cdrskin -toc
2006.10.22.131452 [305]
cdrskin/cdrskin.c
Regulated coexistence of options -toc and -atip
23 Oct 2006 [306]
libburn/mmc.c
Made clarification in remark about atip speed conversion
2006.10.23.074430 [307]
cdrskin/cdrskin.c
Made use of burn_drive_info.revision as firmware revision text
2006.10.23.113116 [308]
libburn/libburn.h
libburn/transport.h
libburn/mmc.h
libburn/mmc.c
libburn/write.c
cdrskin/cdrskin.c
cdrskin/cdrskin_eng.html
cdrskin/README
Made available drive buffer fill during write
23 Oct 2006 [309]
libburn/sg-freebsd.c
Updated tangling of FreeBSD code with mmc.c :(
2006.10.23.134719 [310]
cdrskin/cdrskin.c
Corrected -toc track counter and notified about "hidden" tracks
2006.10.24.075039 [311]
libburn/libdax_audioxtr.h
libburn/libdax_audioxtr.c
test/dewav.c
cdrskin/cdrskin.c
Introduced extraction of .au (but not its usage within cdrskin)
2006.10.24.102107 [312]
libburn/libburn.h
libburn/structure.h
libburn/structure.c
libburn/sector.c
cdrskin/cdrskin.c
cdrskin/README
Enabled byte swapping for audio track sources, added anti option -swab
2006.10.24.130259 [313]
test/dewav.c
cdrskin/cdrskin.c
cdrskin/README
Enabled automatic extraction of .au
24 Oct 2006 [314]
Makefile.am
+ test/fake_au.c
Introduced temporary test program to produce SUN .au files
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.24.144650
2006.10.24.165427 [315]
libburn/sector.c
Closed some loopholes for byte swapping.
2006 []
Open O_EXCL all devices in address resolution chain
(Might help with non-standard hdX device siblings)
2006.10.24.165610 [316]
cdrskin/cdrskin.c
Enabled audio byte swapping by default (to be disabled via option -swab)
2006 []
Convert libburn_experimental: into LIBDAX_MSGS_SEV_DEBUG
Convert burn_print() into libdax_msgs_submit()
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.24.173602
2006 []
Test unlocking of all drives by burn_drive_info_free()
Test unlocking of single drive by burn_drive_grab(), burn_drive_release()
25 Oct 2006 [317]
cdrskin/README
cdrskin/cdrskin_eng.html
cdrskin/wiki_plain.txt
Announced full -audio compatibility with cdrecord
------------------------------------ cycled - cdrskin-0.2.3 - 2006.10.25.160540
2006.10.27.114326 [319 branch]
- cdrskin/add_ts_changes_to_libburn_0_2_3
+ cdrskin/add_ts_changes_to_libburn_0_2_4
cdrskin/README
cdrskin/cdrskin.c
cdrskin/cdrskin_eng.html
cdrskin/changelog.txt
README
Performed cdrskin version leap to cdrskin-0.2.4
2006.10.28.093922 [320 branch]
cdrskin/cdrskin_timestamp.h
Set final timestamp 2006.10.28.093922
------------------------------------ cycled - cdrskin-0.2.4 - 2006.10.28.093922
2006.10.28.115213 [321 trunk] [322 trunk]
- cdrskin/add_ts_changes_to_libburn_0_2_3
+ cdrskin/add_ts_changes_to_libburn_0_2_4
+ cdrskin/add_ts_changes_to_libburn_0_2_5
cdrskin/README
cdrskin/cdrskin.c
cdrskin/cdrskin_eng.html
cdrskin/changelog.txt
README
Performed cdrskin version leap to cdrskin-0.2.5
28 Oct 2006 [323 branch]
- cdrskin/add_ts_changes_to_libburn_0_2_3
cdrskin/add_ts_changes_to_libburn_0_2_4
Corrected misnaming of my development directory
28 Oct 2006 [324 trunk]
cdrskin/add_ts_changes_to_libburn_0_2_4
cdrskin/add_ts_changes_to_libburn_0_2_5
Corrected misnaming of my development directory
2006.10.28.132532 [325 branch]
cdrskin/cdrskin.c
Corrected last-minute bug which made every track from file an audio track
2006.10.28.151521 [326 trunk]
cdrskin/cdrskin.c
Corrected bug which made every track from file an audio track
29 Oct 2006 [327 branch] [328 trunk]
+ CONTRIBUTORS
Copied missing file from libburn-0.2.2
29 Oct 2006 [329 branch] [330 trunk]
Makefile.am
Added to EXTRA_DIST cdrskin/cleanup.[ch]
29 Oct 2006 [331 branch] [332 trunk]
Makefile.am
Added to EXTRA_DIST libburn/sg-*.[ch]
29 Oct 2006 [333 branch] [334 trunk]
Makefile.am
Deleted from to EXTRA_DIST libburn/sg-*.h
30 Oct 2006 [337]
libburn/transport.h
libburn/mmc.c
libburn/sg-freebsd.c
Made MMC command CLOSE TRACK/SESSION available to struct burn_drive
2006.10.31.115606 [338]
libburn/transport.h
libburn/spc.c
libburn/mmc.c
libburn/write.h
libburn/write.c
libburn/sector.c
libburn/libdax_msgs.h
libburn/sg.h
libburn/sg-linux.c
cdrskin/cdrskin.c
Made single track TAO work (sector i/o still wants fixed size, though)
2006.10.31.184736 [339]
libburn/sector.c
libburn/source.c
libburn/structure.h
libburn/structure.c
libburn/write.c
cdrskin/cdrskin.c
Made single track TAO work without fixed size (compile -experimental)
2006.11.01.163934 [340]
libburn/libburn.h
libburn/source.c
libburn/write.h
libburn/write.c
libburn/structure.c
libburn/structure.h
libburn/sector.c
cdrskin/cdrskin.c
cdrskin/compile_cdrskin.sh
Adapted cdrskin pacifier to possibly unknown track size
2006.11.01.172004 [341]
configure.ac
bootstrap
test/libburner.c
Repaired broken macro settings during Linux build
2 Nov 2006 [342]
cdrskin/README
Mentioned -tao and experimental compile
2006.11.02.211816 [343]
libburn/libburn.h
libburn/write.c
cdrskin/cdrskin.c
Installed status communications about closing session ("Fixating")
3 Nov 2006 [344]
test/libburner.c
Changed status report during blanking (there are no "sectors")
2006.11.03.063307 [345]
cdrskin/cdrskin.c
Removed some obsolete debugging messages
2006.11.03.151137 [346]
libburn/structure.h
libburn/structure.c
libburn/write.h
libburn/write.c
libburn/sector.c
libburn/libdax_msgs.h
Installed decent abort behavior with TAO
2006.11.03.202403 [347]
libburn/write.c
Enabled TAO for multiple -data tracks (-audio still ends after 0 bytes)
2006.11.04.092909 [348]
libburn/spc.c
libburn/sector.c
Enabled audio tracks with TAO
2006.11.02.140329 (pl01) [351 tags/CdrskinZeroTwoFourPlZeroOne]
../cdrskin-0.2.4.patch01/configure.ac
../cdrskin-0.2.4.patch01/bootstrap
../cdrskin-0.2.4.patch01/cdrskin/README
../cdrskin-0.2.4.patch01/cdrskin/add_ts_changes_to_libburn_0_2_4_patch01
../cdrskin-0.2.4.patch01/cdrskin/cdrskin_timestamp.h
../cdrskin-0.2.4.patch01/test/libburner.c
Revoked autotools aspect of revision 290
2006.11.06.073810 [352]
cdrskin/cdrskin.c
cdrskin/cdrskin_eng.html
cdrskin/changelog.txt
Adapted documentation to reflect experimental TAO mode
------------------------------------ cycle - cdrskin-0.2.5 - 2006.11.06.085056
2006.11.06.114159 [353]
libburn/libburn.h
libburn/spc.c
libburn/options.c
cdrskin/cdrskin.c
New API burn_write_opts_set_multi(). (But libburn cannot burn next session yet)
2006.11.06.121409 [354]
cdrskin/cdrskin.c
Made -toc on multiple sessions more compatible
2006.11.06.155237 [355]
libburn/libburn.h
libburn/drive.c
libburn/write.c
libburn/mmc.c
libburn/sg-linux.c
cdrskin/cdrskin.c
Made CD with unclosed track blankable (by -force)
2006.11.06.195743 [356]
libburn/transport.h
libburn/mmc.c
libburn/spc.c
libburn/write.c
libburn/sg-linux.c
Cared for some SCSI error conditions which were ignored up to now
2006.11.07.114514 [357]
cdrskin/cdrskin.c
Made -tao default for single track or stdin, -sao for any other multi-track
7 Nov 2006 [358]
cdrskin/cdrskin_eng.html
cdrskin/changelog.txt
Prepared next cdrskin-0.2.5 upload cycle
7 Nov 2006 [359]
cdrskin/changelog.txt
cdrskin/README
cdrskin/wiki_plain.txt
Updated documentation about TAO
2006.11.07.152018 [360]
cdrskin/cdrskin.c
cdrskin/changelog.txt
Updated documentation about TAO
------------------------------------ cycle - cdrskin-0.2.5 - 2006.11.07.152018
* Enabled TAO
2006.11.08.165648 [361]
cdrskin/cdrfifo.h
cdrskin/cdrfifo.c
cdrskin/cdrskin.c
Avoided error message and nonzero exit with trailing trash on .wav
8 Nov 2006 [362]
cdrskin/cdrskin_eng.html
Mentioned bug fix about trailing trash
2006.11.08.172918 [363]
libburn/write.c
Made track write counter of SAO count rather too much than too few bytes
8 Nov 2006 [364]
cdrskin/changelog.txt
Prepared next cdrskin-0.2.5 upload cycle
------------------------------------ cycle - cdrskin-0.2.5 - 2006.11.08.181016
* Bug fixed: Trailing trash appended to .wav files caused error message
and, if exceeding fifo size, could even stall a burn.
2006.11.09.112832 [365]
cdrskin/cdrskin.c
Check desired write and block type with burn_drive_info.*_block_types
2006.11.09.113729 [366]
libburn/sg-linux.c
Silenced SCSI error (debugging) messages about missing media
2006.11.09.151431 [367]
cdrskin/cdrskin.c
Corrected first speed measurement report in TAO mode (which was random)
2006.11.09.193030 [368]
libburn/libburn.h
libburn/write.c
cdrskin/cdrskin.c
Experimentally enabled burning to BURN_DISC_APPENDABLE (tested with TAO only)
2006.11.10.093843 [369]
cdrskin/cdrskin.c
doc/comments
Expressing more self-confidence
2006.11.10.172212 [370]
cdrskin/cdrskin.c
Provisory -msinfo (very verbous on stderr)
2006.11.10.184047 [371]
cdrskin/cdrskin.c
Made it work with fifos and other non-plain files as track sources
2006.11.10.185209 [372]
cdrskin/cdrskin.c
Read -msinfo from first track of last session and not from last track
2006.11.11.122402 [373]
libburn/libburn.h
libburn/transport.h
libburn/mmc.h
libburn/mmc.c
libburn/write.c
libburn/drive.c
libburn/libdax_msgs.h
New API function burn_disc_track_lba_nwa()
2006.11.11.122907 [374] [375]
cdrskin/cdrskin.c
Implemented not so provisory -msinfo
2006.11.11.124020 [376] [377]
cdrskin/cdrskin.c
Reacted on some warnings of gcc -O2
2006.11.11.134752 [378]
cdrskin/cdrskin.c
Implemented handling of unsuitable disk states with -msinfo
2006.11.11.152037 [379]
cdrskin/cdrskin.c
Demanded (for now) -tao for writing to appendable CDs
2006.11.11.152748 [380]
cdrskin/cdrskin.c
Generally enabled -multi, -msinfo and writing to appendable CDs in TAO mode
11 Nov 2006 [381]
cdrskin/changelog.txt
Prepared next cdrskin-0.2.5 cycle
11 Nov 2006 [382]
cdrskin/cdrskin_eng.html
cdrskin/README
Updated docs about multi-session
------------------------------------ cycle - cdrskin-0.2.5 - 2006.11.11.163625
* Multi-session CDs (for now restricted to write mode TAO), -multi, -msinfo
* Bug fixed: False speed with first pacifier cycle. Potential SIGFPE by NaN.
2006.11.12.085808 [383]
libburn/mmc.c
Made speed 0 in burn_drive_set_speed() really maximum speed (i.e. FFFFh)
2006.11.12.113629 [384]
cdrskin/cdrskin.c
Made SAO preferrable default write mode, kept TAO as default where needed
2006.11.12.152723 [385]
libburn/mmc.c
libburn/libdax_msgs.h
Reacted on error condition during write operation
2006.11.12.185342 [386]
cdrskin/cdrskin.c
Made -toc on blank CD exit with value 0 (rather than 7 with no media)
13 Nov 2006 [390]
README
cdrskin/add_ts_changes_to_libburn_0_2_5
cdrskin/cdrskin_eng.html
Changed SVN URLs to reflect new structure
13 Nov 2006 [391]
README
Refered to both libburn and libisofs in SVN description, updated history
------------------------------------ cycle - cdrskin-0.2.5 - 2006.11.13.122418
* Enabled named pipes and other non-plain file types as track sources
(actually already in previous cycle)
* Bug fixed: Default speed was not highest possible but announced as "MAX"
* SAO is preferred default write mode, TAO is default when needed
2006.11.13.122418 [392]
cdrskin/changelog.txt
Next cdrskin-0.2.5 cycle
13 Nov 2006 [393]
cdrskin/cdrskin_eng.html
Adjusted description of write mode default
13 Nov 2006 [394]
Makefile.am
configure.ac
Removed references to libisofs
14 Nov 2006 [399]
README
Changed references to libisofs
14 Nov 2006 [400]
cdrskin/README
Corrected a typo reported by George Danchev
2006.11.14.104023 [401]
cdrskin/cdrskin.c
Implemented try to find on restricted drives a suitable write mode as default
14 Nov 2006 [402]
libburn/libburn.h
Fixed a wrong name in API description
15 Nov 2006 [403]
libburn/write.h
libburn/write.c
Prepared tests for eventual drive which might support SAO to appendable CD
15 Nov 2006 [404]
libburn/sg-linux.c
Enhanced optional SCSI command logging
2006.11.15.091329 [405]
cdrskin/cdrskin.c
Adjusted some texts to new multi-session situation
2006.11.15.170927 [406]
libburn/sg.h
libburn/sg-linux.c
libburn/sg-freebsd.c
+ libburn/sg-freebsd-port.c
libburn/spc.h
libburn/spc.c
libburn/drive.c
Made portability clarifications
15 Nov 2006 [407]
libburn/sg-linux.c
libburn/sg-freebsd-port.c
Narrowed system specific part of enumerate_common()
2006.11.16.111656 [408] [409]
Makefile.am
+ libburn/os.h
+ libburn/os-linux.h
+ libburn/os-freebsd.h
libburn/sg.h
libburn/sg.c
libburn/transport.h
libburn/cleanup.c
libburn/sg-linux.c
libburn/sg-freebsd-port.c
cdrskin/cleanup.c
cdrskin/compile_cdrskin.sh
Made consolidaed operating system adapters for ease of porting
2006.11.16.133951 [410]
libburn/sg-linux.c
libburn/sg-freebsd-port.c
Polished porting hints and self-compliance to newly established specs
16 Nov 2006 [411]
libburn/sg-linux.c
libburn/sg-freebsd-port.c
Polished porting hints
16 Nov 2006 [412]
test/libburner.c
Obsoleted --stdin_size by automatic TAO, cared for non-plain track files
16 Nov 2006 [413]
doc/comments
Updated help text of libburner
17 Nov 2006 [414]
Makefile.am
+ test/telltoc.c
Created info retrieval companion for libburner
17 Nov 2006 [415]
test/libburner.c
Enabled multi-session with libburner
17 Nov 2006 [416]
Makefile.am
- test/toc.c
Obsoleted old test program
17 Nov 2006 [417] [418]
test/telltoc.c
Shifted a comma
2006.11.18.194606 [419]
libburn/transport.h
libburn/sbc.h
libburn/sbc.c
libburn/drive.c
Test wether SCSI 1Bh START UNIT would be helpful with ticket 90
2006.11.19.114413 [420]
libburn/libburn.h
libburn/mmc.c
libburn/sector.c
libburn/write.c
cdrskin/cdrskin.c
Implemented libburn builtin fine granulated drive buffer min-fill recording
2006.11.19.162900 [421]
cdrskin/cdrskin.c
Avoided self contradiction with "Min drive buffer fill"
2006.11.19.163646 [422]
cdrskin/cdrskin.c
Fixed missing brackets from revison 421
2006.11.20.090207 [423]
libburn/sector.c
Silenced compiler warnings
2006.11.20.090503 [424]
libburn/drive.c
Removed a redundant d->start_unit() of revision 419
------------------------------------ cycle - cdrskin-0.2.5 - 2006.11.20.092808
* libisofs unbundled from libburn+cdrskin
* Hints for porting to other operating systems are now in sg-*.c
20 Nov 2006 [425]
cdrskin/changelog.txt
Next cdrskin-0.2.5 cycle
2006.11.20.132717 [426]
cdrskin/cdrskin.c
cdrskin/cdrfifo.h
cdrskin/cdrfifo.c
cdrskin/wiki_plain.txt
Implemented new option fifo_start_at=
20 Nov 2006 [427]
cdrskin/wiki_plain.txt
Updated in respect to multi-session
2006.11.22.122228 [428]
libburn/spc.h
libburn/spc.c
Coordinated scsi_notify_error() and scsi_error()
------------------------------------ cycle - cdrskin-0.2.5 - 2006.11.22.142517
23 Nov 2006 [433]
cdrskin/changelog.txt
Last cdrskin-0.2.5 cycle
23 Nov 2006 [434] [tag ]
- test/burn.c
- test/master.c
- test/tree.py
- test/tree.pyc
- test/rip.c
Removed obsolete test programs
2006.11.23.102340 [435] [tag ]
Makefile.am
cdrskin/compile_cdrskin.sh
cdrskin/cdrskin.c
cdrskin/cdrskin_eng.html
cdrskin/README
cdrskin/wiki_plain.txt
+ cdrskin/add_ts_changes_to_libburn_0_2_6
+ cdrskin/add_ts_changes_to_libburn_0_2_7
- cdrskin/add_ts_changes_to_libburn_0_2_4
- cdrskin/add_ts_changes_to_libburn_0_2_5
Version leap to 0.2.6
2006.11.24.121745 [437]
Version leap to 0.2.7
2006.12.16.090001 []
Makefile.am
+ cdrskin-0.2.6/cdrskin/cdrskin.1
cdrskin-0.2.6/cdrskin/README
cdrskin-0.2.6/cdrskin/cdrskin_eng.html
cdrskin-0.2.6/cdrskin/changelog.txt
cdrskin-0.2.6/cdrskin/cdrskin_timestamp.h
Backported manpage to libburn-0.2.6 -> libburn-0.2.6.2
2006 []
Clear outdated persistent read buffer after small CD image was read (ticket 57)
----------------------------------------- long term intentions:

View File

@ -23,31 +23,27 @@ typedef void (*sighandler_t)(int);
#include "cleanup.h"
#ifdef __FreeBSD__
#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, 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", "SIGPROF", "SIGSYS", "SIGTRAP",
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
};
static int signal_list_count= 23;
#else /* __FreeBSD__ */
/* Signals to be caught */
static int signal_list[]= {
static int signal_list[]= {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
@ -55,7 +51,7 @@ static int signal_list[]= {
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
};
static char *signal_name_list[]= {
static char *signal_name_list[]= {
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
@ -65,15 +61,17 @@ static char *signal_name_list[]= {
};
static int signal_list_count= 24;
#endif /* ! __FreeBSD__ */
/* Signals not to be caught */
static int non_signal_list[]= {
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1
};
};
static int non_signal_list_count= 4;
#endif /* Cleanup_has_no_libburn_os_H */
/* run time dynamic part */
static char cleanup_msg[4096]= {""};
static int cleanup_exiting= 0;

View File

@ -6,7 +6,8 @@
debug_opts=
def_opts=
libvers="-DCdrskin_libburn_0_2_3"
largefile_opts="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1"
libvers="-DCdrskin_libburn_0_2_6"
cleanup_src_or_obj="libburn/cleanup.o"
libdax_msgs_o="libburn/libdax_msgs.o"
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
@ -31,16 +32,16 @@ do
libvers="-DCdrskin_libburn_cvs_A60220_tS"
libdax_audioxtr_o=
libdax_msgs_o="libburn/message.o"
cleanup_src_or_obj="cdrskin/cleanup.c"
elif test "$i" = "-libburn_0_2_2"
cleanup_src_or_obj="-DCleanup_has_no_libburn_os_H cdrskin/cleanup.c"
elif test "$i" = "-libburn_0_2_6"
then
libvers="-DCdrskin_libburn_0_2_2"
libdax_audioxtr_o=
libdax_msgs_o="libburn/message.o"
cleanup_src_or_obj="cdrskin/cleanup.c"
elif test "$i" = "-libburn_0_2_3"
libvers="-DCdrskin_libburn_0_2_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_2_3"
libvers="-DCdrskin_libburn_0_2_6"
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
libdax_msgs_o="libburn/libdax_msgs.o"
cleanup_src_or_obj="libburn/cleanup.o"
@ -50,6 +51,10 @@ do
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
@ -74,8 +79,9 @@ do
echo " -compile_cdrfifo compile program cdrskin/cdrfifo."
echo " -compile_dewav compile program test/dewav without libburn."
echo " -cvs_A60220 set macro to match libburn-CVS of 20 Feb 2006."
echo " -libburn_0_2_2 set macro to match libburn-0.2.2."
echo " -libburn_0_2_3 set macro to match current libburn-SVN."
echo " -libburn_0_2_6 set macro to match libburn-0.2.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."
@ -99,7 +105,14 @@ 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 $warn_opts -I. $static_opts $debug_opts $libvers $def_opts \
cc -I. \
$warn_opts \
$static_opts \
$debug_opts \
$libvers \
$largefile_opts \
$def_opts \
\
-DCdrskin_build_timestamP='"'"$timestamp"'"' \
\
-o cdrskin/cdrskin \

View File

@ -2,7 +2,7 @@
cdrskin Wiki - plain text copy
--------------------------------------------------------------------------
cdrskin-0.2.3 is the cdrecord compatibility middleware of libburn.
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
@ -12,12 +12,16 @@ Its future ability to burn DVD media depends on the development of libburn.
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 cdrskin/README .
can be found in cdrskin/README . Online available as :
http://libburn.pykix.org/browser/trunk/cdrskin/README?format=raw
About libburn API for burning CD: http://libburn-api.pykix.org
--------------------------------------------------------------------------
cdrskin with CD media fails to match its paragon cdrecord on two major
fields: convenient TAO burn mode and multi session.
Appending sessions to an unclosed CD is restricted to write mode TAO.
(Users who have a burner which succeeds with a follow-up session via
cdrecord -sao : please contact us.)
cdrskin does not provide DVD burning yet. See advise to use dvd+rw-tools
at the end of this text.
@ -32,9 +36,9 @@ 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.
For these options you may expect program behavior that is roughly the
same as described in original man 1 cdrecord .
@ -42,9 +46,9 @@ same as described in original man 1 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.
Those have no man page yet. Some are very experimental and should only be
@ -56,11 +60,10 @@ 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
libburn-drive-number, sysadmin-device-file, permissions, vendor, type
{{{
0 dev='/dev/sg0' 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
@ -74,7 +77,7 @@ has to offer both, r- and w-permission.
--------------------------------------------------------------------------
--fifo_start_empty is a throughput enhancer for unsteady data streams
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.
@ -98,10 +101,16 @@ 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_empty makes cdrskin start burning without waiting for the
FIFO to be full resp. the data stream to end. It can make use of the
seconds spend with drive preparation and lead-in, it risks a few drive
buffer underruns at the beginning of burn - but modern drives stand this.
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.
@ -125,6 +134,10 @@ tao_to_sao_tsize=<num> allows the - actually unsupported - cdrecord option
-tao and defines a default track size to be used if - as custom with -tao -
no option tsize=# is given.
Since -tao is supported in cdrskin-0.2.6 the TAO-to-SAO workaround has become
quite obsolete. Nevertheless, tao_to_sao_tsize= allows to preset a default
size for SAO mode which is in effect only if no track size is available.
As in general with cdrskin tsize=# the data source does not have to provide
the full annouced amount of data. Missing data will be padded up by 0-bytes.
Surplus data is supposed to cause an error, though. The burn will then
@ -147,15 +160,15 @@ 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 .

View File

@ -1,4 +1,4 @@
AC_INIT([libburn], [0.2.3], [http://libburn.pykix.org])
AC_INIT([libburn], [0.2.6.2], [http://libburn.pykix.org])
AC_PREREQ([2.50])
dnl AC_CONFIG_HEADER([config.h])
@ -7,7 +7,11 @@ AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([subdir-objects])
AM_CONFIG_HEADER(config.h)
dnl A61101 This breaks Linux build (makes 32 bit off_t)
dnl http://sourceware.org/autobook/autobook/autobook_96.html says
dnl one must include some config.h and this was a pitfall.
dnl So why dig the pit at all ?
dnl AM_CONFIG_HEADER(config.h)
dnl Making releases:
dnl BURN_MICRO_VERSION += 1;
@ -21,7 +25,7 @@ dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
dnl
BURN_MAJOR_VERSION=0
BURN_MINOR_VERSION=2
BURN_MICRO_VERSION=3
BURN_MICRO_VERSION=6.2
BURN_INTERFACE_AGE=0
BURN_BINARY_AGE=0
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
@ -108,6 +112,5 @@ AC_CONFIG_FILES([
doc/doxygen.conf
version.h
libburn-1.pc
libisofs-1.pc
])
AC_OUTPUT

View File

@ -13,10 +13,10 @@ 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 and we will have a hard time to widen
this for now, because of our history. The project could need advise from or
membership of skilled kernel people and people who know how to talk CD/DVD
drives into doing things.
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 do have a workable code base for burning data CDs, though. The burn API is
quite comprehensively documented and can be used to build a presentable
@ -91,9 +91,8 @@ stay upward compatible for a good while.
@subsection libburner-help Libburner --help
<pre>
Usage: test/libburner
[--drive <address>|<driveno>|"-"]
[--blank_fast|--blank_full] [--audio]
[--try_to_simulate] [--stdin_size <bytes>]
[--drive <address>|<driveno>|"-"] [--audio]
[--blank_fast|--blank_full] [--try_to_simulate]
[<one or more imagefiles>|"-"]
Examples
A bus scan (needs rw-permissions to see a drive):
@ -110,7 +109,7 @@ Burn two audio tracks
test/libburner --drive /dev/hdc --audio track1.cd track2.cd
Burn a compressed afio archive on-the-fly, pad up to 700 MB:
( cd my_directory ; find . -print | afio -oZ - ) | \
test/libburner --drive /dev/hdc --stdin_size 734003200 -
test/libburner --drive /dev/hdc -
To be read from *not mounted* CD via: afio -tvZ /dev/hdc
Program tar would need a clean EOF which our padded CD cannot deliver.
</pre>

View File

@ -56,8 +56,8 @@ WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = libburn libisofs doc test
FILE_PATTERNS = libburn.h libisofs.h comments libburner.c
INPUT = libburn doc test
FILE_PATTERNS = libburn.h comments libburner.c
RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO

View File

@ -23,31 +23,27 @@ typedef void (*sighandler_t)(int);
#include "cleanup.h"
#ifdef __FreeBSD__
#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, 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", "SIGPROF", "SIGSYS", "SIGTRAP",
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
};
static int signal_list_count= 23;
#else /* __FreeBSD__ */
/* Signals to be caught */
static int signal_list[]= {
static int signal_list[]= {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
@ -55,7 +51,7 @@ static int signal_list[]= {
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
};
static char *signal_name_list[]= {
static char *signal_name_list[]= {
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
@ -65,15 +61,17 @@ static char *signal_name_list[]= {
};
static int signal_list_count= 24;
#endif /* ! __FreeBSD__ */
/* Signals not to be caught */
static int non_signal_list[]= {
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1
};
};
static int non_signal_list_count= 4;
#endif /* Cleanup_has_no_libburn_os_H */
/* run time dynamic part */
static char cleanup_msg[4096]= {""};
static int cleanup_exiting= 0;

View File

@ -52,7 +52,7 @@ void burn_drive_free(struct burn_drive *d)
return;
/* ts A60822 : close open fds before forgetting them */
if (burn_drive_is_open(d))
sg_close_drive(d);
d->release(d);
free((void *) d->idata);
free((void *) d->mdata);
if(d->toc_entry != NULL)
@ -160,6 +160,7 @@ int burn_drive_grab(struct burn_drive *d, int le)
d->load(d);
d->lock(d);
d->start_unit(d);
/* ts A61020 : this was BURN_DISC_BLANK as pure guess */
d->status = BURN_DISC_UNREADY;
@ -578,8 +579,10 @@ int burn_drive_scan_sync(struct burn_drive_info *drives[],
#endif /* 0 */
/* refresh the lib's drives */
sg_enumerate();
ata_enumerate();
/* ts A61115 : formerly sg_enumerate(); ata_enumerate(); */
scsi_enumerate_drives();
count = burn_drive_count();
if (count)
*drives =
@ -1176,6 +1179,16 @@ int burn_disc_pretend_blank(struct burn_drive *d)
return 1;
}
/* ts A61106 API function */
int burn_disc_pretend_full(struct burn_drive *d)
{
if (d->status != BURN_DISC_UNREADY &&
d->status != BURN_DISC_UNSUITABLE)
return 0;
d->status = BURN_DISC_FULL;
return 1;
}
/* ts A61021: new API function */
int burn_disc_read_atip(struct burn_drive *d)
{
@ -1192,3 +1205,31 @@ int burn_disc_read_atip(struct burn_drive *d)
return 1;
}
/* ts A61110 : new API function */
int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
int trackno, int *lba, int *nwa)
{
int ret;
if (burn_drive_is_released(d)) {
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x0002011b,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Attempt to read track info from ungrabbed drive",
0, 0);
return -1;
}
if (d->busy != BURN_DRIVE_IDLE) {
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x0002011c,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Attempt to read track info from busy drive",
0, 0);
return -1;
}
if (o!=NULL)
d->send_write_parameters(d, o);
ret = d->get_nwa(d, trackno, lba, nwa);
return ret;
}

View File

@ -7,6 +7,7 @@
expressing a file or stream size.
XXX we should enforce 64-bitness for off_t
ts A61101 : this is usually done by the build system (if it is not broken)
*/
#include <sys/types.h>
@ -40,6 +41,10 @@ struct burn_session;
/** References a single track on a disc */
struct burn_track;
/* ts A61111 */
/** References a set of write parameters */
struct burn_write_opts;
/** Session format for normal audio or data discs */
#define BURN_CDROM 0
/** Session format for obsolete CD-I discs */
@ -216,7 +221,16 @@ enum burn_drive_status
/** The drive is erasing a disc */
BURN_DRIVE_ERASING,
/** The drive is being grabbed */
BURN_DRIVE_GRABBING
BURN_DRIVE_GRABBING,
/* ts A61102 */
/** The drive gets written zeroes before the track payload data */
BURN_DRIVE_WRITING_PREGAP,
/** The drive is told to close a track (TAO only) */
BURN_DRIVE_CLOSING_TRACK,
/** The drive is told to close a session (TAO only) */
BURN_DRIVE_CLOSING_SESSION
};
/** Information about a track on a disc - this is from the q sub channel of the
@ -374,9 +388,11 @@ struct burn_progress {
int index;
/** The starting logical block address */
int start_sector;
/** The number of sector */
/** On write: The number of sectors.
On blank: 0x10000 as upper limit for relative progress steps */
int sectors;
/** The current sector being processed */
/** On write: The current sector being processed.
On blank: Relative progress steps 0 to 0x10000 */
int sector;
/* ts A61023 */
@ -384,6 +400,14 @@ struct burn_progress {
unsigned buffer_capacity;
/** The free space in the drive buffer (might be slightly outdated) */
unsigned buffer_available;
/* ts A61119 */
/** The number of bytes sent to the drive buffer */
off_t buffered_bytes;
/** The minimum number of buffered bytes. (Caution: Before surely
one buffer size of bytes was processed, this value is 0xffffffff.)
*/
unsigned buffer_min_fill;
};
/** Initialize the library.
@ -629,7 +653,7 @@ void burn_drive_release(struct burn_drive *drive, int eject);
/** Returns what kind of disc a drive is holding. This function may need to be
called more than once to get a proper status from it. See burn_status
called more than once to get a proper status from it. See burn_disc_status
for details.
@param drive The drive to query for a disc.
@return The status of the drive, or what kind of disc is in it.
@ -648,6 +672,15 @@ enum burn_disc_status burn_disc_get_status(struct burn_drive *drive);
int burn_disc_pretend_blank(struct burn_drive *drive);
/* ts A61106 */
/** WARNING: This overrides the safety measures against unsuitable media.
Sets the drive status to BURN_DISC_FULL if it is BURN_DISC_UNREADY
or BURN_DISC_UNSUITABLE. Thus marking media as blankable which actually
failed to declare themselves either blank or (partially) filled.
*/
int burn_disc_pretend_full(struct burn_drive *drive);
/* ts A61021 */
/** Reads ATIP information from inserted media. To be obtained via
burn_drive_get_write_speed(), burn_drive_get_min_write_speed(),
@ -672,6 +705,21 @@ int burn_disc_read_atip(struct burn_drive *drive);
int burn_drive_get_start_end_lba(struct burn_drive *drive,
int *start_lba, int *end_lba, int flag);
/* ts A61110 */
/** Read start lba and Next Writeable Address of a track from media.
Usually a track lba is obtained from the result of burn_track_get_entry().
This call retrieves an updated lba, eventual nwa, and can address the
invisible track to come.
The drive must be grabbed for this call. One may not issue this call
during ongoing burn_disc_write() or burn_disc_erase().
@param d The drive to query.
@param o If not NULL: write parameters to be set on drive before query
@param trackno 0=next track to come, >0 number of existing track
@return 1=nwa is valid , 0=nwa is not valid , -1=error
*/
int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
int trackno, int *lba, int *nwa);
/** Tells whether a disc can be erased or not
@return Non-zero means erasable
@ -721,6 +769,7 @@ void burn_read_opts_free(struct burn_read_opts *opts);
*/
void burn_disc_erase(struct burn_drive *drive, int fast);
/* ts A61109 : this is defunct */
/** Read a disc from the drive and write it to an fd pair. The drive must be
grabbed successfully BEFORE calling this function. Always ensure that the
drive reports a status of BURN_DISC_FULL before calling this function.
@ -729,10 +778,9 @@ void burn_disc_erase(struct burn_drive *drive, int fast);
*/
void burn_disc_read(struct burn_drive *drive, const struct burn_read_opts *o);
/** Write a disc in the drive. The drive must be grabbed successfully BEFORE
/** Write a disc in the drive. The drive must be grabbed successfully before
calling this function. Always ensure that the drive reports a status of
BURN_DISC_BLANK or BURN_STATUS_FULL (to append a new session to the
disc) before calling this function.
BURN_DISC_BLANK before calling this function.
@param o The options for the writing operation.
@param disc The struct burn_disc * that described the disc to be created
*/
@ -917,10 +965,19 @@ struct burn_source *burn_file_source_new(const char *path,
*/
struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size);
/** Tells how long a track will be on disc */
/** Tells how long a track will be on disc
>>> NOTE: Not reliable with tracks of undefined length
*/
int burn_track_get_sectors(struct burn_track *);
/* ts A61101 */
/** Tells how many source bytes have been read and how many data bytes have
been written by the track during burn */
int burn_track_get_counters(struct burn_track *t,
off_t *read_bytes, off_t *written_bytes);
/** Sets drive read and write speed
@param d The drive to set speed for
@param read Read speed in k/s (0 is max)
@ -985,6 +1042,15 @@ void burn_write_opts_set_has_mediacatalog(struct burn_write_opts *opts, int has_
void burn_write_opts_set_mediacatalog(struct burn_write_opts *opts, unsigned char mediacatalog[13]);
/* ts A61106 */
/* Sets the multi flag which eventually marks the emerging session as not being
the last one and thus creating a BURN_DISC_APPENDABLE media.
@param multi 1=media will be appendable, 0=media will be closed (default)
*/
void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi);
/** Sets whether to read in raw mode or not
@param opts The read opts to change
@param raw_mode If non-zero, reading will be done in raw mode, so that everything in the data tracks on the

View File

@ -303,7 +303,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x00020006 (FATAL,HIGH) = Too many scsi siblings
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
From the hunt on Assert:
General library operations:
0x00020101 (WARNING,HIGH) = Cannot find given worker item
0x00020102 (SORRY,HIGH) = A drive operation is still going on
@ -320,7 +320,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
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
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
@ -329,6 +329,12 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
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 condition on write
libdax_audioxtr:
0x00020200 (SORRY,HIGH) = Cannot open audio source file

View File

@ -20,6 +20,15 @@
#include "structure.h"
#include "options.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 */
/* ts A61005 */
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
@ -90,7 +99,9 @@ void mmc_send_cue_sheet(struct burn_drive *d, struct cue_sheet *s)
d->issue_command(d, &c);
}
int mmc_get_nwa(struct burn_drive *d)
/* 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)
{
struct buffer buf;
struct command c;
@ -101,13 +112,27 @@ int mmc_get_nwa(struct burn_drive *d)
c.oplen = sizeof(MMC_TRACK_INFO);
memcpy(c.opcode, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO));
c.opcode[1] = 1;
c.opcode[5] = 0xFF;
if(trackno<=0)
c.opcode[5] = 0xFF;
else
c.opcode[5] = trackno;
c.page = &buf;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
data = c.page->data;
return (data[12] << 24) + (data[13] << 16)
*lba = (data[8] << 24) + (data[9] << 16)
+ (data[10] << 8) + data[11];
*nwa = (data[12] << 24) + (data[13] << 16)
+ (data[14] << 8) + data[15];
/* ts A61106 : MMC-1 Table 142 : NWA_V = NWA Valid Flag */
if (!(data[7]&1)) {
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
"mmc_get_nwa: Track Info Block: NWA_V == 0", 0, 0);
return 0;
}
return 1;
}
/* ts A61009 : function is obviously unused. */
@ -158,14 +183,13 @@ void mmc_close(struct burn_drive *d, int session, int track)
mmc_function_spy("mmc_close");
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
"HOW THAT ? mmc_close() was called", 0, 0);
c.retry = 1;
c.oplen = sizeof(MMC_CLOSE);
memcpy(c.opcode, MMC_CLOSE, sizeof(MMC_CLOSE));
c.opcode[2] = session | !!track;
/* ts A61030 : shifted !!session rather than or-ing plain session */
c.opcode[2] = ((!!session)<<1) | !!track;
c.opcode[4] = track >> 8;
c.opcode[5] = track & 0xFF;
c.page = NULL;
@ -230,6 +254,14 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
struct command c;
int len;
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
static int tee_fd= -1;
if(tee_fd==-1)
tee_fd= open("/tmp/libburn_sg_written",
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
#endif /* Libburn_log_in_and_out_streaM */
mmc_function_spy("mmc_write");
pthread_mutex_lock(&d->access_lock);
cancelled = d->cancel;
@ -261,9 +293,35 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
burn_print(12, "%d, %d, %d, %d\n", c->opcode[6], c->opcode[7], c->opcode[8], c->opcode[9]);
*/
/* write(fileno(stderr), c.page->data, c.page->bytes);*/
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
if(tee_fd!=-1) {
write(tee_fd,c.page->data,len*2048);
}
#endif /* Libburn_log_in_and_out_streaM */
d->issue_command(d, &c);
/* ts A61112 : react on eventual error condition */
if (c.error && c.sense[2]!=0) {
/* >>> make this scsi_notify_error() when liberated */
if (c.sense[2]!=0) {
char msg[80];
sprintf(msg,
"SCSI error condition on write : key=%X asc=%2.2Xh ascq=%2.2Xh",
c.sense[2],c.sense[12],c.sense[13]);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002011d,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
}
pthread_mutex_lock(&d->access_lock);
d->cancel = 1;
pthread_mutex_unlock(&d->access_lock);
return BE_CANCELLED;
}
return 0;
}
@ -291,6 +349,7 @@ void mmc_read_toc(struct burn_drive *d)
if (c.error) {
/* ts A61020 : this snaps on non-blank DVD media */
/* ts A61106 : also snaps on CD with unclosed track/session */
/* Very unsure wether this old measure is ok.
Obviously higher levels do not care about this.
DVD+RW burns go on after passing through here.
@ -634,8 +693,12 @@ void mmc_read_sectors(struct burn_drive *d,
len >>= 8;
c.opcode[6] = len & 0xFF;
req = 0xF8;
/* ts A61106 : LG GSA-4082B dislikes this. key=5h asc=24h ascq=00h
if (d->busy == BURN_DRIVE_GRABBING || o->report_recovered_errors)
req |= 2;
*/
c.opcode[10] = 0;
/* always read the subcode, throw it away later, since we don't know
@ -721,6 +784,13 @@ void mmc_set_speed(struct burn_drive *d, int r, int w)
{
struct command c;
/* ts A61112 : MMC standards prescribe FFFFh as max speed.
But libburn.h prescribes 0. */
if (r<=0 || r>0xffff)
r = 0xffff;
if (w<=0 || w>0xffff)
w = 0xffff;
mmc_function_spy("mmc_set_speed");
memcpy(c.opcode, MMC_SET_SPEED, sizeof(MMC_SET_SPEED));
c.retry = 1;
@ -804,6 +874,14 @@ int mmc_read_buffer_capacity(struct burn_drive *d)
(data[4]<<24)|(data[5]<<16)|(data[6]<<8)|data[7];
d->progress.buffer_available =
(data[8]<<24)|(data[9]<<16)|(data[10]<<8)|data[11];
if (d->progress.buffered_bytes >= d->progress.buffer_capacity){
double fill;
fill = d->progress.buffer_capacity
- d->progress.buffer_available;
if (fill < d->progress.buffer_min_fill && fill>=0)
d->progress.buffer_min_fill = fill;
}
return 1;
}
@ -824,6 +902,7 @@ int mmc_setup_drive(struct burn_drive *d)
d->get_nwa = mmc_get_nwa;
d->close_disc = mmc_close_disc;
d->close_session = mmc_close_session;
d->close_track_session = mmc_close;
d->read_buffer_capacity = mmc_read_buffer_capacity;
/* ts A61020 */

View File

@ -37,7 +37,11 @@ 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 *);
int mmc_get_nwa(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 */

View File

@ -152,6 +152,14 @@ void burn_write_opts_set_mediacatalog(struct burn_write_opts *opts,
memcpy(opts->mediacatalog, &mediacatalog, 13);
}
/* ts A61106 */
void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi)
{
opts->multi = !!multi;
}
void burn_read_opts_set_raw(struct burn_read_opts *opts, int raw)
{
opts->raw = raw;
@ -198,3 +206,4 @@ void burn_read_opts_set_hardware_error_retries(struct burn_read_opts *opts,
{
opts->hardware_error_retries = hardware_error_retries;
}

72
libburn/os-freebsd.h Normal file
View File

@ -0,0 +1,72 @@
/* 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
*/
#ifndef BURN_OS_H_INCLUDED
#define BURN_OS_H_INCLUDED 1
/** 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
/* The number of above list items */
#define BURN_OS_NON_SIGNAL_COUNT 4
/* The maximum size for a (SCSI) i/o transaction */
#define BURN_OS_TRANSPORT_BUFFER_SIZE 65536/2
/** 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 { \
union ccb ccb; \
int bufsize, fd; \
unsigned int i; \
int skip_device; \
}; \
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;
#endif /* ! BURN_OS_H_INCLUDED */

63
libburn/os-linux.h Normal file
View File

@ -0,0 +1,63 @@
/* 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
/* The number of above list items */
#define BURN_OS_NON_SIGNAL_COUNT 4
/* The maximum size for a (SCSI) i/o transaction */
#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;
/* 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[LIBBURN_SG_MAX_SIBLINGS];

34
libburn/os.h Normal file
View File

@ -0,0 +1,34 @@
/* 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 */

View File

@ -11,6 +11,7 @@
/* spc command set */
static char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
static char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
static char SBC_START_UNIT[] = { 0x1b, 0, 0, 0, 1, 0 };
void sbc_load(struct burn_drive *d)
{
@ -37,12 +38,28 @@ void sbc_eject(struct burn_drive *d)
d->issue_command(d, &c);
}
/* 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;
memcpy(c.opcode, SBC_START_UNIT, sizeof(SBC_START_UNIT));
c.retry = 1;
c.oplen = sizeof(SBC_START_UNIT);
c.dir = NO_TRANSFER;
c.page = NULL;
d->issue_command(d, &c);
return (c.error==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;
}

View File

@ -8,6 +8,9 @@ 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);

View File

@ -19,6 +19,15 @@
#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;
@ -44,7 +53,8 @@ static void uncook_subs(unsigned char *dest, unsigned char *source)
int sector_get_outmode(enum burn_write_types write_type,
enum burn_block_types block_type)
{
if (write_type == BURN_WRITE_SAO)
/* ts A61103 : extended SAO condition to TAO */
if (write_type == BURN_WRITE_SAO || write_type == BURN_WRITE_TAO)
return 0;
else
switch (block_type) {
@ -81,6 +91,15 @@ 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);
@ -107,10 +126,18 @@ static void get_bytes(struct burn_track *track, int count, unsigned char *data)
valid = track->source->read(track->source, data + curr, count - curr);
} else valid = 0;
if (valid == -1) {
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;
@ -134,6 +161,12 @@ static void get_bytes(struct burn_track *track, int count, unsigned char *data)
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.
*/
@ -152,15 +185,6 @@ ex:;
if(shortage)
memset(data + curr, 0, shortage); /* this is old icculus.org */
if (track->swap_source_bytes == 1) {
/*
{ static int swapping_count= 0;
fprintf(stderr,"\rlibburn_debug: swapping #%d \r",
swapping_count);
swapping_count++;
}
*/
for (i = 1; i < count; i += 2) {
tr = data[i];
data[i] = data[i-1];
@ -171,7 +195,9 @@ ex:;
/* ts A61009 : seems to hand out sector start pointer in opts->drive->buffer
and to count hand outs as well as reserved bytes */
static unsigned char *get_sector(struct burn_write_opts *opts, int inmode)
/* 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;
@ -196,6 +222,15 @@ static unsigned char *get_sector(struct burn_write_opts *opts, int inmode)
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;
@ -208,6 +243,32 @@ static unsigned char *get_sector(struct burn_write_opts *opts, int inmode)
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 */
@ -289,6 +350,8 @@ static void convert_subs(struct burn_write_opts *o, int inmode,
out[0] = ~out[0];
out[1] = ~out[1];
break;
/* ts A61119 : to silence compiler warnings */
default:;
}
}
@ -335,7 +398,7 @@ int sector_toc(struct burn_write_opts *o, int mode)
unsigned char *data;
unsigned char subs[96];
data = get_sector(o, mode);
data = get_sector(o, NULL, mode);
if (data == NULL)
return 0;
/* ts A61010 */
@ -355,7 +418,7 @@ int sector_pregap(struct burn_write_opts *o,
unsigned char *data;
unsigned char subs[96];
data = get_sector(o, mode);
data = get_sector(o, NULL, mode);
if (data == NULL)
return 0;
/* ts A61010 */
@ -375,7 +438,7 @@ int sector_postgap(struct burn_write_opts *o,
unsigned char subs[96];
unsigned char *data;
data = get_sector(o, mode);
data = get_sector(o, NULL, mode);
if (data == NULL)
return 0;
/* ts A61010 */
@ -547,7 +610,7 @@ int sector_lout(struct burn_write_opts *o, unsigned char control, int mode)
unsigned char subs[96];
unsigned char *data;
data = get_sector(o, mode);
data = get_sector(o, NULL, mode);
if (!data)
return 0;
/* ts A61010 */
@ -566,13 +629,19 @@ int sector_data(struct burn_write_opts *o, struct burn_track *t, int psub)
unsigned char subs[96];
unsigned char *data;
data = get_sector(o, t->mode);
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;
}
if (!t->source->read_sub)
subcode_user(o, subs, t->entry->point,
t->entry->control, 1, &t->isrc, psub);
@ -622,6 +691,11 @@ int sector_headers_is_ok(struct burn_write_opts *o, int mode)
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;
@ -650,6 +724,11 @@ void sector_headers(struct burn_write_opts *o, unsigned char *out,
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;
@ -736,7 +815,14 @@ void process_q(struct burn_drive *d, unsigned char *q)
#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);

559
libburn/sg-freebsd-port.c Normal file
View File

@ -0,0 +1,559 @@
/* -*- 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.
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 */
/** 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);
}

View File

@ -1,19 +1,17 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* >>> ts A61021 : for testing the new arrangement of code
please outcomment these defines : */
/* Keeps alive old enumerate_common(). New version delegates much work
/* Revives old enumerate_common(). New version delegates much work
to methods in drive, mmc, spc, and sbc .
*/
#define Scsi_freebsd_make_own_enumeratE 1
/* Keeps alive old sg_enumerate(). New version delegates most work to
/* Revives old scsi_enumerate_drives(). New version delegates most work to
sg_give_next_adr().
*/
#define Scsi_freebsd_old_sg_enumeratE 1
#define Scsi_freebsd_old_scsi_enumeratE 1
#include <assert.h>
@ -59,7 +57,7 @@ int burn_drive_is_banned(char *device_address);
int mmc_function_spy(char * text);
#ifdef Scsi_freebsd_old_sg_enumeratE
#ifdef Scsi_freebsd_old_scsi_enumeratE
int sg_give_next_adr(burn_drive_enumerator_t *idx,
char adr[], int adr_size, int initialize)
@ -78,10 +76,11 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
return (0);
}
#else /* Scsi_freebsd_old_sg_enumeratE */
#else /* Scsi_freebsd_old_scsi_enumeratE */
/* ts A61021 : Moved most code from sg_enumerate under sg_give_next_adr() */
/* Some helper functions for sg_give_next_adr() */
/* 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)
{
@ -172,7 +171,7 @@ int sg_give_next_adr(burn_drive_enumerator_t *idx,
try_item:; /* This spaghetti loop keeps the number of tabs small */
/* Loop content from old sg_enumerate() */
/* Loop content from old scsi_enumerate_drives() */
while (idx->i >= idx->ccb.cdm.num_matches) {
ret = sg_next_enumeration_buffer(idx);
@ -277,7 +276,7 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
return (0);
}
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
#endif /* ! Scsi_freebsd_old_scsi_enumeratE */
int sg_close_drive(struct burn_drive * d)
@ -294,20 +293,10 @@ int sg_drive_is_open(struct burn_drive * d)
return (d->cam != NULL);
}
void ata_enumerate(void)
{
/* ts A61021: Only a dummy function is needed in FreeBSD */
/* The difference between sg and ata should be encapsulated
in sg-linux.c */
;
}
void sg_enumerate(void)
int scsi_enumerate_drives(void)
{
#ifdef Scsi_freebsd_old_sg_enumeratE
#ifdef Scsi_freebsd_old_scsi_enumeratE
union ccb ccb;
int bufsize, fd;
@ -404,7 +393,7 @@ void sg_enumerate(void)
close(fd);
#else /* Scsi_freebsd_old_sg_enumeratE */
#else /* Scsi_freebsd_old_scsi_enumeratE */
burn_drive_enumerator_t idx;
int initialize = 1;
@ -423,7 +412,7 @@ void sg_enumerate(void)
}
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
#endif /* ! Scsi_freebsd_old_scsi_enumeratE */
}
@ -481,6 +470,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
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;
@ -705,64 +695,3 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
return 1;
}
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
int senselen)
{
int key, asc, ascq;
senselen = senselen;
key = sense[2];
asc = sense[12];
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:
burn_print(12, "NO ERROR!\n");
return RETRY;
case 2:
burn_print(1, "not ready\n");
return RETRY;
case 4:
burn_print(1,
"logical unit is in the process of becoming ready\n");
return RETRY;
case 0x20:
if (key == 5)
burn_print(1, "bad opcode\n");
return FAIL;
case 0x21:
burn_print(1, "invalid address or something\n");
return FAIL;
case 0x24:
if (key == 5)
burn_print(1, "invalid field in cdb\n");
else
break;
return FAIL;
case 0x26:
if (key == 5)
burn_print( 1, "invalid field in parameter list\n" );
return FAIL;
case 0x28:
if (key == 6)
burn_print(1,
"Not ready to ready change, medium may have changed\n");
else
break;
return RETRY;
case 0x3A:
burn_print(12, "Medium not present in %s %s\n",
d->idata->vendor, d->idata->product);
d->status = BURN_DISC_EMPTY;
return FAIL;
}
burn_print(1, "unknown failure\n");
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
return FAIL;
}

View File

@ -1,7 +1,64 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* ts A61010 */
/* #include <a ssert.h> */
/*
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: Linux SCSI Generic (sg)
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.
Porting hints are marked by the text "PORTING:".
Send feedback to libburn-hackers@pykix.org .
Hint: You should also look into sg-freebsd-port.c, which is a younger and
in some aspects more straightforward implementation of this interface.
*/
/** PORTING : ------- OS dependent headers and definitions ------ */
#include <errno.h>
#include <unistd.h>
@ -10,9 +67,6 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
/* #include <m alloc.h> ts A61013 : not in Linux man 3 malloc */
#include <string.h>
#include <sys/poll.h>
#include <linux/hdreg.h>
@ -20,6 +74,9 @@
#include <scsi/sg.h>
#include <scsi/scsi.h>
/** PORTING : ------ libburn portable headers and definitions ----- */
#include "transport.h"
#include "drive.h"
#include "sg.h"
@ -30,20 +87,24 @@
#include "toc.h"
#include "util.h"
/* kludge! glibc headers don't define all the SCSI stuff that we use! */
#ifndef SG_GET_ACCESS_COUNT
# define SG_GET_ACCESS_COUNT 0x2289
#endif
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
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);
/* ------------------------------------------------------------------------ */
/* PORTING: Private definitions. Port only if needed by public functions. */
/* (Public functions are listed below) */
/* ------------------------------------------------------------------------ */
static void enumerate_common(char *fname, int bus_no, int host_no,
int channel_no, int target_no, int lun_no);
/* >>> ts A61115 : this needs mending. A Linux aspect shows up in cdrskin. */
/* ts A60813 : storage objects are in libburn/init.c
wether to use O_EXCL
wether to use O_NOBLOCK with open(2) on devices
@ -58,6 +119,12 @@ extern int burn_sg_open_abort_busy;
int mmc_function_spy(char * text);
/* ------------------------------------------------------------------------ */
/* PORTING: Private functions. Port only if needed by public functions */
/* (Public functions are listed below) */
/* ------------------------------------------------------------------------ */
static int sgio_test(int fd)
{
unsigned char test_ops[] = { 0, 0, 0, 0, 0, 0 };
@ -73,45 +140,8 @@ static int sgio_test(int fd)
}
/* ts A60925 : ticket 74 */
int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
{
int ret, os_errno, sevno= LIBDAX_MSGS_SEV_DEBUG;
char msg[4096+100];
if(*fd < 0)
return(0);
ret = close(*fd);
*fd = -1337;
if(ret != -1)
return 1;
os_errno= errno;
if (fname != NULL)
sprintf(msg, "Encountered error when closing drive '%s'",
fname);
else
sprintf(msg, "Encountered error when closing drive");
if (sorry)
sevno = LIBDAX_MSGS_SEV_SORRY;
libdax_msgs_submit(libdax_messenger, driveno, 0x00020002,
sevno, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno, 0);
return 0;
}
int sg_drive_is_open(struct burn_drive * d)
{
/* a bit more detailed case distinction than needed */
if (d->fd == -1337)
return 0;
if (d->fd < 0)
return 0;
return 1;
}
/* ts A60924 */
int sg_handle_busy_device(char *fname, int os_errno)
static int sg_handle_busy_device(char *fname, int os_errno)
{
char msg[4096];
@ -135,87 +165,8 @@ int sg_handle_busy_device(char *fname, int os_errno)
}
/* ts A60922 ticket 33 */
/** 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)
{
/* sg.h : typedef int burn_drive_enumerator_t; */
static int sg_limit = 32, ata_limit = 26;
int baseno = 0;
if (initialize == -1)
return 0;
if (initialize == 1)
*idx = -1;
(*idx)++;
if (*idx >= sg_limit)
goto next_ata;
if (adr_size < 10)
return -1;
sprintf(adr, "/dev/sg%d", *idx);
return 1;
next_ata:;
baseno += sg_limit;
if (*idx - baseno >= ata_limit)
goto next_nothing;
if (adr_size < 9)
return -1;
sprintf(adr, "/dev/hd%c", 'a' + (*idx - baseno));
return 1;
next_nothing:;
baseno += ata_limit;
return 0;
}
int sg_is_enumerable_adr(char *adr)
{
char fname[4096];
int i, ret = 0, first = 1;
while (1) {
ret= sg_give_next_adr(&i, fname, sizeof(fname), first);
if(ret <= 0)
break;
first = 0;
if (strcmp(adr, fname) == 0)
return 1;
}
return(0);
}
/* ts A60926 */
int sg_release_siblings(int sibling_fds[], int *sibling_count)
{
int i;
char msg[81];
for(i= 0; i < *sibling_count; i++)
sg_close_drive_fd(NULL, -1, &(sibling_fds[i]), 0);
if(*sibling_count > 0) {
sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count);
libdax_msgs_submit(libdax_messenger, -1, 0x00020007,
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg, 0,0);
}
*sibling_count = 0;
return 1;
}
/* ts A60926 */
int sg_open_drive_fd(char *fname, int scan_mode)
static int sg_open_drive_fd(char *fname, int scan_mode)
{
int open_mode = O_RDWR, fd;
char msg[81];
@ -266,8 +217,67 @@ int sg_open_drive_fd(char *fname, int scan_mode)
}
/* ts A60925 : ticket 74 */
static int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
{
int ret, os_errno, sevno= LIBDAX_MSGS_SEV_DEBUG;
char msg[4096+100];
if(*fd < 0)
return(0);
ret = close(*fd);
*fd = -1337;
if(ret != -1)
return 1;
os_errno= errno;
if (fname != NULL)
sprintf(msg, "Encountered error when closing drive '%s'",
fname);
else
sprintf(msg, "Encountered error when closing drive");
if (sorry)
sevno = LIBDAX_MSGS_SEV_SORRY;
libdax_msgs_submit(libdax_messenger, driveno, 0x00020002,
sevno, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno, 0);
return 0;
}
/* ts A60926 */
int sg_open_scsi_siblings(char *path, int driveno,
static int sg_release_siblings(int sibling_fds[], int *sibling_count)
{
int i;
char msg[81];
for(i= 0; i < *sibling_count; i++)
sg_close_drive_fd(NULL, -1, &(sibling_fds[i]), 0);
if(*sibling_count > 0) {
sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count);
libdax_msgs_submit(libdax_messenger, -1, 0x00020007,
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg, 0,0);
}
*sibling_count = 0;
return 1;
}
/* ts A60926 */
static int sg_close_drive(struct burn_drive *d)
{
int ret;
if (!burn_drive_is_open(d))
return 0;
sg_release_siblings(d->sibling_fds, &(d->sibling_count));
ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
return ret;
}
/* ts A60926 */
static int sg_open_scsi_siblings(char *path, int driveno,
int sibling_fds[], int *sibling_count,
int host_no, int channel_no, int id_no, int lun_no)
{
@ -324,19 +334,9 @@ failed:;
}
/* ts A60926 */
int sg_close_drive(struct burn_drive *d)
{
int ret;
if (!burn_drive_is_open(d))
return 0;
sg_release_siblings(d->sibling_fds, &(d->sibling_count));
ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
return ret;
}
void ata_enumerate(void)
/** Speciality of Linux: detect non-SCSI ATAPI (EIDE) which will from
then on used used via generic SCSI as is done with (emulated) SCSI drives */
static void ata_enumerate(void)
{
struct hd_driveid tm;
int i, fd;
@ -372,7 +372,9 @@ void ata_enumerate(void)
}
}
void sg_enumerate(void)
/** Detects (probably emulated) SCSI drives */
static void sg_enumerate(void)
{
struct sg_scsi_id sid;
int i, fd, sibling_fds[LIBBURN_SG_MAX_SIBLINGS], sibling_count= 0, ret;
@ -428,6 +430,19 @@ void sg_enumerate(void)
}
}
/* ts A61115 */
/* ----------------------------------------------------------------------- */
/* 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.
*/
/* ts A60923 - A61005 : introduced new SCSI parameters */
/* ts A61021 : moved non os-specific code to spc,sbc,mmc,drive */
static void enumerate_common(char *fname, int bus_no, int host_no,
@ -446,13 +461,18 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
if (ret<=0)
return;
/* PORTING: ------------------- non portable part --------------- */
/* Operating system adapter is Linux Generic SCSI (sg) */
/* Adapter specific handles and data */
out.fd = -1337;
out.sibling_count = 0;
for(i= 0; i<LIBBURN_SG_MAX_SIBLINGS; i++)
out.sibling_fds[i] = -1337;
/* Adapter specific functions */
/* 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;
@ -462,17 +482,116 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
burn_drive_finish_enum(&out);
}
/*
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.
ts A60813: this test is too late. O_EXCL is the stronger solution.
After all the test was disabled already in icculus.org/burn CVS.
/* ts A61115 */
/* ------------------------------------------------------------------------ */
/* PORTING: Public functions. These MUST be ported. */
/* ------------------------------------------------------------------------ */
/** PORTING:
In this Linux implementation, this function mirrors the enumeration
done in sg_enumerate and ata_enumerate(). It would be better to base those
functions on this sg_give_next_adr() but the situation is not inviting.
*/
/* ts A60922 ticket 33 : called from drive.c */
/** 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 former.)
@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)
{
/* sg.h : typedef int burn_drive_enumerator_t; */
static int sg_limit = 32, ata_limit = 26;
int baseno = 0;
if (initialize == -1)
return 0;
if (initialize == 1)
*idx = -1;
(*idx)++;
if (*idx >= sg_limit)
goto next_ata;
if (adr_size < 10)
return -1;
sprintf(adr, "/dev/sg%d", *idx);
return 1;
next_ata:;
baseno += sg_limit;
if (*idx - baseno >= ata_limit)
goto next_nothing;
if (adr_size < 9)
return -1;
sprintf(adr, "/dev/hd%c", 'a' + (*idx - baseno));
return 1;
next_nothing:;
baseno += ata_limit;
return 0;
}
/** Brings all available, not-whitelist-banned, and accessible drives into
libburn's list of drives.
*/
/** PORTING:
If not stricken with an incompletely unified situation like in Linux
one would rather implement this by a loop calling sg_give_next_adr().
If needed with your sg_give_next_adr() results, do a test for existence
and accessability. If burn activities are prone to external interference
on your system it is also necessary to obtain exclusive access locks on
the drives.
Hand over each accepted drive to enumerate_common() resp. its replacement
within your port.
See FreeBSD port sketch sg-freebsd-port.c for such an implementation.
*/
/* ts A61115: replacing call to sg-implementation internals from drive.c */
int scsi_enumerate_drives(void)
{
sg_enumerate();
ata_enumerate();
return 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)
{
/* a bit more detailed case distinction than needed */
if (d->fd == -1337)
return 0;
if (d->fd < 0)
return 0;
return 1;
}
/** 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 fd, count, os_errno= 0, ret;
int fd, os_errno= 0, ret;
/* ts A60813 */
int open_mode = O_RDWR;
@ -495,12 +614,11 @@ int sg_grab(struct burn_drive *d)
if(burn_sg_open_o_nonblock)
open_mode |= O_NONBLOCK;
/* ts A60813
/* ts A60813 - A60822
After enumeration the drive fd is probably still open.
-1337 is the initial value of burn_drive.fd and the value after
relase of drive. Unclear why not the official error return
value -1 of open(2) war used. */
/* ts A60822: was if(d->fd == -1337) { */
if(! burn_drive_is_open(d)) {
/* ts A60821
@ -523,49 +641,34 @@ int sg_grab(struct burn_drive *d)
} else
fd= d->fd;
/* ts A61007 : this is redundant */
/* a ssert(fd != -1337); */
if (fd >= 0) {
/* ts A60814:
according to my experiments this test would work now ! */
/* ts A60926 : this was disabled */
/* Tests with growisofs on kernel 2.4.21 yielded that this
does not help against blocking on busy drives.
*/
/* <<< the old dummy */
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
count = 1;
if (1 == count) {
d->fd = fd;
fcntl(fd, F_SETOWN, getpid());
d->released = 0;
return 1;
}
drive_is_in_use:;
libdax_msgs_submit(libdax_messenger, d->global_index,
0x00020003,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Could not grab drive - already in use", 0, 0);
sg_close_drive(d);
d->fd = -1337;
return 0;
d->fd = fd;
fcntl(fd, F_SETOWN, getpid());
d->released = 0;
return 1;
}
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Could not grab drive", os_errno, 0);
return 0;
drive_is_in_use:;
libdax_msgs_submit(libdax_messenger, d->global_index,
0x00020003,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Could not grab drive - already in use", 0, 0);
sg_close_drive(d);
d->fd = -1337;
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?)
*/
/** 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)
{
/* ts A60821
@ -585,19 +688,54 @@ int sg_release(struct burn_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, no_c_page = 0;
int err;
sg_io_hdr_t s;
/*
#define Libburn_log_sg_commandS 1
*/
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
#ifdef Libburn_log_sg_commandS
/* ts A61030 */
static FILE *fp= NULL;
static int fpcount= 0;
int i;
#endif /* Libburn_log_sg_commandS */
/* <<< ts A60821
debug: for tracing calls which might use open drive fds */
char buf[161];
sprintf(buf,"sg_issue_command d->fd= %d d->released= %d\n",
d->fd,d->released);
mmc_function_spy(buf);
#ifdef Libburn_log_sg_commandS
/* ts A61030 */
if(fp==NULL) {
fp= fopen("/tmp/libburn_sg_command_log","a");
fprintf(fp,"\n-----------------------------------------\n");
}
if(fp!=NULL) {
for(i=0;i<10;i++)
fprintf(fp,"%2.2x ", c->opcode[i]);
fprintf(fp,"\n");
fpcount++;
}
#endif /* Libburn_log_sg_commandS */
/* ts A61010 : with no fd there is no chance to send an ioctl */
if (d->fd < 0) {
c->error = 1;
@ -670,7 +808,9 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
if (s.sb_len_wr) {
if (!c->retry) {
c->error = 1;
return 1;
/* A61106: rather than : return 1 */
goto ex;
}
switch (scsi_error(d, s.sbp, s.sb_len_wr)) {
case RETRY:
@ -685,72 +825,27 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
done = 1;
}
} while (!done);
/* ts A61106 */
ex:;
if (c->error) {
scsi_notify_error(d, c, s.sbp, s.sb_len_wr, 0);
#ifdef Libburn_log_sg_commandS
if(fp!=NULL) {
fprintf(fp,"+++ key=%X asc=%2.2Xh ascq=%2.2Xh\n",
s.sbp[2], s.sbp[12], s.sbp[13]);
fpcount++;
}
#endif /* Libburn_log_sg_commandS */
}
return 1;
}
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
int senselen)
{
int key, asc, ascq;
senselen = senselen;
key = sense[2];
asc = sense[12];
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:
burn_print(12, "NO ERROR!\n");
return RETRY;
case 2:
burn_print(1, "not ready\n");
return RETRY;
case 4:
burn_print(1,
"logical unit is in the process of becoming ready\n");
return RETRY;
case 0x20:
if (key == 5)
burn_print(1, "bad opcode\n");
return FAIL;
case 0x21:
burn_print(1, "invalid address or something\n");
return FAIL;
case 0x24:
if (key == 5)
burn_print(1, "invalid field in cdb\n");
else
break;
return FAIL;
case 0x26:
if ( key == 5 )
burn_print( 1, "invalid field in parameter list\n" );
return FAIL;
case 0x28:
if (key == 6)
burn_print(1,
"Not ready to ready change, medium may have changed\n");
else
break;
return RETRY;
case 0x3A:
burn_print(12, "Medium not present in %s %s\n",
d->idata->vendor, d->idata->product);
d->status = BURN_DISC_EMPTY;
return FAIL;
}
burn_print(1, "unknown failure\n");
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
return FAIL;
}
/* ts A60922 */
/** Try to obtain SCSI address parameters.
/** 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,
@ -795,3 +890,31 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
#endif
return 1;
}
/* ts A60922 ticket 33 : called from drive.c */
/** Tells wether a text is a persistent address as listed by the enumeration
functions.
*/
int sg_is_enumerable_adr(char *adr)
{
char fname[4096];
int ret = 0, first = 1;
burn_drive_enumerator_t idx;
while (1) {
ret= sg_give_next_adr(&idx, fname, sizeof(fname), first);
if(ret <= 0)
break;
first = 0;
if (strcmp(adr, fname) == 0) {
sg_give_next_adr(&idx, fname, sizeof(fname), -1);
return 1;
}
}
sg_give_next_adr(&idx, fname, sizeof(fname), -1);
return(0);
}

View File

@ -1,5 +1,9 @@
/* ts A61013 : It would be nice if autotools could do that job */
/* 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__

View File

@ -3,45 +3,17 @@
#ifndef __SG
#define __SG
#ifdef __FreeBSD__
/* >>> 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. */
struct burn_drive_enumeration_state {
#include "os.h"
#ifdef Scsi_freebsd_old_sg_enumeratE
int dummy;
#else
union ccb ccb;
int bufsize, fd;
unsigned int i;
int skip_device;
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
};
typedef struct burn_drive_enumeration_state burn_drive_enumerator_t;
/* see os.h for name of particular os-*.h where this is defined */
BURN_OS_DEFINE_DRIVE_ENUMERATOR_T
#else /* __FreeBSD__ */
/* <<< just for testing the C syntax */
struct burn_drive_enumeration_state {
int dummy;
};
typedef struct burn_drive_enumeration_state burn_drive_enumerator_tX;
typedef int burn_drive_enumerator_t;
#endif /* ! __FreeBSD__ */
struct burn_drive;
struct command;
enum response
{ RETRY, FAIL };
/* ts A60925 : ticket 74 */
int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry);
/* ts A60922 ticket 33 */
int sg_give_next_adr(burn_drive_enumerator_t *enm_context,
@ -50,19 +22,13 @@ 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);
/* ts A60926 : ticket 33 ++ */
int sg_open_scsi_siblings(char *fname, int driveno,
int sibling_fds[], int *sibling_count,
int host_no, int channel_no, int id_no, int lun_no);
int sg_release_siblings(int sibling_fds[], int *sibling_count);
int sg_close_drive(struct burn_drive *d);
void sg_enumerate(void);
void ata_enumerate(void);
int sg_grab(struct burn_drive *);
int sg_release(struct burn_drive *);
int sg_issue_command(struct burn_drive *, struct command *);
enum response scsi_error(struct burn_drive *, unsigned char *, int);
/* ts A61115 : formerly sg_enumerate();ata_enumerate() */
int scsi_enumerate_drives(void);
int sg_drive_is_open(struct burn_drive * d);
#endif /* __SG */

View File

@ -22,6 +22,10 @@ enum burn_source_status burn_track_set_source(struct burn_track *t,
return BURN_SOURCE_FAILED;
s->refcount++;
t->source = s;
/* ts A61031 */
t->open_ended = (s->get_size(s) <= 0);
return BURN_SOURCE_OK;
}

View File

@ -274,6 +274,11 @@ void spc_sense_write_params(struct burn_drive *d)
mmc_read_disc_info(d);
}
/* 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 should be done by a mmc_ function.
*/
void spc_select_write_params(struct burn_drive *d,
const struct burn_write_opts *o)
{
@ -284,6 +289,13 @@ void spc_select_write_params(struct burn_drive *d,
/* 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));
*/
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
@ -307,8 +319,17 @@ void spc_select_write_params(struct burn_drive *d,
c.page->data[10] = (bufe << 6)
+ (sim << 4)
+ o->write_type;
c.page->data[11] = (o->multi << 6) | o->control;
/* ts A61106 : MMC-1 table 110 : multi==0 or multi==3 */
c.page->data[11] = ((3 * !!o->multi) << 6) | o->control;
c.page->data[12] = spc_block_type(o->block_type);
/* ts A61104 */
if(!(o->control&4)) /* audio (MMC-1 table 61) */
if(o->write_type == BURN_WRITE_TAO) /* ??? for others too ? */
c.page->data[12] = 0; /* Data Block Type: Raw Data */
c.page->data[22] = 0;
c.page->data[23] = 150; /* audio pause length */
/*XXX need session format! */
@ -361,7 +382,10 @@ void spc_probe_write_modes(struct burn_drive *d)
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;
key = c.sense[2];
asc = c.sense[12];
@ -470,6 +494,10 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
d->channel = channel_no;
d->lun = lun_no;
/* ts A61106 */
d->silent_on_scsi_error = 0;
d->idata = malloc(sizeof(struct burn_scsi_inquiry_data));
d->idata->valid = 0;
d->mdata = malloc(sizeof(struct scsi_mode_data));
@ -495,3 +523,131 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
}
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;
}

View File

@ -33,5 +33,18 @@ int spc_setup_drive(struct burn_drive *d);
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);
#endif /*__SPC*/

View File

@ -115,6 +115,17 @@ struct burn_track *burn_track_create(void)
t->pad = 1;
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;
@ -318,6 +329,31 @@ int burn_track_get_sectors(struct burn_track *t)
return sectors;
}
/* ts A61031 */
int burn_track_is_open_ended(struct burn_track *t)
{
return !!t->open_ended;
}
/* 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;

View File

@ -31,6 +31,18 @@ struct burn_track
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;
@ -71,4 +83,10 @@ struct burn_disc
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);
#endif /* BURN__STRUCTURE_H */

View File

@ -4,20 +4,16 @@
#define __TRANSPORT
#include "libburn.h"
#include "os.h"
#include <pthread.h>
/* sg data structures */
#include <sys/types.h>
#ifdef __FreeBSD__
#define BUFFER_SIZE 65536/2
/* see os.h for name of particular os-*.h where this is defined */
#define BUFFER_SIZE BURN_OS_TRANSPORT_BUFFER_SIZE
#else /* __FreeBSD__ */
#define BUFFER_SIZE 65536
#endif /* ! __FreeBSD__ */
enum transfer_direction
{ TO_DRIVE, FROM_DRIVE, NO_TRANSFER };
@ -107,15 +103,10 @@ struct burn_drive
int lun;
char *devname;
#if defined(__FreeBSD__)
struct cam_device* cam;
#else
int fd;
/* ts A60926 : trying to lock against growisofs /dev/srN, /dev/scdN */
int sibling_count;
int sibling_fds[LIBBURN_SG_MAX_SIBLINGS];
#endif
/* 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 */
/**
@ -129,6 +120,10 @@ struct burn_drive
enum burn_disc_status status;
int erasable;
volatile int released;
/* ts A61106 */
int silent_on_scsi_error;
int nwa; /* next writeable address */
int alba; /* absolute lba */
int rlba; /* relative lba in section */
@ -164,6 +159,7 @@ 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,
@ -178,7 +174,7 @@ struct burn_drive
void (*send_cue_sheet) (struct burn_drive *, struct cue_sheet *);
void (*sync_cache) (struct burn_drive *);
int (*get_erase_progress) (struct burn_drive *);
int (*get_nwa) (struct burn_drive *);
int (*get_nwa) (struct burn_drive *, int trackno, int *lba, int *nwa);
/* ts A61009 : removed d in favor of o->drive */
/* void (*close_disc) (struct burn_drive * d,
@ -189,6 +185,10 @@ struct burn_drive
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;

View File

@ -7,6 +7,18 @@
/* #include <a ssert.h> */
/* ts A61106 : Deliberate defect provocation macros
DO NOT DEFINE THESE IF YOU WANT SUCCESSFUL TAO !
#define Libburn_experimental_no_close_tracK 1
#define Libburn_experimental_no_close_sessioN 1
*/
/* ts A61114 : Highly experimental : try to achieve SAO on appendables
THIS DOES NOT WORK YET !
#define Libburn_sao_can_appenD 1
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
@ -99,7 +111,7 @@ void type_to_form(int mode, unsigned char *ctladr, int *form)
*form |= 0x40;
}
int burn_write_flush(struct burn_write_opts *o)
int burn_write_flush(struct burn_write_opts *o, struct burn_track *track)
{
struct burn_drive *d = o->drive;
@ -108,13 +120,115 @@ int burn_write_flush(struct burn_write_opts *o)
err = d->write(d, d->nwa, d->buffer);
if (err == BE_CANCELLED)
return 0;
/* A61101 */
if(track != NULL) {
track->writecount += d->buffer->bytes;
track->written_sectors += d->buffer->sectors;
}
/* ts A61119 */
d->progress.buffered_bytes += d->buffer->bytes;
d->nwa += d->buffer->sectors;
d->buffer->bytes = 0;
d->buffer->sectors = 0;
}
d->sync_cache(d);
return 1;
}
/* ts A61030 */
int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
int tnum)
{
char msg[81];
struct burn_drive *d;
struct burn_track *t;
int todo, step, cancelled, seclen;
/* ts A61106 */
#ifdef Libburn_experimental_no_close_tracK
return 1;
#endif
d = o->drive;
t = s->track[tnum];
/* ts A61103 : pad up track to minimum size of 600 sectors */
if (t->written_sectors < 300) {
todo = 300 - t->written_sectors;
sprintf(msg,"Padding up track to minimum size (+ %d sectors)",
todo);
libdax_msgs_submit(libdax_messenger, o->drive->global_index,
0x0002011a,
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
step = BUFFER_SIZE / 4096; /* shall fit any sector size */
if (step <= 0)
step = 1;
seclen = burn_sector_length(t->mode);
if (seclen <= 0)
seclen = 2048;
memset(d->buffer, 0, sizeof(struct buffer));
cancelled = d->cancel;
for (; todo > 0; todo -= step) {
if (step > todo)
step = todo;
d->buffer->bytes = step*seclen;
d->buffer->sectors = step;
d->cancel = 0;
d->write(d, d->nwa, d->buffer);
d->nwa += d->buffer->sectors;
t->writecount += d->buffer->bytes;
t->written_sectors += d->buffer->sectors;
d->progress.buffered_bytes += d->buffer->bytes;
}
d->cancel = cancelled;
}
/* ts A61102 */
d->busy = BURN_DRIVE_CLOSING_TRACK;
sprintf(msg, "Closing track %2.2d", tnum+1);
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
/* MMC-1 mentions track number 0xFF for "the incomplete track",
MMC-3 does not. I tried both. 0xFF was in effect when other
bugs finally gave up and made way for readable tracks. */
d->close_track_session(o->drive, 0, 0xff); /* tnum+1); */
/* ts A61102 */
d->busy = BURN_DRIVE_WRITING;
return 1;
}
/* ts A61030 */
int burn_write_close_session(struct burn_write_opts *o, struct burn_session *s)
{
/* ts A61106 */
#ifdef Libburn_experimental_no_close_sessioN
return 1;
#endif
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
"Closing session", 0, 0);
/* ts A61102 */
o->drive->busy = BURN_DRIVE_CLOSING_SESSION;
o->drive->close_track_session(o->drive, 1, 0);
/* ts A61102 */
o->drive->busy = BURN_DRIVE_WRITING;
return 1;
}
/* ts A60819:
This is unused since about Feb 2006, icculus.org/burn CVS.
The compiler complains. We shall please our compiler.
@ -179,8 +293,10 @@ static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
return 1;
}
/* ts A61114: added parameter nwa */
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
struct burn_session *session)
struct burn_session *session,
int nwa)
{
int i, m, s, f, form, pform, runtime = -150, ret;
unsigned char ctladr;
@ -193,6 +309,11 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
d = o->drive;
#ifdef Libburn_sao_can_appenD
if (d->status == BURN_DISC_APPENDABLE)
runtime = nwa-150;
#endif
sheet = malloc(sizeof(struct cue_sheet));
/* ts A61009 : react on failures of malloc(), add_cue_sheet()
@ -228,11 +349,20 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
/* ts A61009 */
/* a ssert(d->toc_entry == NULL); */
if (d->toc_entry != NULL) {
/* ts A61109 : this happens with appendable CDs
>>> Open question: is the existing TOC needed ? */
/* ts A61109 : for non-SAO, this sheet is thrown away later */
free((char *) d->toc_entry);
/*
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x00020117,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"toc_entry of drive is already in use", 0, 0);
goto failed;
*/
}
d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
@ -302,8 +432,17 @@ XXX this is untested :)
*/
if (!tar[i]->pad) {
rem += burn_track_get_shortage(tar[i]);
if (i +1 != ntr)
tar[i]->source->next = tar[i+1]->source;
/* ts A61101 : I doubt that linking would yield a
desireable effect. With TAO it is
counterproductive in any way.
*/
if (o->write_type == BURN_WRITE_TAO)
tar[i]->source->next = NULL;
else
if (i +1 != ntr)
tar[i]->source->next = tar[i+1]->source;
} else if (rem) {
rem = 0;
runtime++;
@ -417,7 +556,7 @@ int burn_write_session(struct burn_write_opts *o, struct burn_session *s)
{
struct burn_drive *d = o->drive;
struct burn_track *prev = NULL, *next = NULL;
int i;
int i, ret;
d->rlba = 0;
burn_print(1, " writing a session\n");
@ -430,9 +569,15 @@ int burn_write_session(struct burn_write_opts *o, struct burn_session *s)
next = NULL;
if (!burn_write_track(o, s, i))
return 0;
{ ret = 0; goto ex; }
}
return 1;
/* ts A61103 */
ret = 1;
ex:;
if (o->write_type == BURN_WRITE_TAO)
burn_write_close_session(o, s);
return ret;
}
int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
@ -440,13 +585,18 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
{
struct burn_track *t = s->track[tnum];
struct burn_drive *d = o->drive;
int i, tmp = 0;
int i, tmp = 0, open_ended = 0, ret= 0, nwa, lba;
int sectors;
char msg[80];
d->rlba = -150;
/* XXX for tao, we don't want the pregaps but still want post? */
if (o->write_type != BURN_WRITE_TAO) {
/* ts A61102 */
d->busy = BURN_DRIVE_WRITING_PREGAP;
if (t->pregap1)
d->rlba += 75;
if (t->pregap2)
@ -462,20 +612,36 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
for (i = 0; i < 75; i++)
if (!sector_pregap(o, t->entry->point,
pt->entry->control, pt->mode))
return 0;
{ ret = 0; goto ex; }
}
if (t->pregap2)
for (i = 0; i < 150; i++)
if (!sector_pregap(o, t->entry->point,
t->entry->control, t->mode))
return 0;
{ ret = 0; goto ex; }
} else {
o->control = t->entry->control;
d->send_write_parameters(d, o);
/* ts A61103 */
ret = d->get_nwa(d, -1, &lba, &nwa);
sprintf(msg,
"pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d\n",
tnum+1, nwa, ret, d->nwa);
libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg,0,0);
if (nwa > d->nwa)
d->nwa = nwa;
}
/* user data */
/* ts A61102 */
d->busy = BURN_DRIVE_WRITING;
sectors = burn_track_get_sectors(t);
open_ended = burn_track_is_open_ended(t);
/* Update progress */
d->progress.start_sector = d->nwa;
@ -488,10 +654,11 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
burn_print(12, "track %d is %d sectors long\n", tnum, sectors);
/* ts A61030 : this cannot happen. tnum is always < s->tracks */
if (tnum == s->tracks)
tmp = sectors > 150 ? 150 : sectors;
for (i = 0; i < sectors - tmp; i++) {
for (i = 0; open_ended || i < sectors - tmp; i++) {
/* ts A61023 : http://libburn.pykix.org/ticket/14
From time to time inquire drive buffer */
@ -499,12 +666,24 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
d->read_buffer_capacity(d);
if (!sector_data(o, t, 0))
return 0;
{ ret = 0; goto ex; }
/* ts A61031 */
if (open_ended) {
d->progress.sectors = sectors = i;
if (burn_track_is_data_done(t))
break;
}
/* update current progress */
d->progress.sector++;
}
for (; i < sectors; i++) {
/* ts A61030: program execution never gets to this point */
fprintf(stderr,"LIBBURN_DEBUG: TNUM=%d TRACKS=%d TMP=%d\n",
tnum, s->tracks, tmp);
burn_print(1, "last track, leadout prep\n");
/* ts A61023 */
@ -512,7 +691,7 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
d->read_buffer_capacity(d);
if (!sector_data(o, t, 1))
return 0;
{ ret = 0; goto ex; }
/* update progress */
d->progress.sector++;
@ -522,23 +701,43 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
for (i = 0; i < 150; i++)
if (!sector_postgap(o, t->entry->point, t->entry->control,
t->mode))
return 0;
{ ret = 0; goto ex; }
i = t->offset;
if (o->write_type == BURN_WRITE_SAO) {
if (d->buffer->bytes) {
int err;
err = d->write(d, d->nwa, d->buffer);
if (err == BE_CANCELLED)
return 0;
{ ret = 0; goto ex; }
/* A61101 : probably this is not all payload data */
/* A61108 : but audio count is short without this */
t->writecount += d->buffer->bytes;
t->written_sectors += d->buffer->sectors;
d->progress.buffered_bytes += d->buffer->bytes;
d->nwa += d->buffer->sectors;
d->buffer->bytes = 0;
d->buffer->sectors = 0;
}
}
if (o->write_type == BURN_WRITE_TAO)
if (!burn_write_flush(o))
return 0;
return 1;
/* ts A61103 */
ret = 1;
ex:;
if (o->write_type == BURN_WRITE_TAO) {
/* ts A61103 */
/* >>> if cancelled: ensure that at least 600 kB get written */
if (!burn_write_flush(o, t))
ret = 0;
/* ts A61030 */
if (burn_write_close_track(o, s, tnum) <= 0)
ret = 0;
}
return ret;
}
/* ts A61009 */
@ -568,8 +767,8 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
struct burn_drive *d = o->drive;
struct buffer buf;
struct burn_track *lt;
int first = 1, i;
int res;
int first = 1, i, ret, lba, nwa = 0;
char msg[80];
/* ts A60924 : libburn/message.c gets obsoleted
burn_message_clear_queue();
@ -586,15 +785,24 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
/* Apparently some drives require this command to be sent, and a few drives
return crap. so we send the command, then ignore the result.
*/
res = d->get_nwa(d);
/* printf("ignored nwa: %d\n", res);*/
d->alba = d->start_lba;
/* ts A61107 : moved up send_write_parameters because LG GSA-4082B
seems to dislike get_nwa() in advance */
d->alba = d->start_lba; /* ts A61114: this looks senseless */
d->nwa = d->alba;
if (o->write_type == BURN_WRITE_TAO) {
nwa = 0; /* get_nwa() will be called in burn_track() */
} else {
if (o->write_type != BURN_WRITE_TAO)
d->send_write_parameters(d, o);
ret = d->get_nwa(d, -1, &lba, &nwa);
sprintf(msg, "Inquired nwa: %d (ret=%d)", nwa, ret);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg,0,0);
}
/* init progress before showing the state */
d->progress.session = 0;
d->progress.sessions = disc->sessions;
@ -612,6 +820,8 @@ return crap. so we send the command, then ignore the result.
/* ts A61023 */
d->progress.buffer_capacity = 0;
d->progress.buffer_available = 0;
d->progress.buffered_bytes = 0;
d->progress.buffer_min_fill = 0xffffffff;
d->busy = BURN_DRIVE_WRITING;
@ -620,7 +830,8 @@ return crap. so we send the command, then ignore the result.
d->progress.session = i;
d->progress.tracks = disc->session[i]->tracks;
sheet = burn_create_toc_entries(o, disc->session[i]);
/* ts A61114: added parameter nwa */
sheet = burn_create_toc_entries(o, disc->session[i], nwa);
/* ts A61009 */
if (sheet == NULL)
@ -636,8 +847,39 @@ return crap. so we send the command, then ignore the result.
goto fail;
} else {
if (first) {
d->nwa = -150;
d->alba = -150;
/* ts A61030 : 0 made the burner take data. */
/* ts A61103 : Meanwhile d->nwa is updated in
burn_write_track() */
if(o->write_type == BURN_WRITE_TAO) {
d->nwa= d->alba = 0;
} else {
#ifdef Libburn_sao_can_appenD
/* ts A61114: address for d->write() */
if (d->status == BURN_DISC_APPENDABLE
&& o->write_type == BURN_WRITE_SAO) {
d->nwa = d->alba = nwa-150;
sprintf(msg,
"SAO appendable d->nwa= %d\n", d->nwa);
libdax_msgs_submit(
libdax_messenger, d->global_index, 0x000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg,0,0);
} else {
d->nwa = -150;
d->alba = -150;
}
#else
d->nwa = -150;
d->alba = -150;
#endif /* ! Libburn_sao_can_appenD */
}
} else {
d->nwa += 4500;
d->alba += 4500;
@ -652,8 +894,13 @@ return crap. so we send the command, then ignore the result.
lt->mode))
goto fail;
} else {
if (!burn_write_flush(o))
goto fail;
/* ts A61030 */
if (o->write_type != BURN_WRITE_TAO)
if (!burn_write_flush(o, NULL))
goto fail;
d->nwa += first ? 6750 : 2250;
d->alba += first ? 6750 : 2250;
}
@ -665,15 +912,18 @@ return crap. so we send the command, then ignore the result.
d->progress.start_sector = 0;
d->progress.sectors = 0;
}
if (o->write_type != BURN_WRITE_SAO)
if (!burn_write_flush(o))
/* ts A61030: extended skipping of flush to TAO: session is closed */
if (o->write_type != BURN_WRITE_SAO && o->write_type != BURN_WRITE_TAO)
if (!burn_write_flush(o, NULL))
goto fail;
sleep(1);
burn_print(1, "done\n");
d->busy = BURN_DRIVE_IDLE;
/* ts A61012 : This return was traditionally missing, a suspect this
/* ts A61012 : This return was traditionally missing. I suspect this
to have caused Cdrskin_eject() failures */
return;

View File

@ -9,7 +9,8 @@ struct burn_write_opts;
struct burn_disc;
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
struct burn_session *session);
struct burn_session *session,
int nwa);
int burn_sector_length(int trackmode);
int burn_subcode_length(int trackmode);
@ -24,6 +25,11 @@ int burn_write_leadout(struct burn_write_opts *o,
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);
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);
#endif /* BURN__WRITE_H */

View File

@ -1,11 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libisofs
Description: ISO9660 filesystem creation library
Version: @VERSION@
Requires:
Libs: -L${libdir} -lisofs
Cflags: -I${includedir}/libburn

View File

@ -1,4 +0,0 @@
all clean:
$(MAKE) -C .. -$(MAKEFLAGS) $@
.PHONY: all clean

View File

@ -1,49 +0,0 @@
pkgconfigdir=$(libdir)/pkgconfig
libincludedir=$(includedir)/libburn
##bin_PROGRAMS = test
lib_LTLIBRARIES = libisofs.la
libisofs_la_SOURCES = \
tree.h \
tree.c \
volume.h \
volume.c \
util.h \
util.c \
ecma119.c \
ecma119.h \
ecma119_tree.c \
ecma119_tree.h \
susp.h \
susp.c \
rockridge.h \
rockridge.c \
joliet.c \
joliet.h
libinclude_HEADERS = libisofs.h
##test_SOURCES = test.c
##test_LDADD = libisofs.la
##noinst_PROGRAMS = test
##test_SOURCES = test.c
##test_LDADD = $(libisofs_la_OBJECTS)
##INCLUDES = -I../burn/libburn
## ========================================================================= ##
indent_files = $(libisofs_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
## ========================================================================= ##

View File

@ -1,694 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <err.h>
#include "ecma119.h"
#include "ecma119_tree.h"
#include "susp.h"
#include "rockridge.h"
#include "joliet.h"
#include "volume.h"
#include "tree.h"
#include "util.h"
#include "libisofs.h"
#include "libburn/libburn.h"
/* burn-source compatible stuff */
static int
bs_read(struct burn_source *bs, unsigned char *buf, int size);
static off_t
bs_get_size(struct burn_source *bs);
static void
bs_free_data(struct burn_source *bs);
typedef void (*write_fn)(struct ecma119_write_target*, uint8_t*);
/* return true if the given state is only required for Joliet volumes */
static int
is_joliet_state(enum ecma119_write_state);
static void
next_state(struct ecma119_write_target *t);
/* write t->state_data to the buf, one block at a time */
static void
write_data_chunk(struct ecma119_write_target *t, uint8_t *buf);
/* writing functions. All these functions assume the buf is large enough */
static void
write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
static void
write_vol_desc_terminator(struct ecma119_write_target *t, uint8_t *buf);
static void
write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf);
static void
write_l_path_table(struct ecma119_write_target *t, uint8_t *buf);
static void
write_m_path_table(struct ecma119_write_target *t, uint8_t *buf);
static void
write_one_dir_record(struct ecma119_write_target *t,
struct ecma119_tree_node *dir,
int file_id,
uint8_t *buf);
static void
write_one_dir(struct ecma119_write_target *t,
struct ecma119_tree_node *dir,
uint8_t *buf);
static void
write_dirs(struct ecma119_write_target *t, uint8_t *buf);
/* wrapper functions for writing */
static void wr_system_area(struct ecma119_write_target*, uint8_t*);
static void wr_pri_vol_desc(struct ecma119_write_target*, uint8_t*);
static void wr_vol_desc_term(struct ecma119_write_target*, uint8_t*);
static void wr_l_path_table(struct ecma119_write_target*, uint8_t*);
static void wr_m_path_table(struct ecma119_write_target*, uint8_t*);
static void wr_dir_records(struct ecma119_write_target*, uint8_t*);
static void wr_files(struct ecma119_write_target*, uint8_t*);
static const write_fn writers[] =
{
NULL,
wr_system_area,
wr_pri_vol_desc,
joliet_wr_sup_vol_desc,
wr_vol_desc_term,
wr_l_path_table,
wr_m_path_table,
joliet_wr_l_path_table,
joliet_wr_m_path_table,
wr_dir_records,
joliet_wr_dir_records,
wr_files
};
/* When a writer is created, we
* 1) create an ecma119 tree
* 2) add SUSP fields (if necessary)
* 3) calculate the size and position of all nodes in the tree
* 4) finalize SUSP fields (if necessary)
*/
static void
add_susp_fields_rec(struct ecma119_write_target *t,
struct ecma119_tree_node *node)
{
size_t i;
if (!node->iso_self)
return;
rrip_add_PX(t, node);
rrip_add_NM(t, node);
rrip_add_TF(t, node);
if (node->iso_self->attrib.st_rdev)
rrip_add_PN(t, node);
if (S_ISLNK(node->iso_self->attrib.st_mode))
rrip_add_SL(t, node);
if (node->type == ECMA119_FILE && node->file.real_me)
rrip_add_CL(t, node);
if (node->type == ECMA119_DIR
&& node->dir.real_parent != node->parent) {
rrip_add_RE(t, node);
rrip_add_PL(t, node);
}
susp_add_CE(t, node);
if (node->type == ECMA119_DIR) {
for (i = 0; i < node->dir.nchildren; i++) {
add_susp_fields_rec(t, node->dir.children[i]);
}
}
}
static void
add_susp_fields(struct ecma119_write_target *t)
{
susp_add_SP(t, t->root);
rrip_add_ER(t, t->root);
add_susp_fields_rec(t, t->root);
}
/**
* Fill out the dir.len and dir.CE_len fields for each
* ecma119_tree_node that is a directory. Also calculate the total number of
* directories and the number of files for which we need to write out data.
* (dirlist_len and filelist_len)
*/
static void
calc_dir_size(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
size_t i;
assert(dir->type == ECMA119_DIR);
t->dirlist_len++;
dir->dir.len = 34 + dir->dir.self_susp.non_CE_len
+ 34 + dir->dir.parent_susp.non_CE_len;
dir->dir.CE_len = dir->dir.self_susp.CE_len
+ dir->dir.parent_susp.CE_len;
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
dir->dir.len += ch->dirent_len + ch->susp.non_CE_len;
dir->dir.CE_len += ch->susp.CE_len;
}
t->total_dir_size += round_up(dir->dir.len + dir->dir.CE_len,
t->block_size);
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
struct iso_tree_node *iso = ch->iso_self;
if (ch->type == ECMA119_DIR) {
calc_dir_size(t, ch);
} else if (iso && iso->attrib.st_size
&& iso->loc.type == LIBISO_FILESYS
&& iso->loc.path) {
t->filelist_len++;
}
}
}
/**
* Fill out the block field in each ecma119_tree_node that is a directory and
* fill out t->dirlist.
*/
static void
calc_dir_pos(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
size_t i;
assert(dir->type == ECMA119_DIR);
/* we don't need to set iso_self->block since each tree writes
* its own directories */
dir->block = t->curblock;
t->curblock += div_up(dir->dir.len + dir->dir.CE_len, t->block_size);
t->dirlist[t->curfile++] = dir;
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
if (ch->type == ECMA119_DIR)
calc_dir_pos(t, ch);
}
/* reset curfile when we're finished */
if (!dir->parent) {
t->curfile = 0;
}
}
/**
* Fill out the block field for each ecma119_tree_node that is a file and fill
* out t->filelist.
*/
static void
calc_file_pos(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
size_t i;
assert(dir->type == ECMA119_DIR);
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
if (ch->type == ECMA119_FILE && ch->iso_self) {
struct iso_tree_node *iso = ch->iso_self;
off_t size = iso->attrib.st_size;
iso->block = ch->block = t->curblock;
t->curblock += div_up(size, t->block_size);
if (size && iso->loc.type == LIBISO_FILESYS
&& iso->loc.path)
t->filelist[t->curfile++] = ch;
}
}
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
if (ch->type == ECMA119_DIR)
calc_file_pos(t, ch);
}
/* reset curfile when we're finished */
if (!dir->parent) {
t->curfile = 0;
}
}
struct ecma119_write_target*
ecma119_target_new(struct iso_volset *volset,
int volnum,
int level,
int flags)
{
struct ecma119_write_target *t =
calloc(1, sizeof(struct ecma119_write_target));
size_t i, j, cur;
struct iso_tree_node *iso_root = volset->volume[volnum]->root;
volset->refcount++;
t->root = ecma119_tree_create(t, iso_root);
t->joliet = (flags & ECMA119_JOLIET) ? 1 : 0;
if (t->joliet)
t->joliet_root = joliet_tree_create(t, iso_root);
t->volset = volset;
t->volnum = volnum;
t->now = time(NULL);
t->rockridge = (flags & ECMA119_ROCKRIDGE) ? 1 : 0;
t->iso_level = level;
t->block_size = 2048;
if (t->rockridge)
add_susp_fields(t);
calc_dir_size(t, t->root);
if (t->joliet) {
joliet_calc_dir_size(t, t->joliet_root);
t->pathlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len);
t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len);
}
t->dirlist = calloc(1, sizeof(void*) * t->dirlist_len);
t->pathlist = calloc(1, sizeof(void*) * t->dirlist_len);
t->filelist = calloc(1, sizeof(void*) * t->filelist_len);
/* fill out the pathlist */
t->pathlist[0] = t->root;
t->path_table_size = 10; /* root directory record */
cur = 1;
for (i = 0; i < t->dirlist_len; i++) {
struct ecma119_tree_node *dir = t->pathlist[i];
for (j = 0; j < dir->dir.nchildren; j++) {
struct ecma119_tree_node *ch = dir->dir.children[j];
if (ch->type == ECMA119_DIR) {
size_t len = 8 + strlen(ch->name);
t->pathlist[cur++] = ch;
t->path_table_size += len + len % 2;
}
}
}
t->curblock = 16 /* system area */
+ 1 /* volume desc */
+ 1; /* volume desc terminator */
if (t->joliet) /* supplementary vol desc */
t->curblock += div_up (2048, t->block_size);
t->l_path_table_pos = t->curblock;
t->curblock += div_up(t->path_table_size, t->block_size);
t->m_path_table_pos = t->curblock;
t->curblock += div_up(t->path_table_size, t->block_size);
if (t->joliet) {
joliet_prepare_path_tables(t);
t->l_path_table_pos_joliet = t->curblock;
t->curblock += div_up(t->path_table_size_joliet, t->block_size);
t->m_path_table_pos_joliet = t->curblock;
t->curblock += div_up(t->path_table_size_joliet, t->block_size);
}
calc_dir_pos(t, t->root);
if (t->joliet)
joliet_calc_dir_pos(t, t->joliet_root);
calc_file_pos(t, t->root);
if (t->joliet)
joliet_update_file_pos (t, t->joliet_root);
if (t->rockridge) {
susp_finalize(t, t->root);
rrip_finalize(t, t->root);
}
t->total_size = t->curblock * t->block_size;
t->vol_space_size = t->curblock;
/* prepare for writing */
t->curblock = 0;
t->state = ECMA119_WRITE_SYSTEM_AREA;
return t;
}
static int
is_joliet_state(enum ecma119_write_state state)
{
return state == ECMA119_WRITE_SUP_VOL_DESC_JOLIET
|| state == ECMA119_WRITE_L_PATH_TABLE_JOLIET
|| state == ECMA119_WRITE_M_PATH_TABLE_JOLIET
|| state == ECMA119_WRITE_DIR_RECORDS_JOLIET;
}
static void
next_state(struct ecma119_write_target *t)
{
t->state++;
while (!t->joliet && is_joliet_state(t->state))
t->state++;
printf ("now in state %d, curblock=%d\n", (int)t->state, (int)t->curblock);
}
static void
wr_system_area(struct ecma119_write_target *t, uint8_t *buf)
{
memset(buf, 0, t->block_size);
if (t->curblock == 15) {
next_state(t);
}
}
static void
wr_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_pri_vol_desc, 2048, buf);
}
static void
wr_vol_desc_term(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_vol_desc_terminator, 2048, buf);
}
static void
wr_l_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_l_path_table, t->path_table_size, buf);
}
static void
wr_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_m_path_table, t->path_table_size, buf);
}
static void
wr_dir_records(struct ecma119_write_target *t, uint8_t *buf)
{
ecma119_start_chunking(t, write_dirs, t->total_dir_size, buf);
}
static void
wr_files(struct ecma119_write_target *t, uint8_t *buf)
{
struct state_files *f_st = &t->state_files;
size_t nread;
struct ecma119_tree_node *f = t->filelist[f_st->file];
const char *path = f->iso_self->loc.path;
if (!f_st->fd) {
f_st->data_len = f->iso_self->attrib.st_size;
f_st->fd = fopen(path, "r");
if (!f_st->fd)
err(1, "couldn't open %s for reading", path);
assert(t->curblock == f->block);
}
nread = fread(buf, 1, t->block_size, f_st->fd);
f_st->pos += t->block_size;
if (nread < 0)
warn("problem reading from %s", path);
else if (nread != t->block_size && f_st->pos < f_st->data_len)
warnx("incomplete read from %s", path);
if (f_st->pos >= f_st->data_len) {
fclose(f_st->fd);
f_st->fd = 0;
f_st->pos = 0;
f_st->file++;
if (f_st->file >= t->filelist_len)
next_state(t);
}
}
static void
write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
struct ecma119_pri_vol_desc *vol = (struct ecma119_pri_vol_desc*)buf;
struct iso_volume *volume = t->volset->volume[t->volnum];
char *vol_id = str2ascii(volume->volume_id);
char *pub_id = str2ascii(volume->publisher_id);
char *data_id = str2ascii(volume->data_preparer_id);
char *volset_id = str2ascii(t->volset->volset_id);
vol->vol_desc_type[0] = 1;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
memcpy(vol->system_id, "SYSID", 5);
if (vol_id)
strncpy((char*)vol->volume_id, vol_id, 32);
iso_bb(vol->vol_space_size, t->vol_space_size, 4);
iso_bb(vol->vol_set_size, t->volset->volset_size, 2);
iso_bb(vol->vol_seq_number, t->volnum + 1, 2);
iso_bb(vol->block_size, t->block_size, 2);
iso_bb(vol->path_table_size, t->path_table_size, 4);
iso_lsb(vol->l_path_table_pos, t->l_path_table_pos, 4);
iso_msb(vol->m_path_table_pos, t->m_path_table_pos, 4);
write_one_dir_record(t, t->root, 3, vol->root_dir_record);
strncpy((char*)vol->vol_set_id, volset_id, 128);
strncpy((char*)vol->publisher_id, pub_id, 128);
strncpy((char*)vol->data_prep_id, data_id, 128);
strncpy((char*)vol->application_id, "APPID", 128);
iso_datetime_17(vol->vol_creation_time, t->now);
iso_datetime_17(vol->vol_modification_time, t->now);
iso_datetime_17(vol->vol_effective_time, t->now);
vol->file_structure_version[0] = 1;
free(vol_id);
free(volset_id);
free(pub_id);
free(data_id);
}
static void
write_vol_desc_terminator(struct ecma119_write_target *t, uint8_t *buf)
{
struct ecma119_vol_desc_terminator *vol =
(struct ecma119_vol_desc_terminator*) buf;
vol->vol_desc_type[0] = 255;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
}
static void
write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf)
{
void (*write_int)(uint8_t*, uint32_t, int) = l_type ? iso_lsb
: iso_msb;
size_t i;
struct ecma119_path_table_record *rec;
struct ecma119_tree_node *dir;
int parent = 0;
for (i = 0; i < t->dirlist_len; i++) {
dir = t->pathlist[i];
while ((i) && t->pathlist[parent] != dir->parent)
parent++;
assert(parent < i || i == 0);
rec = (struct ecma119_path_table_record*) buf;
rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->name) : 1;
rec->len_xa[0] = 0;
write_int(rec->block, dir->block, 4);
write_int(rec->parent, parent + 1, 2);
if (dir->parent)
memcpy(rec->dir_id, dir->name, rec->len_di[0]);
buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2);
}
}
static void
write_l_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
write_path_table(t, 1, buf);
}
static void
write_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
write_path_table(t, 0, buf);
}
/* if file_id is >= 0, we use it instead of the filename. As a magic number,
* file_id == 3 means that we are writing the root directory record (in order
* to distinguish it from the "." entry in the root directory) */
static void
write_one_dir_record(struct ecma119_write_target *t,
struct ecma119_tree_node *node,
int file_id,
uint8_t *buf)
{
uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len;
uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->name);
uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id);
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name;
uint32_t len = (node->type == ECMA119_DIR) ? node->dir.len
: node->file.real_me ? 0 : node->iso_self->attrib.st_size;
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
/* we don't write out susp fields for the root node */
if (t->rockridge) {
if (file_id == 0) {
susp_write(t, &node->dir.self_susp, &buf[len_dr]);
len_dr += node->dir.self_susp.non_CE_len;
} else if (file_id == 1) {
susp_write(t, &node->dir.parent_susp, &buf[len_dr]);
len_dr += node->dir.parent_susp.non_CE_len;
} else if (file_id < 0) {
susp_write(t, &node->susp, &buf[len_dr]);
len_dr += node->susp.non_CE_len;
}
}
if (file_id == 1 && node->parent)
node = node->parent;
rec->len_dr[0] = len_dr;
iso_bb(rec->block, node->block, 4);
iso_bb(rec->length, len, 4);
iso_datetime_7(rec->recording_time, t->now);
rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0;
iso_bb(rec->vol_seq_number, t->volnum + 1, 2);
rec->len_fi[0] = len_fi;
memcpy(rec->file_id, name, len_fi);
}
static void
write_one_dir(struct ecma119_write_target *t,
struct ecma119_tree_node *dir,
uint8_t *buf)
{
size_t i;
uint8_t *orig_buf = buf;
assert(dir->type == ECMA119_DIR);
/* write the "." and ".." entries first */
write_one_dir_record(t, dir, 0, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
write_one_dir_record(t, dir, 1, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
for (i = 0; i < dir->dir.nchildren; i++) {
write_one_dir_record(t, dir->dir.children[i], -1, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
}
/* write the susp continuation areas */
if (t->rockridge) {
susp_write_CE(t, &dir->dir.self_susp, buf);
buf += dir->dir.self_susp.CE_len;
susp_write_CE(t, &dir->dir.parent_susp, buf);
buf += dir->dir.parent_susp.CE_len;
for (i = 0; i < dir->dir.nchildren; i++) {
susp_write_CE(t, &dir->dir.children[i]->susp, buf);
buf += dir->dir.children[i]->susp.CE_len;
}
}
assert (buf - orig_buf == dir->dir.len + dir->dir.CE_len);
}
static void
write_dirs(struct ecma119_write_target *t, uint8_t *buf)
{
size_t i;
struct ecma119_tree_node *dir;
for (i = 0; i < t->dirlist_len; i++) {
dir = t->dirlist[i];
write_one_dir(t, dir, buf);
buf += round_up(dir->dir.len + dir->dir.CE_len, t->block_size);
}
}
void
ecma119_start_chunking(struct ecma119_write_target *t,
write_fn writer,
off_t data_size,
uint8_t *buf)
{
if (data_size != t->state_data_size) {
data_size = round_up(data_size, t->block_size);
t->state_data = realloc(t->state_data, data_size);
t->state_data_size = data_size;
}
memset(t->state_data, 0, t->state_data_size);
t->state_data_off = 0;
t->state_data_valid = 1;
writer(t, t->state_data);
write_data_chunk(t, buf);
}
static void
write_data_chunk(struct ecma119_write_target *t, uint8_t *buf)
{
memcpy(buf, t->state_data + t->state_data_off, t->block_size);
t->state_data_off += t->block_size;
if (t->state_data_off >= t->state_data_size) {
assert (t->state_data_off <= t->state_data_size);
t->state_data_valid = 0;
next_state(t);
}
}
static int
bs_read(struct burn_source *bs, unsigned char *buf, int size)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
if (size != t->block_size) {
warnx("you must read data in block-sized chunks (%d bytes)",
(int)t->block_size);
return 0;
} else if (t->curblock >= t->vol_space_size) {
return 0;
}
if (t->state_data_valid)
write_data_chunk(t, buf);
else
writers[t->state](t, buf);
t->curblock++;
return size;
}
static off_t
bs_get_size(struct burn_source *bs)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
return t->total_size;
}
static void
bs_free_data(struct burn_source *bs)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
ecma119_tree_free(t->root);
free(t->dirlist);
free(t->pathlist);
free(t->dirlist_joliet);
free(t->pathlist_joliet);
free(t->filelist);
free(t->state_data);
if (t->state_files.fd)
fclose(t->state_files.fd);
}
struct burn_source *iso_source_new_ecma119(struct iso_volset *volset,
int volnum,
int level,
int flags)
{
struct burn_source *ret = calloc(1, sizeof(struct burn_source));
ret->refcount = 1;
ret->read = bs_read;
ret->get_size = bs_get_size;
ret->free_data = bs_free_data;
ret->data = ecma119_target_new(volset, volnum, level, flags);
return ret;
}

View File

@ -1,267 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* \file ecma119.h
*
* Structures and definitions used for writing an emca119 (ISO9660) compatible
* volume.
*/
#ifndef LIBISO_ECMA119_H
#define LIBISO_ECMA119_H
#include <sys/time.h>
#include <stdint.h>
#include <stdio.h> /* for FILE */
#include <sys/types.h>
#include "susp.h"
struct ecma119_tree_node;
struct joliet_tree_node;
/**
* The possible states that the ecma119 writer can be in.
*/
enum ecma119_write_state
{
ECMA119_WRITE_BEFORE,
ECMA119_WRITE_SYSTEM_AREA,
ECMA119_WRITE_PRI_VOL_DESC,
ECMA119_WRITE_SUP_VOL_DESC_JOLIET,
ECMA119_WRITE_VOL_DESC_TERMINATOR,
ECMA119_WRITE_L_PATH_TABLE,
ECMA119_WRITE_M_PATH_TABLE,
ECMA119_WRITE_L_PATH_TABLE_JOLIET,
ECMA119_WRITE_M_PATH_TABLE_JOLIET,
ECMA119_WRITE_DIR_RECORDS,
ECMA119_WRITE_DIR_RECORDS_JOLIET,
ECMA119_WRITE_FILES,
ECMA119_WRITE_DONE
};
/**
* Data describing the state of the ecma119 writer. Everything here should be
* considered private!
*/
struct ecma119_write_target
{
struct ecma119_tree_node *root;
struct joliet_tree_node *joliet_root;
struct iso_volset *volset;
int volnum;
time_t now; /**< Time at which writing began. */
off_t total_size; /**< Total size of the output. This only
* includes the current volume. */
uint32_t vol_space_size;
unsigned int rockridge:1;
unsigned int joliet:1;
unsigned int iso_level:2;
int curblock;
uint16_t block_size;
uint32_t path_table_size;
uint32_t path_table_size_joliet;
uint32_t l_path_table_pos;
uint32_t m_path_table_pos;
uint32_t l_path_table_pos_joliet;
uint32_t m_path_table_pos_joliet;
uint32_t total_dir_size;
uint32_t total_dir_size_joliet;
struct ecma119_tree_node **dirlist;
/**< A pre-order list of directories
* (this is the order in which we write
* out directory records).
*/
struct ecma119_tree_node **pathlist;
/**< A breadth-first list of
* directories. This is used for
* writing out the path tables.
*/
size_t dirlist_len; /**< The length of the previous 2 lists.
*/
struct ecma119_tree_node **filelist;
/**< A pre-order list of files with
* non-NULL paths and non-zero sizes.
*/
size_t filelist_len; /* Length of the previous list. */
int curfile; /**< Used as a helper field for writing
out filelist and dirlist */
/* Joliet versions of the above lists. Since Joliet doesn't require
* directory relocation, the order of these lists might be different
* from the lists above (but they will be the same length).
*/
struct joliet_tree_node **dirlist_joliet;
struct joliet_tree_node **pathlist_joliet;
enum ecma119_write_state state; /* The current state of the writer. */
/* Most writers work by
* 1) making sure state_data is big enough for their data
* 2) writing _all_ their data into state_data
* 3) relying on write_data_chunk to write the data block
* by block.
*/
uint8_t *state_data;
off_t state_data_size;
off_t state_data_off;
int state_data_valid;
/* for writing out files */
struct state_files {
off_t pos; /* The number of bytes we have written
* so far in the current file.
*/
off_t data_len;/* The number of bytes in the currently
* open file.
*/
FILE *fd; /* The currently open file. */
int file; /* The index in filelist that we are
* currently writing (or about to write). */
} state_files;
};
/**
* Create a new ecma119_write_target from the given volume number of the
* given volume set.
*
* \pre \p volnum is less than \p volset-\>volset_size.
* \post For each node in the tree, writer_data has been allocated.
* \post The directory heirarchy has been reorganised to be ecma119-compatible.
*/
struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset,
int volnum,
int level,
int flags);
#define BP(a,b) [(b) - (a) + 1]
struct ecma119_pri_vol_desc
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t unused1 BP(8, 8);
uint8_t system_id BP(9, 40);
uint8_t volume_id BP(41, 72);
uint8_t unused2 BP(73, 80);
uint8_t vol_space_size BP(81, 88);
uint8_t unused3 BP(89, 120);
uint8_t vol_set_size BP(121, 124);
uint8_t vol_seq_number BP(125, 128);
uint8_t block_size BP(129, 132);
uint8_t path_table_size BP(133, 140);
uint8_t l_path_table_pos BP(141, 144);
uint8_t opt_l_path_table_pos BP(145, 148);
uint8_t m_path_table_pos BP(149, 152);
uint8_t opt_m_path_table_pos BP(153, 156);
uint8_t root_dir_record BP(157, 190);
uint8_t vol_set_id BP(191, 318);
uint8_t publisher_id BP(319, 446);
uint8_t data_prep_id BP(447, 574);
uint8_t application_id BP(575, 702);
uint8_t copyright_file_id BP(703, 739);
uint8_t abstract_file_id BP(740, 776);
uint8_t bibliographic_file_id BP(777, 813);
uint8_t vol_creation_time BP(814, 830);
uint8_t vol_modification_time BP(831, 847);
uint8_t vol_expiration_time BP(848, 864);
uint8_t vol_effective_time BP(865, 881);
uint8_t file_structure_version BP(882, 882);
uint8_t reserved1 BP(883, 883);
uint8_t app_use BP(884, 1395);
uint8_t reserved2 BP(1396, 2048);
};
struct ecma119_sup_vol_desc
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t vol_flags BP(8, 8);
uint8_t system_id BP(9, 40);
uint8_t volume_id BP(41, 72);
uint8_t unused2 BP(73, 80);
uint8_t vol_space_size BP(81, 88);
uint8_t esc_sequences BP(89, 120);
uint8_t vol_set_size BP(121, 124);
uint8_t vol_seq_number BP(125, 128);
uint8_t block_size BP(129, 132);
uint8_t path_table_size BP(133, 140);
uint8_t l_path_table_pos BP(141, 144);
uint8_t opt_l_path_table_pos BP(145, 148);
uint8_t m_path_table_pos BP(149, 152);
uint8_t opt_m_path_table_pos BP(153, 156);
uint8_t root_dir_record BP(157, 190);
uint8_t vol_set_id BP(191, 318);
uint8_t publisher_id BP(319, 446);
uint8_t data_prep_id BP(447, 574);
uint8_t application_id BP(575, 702);
uint8_t copyright_file_id BP(703, 739);
uint8_t abstract_file_id BP(740, 776);
uint8_t bibliographic_file_id BP(777, 813);
uint8_t vol_creation_time BP(814, 830);
uint8_t vol_modification_time BP(831, 847);
uint8_t vol_expiration_time BP(848, 864);
uint8_t vol_effective_time BP(865, 881);
uint8_t file_structure_version BP(882, 882);
uint8_t reserved1 BP(883, 883);
uint8_t app_use BP(884, 1395);
uint8_t reserved2 BP(1396, 2048);
};
struct ecma119_vol_desc_terminator
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t reserved BP(8, 2048);
};
struct ecma119_dir_record
{
uint8_t len_dr BP(1, 1);
uint8_t len_xa BP(2, 2);
uint8_t block BP(3, 10);
uint8_t length BP(11, 18);
uint8_t recording_time BP(19, 25);
uint8_t flags BP(26, 26);
uint8_t file_unit_size BP(27, 27);
uint8_t interleave_gap_size BP(28, 28);
uint8_t vol_seq_number BP(29, 32);
uint8_t len_fi BP(33, 33);
uint8_t file_id BP(34, 34); /* 34 to 33+len_fi */
/* padding field (if len_fi is even) */
/* system use (len_dr - len_su + 1 to len_dr) */
};
struct ecma119_path_table_record
{
uint8_t len_di BP(1, 1);
uint8_t len_xa BP(2, 2);
uint8_t block BP(3, 6);
uint8_t parent BP(7, 8);
uint8_t dir_id BP(9, 9); /* 9 to 8+len_di */
/* padding field (if len_di is odd) */
};
/**
* A utility function for writers that want to write their data all at once
* rather than block-by-block. This creates a buffer of size \p size, passes
* it to the given writer, then hands out block-sized chunks.
*/
void
ecma119_start_chunking(struct ecma119_write_target *t,
void (*)(struct ecma119_write_target*, uint8_t*),
off_t size,
uint8_t *buf);
#endif /* LIBISO_ECMA119_H */

View File

@ -1,312 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#include <assert.h>
#include "ecma119.h"
#include "ecma119_tree.h"
#include "tree.h"
#include "util.h"
static size_t calc_dirent_len(struct ecma119_tree_node *n)
{
int ret = n->name ? strlen(n->name) + 33 : 34;
if (ret % 2) ret++;
return ret;
}
static struct ecma119_tree_node*
create_dir(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
assert(t && (!parent || parent->type == ECMA119_DIR)
&& iso && S_ISDIR(iso->attrib.st_mode));
ret = calloc(1, sizeof(struct ecma119_tree_node));
ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_dirid(iso->name)
: iso_2_dirid(iso->name))
: NULL;
ret->dirent_len = calc_dirent_len(ret);
ret->iso_self = iso;
ret->target = t;
ret->type = ECMA119_DIR;
ret->parent = ret->dir.real_parent = parent;
ret->dir.depth = parent ? parent->dir.depth + 1 : 1;
ret->dir.nchildren = iso->nchildren;
ret->dir.children = calloc(1, sizeof(void*) * iso->nchildren);
return ret;
}
static struct ecma119_tree_node*
create_file(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
assert(t && iso && parent && parent->type == ECMA119_DIR);
ret = calloc(1, sizeof(struct ecma119_tree_node));
ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_fileid(iso->name)
: iso_2_fileid(iso->name))
: NULL;
ret->dirent_len = calc_dirent_len(ret);
ret->parent = parent;
ret->iso_self = iso;
ret->target = t;
ret->type = ECMA119_FILE;
return ret;
}
static struct ecma119_tree_node*
create_tree(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node *iso)
{
struct ecma119_tree_node *ret;
size_t i;
assert(t && iso);
ret = (S_ISDIR(iso->attrib.st_mode) ? create_dir : create_file)
(t, parent, iso);
for (i = 0; i < iso->nchildren; i++) {
ret->dir.children[i] = create_tree(t, ret, iso->children[i]);
}
return ret;
}
void
ecma119_tree_free(struct ecma119_tree_node *root)
{
size_t i;
if (root->type == ECMA119_DIR) {
for (i=0; i < root->dir.nchildren; i++) {
ecma119_tree_free(root->dir.children[i]);
}
free(root->dir.children);
}
free(root->name);
free(root);
}
static size_t
max_child_name_len(struct ecma119_tree_node *root)
{
size_t ret = 0, i;
assert(root->type == ECMA119_DIR);
for (i=0; i < root->dir.nchildren; i++) {
size_t len = strlen(root->dir.children[i]->name);
ret = MAX(ret, len);
}
return ret;
}
static void
reparent(struct ecma119_tree_node *child,
struct ecma119_tree_node *parent)
{
int found = 0;
size_t i;
struct ecma119_tree_node *placeholder;
assert(child && parent && parent->type == ECMA119_DIR && child->parent);
/* replace the child in the original parent with a placeholder */
for (i=0; i < child->parent->dir.nchildren; i++) {
if (child->parent->dir.children[i] == child) {
placeholder = create_file(child->target,
child->parent,
child->iso_self);
placeholder->file.real_me = child;
child->parent->dir.children[i] = placeholder;
found = 1;
break;
}
}
assert(found);
/* add the child to its new parent */
child->parent = parent;
parent->dir.nchildren++;
parent->dir.children = realloc( parent->dir.children,
sizeof(void*) * parent->dir.nchildren );
parent->dir.children[parent->dir.nchildren-1] = child;
}
/**
* Reorder the tree, if necessary, to ensure that
* - the depth is at most 8
* - each path length is at most 255 characters
*/
static void
reorder_tree(struct ecma119_tree_node *root,
struct ecma119_tree_node *cur)
{
size_t max_path;
assert(root && cur && cur->type == ECMA119_DIR);
cur->dir.depth = cur->parent ? cur->parent->dir.depth + 1 : 1;
cur->dir.path_len = cur->parent ? cur->parent->dir.path_len
+ strlen(cur->name) : 0;
max_path = cur->dir.path_len + cur->dir.depth + max_child_name_len(cur);
if (cur->dir.depth > 8 || max_path > 255) {
reparent(cur, root);
/* we are appended to the root's children now, so there is no
* need to recurse (the root will hit us again) */
} else {
size_t i;
for (i=0; i < cur->dir.nchildren; i++) {
if (cur->dir.children[i]->type == ECMA119_DIR)
reorder_tree(root, cur->dir.children[i]);
}
}
}
static int
cmp_node(const void *f1, const void *f2)
{
struct ecma119_tree_node *f = *((struct ecma119_tree_node**)f1);
struct ecma119_tree_node *g = *((struct ecma119_tree_node**)f2);
return strcmp(f->name, g->name);
}
static void
sort_tree(struct ecma119_tree_node *root)
{
size_t i;
assert(root && root->type == ECMA119_DIR);
qsort(root->dir.children, root->dir.nchildren, sizeof(void*), cmp_node);
for (i=0; i < root->dir.nchildren; i++) {
if (root->dir.children[i]->type == ECMA119_DIR)
sort_tree(root->dir.children[i]);
}
}
/**
* Change num_change characters of the given filename in order to ensure the
* name is unique. If the name is short enough (depending on the ISO level),
* we can append the characters instead of changing them.
*
* \p seq_num is the index of this file in the sequence of identical filenames.
*
* For example, seq_num=3, num_change=2, name="HELLOTHERE.TXT" changes name to
* "HELLOTHE03.TXT"
*/
static void
mangle_name(char **name, int num_change, int level, int seq_num)
{
char *dot = strrchr(*name, '.');
char *semi = strrchr(*name, ';');
size_t len = strlen(*name);
char base[len+1], ext[len+1];
char fmt[12];
size_t baselen, extlen;
if (num_change >= len) {
return;
}
strncpy(base, *name, len+1);
if (dot) {
base[dot - *name] = '\0';
strncpy(ext, dot+1, len+1);
if (semi) {
ext[semi - dot - 1] = '\0';
}
} else {
base[len-2] = '\0';
ext[0] = '\0';
}
baselen = strlen(base);
extlen = strlen(ext);
if (level == 1 && baselen + num_change > 8) {
base[8 - num_change] = '\0';
} else if (level != 1 && baselen + extlen + num_change > 30) {
base[30 - extlen - num_change] = '\0';
}
sprintf(fmt, "%%s%%0%1dd.%%s;1", num_change);
*name = realloc(*name, baselen + extlen + num_change + 4);
sprintf(*name, fmt, base, seq_num, ext);
}
static void
mangle_all(struct ecma119_tree_node *dir)
{
size_t i, j, k;
struct ecma119_dir_info d = dir->dir;
size_t n_change;
int changed;
assert(dir->type == ECMA119_DIR);
do {
changed = 0;
for (i=0; i < d.nchildren; i++) {
/* find the number of consecutive equal names */
j = 1;
while ( i+j < d.nchildren &&
!strcmp(d.children[i]->name,
d.children[i+j]->name) )
j++;
if (j == 1) continue;
/* mangle the names */
changed = 1;
n_change = j / 10 + 1;
for (k=0; k < j; k++) {
mangle_name(&(d.children[i+k]->name),
n_change,
dir->target->iso_level,
k);
d.children[i+k]->dirent_len =
calc_dirent_len(d.children[i+k]);
}
/* skip ahead by the number of mangled names */
i += j - 1;
}
} while (changed);
for (i=0; i < d.nchildren; i++) {
if (d.children[i]->type == ECMA119_DIR)
mangle_all(d.children[i]);
}
}
struct ecma119_tree_node*
ecma119_tree_create(struct ecma119_write_target *t,
struct iso_tree_node *iso_root)
{
t->root = create_tree(t, NULL, iso_root);
reorder_tree(t->root, t->root);
sort_tree(t->root);
mangle_all(t->root);
return t->root;
}
void
ecma119_tree_print(struct ecma119_tree_node *root, int spaces)
{
size_t i;
char sp[spaces+1];
memset(sp, ' ', spaces);
sp[spaces] = '\0';
printf("%s%s\n", sp, root->name);
if (root->type == ECMA119_DIR)
for (i=0; i < root->dir.nchildren; i++)
ecma119_tree_print(root->dir.children[i], spaces+2);
}

View File

@ -1,95 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* \file ecma119_tree.h
*
* Declarations for creating, modifying and printing filesystem trees that
* are compatible with ecma119.
*/
#ifndef LIBISO_ECMA119_TREE_H
#define LIBISO_ECMA119_TREE_H
struct ecma119_write_target;
enum {
ECMA119_FILE,
ECMA119_DIR
};
struct ecma119_dir_info {
struct susp_info self_susp; /**< susp entries for "." */
struct susp_info parent_susp; /**< susp entries for ".." */
size_t len; /**< sum of the lengths of children's
* Directory Records (including SU) */
size_t CE_len; /**< sum of the lengths of children's
* SUSP CE areas */
int depth;
size_t path_len; /**< The length of a path up to, and
* including, this directory. This
* cannot exceed 255. */
size_t nchildren;
struct ecma119_tree_node **children;
struct ecma119_tree_node *real_parent;
/**< The parent before relocation */
};
struct ecma119_file_info
{
struct ecma119_tree_node *real_me;
/**< If this is non-NULL, the file is
* a placeholder for a relocated
* directory and this field points to
* that relocated directory.
*/
};
/**
* A node for a tree containing all the information necessary for writing
* an ISO9660 volume.
*/
struct ecma119_tree_node
{
char *name; /**< in ASCII, conforming to the
* current ISO level. */
size_t dirent_len; /**< Length of the directory record,
* not including SU. */
size_t block;
struct ecma119_tree_node *parent;
struct iso_tree_node *iso_self;
struct ecma119_write_target *target;
struct susp_info susp;
int type; /**< file or directory */
/* union {*/
struct ecma119_dir_info dir;
struct ecma119_file_info file;
/* };*/
};
/**
* Create a new ecma119_tree that corresponds to the tree represented by
* \p iso_root.
*/
struct ecma119_tree_node*
ecma119_tree_create(struct ecma119_write_target *target,
struct iso_tree_node *iso_root);
/**
* Free an ecma119 tree.
*/
void
ecma119_tree_free(struct ecma119_tree_node *root);
/**
* Print an ecma119 tree.
*/
void
ecma119_tree_print(struct ecma119_tree_node *root, int spaces);
#endif /* LIBISO_ECMA119_TREE_H */

View File

@ -1,42 +0,0 @@
#include "hash.h"
#include "exclude.h"
static struct iso_hash_node *table[HASH_NODES]={0,};
static int num=0;
void
iso_exclude_add_path(const char *path)
{
if (!path)
return;
num += iso_hash_insert(table, path);
}
void
iso_exclude_remove_path(const char *path)
{
if (!num || !path)
return;
num -= iso_hash_remove(table, path);
}
void
iso_exclude_empty(void)
{
if (!num)
return;
iso_hash_empty(table);
num=0;
}
int
iso_exclude_lookup(const char *path)
{
if (!num || !path)
return 0;
return iso_hash_lookup(table, path);
}

View File

@ -1,12 +0,0 @@
#ifndef ISO_EXCLUDE_H
#define ISO_EXCLUDE_H
/**
* Add a path to ignore when adding a directory recursively.
*
* \param path The path, on the local filesystem, of the file.
*/
int
iso_exclude_lookup(const char *path);
#endif /* ISO_EXCLUDE */

View File

@ -1,158 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "hash.h"
static unsigned int
iso_hash_path(const char *path)
{
unsigned int hash_num=0;
const char *c;
c=path;
while(*c)
hash_num = (hash_num << 15) + (hash_num << 3) + (hash_num >> 3) + *c++;
return hash_num % HASH_NODES;
}
int
iso_hash_lookup(struct iso_hash_node **table, const char *path)
{
struct iso_hash_node *node;
unsigned int hash_num;
hash_num = iso_hash_path(path);
node=table[hash_num];
if (!node)
return 0;
if (!strcmp(path, node->path))
return 1;
while (node->next) {
node=node->next;
if (!strcmp(path, node->path))
return 1;
}
return 0;
}
static struct iso_hash_node*
iso_hash_node_new (const char *path)
{
struct iso_hash_node *node;
/*create an element to be inserted in the hash table */
node=malloc(sizeof(struct iso_hash_node));
node->path=strdup(path);
node->next=NULL;
return node;
}
int
iso_hash_insert(struct iso_hash_node **table, const char *path)
{
struct iso_hash_node *node;
unsigned int hash_num;
/* find the hash number */
hash_num = iso_hash_path(path);
/* insert it */
node = table[hash_num];
/* unfortunately, we can't safely consider that a path
* won't be twice in the hash table so make sure it
* doesn't already exists */
if (!node) {
table[hash_num]=iso_hash_node_new(path);
return 1;
}
/* if it's already in, we don't do anything */
if (!strcmp(path, node->path))
return 0;
while (node->next) {
node = node->next;
/* if it's already in, we don't do anything */
if (!strcmp (path, node->path))
return 0;
}
node->next = iso_hash_node_new(path);
return 1;
}
static void
iso_hash_node_free(struct iso_hash_node *node)
{
free(node->path);
free(node);
}
int
iso_hash_remove(struct iso_hash_node **table, const char *path)
{
unsigned int hash_num;
struct iso_hash_node *node;
hash_num = iso_hash_path(path);
node=table[hash_num];
if (!node)
return 0;
if (!strcmp(path, node->path)) {
table[hash_num]=node->next;
iso_hash_node_free(node);
return 1;
}
while (node->next) {
struct iso_hash_node *prev;
prev = node;
node = node->next;
if (!strcmp (path, node->path)) {
prev->next=node->next;
iso_hash_node_free(node);
return 1;
}
}
return 0;
}
void
iso_hash_empty(struct iso_hash_node **table)
{
int i;
for (i=0; i < HASH_NODES; i++) {
struct iso_hash_node *node;
node=table[i];
if (!node)
continue;
table[i]=NULL;
do {
struct iso_hash_node *next;
next=node->next;
iso_hash_node_free(node);
node=next;
} while (node);
}
}

View File

@ -1,46 +0,0 @@
#ifndef ISO_HASH_H
#define ISO_HASH_H
struct iso_hash_node {
struct iso_hash_node *next;
char *path;
};
#define HASH_NODES 128
/**
* Searches in the hash table if the path exists.
*
* \param table The hash table.
* \param path The path of the file to look for.
*
* \return 1 if the path exists in the hash table, 0 otherwise.
*/
int iso_hash_lookup(struct iso_hash_node **table, const char *path);
/**
* Insert a new path in the hash table.
*
* \param table The hash table.
* \param path The path of a file to add to the hash table.
*
* \return 1 if the file wasn't already in the hash table, 0 otherwise.
*/
int iso_hash_insert(struct iso_hash_node **table, const char *path);
/**
* Remove a path from the hash table.
*
* \param table The hash table.
* \param path The path of a file to remove from the hash table.
*
* \return 1 if the file was found and removed, 0 otherwise.
*/
int iso_hash_remove(struct iso_hash_node **table, const char *path);
/**
* Empty the hash table.
*/
void iso_hash_empty(struct iso_hash_node **table);
#endif /* ISO_HASH_H */

View File

@ -1,379 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
#include "joliet.h"
#include "ecma119.h"
#include "ecma119_tree.h"
#include "tree.h"
#include "util.h"
#include "volume.h"
#include <assert.h>
#include <string.h>
static struct joliet_tree_node*
create_node(struct ecma119_write_target *t,
struct joliet_tree_node *parent,
struct iso_tree_node *iso)
{
struct joliet_tree_node *ret =
calloc(1, sizeof(struct joliet_tree_node));
ret->name = iso_j_id(iso->name);
ret->dirent_len = 34 + (ret->name ? ucslen(ret->name) * 2 : 0);
ret->len = iso->attrib.st_size; /* for dirs, we'll change this */
ret->block = iso->block; /* only actually for files, not dirs */
ret->parent = parent;
ret->iso_self = iso;
ret->target = t;
ret->nchildren = iso->nchildren;
if (ret->nchildren)
ret->children = calloc(sizeof(void*), ret->nchildren);
return ret;
}
static struct joliet_tree_node*
create_tree(struct ecma119_write_target *t,
struct joliet_tree_node *parent,
struct iso_tree_node *iso_root)
{
struct joliet_tree_node *root = create_node(t, parent, iso_root);
size_t i;
for (i = 0; i < root->nchildren; i++) {
struct iso_tree_node *iso_ch = iso_root->children[i];
if (ISO_ISDIR(iso_ch))
root->children[i] = create_tree(t, root, iso_ch);
else
root->children[i] = create_node(t, root, iso_ch);
}
return root;
}
static int
cmp_node(const void *f1, const void *f2)
{
struct joliet_tree_node *f = *((struct joliet_tree_node**)f1);
struct joliet_tree_node *g = *((struct joliet_tree_node**)f2);
return ucscmp(f->name, g->name);
}
static void
sort_tree(struct joliet_tree_node *root)
{
size_t i;
assert(root && ISO_ISDIR(root->iso_self));
qsort(root->children, root->nchildren, sizeof(void*), cmp_node);
for (i = 0; i < root->nchildren; i++)
if (ISO_ISDIR(root->children[i]->iso_self))
sort_tree(root->children[i]);
}
void
joliet_prepare_path_tables(struct ecma119_write_target *t)
{
size_t cur, i, j;
t->pathlist_joliet[0] = t->joliet_root;
t->path_table_size_joliet = 10; /* root directory record */
cur = 1;
for (i = 0; i < t->dirlist_len; i++) {
struct joliet_tree_node *dir = t->pathlist_joliet[i];
for (j = 0; j < dir->nchildren; j++) {
struct joliet_tree_node *ch = dir->children[j];
if (ISO_ISDIR(ch->iso_self)) {
size_t len = 8 + ucslen(ch->name)*2;
t->pathlist_joliet[cur++] = ch;
t->path_table_size_joliet += len;
}
}
}
}
/**
* Calculate the size of each directory.
*/
void
joliet_calc_dir_size(struct ecma119_write_target *t,
struct joliet_tree_node *root)
{
size_t i;
struct joliet_tree_node *ch;
assert(root && ISO_ISDIR(root->iso_self));
root->len = 68; /* for "." and ".." entries */
for (i = 0; i < root->nchildren; i++) {
ch = root->children[i];
root->len += ch->dirent_len;
if (ISO_ISDIR(ch->iso_self))
joliet_calc_dir_size(t, ch);
}
t->total_dir_size_joliet += round_up (root->len, t->block_size);
}
/**
* Calculate the position of each directory. Also fill out t->dirlist_joliet.
*/
void
joliet_calc_dir_pos(struct ecma119_write_target *t,
struct joliet_tree_node *root)
{
size_t i;
struct joliet_tree_node *ch;
assert(root && ISO_ISDIR(root->iso_self));
root->block = t->curblock;
t->curblock += div_up(root->len, t->block_size);
t->dirlist_joliet[t->curfile++] = root;
for (i = 0; i < root->nchildren; i++) {
ch = root->children[i];
if (ISO_ISDIR(ch->iso_self))
joliet_calc_dir_pos(t, ch);
}
/* reset curfile when we're finished */
if (!root->parent)
t->curfile = 0;
}
void
joliet_update_file_pos(struct ecma119_write_target *t,
struct joliet_tree_node *dir)
{
size_t i;
assert(dir && ISO_ISDIR(dir->iso_self));
for (i = 0; i < dir->nchildren; i++) {
struct joliet_tree_node *ch;
ch = dir->children[i];
if (!ISO_ISDIR (ch->iso_self)) {
struct iso_tree_node *iso = ch->iso_self;
ch->block = iso->block;
}
else
joliet_update_file_pos(t, ch);
}
/* reset curfile when we're finished */
if (!dir->parent)
t->curfile = 0;
}
struct joliet_tree_node*
joliet_tree_create(struct ecma119_write_target *t,
struct iso_tree_node *iso_root)
{
struct joliet_tree_node *root = create_tree(t, NULL, iso_root);
sort_tree(root);
return root;
}
/* ugh. this is mostly C&P */
static void
write_path_table(struct ecma119_write_target *t,
int l_type,
uint8_t *buf)
{
void (*write_int)(uint8_t*, uint32_t, int) = l_type ?
iso_lsb : iso_msb;
size_t i;
struct ecma119_path_table_record *rec;
struct joliet_tree_node *dir;
int parent = 0;
assert (t->joliet);
for (i = 0; i < t->dirlist_len; i++) {
dir = t->pathlist_joliet[i];
while ((i) && t->pathlist_joliet[parent] != dir->parent)
parent++;
assert(parent < i || i == 0);
rec = (struct ecma119_path_table_record*) buf;
rec->len_di[0] = dir->parent ?
(uint8_t) ucslen(dir->name) * 2 : 1;
rec->len_xa[0] = 0;
write_int(rec->block, dir->block, 4);
write_int(rec->parent, parent + 1, 2);
if (dir->parent)
memcpy(rec->dir_id, dir->name, rec->len_di[0]);
buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2);
}
}
/* if file_id is >= 0, we use it instead of the filename. As a magic number,
* file_id == 3 means that we are writing the root directory record (in order
* to distinguish it from the "." entry in the root directory) */
static void
write_one_dir_record(struct ecma119_write_target *t,
struct joliet_tree_node *node,
int file_id,
uint8_t *buf)
{
uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len;
uint8_t len_fi = (file_id >= 0) ? 1 : ucslen(node->name) * 2;
uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id);
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name;
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
if (file_id == 1 && node->parent)
node = node->parent;
rec->len_dr[0] = len_dr;
iso_bb(rec->block, node->block, 4);
iso_bb(rec->length, node->len, 4);
iso_datetime_7(rec->recording_time, t->now);
rec->flags[0] = ISO_ISDIR(node->iso_self) ? 2 : 0;
iso_bb(rec->vol_seq_number, t->volnum + 1, 2);
rec->len_fi[0] = len_fi;
memcpy(rec->file_id, name, len_fi);
}
static void
write_l_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
write_path_table (t, 1, buf);
}
static void
write_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
{
write_path_table (t, 0, buf);
}
static void
write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
struct ecma119_sup_vol_desc *vol = (struct ecma119_sup_vol_desc*)buf;
struct iso_volume *volume = t->volset->volume[t->volnum];
uint16_t *vol_id = str2ucs(volume->volume_id);
uint16_t *pub_id = str2ucs(volume->publisher_id);
uint16_t *data_id = str2ucs(volume->data_preparer_id);
uint16_t *volset_id = str2ucs(t->volset->volset_id);
int vol_id_len = MIN(32, ucslen(vol_id) * 2);
int pub_id_len = MIN(128, ucslen(pub_id) * 2);
int data_id_len = MIN(128, ucslen(data_id) * 2);
int volset_id_len = MIN(128, ucslen(volset_id) * 2);
vol->vol_desc_type[0] = 2;
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
memcpy(vol->system_id, "SYSID", 5);
if (vol_id)
memcpy(vol->volume_id, vol_id, vol_id_len);
memcpy(vol->esc_sequences, "%/E", 3);
iso_bb(vol->vol_space_size, t->vol_space_size, 4);
iso_bb(vol->vol_set_size, t->volset->volset_size, 2);
iso_bb(vol->vol_seq_number, t->volnum + 1, 2);
iso_bb(vol->block_size, t->block_size, 2);
iso_bb(vol->path_table_size, t->path_table_size_joliet, 4);
iso_lsb(vol->l_path_table_pos, t->l_path_table_pos_joliet, 4);
iso_msb(vol->m_path_table_pos, t->m_path_table_pos_joliet, 4);
write_one_dir_record(t, t->joliet_root, 3, vol->root_dir_record);
memcpy(vol->vol_set_id, volset_id, volset_id_len);
memcpy(vol->publisher_id, pub_id, pub_id_len);
memcpy(vol->data_prep_id, data_id, data_id_len);
/*memcpy(vol->application_id, "APPID", app_id_len);*/
iso_datetime_17(vol->vol_creation_time, t->now);
iso_datetime_17(vol->vol_modification_time, t->now);
iso_datetime_17(vol->vol_effective_time, t->now);
vol->file_structure_version[0] = 1;
free(vol_id);
free(volset_id);
free(pub_id);
free(data_id);
}
static void
write_one_dir(struct ecma119_write_target *t,
struct joliet_tree_node *dir,
uint8_t *buf)
{
size_t i;
uint8_t *orig_buf = buf;
assert(ISO_ISDIR (dir->iso_self));
/* write the "." and ".." entries first */
write_one_dir_record(t, dir, 0, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
write_one_dir_record(t, dir, 1, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
for (i = 0; i < dir->nchildren; i++) {
write_one_dir_record(t, dir->children[i], -1, buf);
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
}
assert (buf - orig_buf == dir->len);
}
static void
write_dirs(struct ecma119_write_target *t, uint8_t *buf)
{
size_t i;
struct joliet_tree_node *dir;
assert (t->curblock == t->dirlist_joliet[0]->block);
for (i = 0; i < t->dirlist_len; i++) {
dir = t->dirlist_joliet[i];
write_one_dir(t, dir, buf);
buf += round_up(dir->len, t->block_size);
}
}
void
joliet_wr_sup_vol_desc(struct ecma119_write_target *t,
uint8_t *buf)
{
ecma119_start_chunking(t,
write_sup_vol_desc,
2048,
buf);
}
void
joliet_wr_l_path_table(struct ecma119_write_target *t,
uint8_t *buf)
{
ecma119_start_chunking(t,
write_l_path_table,
t->path_table_size_joliet,
buf);
}
void
joliet_wr_m_path_table(struct ecma119_write_target *t,
uint8_t *buf)
{
ecma119_start_chunking(t,
write_m_path_table,
t->path_table_size_joliet,
buf);
}
void
joliet_wr_dir_records(struct ecma119_write_target *t,
uint8_t *buf)
{
ecma119_start_chunking(t,
write_dirs,
t->total_dir_size_joliet,
buf);
}

View File

@ -1,84 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* \file joliet.h
*
* Declare the filesystems trees that are Joliet-compatible and the public
* functions for tying them into an ecma119 volume.
*/
#ifndef LIBISO_JOLIET_H
#define LIBISO_JOLIET_H
#include <stdint.h>
#include <stdlib.h>
struct ecma119_write_target;
struct iso_tree_node;
struct joliet_tree_node
{
uint16_t *name; /**< In UCS-2BE. */
size_t dirent_len;
size_t len;
size_t block;
struct joliet_tree_node *parent;
struct iso_tree_node *iso_self;
struct ecma119_write_target *target;
struct joliet_tree_node **children;
size_t nchildren;
};
/**
* Create a new joliet_tree that corresponds to the tree represented by
* \p iso_root.
*/
struct joliet_tree_node*
joliet_tree_create(struct ecma119_write_target *target,
struct iso_tree_node *iso_root);
/**
* Calculate the size of each directory in the joliet heirarchy.
*/
void
joliet_calc_dir_size(struct ecma119_write_target *t, struct joliet_tree_node*);
/**
* Calculate the position of each directory in the joliet heirarchy.
*/
void
joliet_calc_dir_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
/**
* Update the position of each file in the joliet hierarchy (to be called
* AFTER the file positions in the iso tree have been set).
*/
void
joliet_update_file_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
/**
* Calculate the size of the joliet path table and fill in the list of
* directories.
*/
void
joliet_prepare_path_tables(struct ecma119_write_target *t);
void
joliet_tree_free(struct joliet_tree_node *root);
void
joliet_wr_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
void
joliet_wr_l_path_table(struct ecma119_write_target *t, uint8_t *buf);
void
joliet_wr_m_path_table(struct ecma119_write_target *t, uint8_t *buf);
void
joliet_wr_dir_records(struct ecma119_write_target *t, uint8_t *buf);
#endif /* LIBISO_JOLIET_H */

View File

@ -1,225 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* Create an ISO-9660 data volume with Rock Ridge and Joliet extensions.
* Usage is easy:
* - Create a new volume.
* - Add files and directories.
* - Write the volume to a file or create a burn source for use with Libburn.
*/
#ifndef LIBISO_LIBISOFS_H
#define LIBISO_LIBISOFS_H
/* #include <libburn.h> */
struct burn_source;
/**
* Data volume.
* @see volume.h for details.
*/
struct iso_volume;
/**
* A set of data volumes.
* @see volume.h for details.
*/
struct iso_volset;
/**
* A node in the filesystem tree.
* \see tree.h
*/
struct iso_tree_node;
enum ecma119_extension_flag {
ECMA119_ROCKRIDGE = (1<<0),
ECMA119_JOLIET = (1<<1)
};
/**
* Create a new volume.
* The parameters can be set to NULL if you wish to set them later.
*/
struct iso_volume *iso_volume_new(const char *volume_id,
const char *publisher_id,
const char *data_preparer_id);
struct iso_volume *iso_volume_new_with_root(const char *volume_id,
const char *publisher_id,
const char *data_preparer_id,
struct iso_tree_node *root);
/**
* Free a volume.
*/
void iso_volume_free(struct iso_volume *volume);
/**
* Free a set of data volumes.
*/
void iso_volset_free(struct iso_volset *volume);
/**
* Get the root directory for a volume.
*/
struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume);
/**
* Fill in the volume identifier for a volume.
*/
void iso_volume_set_volume_id(struct iso_volume *volume,
const char *volume_id);
/**
* Fill in the publisher for a volume.
*/
void iso_volume_set_publisher_id(struct iso_volume *volume,
const char *publisher_id);
/**
* Fill in the data preparer for a volume.
*/
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
const char *data_preparer_id);
/**
* Locate a node by its path on disc.
*
* \param volume The volume to search in.
* \param path The path, in the image, of the file.
*
* \return The node found or NULL.
*
*/
struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path);
/**
* Add a file or a directory (recursively) to a volume by specifying its path on the volume.
*
* \param volume The volume to add the file to.
* \param disc_path The path on the disc at which to add the disc.
* \param path The path, on the local filesystem, of the file.
*
* \return The node for the file or NULL if the parent doesn't exists on the disc.
*/
struct iso_tree_node *iso_tree_volume_add_path(struct iso_volume *volume,
const char *disc_path,
const char *path);
/**
* Creates a new, empty directory on the volume.
*
* \param volume The volume to add the directory to.
* \param disc_path The path on the volume at which to add the directory.
*
* \return A pointer to the newly created directory.
*/
struct iso_tree_node *iso_tree_volume_add_new_dir(struct iso_volume *volume,
const char *disc_path);
/**
* Create a new Volume Set consisting of only one volume.
* @param volume The first and only volume for the volset to contain.
* @param volset_id The Volume Set ID.
* @return A new iso_volset.
*/
struct iso_volset *iso_volset_new(struct iso_volume *volume,
const char *volset_id);
/**
* Add a file to a directory.
*
* \param path The path, on the local filesystem, of the file.
*
* \pre \p parent is NULL or is a directory.
* \pre \p path is non-NULL and is a valid path to a non-directory on the local
* filesystem.
* \return An iso_tree_node whose path is \p path and whose parent is \p parent.
*/
struct iso_tree_node *iso_tree_add_node(struct iso_tree_node *parent,
const char *path);
/**
* Recursively add an existing directory to the tree.
* Warning: when using this, you'll lose pointers to files or subdirectories.
* If you want to have pointers to all files and directories,
* use iso_tree_add_file and iso_tree_add_dir.
*
* \param path The path, on the local filesystem, of the directory to add.
*
* \pre \p parent is NULL or is a directory.
* \pre \p path is non-NULL and is a valid path to a directory on the local
* filesystem.
* \return a pointer to the newly created directory.
*/
struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent,
const char *path);
/**
* Add the path of a file or directory to ignore when adding a directory recursively.
*
* \param path The path, on the local filesystem, of the file.
*/
void iso_exclude_add_path(const char *path);
/**
* Remove a path that was set to be ignored when adding a directory recusively.
*
* \param path The path, on the local filesystem, of the file.
*/
void iso_exclude_remove_path(const char *path);
/**
* Remove all paths that were set to be ignored when adding a directory recusively.
*/
void iso_exclude_empty(void);
/**
* Creates a new, empty directory on the volume.
*
* \pre \p parent is NULL or is a directory.
* \pre \p name is unique among the children and files belonging to \p parent.
* Also, it doesn't contain '/' characters.
*
* \post \p parent contains a child directory whose name is \p name and whose
* POSIX attributes are the same as \p parent's.
* \return a pointer to the newly created directory.
*/
struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent,
const char *name);
/**
* Set the name of a file (using the current locale).
*/
void iso_tree_node_set_name(struct iso_tree_node *file, const char *name);
/**
* Recursively print a directory to stdout.
* \param spaces The initial number of spaces on the left. Set to 0 if you
* supply a root directory.
*/
void iso_tree_print(const struct iso_tree_node *root, int spaces);
/** Create a burn_source which can be used as a data source for a track
*
* The volume set used to create the libburn_source can _not_ be modified
* until the libburn_source is freed.
*
* \param volumeset The volume set from which you want to write
* \param volnum The volume in the set which you want to write (usually 0)
* \param level ISO level to write at.
* \param flags Which extensions to support.
*
* \pre \p volumeset is non-NULL
* \pre \p volnum is less than \p volset->volset_size.
* \return A burn_source to be used for the data source for a track
*/
struct burn_source* iso_source_new_ecma119 (struct iso_volset *volumeset,
int volnum,
int level,
int flags);
#endif /* LIBISO_LIBISOFS_H */

View File

@ -1,300 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
#include "rockridge.h"
#include "util.h"
#include "ecma119.h"
#include "ecma119_tree.h"
#include "tree.h"
#include "susp.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
/* create a PX field from the permissions on the current node. */
uint8_t *rrip_make_PX(struct ecma119_write_target *t,
struct ecma119_tree_node *node)
{
uint8_t *PX = malloc(44);
PX[0] = 'P';
PX[1] = 'X';
PX[2] = 44;
PX[3] = 1;
iso_bb(&PX[4], node->iso_self->attrib.st_mode, 4);
iso_bb(&PX[12], node->iso_self->attrib.st_nlink, 4);
iso_bb(&PX[20], node->iso_self->attrib.st_uid, 4);
iso_bb(&PX[28], node->iso_self->attrib.st_gid, 4);
iso_bb(&PX[36], node->iso_self->attrib.st_ino, 4);
return PX;
}
/** See IEEE 1282 4.1.1 */
void rrip_add_PX(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
susp_append(t, &node->susp, rrip_make_PX(t, node));
if (node->type == ECMA119_DIR) {
susp_append(t, &node->dir.self_susp, rrip_make_PX(t, node));
susp_append(t, &node->dir.parent_susp, rrip_make_PX(t, node));
}
}
void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
uint8_t *PN = malloc(20);
PN[0] = 'P';
PN[1] = 'N';
PN[2] = 20;
PN[3] = 1;
iso_bb(&PN[4], node->iso_self->attrib.st_dev >> 32, 4);
iso_bb(&PN[12], node->iso_self->attrib.st_dev & 0xffffffff, 4);
susp_append(t, &node->susp, PN);
}
static void rrip_SL_append_comp(int *n, uint8_t ***comps,
char *s, int size, char fl)
{
uint8_t *comp = malloc(size + 2);
(*n)++;
comp[0] = fl;
comp[1] = size;
*comps = realloc(*comps, (*n) * sizeof(void*));
(*comps)[(*n) - 1] = comp;
if (size) {
memcpy(&comp[2], s, size);
}
}
static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
uint8_t ***comps)
{
int size = cur - prev;
if (size == 0) {
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 3);
return;
}
if (size == 1 && prev[0] == '.') {
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 1);
return;
}
if (size == 2 && !strncmp(prev, "..", 2)) {
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 2);
return;
}
/* we can't make a component any bigger than 250 (is this really a
problem)? because then it won't fit inside the SL field */
while (size > 248) {
size -= 248;
rrip_SL_append_comp(n_comp, comps, prev, 248, 1 << 0);
}
rrip_SL_append_comp(n_comp, comps, prev, size, 0);
}
void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
int ret, pathsize = 0;
char *path = NULL, *cur, *prev;
int i, j;
uint8_t **comp = NULL;
int n_comp = 0;
int total_comp_len = 0;
int written = 0, pos;
uint8_t *SL;
do {
pathsize += 128;
path = realloc(path, pathsize);
/* FIXME: what if the file is not on the local fs? */
ret = readlink(node->iso_self->loc.path, path, pathsize);
} while (ret == pathsize);
if (ret == -1) {
fprintf(stderr, "Error: couldn't read symlink: %s\n",
strerror(errno));
return;
}
path[ret] = '\0';
prev = path;
for (cur = strchr(path, '/'); cur && *cur; cur = strchr(cur, '/')) {
rrip_SL_add_component(prev, cur, &n_comp, &comp);
cur++;
prev = cur;
}
/* if there was no trailing '/', we need to add the last component. */
if (prev == path || prev != &path[ret - 1]) {
rrip_SL_add_component(prev, &path[ret], &n_comp, &comp);
}
for (i = 0; i < n_comp; i++) {
total_comp_len += comp[i][1] + 2;
if (total_comp_len > 250) {
total_comp_len -= comp[i][1] + 2;
SL = malloc(total_comp_len + 5);
SL[0] = 'S';
SL[1] = 'L';
SL[2] = total_comp_len + 5;
SL[3] = 1;
SL[4] = 1; /* CONTINUE */
pos = 5;
for (j = written; j < i; j++) {
memcpy(&SL[pos], comp[j], comp[j][2]);
pos += comp[j][2];
}
susp_append(t, &node->susp, SL);
written = i - 1;
total_comp_len = comp[i][1];
}
}
SL = malloc(total_comp_len + 5);
SL[0] = 'S';
SL[1] = 'L';
SL[2] = total_comp_len + 5;
SL[3] = 1;
SL[4] = 0;
pos = 5;
for (j = written; j < n_comp; j++) {
memcpy(&SL[pos], comp[j], comp[j][1] + 2);
pos += comp[j][1] + 2;
}
susp_append(t, &node->susp, SL);
free(path);
/* free the components */
for (i = 0; i < n_comp; i++) {
free(comp[i]);
}
free(comp);
}
static void rrip_add_NM_single(struct ecma119_write_target *t,
struct susp_info *susp,
char *name, int size, int flags)
{
uint8_t *NM = malloc(size + 5);
NM[0] = 'N';
NM[1] = 'M';
NM[2] = size + 5;
NM[3] = 1;
NM[4] = flags;
if (size) {
memcpy(&NM[5], name, size);
}
susp_append(t, susp, NM);
}
void
rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
char *name = iso_p_fileid(node->iso_self->name);
int len = name ? strlen(name) : 0;
char *pos = name;
if (!len)
return;
if (node->type == ECMA119_DIR) {
rrip_add_NM_single(t, &node->dir.self_susp, pos, 0, 1 << 1);
rrip_add_NM_single(t, &node->dir.parent_susp, pos, 0, 1 << 2);
}
while (len > 250) {
rrip_add_NM_single(t, &node->susp, pos, 250, 1);
len -= 250;
pos += 250;
}
rrip_add_NM_single(t, &node->susp, pos, len, 0);
}
void rrip_add_CL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
uint8_t *CL = calloc(1, 12);
CL[0] = 'C';
CL[1] = 'L';
CL[2] = 12;
CL[3] = 1;
susp_append(t, &node->susp, CL);
}
void
rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
uint8_t *PL = calloc(1, 12);
PL[0] = 'P';
PL[1] = 'L';
PL[2] = 12;
PL[3] = 1;
susp_append(t, &node->dir.parent_susp, PL);
}
void
rrip_add_RE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
uint8_t *RE = malloc(4);
RE[0] = 'R';
RE[1] = 'E';
RE[2] = 4;
RE[3] = 1;
susp_append(t, &node->susp, RE);
}
void
rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
uint8_t *TF = malloc(5 + 3 * 7);
TF[0] = 'T';
TF[1] = 'F';
TF[2] = 5 + 3 * 7;
TF[3] = 1;
TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7);
iso_datetime_7(&TF[5], node->iso_self->attrib.st_mtime);
iso_datetime_7(&TF[12], node->iso_self->attrib.st_atime);
iso_datetime_7(&TF[19], node->iso_self->attrib.st_ctime);
susp_append(t, &node->susp, TF);
}
void
rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{
int i;
assert(dir->type == ECMA119_DIR);
if (dir->parent != dir->dir.real_parent) {
uint8_t *PL = susp_find(&dir->dir.parent_susp, "PL");
assert(PL);
iso_bb(&PL[4], dir->dir.real_parent->block, 4);
}
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
if (ch->type == ECMA119_FILE && ch->file.real_me) {
uint8_t *CL = susp_find(&ch->susp, "CL");
assert(CL);
iso_bb(&CL[4], ch->file.real_me->block, 4);
} else if (ch->type == ECMA119_DIR) {
rrip_finalize(t, ch);
}
}
}

View File

@ -1,26 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
/** Functions and structures used for Rock Ridge support. */
#ifndef ISO_ROCKRIDGE_H
#define ISO_ROCKRIDGE_H
struct ecma119_write_target;
struct ecma119_tree_node;
void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *);
/* This is special because it doesn't modify the susp fields of the directory
* that gets passed to it; it modifies the susp fields of the ".." entry in
* that directory. */
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
#endif /* ISO_ROCKRIDGE_H */

View File

@ -1,280 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
#include "susp.h"
#include "util.h"
#include "ecma119.h"
#include "ecma119_tree.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>
void susp_insert(struct ecma119_write_target *t,
struct susp_info *susp,
uint8_t *data,
int pos)
{
int i;
if (pos < 0) {
pos = susp->n_susp_fields;
}
assert(pos <= susp->n_susp_fields);
susp->n_susp_fields++;
susp->susp_fields = realloc(susp->susp_fields,
sizeof(void*) * susp->n_susp_fields);
for (i = susp->n_susp_fields-1; i > pos; i--) {
susp->susp_fields[i] = susp->susp_fields[i - 1];
}
susp->susp_fields[pos] = data;
}
void susp_append(struct ecma119_write_target *t,
struct susp_info *susp,
uint8_t *data)
{
susp_insert(t, susp, data, susp->n_susp_fields);
}
uint8_t *susp_find(struct susp_info *susp, const char *name)
{
int i;
for (i = 0; i < susp->n_susp_fields; i++) {
if (!strncmp((char *)susp->susp_fields[i], name, 2)) {
return susp->susp_fields[i];
}
}
return NULL;
}
/** Utility function for susp_add_CE because susp_add_CE needs to act 3 times
* on directories (for the "." and ".." entries.
*
* \param len The amount of space available for the System Use area.
*/
#define CE_LEN 28
static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
struct susp_info *susp,
int len)
{
int susp_length = 0, tmp_len;
int i;
unsigned char *CE;
for (i = 0; i < susp->n_susp_fields; i++) {
susp_length += susp->susp_fields[i][2];
}
if (susp_length <= len) {
/* no need for a CE field */
susp->non_CE_len = susp_length;
susp->n_fields_fit = susp->n_susp_fields;
return NULL;
}
tmp_len = susp_length;
for (i = susp->n_susp_fields - 1; i >= 0; i--) {
tmp_len -= susp->susp_fields[i][2];
if (tmp_len + CE_LEN <= len) {
susp->non_CE_len = tmp_len + CE_LEN;
susp->CE_len = susp_length - tmp_len;
/* i+1 because we have to count the CE field */
susp->n_fields_fit = i + 1;
CE = calloc(1, CE_LEN);
/* we don't fill in the BLOCK LOCATION or OFFSET
fields yet. */
CE[0] = 'C';
CE[1] = 'E';
CE[2] = (char)CE_LEN;
CE[3] = (char)1;
iso_bb(&CE[20], susp_length - tmp_len, 4);
return CE;
}
}
assert(0);
return NULL;
}
static void
try_add_CE(struct ecma119_write_target *t,
struct susp_info *susp,
size_t dirent_len)
{
uint8_t *CE = susp_add_single_CE(t, susp, 255 - dirent_len);
if (CE)
susp_insert(t, susp, CE, susp->n_fields_fit - 1);
}
/** See IEEE P1281 Draft Version 1.12/5.2. Because this function depends on the
* length of the other SUSP fields, it should always be calculated last. */
void
susp_add_CE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{
try_add_CE(t, &node->susp, node->dirent_len);
if (node->type == ECMA119_DIR) {
try_add_CE(t, &node->dir.self_susp, 34);
try_add_CE(t, &node->dir.parent_susp, 34);
}
}
/** See IEEE P1281 Draft Version 1.12/5.3 */
void
susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{
unsigned char *SP = malloc(7);
assert(dir->type == ECMA119_DIR);
SP[0] = 'S';
SP[1] = 'P';
SP[2] = (char)7;
SP[3] = (char)1;
SP[4] = 0xbe;
SP[5] = 0xef;
SP[6] = 0;
susp_append(t, &dir->dir.self_susp, SP);
}
#if 0
/** See IEEE P1281 Draft Version 1.12/5.4 */
static void susp_add_ST(struct ecma119_write_target *t,
struct iso_tree_node *node)
{
unsigned char *ST = malloc(4);
ST[0] = 'S';
ST[1] = 'T';
ST[2] = (char)4;
ST[3] = (char)1;
susp_append(t, node, ST);
}
#endif
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
void
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{
unsigned char *ER = malloc(182);
assert(dir->type == ECMA119_DIR);
ER[0] = 'E';
ER[1] = 'R';
ER[2] = 182;
ER[3] = 1;
ER[4] = 9;
ER[5] = 72;
ER[6] = 93;
ER[7] = 1;
memcpy(&ER[8], "IEEE_1282", 9);
memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
"FILE SYSTEM SEMANTICS.", 72);
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
susp_append(t, &dir->dir.self_susp, ER);
}
/* calculate the location of the CE areas. Since CE areas don't need to be
* aligned to a block boundary, we contatenate all CE areas from a single
* directory and dump them immediately after all the directory records.
*
* Requires that the following be known:
* - position of the current directory (dir->block)
* - length of the current directory (dir->dir.len)
* - sum of the children's CE lengths (dir->dir.CE_len)
*/
static void
susp_fin_1_CE(struct ecma119_write_target *t,
struct susp_info *susp,
size_t block,
size_t *offset)
{
uint8_t *CE = susp->susp_fields[susp->n_fields_fit - 1];
if (!susp->CE_len) {
return;
}
iso_bb(&CE[4], block + (*offset) / t->block_size, 4);
iso_bb(&CE[12], (*offset) % t->block_size, 4);
*offset += susp->CE_len;
}
static void susp_fin_CE(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
{
int i;
size_t CE_offset = dir->dir.len;
assert(dir->type == ECMA119_DIR);
susp_fin_1_CE(t, &dir->dir.self_susp, dir->block, &CE_offset);
susp_fin_1_CE(t, &dir->dir.parent_susp, dir->block, &CE_offset);
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
susp_fin_1_CE(t, &ch->susp, dir->block, &CE_offset);
}
assert(CE_offset == dir->dir.len + dir->dir.CE_len);
}
void
susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{
int i;
assert(dir->type = ECMA119_DIR);
if (dir->dir.depth != 1) {
susp_fin_CE(t, dir);
}
for (i = 0; i < dir->dir.nchildren; i++) {
if (dir->dir.children[i]->type == ECMA119_DIR)
susp_finalize(t, dir->dir.children[i]);
}
}
void susp_write(struct ecma119_write_target *t,
struct susp_info *susp,
unsigned char *buf)
{
int i;
int pos = 0;
for (i = 0; i < susp->n_fields_fit; i++) {
memcpy(&buf[pos], susp->susp_fields[i],
susp->susp_fields[i][2]);
pos += susp->susp_fields[i][2];
}
}
void susp_write_CE(struct ecma119_write_target *t, struct susp_info *susp,
unsigned char *buf)
{
int i;
int pos = 0;
for (i = susp->n_fields_fit; i < susp->n_susp_fields; i++) {
memcpy(&buf[pos], susp->susp_fields[i],
susp->susp_fields[i][2]);
pos += susp->susp_fields[i][2];
}
}
void susp_free_fields(struct susp_info *susp)
{
int i;
for (i=0; i<susp->n_susp_fields; i++) {
free(susp->susp_fields[i]);
}
if (susp->susp_fields) {
free(susp->susp_fields);
}
memset(susp, 0, sizeof(struct susp_info));
}

View File

@ -1,62 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
/** Functions and structures used for SUSP (IEEE 1281).
*/
#ifndef __ISO_SUSP
#define __ISO_SUSP
#include <stdint.h>
/* SUSP is only present in standard ecma119 */
struct ecma119_write_target;
struct ecma119_tree_node;
/** This contains the information that needs to go in the SUSP area of a file.
*/
struct susp_info
{
int n_susp_fields; /**< Number of SUSP fields */
uint8_t **susp_fields; /**< Data for each SUSP field */
/* the next 3 relate to CE and are filled out by susp_add_CE. */
int n_fields_fit; /**< How many of the above SUSP fields fit
* within this node's dirent. */
int non_CE_len; /**< Length of the part of the SUSP area that
* fits in the dirent. */
int CE_len; /**< Length of the part of the SUSP area that
* will go in a CE area. */
};
void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *);
/* these next 2 are special because they don't modify the susp fields of the
* directory; they modify the susp fields of the
* "." entry in the directory. */
void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
/** Once all the directories and files are laid out, recurse through the tree
* and finalize all SUSP CE entries. */
void susp_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
void susp_append(struct ecma119_write_target *,
struct susp_info *,
uint8_t *);
void susp_insert(struct ecma119_write_target *,
struct susp_info *,
uint8_t *,
int pos);
uint8_t *susp_find(struct susp_info *,
const char *);
void susp_write(struct ecma119_write_target *,
struct susp_info *,
uint8_t *);
void susp_write_CE(struct ecma119_write_target *,
struct susp_info *,
uint8_t *);
void susp_free_fields(struct susp_info *);
#endif /* __ISO_SUSP */

View File

@ -1,223 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* \file tree.c
*
* Implement filesystem trees.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <err.h>
#include <stdio.h>
#include "tree.h"
#include "util.h"
#include "volume.h"
#include "exclude.h"
static void
set_default_stat(struct stat *s)
{
time_t now = time(NULL);
memset(s, 0, sizeof(struct stat));
s->st_mode = 0777 | S_IFREG;
s->st_atime = s->st_mtime = s->st_ctime = now;
}
static struct stat
get_attrib(const struct iso_tree_node *node)
{
struct stat st;
if (node) {
return node->attrib;
}
set_default_stat(&st);
return st;
}
static void
append_node(struct iso_tree_node *parent,
struct iso_tree_node *child)
{
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child);
if (!parent)
return;
parent->nchildren++;
parent->children =
realloc(parent->children, parent->nchildren * sizeof(void*));
parent->children[parent->nchildren-1] = child;
}
struct iso_tree_node*
iso_tree_new_root(struct iso_volume *vol)
{
assert(vol);
if (vol->root) {
iso_tree_free(vol->root);
}
vol->root = calloc(1, sizeof(struct iso_tree_node));
vol->root->volume = vol;
set_default_stat(&vol->root->attrib);
vol->root->attrib.st_mode = S_IFDIR | 0777;
vol->root->loc.type = LIBISO_NONE;
return vol->root;
}
struct iso_tree_node*
iso_tree_add_new_file(struct iso_tree_node *parent, const char *name)
{
struct iso_tree_node *f = calloc(1, sizeof(struct iso_tree_node));
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
f->volume = parent ? parent->volume : NULL;
f->parent = parent;
f->name = parent ? strdup(name) : NULL;
f->attrib = get_attrib(parent);
f->attrib.st_mode = 0777 | S_IFREG;
f->loc.type = LIBISO_NONE;
append_node(parent, f);
return f;
}
struct iso_tree_node*
iso_tree_add_new_dir(struct iso_tree_node *parent, const char *name)
{
struct iso_tree_node *d = iso_tree_add_new_file(parent, name);
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
d->attrib.st_mode = (d->attrib.st_mode & ~S_IFMT) | S_IFDIR;
return d;
}
struct iso_tree_node*
iso_tree_add_node(struct iso_tree_node *parent, const char *path)
{
char *p;
struct stat st;
struct iso_tree_node *ret;
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
if (lstat(path, &st) == -1)
return NULL;
p = strdup(path); /* because basename() might modify its arg */
/* it doesn't matter if we add a file or directory since we modify
* attrib anyway. */
ret = iso_tree_add_new_file(parent, basename(p));
ret->attrib = st;
ret->loc.type = LIBISO_FILESYS;
ret->loc.path = strdup(path);
free(p);
return ret;
}
struct iso_tree_node*
iso_tree_radd_dir (struct iso_tree_node *parent, const char *path)
{
struct iso_tree_node *new;
DIR *dir;
struct dirent *ent;
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
new = iso_tree_add_node(parent, path);
if (!new || !S_ISDIR(new->attrib.st_mode)) {
return new;
}
dir = opendir(path);
if (!dir) {
warn("couldn't open directory %s: %s\n", path, strerror(errno));
return new;
}
while ((ent = readdir(dir))) {
char child[strlen(ent->d_name) + strlen(path) + 2];
if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0)
continue;
sprintf(child, "%s/%s", path, ent->d_name);
/* see if this child is excluded. */
if (iso_exclude_lookup(child))
continue;
iso_tree_radd_dir(new, child);
}
closedir(dir);
return new;
}
void
iso_tree_free(struct iso_tree_node *root)
{
size_t i;
for (i=0; i < root->nchildren; i++) {
iso_tree_free(root->children[i]);
}
free(root->name);
free(root->children);
free(root);
}
void
iso_tree_print(const struct iso_tree_node *root, int spaces)
{
size_t i;
char sp[spaces+1];
memset(sp, ' ', spaces);
sp[spaces] = '\0';
printf("%s%sn", sp, root->name);
for (i=0; i < root->nchildren; i++) {
iso_tree_print(root->children[i], spaces+2);
}
}
void
iso_tree_print_verbose(const struct iso_tree_node *root,
print_dir_callback dir,
print_file_callback file,
void *callback_data,
int spaces)
{
size_t i;
(S_ISDIR(root->attrib.st_mode) ? dir : file)
(root, callback_data, spaces);
for (i=0; i < root->nchildren; i++) {
iso_tree_print_verbose(root->children[i], dir,
file, callback_data, spaces+2);
}
}
void
iso_tree_node_set_name(struct iso_tree_node *file, const char *name)
{
free(file->name);
file->name = strdup(name);
}

View File

@ -1,159 +0,0 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* \file tree.h
*
* Declare the structure of a libisofs filesystem tree. The files in this
* tree can come from either the local filesystem or from another .iso image
* (for multisession).
*
* This tree preserves as much information as it can about the files; names
* are stored in wchar_t and we preserve POSIX attributes. This tree does
* *not* include information that is necessary for writing out, for example,
* an ISO level 1 tree. That information will go in a different tree because
* the structure is sufficiently different.
*/
#ifndef LIBISO_TREE_H
#define LIBISO_TREE_H
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <wchar.h>
#include "libisofs.h"
enum file_location {
LIBISO_FILESYS,
LIBISO_PREVSESSION,
LIBISO_NONE /**< for files/dirs that were added with
* iso_tree_add_new_XXX. */
};
/**
* This tells us where to read the data from a file. Either we read from the
* local filesystem or we just point to the block on a previous session.
*/
struct iso_file_location
{
enum file_location type;
/* union {*/
char *path; /* in the current locale */
uint32_t block;
/* };*/
};
/**
* A node in the filesystem tree.
*/
struct iso_tree_node
{
struct iso_volume *volume;
struct iso_tree_node *parent;
char *name;
struct stat attrib; /**< The POSIX attributes of this node as
* documented in "man 2 stat". */
struct iso_file_location loc;
/**< Only used for regular files and symbolic
* links (ie. files for which we might have to
* copy data). */
size_t nchildren; /**< The number of children of this
* directory (if this is a directory). */
struct iso_tree_node **children;
size_t block; /**< The block at which this file will
* reside on disk. We store this here as
* well as in the various mangled trees
* because many different trees might point
* to the same file and they need to share the
* block location. */
};
/**
* Create a new root directory for a volume.
*
* \param vol The volume for which to create a new root directory.
*
* \pre \p vol is non-NULL.
* \post \p vol has a non-NULL, empty root directory with permissions 777.
* \return \p vol's new non-NULL, empty root directory.
*/
struct iso_tree_node *iso_tree_new_root(struct iso_volume *vol);
/**
* Create a new, empty, file.
*
* \param parent The parent directory of the new file. If this is null, create
* and return a new file node without adding it to any tree.
* \param name The name of the new file, encoded in the current locale.
* \pre \p name is non-NULL and it does not match any other file or directory
* name in \p parent.
* \post \p parent (if non-NULL) contains a file with the following properties:
* - the file's name is \p name (converted to wchar_t)
* - the file's POSIX permissions are the same as \p parent's
* - the file is a regular file
* - the file is empty
*
* \return \p parent's newly created file.
*/
struct iso_tree_node *iso_tree_add_new_file(struct iso_tree_node *parent,
const char *name);
/**
* Recursively free a directory.
*
* \param root The root of the directory heirarchy to free.
*
* \pre \p root is non-NULL.
*/
void iso_tree_free(struct iso_tree_node *root);
/**
* A function that prints verbose information about a directory.
*
* \param dir The directory about which to print information.
* \param data Unspecified function-dependent data.
* \param spaces The number of spaces to prepend to the output.
*
* \see iso_tree_print_verbose
*/
typedef void (*print_dir_callback) (const struct iso_tree_node *dir,
void *data,
int spaces);
/**
* A function that prints verbose information about a file.
*
* \param dir The file about which to print information.
* \param data Unspecified function-dependent data.
* \param spaces The number of spaces to prepend to the output.
*
* \see iso_tree_print_verbose
*/
typedef void (*print_file_callback) (const struct iso_tree_node *file,
void *data,
int spaces);
/**
* Recursively print a directory heirarchy. For each node in the directory
* heirarchy, call a callback function to print information more verbosely.
*
* \param root The root of the directory heirarchy to print.
* \param dir The callback function to call for each directory in the tree.
* \param file The callback function to call for each file in the tree.
* \param callback_data The data to pass to the callback functions.
* \param spaces The number of spaces to prepend to the output.
*
* \pre \p root is not NULL.
* \pre Neither of the callback functions modifies the directory heirarchy.
*/
void iso_tree_print_verbose(const struct iso_tree_node *root,
print_dir_callback dir,
print_file_callback file,
void *callback_data,
int spaces);
#define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode)
#endif /* LIBISO_TREE_H */

View File

@ -1,584 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* Utility functions for the Libisofs library.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wchar.h>
#include <iconv.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <errno.h>
#include <locale.h>
#include "util.h"
/* avoids warning and names in iso, joliet and rockridge can't be > 255 bytes
* anyway. There are at most 31 characters in iso level 1, 255 for rockridge,
* 64 characters (* 2 since UCS) for joliet. */
#define NAME_BUFFER_SIZE 255
int div_up(int n, int div)
{
return (n + div - 1) / div;
}
int round_up(int n, int mul)
{
return div_up(n, mul) * mul;
}
/* this function must always return a name
* since the caller never checks if a NULL
* is returned. It also avoids some warnings. */
char *str2ascii(const char *src_arg)
{
wchar_t wsrc_[NAME_BUFFER_SIZE];
char *src = (char*)wsrc_;
char *ret_;
char *ret;
mbstate_t state;
iconv_t conv;
size_t numchars;
size_t outbytes;
size_t inbytes;
size_t n;
if (!src_arg)
return NULL;
/* convert the string to a wide character string. Note: outbytes
* is in fact the number of characters in the string and doesn't
* include the last NULL character. */
memset(&state, 0, sizeof(state));
numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state);
if (numchars < 0)
return NULL;
inbytes = numchars * sizeof(wchar_t);
ret_ = malloc(numchars+1);
outbytes = numchars;
ret = ret_;
/* initialize iconv */
conv = iconv_open("ASCII", "WCHAR_T");
if (conv == (iconv_t)-1)
return NULL;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
while(n == -1) {
/* The destination buffer is too small. Stops here. */
if(errno == E2BIG)
break;
/* An incomplete multi bytes sequence was found. We
* can't do anything here. That's quite unlikely. */
if(errno == EINVAL)
break;
/* The last possible error is an invalid multi bytes
* sequence. Just replace the character with a "_".
* Probably the character doesn't exist in ascii like
* "é, è, à, ç, ..." in French. */
*ret++ = '_';
outbytes--;
if(!outbytes)
break;
/* There was an error with one character but some other remain
* to be converted. That's probably a multibyte character.
* See above comment. */
src += sizeof(wchar_t);
inbytes -= sizeof(wchar_t);
if(!inbytes)
break;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
}
iconv_close(conv);
*ret='\0';
return ret_;
}
/* FIXME: C&P */
uint16_t *str2ucs(const char *src_arg)
{
wchar_t wsrc_[NAME_BUFFER_SIZE];
char *src = (char*)wsrc_;
char *ret_;
char *ret;
mbstate_t state;
iconv_t conv;
size_t outbytes;
size_t numchars;
size_t inbytes;
size_t n;
if (!src_arg)
return calloc(2, 1); /* empty UCS string */
/* convert the string to a wide character string. Note: outbytes
* is in fact the number of characters in the string and doesn't
* include the last NULL character. */
memset(&state, 0, sizeof(state));
numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state);
if (numchars < 0)
return calloc(2, 1); /* empty UCS string */
inbytes = numchars * sizeof(wchar_t);
outbytes = numchars * sizeof(uint16_t);
ret_ = malloc ((numchars+1) * sizeof(uint16_t));
ret = ret_;
/* initialize iconv */
conv = iconv_open("UCS-2BE", "WCHAR_T");
if (conv == (iconv_t)-1)
return calloc(2, 1); /* empty UCS string */
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
while(n == -1) {
/* The destination buffer is too small. Stops here. */
if(errno == E2BIG)
break;
/* An incomplete multi bytes sequence was found. We
* can't do anything here. That's quite unlikely. */
if(errno == EINVAL)
break;
/* The last possible error is an invalid multi bytes
* sequence. Just replace the character with a "_".
* Probably the character doesn't exist in ascii like
* "é, è, à, ç, ..." in French. */
*((uint16_t*) ret) = '_';
ret += sizeof(uint16_t);
outbytes -= sizeof(uint16_t);
if(!outbytes)
break;
/* There was an error with one character but some other remain
* to be converted. That's probably a multibyte character.
* See above comment. */
src += sizeof(wchar_t);
inbytes -= sizeof(wchar_t);
if(!inbytes)
break;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
}
iconv_close(conv);
/* close the ucs string */
*((uint16_t*) ret) = 0;
return (uint16_t*)ret_;
}
static int valid_d_char(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
}
static int valid_a_char(char c)
{
return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?')
|| (c >= 'A' && c <= 'Z')
|| (c == '_');
}
static int valid_j_char(uint16_t c)
{
return !(c < (uint16_t)' ' || c == (uint16_t)'*' || c == (uint16_t)'/'
|| c == (uint16_t)':' || c == (uint16_t)';'
|| c == (uint16_t)'?' || c == (uint16_t)'\\');
}
/* FIXME: where are these documented? */
static int valid_p_char(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c == '.') || (c == '_') || (c == '-');
}
static char *iso_dirid(const char *src, int size)
{
char *ret = str2ascii(src);
size_t len, i;
if (!ret)
return NULL;
len = strlen(ret);
if (len > size) {
ret[size] = '\0';
len = size;
}
for (i = 0; i < len; i++) {
char c = toupper(ret[i]);
ret[i] = valid_d_char(c) ? c : '_';
}
return ret;
}
char *iso_1_dirid(const char *src)
{
return iso_dirid(src, 8);
}
char *iso_2_dirid(const char *src)
{
return iso_dirid(src, 31);
}
char *iso_1_fileid(const char *src_arg)
{
char *src = str2ascii(src_arg);
char *dest;
char *dot; /* Position of the last dot in the
filename, will be used to calculate
lname and lext. */
int lname, lext, pos, i;
if (!src)
return NULL;
dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2
(;1) + 1 (\0) */
dot = strrchr(src, '.');
lext = dot ? strlen(dot + 1) : 0;
lname = strlen(src) - lext - (dot ? 1 : 0);
/* If we can't build a filename, return NULL. */
if (lname == 0 && lext == 0) {
free(src);
free(dest);
return NULL;
}
pos = 0;
/* Convert up to 8 characters of the filename. */
for (i = 0; i < lname && i < 8; i++) {
char c = toupper(src[i]);
dest[pos++] = valid_d_char(c) ? c : '_';
}
/* This dot is mandatory, even if there is no extension. */
dest[pos++] = '.';
/* Convert up to 3 characters of the extension, if any. */
for (i = 0; i < lext && i < 3; i++) {
char c = toupper(src[lname + 1 + i]);
dest[pos++] = valid_d_char(c) ? c : '_';
}
/* File versions are mandatory, even if they aren't used. */
dest[pos++] = ';';
dest[pos++] = '1';
dest[pos] = '\0';
dest = (char *)realloc(dest, pos + 1);
free(src);
return dest;
}
char *iso_2_fileid(const char *src_arg)
{
char *src = str2ascii(src_arg);
char *dest;
char *dot;
int lname, lext, lnname, lnext, pos, i;
if (!src)
return NULL;
dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2
(;1) + 1 (\0) */
dot = strrchr(src, '.');
/* Since the maximum length can be divided freely over the name and
extension, we need to calculate their new lengths (lnname and
lnext). If the original filename is too long, we start by trimming
the extension, but keep a minimum extension length of 3. */
if (dot == NULL || dot == src || *(dot + 1) == '\0') {
lname = strlen(src);
lnname = (lname > 30) ? 30 : lname;
lext = lnext = 0;
} else {
lext = strlen(dot + 1);
lname = strlen(src) - lext - 1;
lnext = (strlen(src) > 31 && lext > 3)
? (lname < 27 ? 30 - lname : 3) : lext;
lnname = (strlen(src) > 31) ? 30 - lnext : lname;
}
if (lnname == 0 && lnext == 0) {
free(src);
free(dest);
return NULL;
}
pos = 0;
/* Convert up to lnname characters of the filename. */
for (i = 0; i < lnname; i++) {
char c = toupper(src[i]);
dest[pos++] = valid_d_char(c) ? c : '_';
}
dest[pos++] = '.';
/* Convert up to lnext characters of the extension, if any. */
for (i = 0; i < lnext; i++) {
char c = toupper(src[lname + 1 + i]);
dest[pos++] = valid_d_char(c) ? c : '_';
}
dest[pos++] = ';';
dest[pos++] = '1';
dest[pos] = '\0';
dest = (char *)realloc(dest, pos + 1);
free(src);
return dest;
}
char *
iso_p_fileid(const char *src)
{
char *ret = str2ascii(src);
size_t i, len;
if (!ret)
return NULL;
len = strlen(ret);
for (i = 0; i < len; i++) {
if (!valid_p_char(ret[i])) {
ret[i] = (uint16_t)'_';
}
}
return ret;
}
uint16_t *
iso_j_id(const char *src_arg)
{
uint16_t *j_str = str2ucs(src_arg);
size_t len = ucslen(j_str);
size_t n;
if (len > 128) {
j_str[128] = '\0';
len = 128;
}
for (n = 0; n < len; n++)
if (!valid_j_char(j_str[n]))
j_str[n] = '_';
return j_str;
}
void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
{
int i;
assert(bytes <= 4);
for (i = 0; i < bytes; ++i)
buf[i] = (num >> (8 * i)) & 0xff;
}
void iso_msb(uint8_t *buf, uint32_t num, int bytes)
{
int i;
assert(bytes <= 4);
for (i = 0; i < bytes; ++i)
buf[bytes - 1 - i] = (num >> (8 * i)) & 0xff;
}
void iso_bb(uint8_t *buf, uint32_t num, int bytes)
{
iso_lsb(buf, num, bytes);
iso_msb(buf+bytes, num, bytes);
}
void iso_datetime_7(unsigned char *buf, time_t t)
{
static int tzsetup = 0;
int tzoffset;
struct tm tm;
if (!tzsetup) {
tzset();
tzsetup = 1;
}
localtime_r(&t, &tm);
buf[0] = tm.tm_year;
buf[1] = tm.tm_mon + 1;
buf[2] = tm.tm_mday;
buf[3] = tm.tm_hour;
buf[4] = tm.tm_min;
buf[5] = tm.tm_sec;
#ifdef HAVE_TM_GMTOFF
tzoffset = -tm.tm_gmtoff / 60 / 15;
#else
tzoffset = -timezone / 60 / 15;
#endif
if (tzoffset < -48)
tzoffset += 101;
buf[6] = tzoffset;
}
time_t iso_datetime_read_7(const uint8_t *buf)
{
struct tm tm;
tm.tm_year = buf[0];
tm.tm_mon = buf[1] + 1;
tm.tm_mday = buf[2];
tm.tm_hour = buf[3];
tm.tm_min = buf[4];
tm.tm_sec = buf[5];
return mktime(&tm) - buf[6] * 60 * 60;
}
void iso_datetime_17(unsigned char *buf, time_t t)
{
static int tzsetup = 0;
static int tzoffset;
struct tm tm;
if (t == (time_t) - 1) {
/* unspecified time */
memset(buf, '0', 16);
buf[16] = 0;
} else {
if (!tzsetup) {
tzset();
tzsetup = 1;
}
localtime_r(&t, &tm);
sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
sprintf((char*)&buf[6], "%02d", tm.tm_mday);
sprintf((char*)&buf[8], "%02d", tm.tm_hour);
sprintf((char*)&buf[10], "%02d", tm.tm_min);
sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
memcpy(&buf[14], "00", 2);
#ifdef HAVE_TM_GMTOFF
tzoffset = -tm.tm_gmtoff / 60 / 15;
#else
tzoffset = -timezone / 60 / 15;
#endif
if (tzoffset < -48)
tzoffset += 101;
buf[16] = tzoffset;
}
}
time_t iso_datetime_read_17(const uint8_t *buf)
{
struct tm tm;
sscanf((char*)&buf[0], "%4d", &tm.tm_year);
sscanf((char*)&buf[4], "%2d", &tm.tm_mon);
sscanf((char*)&buf[6], "%2d", &tm.tm_mday);
sscanf((char*)&buf[8], "%2d", &tm.tm_hour);
sscanf((char*)&buf[10], "%2d", &tm.tm_min);
sscanf((char*)&buf[12], "%2d", &tm.tm_sec);
tm.tm_year -= 1900;
tm.tm_mon -= 1;
return mktime(&tm) - buf[16] * 60 * 60;
}
size_t ucslen(const uint16_t *str)
{
int i;
for (i=0; str[i]; i++)
;
return i;
}
/**
* Although each character is 2 bytes, we actually compare byte-by-byte
* (thats what the spec says).
*/
int ucscmp(const uint16_t *s1, const uint16_t *s2)
{
const char *s = (const char*)s1;
const char *t = (const char*)s2;
size_t len1 = ucslen(s1);
size_t len2 = ucslen(s2);
size_t i, len = MIN(len1, len2) * 2;
for (i=0; i < len; i++) {
if (s[i] < t[i]) {
return -1;
} else if (s[i] > t[i]) {
return 1;
}
}
if (len1 < len2)
return -1;
else if (len1 > len2)
return 1;
return 0;
}
uint32_t iso_read_lsb(const uint8_t *buf, int bytes)
{
int i;
uint32_t ret = 0;
for (i=0; i<bytes; i++) {
ret += ((uint32_t) buf[i]) << (i*8);
}
return ret;
}
uint32_t iso_read_msb(const uint8_t *buf, int bytes)
{
int i;
uint32_t ret = 0;
for (i=0; i<bytes; i++) {
ret += ((uint32_t) buf[bytes-i-1]) << (i*8);
}
return ret;
}
uint32_t iso_read_bb(const uint8_t *buf, int bytes)
{
uint32_t v1 = iso_read_lsb(buf, bytes);
uint32_t v2 = iso_read_msb(buf+bytes, bytes);
assert(v1 == v2);
return v1;
}

View File

@ -1,121 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* Utility functions for the Libisofs library.
*/
#ifndef LIBISO_UTIL_H
#define LIBISO_UTIL_H
#include <stdint.h>
#include <time.h>
#include <wchar.h>
#ifndef MAX
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
extern inline int div_up(int n, int div)
{
return (n + div - 1) / div;
}
extern inline int round_up(int n, int mul)
{
return div_up(n, mul) * mul;
}
wchar_t *towcs(const char *);
char *str2ascii(const char*);
uint16_t *str2ucs(const char*);
/**
* Create a level 1 directory identifier.
*/
char *iso_1_dirid(const char *src);
/**
* Create a level 2 directory identifier.
*/
char *iso_2_dirid(const char *src);
/**
* Create a level 1 file identifier that consists of a name, extension and
* version number. The resulting string will have a file name of maximum
* length 8, followed by a separator (.), an optional extension of maximum
* length 3, followed by a separator (;) and a version number (digit 1).
* @return NULL if the original name and extension both are of length 0.
*/
char *iso_1_fileid(const char *src);
/**
* Create a level 2 file identifier that consists of a name, extension and
* version number. The combined file name and extension length will not exceed
* 30, the name and extension will be separated (.), and the extension will be
* followed by a separator (;) and a version number (digit 1).
* @return NULL if the original name and extension both are of length 0.
*/
char *iso_2_fileid(const char *src);
/**
* Create a Joliet file or directory identifier that consists of a name,
* extension and version number. The combined name and extension length will
* not exceed 128 bytes, the name and extension will be separated (.),
* and the extension will be followed by a separator (;) and a version number
* (digit 1). All characters consist of 2 bytes and the resulting string is
* NULL-terminated by a 2-byte NULL. Requires the locale to be set correctly.
*
* @param size will be set to the size (in bytes) of the identifier.
* @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available.
*/
uint16_t *iso_j_id(const char *src);
/**
* FIXME: what are the requirements for these next two? Is this for RR?
*
* Create a POSIX portable file name that consists of a name and extension.
* The resulting file name will not exceed 250 characters.
* @return NULL if the original name and extension both are of length 0.
*/
char *iso_p_fileid(const char *src);
/**
* Create a POSIX portable directory name.
* The resulting directory name will not exceed 250 characters.
* @return NULL if the original name is of length 0.
*/
char *iso_p_dirid(const char *src);
void iso_lsb(uint8_t *buf, uint32_t num, int bytes);
void iso_msb(uint8_t *buf, uint32_t num, int bytes);
void iso_bb(uint8_t *buf, uint32_t num, int bytes);
uint32_t iso_read_lsb(const uint8_t *buf, int bytes);
uint32_t iso_read_msb(const uint8_t *buf, int bytes);
uint32_t iso_read_bb(const uint8_t *buf, int bytes);
/** Records the date/time into a 7 byte buffer (9.1.5) */
void iso_datetime_7(uint8_t *buf, time_t t);
/** Records the date/time into a 17 byte buffer (8.4.26.1) */
void iso_datetime_17(uint8_t *buf, time_t t);
time_t iso_datetime_read_7(const uint8_t *buf);
time_t iso_datetime_read_17(const uint8_t *buf);
/**
* Like strlen, but for Joliet strings.
*/
size_t ucslen(const uint16_t *str);
/**
* Like strcmp, but for Joliet strings.
*/
int ucscmp(const uint16_t *s1, const uint16_t *s2);
#endif /* LIBISO_UTIL_H */

View File

@ -1,189 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set ts=8 sts=8 sw=8 noet : */
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include "libisofs.h"
#include "tree.h"
#include "util.h"
#include "volume.h"
struct iso_volset*
iso_volset_new(struct iso_volume *vol, const char *id)
{
struct iso_volset *volset = calloc(1, sizeof(struct iso_volset));
volset->volset_size = 1;
volset->refcount = 1;
volset->volume = malloc(sizeof(void *));
volset->volume[0] = vol;
volset->volset_id = strdup(id);
vol->refcount++;
return volset;
}
void
iso_volset_free(struct iso_volset *volset)
{
if (--volset->refcount < 1) {
int i;
for (i = 0; i < volset->volset_size; i++) {
iso_volume_free(volset->volume[i]);
}
free(volset->volume);
free(volset->volset_id);
}
}
struct iso_volume*
iso_volume_new(const char *volume_id,
const char *publisher_id,
const char *data_preparer_id)
{
return iso_volume_new_with_root(volume_id,
publisher_id,
data_preparer_id,
NULL);
}
struct iso_volume*
iso_volume_new_with_root(const char *volume_id,
const char *publisher_id,
const char *data_preparer_id,
struct iso_tree_node *root)
{
struct iso_volume *volume;
volume = calloc(1, sizeof(struct iso_volume));
volume->refcount = 1;
volume->root = root ? root : iso_tree_new_root(volume);
if (volume_id != NULL)
volume->volume_id = strdup(volume_id);
if (publisher_id != NULL)
volume->publisher_id = strdup(publisher_id);
if (data_preparer_id != NULL)
volume->data_preparer_id = strdup(data_preparer_id);
return volume;
}
void
iso_volume_free(struct iso_volume *volume)
{
/* Only free if no references are in use. */
if (--volume->refcount < 1) {
iso_tree_free(volume->root);
free(volume->volume_id);
free(volume->publisher_id);
free(volume->data_preparer_id);
free(volume);
}
}
struct iso_tree_node *
iso_volume_get_root(const struct iso_volume *volume)
{
return volume->root;
}
struct iso_tree_node *
iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
{
struct iso_tree_node *node;
char *ptr, *brk_info, *component;
/* get the first child at the root of the volume
* that is "/" */
node=iso_volume_get_root(volume);
if (!strcmp (path, "/"))
return node;
if (!node->nchildren)
return NULL;
/* the name of the nodes is in wide characters so first convert path
* into wide characters. */
ptr = strdup(path);
/* get the first component of the path */
component=strtok_r(ptr, "/", &brk_info);
while (component) {
size_t max;
size_t i;
/* search among all the children of this directory if this path component exists */
max=node->nchildren;
for (i=0; i < max; i++) {
if (!strcmp(component, node->children[i]->name)) {
node=node->children[i];
break;
}
}
/* see if a node could be found */
if (i==max) {
node=NULL;
break;
}
component=strtok_r(NULL, "/", &brk_info);
}
free(ptr);
return node;
}
struct iso_tree_node *
iso_tree_volume_add_path(struct iso_volume *volume,
const char *disc_path,
const char *path)
{
char *tmp;
struct iso_tree_node *node;
struct iso_tree_node *parent_node;
tmp=strdup(disc_path);
parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
free(tmp);
if (!parent_node)
return NULL;
node = iso_tree_radd_dir(parent_node, path);
if (!node)
return NULL;
tmp=strdup(disc_path);
iso_tree_node_set_name(node, basename(tmp));
free(tmp);
return node;
}
struct iso_tree_node *
iso_tree_volume_add_new_dir(struct iso_volume *volume,
const char *disc_path)
{
char *tmp;
struct iso_tree_node *node;
struct iso_tree_node *parent_node;
tmp=strdup(disc_path);
parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
free(tmp);
if (!parent_node)
return NULL;
tmp=strdup(disc_path);
node = iso_tree_add_new_dir(parent_node, basename(tmp));
free(tmp);
return node;
}

View File

@ -1,45 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet sts=8 ts=8 sw=8 : */
/**
* Extra declarations for use with the iso_volume structure.
*/
#ifndef LIBISO_VOLUME_H
#define LIBISO_VOLUME_H
#include "libisofs.h"
/**
* Data volume.
*/
struct iso_volume
{
int refcount; /**< Number of used references to this
volume. */
struct iso_tree_node *root; /**< Root of the directory tree for the
volume. */
char *volume_id; /**< Volume identifier. */
char *publisher_id; /**< Volume publisher. */
char *data_preparer_id; /**< Volume data preparer. */
};
/**
* A set of data volumes.
*/
struct iso_volset
{
int refcount;
struct iso_volume **volume; /**< The volumes belonging to this
volume set. */
int volset_size; /**< The number of volumes in this
volume set. */
char *volset_id; /**< The id of this volume set, encoded
in the current locale. */
};
#endif /* __ISO_VOLUME */

View File

@ -1,4 +0,0 @@
int main()
{
return 0;
}

View File

@ -1,107 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set ts=8 sts=8 sw=8 noet : */
#define _GNU_SOURCE
#include "libisofs.h"
#include "libburn/libburn.h"
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <err.h>
#define SECSIZE 2048
const char * const optstring = "JRL:h";
extern char *optarg;
extern int optind;
void usage()
{
printf("test [OPTIONS] DIRECTORY OUTPUT\n");
}
void help()
{
printf(
"Options:\n"
" -J Add Joliet support\n"
" -R Add Rock Ridge support\n"
" -L <num> Set the ISO level (1 or 2)\n"
" -h Print this message\n"
);
}
int main(int argc, char **argv)
{
struct iso_volset *volset;
struct iso_volume *volume;
struct iso_tree_node *root;
struct burn_source *src;
unsigned char buf[2048];
FILE *fd;
int c;
int level=1, flags=0;
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
case 'h':
usage();
help();
exit(0);
break;
case 'J':
flags |= ECMA119_JOLIET;
break;
case 'R':
flags |= ECMA119_ROCKRIDGE;
break;
case 'L':
level = atoi(optarg);
break;
case '?':
usage();
exit(1);
break;
}
}
if (argc < 2) {
printf ("must pass directory to build iso from\n");
usage();
return 1;
}
if (argc < 3) {
printf ("must supply output file\n");
usage();
return 1;
}
fd = fopen(argv[optind+1], "w");
if (!fd) {
err(1, "error opening output file");
}
root = iso_tree_radd_dir(NULL, argv[optind]);
if (!root) {
err(1, "error opening input directory");
}
volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root );
volset = iso_volset_new( volume, "VOLSETID" );
src = iso_source_new_ecma119(volset, 0, level, flags);
while (src->read(src, buf, 2048) == 2048) {
fwrite(buf, 1, 2048, fd);
}
fclose(fd);
return 0;
}

View File

@ -1,297 +0,0 @@
import struct
import tree
import sys
voldesc_fmt = "B" "5s" "B" "2041x"
# all these fields are common between the pri and sec voldescs
privoldesc_fmt = "B" "5s" "B" "x" "32s" "32s" "8x" "8s" "32x" "4s" "4s" "4s" "8s" "4s4s" "4s4s" "34s" "128s" \
"128s" "128s" "128s" "37s" "37s" "37s" "17s" "17s" "17s" "17s" "B" "x" "512s" "653x"
# the fields unique to the sec_vol_desc
secvoldesc_fmt = "x" "5x" "x" "B" "32x" "32x" "8x" "8x" "32s" "4x" "4x" "4x" "8x" "4x4x" "4x4x" "34x" "128x" \
"128x" "128x" "128x" "37x" "37x" "37x" "17x" "17x" "17x" "17x" "x" "x" "512x" "653x"
dirrecord_fmt = "B" "B" "8s" "8s" "7s" "B" "B" "B" "4s" "B" # + file identifier, padding field and SU area
pathrecord_fmt = "B" "B" "4s" "2s" # + directory identifier and padding field
def read_bb(str, le, be):
val1, = struct.unpack(le, str)
val2, = struct.unpack(be, str)
if val1 != val2:
print "val1=%d, val2=%d" % (val1, val2)
raise AssertionError, "values are not equal in dual byte-order field"
return val1
def read_bb4(str):
return read_bb(str, "<I4x", ">4xI")
def read_bb2(str):
return read_bb(str, "<H2x", ">2xH")
def read_lsb4(str):
return struct.unpack("<I", str)[0]
def read_lsb2(str):
return struct.unpack("<H", str)[0]
def read_msb4(str):
return struct.unpack(">I", str)[0]
def read_msb2(str):
return struct.unpack(">H", str)[0]
class VolDesc(object):
def __init__(self, data):
print "fmt len=%d, data len=%d" % ( struct.calcsize(voldesc_fmt), len(data) )
self.vol_desc_type, self.standard_id, self.vol_desc_version = struct.unpack(voldesc_fmt, data)
class PriVolDesc(VolDesc):
def __init__(self, data):
self.vol_desc_type, \
self.standard_id, \
self.vol_desc_version, \
self.system_id, \
self.volume_id, \
self.vol_space_size, \
self.vol_set_size, \
self.vol_seq_num, \
self.block_size, \
self.path_table_size, \
self.l_table_pos, \
self.l_table2_pos, \
self.m_table_pos, \
self.m_table2_pos, \
self.root_record, \
self.volset_id, \
self.publisher_id, \
self.preparer_id, \
self.application_id, \
self.copyright_file, \
self.abstract_file, \
self.bibliographic_file, \
self.creation_timestamp, \
self.modification_timestamp, \
self.expiration_timestamp, \
self.effective_timestamp, \
self.file_struct_version, \
self.application_use = struct.unpack(privoldesc_fmt, data)
# take care of reading the integer types
self.vol_space_size = read_bb4(self.vol_space_size)
self.vol_set_size = read_bb2(self.vol_set_size)
self.vol_seq_num = read_bb2(self.vol_seq_num)
self.block_size = read_bb2(self.block_size)
self.path_table_size = read_bb4(self.path_table_size)
self.l_table_pos = read_lsb4(self.l_table_pos)
self.l_table2_pos = read_lsb4(self.l_table2_pos)
self.m_table_pos = read_msb4(self.m_table_pos)
self.m_table2_pos = read_msb4(self.m_table2_pos)
# parse the root directory record
self.root_record = DirRecord(self.root_record)
def readPathTables(self, file):
file.seek( self.block_size * self.l_table_pos )
self.l_table = PathTable( file.read(self.path_table_size), 0 )
file.seek( self.block_size * self.m_table_pos )
self.m_table = PathTable( file.read(self.path_table_size), 1 )
if self.l_table2_pos:
file.seek( self.block_size * self.l_table2_pos )
self.l_table2 = PathTable( file.read(self.path_table_size), 0 )
else:
self.l_table2 = None
if self.m_table2_pos:
file.seek( self.block_size * self.m_table2_pos )
self.m_table2 = PathTable( file.read(self.path_table_size), 1 )
else:
self.m_table2 = None
def toTree(self, isofile):
ret = tree.Tree(isofile=isofile.name)
ret.root = self.root_record.toTreeNode(parent=None, isofile=isofile)
return ret
class SecVolDesc(PriVolDesc):
def __init__(self, data):
super(SecVolDesc,self).__init__(data)
self.flags, self.escape_sequences = struct.unpack(secvoldesc_fmt, data)
# return a single volume descriptor of the appropriate type
def readVolDesc(data):
desc = VolDesc(data)
if desc.standard_id != "CD001":
print "Unexpected standard_id " +desc.standard_id
return None
if desc.vol_desc_type == 1:
return PriVolDesc(data)
elif desc.vol_desc_type == 2:
return SecVolDesc(data)
elif desc.vol_desc_type == 3:
print "I don't know about partitions yet!"
return None
elif desc.vol_desc_type == 255:
return desc
else:
print "Unknown volume descriptor type %d" % (desc.vol_desc_type,)
return None
def readVolDescSet(file):
ret = [ readVolDesc(file.read(2048)) ]
while ret[-1].vol_desc_type != 255:
ret.append( readVolDesc(file.read(2048)) )
for vol in ret:
if vol.vol_desc_type == 1 or vol.vol_desc_type == 2:
vol.readPathTables(file)
return ret
class DirRecord:
def __init__(self, data):
self.len_dr, \
self.len_xa, \
self.block, \
self.len_data, \
self.timestamp, \
self.flags, \
self.unit_size, \
self.gap_size, \
self.vol_seq_number, \
self.len_fi = struct.unpack(dirrecord_fmt, data[:33])
self.children = []
if self.len_dr > len(data):
raise AssertionError, "Error: not enough data to read in DirRecord()"
elif self.len_dr < 34:
raise AssertionError, "Error: directory record too short"
fmt = str(self.len_fi) + "s"
if self.len_fi % 2 == 0:
fmt += "1x"
len_su = self.len_dr - (33 + self.len_fi + 1 - (self.len_fi % 2))
fmt += str(len_su) + "s"
if len(data) >= self.len_dr:
self.file_id, self.su = struct.unpack(fmt, data[33 : self.len_dr])
else:
print "Error: couldn't read file_id: not enough data"
self.file_id = "BLANK"
self.su = ""
# convert to integers
self.block = read_bb4(self.block)
self.len_data = read_bb4(self.len_data)
self.vol_seq_number = read_bb2(self.vol_seq_number)
def toTreeNode(self, parent, isofile, path=""):
ret = tree.TreeNode(parent=parent, isofile=isofile.name)
if len(path) > 0:
path += "/"
path += self.file_id
ret.path = path
if self.flags & 2: # we are a directory, recurse
isofile.seek( 2048 * self.block )
data = isofile.read( self.len_data )
pos = 0
while pos < self.len_data:
try:
child = DirRecord( data[pos:] )
pos += child.len_dr
if child.len_fi == 1 and (child.file_id == "\x00" or child.file_id == "\x01"):
continue
print "read child named " +child.file_id
self.children.append( child )
ret.children.append( child.toTreeNode(ret, isofile, path) )
except AssertionError:
print "Couldn't read child of directory %s, position is %d, len is %d" % \
(path, pos, self.len_data)
raise
return ret
class PathTableRecord:
def __init__(self, data, readint2, readint4):
self.len_di, self.len_xa, self.block, self.parent_number = struct.unpack(pathrecord_fmt, data[:8])
if len(data) < self.len_di + 8:
raise AssertionError, "Error: not enough data to read path table record"
fmt = str(self.len_di) + "s"
self.dir_id, = struct.unpack(fmt, data[8:8+self.len_di])
self.block = readint4(self.block)
self.parent_number = readint2(self.parent_number)
class PathTable:
def __init__(self, data, m_type):
if m_type:
readint2 = read_msb2
readint4 = read_msb4
else:
readint2 = read_lsb2
readint4 = read_lsb4
pos = 0
self.records = []
while pos < len(data):
try:
self.records.append( PathTableRecord(data[pos:], readint2, readint4) )
print "Read path record %d: dir_id %s, block %d, parent_number %d" %\
(len(self.records), self.records[-1].dir_id, self.records[-1].block, self.records[-1].parent_number)
pos += self.records[-1].len_di + 8
pos += pos % 2
except AssertionError:
print "Last successfully read path table record had dir_id %s, block %d, parent_number %d" % \
(self.records[-1].dir_id, self.records[-1].block, self.records[-1].parent_number)
print "Error was near offset %x" % (pos,)
raise
def findRecord(self, dir_id, block, parent_number):
number=1
for record in self.records:
if record.dir_id == dir_id and record.block == block and record.parent_number == parent_number:
return number, record
number += 1
return None, None
# check this path table for consistency against the actual directory heirarchy
def crossCheckDirRecords(self, root, parent_number=1):
number, rec = self.findRecord(root.file_id, root.block, parent_number)
if not rec:
print "Error: directory record parent_number %d, dir_id %s, block %d doesn't match a path table record" % \
(parent_number, root.file_id, root.block)
parent = self.records[parent_number]
print "Parent has parent_number %d, dir_id %s, block %d" % (parent.parent_number, parent.dir_id, parent.block)
return 0
for child in root.children:
if child.flags & 2:
self.crossCheckDirRecords(child, number)
if len(sys.argv) != 2:
print "Please enter the name of the .iso file to open"
sys.exit(1)
f = file(sys.argv[1])
f.seek(2048 * 16) # system area
volumes = readVolDescSet(f)
vol = volumes[0]
t = vol.toTree(f)
vol.l_table.crossCheckDirRecords(vol.root_record)
vol.m_table.crossCheckDirRecords(vol.root_record)
vol = volumes[1]
try:
t = vol.toTree(f)
vol.l_table.crossCheckDirRecords(vol.root_record)
vol.m_table.crossCheckDirRecords(vol.root_record)
except AttributeError:
pass

View File

@ -1,7 +1,7 @@
/* test/libburner.c , API illustration of burning a single data track to CD */
/* Copyright (C) 2005 - 2006 Thomas Schmitt <scdbackup@gmx.net> */
/* Provided under GPL, see also "License and copyright aspects" at file end */
/* test/libburner.c , API illustration of burning data or audio tracks to CD */
/* Copyright (C) 2005 - 2006 Thomas Schmitt <scdbackup@gmx.net> */
/* Provided under GPL, see also "License and copyright aspects" at file end */
/** Overview
@ -35,17 +35,10 @@
*/
/* We shall prepare for times when more than 2 GB of data are to be handled.
This gives POSIX-ly 64 bit off_t */
#ifndef _LARGEFILE_SOURCE
#define _LARGEFILE_SOURCE 1
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
/** See this for the decisive API specs . libburn.h is The Original */
#include <libburn/libburn.h>
/* For using the installed header file : #include <libburn/libburn.h> */
/* This program insists in the own headerfile. */
#include "../libburn/libburn.h"
/* libburn is intended for Linux systems with kernel 2.4 or 2.6 for now */
#include <stdio.h>
@ -56,6 +49,8 @@
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
/** For simplicity i use global variables to represent the drives.
@ -120,9 +115,6 @@ int libburner_aquire_by_adr(char *drive_adr)
if (ret <= 0) {
fprintf(stderr,"FAILURE with persistent drive address '%s'\n",
drive_adr);
if (strncmp(drive_adr,"/dev/sg",7) != 0 &&
strncmp(drive_adr,"/dev/hd",7) != 0)
fprintf(stderr,"\nHINT: Consider addresses like '/dev/hdc' or '/dev/sg0'\n");
} else {
printf("Done\n");
drive_is_grabbed = 1;
@ -182,7 +174,6 @@ int libburner_aquire_by_driveno(int *driveno)
}
printf("-----------------------------------------------------------------------------\n\n");
/*
On multi-drive systems save yourself from sysadmins' revenge.
@ -249,7 +240,8 @@ int libburner_aquire_by_driveno(int *driveno)
int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
{
enum burn_disc_status disc_state;
struct burn_progress progress;
struct burn_progress p;
int percent = 1;
while (burn_drive_get_status(drive, NULL) != BURN_DRIVE_IDLE)
usleep(1001);
@ -281,11 +273,13 @@ int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
}
printf(
"Beginning to %s-blank CD media.\n", (blank_fast?"fast":"full"));
printf(
"Expect some garbage sector numbers and some zeros at first.\n");
burn_disc_erase(drive, blank_fast);
while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
printf("Blanking sector %d\n", progress.sector);
sleep(1);
while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
percent = 1.0 + ((double) p.sector+1.0)
/ ((double) p.sectors) * 98.0;
printf("Blanking ( %d%% done )\n", percent);
sleep(1);
}
printf("Done\n");
@ -324,7 +318,7 @@ int libburner_regrab(struct burn_drive *drive) {
*/
int libburner_payload(struct burn_drive *drive,
char source_adr[][4096], int source_adr_count,
off_t stdin_size, int simulate_burn, int all_tracks_type)
int multi, int simulate_burn, int all_tracks_type)
{
struct burn_source *data_src;
struct burn_disc *target_disc;
@ -334,8 +328,10 @@ int libburner_payload(struct burn_drive *drive,
struct burn_track *track, *tracklist[99];
struct burn_progress progress;
time_t start_time;
int last_sector = 0, padding = 0, trackno;
int last_sector = 0, padding = 0, trackno, write_mode_tao = 0, fd;
off_t fixed_size;
char *adr;
struct stat stbuf;
if (all_tracks_type != BURN_AUDIO) {
all_tracks_type = BURN_MODE1;
@ -352,12 +348,21 @@ int libburner_payload(struct burn_drive *drive,
burn_track_define_data(track, 0, padding, 1, all_tracks_type);
adr = source_adr[trackno];
fixed_size = 0;
if (adr[0] == '-' && adr[1] == 0) {
data_src = burn_fd_source_new(0, -1, stdin_size);
printf("Note: using standard input as source with %.f bytes\n",
(double) stdin_size);
} else
data_src = burn_file_source_new(adr, NULL);
fd = 0;
} else {
fd = open(adr, O_RDONLY);
if (fd>=0)
if (fstat(fd,&stbuf)!=-1)
if((stbuf.st_mode&S_IFMT)==S_IFREG)
fixed_size = stbuf.st_size;
}
if (fixed_size==0)
write_mode_tao = 1;
data_src = NULL;
if (fd>=0)
data_src = burn_fd_source_new(fd, -1, fixed_size);
if (data_src == NULL) {
fprintf(stderr,
"FATAL: Could not open data source '%s'.\n",adr);
@ -382,39 +387,30 @@ int libburner_payload(struct burn_drive *drive,
/* Evaluate drive and media */
while ((disc_state = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
usleep(100001);
if (disc_state != BURN_DISC_BLANK) {
if (disc_state == BURN_DISC_FULL ||
disc_state == BURN_DISC_APPENDABLE) {
fprintf(stderr,
"FATAL: Media with data detected. Need blank media.\n");
if (disc_state == BURN_DISC_APPENDABLE) {
write_mode_tao = 1;
} else if (disc_state != BURN_DISC_BLANK) {
if (disc_state == BURN_DISC_FULL) {
fprintf(stderr, "FATAL: Closed media with data detected. Need blank or appendable media.\n");
if (burn_disc_erasable(drive))
fprintf(stderr, "HINT: Try --blank_fast\n\n");
} else if (disc_state == BURN_DISC_EMPTY)
fprintf(stderr,"FATAL: No media detected in drive\n");
else
fprintf(stderr,
"FATAL: Cannot recognize drive and media state\n");
"FATAL: Cannot recognize state of drive and media\n");
return 0;
}
burn_options = burn_write_opts_new(drive);
burn_write_opts_set_perform_opc(burn_options, 0);
#ifdef Libburner_raw_mode_which_i_do_not_likE
/* This yields higher CD capacity but hampers my IDE controller
with burning on one drive and reading on another simultaneously.
My burner does not obey the order --try_to_simulate in this mode.
*/
burn_write_opts_set_write_type(burn_options,
BURN_WRITE_RAW, BURN_BLOCK_RAW96R);
#else
/* This is by what cdrskin competes with cdrecord -sao which
i understand is the mode preferrably advised by Joerg Schilling */
burn_write_opts_set_write_type(burn_options,
BURN_WRITE_SAO, BURN_BLOCK_SAO);
#endif
burn_write_opts_set_multi(burn_options, !!multi);
if (write_mode_tao)
burn_write_opts_set_write_type(burn_options,
BURN_WRITE_TAO, BURN_BLOCK_MODE1);
else
burn_write_opts_set_write_type(burn_options,
BURN_WRITE_SAO, BURN_BLOCK_SAO);
if(simulate_burn)
printf("\n*** Will TRY to SIMULATE burning ***\n\n");
burn_write_opts_set_simulate(burn_options, simulate_burn);
@ -434,8 +430,11 @@ int libburner_payload(struct burn_drive *drive,
printf(
"Thank you for being patient since %d seconds.\n",
(int) (time(0) - start_time));
else if(write_mode_tao)
printf("Track %d : sector %d\n", progress.track+1,
progress.sector);
else
printf("Track %d : sector %d of %d\n", progress.track,
printf("Track %d : sector %d of %d\n",progress.track+1,
progress.sector, progress.sectors);
last_sector = progress.sector;
sleep(1);
@ -446,19 +445,21 @@ int libburner_payload(struct burn_drive *drive,
burn_track_free(tracklist[trackno]);
burn_session_free(session);
burn_disc_free(target_disc);
if(simulate_burn)
if (multi)
printf("NOTE: Media left appendable.\n");
if (simulate_burn)
printf("\n*** Did TRY to SIMULATE burning ***\n\n");
return 0;
}
/** The setup parameters of libburn */
static char drive_adr[BURN_DRIVE_ADR_LEN]= {""};
static int driveno= 0;
static int do_blank= 0;
/** The setup parameters of libburner */
static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
static int driveno = 0;
static int do_blank = 0;
static char source_adr[99][4096];
static int source_adr_count= 0;
static off_t stdin_size= 650*1024*1024;
static int source_adr_count = 0;
static int do_multi = 0;
static int simulate_burn = 0;
static int all_tracks_type = BURN_MODE1;
@ -503,15 +504,12 @@ int libburner_setup(int argc, char **argv)
}
strcpy(drive_adr, argv[i]);
}
} else if (!strcmp(argv[i], "--stdin_size")) {
++i;
if (i >= argc) {
fprintf(stderr,"--stdin_size requires an argument\n");
return 3;
} else
stdin_size = atoi(argv[i]);
if (stdin_size < 600*1024) /* minimum readable track size */
stdin_size = 600*1024;
} else if (!strcmp(argv[i], "--multi")) {
do_multi = 1;
} else if (!strcmp(argv[i], "--stdin_size")) { /* obsoleted */
i++;
} else if (!strcmp(argv[i], "--try_to_simulate")) {
simulate_burn = 1;
@ -543,17 +541,15 @@ int libburner_setup(int argc, char **argv)
insuffient_parameters = 0;
if (print_help || insuffient_parameters ) {
printf("Usage: %s\n", argv[0]);
printf(" [--drive <address>|<driveno>|\"-\"]\n");
printf(" [--blank_fast|--blank_full] [--audio]\n");
printf(" [--try_to_simulate] [--stdin_size <bytes>]\n");
printf(" [<one or more imagefiles>|\"-\"]\n");
printf(" [--drive <address>|<driveno>|\"-\"] [--audio]\n");
printf(" [--blank_fast|--blank_full] [--try_to_simulate]\n");
printf(" [--multi] [<one or more imagefiles>|\"-\"]\n");
printf("Examples\n");
printf("A bus scan (needs rw-permissions to see a drive):\n");
printf(" %s --drive -\n",argv[0]);
printf("Burn a file to drive chosen by number:\n");
printf(" %s --drive 0 my_image_file\n",
argv[0]);
printf("Burn a file to drive chosen by persistent address:\n");
printf("Burn a file to drive chosen by number, leave appendable:\n");
printf(" %s --drive 0 --multi my_image_file\n", argv[0]);
printf("Burn a file to drive chosen by persistent address, close:\n");
printf(" %s --drive /dev/hdc my_image_file\n", argv[0]);
printf("Blank a used CD-RW (is combinable with burning in one run):\n");
printf(" %s --drive /dev/hdc --blank_fast\n",argv[0]);
@ -561,9 +557,9 @@ int libburner_setup(int argc, char **argv)
printf(" lame --decode -t /path/to/track1.mp3 track1.cd\n");
printf(" test/dewav /path/to/track2.wav -o track2.cd\n");
printf(" %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);
printf("Burn a compressed afio archive on-the-fly, pad up to 700 MB:\n");
printf("Burn a compressed afio archive on-the-fly:\n");
printf(" ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
printf(" %s --drive /dev/hdc --stdin_size 734003200 -\n", argv[0]);
printf(" %s --drive /dev/hdc -\n", argv[0]);
printf("To be read from *not mounted* CD via: afio -tvZ /dev/hdc\n");
printf("Program tar would need a clean EOF which our padded CD cannot deliver.\n");
if (insuffient_parameters)
@ -620,8 +616,8 @@ int main(int argc, char **argv)
}
if (source_adr_count > 0) {
ret = libburner_payload(drive_list[driveno].drive,
source_adr, source_adr_count, stdin_size,
simulate_burn, all_tracks_type);
source_adr, source_adr_count,
do_multi, simulate_burn, all_tracks_type);
if (ret<=0)
{ ret = 38; goto release_drive; }
}

View File

@ -1,126 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <libburn/libburn.h>
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
static struct burn_drive_info *drives;
static unsigned int n_drives;
void burn_files(struct burn_drive *drive, struct burn_disc *disc)
{
struct burn_write_opts *o;
enum burn_disc_status s;
if (!burn_drive_grab(drive, 1)) {
printf("Unable to open the drive!\n");
return;
}
while (burn_drive_get_status(drive, NULL))
usleep(1000);
while ((s = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
usleep(1000);
if (s != BURN_DISC_BLANK) {
burn_drive_release(drive, 0);
printf("Please insert blank media in the drive\n");
return;
}
o = burn_write_opts_new(drive);
burn_drive_set_speed(drive, 0, 2816);
burn_write_opts_set_perform_opc(o, 0);
burn_write_opts_set_write_type(o, BURN_WRITE_TAO, BURN_BLOCK_MODE1);
burn_write_opts_set_simulate(o, 1);
/* want failure on seggy while debugging :) */
burn_write_opts_set_underrun_proof(o, 0);
burn_structure_print_disc(disc);
burn_disc_write(o, disc);
burn_write_opts_free(o);
while (burn_drive_get_status(drive, NULL)) {
sleep(1);
}
printf("\n");
burn_drive_release(drive, 0);
burn_disc_free(disc);
}
void parse_args(int argc, char **argv, int *drive, struct burn_disc **disc)
{
int i, tmode = BURN_AUDIO;
int help = 1;
struct burn_session *session;
struct burn_track *tr;
struct burn_source *src;
*disc = burn_disc_create();
session = burn_session_create();
burn_disc_add_session(*disc, session, BURN_POS_END);
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--drive")) {
++i;
if (i >= argc)
printf("--drive requires an argument\n");
else
*drive = atoi(argv[i]);
} else if (!strcmp(argv[i], "--audio")) {
tmode = BURN_AUDIO;
} else if (!strcmp(argv[i], "--data")) {
tmode = BURN_MODE1;
} else if (!strcmp(argv[i], "--verbose")) {
++i;
if (i >= argc)
printf("--verbose requires an argument\n");
else
burn_set_verbosity(atoi(argv[i]));
} else if (!strcmp(argv[i], "--help")) {
help = 1; /* who cares */
} else {
help = 0;
printf("%s is a track\n", argv[i]);
tr = burn_track_create();
src = burn_file_source_new(argv[i], NULL);
burn_track_set_source(tr, src);
burn_source_free(src);
burn_track_define_data(tr, 0, 0, 1, tmode);
burn_session_add_track(session, tr, BURN_POS_END);
}
}
if (help) {
printf("Usage: %s [--drive <num>] [--verbose <level>] files\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
int main(int argc, char **argv)
{
int drive = 0;
struct burn_disc *disc;
parse_args(argc, argv, &drive, &disc);
printf("Initializing library...");
if (burn_initialize())
printf("Success\n");
else {
printf("Failed\n");
return 1;
}
printf("Scanning for devices...");
while (!burn_drive_scan(&drives, &n_drives)) ;
printf("Done\n");
burn_files(drives[drive].drive, disc);
burn_drive_info_free(drives);
burn_finish();
return 0;
}

View File

@ -1,54 +0,0 @@
/* THIS IS NOT A PROPER EXAMPLE */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libburn/libburn.h>
static struct burn_drive_info *drives;
static unsigned int n_drives;
#warning this example is totally fried
int main()
{
#if 0
struct burn_drive *drive;
struct burn_read_opts o;
burn_initialize();
o.datafd =
open("/xp/burn/blah.data", O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR);
o.subfd =
open("/xp/burn/blah.sub", O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR);
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;
printf("Scanning for devices...");
while (!burn_drive_scan(&drives, &n_drives)) ;
printf("Done\n");
drive = drives[0].drive;
burn_drive_set_speed(drive, 0, 0);
if (!burn_drive_grab(drive, 1)) {
printf("Unable to open the drive!\n");
return EXIT_FAILURE;
}
while (burn_drive_get_status(drive, NULL))
usleep(1000);
burn_disc_read(drive, &o);
#endif
return EXIT_SUCCESS;
}

574
test/telltoc.c Normal file
View File

@ -0,0 +1,574 @@
/* test/telltoc.c , API illustration of obtaining media status info */
/* Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net> Provided under GPL */
/** Overview
telltoc is a minimal demo application for the library libburn as provided
on http://libburn.pykix.org . It can list the available devices, can display
some drive properties, the type of media, eventual table of content and
multisession info for mkisofs option -C .
It's main purpose, nevertheless, is to show you how to use libburn and also
to serve the libburn team as reference application. telltoc.c does indeed
define the standard way how above gestures can be implemented and stay upward
compatible for a good while.
Before you can do anything, you have to initialize libburn by
burn_initialize()
as it is done in main() at the end of this file. Then you aquire a
drive in an appropriate way conforming to the API. The two main
approaches are shown here in application functions:
telltoc_aquire_by_adr() demonstrates usage as of cdrecord traditions
telltoc_aquire_by_driveno() demonstrates a scan-and-choose approach
With that aquired drive you can call
telltoc_media() prints some information about the media in a drive
telltoc_toc() prints a table of content (if there is content)
telltoc_msinfo() prints parameters for mkisofs option -C
When everything is done, main() releases the drive and shuts down libburn:
burn_drive_release();
burn_finish()
*/
/** See this for the decisive API specs . libburn.h is The Original */
/* For using the installed header file : #include <libburn/libburn.h> */
/* This program insists in the own headerfile. */
#include "../libburn/libburn.h"
/* libburn is intended for Linux systems with kernel 2.4 or 2.6 for now */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
/** For simplicity i use global variables to represent the drives.
Drives are systemwide global, so we do not give away much of good style.
*/
/** This list will hold the drives known to libburn. This might be all CD
drives of the system and thus might impose severe impact on the system.
*/
static struct burn_drive_info *drive_list;
/** If you start a long lasting operation with drive_count > 1 then you are
not friendly to the users of other drives on those systems. Beware. */
static unsigned int drive_count;
/** This variable indicates wether the drive is grabbed and must be
finally released */
static int drive_is_grabbed = 0;
/* Some in-advance definitions to allow a more comprehensive ordering
of the functions and their explanations in here */
int telltoc_aquire_by_adr(char *drive_adr);
int telltoc_aquire_by_driveno(int *drive_no, int silent);
/* ------------------------------- API gestures ---------------------------- */
/** You need to aquire a drive before burning. The API offers this as one
compact call and alternatively as application controllable gestures of
whitelisting, scanning for drives and finally grabbing one of them.
If you have a persistent address of the drive, then the compact call is
to prefer because it only touches one drive. On modern Linux kernels,
there should be no fatal disturbance of ongoing burns of other libburn
instances with any of our approaches. We use open(O_EXCL) by default.
On /dev/hdX it should cooperate with growisofs and some cdrecord variants.
On /dev/sgN versus /dev/scdM expect it not to respect other programs.
*/
int telltoc_aquire_drive(char *drive_adr, int *driveno, int silent_drive)
{
int ret;
if(drive_adr != NULL && drive_adr[0] != 0)
ret = telltoc_aquire_by_adr(drive_adr);
else
ret = telltoc_aquire_by_driveno(driveno, silent_drive);
return ret;
}
/** If the persistent drive address is known, then this approach is much
more un-obtrusive to the systemwide livestock of drives. Only the
given drive device will be opened during this procedure.
*/
int telltoc_aquire_by_adr(char *drive_adr)
{
int ret;
fprintf(stderr,"Aquiring drive '%s' ...\n",drive_adr);
ret = burn_drive_scan_and_grab(&drive_list,drive_adr,1);
if (ret <= 0) {
fprintf(stderr,"FAILURE with persistent drive address '%s'\n",
drive_adr);
} else {
fprintf(stderr,"Done\n");
drive_is_grabbed = 1;
}
return ret;
}
/** This method demonstrates how to use libburn without knowing a persistent
drive address in advance. It has to make sure that after assessing the list
of available drives, all unwanted drives get closed again. As long as they
are open, no other libburn instance can see them. This is an intended
locking feature. The application is responsible for giving up the locks
by either burn_drive_release() (only after burn_drive_grab() !),
burn_drive_info_forget(), burn_drive_info_free(), or burn_finish().
@param driveno the index number in libburn's drive list. This will get
set to 0 on success and will then be the drive index to
use in the further dourse of processing.
@param silent_drive 1=do not print "Drive found :" line with *driveno >= 0
@return 1 success , <= 0 failure
*/
int telltoc_aquire_by_driveno(int *driveno, int silent_drive)
{
char adr[BURN_DRIVE_ADR_LEN];
int ret, i;
fprintf(stderr, "Beginning to scan for devices ...\n");
while (!burn_drive_scan(&drive_list, &drive_count))
usleep(1002);
if (drive_count <= 0 && *driveno >= 0) {
fprintf(stderr, "FAILED (no drives found)\n");
return 0;
}
fprintf(stderr, "Done\n");
for (i = 0; i < drive_count; i++) {
if (*driveno >= 0 && (silent_drive || *driveno != i))
continue;
if (burn_drive_get_adr(&(drive_list[i]), adr) <=0)
strcpy(adr, "-get_adr_failed-");
printf("Drive found : %d --drive '%s' : ", i,adr);
printf("%-8s %-16s (%4s)\n",
drive_list[i].vendor,drive_list[i].product,
drive_list[i].revision);
}
if (*driveno < 0) {
fprintf(stderr,
"Pseudo-drive \"-\" given : bus scanning done.\n");
return 2; /* the program will end after this */
}
/* We already made our choice via command line. (default is 0)
So we just have to keep our desired drive and drop all others.
*/
if (drive_count <= *driveno) {
fprintf(stderr,
"Found only %d drives. Number %d not available.\n",
drive_count, *driveno);
return 0; /* the program will end after this */
}
/* Drop all drives which we do not want to use */
for (i = 0; i < drive_count; i++) {
if (i == *driveno) /* the one drive we want to keep */
continue;
ret = burn_drive_info_forget(&(drive_list[i]),0);
if (ret != 1)
fprintf(stderr, "Cannot drop drive %d. Please report \"ret=%d\" to libburn-hackers@pykix.org\n",
i, ret);
else
fprintf(stderr, "Dropped unwanted drive %d\n",i);
}
/* Make the one we want ready for inquiry */
ret= burn_drive_grab(drive_list[*driveno].drive, 1);
if (ret != 1)
return 0;
drive_is_grabbed = 1;
return 1;
}
/** This gesture is necessary to get my NEC DVD_RW ND-4570A out of a state
of noisy overexcitement after it was inquired for Next Writeable Address.
The noise then still lasts 20 seconds. Same with cdrecord -toc, btw.
It opens a small gap for losing the drive to another libburn instance.
Not a problem in telltoc. This is done as very last drive operation.
Eventually the other libburn instance will have the same sanitizing effect.
*/
int telltoc_regrab(struct burn_drive *drive) {
int ret;
if (drive_is_grabbed)
burn_drive_release(drive, 0);
drive_is_grabbed = 0;
ret = burn_drive_grab(drive, 0);
if (ret != 0) {
drive_is_grabbed = 1;
}
return !!ret;
}
int telltoc_media(struct burn_drive *drive)
{
int ret, media_found = 0;
double max_speed = 0.0, min_speed = 0.0;
enum burn_disc_status s;
while (burn_drive_get_status(drive, NULL) != BURN_DRIVE_IDLE)
usleep(100001);
while ((s = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
usleep(100001);
printf("Media status : ");
if (s==BURN_DISC_FULL) {
printf("is written , is closed\n");
media_found = 1;
} else if (s==BURN_DISC_APPENDABLE) {
printf("is written , is appendable\n");
media_found = 1;
} else if (s==BURN_DISC_BLANK) {
printf("is blank\n");
media_found = 1;
} else if (s==BURN_DISC_EMPTY)
printf("is not present\n");
else
printf("is not recognizable\n");
printf("Media type : ");
if (media_found) {
if (burn_disc_erasable(drive))
printf("is erasable\n");
else
printf("is not erasable\n");
} else
printf("is not recognizable\n");
ret= burn_disc_read_atip(drive);
if(ret>0) {
ret= burn_drive_get_min_write_speed(drive);
min_speed = ((double ) ret) / 176.0;
}
ret= burn_drive_get_write_speed(drive);
max_speed = ((double ) ret) / 176.0;
if (!media_found)
printf("Drive speed : max=%.f\n", max_speed);
else if (min_speed<=0)
printf("Media speed : max=%.f\n", max_speed);
else
printf("Media speed : max=%.f , min=%.f\n",
max_speed, min_speed);
return 1;
}
int telltoc_toc(struct burn_drive *drive)
{
int num_sessions = 0 , num_tracks = 0 , lba = 0;
int track_count = 0;
int session_no, track_no;
enum burn_disc_status s;
struct burn_disc *disc= NULL;
struct burn_session **sessions;
struct burn_track **tracks;
struct burn_toc_entry toc_entry;
while (burn_drive_get_status(drive, NULL) != BURN_DRIVE_IDLE)
usleep(100001);
while ((s = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
usleep(100001);
disc = burn_drive_get_disc(drive);
if (disc==NULL) {
fprintf(stderr, "SORRY: Cannot obtain Table Of Content\n");
return 2;
}
sessions = burn_disc_get_sessions(disc, &num_sessions);
for (session_no = 0; session_no<num_sessions; session_no++) {
tracks = burn_session_get_tracks(sessions[session_no],
&num_tracks);
if (tracks==NULL)
continue;
for(track_no= 0; track_no<num_tracks; track_no++) {
track_count++;
burn_track_get_entry(tracks[track_no], &toc_entry);
lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec,
toc_entry.pframe);
printf("Media content: session %2d ", session_no+1);
printf("track %2d %s lba: %9d %2.2u:%2.2u:%2.2u\n",
track_count,
((toc_entry.control&7)<4?"audio":"data "),
lba,
toc_entry.pmin,
toc_entry.psec,
toc_entry.pframe);
}
burn_session_get_leadout_entry(sessions[session_no],
&toc_entry);
lba = burn_msf_to_lba(toc_entry.pmin,
toc_entry.psec, toc_entry.pframe);
printf("Media content: session %2d ", session_no+1);
printf("leadout lba: %9d %2.2u:%2.2u:%2.2u\n",
lba,
toc_entry.pmin,
toc_entry.psec,
toc_entry.pframe);
}
if (disc!=NULL)
burn_disc_free(disc);
return 1;
}
int telltoc_msinfo(struct burn_drive *drive,
int msinfo_explicit, int msinfo_alone)
{
int num_sessions, session_no, ret, num_tracks;
int nwa = -123456789, lba = -123456789, aux_lba, lout_lba;
enum burn_disc_status s;
struct burn_disc *disc= NULL;
struct burn_session **sessions;
struct burn_track **tracks;
struct burn_toc_entry toc_entry;
struct burn_write_opts *o= NULL;
while (burn_drive_get_status(drive, NULL) != BURN_DRIVE_IDLE)
usleep(100001);
while ((s = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
usleep(100001);
if (s!=BURN_DISC_APPENDABLE) {
if (!msinfo_explicit)
return 2;
fprintf(stderr,
"SORRY: --msinfo can only operate on appendable media.\n");
return 0;
}
/* man mkisofs , option -C :
The first number is the sector number of the first sector in
the last session of the disk that should be appended to.
*/
disc = burn_drive_get_disc(drive);
if (disc==NULL) {
fprintf(stderr,"SORRY: Cannot obtain info about CD content\n");
return 2;
}
sessions = burn_disc_get_sessions(disc, &num_sessions);
for (session_no = 0; session_no<num_sessions; session_no++) {
tracks = burn_session_get_tracks(sessions[session_no],
&num_tracks);
if (tracks==NULL || num_tracks<=0)
continue;
burn_track_get_entry(tracks[0], &toc_entry);
lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec,
toc_entry.pframe);
}
if(lba==-123456789) {
fprintf(stderr,"SORRY: Cannot find any track on media\n");
{ ret = 0; goto ex; }
}
/* Prepare a qualified guess as fallback for nwa inquiry */
burn_session_get_leadout_entry(sessions[num_sessions-1], &toc_entry);
lout_lba= burn_msf_to_lba(toc_entry.pmin,toc_entry.psec,
toc_entry.pframe);
/* man mkisofs , option -C :
The second number is the starting sector number of the new session.
*/
/* Set some write opts to be sent to drive. LG GSA-4082B needs it. */
o= burn_write_opts_new(drive);
if(o!=NULL) {
burn_write_opts_set_perform_opc(o, 0);
burn_write_opts_set_write_type(o,
BURN_WRITE_TAO, BURN_BLOCK_MODE1);
}
/* Now try to inquire nwa from drive */
ret= burn_disc_track_lba_nwa(drive,o,0,&aux_lba,&nwa);
telltoc_regrab(drive); /* necessary to calm down my NEC drive */
if(ret<=0) {
fprintf(stderr,
"NOTE: Guessing next writeable address from leadout\n");
if(num_sessions>0)
nwa= lout_lba+6900;
else
nwa= lout_lba+11400;
}
if (!msinfo_alone)
printf("Media msinfo : mkisofs ... -C ");
printf("%d,%d\n",lba,nwa);
ret = 1;
ex:;
if (disc!=NULL)
burn_disc_free(disc);
if (o!=NULL)
burn_write_opts_free(o);
return ret;
}
/** The setup parameters of telltoc */
static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
static int driveno = 0;
static int do_media = 0;
static int do_toc = 0;
static int do_msinfo = 0;
static int print_help = 0;
/** Converts command line arguments into above setup parameters.
drive_adr[] must provide at least BURN_DRIVE_ADR_LEN bytes.
source_adr[] must provide at least 4096 bytes.
*/
int telltoc_setup(int argc, char **argv)
{
int i;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--drive")) {
++i;
if (i >= argc) {
fprintf(stderr,"--drive requires an argument\n");
return 1;
} else if (strcmp(argv[i], "-") == 0) {
drive_adr[0] = 0;
driveno = -1;
} else if (isdigit(argv[i][0])) {
drive_adr[0] = 0;
driveno = atoi(argv[i]);
} else {
if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
fprintf(stderr,"--drive address too long (max. %d)\n",
BURN_DRIVE_ADR_LEN-1);
return 2;
}
strcpy(drive_adr, argv[i]);
}
} else if (strcmp(argv[i],"--media")==0) {
do_media = 1;
} else if (!strcmp(argv[i], "--msinfo")) {
do_msinfo = 1;
} else if (!strcmp(argv[i], "--toc")) {
do_toc = 1;
} else if (!strcmp(argv[i], "--help")) {
print_help = 1;
} else {
fprintf(stderr, "Unidentified option: %s\n", argv[i]);
return 7;
}
}
if (argc==1)
print_help = 1;
if (print_help) {
printf("Usage: %s\n", argv[0]);
printf(" [--drive <address>|<driveno>|\"-\"]\n");
printf(" [--media] [--toc] [--msinfo]\n");
printf("Examples\n");
printf("A bus scan (needs rw-permissions to see a drive):\n");
printf(" %s --drive -\n",argv[0]);
printf("Obtain info about the type of loaded media:\n");
printf(" %s --drive /dev/hdc --media\n",argv[0]);
printf("Obtain table of content:\n");
printf(" %s --drive /dev/hdc --toc\n",argv[0]);
printf("Obtain parameters for option -C of program mkisofs:\n");
printf(" msinfo=$(%s --drive /dev/hdc --msinfo 2>/dev/null)\n",
argv[0]);
printf(" mkisofs ... -C \"$msinfo\" ...\n");
printf("Obtain what is available about drive 0 and its media\n");
printf(" %s --drive 0\n",argv[0]);
}
return 0;
}
int main(int argc, char **argv)
{
int ret, toc_failed = 0, msinfo_alone = 0, msinfo_explicit = 0;
int full_default = 0;
ret = telltoc_setup(argc, argv);
if (ret)
exit(ret);
/* Behavior shall be different if --msinfo is only option */
if (do_msinfo) {
msinfo_explicit = 1;
if (!(do_media || do_toc))
msinfo_alone = 1;
}
/* Default option is to do everything if possible */
if (do_media==0 && do_msinfo==0 && do_toc==0 && driveno!=-1) {
if(print_help)
exit(0);
full_default = do_media = do_msinfo = do_toc = 1;
}
fprintf(stderr, "Initializing libburn.pykix.org ...\n");
if (burn_initialize())
fprintf(stderr, "Done\n");
else {
fprintf(stderr,"\nFATAL: Failed to initialize.\n");
exit(33);
}
/* Print messages of severity SORRY or more directly to stderr */
burn_msgs_set_severities("NEVER", "SORRY", "telltoc : ");
/** Note: driveno might change its value in this call */
ret = telltoc_aquire_drive(drive_adr, &driveno, !full_default);
if (ret<=0) {
fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
{ ret = 34; goto finish_libburn; }
}
if (ret == 2)
{ ret = 0; goto release_drive; }
if (do_media) {
ret = telltoc_media(drive_list[driveno].drive);
if (ret<=0)
{ret = 36; goto release_drive; }
}
if (do_toc) {
ret = telltoc_toc(drive_list[driveno].drive);
if (ret<=0)
{ret = 37; goto release_drive; }
if (ret==2)
toc_failed = 1;
}
if (do_msinfo) {
ret = telltoc_msinfo(drive_list[driveno].drive,
msinfo_explicit, msinfo_alone);
if (ret<=0)
{ret = 38; goto release_drive; }
}
ret = 0;
if (toc_failed)
ret = 37;
release_drive:;
if (drive_is_grabbed)
burn_drive_release(drive_list[driveno].drive, 0);
finish_libburn:;
/* This app does not bother to know about exact scan state.
Better to accept a memory leak here. We are done anyway. */
/* burn_drive_info_free(drive_list); */
burn_finish();
exit(ret);
}
/* License and copyright aspects:
See libburner.c
*/

View File

@ -1,103 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <libburn/libburn.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
static struct burn_drive_info *drives;
static unsigned int n_drives;
static void show_tocs()
{
struct burn_session **sessions;
struct burn_track **tracks;
struct burn_disc *disc;
int nses, ntracks, hidefirst;
unsigned int i, j, k;
struct burn_toc_entry e;
enum burn_disc_status s;
for (i = 0; i < n_drives; ++i) {
fprintf(stderr, "TOC for disc in %s - %s:\n",
drives[i].vendor, drives[i].product);
if (!burn_drive_grab(drives[i].drive, 1)) {
fprintf(stderr, "Unable to open the drive!\n");
continue;
}
while (burn_drive_get_status(drives[i].drive, NULL))
usleep(1000);
while ((s = burn_disc_get_status(drives[i].drive))
== BURN_DISC_UNREADY)
usleep(1000);
if (s != BURN_DISC_FULL) {
burn_drive_release(drives[i].drive, 0);
fprintf(stderr, "No disc found!\n");
continue;
}
disc = burn_drive_get_disc(drives[i].drive);
sessions = burn_disc_get_sessions(disc, &nses);
for (k = 0; k < nses; ++k) {
tracks = burn_session_get_tracks(sessions[k],
&ntracks);
hidefirst = burn_session_get_hidefirst(sessions[k]);
if (hidefirst)
fprintf(stderr,
"track: GAP (%2d) lba: %9d (%9d) %02d:%02d:%02d adr: X control: X mode: %d\n",
k + 1, 0, 0, 0, 2, 0,
burn_track_get_mode(tracks[0]));
for (j = !!hidefirst; j < ntracks; ++j) {
burn_track_get_entry(tracks[j], &e);
fprintf(stderr,
"track: %3d (%2d) lba: %9d (%9d) %02d:%02d:%02d "
"adr: %d control: %d mode: %d\n",
e.point, e.session,
burn_msf_to_lba(e.pmin, e.psec,
e.pframe),
burn_msf_to_lba(e.pmin, e.psec,
e.pframe) * 4,
e.pmin, e.psec, e.pframe, e.adr,
e.control,
burn_track_get_mode(tracks[j]));
}
burn_session_get_leadout_entry(sessions[k], &e);
fprintf(stderr,
"track:lout (%2d) lba: %9d (%9d) %02d:%02d:%02d "
"adr: %d control: %d mode: %d\n",
k + 1, burn_msf_to_lba(e.pmin, e.psec,
e.pframe),
burn_msf_to_lba(e.pmin, e.psec,
e.pframe) * 4, e.pmin,
e.psec, e.pframe, e.adr, e.control, -1);
}
burn_disc_free(disc);
burn_drive_release(drives[i].drive, 0);
}
}
int main()
{
fprintf(stderr, "Initializing library...");
if (burn_initialize())
fprintf(stderr, "Success\n");
else {
printf("Failed\n");
return 1;
}
fprintf(stderr, "Scanning for devices...");
while (!burn_drive_scan(&drives, &n_drives)) ;
fprintf(stderr, "Done\n");
show_tocs();
burn_drive_info_free(drives);
burn_finish();
return 0;
}

View File

@ -1,77 +0,0 @@
# a module to help with handling of filenames, directory trees, etc.
import os
import os.path
import stat
def pathsubtract(a, b):
index = a.find(b)
if index == -1:
return None
res = a[ (index + len(b)): ]
if res.find("/") == 0:
res = res[1:]
return res
# same as C strcmp()
def strcmp(a, b):
if a < b:
return -1
if a > b:
return 1
return 0
class TreeNode:
# path is the location of the file/directory. It is either a full path or
# a path relative to $PWD
def __init__(self, parent, path=".", root=".", isofile=None):
if isofile:
self.root = os.path.abspath(isofile)
self.path = ""
else:
fullpath = os.path.abspath( path )
fullroot = os.path.abspath( root )
self.root = fullroot
self.path = pathsubtract( fullpath, fullroot )
self.parent = parent
self.children = []
if self.path == None:
raise NameError, "Invalid paths %s and %s" % (fullpath, fullroot)
# if this is a directory, add its children recursively
def addchildren(self):
if not stat.S_ISDIR( os.lstat(self.root + "/" + self.path).st_mode ):
return
children = os.listdir( self.root + "/" + self.path )
for child in children:
if self.path:
child = self.path + "/" + child
self.children.append( TreeNode(self, child, self.root) )
for child in self.children:
child.addchildren()
def printAll(self, spaces=0):
print " "*spaces + self.root + "/" + self.path
for child in self.children:
child.printAll(spaces + 2)
def isValidISO1(self):
pass
class Tree:
def __init__(self, root=None, isofile=None):
if isofile:
self.root = TreeNode(parent=None, isofile=isofile)
else:
self.root = TreeNode(parent=None, path=root, root=root)
self.root.addchildren()
def isValidISO1(self):
return root.isValidISO1();
#t = Tree(root=".")
#t.root.printAll()

Binary file not shown.