diff -r d09ec85ffdfe -r 79da91042fcc virtual.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/virtual.c Sat Dec 29 15:25:21 2007 +0100 @@ -0,0 +1,287 @@ +/* virtual.c +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ + +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "virtual.h" +#include "cdbackup.h" +#include "cdrom.h" +#include "misc.h" +#include "debug.h" + +int fd=-1; +struct toc_entry *toc=0; +long long cd_used, cd_avail; + +static struct cd_header cd_header; + +static unsigned char virt_buffer[VIRT_HEADER_LEN]; +struct virt_header *virt_header=(struct virt_header *)virt_buffer; +int virtualMissing=0, virt_off=-1, virt_regular; +char *real_virt_name=0; + +extern int virtual; +extern int disknum; +extern char *virt_name, *cd_dev; + +/****************************************************************************/ + +void Vopen(int ro) +{ + Vclose(); + if(!virtual) { + if((fd=open64(cd_dev,O_RDONLY|O_NONBLOCK))<0) + error("Open failed (device)"); + } + else { + free(real_virt_name); + if(disknum==1) { + real_virt_name=strdup(virt_name); + } + else if(virt_off>0) { + char *strip=strdup(virt_name); + char *dot=rindex(strip,'.'); + if(dot) { + *dot=0; + asprintf(&real_virt_name,"%s.%d",strip,disknum+virt_off); + } + else serror("Bad filename format"); + free(strip); + } + else { + asprintf(&real_virt_name,"%s.%d",virt_name,disknum); + } + DEBUG("Vopen: real filename is '%s' disknum=%d virt_off=%d\n", + real_virt_name,disknum,virt_off); + virtualMissing=0; virt_regular=0; + if((fd=open64(real_virt_name,ro ? O_RDONLY:O_RDWR))<0) { + if(errno==EACCES || errno==ENOENT || errno==ENOTDIR) { + virtualMissing=1; virt_regular=1; + DEBUG("Vopen: missing virtual image, assuming an empty one\n"); + } + else error("Open failed (virtual)"); + } + else { + struct stat64 st; + if(fstat64(fd,&st)<0) error("Stat failed (virtual)"); + if(S_ISREG(st.st_mode)) virt_regular=1; + } + } +} + +/****************************************************************************/ + +void Vclose(void) +{ + if(fd>=0) { + close(fd); + fd=-1; + } +} + +/****************************************************************************/ + +int VisRegular(void) +{ + return virt_regular; +} + +/****************************************************************************/ + +static int VgetCdHeader(struct cd_header *cd) +{ + if(virtualMissing) { + if(verbose) + fprintf(stderr,"%s: Unable to get virtual image header, assuming new virtual image\n",prg_name); + memset(virt_buffer,0,VIRT_HEADER_LEN); + virt_header->magic=VIRT_MAGIC; + virt_header->version=VIRT_VERSION; + virt_header->leadout=1; + virt_header->count=disknum + (virt_off>0 ? virt_off:0); + } + else { + int n; + if((n=read(fd,virt_buffer,VIRT_HEADER_LEN))<0) + error("Read failed (virtual header)"); + if(n!=VIRT_HEADER_LEN) + serror("Short read on virtual header"); + if(virt_header->magic!=VIRT_MAGIC) + serror("Missing magic value in virtual header. Really a virtual image?"); + if(virt_header->version>VIRT_VERSION) + serror("Don't know how to handle this virtual image version"); + } + + if(virt_off<0 && disknum==1) { + virt_off=virt_header->count-1; + DEBUG("VgetCdHeader: setting virt_off=%d\n",virt_off); + } + cd->start_track=1; cd->end_track=virt_header->tracks; + cd->used=virt_header->leadout; + return cd->end_track; +} + +/****************************************************************************/ + +static void VgetCdTrack(int num, struct cd_track *cd) +{ + cd->start_sec=virt_header->start[num-1]; + cd->leadout_size=0; + cd->is_data=1; +} + +/****************************************************************************/ + +int VreadToc(int trackInfos) +{ + struct cd_track cd_track; + int i, tracks; + + tracks=virtual ? VgetCdHeader(&cd_header) : getCdHeader(&cd_header); + if(!tracks) { + cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE; + DEBUG("Vreadtoc: empty media\n"); + return 0; + } + DEBUG("Vreadtoc: starttrack=%d endtrack=%d tracks=%d\n", + cd_header.start_track,cd_header.end_track,tracks); + + cd_used =(long long)cd_header.used*CD_FRAMESIZE; + cd_avail =(long long)cd_len*CD_FRAMESIZE-cd_used; + if(cd_avail<0) cd_avail=0; + DEBUG("Vreadtoc: cd_used=%lld (%lld secs) cd_avail=%lld (%lld secs)\n", + cd_used,cd_used/CD_FRAMESIZE,cd_avail,cd_avail/CD_FRAMESIZE); + + free(toc); + if(!(toc=calloc(tracks,sizeof(struct toc_entry)))) serror("No memory for TOC"); + + cd_track.start_track=cd_header.start_track; + for(i=tracks-1; i>=0; i--) { + int t=cd_header.start_track+i; + if(virtual) VgetCdTrack(t,&cd_track); else getCdTrack(t,&cd_track); + toc[i].track_no=t; + toc[i].sec_start=cd_track.start_sec; + toc[i].sec_end=((i==tracks-1) ? cd_header.used : toc[i+1].sec_start)-1-cd_track.leadout_size; + toc[i].is_data=cd_track.is_data; + DEBUG("Vreadtoc: index=%d track=%d sec_start=%d sec_end=%d data=%d\n", + i,t,toc[i].sec_start,toc[i].sec_end,toc[i].is_data); + } + + if(trackInfos) { + for(i=0; iid_str,strlen(SHORT_HDR))) { + toc[i].is_cdbackup=1; + strncpy(toc[i].id_str,track_header->id_str,32); toc[i].id_str[32]=0; + strncpy(toc[i].vol_id, track_header->vol_id,32); toc[i].vol_id[32]=0; + strncpy(toc[i].t_stamp, track_header->t_stamp,12); toc[i].t_stamp[12]=0; + toc[i].disk_set = track_header->disk_set; + toc[i].flags = track_header->flags; + } + } + } + } + + return tracks; +} + +/****************************************************************************/ + +const char *VdevName(void) +{ + static char buff[80]; + if(virtual) snprintf(buff,sizeof(buff),"image %s",virt_name); + else snprintf(buff,sizeof(buff),"device %s",cd_dev); + return buff; +} + +/****************************************************************************/ + +void VprintSpace(void) +{ + if(verbose) { + char flex1[16], flex2[16], flex3[16]; + fprintf(stderr, + "Disk size: %s (%7ld blocks)\n" + "Space used: %s (%7lld blocks)\n" + "Space avail:%s (%7lld blocks)\n", + FlexSize(flex1,(long long)cd_len*CD_FRAMESIZE),cd_len, + FlexSize(flex2,cd_used), cd_used/CD_FRAMESIZE, + FlexSize(flex3,cd_avail), cd_avail/CD_FRAMESIZE); + } +} + +/****************************************************************************/ + +long long Vseek(int trackNum) +{ + long long pos=0; + if(trackNum>=0) pos=(long long)toc[trackNum].sec_start*CD_FRAMESIZE; + DEBUG("Vseek: seeking to index %d, track %d, offset %lld (%s)\n", + trackNum,toc[trackNum].track_no,pos,virtual ? "virtual":"real"); + if(lseek64(fd,pos,SEEK_SET)<0) error("Seek failed"); + return pos; +} + +/****************************************************************************/ + +void Vread(void *buf) +{ + if(full_read(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE) + serror("Unexpected EOF reading data"); +} + +/****************************************************************************/ + +static unsigned long r_ahead, r_fahead; + +void VgetAhead(void) +{ + if(!virtual) get_param(fd,&r_ahead,&r_fahead); +} + +/****************************************************************************/ + +void VsetAhead(int restore) +{ + if(!virtual) { + if(restore) set_param(fd,r_ahead,r_fahead); + else set_param(fd,0,0); + } +}