cdrom.c
author nathan
Sat, 29 Dec 2007 15:23:49 +0100
branchtrunk
changeset 2 6bcb44b9edb1
parent 0 d85c12073dea
child 4 79da91042fcc
permissions -rw-r--r--
release 0.6.3
nathan@0
     1
/* cdrom.c
nathan@0
     2
Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
nathan@0
     3
nathan@0
     4
Redistribution and use in source and binary forms, with or without
nathan@0
     5
modification, are permitted provided that the following conditions are met: 
nathan@0
     6
nathan@0
     7
1. Redistributions of source code must retain the above copyright notice,
nathan@0
     8
   this list of conditions and the following disclaimer. 
nathan@0
     9
2. Redistributions in binary form must reproduce the above copyright notice,
nathan@0
    10
   this list of conditions and the following disclaimer in the documentation
nathan@0
    11
   and/or other materials provided with the distribution. 
nathan@0
    12
nathan@0
    13
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
nathan@0
    14
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
nathan@0
    15
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
nathan@0
    16
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
nathan@0
    17
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
nathan@0
    18
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
nathan@0
    19
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
nathan@0
    20
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
nathan@0
    21
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
nathan@0
    22
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
nathan@0
    23
SUCH DAMAGE.
nathan@0
    24
*/
nathan@0
    25
nathan@0
    26
#define _LARGEFILE64_SOURCE
nathan@0
    27
nathan@0
    28
#include <stdlib.h>
nathan@0
    29
#include <stdio.h>
nathan@0
    30
#include <unistd.h>
nathan@0
    31
#include <fcntl.h>
nathan@0
    32
#include <string.h>
nathan@0
    33
#include <linux/cdrom.h>
nathan@2
    34
#include <linux/fs.h>
nathan@0
    35
#include <sys/ioctl.h>
nathan@0
    36
nathan@2
    37
#include "cdrom.h"
nathan@0
    38
#include "cdbackup.h"
nathan@0
    39
#include "misc.h"
nathan@2
    40
#include "debug.h"
nathan@0
    41
nathan@0
    42
/* size of leadin/out depending of how many tracks are on cd */
nathan@0
    43
#define MIN_FREE_1	(11400*CD_FRAMESIZE) /* 1th track */
nathan@0
    44
#define MIN_FREE_2	(6900*CD_FRAMESIZE)  /* 2nd and more tracks */
nathan@2
    45
/* number of (unreadable) runout sectos */
nathan@2
    46
#define RUNOUT          2
nathan@0
    47
nathan@0
    48
struct toc_entry *toc=0;
nathan@0
    49
long long cd_used, cd_avail;
nathan@0
    50
nathan@0
    51
extern long cd_len;
nathan@0
    52
extern int verbose;
nathan@0
    53
extern char *prg_name;
nathan@0
    54
nathan@0
    55
/****************************************************************************/
nathan@0
    56
nathan@0
    57
int open_cdr(char *device) 
nathan@0
    58
{
nathan@0
    59
  return open(device, O_RDONLY | O_NONBLOCK);
nathan@0
    60
}
nathan@0
    61
nathan@0
    62
/****************************************************************************/
nathan@0
    63
nathan@0
    64
void close_cdr(int cd_fd)
nathan@0
    65
{
nathan@0
    66
  close(cd_fd);
nathan@0
    67
}
nathan@0
    68
nathan@0
    69
/****************************************************************************/
nathan@0
    70
nathan@2
    71
void get_param(int fd, unsigned long *ahead, unsigned long *fahead)
nathan@2
    72
{
nathan@2
    73
#if defined(BLKRAGET) && defined(BLKFRAGET)
nathan@2
    74
  *ahead = *fahead = 0;
nathan@2
    75
  ioctl(fd,BLKRAGET,ahead);
nathan@2
    76
  ioctl(fd,BLKFRAGET,fahead);
nathan@2
    77
  DEBUG("get_param: readahead=%ld freadahead=%ld\n",*ahead,*fahead);
nathan@2
    78
#else
nathan@2
    79
  fprintf("Can't get readahead parameter. Ioctl's not available\n");
nathan@2
    80
#endif
nathan@2
    81
}
nathan@2
    82
nathan@2
    83
/****************************************************************************/
nathan@2
    84
nathan@2
    85
void set_param(int fd, unsigned long ahead, unsigned long fahead)
nathan@2
    86
{
nathan@2
    87
#if defined(BLKRAGET) && defined(BLKFRAGET)
nathan@2
    88
  ioctl(fd, BLKRASET, ahead);
nathan@2
    89
  ioctl(fd, BLKFRASET, fahead);
nathan@2
    90
  DEBUG("set_param: readahead=%ld freadahead=%ld\n",ahead,fahead);
nathan@2
    91
#else
nathan@2
    92
  fprintf("Can't set readahead parameter. Ioctl's not available\n");
nathan@2
    93
#endif
nathan@2
    94
}
nathan@2
    95
nathan@2
    96
/****************************************************************************/
nathan@2
    97
nathan@0
    98
int full_read(int fd, void *buf, int count)
nathan@0
    99
{
nathan@0
   100
  int total=0;
nathan@0
   101
nathan@0
   102
  while(count>0) {
nathan@0
   103
    int bytes;
nathan@0
   104
    bytes=read(fd,buf,count); if(bytes<0) return bytes;
nathan@0
   105
    if(bytes==0) break;
nathan@0
   106
    count-=bytes; total+=bytes; buf+=bytes;
nathan@0
   107
    }
nathan@0
   108
  return total;
nathan@0
   109
}
nathan@0
   110
nathan@0
   111
/****************************************************************************/
nathan@0
   112
nathan@0
   113
void free_toc()
nathan@0
   114
{
nathan@0
   115
  if(toc) { free(toc); toc=0; }
nathan@0
   116
}
nathan@0
   117
nathan@0
   118
/****************************************************************************/
nathan@0
   119
nathan@0
   120
int read_toc(int cd_fd, int trackinfos)
nathan@0
   121
{
nathan@0
   122
  int i;
nathan@0
   123
  struct cdrom_tochdr cd_header;
nathan@0
   124
  struct cdrom_tocentry cd_entry;
nathan@0
   125
  int tracks,start_track;
nathan@0
   126
 
nathan@0
   127
  /* read table of contents header */
nathan@0
   128
  if(ioctl(cd_fd,CDROMREADTOCHDR,&cd_header)) {
nathan@0
   129
    if(verbose) fprintf(stderr,"%s: Unable to read CD header, assuming empty CD-R\n", prg_name);
nathan@0
   130
    cd_used=0; cd_avail=(long long)cd_len*CD_FRAMESIZE; return 0;
nathan@0
   131
    }
nathan@0
   132
nathan@0
   133
  /* get start and end tracks */
nathan@0
   134
  start_track = cd_header.cdth_trk0;
nathan@0
   135
  tracks = cd_header.cdth_trk1-start_track+1;
nathan@2
   136
  DEBUG("read_toc: starttrack=%d tracks=%d\n",start_track,tracks);
nathan@0
   137
nathan@0
   138
  free_toc();
nathan@0
   139
  if(!(toc=calloc(tracks+1,sizeof(struct toc_entry)))) serror("No memory for TOC");
nathan@0
   140
nathan@0
   141
  /* set some parameters */
nathan@0
   142
  cd_entry.cdte_format=CDROM_LBA;
nathan@0
   143
nathan@0
   144
  /* read lead-out */
nathan@0
   145
  cd_entry.cdte_track=CDROM_LEADOUT;
nathan@0
   146
  if(ioctl(cd_fd,CDROMREADTOCENTRY,&cd_entry)) error("Error reading lead-out");
nathan@0
   147
nathan@0
   148
  toc[0].track_no=CDROM_LEADOUT;  /* not a real track */
nathan@0
   149
  toc[0].sec_start=cd_entry.cdte_addr.lba;
nathan@0
   150
nathan@2
   151
  cd_used  =(long long)toc[0].sec_start*CD_FRAMESIZE;
nathan@2
   152
  cd_avail =(long long)cd_len*CD_FRAMESIZE-cd_used;
nathan@0
   153
  cd_avail-=(tracks>1?MIN_FREE_2:MIN_FREE_1);
nathan@2
   154
  DEBUG("read_toc: cd_used=%lld (%lld secs) cd_avail=%lld (%lld secs)\n",cd_used,cd_used/CD_FRAMESIZE,cd_avail,cd_avail/CD_FRAMESIZE);
nathan@2
   155
nathan@0
   156
  if(cd_avail<0) cd_avail=0; /* can be <0 due to assumed additional lead-in/out */
nathan@0
   157
nathan@0
   158
  /* read rest of tracks */
nathan@0
   159
  for(i=1; i<=tracks; i++) {
nathan@0
   160
    cd_entry.cdte_track=start_track+i-1;
nathan@0
   161
    if(ioctl(cd_fd,CDROMREADTOCENTRY,&cd_entry)) error("Error reading TOC");  
nathan@0
   162
nathan@0
   163
    toc[i].track_no=start_track+i-1;
nathan@0
   164
    toc[i].sec_start=cd_entry.cdte_addr.lba;
nathan@0
   165
    if(cd_entry.cdte_ctrl&CDROM_DATA_TRACK) toc[i].is_data=1;
nathan@0
   166
    }    
nathan@0
   167
nathan@2
   168
  /* calculate end sectors */
nathan@2
   169
  toc[tracks].sec_end = toc[  0].sec_start - 1 - RUNOUT;
nathan@2
   170
  for(i=1; i<tracks; i++)
nathan@2
   171
    toc[i].sec_end = toc[i+1].sec_start - 1 - RUNOUT - (i>1?(MIN_FREE_2/CD_FRAMESIZE):(MIN_FREE_1/CD_FRAMESIZE));
nathan@2
   172
nathan@0
   173
 if(trackinfos)
nathan@0
   174
  /* now loop through tracks and read header info */
nathan@0
   175
  for(i=1; i<=tracks; i++) {
nathan@0
   176
    char inbuffer[CD_FRAMESIZE];
nathan@0
   177
    struct header_block *track_header=(struct header_block *)&inbuffer[0];
nathan@0
   178
nathan@0
   179
    if (toc[i].is_data == 1) {
nathan@0
   180
      if(lseek64(cd_fd,(long long)toc[i].sec_start*CD_FRAMESIZE,SEEK_SET)<0) error("Seek failed");
nathan@0
   181
nathan@0
   182
      if(full_read(cd_fd,inbuffer,CD_FRAMESIZE)==CD_FRAMESIZE) {
nathan@0
   183
        if(!strncmp(SHORT_HDR,track_header->id_str,strlen(SHORT_HDR))) {
nathan@0
   184
          toc[i].is_cdbackup=1;
nathan@0
   185
          strncpy(toc[i].id_str,track_header->id_str,32); toc[i].id_str[32]=0;
nathan@0
   186
          strncpy(toc[i].vol_id, track_header->vol_id,32); toc[i].vol_id[32]=0;
nathan@0
   187
          strncpy(toc[i].t_stamp, track_header->t_stamp,12); toc[i].t_stamp[12]=0;
nathan@0
   188
          toc[i].disk_set = track_header->disk_set;
nathan@0
   189
          }
nathan@0
   190
        }      
nathan@0
   191
      }
nathan@0
   192
    }
nathan@0
   193
  
nathan@0
   194
  return tracks;
nathan@0
   195
}
nathan@0
   196
nathan@0
   197
/****************************************************************************/
nathan@0
   198
nathan@0
   199
void print_space() 
nathan@0
   200
{
nathan@0
   201
  if(verbose)
nathan@0
   202
    fprintf(stderr,
nathan@0
   203
      "Disk size:  %7lld kB (%7ld blocks)\n"
nathan@0
   204
      "Space used: %7lld kB (%7lld blocks)\n"
nathan@0
   205
      "Space avail:%7lld kB (%7lld blocks)\n",
nathan@0
   206
      (long long)cd_len*CD_FRAMESIZE/1024,cd_len,
nathan@0
   207
      cd_used/1024, cd_used/CD_FRAMESIZE,
nathan@0
   208
      cd_avail/1024, cd_avail/CD_FRAMESIZE);
nathan@0
   209
}