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)
nathan@4
     1
/* virtual.c
nathan@4
     2
Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
nathan@4
     3
nathan@4
     4
Redistribution and use in source and binary forms, with or without
nathan@4
     5
modification, are permitted provided that the following conditions are met: 
nathan@4
     6
nathan@4
     7
1. Redistributions of source code must retain the above copyright notice,
nathan@4
     8
   this list of conditions and the following disclaimer. 
nathan@4
     9
2. Redistributions in binary form must reproduce the above copyright notice,
nathan@4
    10
   this list of conditions and the following disclaimer in the documentation
nathan@4
    11
   and/or other materials provided with the distribution. 
nathan@4
    12
nathan@4
    13
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
nathan@4
    14
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
nathan@4
    15
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
nathan@4
    16
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
nathan@4
    17
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
nathan@4
    18
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
nathan@4
    19
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
nathan@4
    20
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
nathan@4
    21
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
nathan@4
    22
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
nathan@4
    23
SUCH DAMAGE.
nathan@4
    24
*/
nathan@4
    25
nathan@4
    26
#define _LARGEFILE64_SOURCE
nathan@4
    27
#define _GNU_SOURCE
nathan@4
    28
nathan@4
    29
#include <stdlib.h>
nathan@4
    30
#include <stdio.h>
nathan@4
    31
#include <unistd.h>
nathan@4
    32
#include <fcntl.h>
nathan@4
    33
#include <errno.h>
nathan@4
    34
#include <string.h>
nathan@4
    35
#include <sys/wait.h>
nathan@4
    36
#include <sys/stat.h>
nathan@4
    37
nathan@4
    38
#include "virtual.h"
nathan@4
    39
#include "cdbackup.h"
nathan@4
    40
#include "cdrom.h"
nathan@4
    41
#include "misc.h"
nathan@4
    42
#include "debug.h"
nathan@4
    43
nathan@4
    44
int fd=-1;
nathan@4
    45
struct toc_entry *toc=0;
nathan@4
    46
long long cd_used, cd_avail;
nathan@4
    47
nathan@4
    48
static struct cd_header cd_header;
nathan@4
    49
nathan@4
    50
static unsigned char virt_buffer[VIRT_HEADER_LEN];
nathan@4
    51
struct virt_header *virt_header=(struct virt_header *)virt_buffer;
nathan@6
    52
int virtualMissing=0, virt_off=-1, virt_regular=0;
nathan@4
    53
char *real_virt_name=0;
nathan@4
    54
nathan@4
    55
extern int virtual;
nathan@4
    56
extern int disknum;
nathan@4
    57
extern char *virt_name, *cd_dev;
nathan@4
    58
nathan@4
    59
/****************************************************************************/
nathan@4
    60
nathan@4
    61
void Vopen(int ro)
nathan@4
    62
{
nathan@4
    63
  Vclose();
nathan@4
    64
  if(!virtual) {
nathan@4
    65
    if((fd=open64(cd_dev,O_RDONLY|O_NONBLOCK))<0)
nathan@4
    66
      error("Open failed (device)");
nathan@4
    67
    }
nathan@4
    68
  else {
nathan@4
    69
    free(real_virt_name);
nathan@6
    70
    if(disknum==1 || !virt_regular) {
nathan@4
    71
      real_virt_name=strdup(virt_name);
nathan@4
    72
      }
nathan@4
    73
    else if(virt_off>0) {
nathan@4
    74
      char *strip=strdup(virt_name);
nathan@4
    75
      char *dot=rindex(strip,'.');
nathan@4
    76
      if(dot) {
nathan@4
    77
        *dot=0;
nathan@13
    78
        if(asprintf(&real_virt_name,"%s.%d",strip,disknum+virt_off)<0)
nathan@13
    79
          error("error making virtual name");
nathan@4
    80
        }
nathan@4
    81
      else serror("Bad filename format");
nathan@4
    82
      free(strip);
nathan@4
    83
      }
nathan@4
    84
    else {
nathan@13
    85
      if(asprintf(&real_virt_name,"%s.%d",virt_name,disknum)<0)
nathan@13
    86
        error("error making virtual name");
nathan@4
    87
      }
nathan@4
    88
    DEBUG("Vopen: real filename is '%s' disknum=%d virt_off=%d\n",
nathan@4
    89
          real_virt_name,disknum,virt_off);
nathan@4
    90
    virtualMissing=0; virt_regular=0;
nathan@4
    91
    if((fd=open64(real_virt_name,ro ? O_RDONLY:O_RDWR))<0) {
nathan@4
    92
      if(errno==EACCES || errno==ENOENT || errno==ENOTDIR) {
nathan@4
    93
        virtualMissing=1; virt_regular=1;
nathan@4
    94
        DEBUG("Vopen: missing virtual image, assuming an empty one\n");
nathan@4
    95
        }
nathan@4
    96
      else error("Open failed (virtual)");
nathan@4
    97
      }
nathan@4
    98
    else {
nathan@4
    99
      struct stat64 st;
nathan@4
   100
      if(fstat64(fd,&st)<0) error("Stat failed (virtual)");
nathan@4
   101
      if(S_ISREG(st.st_mode)) virt_regular=1;
nathan@4
   102
      }
nathan@4
   103
    }
nathan@4
   104
}
nathan@4
   105
nathan@4
   106
/****************************************************************************/
nathan@4
   107
nathan@4
   108
void Vclose(void)
nathan@4
   109
{
nathan@4
   110
  if(fd>=0) {
nathan@4
   111
    close(fd);
nathan@4
   112
    fd=-1;
nathan@4
   113
    }
nathan@4
   114
}
nathan@4
   115
nathan@4
   116
/****************************************************************************/
nathan@4
   117
nathan@4
   118
int VisRegular(void)
nathan@4
   119
{
nathan@4
   120
  return virt_regular;
nathan@4
   121
}
nathan@4
   122
nathan@4
   123
/****************************************************************************/
nathan@4
   124
nathan@4
   125
static int VgetCdHeader(struct cd_header *cd)
nathan@4
   126
{
nathan@4
   127
  if(virtualMissing) {
nathan@4
   128
    if(verbose) 
nathan@4
   129
      fprintf(stderr,"%s: Unable to get virtual image header, assuming new virtual image\n",prg_name);
nathan@4
   130
    memset(virt_buffer,0,VIRT_HEADER_LEN);
nathan@4
   131
    virt_header->magic=VIRT_MAGIC;
nathan@4
   132
    virt_header->version=VIRT_VERSION;
nathan@4
   133
    virt_header->leadout=1;
nathan@4
   134
    virt_header->count=disknum + (virt_off>0 ? virt_off:0);
nathan@4
   135
    }
nathan@4
   136
  else {
nathan@4
   137
    int n;
nathan@4
   138
    if((n=read(fd,virt_buffer,VIRT_HEADER_LEN))<0) 
nathan@4
   139
      error("Read failed (virtual header)");
nathan@4
   140
    if(n!=VIRT_HEADER_LEN) 
nathan@4
   141
      serror("Short read on virtual header");
nathan@4
   142
    if(virt_header->magic!=VIRT_MAGIC) 
nathan@4
   143
      serror("Missing magic value in virtual header. Really a virtual image?");
nathan@4
   144
    if(virt_header->version>VIRT_VERSION) 
nathan@4
   145
      serror("Don't know how to handle this virtual image version");
nathan@4
   146
    }
nathan@4
   147
nathan@4
   148
  if(virt_off<0 && disknum==1) {
nathan@4
   149
    virt_off=virt_header->count-1;
nathan@4
   150
    DEBUG("VgetCdHeader: setting virt_off=%d\n",virt_off);
nathan@4
   151
    }
nathan@4
   152
  cd->start_track=1; cd->end_track=virt_header->tracks;
nathan@4
   153
  cd->used=virt_header->leadout;
nathan@4
   154
  return cd->end_track;
nathan@4
   155
}
nathan@4
   156
nathan@4
   157
/****************************************************************************/
nathan@4
   158
nathan@4
   159
static void VgetCdTrack(int num, struct cd_track *cd)
nathan@4
   160
{
nathan@4
   161
  cd->start_sec=virt_header->start[num-1];
nathan@4
   162
  cd->leadout_size=0;
nathan@4
   163
  cd->is_data=1;
nathan@4
   164
}
nathan@4
   165
nathan@4
   166
/****************************************************************************/
nathan@4
   167
nathan@4
   168
int VreadToc(int trackInfos)
nathan@4
   169
{
nathan@4
   170
  struct cd_track cd_track;
nathan@4
   171
  int i, tracks;
nathan@4
   172
nathan@4
   173
  tracks=virtual ? VgetCdHeader(&cd_header) : getCdHeader(&cd_header);
nathan@4
   174
  if(!tracks) {
nathan@4
   175
    cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE;
nathan@4
   176
    DEBUG("Vreadtoc: empty media\n");
nathan@4
   177
    return 0;
nathan@4
   178
    }
nathan@4
   179
  DEBUG("Vreadtoc: starttrack=%d endtrack=%d tracks=%d\n",
nathan@4
   180
        cd_header.start_track,cd_header.end_track,tracks);
nathan@4
   181
nathan@4
   182
  cd_used  =(long long)cd_header.used*CD_FRAMESIZE;
nathan@4
   183
  cd_avail =(long long)cd_len*CD_FRAMESIZE-cd_used;
nathan@4
   184
  if(cd_avail<0) cd_avail=0;
nathan@4
   185
  DEBUG("Vreadtoc: cd_used=%lld (%lld secs) cd_avail=%lld (%lld secs)\n",
nathan@4
   186
        cd_used,cd_used/CD_FRAMESIZE,cd_avail,cd_avail/CD_FRAMESIZE);
nathan@4
   187
nathan@4
   188
  free(toc);
nathan@4
   189
  if(!(toc=calloc(tracks,sizeof(struct toc_entry)))) serror("No memory for TOC");
nathan@4
   190
nathan@4
   191
  cd_track.start_track=cd_header.start_track;
nathan@4
   192
  for(i=tracks-1; i>=0; i--) {
nathan@4
   193
    int t=cd_header.start_track+i;
nathan@4
   194
    if(virtual) VgetCdTrack(t,&cd_track); else getCdTrack(t,&cd_track);
nathan@4
   195
    toc[i].track_no=t;
nathan@4
   196
    toc[i].sec_start=cd_track.start_sec;
nathan@4
   197
    toc[i].sec_end=((i==tracks-1) ? cd_header.used : toc[i+1].sec_start)-1-cd_track.leadout_size; 
nathan@4
   198
    toc[i].is_data=cd_track.is_data;
nathan@4
   199
    DEBUG("Vreadtoc: index=%d track=%d sec_start=%d sec_end=%d data=%d\n",
nathan@4
   200
          i,t,toc[i].sec_start,toc[i].sec_end,toc[i].is_data);
nathan@4
   201
    }
nathan@4
   202
nathan@4
   203
  if(trackInfos) {
nathan@4
   204
    for(i=0; i<tracks; i++) {
nathan@4
   205
      char inbuffer[CD_FRAMESIZE];
nathan@4
   206
      struct header_block *track_header=(struct header_block *)inbuffer;
nathan@4
   207
nathan@4
   208
      if(toc[i].is_data) {
nathan@4
   209
        Vseek(i);
nathan@4
   210
        Vread(inbuffer);
nathan@4
   211
        if(!strncmp(SHORT_HDR,track_header->id_str,strlen(SHORT_HDR))) {
nathan@4
   212
          toc[i].is_cdbackup=1;
nathan@4
   213
          strncpy(toc[i].id_str,track_header->id_str,32); toc[i].id_str[32]=0;
nathan@4
   214
          strncpy(toc[i].vol_id, track_header->vol_id,32); toc[i].vol_id[32]=0;
nathan@4
   215
          strncpy(toc[i].t_stamp, track_header->t_stamp,12); toc[i].t_stamp[12]=0;
nathan@4
   216
          toc[i].disk_set = track_header->disk_set;
nathan@4
   217
          toc[i].flags = track_header->flags;
nathan@4
   218
          }
nathan@4
   219
        }
nathan@4
   220
      }
nathan@4
   221
    }
nathan@4
   222
nathan@4
   223
  return tracks;
nathan@4
   224
}
nathan@4
   225
nathan@4
   226
/****************************************************************************/
nathan@4
   227
nathan@4
   228
const char *VdevName(void)
nathan@4
   229
{
nathan@4
   230
  static char buff[80];
nathan@4
   231
  if(virtual) snprintf(buff,sizeof(buff),"image %s",virt_name);
nathan@4
   232
  else snprintf(buff,sizeof(buff),"device %s",cd_dev);
nathan@4
   233
  return buff;
nathan@4
   234
}
nathan@4
   235
nathan@4
   236
/****************************************************************************/
nathan@4
   237
nathan@4
   238
void VprintSpace(void)
nathan@4
   239
{
nathan@4
   240
  if(verbose) {
nathan@4
   241
    char flex1[16], flex2[16], flex3[16];
nathan@4
   242
    fprintf(stderr,
nathan@4
   243
      "Disk size:  %s (%7ld blocks)\n"
nathan@4
   244
      "Space used: %s (%7lld blocks)\n"
nathan@4
   245
      "Space avail:%s (%7lld blocks)\n",
nathan@4
   246
      FlexSize(flex1,(long long)cd_len*CD_FRAMESIZE),cd_len,
nathan@4
   247
      FlexSize(flex2,cd_used), cd_used/CD_FRAMESIZE,
nathan@4
   248
      FlexSize(flex3,cd_avail), cd_avail/CD_FRAMESIZE);
nathan@4
   249
    }
nathan@4
   250
}
nathan@4
   251
nathan@4
   252
/****************************************************************************/
nathan@4
   253
nathan@4
   254
long long Vseek(int trackNum)
nathan@4
   255
{
nathan@4
   256
  long long pos=0;
nathan@4
   257
  if(trackNum>=0) pos=(long long)toc[trackNum].sec_start*CD_FRAMESIZE;
nathan@4
   258
  DEBUG("Vseek: seeking to index %d, track %d, offset %lld (%s)\n",
nathan@4
   259
        trackNum,toc[trackNum].track_no,pos,virtual ? "virtual":"real");
nathan@4
   260
  if(lseek64(fd,pos,SEEK_SET)<0) error("Seek failed");
nathan@4
   261
  return pos;
nathan@4
   262
}
nathan@4
   263
nathan@4
   264
/****************************************************************************/
nathan@4
   265
nathan@4
   266
void Vread(void *buf)
nathan@4
   267
{
nathan@4
   268
  if(full_read(fd,buf,CD_FRAMESIZE)!=CD_FRAMESIZE)
nathan@4
   269
    serror("Unexpected EOF reading data");
nathan@4
   270
}
nathan@4
   271
nathan@4
   272
/****************************************************************************/
nathan@4
   273
nathan@4
   274
static unsigned long r_ahead, r_fahead;
nathan@4
   275
nathan@4
   276
void VgetAhead(void)
nathan@4
   277
{
nathan@4
   278
  if(!virtual) get_param(fd,&r_ahead,&r_fahead);
nathan@4
   279
}
nathan@4
   280
nathan@4
   281
/****************************************************************************/
nathan@4
   282
nathan@4
   283
void VsetAhead(int restore)
nathan@4
   284
{
nathan@4
   285
  if(!virtual) {
nathan@4
   286
    if(restore) set_param(fd,r_ahead,r_fahead);
nathan@4
   287
    else set_param(fd,0,0);
nathan@4
   288
    }
nathan@4
   289
}