1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/virtual.c Sat Dec 29 15:25:21 2007 +0100
1.3 @@ -0,0 +1,287 @@
1.4 +/* virtual.c
1.5 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
1.6 +
1.7 +Redistribution and use in source and binary forms, with or without
1.8 +modification, are permitted provided that the following conditions are met:
1.9 +
1.10 +1. Redistributions of source code must retain the above copyright notice,
1.11 + this list of conditions and the following disclaimer.
1.12 +2. Redistributions in binary form must reproduce the above copyright notice,
1.13 + this list of conditions and the following disclaimer in the documentation
1.14 + and/or other materials provided with the distribution.
1.15 +
1.16 +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1.17 +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1.18 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1.19 +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
1.20 +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1.21 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1.22 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1.23 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1.24 +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1.25 +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1.26 +SUCH DAMAGE.
1.27 +*/
1.28 +
1.29 +#define _LARGEFILE64_SOURCE
1.30 +#define _GNU_SOURCE
1.31 +
1.32 +#include <stdlib.h>
1.33 +#include <stdio.h>
1.34 +#include <unistd.h>
1.35 +#include <fcntl.h>
1.36 +#include <errno.h>
1.37 +#include <string.h>
1.38 +#include <sys/wait.h>
1.39 +#include <sys/stat.h>
1.40 +
1.41 +#include "virtual.h"
1.42 +#include "cdbackup.h"
1.43 +#include "cdrom.h"
1.44 +#include "misc.h"
1.45 +#include "debug.h"
1.46 +
1.47 +int fd=-1;
1.48 +struct toc_entry *toc=0;
1.49 +long long cd_used, cd_avail;
1.50 +
1.51 +static struct cd_header cd_header;
1.52 +
1.53 +static unsigned char virt_buffer[VIRT_HEADER_LEN];
1.54 +struct virt_header *virt_header=(struct virt_header *)virt_buffer;
1.55 +int virtualMissing=0, virt_off=-1, virt_regular;
1.56 +char *real_virt_name=0;
1.57 +
1.58 +extern int virtual;
1.59 +extern int disknum;
1.60 +extern char *virt_name, *cd_dev;
1.61 +
1.62 +/****************************************************************************/
1.63 +
1.64 +void Vopen(int ro)
1.65 +{
1.66 + Vclose();
1.67 + if(!virtual) {
1.68 + if((fd=open64(cd_dev,O_RDONLY|O_NONBLOCK))<0)
1.69 + error("Open failed (device)");
1.70 + }
1.71 + else {
1.72 + free(real_virt_name);
1.73 + if(disknum==1) {
1.74 + real_virt_name=strdup(virt_name);
1.75 + }
1.76 + else if(virt_off>0) {
1.77 + char *strip=strdup(virt_name);
1.78 + char *dot=rindex(strip,'.');
1.79 + if(dot) {
1.80 + *dot=0;
1.81 + asprintf(&real_virt_name,"%s.%d",strip,disknum+virt_off);
1.82 + }
1.83 + else serror("Bad filename format");
1.84 + free(strip);
1.85 + }
1.86 + else {
1.87 + asprintf(&real_virt_name,"%s.%d",virt_name,disknum);
1.88 + }
1.89 + DEBUG("Vopen: real filename is '%s' disknum=%d virt_off=%d\n",
1.90 + real_virt_name,disknum,virt_off);
1.91 + virtualMissing=0; virt_regular=0;
1.92 + if((fd=open64(real_virt_name,ro ? O_RDONLY:O_RDWR))<0) {
1.93 + if(errno==EACCES || errno==ENOENT || errno==ENOTDIR) {
1.94 + virtualMissing=1; virt_regular=1;
1.95 + DEBUG("Vopen: missing virtual image, assuming an empty one\n");
1.96 + }
1.97 + else error("Open failed (virtual)");
1.98 + }
1.99 + else {
1.100 + struct stat64 st;
1.101 + if(fstat64(fd,&st)<0) error("Stat failed (virtual)");
1.102 + if(S_ISREG(st.st_mode)) virt_regular=1;
1.103 + }
1.104 + }
1.105 +}
1.106 +
1.107 +/****************************************************************************/
1.108 +
1.109 +void Vclose(void)
1.110 +{
1.111 + if(fd>=0) {
1.112 + close(fd);
1.113 + fd=-1;
1.114 + }
1.115 +}
1.116 +
1.117 +/****************************************************************************/
1.118 +
1.119 +int VisRegular(void)
1.120 +{
1.121 + return virt_regular;
1.122 +}
1.123 +
1.124 +/****************************************************************************/
1.125 +
1.126 +static int VgetCdHeader(struct cd_header *cd)
1.127 +{
1.128 + if(virtualMissing) {
1.129 + if(verbose)
1.130 + fprintf(stderr,"%s: Unable to get virtual image header, assuming new virtual image\n",prg_name);
1.131 + memset(virt_buffer,0,VIRT_HEADER_LEN);
1.132 + virt_header->magic=VIRT_MAGIC;
1.133 + virt_header->version=VIRT_VERSION;
1.134 + virt_header->leadout=1;
1.135 + virt_header->count=disknum + (virt_off>0 ? virt_off:0);
1.136 + }
1.137 + else {
1.138 + int n;
1.139 + if((n=read(fd,virt_buffer,VIRT_HEADER_LEN))<0)
1.140 + error("Read failed (virtual header)");
1.141 + if(n!=VIRT_HEADER_LEN)
1.142 + serror("Short read on virtual header");
1.143 + if(virt_header->magic!=VIRT_MAGIC)
1.144 + serror("Missing magic value in virtual header. Really a virtual image?");
1.145 + if(virt_header->version>VIRT_VERSION)
1.146 + serror("Don't know how to handle this virtual image version");
1.147 + }
1.148 +
1.149 + if(virt_off<0 && disknum==1) {
1.150 + virt_off=virt_header->count-1;
1.151 + DEBUG("VgetCdHeader: setting virt_off=%d\n",virt_off);
1.152 + }
1.153 + cd->start_track=1; cd->end_track=virt_header->tracks;
1.154 + cd->used=virt_header->leadout;
1.155 + return cd->end_track;
1.156 +}
1.157 +
1.158 +/****************************************************************************/
1.159 +
1.160 +static void VgetCdTrack(int num, struct cd_track *cd)
1.161 +{
1.162 + cd->start_sec=virt_header->start[num-1];
1.163 + cd->leadout_size=0;
1.164 + cd->is_data=1;
1.165 +}
1.166 +
1.167 +/****************************************************************************/
1.168 +
1.169 +int VreadToc(int trackInfos)
1.170 +{
1.171 + struct cd_track cd_track;
1.172 + int i, tracks;
1.173 +
1.174 + tracks=virtual ? VgetCdHeader(&cd_header) : getCdHeader(&cd_header);
1.175 + if(!tracks) {
1.176 + cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE;
1.177 + DEBUG("Vreadtoc: empty media\n");
1.178 + return 0;
1.179 + }
1.180 + DEBUG("Vreadtoc: starttrack=%d endtrack=%d tracks=%d\n",
1.181 + cd_header.start_track,cd_header.end_track,tracks);
1.182 +
1.183 + cd_used =(long long)cd_header.used*CD_FRAMESIZE;
1.184 + cd_avail =(long long)cd_len*CD_FRAMESIZE-cd_used;
1.185 + if(cd_avail<0) cd_avail=0;
1.186 + DEBUG("Vreadtoc: cd_used=%lld (%lld secs) cd_avail=%lld (%lld secs)\n",
1.187 + cd_used,cd_used/CD_FRAMESIZE,cd_avail,cd_avail/CD_FRAMESIZE);
1.188 +
1.189 + free(toc);
1.190 + if(!(toc=calloc(tracks,sizeof(struct toc_entry)))) serror("No memory for TOC");
1.191 +
1.192 + cd_track.start_track=cd_header.start_track;
1.193 + for(i=tracks-1; i>=0; i--) {
1.194 + int t=cd_header.start_track+i;
1.195 + if(virtual) VgetCdTrack(t,&cd_track); else getCdTrack(t,&cd_track);
1.196 + toc[i].track_no=t;
1.197 + toc[i].sec_start=cd_track.start_sec;
1.198 + toc[i].sec_end=((i==tracks-1) ? cd_header.used : toc[i+1].sec_start)-1-cd_track.leadout_size;
1.199 + toc[i].is_data=cd_track.is_data;
1.200 + DEBUG("Vreadtoc: index=%d track=%d sec_start=%d sec_end=%d data=%d\n",
1.201 + i,t,toc[i].sec_start,toc[i].sec_end,toc[i].is_data);
1.202 + }
1.203 +
1.204 + if(trackInfos) {
1.205 + for(i=0; i<tracks; i++) {
1.206 + char inbuffer[CD_FRAMESIZE];
1.207 + struct header_block *track_header=(struct header_block *)inbuffer;
1.208 +
1.209 + if(toc[i].is_data) {
1.210 + Vseek(i);
1.211 + Vread(inbuffer);
1.212 + if(!strncmp(SHORT_HDR,track_header->id_str,strlen(SHORT_HDR))) {
1.213 + toc[i].is_cdbackup=1;
1.214 + strncpy(toc[i].id_str,track_header->id_str,32); toc[i].id_str[32]=0;
1.215 + strncpy(toc[i].vol_id, track_header->vol_id,32); toc[i].vol_id[32]=0;
1.216 + strncpy(toc[i].t_stamp, track_header->t_stamp,12); toc[i].t_stamp[12]=0;
1.217 + toc[i].disk_set = track_header->disk_set;
1.218 + toc[i].flags = track_header->flags;
1.219 + }
1.220 + }
1.221 + }
1.222 + }
1.223 +
1.224 + return tracks;
1.225 +}
1.226 +
1.227 +/****************************************************************************/
1.228 +
1.229 +const char *VdevName(void)
1.230 +{
1.231 + static char buff[80];
1.232 + if(virtual) snprintf(buff,sizeof(buff),"image %s",virt_name);
1.233 + else snprintf(buff,sizeof(buff),"device %s",cd_dev);
1.234 + return buff;
1.235 +}
1.236 +
1.237 +/****************************************************************************/
1.238 +
1.239 +void VprintSpace(void)
1.240 +{
1.241 + if(verbose) {
1.242 + char flex1[16], flex2[16], flex3[16];
1.243 + fprintf(stderr,
1.244 + "Disk size: %s (%7ld blocks)\n"
1.245 + "Space used: %s (%7lld blocks)\n"
1.246 + "Space avail:%s (%7lld blocks)\n",
1.247 + FlexSize(flex1,(long long)cd_len*CD_FRAMESIZE),cd_len,
1.248 + FlexSize(flex2,cd_used), cd_used/CD_FRAMESIZE,
1.249 + FlexSize(flex3,cd_avail), cd_avail/CD_FRAMESIZE);
1.250 + }
1.251 +}
1.252 +
1.253 +/****************************************************************************/
1.254 +
1.255 +long long Vseek(int trackNum)
1.256 +{
1.257 + long long pos=0;
1.258 + if(trackNum>=0) pos=(long long)toc[trackNum].sec_start*CD_FRAMESIZE;
1.259 + DEBUG("Vseek: seeking to index %d, track %d, offset %lld (%s)\n",
1.260 + trackNum,toc[trackNum].track_no,pos,virtual ? "virtual":"real");
1.261 + if(lseek64(fd,pos,SEEK_SET)<0) error("Seek failed");
1.262 + return pos;
1.263 +}
1.264 +
1.265 +/****************************************************************************/
1.266 +
1.267 +void Vread(void *buf)
1.268 +{
1.269 + if(full_read(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE)
1.270 + serror("Unexpected EOF reading data");
1.271 +}
1.272 +
1.273 +/****************************************************************************/
1.274 +
1.275 +static unsigned long r_ahead, r_fahead;
1.276 +
1.277 +void VgetAhead(void)
1.278 +{
1.279 + if(!virtual) get_param(fd,&r_ahead,&r_fahead);
1.280 +}
1.281 +
1.282 +/****************************************************************************/
1.283 +
1.284 +void VsetAhead(int restore)
1.285 +{
1.286 + if(!virtual) {
1.287 + if(restore) set_param(fd,r_ahead,r_fahead);
1.288 + else set_param(fd,0,0);
1.289 + }
1.290 +}