virtual.c
author nathan
Sun, 23 May 2010 08:39:19 +0200
branchtrunk
changeset 13 6ef9b2adca64
parent 6 6262df5a6216
child 15 a9348bf5f6e7
permissions -rw-r--r--
fix gcc warnings (asprintf)
     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         if(asprintf(&real_virt_name,"%s.%d",strip,disknum+virt_off)<0)
    79           error("error making virtual name");
    80         }
    81       else serror("Bad filename format");
    82       free(strip);
    83       }
    84     else {
    85       if(asprintf(&real_virt_name,"%s.%d",virt_name,disknum)<0)
    86         error("error making virtual name");
    87       }
    88     DEBUG("Vopen: real filename is '%s' disknum=%d virt_off=%d\n",
    89           real_virt_name,disknum,virt_off);
    90     virtualMissing=0; virt_regular=0;
    91     if((fd=open64(real_virt_name,ro ? O_RDONLY:O_RDWR))<0) {
    92       if(errno==EACCES || errno==ENOENT || errno==ENOTDIR) {
    93         virtualMissing=1; virt_regular=1;
    94         DEBUG("Vopen: missing virtual image, assuming an empty one\n");
    95         }
    96       else error("Open failed (virtual)");
    97       }
    98     else {
    99       struct stat64 st;
   100       if(fstat64(fd,&st)<0) error("Stat failed (virtual)");
   101       if(S_ISREG(st.st_mode)) virt_regular=1;
   102       }
   103     }
   104 }
   105 
   106 /****************************************************************************/
   107 
   108 void Vclose(void)
   109 {
   110   if(fd>=0) {
   111     close(fd);
   112     fd=-1;
   113     }
   114 }
   115 
   116 /****************************************************************************/
   117 
   118 int VisRegular(void)
   119 {
   120   return virt_regular;
   121 }
   122 
   123 /****************************************************************************/
   124 
   125 static int VgetCdHeader(struct cd_header *cd)
   126 {
   127   if(virtualMissing) {
   128     if(verbose) 
   129       fprintf(stderr,"%s: Unable to get virtual image header, assuming new virtual image\n",prg_name);
   130     memset(virt_buffer,0,VIRT_HEADER_LEN);
   131     virt_header->magic=VIRT_MAGIC;
   132     virt_header->version=VIRT_VERSION;
   133     virt_header->leadout=1;
   134     virt_header->count=disknum + (virt_off>0 ? virt_off:0);
   135     }
   136   else {
   137     int n;
   138     if((n=read(fd,virt_buffer,VIRT_HEADER_LEN))<0) 
   139       error("Read failed (virtual header)");
   140     if(n!=VIRT_HEADER_LEN) 
   141       serror("Short read on virtual header");
   142     if(virt_header->magic!=VIRT_MAGIC) 
   143       serror("Missing magic value in virtual header. Really a virtual image?");
   144     if(virt_header->version>VIRT_VERSION) 
   145       serror("Don't know how to handle this virtual image version");
   146     }
   147 
   148   if(virt_off<0 && disknum==1) {
   149     virt_off=virt_header->count-1;
   150     DEBUG("VgetCdHeader: setting virt_off=%d\n",virt_off);
   151     }
   152   cd->start_track=1; cd->end_track=virt_header->tracks;
   153   cd->used=virt_header->leadout;
   154   return cd->end_track;
   155 }
   156 
   157 /****************************************************************************/
   158 
   159 static void VgetCdTrack(int num, struct cd_track *cd)
   160 {
   161   cd->start_sec=virt_header->start[num-1];
   162   cd->leadout_size=0;
   163   cd->is_data=1;
   164 }
   165 
   166 /****************************************************************************/
   167 
   168 int VreadToc(int trackInfos)
   169 {
   170   struct cd_track cd_track;
   171   int i, tracks;
   172 
   173   tracks=virtual ? VgetCdHeader(&cd_header) : getCdHeader(&cd_header);
   174   if(!tracks) {
   175     cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE;
   176     DEBUG("Vreadtoc: empty media\n");
   177     return 0;
   178     }
   179   DEBUG("Vreadtoc: starttrack=%d endtrack=%d tracks=%d\n",
   180         cd_header.start_track,cd_header.end_track,tracks);
   181 
   182   cd_used  =(long long)cd_header.used*CD_FRAMESIZE;
   183   cd_avail =(long long)cd_len*CD_FRAMESIZE-cd_used;
   184   if(cd_avail<0) cd_avail=0;
   185   DEBUG("Vreadtoc: cd_used=%lld (%lld secs) cd_avail=%lld (%lld secs)\n",
   186         cd_used,cd_used/CD_FRAMESIZE,cd_avail,cd_avail/CD_FRAMESIZE);
   187 
   188   free(toc);
   189   if(!(toc=calloc(tracks,sizeof(struct toc_entry)))) serror("No memory for TOC");
   190 
   191   cd_track.start_track=cd_header.start_track;
   192   for(i=tracks-1; i>=0; i--) {
   193     int t=cd_header.start_track+i;
   194     if(virtual) VgetCdTrack(t,&cd_track); else getCdTrack(t,&cd_track);
   195     toc[i].track_no=t;
   196     toc[i].sec_start=cd_track.start_sec;
   197     toc[i].sec_end=((i==tracks-1) ? cd_header.used : toc[i+1].sec_start)-1-cd_track.leadout_size; 
   198     toc[i].is_data=cd_track.is_data;
   199     DEBUG("Vreadtoc: index=%d track=%d sec_start=%d sec_end=%d data=%d\n",
   200           i,t,toc[i].sec_start,toc[i].sec_end,toc[i].is_data);
   201     }
   202 
   203   if(trackInfos) {
   204     for(i=0; i<tracks; i++) {
   205       char inbuffer[CD_FRAMESIZE];
   206       struct header_block *track_header=(struct header_block *)inbuffer;
   207 
   208       if(toc[i].is_data) {
   209         Vseek(i);
   210         Vread(inbuffer);
   211         if(!strncmp(SHORT_HDR,track_header->id_str,strlen(SHORT_HDR))) {
   212           toc[i].is_cdbackup=1;
   213           strncpy(toc[i].id_str,track_header->id_str,32); toc[i].id_str[32]=0;
   214           strncpy(toc[i].vol_id, track_header->vol_id,32); toc[i].vol_id[32]=0;
   215           strncpy(toc[i].t_stamp, track_header->t_stamp,12); toc[i].t_stamp[12]=0;
   216           toc[i].disk_set = track_header->disk_set;
   217           toc[i].flags = track_header->flags;
   218           }
   219         }
   220       }
   221     }
   222 
   223   return tracks;
   224 }
   225 
   226 /****************************************************************************/
   227 
   228 const char *VdevName(void)
   229 {
   230   static char buff[80];
   231   if(virtual) snprintf(buff,sizeof(buff),"image %s",virt_name);
   232   else snprintf(buff,sizeof(buff),"device %s",cd_dev);
   233   return buff;
   234 }
   235 
   236 /****************************************************************************/
   237 
   238 void VprintSpace(void)
   239 {
   240   if(verbose) {
   241     char flex1[16], flex2[16], flex3[16];
   242     fprintf(stderr,
   243       "Disk size:  %s (%7ld blocks)\n"
   244       "Space used: %s (%7lld blocks)\n"
   245       "Space avail:%s (%7lld blocks)\n",
   246       FlexSize(flex1,(long long)cd_len*CD_FRAMESIZE),cd_len,
   247       FlexSize(flex2,cd_used), cd_used/CD_FRAMESIZE,
   248       FlexSize(flex3,cd_avail), cd_avail/CD_FRAMESIZE);
   249     }
   250 }
   251 
   252 /****************************************************************************/
   253 
   254 long long Vseek(int trackNum)
   255 {
   256   long long pos=0;
   257   if(trackNum>=0) pos=(long long)toc[trackNum].sec_start*CD_FRAMESIZE;
   258   DEBUG("Vseek: seeking to index %d, track %d, offset %lld (%s)\n",
   259         trackNum,toc[trackNum].track_no,pos,virtual ? "virtual":"real");
   260   if(lseek64(fd,pos,SEEK_SET)<0) error("Seek failed");
   261   return pos;
   262 }
   263 
   264 /****************************************************************************/
   265 
   266 void Vread(void *buf)
   267 {
   268   if(full_read(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE)
   269     serror("Unexpected EOF reading data");
   270 }
   271 
   272 /****************************************************************************/
   273 
   274 static unsigned long r_ahead, r_fahead;
   275 
   276 void VgetAhead(void)
   277 {
   278   if(!virtual) get_param(fd,&r_ahead,&r_fahead);
   279 }
   280 
   281 /****************************************************************************/
   282 
   283 void VsetAhead(int restore)
   284 {
   285   if(!virtual) {
   286     if(restore) set_param(fd,r_ahead,r_fahead);
   287     else set_param(fd,0,0);
   288     }
   289 }