2 Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
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.
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
26 #define _LARGEFILE64_SOURCE
45 struct toc_entry *toc=0;
46 long long cd_used, cd_avail;
48 static struct cd_header cd_header;
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;
57 extern char *virt_name, *cd_dev;
59 /****************************************************************************/
65 if((fd=open64(cd_dev,O_RDONLY|O_NONBLOCK))<0)
66 error("Open failed (device)");
70 if(disknum==1 || !virt_regular) {
71 real_virt_name=strdup(virt_name);
74 char *strip=strdup(virt_name);
75 char *dot=rindex(strip,'.');
78 if(asprintf(&real_virt_name,"%s.%d",strip,disknum+virt_off)<0)
79 error("error making virtual name");
81 else serror("Bad filename format");
85 if(asprintf(&real_virt_name,"%s.%d",virt_name,disknum)<0)
86 error("error making virtual name");
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");
96 else error("Open failed (virtual)");
100 if(fstat64(fd,&st)<0) error("Stat failed (virtual)");
101 if(S_ISREG(st.st_mode)) virt_regular=1;
106 /****************************************************************************/
116 /****************************************************************************/
123 /****************************************************************************/
125 static int VgetCdHeader(struct cd_header *cd)
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);
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");
148 if(virt_off<0 && disknum==1) {
149 virt_off=virt_header->count-1;
150 DEBUG("VgetCdHeader: setting virt_off=%d\n",virt_off);
152 cd->start_track=1; cd->end_track=virt_header->tracks;
153 cd->used=virt_header->leadout;
154 return cd->end_track;
157 /****************************************************************************/
159 static void VgetCdTrack(int num, struct cd_track *cd)
161 cd->start_sec=virt_header->start[num-1];
166 /****************************************************************************/
168 int VreadToc(int trackInfos)
170 struct cd_track cd_track;
173 tracks=virtual ? VgetCdHeader(&cd_header) : getCdHeader(&cd_header);
175 cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE;
176 DEBUG("Vreadtoc: empty media\n");
179 DEBUG("Vreadtoc: starttrack=%d endtrack=%d tracks=%d\n",
180 cd_header.start_track,cd_header.end_track,tracks);
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);
189 if(!(toc=calloc(tracks,sizeof(struct toc_entry)))) serror("No memory for TOC");
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);
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);
204 for(i=0; i<tracks; i++) {
205 char inbuffer[CD_FRAMESIZE];
206 struct header_block *track_header=(struct header_block *)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;
226 /****************************************************************************/
228 const char *VdevName(void)
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);
236 /****************************************************************************/
238 void VprintSpace(void)
241 char flex1[16], flex2[16], flex3[16];
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);
252 /****************************************************************************/
254 long long Vseek(int trackNum)
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");
264 /****************************************************************************/
266 void Vread(void *buf)
268 if(full_read(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE)
269 serror("Unexpected EOF reading data");
272 /****************************************************************************/
274 static unsigned long r_ahead, r_fahead;
278 if(!virtual) get_param(fd,&r_ahead,&r_fahead);
281 /****************************************************************************/
283 void VsetAhead(int restore)
286 if(restore) set_param(fd,r_ahead,r_fahead);
287 else set_param(fd,0,0);