virtual.c
author nathan
Sat, 29 Dec 2007 15:28:22 +0100
branchtrunk
changeset 9 d6649fe2a4e0
parent 6 6262df5a6216
child 13 6ef9b2adca64
permissions -rw-r--r--
Added tag 0.7.0 for changeset a306b5e43b44
     1 /* virtual.c
     2 Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
     3 
     4 Redistribution and use in source and binary forms, with or without
     5 modification, are permitted provided that the following conditions are met: 
     6 
     7 1. Redistributions of source code must retain the above copyright notice,
     8    this list of conditions and the following disclaimer. 
     9 2. Redistributions in binary form must reproduce the above copyright notice,
    10    this list of conditions and the following disclaimer in the documentation
    11    and/or other materials provided with the distribution. 
    12 
    13 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
    14 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    16 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
    17 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    20 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    21 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    22 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    23 SUCH DAMAGE.
    24 */
    25 
    26 #define _LARGEFILE64_SOURCE
    27 #define _GNU_SOURCE
    28 
    29 #include <stdlib.h>
    30 #include <stdio.h>
    31 #include <unistd.h>
    32 #include <fcntl.h>
    33 #include <errno.h>
    34 #include <string.h>
    35 #include <sys/wait.h>
    36 #include <sys/stat.h>
    37 
    38 #include "virtual.h"
    39 #include "cdbackup.h"
    40 #include "cdrom.h"
    41 #include "misc.h"
    42 #include "debug.h"
    43 
    44 int fd=-1;
    45 struct toc_entry *toc=0;
    46 long long cd_used, cd_avail;
    47 
    48 static struct cd_header cd_header;
    49 
    50 static unsigned char virt_buffer[VIRT_HEADER_LEN];
    51 struct virt_header *virt_header=(struct virt_header *)virt_buffer;
    52 int virtualMissing=0, virt_off=-1, virt_regular=0;
    53 char *real_virt_name=0;
    54 
    55 extern int virtual;
    56 extern int disknum;
    57 extern char *virt_name, *cd_dev;
    58 
    59 /****************************************************************************/
    60 
    61 void Vopen(int ro)
    62 {
    63   Vclose();
    64   if(!virtual) {
    65     if((fd=open64(cd_dev,O_RDONLY|O_NONBLOCK))<0)
    66       error("Open failed (device)");
    67     }
    68   else {
    69     free(real_virt_name);
    70     if(disknum==1 || !virt_regular) {
    71       real_virt_name=strdup(virt_name);
    72       }
    73     else if(virt_off>0) {
    74       char *strip=strdup(virt_name);
    75       char *dot=rindex(strip,'.');
    76       if(dot) {
    77         *dot=0;
    78         asprintf(&real_virt_name,"%s.%d",strip,disknum+virt_off);
    79         }
    80       else serror("Bad filename format");
    81       free(strip);
    82       }
    83     else {
    84       asprintf(&real_virt_name,"%s.%d",virt_name,disknum);
    85       }
    86     DEBUG("Vopen: real filename is '%s' disknum=%d virt_off=%d\n",
    87           real_virt_name,disknum,virt_off);
    88     virtualMissing=0; virt_regular=0;
    89     if((fd=open64(real_virt_name,ro ? O_RDONLY:O_RDWR))<0) {
    90       if(errno==EACCES || errno==ENOENT || errno==ENOTDIR) {
    91         virtualMissing=1; virt_regular=1;
    92         DEBUG("Vopen: missing virtual image, assuming an empty one\n");
    93         }
    94       else error("Open failed (virtual)");
    95       }
    96     else {
    97       struct stat64 st;
    98       if(fstat64(fd,&st)<0) error("Stat failed (virtual)");
    99       if(S_ISREG(st.st_mode)) virt_regular=1;
   100       }
   101     }
   102 }
   103 
   104 /****************************************************************************/
   105 
   106 void Vclose(void)
   107 {
   108   if(fd>=0) {
   109     close(fd);
   110     fd=-1;
   111     }
   112 }
   113 
   114 /****************************************************************************/
   115 
   116 int VisRegular(void)
   117 {
   118   return virt_regular;
   119 }
   120 
   121 /****************************************************************************/
   122 
   123 static int VgetCdHeader(struct cd_header *cd)
   124 {
   125   if(virtualMissing) {
   126     if(verbose) 
   127       fprintf(stderr,"%s: Unable to get virtual image header, assuming new virtual image\n",prg_name);
   128     memset(virt_buffer,0,VIRT_HEADER_LEN);
   129     virt_header->magic=VIRT_MAGIC;
   130     virt_header->version=VIRT_VERSION;
   131     virt_header->leadout=1;
   132     virt_header->count=disknum + (virt_off>0 ? virt_off:0);
   133     }
   134   else {
   135     int n;
   136     if((n=read(fd,virt_buffer,VIRT_HEADER_LEN))<0) 
   137       error("Read failed (virtual header)");
   138     if(n!=VIRT_HEADER_LEN) 
   139       serror("Short read on virtual header");
   140     if(virt_header->magic!=VIRT_MAGIC) 
   141       serror("Missing magic value in virtual header. Really a virtual image?");
   142     if(virt_header->version>VIRT_VERSION) 
   143       serror("Don't know how to handle this virtual image version");
   144     }
   145 
   146   if(virt_off<0 && disknum==1) {
   147     virt_off=virt_header->count-1;
   148     DEBUG("VgetCdHeader: setting virt_off=%d\n",virt_off);
   149     }
   150   cd->start_track=1; cd->end_track=virt_header->tracks;
   151   cd->used=virt_header->leadout;
   152   return cd->end_track;
   153 }
   154 
   155 /****************************************************************************/
   156 
   157 static void VgetCdTrack(int num, struct cd_track *cd)
   158 {
   159   cd->start_sec=virt_header->start[num-1];
   160   cd->leadout_size=0;
   161   cd->is_data=1;
   162 }
   163 
   164 /****************************************************************************/
   165 
   166 int VreadToc(int trackInfos)
   167 {
   168   struct cd_track cd_track;
   169   int i, tracks;
   170 
   171   tracks=virtual ? VgetCdHeader(&cd_header) : getCdHeader(&cd_header);
   172   if(!tracks) {
   173     cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE;
   174     DEBUG("Vreadtoc: empty media\n");
   175     return 0;
   176     }
   177   DEBUG("Vreadtoc: starttrack=%d endtrack=%d tracks=%d\n",
   178         cd_header.start_track,cd_header.end_track,tracks);
   179 
   180   cd_used  =(long long)cd_header.used*CD_FRAMESIZE;
   181   cd_avail =(long long)cd_len*CD_FRAMESIZE-cd_used;
   182   if(cd_avail<0) cd_avail=0;
   183   DEBUG("Vreadtoc: cd_used=%lld (%lld secs) cd_avail=%lld (%lld secs)\n",
   184         cd_used,cd_used/CD_FRAMESIZE,cd_avail,cd_avail/CD_FRAMESIZE);
   185 
   186   free(toc);
   187   if(!(toc=calloc(tracks,sizeof(struct toc_entry)))) serror("No memory for TOC");
   188 
   189   cd_track.start_track=cd_header.start_track;
   190   for(i=tracks-1; i>=0; i--) {
   191     int t=cd_header.start_track+i;
   192     if(virtual) VgetCdTrack(t,&cd_track); else getCdTrack(t,&cd_track);
   193     toc[i].track_no=t;
   194     toc[i].sec_start=cd_track.start_sec;
   195     toc[i].sec_end=((i==tracks-1) ? cd_header.used : toc[i+1].sec_start)-1-cd_track.leadout_size; 
   196     toc[i].is_data=cd_track.is_data;
   197     DEBUG("Vreadtoc: index=%d track=%d sec_start=%d sec_end=%d data=%d\n",
   198           i,t,toc[i].sec_start,toc[i].sec_end,toc[i].is_data);
   199     }
   200 
   201   if(trackInfos) {
   202     for(i=0; i<tracks; i++) {
   203       char inbuffer[CD_FRAMESIZE];
   204       struct header_block *track_header=(struct header_block *)inbuffer;
   205 
   206       if(toc[i].is_data) {
   207         Vseek(i);
   208         Vread(inbuffer);
   209         if(!strncmp(SHORT_HDR,track_header->id_str,strlen(SHORT_HDR))) {
   210           toc[i].is_cdbackup=1;
   211           strncpy(toc[i].id_str,track_header->id_str,32); toc[i].id_str[32]=0;
   212           strncpy(toc[i].vol_id, track_header->vol_id,32); toc[i].vol_id[32]=0;
   213           strncpy(toc[i].t_stamp, track_header->t_stamp,12); toc[i].t_stamp[12]=0;
   214           toc[i].disk_set = track_header->disk_set;
   215           toc[i].flags = track_header->flags;
   216           }
   217         }
   218       }
   219     }
   220 
   221   return tracks;
   222 }
   223 
   224 /****************************************************************************/
   225 
   226 const char *VdevName(void)
   227 {
   228   static char buff[80];
   229   if(virtual) snprintf(buff,sizeof(buff),"image %s",virt_name);
   230   else snprintf(buff,sizeof(buff),"device %s",cd_dev);
   231   return buff;
   232 }
   233 
   234 /****************************************************************************/
   235 
   236 void VprintSpace(void)
   237 {
   238   if(verbose) {
   239     char flex1[16], flex2[16], flex3[16];
   240     fprintf(stderr,
   241       "Disk size:  %s (%7ld blocks)\n"
   242       "Space used: %s (%7lld blocks)\n"
   243       "Space avail:%s (%7lld blocks)\n",
   244       FlexSize(flex1,(long long)cd_len*CD_FRAMESIZE),cd_len,
   245       FlexSize(flex2,cd_used), cd_used/CD_FRAMESIZE,
   246       FlexSize(flex3,cd_avail), cd_avail/CD_FRAMESIZE);
   247     }
   248 }
   249 
   250 /****************************************************************************/
   251 
   252 long long Vseek(int trackNum)
   253 {
   254   long long pos=0;
   255   if(trackNum>=0) pos=(long long)toc[trackNum].sec_start*CD_FRAMESIZE;
   256   DEBUG("Vseek: seeking to index %d, track %d, offset %lld (%s)\n",
   257         trackNum,toc[trackNum].track_no,pos,virtual ? "virtual":"real");
   258   if(lseek64(fd,pos,SEEK_SET)<0) error("Seek failed");
   259   return pos;
   260 }
   261 
   262 /****************************************************************************/
   263 
   264 void Vread(void *buf)
   265 {
   266   if(full_read(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE)
   267     serror("Unexpected EOF reading data");
   268 }
   269 
   270 /****************************************************************************/
   271 
   272 static unsigned long r_ahead, r_fahead;
   273 
   274 void VgetAhead(void)
   275 {
   276   if(!virtual) get_param(fd,&r_ahead,&r_fahead);
   277 }
   278 
   279 /****************************************************************************/
   280 
   281 void VsetAhead(int restore)
   282 {
   283   if(!virtual) {
   284     if(restore) set_param(fd,r_ahead,r_fahead);
   285     else set_param(fd,0,0);
   286     }
   287 }