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