nathan@4: /* virtual-backup.c nathan@4: Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt. nathan@4: nathan@4: Redistribution and use in source and binary forms, with or without nathan@4: modification, are permitted provided that the following conditions are met: nathan@4: nathan@4: 1. Redistributions of source code must retain the above copyright notice, nathan@4: this list of conditions and the following disclaimer. nathan@4: 2. Redistributions in binary form must reproduce the above copyright notice, nathan@4: this list of conditions and the following disclaimer in the documentation nathan@4: and/or other materials provided with the distribution. nathan@4: nathan@4: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS nathan@4: OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED nathan@4: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE nathan@4: DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR nathan@4: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL nathan@4: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR nathan@4: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER nathan@4: CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT nathan@4: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY nathan@4: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF nathan@4: SUCH DAMAGE. nathan@4: */ nathan@4: nathan@4: #define _LARGEFILE64_SOURCE nathan@4: #define _GNU_SOURCE nathan@4: nathan@4: #include nathan@4: #include nathan@4: #include nathan@4: #include nathan@4: #include nathan@4: #include nathan@4: #include nathan@4: #include nathan@4: nathan@4: #include "virtual.h" nathan@4: #include "cdbackup.h" nathan@4: #include "cdrom.h" nathan@4: #include "misc.h" nathan@4: #include "debug.h" nathan@4: nathan@4: //#define DEBUGOUT nathan@4: nathan@4: extern int virtual, multi; nathan@4: nathan@4: extern int fd; nathan@4: extern struct virt_header *virt_header; nathan@4: extern int virtualMissing; nathan@4: extern char *real_virt_name; nathan@4: nathan@4: #ifndef DEBUGOUT nathan@4: static pid_t childpid; nathan@4: #endif nathan@4: static int vfd=-1; nathan@4: nathan@4: /****************************************************************************/ nathan@4: nathan@4: void VnewTrack(void) nathan@4: { nathan@4: if(virtual) { nathan@4: long long pos; nathan@4: if(virtualMissing) { nathan@4: if((fd=open64(real_virt_name,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP| S_IROTH))<0) error("Open failed (new track)"); nathan@4: if(write(fd,virt_header,CD_FRAMESIZE)!=CD_FRAMESIZE) error("Write failed (new track)"); nathan@4: virtualMissing=0; nathan@4: } nathan@4: if(virt_header->tracks>=MAX_VIRT_TRACKS-1) serror("Maximum number of virtual tracks reached"); nathan@6: pos=(long long)(virt_header->start[virt_header->tracks]=virt_header->leadout)*CD_FRAMESIZE; nathan@4: virt_header->tracks++; nathan@4: if(lseek64(fd,pos,SEEK_SET)<0) error("Seek failed (new track)"); nathan@4: } nathan@4: else { nathan@4: #ifndef DEBUGOUT nathan@4: int pd[2]; nathan@4: Vclose(); nathan@4: if(pipe(pd)<0) error("Pipe failed (new track)"); nathan@4: if((childpid=fork())<0) error("Fork failed (new track)"); nathan@4: if(childpid==0) { /* child */ nathan@4: close(pd[1]); nathan@4: close(0); nathan@4: dup2(pd[0],0); nathan@4: start_cdrecord(); /* doesn't returns */ nathan@4: } nathan@4: close(pd[0]); fd=pd[1]; nathan@4: #else nathan@4: /* debug code; send data to /dev/null. */ nathan@4: Vclose(); nathan@4: fprintf(stderr,"DEBUG CODE: NO recording, sending data to /dev/null!\n"); nathan@4: if((fd=open("/dev/null",O_WRONLY))<0) error("Open failed (/dev/null)"); nathan@4: #endif nathan@4: cd_avail-=padsize*CD_FRAMESIZE; nathan@4: } nathan@4: } nathan@4: nathan@4: /****************************************************************************/ nathan@4: nathan@4: int Vsize(void) nathan@4: { nathan@4: return virt_header->leadout; nathan@4: } nathan@4: nathan@4: /****************************************************************************/ nathan@4: nathan@4: int VhasCont(void) nathan@4: { nathan@4: return virt_header->has_cont; nathan@4: } nathan@4: nathan@4: /****************************************************************************/ nathan@4: nathan@4: void VprepareDump(void) nathan@4: { nathan@4: if((vfd=dup(fd))<0) error("Dup failed"); nathan@4: Vclose(); nathan@4: } nathan@4: nathan@4: /****************************************************************************/ nathan@4: nathan@4: void VvirtRead(void *buf) nathan@4: { nathan@4: if(full_read(vfd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE) nathan@4: serror("Unexpected EOF reading data"); nathan@4: } nathan@4: nathan@4: /****************************************************************************/ nathan@4: nathan@4: void VcloseTrack(int cont) nathan@4: { nathan@4: if(virtual) { nathan@4: if(lseek64(fd,0,SEEK_SET)<0) error("Seek failed (close track)"); nathan@4: virt_header->has_cont=cont; nathan@4: if(write(fd,virt_header,CD_FRAMESIZE)!=CD_FRAMESIZE) error("Write failed (close track)"); nathan@4: Vclose(); nathan@4: } nathan@4: else { nathan@4: Vclose(); nathan@4: #ifndef DEBUGOUT nathan@4: DEBUG("VcloseTrack: waiting for child termination\n"); nathan@4: while(wait(0)!=childpid); nathan@4: #endif nathan@4: } nathan@4: if(vfd>=0) { close(vfd); vfd=-1; } nathan@4: } nathan@4: nathan@4: /****************************************************************************/ nathan@4: nathan@4: void Vwrite(const void *buf) nathan@4: { nathan@4: if(write(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE) error("Write failed"); nathan@4: if(virtual) virt_header->leadout++; nathan@4: cd_avail-=CD_FRAMESIZE; nathan@4: }