release 0.6.4beta trunk 0.6.4beta
authornathan
Sat, 29 Dec 2007 15:25:21 +0100
branchtrunk
changeset 479da91042fcc
parent 3 d09ec85ffdfe
child 5 dbe5f35a0fa4
release 0.6.4beta
.hgtags
CHANGES
CREDITS
Makefile
README
TODO
cdbackup.1
cdbackup.c
cdbackup.h
cdrestore.1
cdrestore.c
cdrom.c
cdrom.h
examples/cdload
examples/cdsave
misc.c
misc.h
version.h
virtual-backup.c
virtual.c
virtual.h
     1.1 --- a/.hgtags	Sat Dec 29 15:23:55 2007 +0100
     1.2 +++ b/.hgtags	Sat Dec 29 15:25:21 2007 +0100
     1.3 @@ -1,2 +1,3 @@
     1.4  d85c12073deaa1b5048d3a8c761d9dd55d8169a1 0.6.2
     1.5  6bcb44b9edb16f763d32184678a6f6627675c0ab 0.6.3
     1.6 +d09ec85ffdfeffa93a5c341bef50509d40d215bc 0.6.4beta
     2.1 --- a/CHANGES	Sat Dec 29 15:23:55 2007 +0100
     2.2 +++ b/CHANGES	Sat Dec 29 15:25:21 2007 +0100
     2.3 @@ -1,3 +1,15 @@
     2.4 +0.6.4beta
     2.5 +---------
     2.6 +- added support for file based backups (virtual image).
     2.7 +- added DVD support (needs cdrecord-ProDVD).
     2.8 +- added CRC checksum to ensure backup integrity.
     2.9 +- now auto-detecting media size (via cdrecord -atip).
    2.10 +- now using defaults from environment vars CDR_DEVICE & CDR_SPEED.
    2.11 +- fixed a typo in the man page (Debian Bug#180279).
    2.12 +- check return value of read() in diskchange.
    2.13 +- fixed missing stderr in fprintf() calls.
    2.14 +- added some glue to compile on SunOS.
    2.15 +
    2.16  0.6.3
    2.17  -----
    2.18  - added -F option to cdrestore to force starting restore in the
     3.1 --- a/CREDITS	Sat Dec 29 15:23:55 2007 +0100
     3.2 +++ b/CREDITS	Sat Dec 29 15:25:21 2007 +0100
     3.3 @@ -20,3 +20,8 @@
     3.4  E: huels@iname.com
     3.5  D: multidisk support, code cleanup, bugfixes
     3.6  S: Monheim, Germany
     3.7 +
     3.8 +N: Alejandro Marín
     3.9 +E: amarin@servpast.org
    3.10 +D: SunOS port
    3.11 +S: San José, Costa Rica
     4.1 --- a/Makefile	Sat Dec 29 15:23:55 2007 +0100
     4.2 +++ b/Makefile	Sat Dec 29 15:25:21 2007 +0100
     4.3 @@ -22,15 +22,15 @@
     4.4  	$(CC) $(CFLAGS) -c $< -o $@
     4.5  
     4.6  $(DEPFILE): Makefile
     4.7 -	@$(CC) $(DEPFLAGS) cdbackup.c cdrestore.c cdrom.c misc.c > $@
     4.8 +	@$(CC) $(DEPFLAGS) cdbackup.c cdrestore.c cdrom.c virtual.c misc.c > $@
     4.9  
    4.10  include $(DEPFILE)
    4.11  
    4.12 -cdbackup: cdbackup.o cdrom.o misc.o
    4.13 -	$(CC) $(CFLAGS) -o cdbackup cdbackup.o cdrom.o misc.o
    4.14 +cdbackup: cdbackup.o cdrom.o virtual.o virtual-backup.o misc.o
    4.15 +	$(CC) $(CFLAGS) -o $@ $^
    4.16  
    4.17 -cdrestore: cdrestore.o cdrom.o misc.o
    4.18 -	$(CC) $(CFLAGS) -o cdrestore cdrestore.o cdrom.o misc.o
    4.19 +cdrestore: cdrestore.o cdrom.o virtual.o misc.o
    4.20 +	$(CC) $(CFLAGS) -o $@ $^
    4.21  
    4.22  strip: $(TARGETS)
    4.23  	strip $(TARGETS)
     5.1 --- a/README	Sat Dec 29 15:23:55 2007 +0100
     5.2 +++ b/README	Sat Dec 29 15:25:21 2007 +0100
     5.3 @@ -1,19 +1,23 @@
     5.4 -cdbackup, cdrestore - CD archive utilities version 0.6.3
     5.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt. All rights reserved.
     5.6 +cdbackup, cdrestore - CD archive utilities version 0.6.4beta
     5.7 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt. All rights reserved.
     5.8  
     5.9  This software is released under a BSD-style license - see the LICENSE file.
    5.10  
    5.11  cdbackup and cdrestore are a pair of utilities designed to facilitiate
    5.12 -streaming backup to and from CD-R(W) disks.  Specificially, they were
    5.13 -designed to work with dump/restore, but tar/cpio/whatever you want should
    5.14 +streaming backup to and from CD-R(W)/DVD-R(W) disks.  Specificially, they were
    5.15 +designed to work with dump/restore, but tar/cpio/afio/whatever you want should
    5.16  work, so long as it writes to stdout for backups and reads from stdin for
    5.17  restores.
    5.18  
    5.19 -NOTE: this program REQUIRES that a recent version of cdrecord be present
    5.20 -in the PATH.
    5.21 +NOTE: this program REQUIRES that a recent version of cdrecord (or
    5.22 +cdrecord-ProDVD for DVD support) be present in the PATH.
    5.23  
    5.24  See manpages for further details.
    5.25  
    5.26 +This release has beta-state as it introduces many new features
    5.27 +and also changed on-disk data format. It has been carefully
    5.28 +tested, but for now I cannot be sure that it's as reliable and
    5.29 +stable as the 0.6.3 release. Take care!
    5.30  
    5.31  INSTALL:
    5.32  --------
    5.33 @@ -45,7 +49,7 @@
    5.34  CONTACT:
    5.35  --------
    5.36  
    5.37 -Project maintainer is: Stefan Hülswitt <huels@iname.com>
    5.38 +Project maintainer is: Stefan Hülswitt <s.huelswitt@gmx.de>
    5.39  Homepage:              http://www.muempf.de/
    5.40  
    5.41  Any comments, suggestions, bug reports, patches and fixes
     6.1 --- a/TODO	Sat Dec 29 15:23:55 2007 +0100
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,1 +0,0 @@
     6.4 --increase buffer size on restore for speed?
     7.1 --- a/cdbackup.1	Sat Dec 29 15:23:55 2007 +0100
     7.2 +++ b/cdbackup.1	Sat Dec 29 15:25:21 2007 +0100
     7.3 @@ -1,17 +1,24 @@
     7.4 -.TH "cdbackup" "1" "0.6.3" "Stefan Hülswitt" ""
     7.5 +.TH "cdbackup" "1" "0.6.4beta" "Stefan Hülswitt" ""
     7.6  .SH "NAME"
     7.7  .LP 
     7.8 -cdbackup \- Streaming backup to CD\-R(W)
     7.9 +cdbackup \- Streaming backup to CD\-R(W)/DVR\-R(W)
    7.10  .SH "SYNOPSIS"
    7.11  .LP 
    7.12 -cdbackup [\-mvDVX] [\-d \fIdevice\fP] [\-r \fIscsi\-dev\fP] [\-s \fIspeed\fP]
    7.13 -         [\-p \fInum\fP] [\-l \fIsize\fP] [\-a \fIlabel\fP] [\-c \fIcommand\fP]
    7.14 -         [\-\- \fIcdrecord\-options\fP]
    7.15 +cdbackup [\-mvwCDRVX] [\-d \fIdevice\fP] [\-r \fIscsi\-dev\fP] [\-s \fIspeed\fP]
    7.16 +         [\-i \fIimage\fP] [\-p \fInum\fP] [\-l \fIsize\fP] [\-a \fIlabel\fP]
    7.17 +         [\-c \fIcommand\fP] [\-\- \fIcdrecord\-options\fP]
    7.18  .SH "DESCRIPTION"
    7.19  .LP 
    7.20 -cdbackup is a utility to make streaming backups to CD\-R(W) disks. It's designed to work with any backup tool which writes the backup to stdout (like tar/cpio/afio).
    7.21 -.LP 
    7.22 -\fINOTE:\fR this program REQUIRES that a recent version of \fBcdrecord\fR(1) is present in the PATH.
    7.23 +cdbackup is a utility to make streaming backups to CD\-R(W)/DVD\-R(W) disks. It's designed to work with any backup tool which writes the backup to stdout (like tar/cpio/afio).
    7.24 +.LP 
    7.25 +\fINOTE:\fR this program REQUIRES that a recent version of \fBcdrecord\fR(1) (or
    7.26 +cdrecord\-ProDVD for DVD support) is present in the PATH.
    7.27 +.LP 
    7.28 +While you can perfectly append several sessions on CD\-R(W) media, I didn't manage to make this work on DVD\-R(W) media. To allow multiple, separate backups on these media, the concept of virtual images has been introduced.
    7.29 +.br 
    7.30 +A virtual image is a plain file on your harddisk. You can append several backups to an image and after completing your backup session, the image is dumped to CDR/DVD media in one burning session. You can dump the same image multiple times too, if you want redundancy on the CDR/DVD media.
    7.31 +.br 
    7.32 +Virtual image files are never deleted by cdbackup. After dumping an image, you have to delete it by your self.
    7.33  .LP 
    7.34  \fIWARNING!\fR When using this program under Linux, be sure not to use dump on a mounted
    7.35  filesystem. This has a high potential for creating corrupted backups. As of kernel version
    7.36 @@ -29,13 +36,13 @@
    7.37  \fB\-r\fR \fIscsi\-device\fP
    7.38  The scsi device which is passed to \fBcdrecord\fR(1) (via dev=\fIscsi\-device\fP). Must be given as three, comma seperated number: \fIscsibus\fR,\fItarget\fR,\fIlun\fR.
    7.39  .br 
    7.40 -(default: none)
    7.41 +(default: none or the contents of the environment variable CDR_DEVICE)
    7.42  
    7.43  .TP 
    7.44  \fB\-s\fR \fIspeed\fP
    7.45  The writing speed which is passed to \fBcdrecord\fR(1) (via speed=\fIspeed\fP).
    7.46  .br 
    7.47 -(default: 4)
    7.48 +(default: 4 or the contents of the environment variable CDR_SPEED)
    7.49  
    7.50  .TP 
    7.51  \fB\-p\fR \fInum\fP
    7.52 @@ -48,10 +55,41 @@
    7.53  Enables the use of CDROM XA2 mode in \fBcdrecord\fR(1). By default CDROM mode 1 is used. The default is possibly causing problems during restore on certain kernel version/CDROM hardware combinations at the end of the last session on a media. Sony drives doesn't support CDROM XA 2 mode (see \fBcdrecord\fR(1) \-multi).
    7.54  
    7.55  .TP 
    7.56 +\fB\-R\fR
    7.57 +Enables DVD writing mode. Cdrecord\-ProDVD is used to burn DVD media, but it's called through a script called "dvdrecord". You should set your cdrecord\-ProDVD key and call cdrecord\-ProDVD from there.
    7.58 +.br 
    7.59 +Remember that you cannot write multiple sessions to DVD media. Either you stick with one backup per media or you have to use virtual images.
    7.60 +.br 
    7.61 +In DVD mode the options \-p and \-X have no effect.
    7.62 +
    7.63 +.TP 
    7.64 +\fB\-i\fR \fIimage\fP
    7.65 +Enables virtual image mode. The backup stream is written to the given image file. The file is created if it doesn't exists. It's mandatory to give an explicit media size with \-l. Take care that the created virtual image isn't lager that the media size you want to dump it later.
    7.66 +You can add up to 96 backups to an virtual image.
    7.67 +.br 
    7.68 +If the backup extends the specified media size and you have enabled multi\-disk mode, additional images files are created (the filenames are derived from the inital image name by adding a dot and a decimal number).
    7.69 +.br 
    7.70 +(default: none)
    7.71 +
    7.72 +.TP 
    7.73 +\fB\-w\fR
    7.74 +Dump the virtual image specified with \-i to real media. Image dumps are written as single sessions always. If you have enabled multi\-disk mode and additional images are found, you're prompted for media change, so that you can dump all images in turn.
    7.75 +.br 
    7.76 +Virtual images (even when dumped to media) are not compatible with older cdbackup versions.
    7.77 +
    7.78 +.TP 
    7.79  \fB\-l\fR \fIsize\fP
    7.80 -The media size in megabytes. This value is used to calculate how much data can be stored on the media.
    7.81 -.br 
    7.82 -(default: 650)
    7.83 +For normal operation the media size is auto\-detected from the cdrecord ATIP information. If this fails or for virtual image mode use this option to set the media size. This is used to calculate how much data can be stored on the media.
    7.84 +.br 
    7.85 +By default the given value is taken as megabytes. You can append a single letter to the number to select: (k)ilobytes, (m)egabytes, (g)igabytes or (s)ectors (e.g. 170k, 4488m, 350000s).
    7.86 +.br 
    7.87 +(default: auto\-detect)
    7.88 +
    7.89 +.TP 
    7.90 +\fB\-C\fR
    7.91 +Disables creation of the datablock CRC checksum. There is no real reason to use this option, unless you can't efford the extra 0,2% media space that is used to store the checksum.
    7.92 +.br 
    7.93 +Although the on\-disk layout of checksumed backups is different, they are fully backwards compatible with older version of cdbackup, but obviously older versions can't check the backup integrity.
    7.94  
    7.95  .TP 
    7.96  \fB\-a\fR \fIlabel\fP
    7.97 @@ -95,6 +133,21 @@
    7.98  To create a tar archive of /usr and output it to a series (multi\-disk mode) of 650 MB CD\-R(W) on /dev/sr1 (scsi device 1,4,0) with writting speed 12 and verbose output:
    7.99  .IP 
   7.100  tar cf \- /usr | cdbackup \-d /dev/sr1 \-r 1,4,0 \-s 12 \-m \-v
   7.101 +
   7.102 +.LP 
   7.103 +To create a backup on a virtual image:
   7.104 +.IP 
   7.105 +tar cf \- /usr | cdbackup \-i /tmp/vimage \-l 4488m
   7.106 +
   7.107 +.LP 
   7.108 +Add another backup to the same virtual image (with multi\-disk mode):
   7.109 +.IP 
   7.110 +tar cf \- /home | cdbackup \-i /tmp/vimage \-l 4488m
   7.111 +
   7.112 +.LP 
   7.113 +Dump the virtual image to one (or several) DVD media on /dev/cdrom (scsi\-ide device 0,0,0), enabling BURNFREE:
   7.114 +.IP 
   7.115 +cdbackup \-i /tmp/vimage \-w \-R \-d /dev/cdrom \-r 0,0,0 \-s 4 \-m \-\- driveropts=burnfree
   7.116  .SH "KNOWN PROBLEMS"
   7.117  .LP 
   7.118  Certain combinations of CDROM drivers and kernel versions are causing a problem when restoring data. The restore process aborts with an read error close to the end of the session, while the data on the media is perfectly good.
   7.119 @@ -120,12 +173,12 @@
   7.120  Please contact the author if you can contribute additional information about the problem.
   7.121  .SH "AUTHORS"
   7.122  .LP 
   7.123 -Stefan Hülswitt <huels@iname.com>
   7.124 +Stefan Hülswitt <s.huelswitt@gmx.de>
   7.125  .SH "SEE ALSO"
   7.126  .LP 
   7.127  \fBcdrestore\fR(1), \fBcdrecord\fR(1)
   7.128  .SH "LICENSE"
   7.129 -Copyright (c) 2000\-2002 Craig Condit, Stefan Hülswitt.
   7.130 +Copyright (c) 2000\-2004 Craig Condit, Stefan Hülswitt.
   7.131  
   7.132  Redistribution and use in source and binary forms, with or without
   7.133  modification, are permitted provided that the following conditions are met: 
     8.1 --- a/cdbackup.c	Sat Dec 29 15:23:55 2007 +0100
     8.2 +++ b/cdbackup.c	Sat Dec 29 15:25:21 2007 +0100
     8.3 @@ -1,5 +1,5 @@
     8.4  /* cdbackup.c
     8.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
     8.6 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
     8.7  
     8.8  Redistribution and use in source and binary forms, with or without
     8.9  modification, are permitted provided that the following conditions are met: 
    8.10 @@ -24,69 +24,135 @@
    8.11  */
    8.12  
    8.13  #define _LARGEFILE64_SOURCE
    8.14 +#define _GNU_SOURCE
    8.15  
    8.16  #include <stdlib.h>
    8.17  #include <stdio.h>
    8.18 +#include <stdarg.h>
    8.19  #include <unistd.h>
    8.20  #include <fcntl.h>
    8.21  #include <string.h>
    8.22  #include <time.h>
    8.23  #include <errno.h>
    8.24 -#include <getopt.h>
    8.25  #include <sys/wait.h>
    8.26  #include <sys/ioctl.h>
    8.27  #include <netinet/in.h>
    8.28 -#include <linux/cdrom.h>
    8.29 +
    8.30 +#ifndef sun
    8.31 +#include <getopt.h>
    8.32 +#endif
    8.33  
    8.34  #include "cdbackup.h"
    8.35  #include "cdrom.h"
    8.36 +#include "virtual.h"
    8.37  #include "misc.h"
    8.38  #include "debug.h"
    8.39  #include "version.h"
    8.40  
    8.41 -/* #define DEBUGOUT */
    8.42 -
    8.43  /* defaults */
    8.44 -char * prg_name ="cdbackup";
    8.45 -char * cd_dev   ="/dev/burner";
    8.46 -char * cdr_dev  =0;			/* no default here, too dangerous */
    8.47 -char * cd_label ="CDBackup Track";
    8.48 -int    cd_speed =4;
    8.49 -long   cd_len   =333000;		/* blocks */
    8.50 -int    padsize  =15;			/* blocks */
    8.51 -int    multidisk=0;
    8.52 -char * multicmd =0;
    8.53 -int    verbose  =0;
    8.54 -int    xamode2  =0;
    8.55 -int    debug    =0;
    8.56 +char *prg_name ="cdbackup";
    8.57 +char *cd_dev   ="/dev/burner";
    8.58 +char *cdr_dev  =0;                     /* no default here, too dangerous */
    8.59 +char *cd_label ="CDBackup Track";
    8.60 +int   cd_speed =4;
    8.61 +long  cd_len   =-1;                    /* blocks */
    8.62 +int   padsize  =15;                    /* blocks */
    8.63 +int   multidisk=0;
    8.64 +char *multicmd =0;
    8.65 +int   verbose  =0;
    8.66 +int   xamode2  =0;
    8.67 +int   crc      =1;
    8.68 +int   debug    =0;
    8.69 +int   virtual  =0;
    8.70 +char *virt_name=0;
    8.71 +int   virt_dump=0;
    8.72 +int   dvd      =0;
    8.73  
    8.74  char **cdrec_opt=0;
    8.75  int    cdrec_opt_count=0;
    8.76  
    8.77 -long long totalSize;
    8.78 +long long totalSize=0;
    8.79 +int disknum=1;
    8.80 +int secs;
    8.81  struct tm curtime;  /* global, so multi-disks get all the same time */
    8.82 -
    8.83 -/****************************************************************************/
    8.84 -
    8.85 -void usage()
    8.86 -{
    8.87 -  fprintf(stderr,
    8.88 -    "Usage: %s [options ...] [-- cdrecord-options ...]\n"
    8.89 -    "Reads from standard input, block formats and writes to CD-R(W).\n\n"
    8.90 -    "  -d DEVICE      DEVICE for CD queries (default /dev/burner)\n"
    8.91 -    "  -l N           CD-R has a size of N MB (default 650)\n"
    8.92 -    "  -r DEVICE      DEVICE for CD recording (e.g. 0,4,0)\n"
    8.93 -    "  -s N           record CD at speed N (default 4)\n"
    8.94 -    "  -X             enable CDROM XA2 mode in cdrecord\n"
    8.95 -    "  -a LABEL       use LABEL as CD session title\n"
    8.96 -    "  -p N           use a padsize of N sectors for the session (default 15)\n"
    8.97 -    "  -m             enable multi-disk mode\n"
    8.98 -    "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
    8.99 -    "  -v             be verbose\n"
   8.100 -    "  -D             enable DEBUG output\n"
   8.101 -    "  -V             prints version & exits\n"
   8.102 -    "  --             pass rest of commandline to cdrecord\n"
   8.103 -    "\n", prg_name);
   8.104 +int auto_size=0;
   8.105 +
   8.106 +/****************************************************************************/
   8.107 +
   8.108 +char *make_arg(const char *format, ...)
   8.109 +{
   8.110 +  char *ptr;
   8.111 +  va_list ap;
   8.112 +  va_start(ap,format);
   8.113 +  if(vasprintf(&ptr,format,ap)<0) serror("No memory for cdrecord args\n");
   8.114 +  va_end(ap);
   8.115 +  return ptr;
   8.116 +}
   8.117 +
   8.118 +void start_cdrecord(void)
   8.119 +{
   8.120 +  char **args, **p, *exname;
   8.121 +  int l;
   8.122 +  
   8.123 +  if(!(p=args=calloc(cdrec_opt_count+10,sizeof(char *))))
   8.124 +    serror("No memory for cdrecord args\n");
   8.125 +
   8.126 +  if(dvd) exname="dvdrecord"; else exname="cdrecord";
   8.127 +  *p++=exname;
   8.128 +
   8.129 +  if(virt_dump || dvd) {
   8.130 +    *p++="-dao";
   8.131 +    *p++=make_arg("tsize=%ds",secs);
   8.132 +    }
   8.133 +  else {
   8.134 +    *p++="-multi";
   8.135 +    *p++=make_arg("padsize=%ds",padsize);
   8.136 +    }
   8.137 +
   8.138 +  *p++=make_arg("speed=%d",cd_speed);
   8.139 +  *p++=make_arg("dev=%s",cdr_dev);
   8.140 +
   8.141 +  for(l=0 ; l<cdrec_opt_count ; l++) *p++=cdrec_opt[l];
   8.142 +
   8.143 +  if(xamode2 && !dvd) *p++="-xa2"; else *p++="-data";
   8.144 +  *p++="-";
   8.145 +  *p++=0;
   8.146 +
   8.147 +  if(debug) {
   8.148 +    fprintf(stderr,"%s: cdrecord command:",prg_name);
   8.149 +    for(p=args ; *p ; p++) fprintf(stderr," %s",*p);
   8.150 +    fprintf(stderr,"\n");
   8.151 +    }
   8.152 +
   8.153 +  execvp(exname,args);
   8.154 +  error("Exec failed (cdrecord)");
   8.155 +}
   8.156 +
   8.157 +long atip_cdrecord(void)
   8.158 +{
   8.159 +  char *cmd;
   8.160 +  FILE *p;
   8.161 +  long size=-1;
   8.162 +  
   8.163 +  asprintf(&cmd,"%srecord 2>&1 dev=%s -atip",dvd ? "dvd":"cd",cdr_dev);
   8.164 +  DEBUG("%s: cdrecord atip command: %s\n",prg_name,cmd);
   8.165 +
   8.166 +  p=popen(cmd,"r");
   8.167 +  if(!p) fprintf(stderr,"%s: atip command failed\n",prg_name);
   8.168 +  else {
   8.169 +    char buff[256];
   8.170 +    while(fgets(buff,sizeof(buff),p)) {
   8.171 +      if(dvd && !strncmp(buff,"rzone size:",11)) size=strtol(&buff[12],NULL,10);
   8.172 +      else if(!strncmp(buff,"  ATIP start of lead out:",25)) size=strtol(&buff[26],NULL,10);
   8.173 +      }
   8.174 +    }
   8.175 +  pclose(p);
   8.176 +  free(cmd);
   8.177 +  if(size>0 && verbose) {
   8.178 +    char buff[16];
   8.179 +    fprintf(stderr,"%s: auto-detected media size %s (%ld blocks)\n",prg_name,FlexSize(buff,(long long)size*CD_FRAMESIZE),size);
   8.180 +    }
   8.181 +  return size;
   8.182  }
   8.183  
   8.184  /****************************************************************************/
   8.185 @@ -94,11 +160,24 @@
   8.186  void parse_cmdline(char argc, char *argv[]) 
   8.187  {
   8.188    int i;
   8.189 -
   8.190 -  while ((i=getopt(argc,argv,"d:r:l:s:p:a:c:mvVXD"))>0) {
   8.191 +  char *val;
   8.192 +
   8.193 +  /* get some default from the environment */
   8.194 +  val=getenv("CDR_DEVICE");
   8.195 +  if(val) {
   8.196 +    cdr_dev=strdup(val);
   8.197 +    DEBUG("cdbackup: using recording device %s from CDR_DEVICE\n",cdr_dev);
   8.198 +    }
   8.199 +  val=getenv("CDR_SPEED");
   8.200 +  if(val) {
   8.201 +    cd_speed=strtol(val,NULL,10);
   8.202 +    DEBUG("cdbackup: using speed %d from CDR_SPEED\n",cd_speed);
   8.203 +    }
   8.204 +  
   8.205 +  while ((i=getopt(argc,argv,"d:r:l:s:p:a:c:mvVXDCi:wR"))>0) {
   8.206      switch (i) {
   8.207         case 'V': fprintf(stderr,"cdbackup "VERSION" (compiled "__DATE__")\n"
   8.208 -	                        "Copyright (C) 2000-2002\n"
   8.209 +	                        "Copyright (C) 2000-2004\n"
   8.210  			        "This is free software; see the source for copying conditions.\n"
   8.211  			        "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
   8.212  			        "PARTICULAR PURPOSE.\n");
   8.213 @@ -110,20 +189,45 @@
   8.214         case 'd': cd_dev=optarg; break;
   8.215         case 'r': cdr_dev=optarg; break;
   8.216         case 'a': cd_label=optarg; break;
   8.217 +       case 'C': crc=0; break;
   8.218 +       case 'i': virt_name=optarg; virtual=1; break;
   8.219 +       case 'w': virt_dump=1; break;
   8.220 +       case 'R': dvd=1;
   8.221 +                 DEBUG("cdbackup: DVD mode enabled\n");
   8.222 +                 break;
   8.223         case 'D': verbose=1; debug=1; 
   8.224                   DEBUG("cdbackup: DEBUG output enabled ("VERSION")\n");
   8.225                   break;
   8.226 -       case 'l': errno=0; cd_len=strtol(optarg,NULL,10);
   8.227 -                 if(errno==ERANGE || cd_len<1) serror("Option -l: length out of range (must be >=1)\n");
   8.228 -	         cd_len = (long long)cd_len * (1024*1024) / CD_FRAMESIZE; /* convert to blocks */
   8.229 -	         break;
   8.230 +       case 'l': cd_len=(long)(FlexLen(optarg)/CD_FRAMESIZE);
   8.231 +                 break;
   8.232         case 's': errno=0; cd_speed=strtol(optarg,NULL,10);
   8.233                   if(errno==ERANGE || cd_speed<1) serror("Option -s: speed out of range (must be >=1)\n");
   8.234  	         break;
   8.235         case 'p': errno=0; padsize=strtol(optarg,NULL,10);
   8.236                   if(errno==ERANGE || padsize<15) serror("Option -p: padsize out of range (must be >=15)\n");
   8.237  	         break;
   8.238 -       default:  usage(); exit(0);
   8.239 +       default:  fprintf(stderr,
   8.240 +                         "Usage: %s [options ...] [-- cdrecord-options ...]\n"
   8.241 +                         "Reads from standard input, block formats and writes to CD-R(W).\n\n"
   8.242 +                         "  -d DEVICE      DEVICE for CD queries (default /dev/burner)\n"
   8.243 +                         "  -l N           set media size, disable auto-detect\n"
   8.244 +                         "  -r DEVICE      DEVICE for CD recording (e.g. 0,4,0)\n"
   8.245 +                         "  -s N           record CD at speed N (default 4)\n"
   8.246 +                         "  -X             enable CDROM XA2 mode in cdrecord\n"
   8.247 +                         "  -a LABEL       use LABEL as CD session title\n"
   8.248 +                         "  -p N           use a padsize of N sectors for the session (default 15)\n"
   8.249 +                         "  -m             enable multi-disk mode\n"
   8.250 +                         "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
   8.251 +                         "  -C             disable checksum creation for datablocks\n"
   8.252 +                         "  -i IMAGE       use virtual image IMAGE for recording\n"
   8.253 +                         "  -w             dump virtual image to media\n"
   8.254 +                         "  -R             enables DVD mode\n"
   8.255 +                         "  -v             be verbose\n"
   8.256 +                         "  -D             enable DEBUG output\n"
   8.257 +                         "  -V             prints version & exits\n"
   8.258 +                         "  --             pass rest of commandline to cdrecord\n"
   8.259 +                         "\n", prg_name);
   8.260 +                 exit(0);
   8.261         }
   8.262      }
   8.263  
   8.264 @@ -132,173 +236,215 @@
   8.265      cdrec_opt=&argv[optind];
   8.266      }
   8.267      
   8.268 -  if(!cdr_dev) serror("You must specify a device for cdrecord with -r\n");
   8.269 -}
   8.270 -
   8.271 -/****************************************************************************/
   8.272 -
   8.273 -#define MARG(ptr,len,form,arg) { int l=(len);\
   8.274 -                               if(!(*ptr=(char *)malloc(l+1))) serror("No memory for cdrecord args\n");\
   8.275 -                               snprintf(*ptr++,l,form,arg);\
   8.276 -                             }
   8.277 -
   8.278 -void start_cdrecord() 
   8.279 -{
   8.280 -  char **args, **p;
   8.281 -  int l;
   8.282 -  
   8.283 -  if(!(p=args=calloc(cdrec_opt_count+8,sizeof(char *))))
   8.284 -    serror("No memory for cdrecord args\n");
   8.285 -
   8.286 -  *p++="cdrecord";
   8.287 -  *p++="-multi";
   8.288 -  MARG(p,16,"speed=%d",cd_speed);
   8.289 -  MARG(p,6+strlen(cdr_dev),"dev=%s",cdr_dev);
   8.290 -
   8.291 -  for(l=0 ; l<cdrec_opt_count ; l++) *p++=cdrec_opt[l];
   8.292 -
   8.293 -  MARG(p,20,"padsize=%ds",padsize);
   8.294 -  if(xamode2) *p++="-xa2"; else *p++="-data";
   8.295 -  *p++="-";
   8.296 -  *p++=0;
   8.297 -
   8.298 -  if(debug) {
   8.299 -    fprintf(stderr,"%s: cdrecord command:",prg_name);
   8.300 -    for(p=args ; *p ; p++) fprintf(stderr," %s",*p);
   8.301 -    fprintf(stderr,"\n");
   8.302 -    }
   8.303 -
   8.304 -  execvp("cdrecord",args);
   8.305 -  error("Unable to launch cdrecord");
   8.306 -}
   8.307 -
   8.308 -/****************************************************************************/
   8.309 -
   8.310 -int backup(char disk_set)
   8.311 -{
   8.312 -  pid_t childpid;
   8.313 -  int fd[2];
   8.314 -  int outpipe, bytes;
   8.315 +  if(cd_len<0) {
   8.316 +    auto_size=1;
   8.317 +    if(virtual && !virt_dump) serror("Can't auto-detect media size in virtual mode. Use option -l to set media size\n");
   8.318 +    }
   8.319 +  if(virtual && dvd && !virt_dump) {
   8.320 +     fprintf(stderr,"Option -R ignored in virtual mode\n");
   8.321 +     dvd=0;
   8.322 +     }
   8.323 +  if(dvd) {
   8.324 +    if(xamode2) fprintf(stderr,"Option -X ignored in DVD mode\n");
   8.325 +    padsize=0;
   8.326 +    }
   8.327 +  if(virt_dump && !virtual) serror("To dump an image you must supply the image name with -i\n");
   8.328 +  if(!cdr_dev && (!virtual || virt_dump)) serror("You must specify a device for cdrecord with -r\n");
   8.329 +}
   8.330 +
   8.331 +/****************************************************************************/
   8.332 +
   8.333 +void autosize(void)
   8.334 +{
   8.335 +  if(auto_size) {
   8.336 +    cd_len=atip_cdrecord();
   8.337 +    if(cd_len<0) serror("Media size detection failed. Use option -l to set media size\n");
   8.338 +    }
   8.339 +}
   8.340 +
   8.341 +/****************************************************************************/
   8.342 +
   8.343 +void dump(void)
   8.344 +{
   8.345 +  int n, cont;
   8.346 +  char buffer[CD_FRAMESIZE];
   8.347 +  long long grandTotal;
   8.348 +
   8.349 +  do {
   8.350 +    int change;
   8.351 +    do {
   8.352 +      autosize();
   8.353 +      virtual=1;
   8.354 +      Vopen(1); n=VreadToc(0);
   8.355 +      if(n<1) serror("It's not usefull to dump an empty image");
   8.356 +      secs=Vsize(); cont=VhasCont();
   8.357 +      if(cd_avail<secs*CD_FRAMESIZE) serror("Image doesn't fits to media");
   8.358 +      Vseek(-1); VprepareDump();
   8.359 +
   8.360 +      virtual=0; change=0;
   8.361 +      Vopen(0); n=VreadToc(0); VprintSpace();
   8.362 +      if(n!=0) {
   8.363 +        fprintf(stderr,"Can't dump to non-empty disk! Try another disk\n");
   8.364 +        change=1;
   8.365 +        }
   8.366 +
   8.367 +      if(change) {
   8.368 +        Vclose();
   8.369 +        diskchange(multicmd,cd_dev);
   8.370 +        }
   8.371 +      } while(change);
   8.372 +
   8.373 +    if(verbose)
   8.374 +      fprintf(stderr,"%s: Dumping image (%d blocks) to %s\n",prg_name,secs,VdevName());
   8.375 +    VnewTrack();
   8.376 +
   8.377 +    grandTotal=0;
   8.378 +    while(secs>0) {
   8.379 +      VvirtRead(buffer);
   8.380 +      Vwrite(buffer); grandTotal+=CD_FRAMESIZE;
   8.381 +      secs--;
   8.382 +      }
   8.383 +
   8.384 +    VcloseTrack(0);
   8.385 +
   8.386 +    totalSize+=grandTotal;
   8.387 +    if(verbose) {
   8.388 +      char str1[16], str2[16];
   8.389 +      fprintf(stderr,"%s: Dumping finished. %s written (%s on this disk)\n",
   8.390 +              prg_name,FlexSize(str1,totalSize),FlexSize(str2,grandTotal));
   8.391 +      }
   8.392 +
   8.393 +    if(multidisk==0) {
   8.394 +      if(cont) fprintf(stderr,"Multi-disk not enabled, ignoring continuation image(s)!\n");
   8.395 +      cont=0;
   8.396 +      }
   8.397 +    else {
   8.398 +      disknum++;
   8.399 +      diskchange(multicmd,cd_dev);
   8.400 +      }
   8.401 +    } while(cont);
   8.402 +}
   8.403 +
   8.404 +/****************************************************************************/
   8.405 +
   8.406 +int backup(void)
   8.407 +{
   8.408    long long grandTotal=0;
   8.409    struct header_block header;
   8.410 +  int flags, datasize, result=0;
   8.411  
   8.412    char buffer[CD_FRAMESIZE];
   8.413    struct data_block *db=(struct data_block *)&buffer[0];
   8.414  
   8.415 -  sprintf(buffer, "%04d%02d%02d%02d%02d", curtime.tm_year + 1900,
   8.416 -    curtime.tm_mon + 1, curtime.tm_mday, curtime.tm_hour, curtime.tm_min);
   8.417 +  flags=F_NONE;
   8.418 +  datasize=DATASIZE;
   8.419 +  if(crc) { flags|=F_CRC; datasize-=4; }
   8.420 +
   8.421 +  sprintf(buffer,"%04d%02d%02d%02d%02d",curtime.tm_year+1900,
   8.422 +    curtime.tm_mon+1,curtime.tm_mday,curtime.tm_hour,curtime.tm_min);
   8.423    
   8.424 -  strncpy(header.id_str,HDR_STRING,32); header.id_str[32] = 0;
   8.425 -  strncpy(header.vol_id,cd_label,32); header.vol_id[32] = 0;
   8.426 -  strncpy(header.t_stamp,buffer,12); header.t_stamp[12] = 0;
   8.427 -  header.disk_set = disk_set;
   8.428 +  strncpy(header.id_str,HDR_STRING,32); header.id_str[32]=0;
   8.429 +  strncpy(header.vol_id,cd_label,32); header.vol_id[32]=0;
   8.430 +  strncpy(header.t_stamp,buffer,12); header.t_stamp[12]=0;
   8.431 +  header.disk_set = disknum;
   8.432 +  header.flags = flags;
   8.433  
   8.434    if(verbose)
   8.435 -    fprintf(stderr,"%s: Recording to device %s, multidisk %s, disk %d\n",prg_name,cdr_dev,multidisk?"enabled":"disabled",disk_set); 
   8.436 -
   8.437 -#ifndef DEBUGOUT /* the "real" code */
   8.438 -  /* launch cdrecord */
   8.439 -  if(pipe(fd) == -1) error("Unable to create pipe handles");
   8.440 -  if((childpid=fork()) == -1) error("Fork failed");
   8.441 -  if(childpid == 0) {        /* child */
   8.442 -    close(fd[1]);
   8.443 -    close(0);		     /* stdin */
   8.444 -    dup2(fd[0], 0);
   8.445 -    start_cdrecord();        /* doesn't return */
   8.446 -    }
   8.447 -
   8.448 -  close(fd[0]); outpipe=fd[1];
   8.449 -  
   8.450 -  /* output the header block */
   8.451 +    fprintf(stderr,"%s: Recording to %s, multidisk %s, CRC %s, disk %d\n",
   8.452 +            prg_name,VdevName(),
   8.453 +            multidisk?"enabled":"disabled",
   8.454 +            crc?"enabled":"disabled",
   8.455 +            disknum); 
   8.456 +  secs=cd_len;
   8.457 +  VnewTrack();
   8.458 +
   8.459    memset(buffer,0,CD_FRAMESIZE);
   8.460    memcpy(buffer,&header,sizeof(struct header_block));
   8.461 -  if((bytes=write(outpipe, buffer, CD_FRAMESIZE)) != CD_FRAMESIZE) error("Error writing header block");
   8.462 -
   8.463 -  cd_avail-=bytes; grandTotal+=bytes;
   8.464 -  /* account for the padsize */
   8.465 -  cd_avail-=padsize*CD_FRAMESIZE;
   8.466 -#else
   8.467 -  /* debug code; send data to /dev/null.  Don't need the pipe. */
   8.468 -  fprintf(stderr, "DEBUG CODE: sending data to /dev/null!\n");
   8.469 -  outpipe = open("/dev/null", O_WRONLY);
   8.470 -  if (outpipe < 0) { perror("/dev/null"); exit(1); }
   8.471 -#endif
   8.472 -
   8.473 -  db->reserved = 0;
   8.474 +  Vwrite(buffer); grandTotal+=CD_FRAMESIZE;
   8.475  
   8.476    do {
   8.477 -    /* read a block */
   8.478 -    db->status = 0;		         /* this isn't the last block (for now) */
   8.479 -    bytes=full_read(0,&buffer[DBSIZE],DATASIZE);
   8.480 -    if (bytes < 0) error("Error reading input");
   8.481 -    if (bytes != DATASIZE) db->status=1; /* EOF, this is the last block */
   8.482 -    db->datasize = htons(bytes);
   8.483 -
   8.484 -    /* check for free space */
   8.485 -    if(cd_avail < (CD_FRAMESIZE*2)) {	/* less than 2 block free */
   8.486 -      if(db->status==0) db->status=2;   /* if not last block, mark disk as full */
   8.487 -      }
   8.488 -
   8.489 -    /* write a block */
   8.490 -    bytes = write(outpipe, buffer, CD_FRAMESIZE);
   8.491 -    if(bytes != CD_FRAMESIZE) error("Error writing data block");
   8.492 -
   8.493 -    grandTotal+=bytes; cd_avail-=bytes;
   8.494 +    int bytes;
   8.495 +
   8.496 +    db->flags=flags;
   8.497 +    db->status=0;		      /* this isn't the last block (for now) */
   8.498 +    bytes=full_read(0,&buffer[DBSIZE],datasize);
   8.499 +    if(bytes!=datasize) db->status=1; /* EOF, this is the last block */
   8.500 +    db->datasize=htons(bytes);
   8.501 +
   8.502 +    if(cd_avail<(CD_FRAMESIZE*2)) {   /* less than 2 block free */
   8.503 +      if(db->status==0) {             /* if not last block, mark disk as full */
   8.504 +        db->status=2;
   8.505 +        result=1;
   8.506 +        }
   8.507 +      }
   8.508 +    if(crc) {
   8.509 +      int l=crc32(buffer,bytes+DBSIZE);
   8.510 +      *((unsigned long *)(&buffer[CD_FRAMESIZE-4]))=l;
   8.511 +      }
   8.512 +    Vwrite(buffer); grandTotal+=CD_FRAMESIZE;
   8.513      } while(db->status==0);
   8.514  
   8.515 -  /* close pipe and wait for child termination */
   8.516 -  close(outpipe);
   8.517 -  while (wait(0) != childpid);
   8.518 +  if(dvd && cd_avail>=CD_FRAMESIZE) { /* pad up the track with zeros */
   8.519 +    memset(buffer,0,CD_FRAMESIZE);
   8.520 +    if(verbose) fprintf(stderr,"%s: padding up the track\n",prg_name);
   8.521 +    while(cd_avail>=CD_FRAMESIZE) Vwrite(buffer);
   8.522 +    }
   8.523 +
   8.524 +  VcloseTrack(result);
   8.525  
   8.526    totalSize+=grandTotal;
   8.527 -  if(verbose) fprintf(stderr,"%s: Recording finished. %lld kB written (%lld kB on this disk)\n",
   8.528 -                      prg_name,totalSize/1024,grandTotal/1024);
   8.529 -
   8.530 -  if(db->status==2) return 1; /* disk was full */
   8.531 +  if(verbose) {
   8.532 +    char str1[16], str2[16];
   8.533 +    fprintf(stderr,"%s: Recording finished. %s written (%s on this disk)\n",
   8.534 +            prg_name,FlexSize(str1,totalSize),FlexSize(str2,grandTotal));
   8.535 +    }
   8.536 +  return result;
   8.537 +}
   8.538 +
   8.539 +/****************************************************************************/
   8.540 +
   8.541 +int main(int argc, char *argv[]) 
   8.542 +{
   8.543 +  int result, loop;
   8.544 +  time_t curtime_t;
   8.545 +
   8.546 +  curtime_t=time(0); curtime=*localtime(&curtime_t);
   8.547 +  parse_cmdline(argc,argv);
   8.548 +
   8.549 +  if(virt_dump) {
   8.550 +    dump();
   8.551 +    }
   8.552 +  else {
   8.553 +    do {
   8.554 +      do {
   8.555 +        autosize();
   8.556 +        Vopen(0); result=VreadToc(0); VprintSpace();
   8.557 +        loop=1;
   8.558 +
   8.559 +        if(disknum>1 && result!=0) {
   8.560 +          Vclose();
   8.561 +          fprintf(stderr,"%s: Can't do multidisk continuation on non-empty disk! Try another disk\n", prg_name);
   8.562 +          diskchange(multicmd,cd_dev);
   8.563 +          }
   8.564 +        else if(cd_avail<(padsize+MIN_BLOCKS)*CD_FRAMESIZE) {
   8.565 +          Vclose();
   8.566 +          if(multidisk) {
   8.567 +            fprintf(stderr,"%s: Not enough free space on disk! Try another disk\n", prg_name);
   8.568 +            diskchange(multicmd,cd_dev);
   8.569 +            }
   8.570 +          else serror("Not enough free space on disk");
   8.571 +          }
   8.572 +        else loop=0;
   8.573 +        } while(loop);
   8.574 +
   8.575 +      result=backup();
   8.576 +      if(result==1) {
   8.577 +        if(multidisk==0) serror("Disk full, multi-disk not enabled. Aborting");
   8.578 +
   8.579 +        disknum++;
   8.580 +        if(!VisRegular()) diskchange(multicmd,cd_dev);
   8.581 +        }
   8.582 +      } while(result!=0);
   8.583 +    }
   8.584    return 0;
   8.585  }
   8.586 -
   8.587 -/****************************************************************************/
   8.588 -
   8.589 -int main(int argc, char *argv[]) 
   8.590 -{
   8.591 -  int cdr;
   8.592 -  int disknum, result, loop;
   8.593 -  time_t curtime_t;
   8.594 -
   8.595 -  disknum=1; totalSize=0;
   8.596 -  curtime_t=time(0); curtime=*localtime(&curtime_t);
   8.597 -
   8.598 -  parse_cmdline(argc,argv);
   8.599 -
   8.600 -  do {
   8.601 -    do {
   8.602 -      cdr=open_cdr(cd_dev); result=read_toc(cdr,0); close_cdr(cdr);
   8.603 -      print_space();
   8.604 -      loop=1;
   8.605 -  
   8.606 -      if(disknum>1 && result!=0) {
   8.607 -        fprintf(stderr,"%s: Can't do multidisk continuation on non-empty disk! Try another disk\n", prg_name);
   8.608 -        if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
   8.609 -        }
   8.610 -      else if(cd_avail<(padsize+MIN_BLOCKS)*CD_FRAMESIZE) {
   8.611 -        if(multidisk) {
   8.612 -          fprintf(stderr,"%s: Not enough free space on disk! Try another disk\n", prg_name);
   8.613 -          if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
   8.614 -          }
   8.615 -        else serror("Not enough free space on disk");
   8.616 -        }
   8.617 -      else loop=0;
   8.618 -      } while(loop);
   8.619 -
   8.620 -    result = backup(disknum);
   8.621 -    if(result == 1) {
   8.622 -      if(multidisk == 0) serror("Disk full, multi-disk not enabled. Aborting");
   8.623 -      
   8.624 -      disknum++;
   8.625 -      if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
   8.626 -      }
   8.627 -    } while (result != 0);
   8.628 -
   8.629 -  return 0;
   8.630 -}
     9.1 --- a/cdbackup.h	Sat Dec 29 15:23:55 2007 +0100
     9.2 +++ b/cdbackup.h	Sat Dec 29 15:25:21 2007 +0100
     9.3 @@ -1,5 +1,5 @@
     9.4  /* cdbackup.h.
     9.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
     9.6 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
     9.7  
     9.8  Redistribution and use in source and binary forms, with or without
     9.9  modification, are permitted provided that the following conditions are met: 
    9.10 @@ -34,19 +34,30 @@
    9.11  
    9.12  #define MIN_BLOCKS	2   /* min. required blocks for a session: header block, one data block */
    9.13  
    9.14 +#define F_NONE   0   /* flag values */
    9.15 +#define F_CRC    1   /* backup has CRC checksum */
    9.16 +
    9.17  struct header_block {
    9.18    char id_str[33];	/* recorder id string (32 chars) */
    9.19    char vol_id[33];	/* volume label (32 characters) */
    9.20    char t_stamp[13];	/* timestamp */
    9.21    char disk_set;	/* disk number - starts with 1 on multi-disk set */
    9.22 +  char flags;           /* flags for the backup set */
    9.23  };
    9.24  
    9.25  struct data_block {
    9.26    char status;		/* status of block (0=continue, 1=done, 2=disk full) */
    9.27 -  char reserved;	/* reserved byte to make structure 4 bytes long */
    9.28 +  char flags;		/* flags for this data block */
    9.29    short datasize;	/* # of bytes in block (max = CD_FRAMESIZE-this) */
    9.30  };
    9.31  
    9.32 +extern int padsize;
    9.33 +extern long cd_len;
    9.34 +extern int verbose;
    9.35 +extern char *prg_name;
    9.36 +
    9.37 +void start_cdrecord(void);
    9.38 +
    9.39  #define DBSIZE   sizeof(struct data_block)
    9.40  #define DATASIZE (CD_FRAMESIZE-DBSIZE)
    9.41  
    10.1 --- a/cdrestore.1	Sat Dec 29 15:23:55 2007 +0100
    10.2 +++ b/cdrestore.1	Sat Dec 29 15:25:21 2007 +0100
    10.3 @@ -1,14 +1,14 @@
    10.4 -.TH "cdrestore" "1" "0.6.3" "Stefan Hülswitt" ""
    10.5 +.TH "cdrestore" "1" "0.6.4beta" "Stefan Hülswitt" ""
    10.6  .SH "NAME"
    10.7  .LP 
    10.8 -cdrestore \- Streaming restore from CD\-R(W)
    10.9 +cdrestore \- Streaming restore from CD\-R(W)/DVD\-R(W)
   10.10  .SH "SYNOPSIS"
   10.11  .LP 
   10.12 -cdrestore [\-qvDFRTV] [\-d \fIdevice\fP] [\-l \fIsize\fP] [\-t \fItrack\fP]
   10.13 -          [\-c \fIcommand\fP]
   10.14 +cdrestore [\-qvDFRTV] [\-d \fIdevice\fP] [\-i \fIimage\fP] [\-l \fIsize\fP]
   10.15 +          [\-t \fItrack\fP] [\-c \fIcommand\fP]
   10.16  .SH "DESCRIPTION"
   10.17  .LP 
   10.18 -cdrestore is a utility to make streaming restores from CD\-R(W) disks. It's designed to work with any backup tool which is able to restore from stdin (like tar/cpio/afio).
   10.19 +cdrestore is a utility to make streaming restores from CD\-R(W)/DVD\-R(W) disks. It's designed to work with any backup tool which is able to restore from stdin (like tar/cpio/afio).
   10.20  .SH "OPTIONS"
   10.21  .LP 
   10.22  .TP 
   10.23 @@ -18,10 +18,18 @@
   10.24  (default: /dev/cdrom)
   10.25  
   10.26  .TP 
   10.27 +\fB\-i\fR \fIimage\fP
   10.28 +Enables virtual image mode. The backup stream is read from the given image file. You have to use this option, if you are restoring from a dumped image too.
   10.29 +.br 
   10.30 +(default: none)
   10.31 +
   10.32 +.TP 
   10.33  \fB\-l\fR \fIsize\fP
   10.34 -The media size in megabytes. This value is used to calculate the free space on the media.
   10.35 +Specifies the media size. This value is used to display the free space on the media only.
   10.36  .br 
   10.37 -(default: 650)
   10.38 +By default the given value is taken as megabytes. You can append a single letter to the number to select: (k)ilobytes, (m)egabytes, (g)igabytes or (s)ectors (e.g. 170k, 4488m, 350000s).
   10.39 +.br 
   10.40 +(default: 650m)
   10.41  
   10.42  .TP 
   10.43  \fB\-t\fR \fItrack\fP
   10.44 @@ -31,9 +39,9 @@
   10.45  
   10.46  .TP 
   10.47  \fB\-T\fR
   10.48 -Enables test mode. The complete restore process is done to test data integrity, but no data is output.
   10.49 +Enables test mode. The complete restore process is done to test data integrity (includes CRC checksum test, if available), but no data is output.
   10.50  .br 
   10.51 -\fINOTE:\fR This only verifies that the data is readable by cdrestore at all. This doesn't quaranties that your backup software will be able to do a real restore with the data.
   10.52 +\fINOTE:\fR This only verifies that the data is readable by cdrestore at all. This doesn't guarantee that your backup software will be able to do a real restore with the data.
   10.53  
   10.54  .TP 
   10.55  \fB\-F\fR
   10.56 @@ -69,22 +77,32 @@
   10.57  Prints out version information and exits.
   10.58  .SH "EXAMPLES"
   10.59  .LP 
   10.60 -To query the 700 MB media on /dev/sr0:
   10.61 +Query the 700 MB media on /dev/sr0:
   10.62  .IP 
   10.63  cdrestore \-d /dev/sr0 \-l 700 \-q
   10.64  
   10.65  .LP 
   10.66 -To restore a tar archive to the current directory from track 2 of a 702 MB media on /dev/scd0:
   10.67 +Restore a tar archive to the current directory from track 2 of a 702 MB media on /dev/scd0:
   10.68  .IP 
   10.69  cdrestore \-d /dev/scd0 \-l 702 \-t 2 | tar xf \-
   10.70 +
   10.71 +.LP 
   10.72 +Query the contents of a virtual image:
   10.73 +.IP 
   10.74 +cdrestore \-i /tmp/vimage \-l 4488m \-q
   10.75 +
   10.76 +.LP 
   10.77 +Check data integrity of track 3 in a virtual image after dumping it to DVD media:
   10.78 +.IP 
   10.79 +cdrestore \-i /dev/dvd \-t 3 \-T
   10.80  .SH "AUTHORS"
   10.81  .LP 
   10.82 -Stefan Hülswitt <huels@iname.com>
   10.83 +Stefan Hülswitt <s.huelswitt@gmx.de>
   10.84  .SH "SEE ALSO"
   10.85  .LP 
   10.86  \fBcdbackup\fR(1)
   10.87  .SH "LICENSE"
   10.88 -Copyright (c) 2000\-2002 Craig Condit, Stefan Hülswitt.
   10.89 +Copyright (c) 2000\-2004 Craig Condit, Stefan Hülswitt.
   10.90  
   10.91  Redistribution and use in source and binary forms, with or without
   10.92  modification, are permitted provided that the following conditions are met: 
    11.1 --- a/cdrestore.c	Sat Dec 29 15:23:55 2007 +0100
    11.2 +++ b/cdrestore.c	Sat Dec 29 15:25:21 2007 +0100
    11.3 @@ -1,5 +1,5 @@
    11.4  /* cdrestore.c
    11.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
    11.6 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
    11.7  
    11.8  Redistribution and use in source and binary forms, with or without
    11.9  modification, are permitted provided that the following conditions are met: 
   11.10 @@ -24,38 +24,40 @@
   11.11  */
   11.12  
   11.13  #define _LARGEFILE64_SOURCE
   11.14 +#define _GNU_SOURCE
   11.15  
   11.16  #include <stdio.h>
   11.17  #include <stdlib.h>
   11.18  #include <string.h>
   11.19  #include <unistd.h>
   11.20 -#include <fcntl.h>
   11.21  #include <time.h>
   11.22  #include <errno.h>
   11.23 +#ifndef sun
   11.24  #include <getopt.h>
   11.25 -#include <sys/ioctl.h>
   11.26 -#include <sys/wait.h>
   11.27 +#endif
   11.28  #include <netinet/in.h>
   11.29 -#include <linux/cdrom.h>
   11.30  
   11.31  #include "cdbackup.h"
   11.32 +#include "virtual.h"
   11.33  #include "cdrom.h"
   11.34  #include "misc.h"
   11.35  #include "debug.h"
   11.36  #include "version.h"
   11.37  
   11.38  /* defaults */
   11.39 -char * prg_name ="cdrestore";
   11.40 -int    cd_track =-1;
   11.41 -char * cd_dev   ="/dev/cdrom";
   11.42 -long   cd_len   =333000; /* blocks */
   11.43 -char * multicmd =0;
   11.44 -int    verbose  =0;
   11.45 -int    force    =0;
   11.46 -int    query    =0;
   11.47 -int    verify   =0;
   11.48 -int    ahead    =0;
   11.49 -int    debug    =0;
   11.50 +char *prg_name ="cdrestore";
   11.51 +int   cd_track =-1;
   11.52 +char *cd_dev   ="/dev/cdrom";
   11.53 +long  cd_len   =333000; /* blocks */
   11.54 +char *multicmd =0;
   11.55 +int   verbose  =0;
   11.56 +int   force    =0;
   11.57 +int   query    =0;
   11.58 +int   verify   =0;
   11.59 +int   ahead    =0;
   11.60 +int   debug    =0;
   11.61 +int   virtual  =0;
   11.62 +char *virt_name=0;
   11.63  
   11.64  int tracks;
   11.65  int disknum;
   11.66 @@ -64,35 +66,14 @@
   11.67  
   11.68  /****************************************************************************/
   11.69  
   11.70 -void usage()
   11.71 -{
   11.72 -  fprintf(stderr,
   11.73 -    "Usage: %s [OPTION]...\n"
   11.74 -    "Reads block input from CD-R(W) and writes it to standard output.\n\n"
   11.75 -    "  -d DEVICE      DEVICE for CD queries (e.g. /dev/sr0)\n"
   11.76 -    "  -q             query disk and print TOC only\n"
   11.77 -    "  -t N           restore from track N\n"
   11.78 -    "  -l N           CD-R has a size of N MB\n"
   11.79 -    "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
   11.80 -    "  -T             don't restore, test data integrity only\n"
   11.81 -    "  -F             force starting restore in the middle of a multi-disk set\n"
   11.82 -    "  -R             set the kernel read-ahead to zero during restore\n"
   11.83 -    "  -v             be verbose\n"
   11.84 -    "  -D             enable DEBUG output\n"
   11.85 -    "  -V             prints version & exits\n"
   11.86 -    "\n", prg_name);
   11.87 -}
   11.88 -
   11.89 -/****************************************************************************/
   11.90 -
   11.91  void parse_cmdline(char argc, char *argv[]) 
   11.92  {
   11.93    int i;
   11.94  
   11.95 -  while ((i=getopt(argc,argv,"d:l:c:t:qvVFTDR"))>0) {
   11.96 +  while ((i=getopt(argc,argv,"d:l:c:t:qvVFTDRi:"))>0) {
   11.97      switch (i) {
   11.98         case 'V': fprintf(stderr,"cdrestore "VERSION" (compiled "__DATE__")\n"
   11.99 -	                        "Copyright (C) 2000-2002\n"
  11.100 +	                        "Copyright (C) 2000-2004\n"
  11.101  			        "This is free software; see the source for copying conditions.\n"
  11.102  			        "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
  11.103  			        "PARTICULAR PURPOSE.\n");
  11.104 @@ -104,17 +85,32 @@
  11.105         case 'R': ahead=1; break;
  11.106         case 'T': verify=1; break;
  11.107         case 'v': verbose=1; break;
  11.108 +       case 'i': virt_name=optarg; virtual=1; break;
  11.109         case 'D': verbose=1; debug=1; 
  11.110                   DEBUG("cdrestore: DEBUG output enabled ("VERSION")\n");
  11.111                   break;
  11.112         case 't': errno=0; cd_track=strtol(optarg,NULL,10);
  11.113                   if(errno==ERANGE || cd_track<1) serror("Option -t: invalid track (must be >=1)\n");
  11.114  	         break;
  11.115 -       case 'l': errno=0; cd_len=strtol(optarg,NULL,10);
  11.116 -                 if(errno==ERANGE || cd_len<1) serror("Option -l: length out of range (must be >=1)\n");
  11.117 -	         cd_len = (long long)cd_len * (1024*1024) / CD_FRAMESIZE; /* convert to blocks */
  11.118 +       case 'l': cd_len=(long)(FlexLen(optarg)/CD_FRAMESIZE);
  11.119  	         break;
  11.120 -       default:  usage(); exit(0);
  11.121 +       default:  fprintf(stderr,
  11.122 +                         "Usage: %s [OPTION]...\n"
  11.123 +                         "Reads block input from CD-R(W) and writes it to standard output.\n\n"
  11.124 +                         "  -d DEVICE      DEVICE for CD queries (e.g. /dev/sr0)\n"
  11.125 +                         "  -q             query disk and print TOC only\n"
  11.126 +                         "  -t N           restore from track N\n"
  11.127 +                         "  -l N           set media size\n"
  11.128 +                         "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
  11.129 +                         "  -T             don't restore, test data integrity only\n"
  11.130 +                         "  -F             force starting restore in the middle of a multi-disk set\n"
  11.131 +                         "  -R             set the kernel read-ahead to zero during restore\n"
  11.132 +                         "  -i IMAGE       use virtual image IMAGE for operation\n"
  11.133 +                         "  -v             be verbose\n"
  11.134 +                         "  -D             enable DEBUG output\n"
  11.135 +                         "  -V             prints version & exits\n"
  11.136 +                         "\n", prg_name);
  11.137 +                 exit(0);
  11.138         }
  11.139      }
  11.140  
  11.141 @@ -124,21 +120,22 @@
  11.142  
  11.143  /****************************************************************************/
  11.144  
  11.145 -void print_track(int track, char *stamp, char *id, int disk, int startsec, int endsec)
  11.146 -{
  11.147 -  char timestr[32], size[32];
  11.148 -
  11.149 -  snprintf(timestr,sizeof(timestr)-1,"%02d/%02d/%04d %02d:%02d",
  11.150 +void print_track(int track, char *stamp, char *id, int disk, int startsec, int endsec, char flags)
  11.151 +{
  11.152 +  char timestr[32], size[32], flstr[12];
  11.153 +
  11.154 +  snprintf(timestr,sizeof(timestr),"%02d/%02d/%04d %02d:%02d",
  11.155      (stamp[4]-'0')*10   + (stamp[5]-'0'), 
  11.156      (stamp[6]-'0')*10   + (stamp[7]-'0'),
  11.157      (stamp[0]-'0')*1000 + (stamp[1]-'0')*100 + (stamp[2]-'0')*10 + (stamp[3]-'0'),
  11.158      (stamp[8]-'0')*10   + (stamp[9]-'0'),
  11.159      (stamp[10]-'0')*10  + (stamp[11]-'0'));
  11.160  
  11.161 -  if(startsec>=0) snprintf(size,sizeof(size)-1," %3ld MB:",(long)((long long)(endsec-startsec+1)*CD_FRAMESIZE/(1024*1024)));
  11.162 +  if(startsec>=0) snprintf(size,sizeof(size)," %s:",FlexSize(flstr,((long long)(endsec-startsec+1)*CD_FRAMESIZE)));
  11.163    else size[0]=0;
  11.164 -
  11.165 -  fprintf(stderr,"Track %02d:%s %s  Part %d: %s\n", track, size, timestr, disk, id);
  11.166 +  snprintf(flstr,sizeof(flstr),"%c",flags&F_CRC?'C':'.');
  11.167 +
  11.168 +  fprintf(stderr,"Track %02d:%s %s Part %d %s : %s\n", track, size, timestr, disk, flstr, id);
  11.169    if(startsec>=0) DEBUG("          Start sector %7d Last sector %7d\n",startsec,endsec);
  11.170  }
  11.171  
  11.172 @@ -146,39 +143,22 @@
  11.173  
  11.174  int restore(int disktrack)
  11.175  {
  11.176 -  int infile;
  11.177    int result=0, i, bytes;
  11.178 -  long long totalRead, startPos;
  11.179 +  long long totalRead=0, startPos;
  11.180    struct header_block header;
  11.181    char buffer[CD_FRAMESIZE];
  11.182    struct data_block *db=(struct data_block *)&buffer[0];
  11.183 -  unsigned long r_ahead, r_fahead;
  11.184 -
  11.185 -  if((infile=open(cd_dev, O_RDONLY)) < 0) error("Error opening device");
  11.186 -  if(ahead) {
  11.187 -    get_param(infile,&r_ahead,&r_fahead);
  11.188 -    set_param(infile,0,0);
  11.189 -    }
  11.190 -
  11.191 -  /* seek to proper CD-R(W) track */
  11.192 -  for(i=tracks;i>0;i--) if(toc[i].track_no==disktrack) break;
  11.193 -  if(!i) { fprintf(stderr, "%s: Can't find track %d\n", prg_name, disktrack); exit(1); }
  11.194 -
  11.195 -  startPos=(long long)toc[i].sec_start*CD_FRAMESIZE;
  11.196 -  if(lseek64(infile,startPos,SEEK_SET) != startPos) error("Error seeking to track");
  11.197 -
  11.198 -  /* read header block */
  11.199 -  bytes=full_read(infile,buffer,CD_FRAMESIZE);
  11.200 -  if (bytes < 0) error("Error reading header block");
  11.201 -  if (bytes != CD_FRAMESIZE) error("Unexpected EOF reading header block");
  11.202 -  totalRead = bytes;
  11.203 -
  11.204 +
  11.205 +  for(i=tracks-1; i>=0; i--) if(toc[i].track_no==disktrack) break;
  11.206 +  if(i<0) { fprintf(stderr, "%s: Can't find track %d\n", prg_name, disktrack); exit(1); }
  11.207 +  startPos=Vseek(i);
  11.208 +
  11.209 +  Vread(buffer); totalRead+=CD_FRAMESIZE;
  11.210    memcpy(&header,buffer,sizeof(header));
  11.211 -
  11.212    if(!strncmp(SHORT_HDR,header.id_str,strlen(SHORT_HDR))) {
  11.213      if(verbose) {
  11.214        fprintf(stderr,"%s: ", prg_name);
  11.215 -      print_track(disktrack, header.t_stamp, header.vol_id, header.disk_set, -1, -1);
  11.216 +      print_track(disktrack, header.t_stamp, header.vol_id, header.disk_set, -1, -1, header.flags);
  11.217        }
  11.218  
  11.219      if(disknum==1) {
  11.220 @@ -194,11 +174,11 @@
  11.221        }
  11.222      else {
  11.223        if(strcmp(header.t_stamp,headersave.t_stamp) || strcmp(header.vol_id,headersave.vol_id)) {
  11.224 -        fprintf(stderr,"%s: This disk doesn't belong to the current set!\n",prg_name);
  11.225 +        fprintf(stderr,"%s: This disk belongs to the backup set '%s', but you're restoring set '%s'!\n",prg_name,header.vol_id,headersave.vol_id);
  11.226          result=-1;
  11.227          }
  11.228        else if(header.disk_set!=disknum) {
  11.229 -        fprintf(stderr,"%s: Wrong sequence. You need disk %d now!\n",prg_name,disknum);
  11.230 +        fprintf(stderr,"%s: Wrong sequence. This is disk %d, but you need disk %d now!\n",prg_name,header.disk_set,disknum);
  11.231          result=-1;
  11.232          }
  11.233        else if(verbose) fprintf(stderr, "%s: Beginning restore (Disk %d)\n", prg_name,disknum);
  11.234 @@ -213,24 +193,28 @@
  11.235    while(!result) {
  11.236      int size;
  11.237  
  11.238 -    /* read data block */
  11.239      DEBUG("\rReading sector %7ld  ",(long)((startPos+totalRead)/CD_FRAMESIZE));
  11.240 -    bytes = full_read(infile, buffer, CD_FRAMESIZE);
  11.241 -    if (bytes < 0) error("Error reading data");
  11.242 -    if (bytes != CD_FRAMESIZE) error("Unexpected EOF reading data");
  11.243 -    totalRead += bytes;
  11.244 -
  11.245 -    /* sanity check */
  11.246 +    Vread(buffer);
  11.247 +
  11.248      size=ntohs(db->datasize);
  11.249      if(size>DATASIZE) {
  11.250        if(verbose) fprintf(stderr,"%s: Warning! Bad datasize at %lld\n",prg_name,totalRead);
  11.251        size=DATASIZE;
  11.252        }
  11.253  
  11.254 +    if(db->flags&F_CRC) {
  11.255 +      int l=crc32(buffer,size+DBSIZE);
  11.256 +      if(*((unsigned long *)(&buffer[CD_FRAMESIZE-4]))!=l) {
  11.257 +        if(verbose) fprintf(stderr,"%s: bad CRC checksum at %lld\n",prg_name,totalRead);
  11.258 +        serror("Bad checksum, block corrupted, restore failed");
  11.259 +        }
  11.260 +      }
  11.261 +
  11.262 +    totalRead+=CD_FRAMESIZE;
  11.263 +
  11.264      if(!verify) {
  11.265 -      /* write the data block */
  11.266 -      bytes=write(1,&buffer[DBSIZE], size);
  11.267 -      if(bytes!=size) error("Error writing data");
  11.268 +      bytes=write(1,&buffer[DBSIZE],size);
  11.269 +      if(bytes!=size) error("Write failed (stdout)");
  11.270        }
  11.271  
  11.272      if(db->status == 1) break; 	  /* end of backup*/
  11.273 @@ -240,14 +224,12 @@
  11.274  
  11.275    /* print status */
  11.276    totalSize+=totalRead;
  11.277 -  if(result>=0 && verbose)
  11.278 -    fprintf(stderr, "%s: Restore complete. %lld kB read (%lld kB from this disk)\n",prg_name, totalSize/1024, totalRead/1024);
  11.279 -
  11.280 -  if(ahead) {
  11.281 -    set_param(infile,r_ahead,r_fahead);
  11.282 -    get_param(infile,&r_ahead,&r_fahead);
  11.283 -    }
  11.284 -  close(infile);
  11.285 +  if(result>=0 && verbose) {
  11.286 +    char str1[16], str2[16];
  11.287 +    fprintf(stderr, "%s: Restore complete. %s read (%s from this disk)\n",
  11.288 +            prg_name,FlexSize(str1,totalSize),FlexSize(str2,totalRead));
  11.289 +    }
  11.290 +
  11.291    return(result);
  11.292  }
  11.293  
  11.294 @@ -258,14 +240,16 @@
  11.295    int i;
  11.296  
  11.297    fprintf(stderr,"Tracks: %d\n",tracks);
  11.298 -  print_space();
  11.299 +  VprintSpace();
  11.300    fprintf(stderr,"\n");
  11.301    
  11.302 -  for (i = 1; i <= tracks; i++) {
  11.303 -    if(toc[i].is_data==0) fprintf(stderr,"Track %02d: Non-data\n", toc[i].track_no);
  11.304 -    else if (toc[i].is_cdbackup == 1)
  11.305 -      print_track(i, toc[i].t_stamp, toc[i].vol_id, toc[i].disk_set, toc[i].sec_start, toc[i].sec_end);
  11.306 -    else fprintf(stderr,"Track %02d: Data\n", toc[i].track_no);
  11.307 +  for(i=0; i<tracks; i++) {
  11.308 +    if(!toc[i].is_data)
  11.309 +      fprintf(stderr,"Track %02d: Non-data\n",toc[i].track_no);
  11.310 +    else if(toc[i].is_cdbackup)
  11.311 +      print_track(toc[i].track_no,toc[i].t_stamp,toc[i].vol_id,toc[i].disk_set,toc[i].sec_start,toc[i].sec_end,toc[i].flags);
  11.312 +    else
  11.313 +      fprintf(stderr,"Track %02d: Data\n", toc[i].track_no);
  11.314      }
  11.315  }
  11.316  
  11.317 @@ -273,11 +257,10 @@
  11.318  
  11.319  int main(int argc, char *argv[])
  11.320  {
  11.321 -  int cdr;
  11.322 -
  11.323    parse_cmdline(argc, argv);
  11.324  
  11.325 -  cdr=open_cdr(cd_dev); tracks=read_toc(cdr,(query || debug)); close_cdr(cdr);
  11.326 +  disknum=1; totalSize=0;
  11.327 +  Vopen(1); tracks=VreadToc(query || debug);
  11.328    if(query || debug) {
  11.329      verbose=1;
  11.330      print_toc();
  11.331 @@ -285,15 +268,22 @@
  11.332    if(!query) {
  11.333      int result;
  11.334      if(verify) fprintf(stderr,"%s: Verify mode enabled, no data output!\n",prg_name);
  11.335 -    totalSize=0; disknum=1;
  11.336 +    if(ahead) { VgetAhead(); VsetAhead(0); }
  11.337      do {
  11.338        result=restore(cd_track);
  11.339        if(result) {
  11.340          if(result>0) { disknum++; cd_track=1; }
  11.341 -        fprintf(stderr,"%s: Next disk needed: disk %d from %s\n",prg_name,disknum,headersave.vol_id);
  11.342 -        if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
  11.343 +        Vclose();
  11.344 +        if(!VisRegular()) {
  11.345 +          fprintf(stderr,"%s: Next disk needed: disk %d from %s\n",prg_name,disknum,headersave.vol_id);
  11.346 +          diskchange(multicmd,cd_dev);
  11.347 +          }
  11.348 +        else if(result<0) break;
  11.349 +        Vopen(1); tracks=VreadToc(0);
  11.350  	}
  11.351        } while(result);
  11.352 -    }
  11.353 +    if(ahead) VsetAhead(1);
  11.354 +    }
  11.355 +  Vclose();
  11.356    return 0;
  11.357  }
    12.1 --- a/cdrom.c	Sat Dec 29 15:23:55 2007 +0100
    12.2 +++ b/cdrom.c	Sat Dec 29 15:25:21 2007 +0100
    12.3 @@ -1,5 +1,5 @@
    12.4  /* cdrom.c
    12.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
    12.6 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
    12.7  
    12.8  Redistribution and use in source and binary forms, with or without
    12.9  modification, are permitted provided that the following conditions are met: 
   12.10 @@ -27,47 +27,28 @@
   12.11  
   12.12  #include <stdlib.h>
   12.13  #include <stdio.h>
   12.14 -#include <unistd.h>
   12.15 -#include <fcntl.h>
   12.16 -#include <string.h>
   12.17 -#include <linux/cdrom.h>
   12.18 -#include <linux/fs.h>
   12.19  #include <sys/ioctl.h>
   12.20  
   12.21 +#ifdef linux
   12.22 +#include <linux/fs.h>
   12.23 +#endif
   12.24 +
   12.25  #include "cdrom.h"
   12.26 -#include "cdbackup.h"
   12.27  #include "misc.h"
   12.28  #include "debug.h"
   12.29  
   12.30  /* size of leadin/out depending of how many tracks are on cd */
   12.31 -#define MIN_FREE_1	(11400*CD_FRAMESIZE) /* 1th track */
   12.32 -#define MIN_FREE_2	(6900*CD_FRAMESIZE)  /* 2nd and more tracks */
   12.33 +#define LEADOUT_1	11400 /* 1th track */
   12.34 +#define LEADOUT_2	6900  /* 2nd and more tracks */
   12.35  /* number of (unreadable) runout sectos */
   12.36  #define RUNOUT          2
   12.37  
   12.38 -struct toc_entry *toc=0;
   12.39 -long long cd_used, cd_avail;
   12.40 -
   12.41 -extern long cd_len;
   12.42 +extern int fd;
   12.43  extern int verbose;
   12.44  extern char *prg_name;
   12.45  
   12.46  /****************************************************************************/
   12.47  
   12.48 -int open_cdr(char *device) 
   12.49 -{
   12.50 -  return open(device, O_RDONLY | O_NONBLOCK);
   12.51 -}
   12.52 -
   12.53 -/****************************************************************************/
   12.54 -
   12.55 -void close_cdr(int cd_fd)
   12.56 -{
   12.57 -  close(cd_fd);
   12.58 -}
   12.59 -
   12.60 -/****************************************************************************/
   12.61 -
   12.62  void get_param(int fd, unsigned long *ahead, unsigned long *fahead)
   12.63  {
   12.64  #if defined(BLKRAGET) && defined(BLKFRAGET)
   12.65 @@ -76,7 +57,7 @@
   12.66    ioctl(fd,BLKFRAGET,fahead);
   12.67    DEBUG("get_param: readahead=%ld freadahead=%ld\n",*ahead,*fahead);
   12.68  #else
   12.69 -  fprintf("Can't get readahead parameter. Ioctl's not available\n");
   12.70 +  fprintf(stderr,"Can't get readahead parameter. Ioctl's not available\n");
   12.71  #endif
   12.72  }
   12.73  
   12.74 @@ -85,125 +66,52 @@
   12.75  void set_param(int fd, unsigned long ahead, unsigned long fahead)
   12.76  {
   12.77  #if defined(BLKRAGET) && defined(BLKFRAGET)
   12.78 -  ioctl(fd, BLKRASET, ahead);
   12.79 -  ioctl(fd, BLKFRASET, fahead);
   12.80 +  ioctl(fd,BLKRASET,ahead);
   12.81 +  ioctl(fd,BLKFRASET,fahead);
   12.82    DEBUG("set_param: readahead=%ld freadahead=%ld\n",ahead,fahead);
   12.83  #else
   12.84 -  fprintf("Can't set readahead parameter. Ioctl's not available\n");
   12.85 +  fprintf(stderr,"Can't set readahead parameter. Ioctl's not available\n");
   12.86  #endif
   12.87  }
   12.88  
   12.89  /****************************************************************************/
   12.90  
   12.91 -int full_read(int fd, void *buf, int count)
   12.92 +int getCdHeader(struct cd_header *cd)
   12.93  {
   12.94 -  int total=0;
   12.95 -
   12.96 -  while(count>0) {
   12.97 -    int bytes;
   12.98 -    bytes=read(fd,buf,count); if(bytes<0) return bytes;
   12.99 -    if(bytes==0) break;
  12.100 -    count-=bytes; total+=bytes; buf+=bytes;
  12.101 -    }
  12.102 -  return total;
  12.103 -}
  12.104 -
  12.105 -/****************************************************************************/
  12.106 -
  12.107 -void free_toc()
  12.108 -{
  12.109 -  if(toc) { free(toc); toc=0; }
  12.110 -}
  12.111 -
  12.112 -/****************************************************************************/
  12.113 -
  12.114 -int read_toc(int cd_fd, int trackinfos)
  12.115 -{
  12.116 -  int i;
  12.117    struct cdrom_tochdr cd_header;
  12.118    struct cdrom_tocentry cd_entry;
  12.119 -  int tracks,start_track;
  12.120 - 
  12.121 -  /* read table of contents header */
  12.122 -  if(ioctl(cd_fd,CDROMREADTOCHDR,&cd_header)) {
  12.123 -    if(verbose) fprintf(stderr,"%s: Unable to read CD header, assuming empty CD-R\n", prg_name);
  12.124 -    cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE; return 0;
  12.125 +  int tracks;
  12.126 +
  12.127 +  if(ioctl(fd,CDROMREADTOCHDR,&cd_header)<0) {
  12.128 +    if(verbose) fprintf(stderr,"%s: Unable to read CD header, assuming empty CD-R\n",prg_name);
  12.129 +    cd->start_track=1; cd->end_track=0;
  12.130 +    cd->used=0;
  12.131 +    return 0;
  12.132      }
  12.133  
  12.134 -  /* get start and end tracks */
  12.135 -  start_track = cd_header.cdth_trk0;
  12.136 -  tracks = cd_header.cdth_trk1-start_track+1;
  12.137 -  DEBUG("read_toc: starttrack=%d tracks=%d\n",start_track,tracks);
  12.138 +  cd->start_track=cd_header.cdth_trk0;
  12.139 +  cd->end_track  =cd_header.cdth_trk1;
  12.140 +  tracks=cd->end_track-cd->start_track+1;
  12.141  
  12.142 -  free_toc();
  12.143 -  if(!(toc=calloc(tracks+1,sizeof(struct toc_entry)))) serror("No memory for TOC");
  12.144 +  cd_entry.cdte_format=CDROM_LBA;
  12.145 +  cd_entry.cdte_track=CDROM_LEADOUT;
  12.146 +  if(ioctl(fd,CDROMREADTOCENTRY,&cd_entry)<0) error("Ioctl failed (lead-out)");
  12.147  
  12.148 -  /* set some parameters */
  12.149 -  cd_entry.cdte_format=CDROM_LBA;
  12.150 -
  12.151 -  /* read lead-out */
  12.152 -  cd_entry.cdte_track=CDROM_LEADOUT;
  12.153 -  if(ioctl(cd_fd,CDROMREADTOCENTRY,&cd_entry)) error("Error reading lead-out");
  12.154 -
  12.155 -  toc[0].track_no=CDROM_LEADOUT;  /* not a real track */
  12.156 -  toc[0].sec_start=cd_entry.cdte_addr.lba;
  12.157 -
  12.158 -  cd_used  =(long long)toc[0].sec_start*CD_FRAMESIZE;
  12.159 -  cd_avail =(long long)cd_len*CD_FRAMESIZE-cd_used;
  12.160 -  cd_avail-=(tracks>1?MIN_FREE_2:MIN_FREE_1);
  12.161 -  DEBUG("read_toc: cd_used=%lld (%lld secs) cd_avail=%lld (%lld secs)\n",cd_used,cd_used/CD_FRAMESIZE,cd_avail,cd_avail/CD_FRAMESIZE);
  12.162 -
  12.163 -  if(cd_avail<0) cd_avail=0; /* can be <0 due to assumed additional lead-in/out */
  12.164 -
  12.165 -  /* read rest of tracks */
  12.166 -  for(i=1; i<=tracks; i++) {
  12.167 -    cd_entry.cdte_track=start_track+i-1;
  12.168 -    if(ioctl(cd_fd,CDROMREADTOCENTRY,&cd_entry)) error("Error reading TOC");  
  12.169 -
  12.170 -    toc[i].track_no=start_track+i-1;
  12.171 -    toc[i].sec_start=cd_entry.cdte_addr.lba;
  12.172 -    if(cd_entry.cdte_ctrl&CDROM_DATA_TRACK) toc[i].is_data=1;
  12.173 -    }    
  12.174 -
  12.175 -  /* calculate end sectors */
  12.176 -  toc[tracks].sec_end = toc[  0].sec_start - 1 - RUNOUT;
  12.177 -  for(i=1; i<tracks; i++)
  12.178 -    toc[i].sec_end = toc[i+1].sec_start - 1 - RUNOUT - (i>1?(MIN_FREE_2/CD_FRAMESIZE):(MIN_FREE_1/CD_FRAMESIZE));
  12.179 -
  12.180 - if(trackinfos)
  12.181 -  /* now loop through tracks and read header info */
  12.182 -  for(i=1; i<=tracks; i++) {
  12.183 -    char inbuffer[CD_FRAMESIZE];
  12.184 -    struct header_block *track_header=(struct header_block *)&inbuffer[0];
  12.185 -
  12.186 -    if (toc[i].is_data == 1) {
  12.187 -      if(lseek64(cd_fd,(long long)toc[i].sec_start*CD_FRAMESIZE,SEEK_SET)<0) error("Seek failed");
  12.188 -
  12.189 -      if(full_read(cd_fd,inbuffer,CD_FRAMESIZE)==CD_FRAMESIZE) {
  12.190 -        if(!strncmp(SHORT_HDR,track_header->id_str,strlen(SHORT_HDR))) {
  12.191 -          toc[i].is_cdbackup=1;
  12.192 -          strncpy(toc[i].id_str,track_header->id_str,32); toc[i].id_str[32]=0;
  12.193 -          strncpy(toc[i].vol_id, track_header->vol_id,32); toc[i].vol_id[32]=0;
  12.194 -          strncpy(toc[i].t_stamp, track_header->t_stamp,12); toc[i].t_stamp[12]=0;
  12.195 -          toc[i].disk_set = track_header->disk_set;
  12.196 -          }
  12.197 -        }      
  12.198 -      }
  12.199 -    }
  12.200 -  
  12.201 +  cd->used=cd_entry.cdte_addr.lba + (tracks==1 ? LEADOUT_1:LEADOUT_2);
  12.202    return tracks;
  12.203  }
  12.204  
  12.205  /****************************************************************************/
  12.206  
  12.207 -void print_space() 
  12.208 +void getCdTrack(int num, struct cd_track *cd)
  12.209  {
  12.210 -  if(verbose)
  12.211 -    fprintf(stderr,
  12.212 -      "Disk size:  %7lld kB (%7ld blocks)\n"
  12.213 -      "Space used: %7lld kB (%7lld blocks)\n"
  12.214 -      "Space avail:%7lld kB (%7lld blocks)\n",
  12.215 -      (long long)cd_len*CD_FRAMESIZE/1024,cd_len,
  12.216 -      cd_used/1024, cd_used/CD_FRAMESIZE,
  12.217 -      cd_avail/1024, cd_avail/CD_FRAMESIZE);
  12.218 +  struct cdrom_tocentry cd_entry;
  12.219 +
  12.220 +  cd_entry.cdte_format=CDROM_LBA;
  12.221 +  cd_entry.cdte_track=num;
  12.222 +  if(ioctl(fd,CDROMREADTOCENTRY,&cd_entry)<0) error("Ioctl failed (toc entry)");  
  12.223 +
  12.224 +  cd->start_sec   =cd_entry.cdte_addr.lba;
  12.225 +  cd->leadout_size=RUNOUT+(num==cd->start_track ? LEADOUT_1:LEADOUT_2);
  12.226 +  cd->is_data     =(cd_entry.cdte_ctrl&CDROM_DATA_TRACK) ? 1:0;
  12.227  }
    13.1 --- a/cdrom.h	Sat Dec 29 15:23:55 2007 +0100
    13.2 +++ b/cdrom.h	Sat Dec 29 15:25:21 2007 +0100
    13.3 @@ -1,5 +1,5 @@
    13.4  /* cdrom.h
    13.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
    13.6 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
    13.7  
    13.8  Redistribution and use in source and binary forms, with or without
    13.9  modification, are permitted provided that the following conditions are met: 
   13.10 @@ -26,28 +26,33 @@
   13.11  #ifndef _CDBACKUP_CDROM_H
   13.12  #define _CDBACKUP_CDROM_H
   13.13  
   13.14 -extern struct toc_entry *toc;
   13.15 -extern long long cd_used, cd_avail;
   13.16 +#ifdef linux
   13.17 +#include <linux/cdrom.h>
   13.18 +#endif
   13.19  
   13.20 -struct toc_entry {
   13.21 -  u_char track_no;	/* track number */
   13.22 -  char is_data;		/* 1 = data track */
   13.23 -  char is_cdbackup;	/* was it created by CD-Backup? */
   13.24 -  int sec_start;	/* start sector */
   13.25 -  int sec_end;		/* last sector */
   13.26 -  char id_str[33];	/* recorder id string (32 chars) */
   13.27 -  char vol_id[33];	/* volume label (32 characters) */
   13.28 -  char t_stamp[13];	/* time stamp: yyyymmddhhmm */
   13.29 -  char disk_set;	/* disk number */
   13.30 -};
   13.31 +#ifdef sun
   13.32 +#include <sys/cdio.h>
   13.33 +#endif
   13.34  
   13.35 -int open_cdr(char *device);
   13.36 -void close_cdr(int cd_fd);
   13.37 +#ifndef CD_FRAMESIZE
   13.38 +#define CD_FRAMESIZE 2048
   13.39 +#endif
   13.40 +
   13.41 +struct cd_header {
   13.42 +  int start_track, end_track;
   13.43 +  int used;
   13.44 +  };
   13.45 +
   13.46 +struct cd_track {
   13.47 +  int start_sec;
   13.48 +  int leadout_size;
   13.49 +  int is_data;
   13.50 +  int start_track;
   13.51 +  };
   13.52 +
   13.53  void get_param(int fd, unsigned long *ahead, unsigned long *fahead);
   13.54  void set_param(int fd, unsigned long ahead, unsigned long fahead);
   13.55 -int full_read(int fd, void *buf, int count);
   13.56 -int read_toc(int cd_fd, int trackinfos);
   13.57 -void free_toc();
   13.58 -void print_space();
   13.59 +int getCdHeader(struct cd_header *cd);
   13.60 +void getCdTrack(int num, struct cd_track *cd);
   13.61  
   13.62  #endif
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/examples/cdload	Sat Dec 29 15:25:21 2007 +0100
    14.3 @@ -0,0 +1,55 @@
    14.4 +#!/bin/bash 
    14.5 +
    14.6 +# defaults
    14.7 +
    14.8 +DEVICE="/dev/sr1"
    14.9 +TRACK="1"
   14.10 +LIST=0
   14.11 +
   14.12 +# process command-line options
   14.13 +
   14.14 +while getopts ":d:t:l" optn; do
   14.15 +    case $optn in
   14.16 +    d ) DEVICE=$OPTARG
   14.17 +        ;;
   14.18 +    t ) TRACK=$OPTARG
   14.19 +        ;;
   14.20 +    l ) LIST=1
   14.21 +        ;;
   14.22 +    \? ) echo "Usage: `basename $0` [-d device] [-t track] [-l] [filespec]"
   14.23 +         echo ""
   14.24 +	 echo "Defaults: -d /dev/sr1"
   14.25 +	 echo "          -t 1"
   14.26 +         echo ""
   14.27 +	 echo "if -l is given, archive is listed not restored."
   14.28 +        exit 1  
   14.29 +        ;;
   14.30 +    esac
   14.31 +done
   14.32 +shift $(($OPTIND - 1))
   14.33 +
   14.34 +#   process input-files
   14.35 +
   14.36 +TMP="/tmp/cdload.$$"
   14.37 +rm -f $TMP
   14.38 +
   14.39 +SPECOPT=""
   14.40 +for filespec in "$@"; do
   14.41 +    echo "$filespec" >>$TMP
   14.42 +    SPECOPT="-w $TMP"
   14.43 +    done
   14.44 +#echo "-$SPECOPT-"
   14.45 +#cat $TMP
   14.46 +#echo "--"
   14.47 +
   14.48 +if [ $LIST -eq 1 ]; then
   14.49 +  aopt="-t"	# list archive
   14.50 +  echo "`basename $0`: listing archive"
   14.51 +else
   14.52 +  aopt="-i"	# restore archive
   14.53 +  echo "`basename $0`: restoring archive"
   14.54 +fi
   14.55 +
   14.56 +cdrestore -d $DEVICE -t $TRACK | afio $aopt -vnz $SPECOPT -
   14.57 +
   14.58 +rm -f $TMP
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/examples/cdsave	Sat Dec 29 15:25:21 2007 +0100
    15.3 @@ -0,0 +1,65 @@
    15.4 +#!/bin/bash 
    15.5 +
    15.6 +# defaults
    15.7 +
    15.8 +LABEL="Afio-Backup"
    15.9 +SCSIDEV="0,4,0"
   15.10 +DEVICE="/dev/sr1"
   15.11 +SPEED="8"
   15.12 +LEN="702"
   15.13 +MULTI=""
   15.14 +
   15.15 +# process command-line options
   15.16 +
   15.17 +while getopts ":a:d:r:s:l:m" optn; do
   15.18 +    case $optn in
   15.19 +    a ) LABEL=$OPTARG
   15.20 +        ;;
   15.21 +    d ) DEVICE=$OPTARG
   15.22 +        ;;
   15.23 +    r ) SCSIDEV=$OPTARG
   15.24 +        ;;
   15.25 +    s ) SPEED=$OPTARG
   15.26 +        ;;
   15.27 +    l ) LEN=$OPTARG
   15.28 +        ;;
   15.29 +    m ) MULTI="-m"
   15.30 +        ;;
   15.31 +    \? ) echo "Usage: `basename $0` [-a label] [-l cd_len] [-m] [-d device] [-r scsidev] [-s speed] file1 file2 ..."
   15.32 +         echo ""
   15.33 +	 echo "Defaults: -a Afio-Backup"
   15.34 +	 echo "          -d /dev/sr1"
   15.35 +	 echo "          -r 0,4,0"
   15.36 +	 echo "          -s 8"
   15.37 +	 echo "          -l 702"
   15.38 +        exit 1  
   15.39 +        ;;
   15.40 +    esac
   15.41 +done
   15.42 +shift $(($OPTIND - 1))
   15.43 +
   15.44 +#   process input-files
   15.45 +
   15.46 +TMP="/tmp/cdsave.$$"
   15.47 +rm -f $TMP
   15.48 +
   15.49 +for filename in "$@"; do
   15.50 +    case $filename in
   15.51 +    *[*?]*  )   # means shell couldn´t extend *.wav, etc.
   15.52 +        echo "warning: no $filename file(s) found"
   15.53 +        ;;
   15.54 +    *   )
   15.55 +        echo >>$TMP "$filename"
   15.56 +        ;;
   15.57 +    esac
   15.58 +done
   15.59 +
   15.60 +if [ -s $TMP ] ; then
   15.61 +    cat $TMP | \
   15.62 +    afio -o -uz - | \
   15.63 +    cdbackup -v -a "$LABEL" $MULTI -l "$LEN" -d "$DEVICE" -r "$SCSIDEV" -s "$SPEED" -- -v fs=8m
   15.64 +else
   15.65 +    echo "Error: no files specified"
   15.66 +fi
   15.67 +rm -f $TMP
   15.68 +
    16.1 --- a/misc.c	Sat Dec 29 15:23:55 2007 +0100
    16.2 +++ b/misc.c	Sat Dec 29 15:25:21 2007 +0100
    16.3 @@ -1,5 +1,5 @@
    16.4  /* misc.c
    16.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
    16.6 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
    16.7  
    16.8  Redistribution and use in source and binary forms, with or without
    16.9  modification, are permitted provided that the following conditions are met: 
   16.10 @@ -30,6 +30,9 @@
   16.11  #include <sys/wait.h>
   16.12  #include <errno.h>
   16.13  
   16.14 +#include "cdrom.h"
   16.15 +#include "debug.h"
   16.16 +
   16.17  extern char *prg_name;
   16.18  
   16.19  /****************************************************************************/
   16.20 @@ -50,34 +53,156 @@
   16.21  
   16.22  /****************************************************************************/
   16.23  
   16.24 -int start_diskchange(char *multicmd, char *cd_dev)
   16.25 -{
   16.26 -int pid, status=0;
   16.27 -char buffer[12];
   16.28 -
   16.29 -if(multicmd) { /* we have an external script */
   16.30 -  if((pid=fork())<0) error("Fork failed in diskchange");
   16.31 -  if(pid==0) { /* child */
   16.32 -    char *argv[3];
   16.33 -
   16.34 -    dup2(2,0); dup2(2,1); /* duplicate stderr as stdin/stdout */
   16.35 -    argv[0] = multicmd;
   16.36 -    argv[1] = cd_dev;
   16.37 -    argv[2] = 0;
   16.38 -    execvp(multicmd, argv);
   16.39 -    error("Starting diskchange command failed");
   16.40 -    }
   16.41 -
   16.42 -  while(1) {
   16.43 -    if(waitpid(pid,&status,0)==-1) { if (errno != EINTR) { status=-1; break; } }
   16.44 -    else break;
   16.45 -    }
   16.46 -  }
   16.47 -else { /* use internal diskchange */
   16.48 -  fprintf(stderr,"\n\nPlease insert next disk and press RETURN\n\n\n");
   16.49 -  do {
   16.50 -    pid=read(2,buffer,sizeof(buffer));
   16.51 -    } while(pid==sizeof(buffer) && buffer[sizeof(buffer)-1]!='\n');
   16.52 -  }
   16.53 -return status;
   16.54 -}
   16.55 +long long FlexLen(char *optarg)
   16.56 +{
   16.57 +  char *end;
   16.58 +  long long len;
   16.59 +  errno=0; len=strtoll(optarg,&end,10);
   16.60 +  if(errno==ERANGE || len<1) serror("Option -l: length out of range (must be >=1)\n");
   16.61 +  switch(*end) {
   16.62 +    case 'K': /* kilo-bytes*/
   16.63 +    case 'k':
   16.64 +      len*=1024; break;
   16.65 +    case 0:   /* mega-bytes */
   16.66 +    case 'M':
   16.67 +    case 'm':
   16.68 +      len*=(1024*1024); break;
   16.69 +    case 'G':
   16.70 +    case 'g':
   16.71 +      len*=(1024*1024*1024LL); break;
   16.72 +    case 's':
   16.73 +    case 'S':
   16.74 +      len*=CD_FRAMESIZE; break;
   16.75 +    default:
   16.76 +      serror("Unknown extention for media size");
   16.77 +    }
   16.78 +  DEBUG("media size len=%lld blocks=%lld\n",len,len/CD_FRAMESIZE);
   16.79 +  return len;
   16.80 +}
   16.81 +
   16.82 +/****************************************************************************/
   16.83 +
   16.84 +char *FlexSize(char *buff, long long val)
   16.85 +{
   16.86 +  char *unit=" ";
   16.87 +       if(val > 1024*1024*1024*16LL) { val/=1024*1024*1024LL; unit="G"; }
   16.88 +  else if(val > 1024*1024*16LL)      { val/=1024*1024LL; unit="M"; }
   16.89 +  else if(val > 1024*16LL)           { val/=1024LL; unit="k"; }
   16.90 +  sprintf(buff,"%5lld %sB",val,unit);
   16.91 +  return buff;
   16.92 +}
   16.93 +
   16.94 +/****************************************************************************/
   16.95 +
   16.96 +int full_read(int fd, void *buf, int count)
   16.97 +{
   16.98 +  int total=0;
   16.99 +  while(count>0) {
  16.100 +    int bytes;
  16.101 +    bytes=read(fd,buf,count);
  16.102 +    if(bytes==0) break;
  16.103 +    else if(bytes<0) {
  16.104 +      if(errno!=EAGAIN) error("Read failed");
  16.105 +      usleep(200*1000);
  16.106 +      }
  16.107 +    else {
  16.108 +      count-=bytes; buf+=bytes; total+=bytes;
  16.109 +      }
  16.110 +    }
  16.111 +  return total;
  16.112 +}
  16.113 +
  16.114 +/****************************************************************************/
  16.115 +
  16.116 +void diskchange(char *multicmd, char *cd_dev)
  16.117 +{
  16.118 +  int pid, status=0;
  16.119 +  char buffer[12];
  16.120 +
  16.121 +  if(multicmd) { /* we have an external script */
  16.122 +    DEBUG("external diskchange started '%s'\n",multicmd);
  16.123 +    if((pid=fork())<0) error("Fork failed (diskchange)");
  16.124 +    if(pid==0) { /* child */
  16.125 +      char *argv[3];
  16.126 +
  16.127 +      dup2(2,0); dup2(2,1); /* duplicate stderr as stdin/stdout */
  16.128 +      argv[0] = multicmd;
  16.129 +      argv[1] = cd_dev;
  16.130 +      argv[2] = 0;
  16.131 +      execvp(multicmd, argv);
  16.132 +      error("Exec failed (diskchange)");
  16.133 +      }
  16.134 +
  16.135 +    while(1) {
  16.136 +      if(waitpid(pid,&status,0)==-1) { if (errno!=EINTR) { status=-1; break; } }
  16.137 +      else break;
  16.138 +      }
  16.139 +    }
  16.140 +  else { /* use internal diskchange */
  16.141 +    DEBUG("internal diskchange started\n");
  16.142 +    fprintf(stderr,"\n\nPlease insert next disk and press RETURN\n\n\n");
  16.143 +    do {
  16.144 +      pid=read(2,buffer,sizeof(buffer));
  16.145 +      if(pid<0 && errno!=EAGAIN) error("Read failed (diskchange)");
  16.146 +      } while(pid<=0 || (pid==sizeof(buffer) && buffer[sizeof(buffer)-1]!='\n'));
  16.147 +    }
  16.148 +  if(status) serror("Diskchange command failed");
  16.149 +  DEBUG("diskchange completed\n");
  16.150 +}
  16.151 +
  16.152 +/****************************************************************************/
  16.153 +
  16.154 +static unsigned long crc_table[256] = {
  16.155 +  0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
  16.156 +  0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
  16.157 +  0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
  16.158 +  0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
  16.159 +  0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
  16.160 +  0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
  16.161 +  0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
  16.162 +  0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
  16.163 +  0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
  16.164 +  0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
  16.165 +  0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
  16.166 +  0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
  16.167 +  0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
  16.168 +  0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
  16.169 +  0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
  16.170 +  0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
  16.171 +  0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
  16.172 +  0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
  16.173 +  0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
  16.174 +  0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
  16.175 +  0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
  16.176 +  0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
  16.177 +  0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
  16.178 +  0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
  16.179 +  0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
  16.180 +  0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
  16.181 +  0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
  16.182 +  0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
  16.183 +  0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
  16.184 +  0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
  16.185 +  0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
  16.186 +  0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
  16.187 +  0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
  16.188 +  0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
  16.189 +  0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
  16.190 +  0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
  16.191 +  0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
  16.192 +  0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
  16.193 +  0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
  16.194 +  0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
  16.195 +  0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
  16.196 +  0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
  16.197 +  0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
  16.198 +  };
  16.199 +
  16.200 +unsigned long crc32(char *data, int len)
  16.201 +{
  16.202 +  unsigned long crc=0xffffffff;
  16.203 +  int i;
  16.204 +  for(i=0 ; i<len ; i++)
  16.205 +    crc=(crc<<8) ^ crc_table[((crc>>24)^*data++)&0xff];
  16.206 +  return crc;
  16.207 +}
    17.1 --- a/misc.h	Sat Dec 29 15:23:55 2007 +0100
    17.2 +++ b/misc.h	Sat Dec 29 15:25:21 2007 +0100
    17.3 @@ -1,5 +1,5 @@
    17.4  /* misc.h
    17.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
    17.6 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
    17.7  
    17.8  Redistribution and use in source and binary forms, with or without
    17.9  modification, are permitted provided that the following conditions are met: 
   17.10 @@ -26,8 +26,12 @@
   17.11  #ifndef _CDBACKUP_MISC_H
   17.12  #define _CDBACKUP_MISC_H
   17.13  
   17.14 -int start_diskchange(char *multicmd, char *cd_dev);
   17.15 +unsigned long crc32(char *data, int len);
   17.16 +void diskchange(char *multicmd, char *cd_dev);
   17.17 +int full_read(int fd, void *buf, int count);
   17.18  void error(char *text);
   17.19  void serror(char *text);
   17.20 +char *FlexSize(char *buff, long long val);
   17.21 +long long FlexLen(char *optarg);
   17.22  
   17.23  #endif
    18.1 --- a/version.h	Sat Dec 29 15:23:55 2007 +0100
    18.2 +++ b/version.h	Sat Dec 29 15:25:21 2007 +0100
    18.3 @@ -2,7 +2,7 @@
    18.4  #define _CDBACKUP_VERSION_H
    18.5  
    18.6  #ifndef VERSION
    18.7 -#define VERSION "0.6.3"
    18.8 +#define VERSION "0.6.4beta"
    18.9  #endif
   18.10  
   18.11  #endif
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/virtual-backup.c	Sat Dec 29 15:25:21 2007 +0100
    19.3 @@ -0,0 +1,154 @@
    19.4 +/* virtual-backup.c
    19.5 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
    19.6 +
    19.7 +Redistribution and use in source and binary forms, with or without
    19.8 +modification, are permitted provided that the following conditions are met: 
    19.9 +
   19.10 +1. Redistributions of source code must retain the above copyright notice,
   19.11 +   this list of conditions and the following disclaimer. 
   19.12 +2. Redistributions in binary form must reproduce the above copyright notice,
   19.13 +   this list of conditions and the following disclaimer in the documentation
   19.14 +   and/or other materials provided with the distribution. 
   19.15 +
   19.16 +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   19.17 +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   19.18 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   19.19 +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
   19.20 +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19.21 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   19.22 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   19.23 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   19.24 +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   19.25 +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   19.26 +SUCH DAMAGE.
   19.27 +*/
   19.28 +
   19.29 +#define _LARGEFILE64_SOURCE
   19.30 +#define _GNU_SOURCE
   19.31 +
   19.32 +#include <stdlib.h>
   19.33 +#include <stdio.h>
   19.34 +#include <unistd.h>
   19.35 +#include <fcntl.h>
   19.36 +#include <errno.h>
   19.37 +#include <string.h>
   19.38 +#include <sys/wait.h>
   19.39 +#include <sys/stat.h>
   19.40 +
   19.41 +#include "virtual.h"
   19.42 +#include "cdbackup.h"
   19.43 +#include "cdrom.h"
   19.44 +#include "misc.h"
   19.45 +#include "debug.h"
   19.46 +
   19.47 +//#define DEBUGOUT
   19.48 +
   19.49 +extern int virtual, multi;
   19.50 +
   19.51 +extern int fd;
   19.52 +extern struct virt_header *virt_header;
   19.53 +extern int virtualMissing;
   19.54 +extern char *real_virt_name;
   19.55 +
   19.56 +#ifndef DEBUGOUT
   19.57 +static pid_t childpid;
   19.58 +#endif
   19.59 +static int vfd=-1;
   19.60 +
   19.61 +/****************************************************************************/
   19.62 +
   19.63 +void VnewTrack(void)
   19.64 +{
   19.65 +  if(virtual) {
   19.66 +    long long pos;
   19.67 +    if(virtualMissing) {
   19.68 +      if((fd=open64(real_virt_name,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP| S_IROTH))<0) error("Open failed (new track)");
   19.69 +      if(write(fd,virt_header,CD_FRAMESIZE)!=CD_FRAMESIZE) error("Write failed (new track)");
   19.70 +      virtualMissing=0;
   19.71 +      }
   19.72 +    if(virt_header->tracks>=MAX_VIRT_TRACKS-1) serror("Maximum number of virtual tracks reached");
   19.73 +    pos=(virt_header->start[virt_header->tracks]=virt_header->leadout)*CD_FRAMESIZE;
   19.74 +    virt_header->tracks++;
   19.75 +    if(lseek64(fd,pos,SEEK_SET)<0) error("Seek failed (new track)");
   19.76 +    }
   19.77 +  else {
   19.78 +#ifndef DEBUGOUT
   19.79 +    int pd[2];
   19.80 +    Vclose();
   19.81 +    if(pipe(pd)<0) error("Pipe failed (new track)");
   19.82 +    if((childpid=fork())<0) error("Fork failed (new track)");
   19.83 +    if(childpid==0) { /* child */
   19.84 +      close(pd[1]);
   19.85 +      close(0);
   19.86 +      dup2(pd[0],0);
   19.87 +      start_cdrecord(); /* doesn't returns */
   19.88 +      }
   19.89 +    close(pd[0]); fd=pd[1];
   19.90 +#else
   19.91 +    /* debug code; send data to /dev/null. */
   19.92 +    Vclose();
   19.93 +    fprintf(stderr,"DEBUG CODE: NO recording, sending data to /dev/null!\n");
   19.94 +    if((fd=open("/dev/null",O_WRONLY))<0) error("Open failed (/dev/null)");
   19.95 +#endif
   19.96 +    cd_avail-=padsize*CD_FRAMESIZE;
   19.97 +    }
   19.98 +}
   19.99 +
  19.100 +/****************************************************************************/
  19.101 +
  19.102 +int Vsize(void)
  19.103 +{
  19.104 +  return virt_header->leadout;
  19.105 +}
  19.106 +
  19.107 +/****************************************************************************/
  19.108 +
  19.109 +int VhasCont(void)
  19.110 +{
  19.111 +  return virt_header->has_cont;
  19.112 +}
  19.113 +
  19.114 +/****************************************************************************/
  19.115 +
  19.116 +void VprepareDump(void)
  19.117 +{
  19.118 +  if((vfd=dup(fd))<0) error("Dup failed");
  19.119 +  Vclose();
  19.120 +}
  19.121 +
  19.122 +/****************************************************************************/
  19.123 +
  19.124 +void VvirtRead(void *buf)
  19.125 +{
  19.126 +  if(full_read(vfd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE)
  19.127 +    serror("Unexpected EOF reading data");
  19.128 +}
  19.129 +
  19.130 +/****************************************************************************/
  19.131 +
  19.132 +void VcloseTrack(int cont)
  19.133 +{
  19.134 +  if(virtual) {
  19.135 +    if(lseek64(fd,0,SEEK_SET)<0) error("Seek failed (close track)");
  19.136 +    virt_header->has_cont=cont;
  19.137 +    if(write(fd,virt_header,CD_FRAMESIZE)!=CD_FRAMESIZE) error("Write failed (close track)");
  19.138 +    Vclose();
  19.139 +    }
  19.140 +  else {
  19.141 +    Vclose();
  19.142 +#ifndef DEBUGOUT
  19.143 +    DEBUG("VcloseTrack: waiting for child termination\n");
  19.144 +    while(wait(0)!=childpid);
  19.145 +#endif
  19.146 +    }
  19.147 +  if(vfd>=0) { close(vfd); vfd=-1; }
  19.148 +}
  19.149 +
  19.150 +/****************************************************************************/
  19.151 +
  19.152 +void Vwrite(const void *buf)
  19.153 +{
  19.154 +  if(write(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE) error("Write failed");
  19.155 +  if(virtual) virt_header->leadout++;
  19.156 +  cd_avail-=CD_FRAMESIZE;
  19.157 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/virtual.c	Sat Dec 29 15:25:21 2007 +0100
    20.3 @@ -0,0 +1,287 @@
    20.4 +/* virtual.c
    20.5 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
    20.6 +
    20.7 +Redistribution and use in source and binary forms, with or without
    20.8 +modification, are permitted provided that the following conditions are met: 
    20.9 +
   20.10 +1. Redistributions of source code must retain the above copyright notice,
   20.11 +   this list of conditions and the following disclaimer. 
   20.12 +2. Redistributions in binary form must reproduce the above copyright notice,
   20.13 +   this list of conditions and the following disclaimer in the documentation
   20.14 +   and/or other materials provided with the distribution. 
   20.15 +
   20.16 +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   20.17 +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   20.18 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   20.19 +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
   20.20 +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20.21 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   20.22 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   20.23 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   20.24 +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   20.25 +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   20.26 +SUCH DAMAGE.
   20.27 +*/
   20.28 +
   20.29 +#define _LARGEFILE64_SOURCE
   20.30 +#define _GNU_SOURCE
   20.31 +
   20.32 +#include <stdlib.h>
   20.33 +#include <stdio.h>
   20.34 +#include <unistd.h>
   20.35 +#include <fcntl.h>
   20.36 +#include <errno.h>
   20.37 +#include <string.h>
   20.38 +#include <sys/wait.h>
   20.39 +#include <sys/stat.h>
   20.40 +
   20.41 +#include "virtual.h"
   20.42 +#include "cdbackup.h"
   20.43 +#include "cdrom.h"
   20.44 +#include "misc.h"
   20.45 +#include "debug.h"
   20.46 +
   20.47 +int fd=-1;
   20.48 +struct toc_entry *toc=0;
   20.49 +long long cd_used, cd_avail;
   20.50 +
   20.51 +static struct cd_header cd_header;
   20.52 +
   20.53 +static unsigned char virt_buffer[VIRT_HEADER_LEN];
   20.54 +struct virt_header *virt_header=(struct virt_header *)virt_buffer;
   20.55 +int virtualMissing=0, virt_off=-1, virt_regular;
   20.56 +char *real_virt_name=0;
   20.57 +
   20.58 +extern int virtual;
   20.59 +extern int disknum;
   20.60 +extern char *virt_name, *cd_dev;
   20.61 +
   20.62 +/****************************************************************************/
   20.63 +
   20.64 +void Vopen(int ro)
   20.65 +{
   20.66 +  Vclose();
   20.67 +  if(!virtual) {
   20.68 +    if((fd=open64(cd_dev,O_RDONLY|O_NONBLOCK))<0)
   20.69 +      error("Open failed (device)");
   20.70 +    }
   20.71 +  else {
   20.72 +    free(real_virt_name);
   20.73 +    if(disknum==1) {
   20.74 +      real_virt_name=strdup(virt_name);
   20.75 +      }
   20.76 +    else if(virt_off>0) {
   20.77 +      char *strip=strdup(virt_name);
   20.78 +      char *dot=rindex(strip,'.');
   20.79 +      if(dot) {
   20.80 +        *dot=0;
   20.81 +        asprintf(&real_virt_name,"%s.%d",strip,disknum+virt_off);
   20.82 +        }
   20.83 +      else serror("Bad filename format");
   20.84 +      free(strip);
   20.85 +      }
   20.86 +    else {
   20.87 +      asprintf(&real_virt_name,"%s.%d",virt_name,disknum);
   20.88 +      }
   20.89 +    DEBUG("Vopen: real filename is '%s' disknum=%d virt_off=%d\n",
   20.90 +          real_virt_name,disknum,virt_off);
   20.91 +    virtualMissing=0; virt_regular=0;
   20.92 +    if((fd=open64(real_virt_name,ro ? O_RDONLY:O_RDWR))<0) {
   20.93 +      if(errno==EACCES || errno==ENOENT || errno==ENOTDIR) {
   20.94 +        virtualMissing=1; virt_regular=1;
   20.95 +        DEBUG("Vopen: missing virtual image, assuming an empty one\n");
   20.96 +        }
   20.97 +      else error("Open failed (virtual)");
   20.98 +      }
   20.99 +    else {
  20.100 +      struct stat64 st;
  20.101 +      if(fstat64(fd,&st)<0) error("Stat failed (virtual)");
  20.102 +      if(S_ISREG(st.st_mode)) virt_regular=1;
  20.103 +      }
  20.104 +    }
  20.105 +}
  20.106 +
  20.107 +/****************************************************************************/
  20.108 +
  20.109 +void Vclose(void)
  20.110 +{
  20.111 +  if(fd>=0) {
  20.112 +    close(fd);
  20.113 +    fd=-1;
  20.114 +    }
  20.115 +}
  20.116 +
  20.117 +/****************************************************************************/
  20.118 +
  20.119 +int VisRegular(void)
  20.120 +{
  20.121 +  return virt_regular;
  20.122 +}
  20.123 +
  20.124 +/****************************************************************************/
  20.125 +
  20.126 +static int VgetCdHeader(struct cd_header *cd)
  20.127 +{
  20.128 +  if(virtualMissing) {
  20.129 +    if(verbose) 
  20.130 +      fprintf(stderr,"%s: Unable to get virtual image header, assuming new virtual image\n",prg_name);
  20.131 +    memset(virt_buffer,0,VIRT_HEADER_LEN);
  20.132 +    virt_header->magic=VIRT_MAGIC;
  20.133 +    virt_header->version=VIRT_VERSION;
  20.134 +    virt_header->leadout=1;
  20.135 +    virt_header->count=disknum + (virt_off>0 ? virt_off:0);
  20.136 +    }
  20.137 +  else {
  20.138 +    int n;
  20.139 +    if((n=read(fd,virt_buffer,VIRT_HEADER_LEN))<0) 
  20.140 +      error("Read failed (virtual header)");
  20.141 +    if(n!=VIRT_HEADER_LEN) 
  20.142 +      serror("Short read on virtual header");
  20.143 +    if(virt_header->magic!=VIRT_MAGIC) 
  20.144 +      serror("Missing magic value in virtual header. Really a virtual image?");
  20.145 +    if(virt_header->version>VIRT_VERSION) 
  20.146 +      serror("Don't know how to handle this virtual image version");
  20.147 +    }
  20.148 +
  20.149 +  if(virt_off<0 && disknum==1) {
  20.150 +    virt_off=virt_header->count-1;
  20.151 +    DEBUG("VgetCdHeader: setting virt_off=%d\n",virt_off);
  20.152 +    }
  20.153 +  cd->start_track=1; cd->end_track=virt_header->tracks;
  20.154 +  cd->used=virt_header->leadout;
  20.155 +  return cd->end_track;
  20.156 +}
  20.157 +
  20.158 +/****************************************************************************/
  20.159 +
  20.160 +static void VgetCdTrack(int num, struct cd_track *cd)
  20.161 +{
  20.162 +  cd->start_sec=virt_header->start[num-1];
  20.163 +  cd->leadout_size=0;
  20.164 +  cd->is_data=1;
  20.165 +}
  20.166 +
  20.167 +/****************************************************************************/
  20.168 +
  20.169 +int VreadToc(int trackInfos)
  20.170 +{
  20.171 +  struct cd_track cd_track;
  20.172 +  int i, tracks;
  20.173 +
  20.174 +  tracks=virtual ? VgetCdHeader(&cd_header) : getCdHeader(&cd_header);
  20.175 +  if(!tracks) {
  20.176 +    cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE;
  20.177 +    DEBUG("Vreadtoc: empty media\n");
  20.178 +    return 0;
  20.179 +    }
  20.180 +  DEBUG("Vreadtoc: starttrack=%d endtrack=%d tracks=%d\n",
  20.181 +        cd_header.start_track,cd_header.end_track,tracks);
  20.182 +
  20.183 +  cd_used  =(long long)cd_header.used*CD_FRAMESIZE;
  20.184 +  cd_avail =(long long)cd_len*CD_FRAMESIZE-cd_used;
  20.185 +  if(cd_avail<0) cd_avail=0;
  20.186 +  DEBUG("Vreadtoc: cd_used=%lld (%lld secs) cd_avail=%lld (%lld secs)\n",
  20.187 +        cd_used,cd_used/CD_FRAMESIZE,cd_avail,cd_avail/CD_FRAMESIZE);
  20.188 +
  20.189 +  free(toc);
  20.190 +  if(!(toc=calloc(tracks,sizeof(struct toc_entry)))) serror("No memory for TOC");
  20.191 +
  20.192 +  cd_track.start_track=cd_header.start_track;
  20.193 +  for(i=tracks-1; i>=0; i--) {
  20.194 +    int t=cd_header.start_track+i;
  20.195 +    if(virtual) VgetCdTrack(t,&cd_track); else getCdTrack(t,&cd_track);
  20.196 +    toc[i].track_no=t;
  20.197 +    toc[i].sec_start=cd_track.start_sec;
  20.198 +    toc[i].sec_end=((i==tracks-1) ? cd_header.used : toc[i+1].sec_start)-1-cd_track.leadout_size; 
  20.199 +    toc[i].is_data=cd_track.is_data;
  20.200 +    DEBUG("Vreadtoc: index=%d track=%d sec_start=%d sec_end=%d data=%d\n",
  20.201 +          i,t,toc[i].sec_start,toc[i].sec_end,toc[i].is_data);
  20.202 +    }
  20.203 +
  20.204 +  if(trackInfos) {
  20.205 +    for(i=0; i<tracks; i++) {
  20.206 +      char inbuffer[CD_FRAMESIZE];
  20.207 +      struct header_block *track_header=(struct header_block *)inbuffer;
  20.208 +
  20.209 +      if(toc[i].is_data) {
  20.210 +        Vseek(i);
  20.211 +        Vread(inbuffer);
  20.212 +        if(!strncmp(SHORT_HDR,track_header->id_str,strlen(SHORT_HDR))) {
  20.213 +          toc[i].is_cdbackup=1;
  20.214 +          strncpy(toc[i].id_str,track_header->id_str,32); toc[i].id_str[32]=0;
  20.215 +          strncpy(toc[i].vol_id, track_header->vol_id,32); toc[i].vol_id[32]=0;
  20.216 +          strncpy(toc[i].t_stamp, track_header->t_stamp,12); toc[i].t_stamp[12]=0;
  20.217 +          toc[i].disk_set = track_header->disk_set;
  20.218 +          toc[i].flags = track_header->flags;
  20.219 +          }
  20.220 +        }
  20.221 +      }
  20.222 +    }
  20.223 +
  20.224 +  return tracks;
  20.225 +}
  20.226 +
  20.227 +/****************************************************************************/
  20.228 +
  20.229 +const char *VdevName(void)
  20.230 +{
  20.231 +  static char buff[80];
  20.232 +  if(virtual) snprintf(buff,sizeof(buff),"image %s",virt_name);
  20.233 +  else snprintf(buff,sizeof(buff),"device %s",cd_dev);
  20.234 +  return buff;
  20.235 +}
  20.236 +
  20.237 +/****************************************************************************/
  20.238 +
  20.239 +void VprintSpace(void)
  20.240 +{
  20.241 +  if(verbose) {
  20.242 +    char flex1[16], flex2[16], flex3[16];
  20.243 +    fprintf(stderr,
  20.244 +      "Disk size:  %s (%7ld blocks)\n"
  20.245 +      "Space used: %s (%7lld blocks)\n"
  20.246 +      "Space avail:%s (%7lld blocks)\n",
  20.247 +      FlexSize(flex1,(long long)cd_len*CD_FRAMESIZE),cd_len,
  20.248 +      FlexSize(flex2,cd_used), cd_used/CD_FRAMESIZE,
  20.249 +      FlexSize(flex3,cd_avail), cd_avail/CD_FRAMESIZE);
  20.250 +    }
  20.251 +}
  20.252 +
  20.253 +/****************************************************************************/
  20.254 +
  20.255 +long long Vseek(int trackNum)
  20.256 +{
  20.257 +  long long pos=0;
  20.258 +  if(trackNum>=0) pos=(long long)toc[trackNum].sec_start*CD_FRAMESIZE;
  20.259 +  DEBUG("Vseek: seeking to index %d, track %d, offset %lld (%s)\n",
  20.260 +        trackNum,toc[trackNum].track_no,pos,virtual ? "virtual":"real");
  20.261 +  if(lseek64(fd,pos,SEEK_SET)<0) error("Seek failed");
  20.262 +  return pos;
  20.263 +}
  20.264 +
  20.265 +/****************************************************************************/
  20.266 +
  20.267 +void Vread(void *buf)
  20.268 +{
  20.269 +  if(full_read(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE)
  20.270 +    serror("Unexpected EOF reading data");
  20.271 +}
  20.272 +
  20.273 +/****************************************************************************/
  20.274 +
  20.275 +static unsigned long r_ahead, r_fahead;
  20.276 +
  20.277 +void VgetAhead(void)
  20.278 +{
  20.279 +  if(!virtual) get_param(fd,&r_ahead,&r_fahead);
  20.280 +}
  20.281 +
  20.282 +/****************************************************************************/
  20.283 +
  20.284 +void VsetAhead(int restore)
  20.285 +{
  20.286 +  if(!virtual) {
  20.287 +    if(restore) set_param(fd,r_ahead,r_fahead);
  20.288 +    else set_param(fd,0,0);
  20.289 +    }
  20.290 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/virtual.h	Sat Dec 29 15:25:21 2007 +0100
    21.3 @@ -0,0 +1,78 @@
    21.4 +/* virtual.h
    21.5 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
    21.6 +
    21.7 +Redistribution and use in source and binary forms, with or without
    21.8 +modification, are permitted provided that the following conditions are met: 
    21.9 +
   21.10 +1. Redistributions of source code must retain the above copyright notice,
   21.11 +   this list of conditions and the following disclaimer. 
   21.12 +2. Redistributions in binary form must reproduce the above copyright notice,
   21.13 +   this list of conditions and the following disclaimer in the documentation
   21.14 +   and/or other materials provided with the distribution. 
   21.15 +
   21.16 +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   21.17 +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   21.18 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   21.19 +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
   21.20 +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21.21 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   21.22 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   21.23 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21.24 +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   21.25 +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   21.26 +SUCH DAMAGE.
   21.27 +*/
   21.28 +
   21.29 +#ifndef _CDBACKUP_VIRTUAL_H
   21.30 +#define _CDBACKUP_VIRTUAL_H
   21.31 +
   21.32 +#define VIRT_VERSION    1
   21.33 +#define VIRT_MAGIC      0x144391C83A78412FLL
   21.34 +#define MAX_VIRT_TRACKS 96
   21.35 +#define VIRT_HEADER_LEN CD_FRAMESIZE
   21.36 +
   21.37 +struct virt_header {
   21.38 +  long long magic;
   21.39 +  int version;
   21.40 +  int tracks;
   21.41 +  int leadout;
   21.42 +  int count, has_cont;
   21.43 +  int reserved[25];
   21.44 +  int start[MAX_VIRT_TRACKS];
   21.45 +  };
   21.46 +
   21.47 +struct toc_entry {
   21.48 +  u_char track_no;	/* track number */
   21.49 +  char is_data;		/* 1 = data track */
   21.50 +  char is_cdbackup;	/* was it created by CD-Backup? */
   21.51 +  int sec_start;	/* start sector */
   21.52 +  int sec_end;		/* last sector */
   21.53 +  char id_str[33];	/* recorder id string (32 chars) */
   21.54 +  char vol_id[33];	/* volume label (32 characters) */
   21.55 +  char t_stamp[13];	/* time stamp: yyyymmddhhmm */
   21.56 +  char disk_set;	/* disk number */
   21.57 +  char flags;           /* backup flags */
   21.58 +  };
   21.59 +
   21.60 +extern struct toc_entry *toc;
   21.61 +extern long long cd_used, cd_avail;
   21.62 +
   21.63 +void Vopen(int ro);
   21.64 +void Vclose(void);
   21.65 +int VisRegular(void);
   21.66 +int VreadToc(int trackInfos);
   21.67 +void VprintSpace(void);
   21.68 +const char *VdevName(void);
   21.69 +long long Vseek(int trackNum);
   21.70 +void Vread(void *buf);
   21.71 +void VnewTrack(void);
   21.72 +void VcloseTrack(int cont);
   21.73 +void Vwrite(const void *buf);
   21.74 +void VgetAhead(void);
   21.75 +void VsetAhead(int restore);
   21.76 +int Vsize(void);
   21.77 +int VhasCont(void);
   21.78 +void VprepareDump(void);
   21.79 +void VvirtRead(void *buf);
   21.80 +
   21.81 +#endif