Logo Search packages:      
Sourcecode: udftools version File versions  Download package

wrudf-cdr.c

/*    wrudf-cdr.c 
 *
 */

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "wrudf.h"
#include "ide-pc.h"
#include "bswap.h"

char  *blockBuffer;
uint32_t    newVATindex;
uint32_t    sizeVAT;
uint32_t    prevVATlbn;
uint64_t  CDRuniqueID;              // from VAT FE


uint32_t newVATentry() {

    if( newVATindex + 10 > (sizeVAT >> 2) ) {         // ensure enough spave for regid and prevVATlbn
      sizeVAT += 2048;
      vat = realloc(vat, sizeVAT);
      if( vat == NULL )
          printf("VAT reallocation failed\n");
    }
    /* could go through VAT and try to find unused 0xFFFFFFFF entry rather than alloc new one at the end */
    vat[newVATindex] = getNWA() - pd->partitionStartingLocation;
    return newVATindex++;
}

uint32_t    getNWA() {
    if( devicetype == DISK_IMAGE )
      return lseek(device, 0, SEEK_END) >> 11;

    if( read_trackinfo(device, &ti, lastTrack) )
      printf("Get Track Info failed\n");

    if( ti.nwa_v )
      return ti.nwa;
    else
      return INVALID;
}

uint32_t getMaxVarPktSize() {
    struct cdrom_buffercapacity bc;

    if( devicetype == DISK_IMAGE  )
      return 1024 * 2048;                 // nonsense value; just for testing

    read_buffercapacity(device, &bc);

    return ((bc.freeBufferLength >> 11) - 20) << 11;  // - 20 :: keep some spare blocks ???
}

char* readCDR(uint32_t lbn, uint16_t partition) {
    int           stat;
    uint32_t      pbn = getPhysical(lbn, partition);


    if( devicetype == DISK_IMAGE  ) {
      stat = lseek(device, 2048 * pbn, SEEK_SET);
      stat = read(device, blockBuffer, 2048);
      if( stat != 2048 )
          fail("readCDR(hd) failed %m\n");
      else
          return blockBuffer;
    }

    stat = readCD(device, sectortype, pbn, 1, blockBuffer);

    if( stat ) {
      if( ! ignoreReadError )
          printf("readCDR: %s\n", get_sense_string());
      return NULL;
    }
    return blockBuffer;
}    

void
writeHD(uint32_t physical, char* src) 
{
    int           stat;

    stat = lseek(device, 2048 * physical, SEEK_SET);
    stat = write(device, src, 2048);

    if( stat != 2048 ) {
      printf("writeHD failed %m\n");
    }
}

void syncCDR() {
//    uint32_t nwa;

    if( device == DISK_IMAGE )
      return;

    synchronize_cache(device);
//    nwa = getNWA();
//    printf("Link from %d to %d\n", nwa-7, nwa-1);
}

void writeHDlink() {
    uint32_t blk = getNWA();
    int           i;

    for(i = 0; i < 7; i++ )
      writeHD(blk+i, blockBuffer);
}



/*    writeBlockCDR()
 *    Writes one 2048 byte block
 */
uint32_t
writeCDR(void* src) {
    uint32_t      physical;

    physical = getNWA();
//    printf("Write CDR sector %d\n", physical);

    if( devicetype == DISK_IMAGE )
      writeHD(physical, src);
    else {
      writeCD(device, physical, 1, src);
    }
    return physical;
}


/*    flagError
 *    split up extent in (1) good, (2) bad and (3) good subextents.
 *    In bad extent (2) set logicalBlockNum to zero
 *    If (1) is empty, maybe (2) can be merged with immediately preceding bad extent
 */
long_ad *
flagError(long_ad *extents, long_ad *ext, uint32_t pbn) 
{
    uint32_t lbn = pbn - pd->partitionStartingLocation;
    int     posInExtent = lbn - ext->extLocation.logicalBlockNum + 1;
    int     blksInExtent = (ext->extLength + 2047) >> 11;

    /* if there is a preceding extent which is bad and 
     * the current bad block is the first in this extent, 
     * then add this bad to the preceding extent
     */
    if( ext > extents && lbn == ext->extLocation.logicalBlockNum && !ext[-1].extLocation.logicalBlockNum ) {
      if( ext[0].extLength < 2048 ) {
          ext[-1].extLength += ext[0].extLength;
          ext[0].extLength = 0;
      } else {
          ext[-1].extLength += 2048;
          ext[0].extLength -= 2048;
          ext[0].extLocation.logicalBlockNum++;
      }
      return ext - 1;
    }

    /* watch one block extents */
    if( blksInExtent == 1 ) {
      ext[0].extLocation.logicalBlockNum = 0;
      return ext;
    }

    /* 1st block of extent is bad */
    if( posInExtent == 1 ) {
      memmove(ext+1, ext, extents - ext + 62);
      ext[0].extLength = 2048;
      ext[0].extLocation.logicalBlockNum = 0;
      ext[1].extLength -= 2048;
      ext[1].extLocation.logicalBlockNum = lbn + 1;
      return ext;
    }

    /* last block of extent is bad - watch partial block */
    if( posInExtent == blksInExtent ) {
      memmove(ext+1, ext, extents - ext + 62);
      ext[1].extLength = ext->extLength - 2048;
      ext[1].extLocation.logicalBlockNum = 0;
      ext[0].extLength -= ext[1].extLength;
      return ext;
    }

    /* middle block in extent is bad */
    memmove(ext+2, ext, extents - ext + 61);
    memcpy(ext+1, ext, sizeof(long_ad));
    ext[0].extLength = 2048 * posInExtent;
    ext[1].extLength = 2048;
    ext[1].extLocation.logicalBlockNum = 0;
    ext[2].extLength -= ext[0].extLength + 2048;
    ext[2].extLocation.logicalBlockNum = lbn + 1;
    return ext+1;
}

int verifyCDR(struct fileEntry *fe) {
    long_ad *ext, *extents;
    int           processed;
    int           stat, rv = 0;
    uint32_t      pbn, pbnFE, rewriteBlkno;

    setStrictRead(1);
    extents = ext = (long_ad*)(fe->allocDescs + fe->lengthExtendedAttr);
    processed = 0;
    pbnFE = vat[fe->descTag.tagLocation] + pd->partitionStartingLocation;
    pbn = ext->extLocation.logicalBlockNum + pd->partitionStartingLocation;

    if( (fe->icbTag.flags & ICBTAG_FLAG_AD_MASK) == ICBTAG_FLAG_AD_IN_ICB )
      goto FileEntryOnly;

    do {
      if( pbn > pbnFE ) {
          if( devicetype == DISK_IMAGE ) {
            printf("Verify %d\n", pbn);
            stat = 0;
//          if( (pbn == 557) || pbn == 565 ) stat = 1;      /* for testing only */
          } else 
            stat = readCD(device, sectortype, pbn, 1, blockBuffer);

          if( stat ) {
            printf("readError %d : %s\n", pbn, get_sense_string());
            rv++;
            ext = flagError(extents, ext, pbn);
            processed = ext->extLength - 2048;
          }
      }
      processed += 2048;
      pbn++;

      if( processed == ext->extLength ) {
          ext++;
          pbn = ext->extLocation.logicalBlockNum + pd->partitionStartingLocation;
          processed = 0;
      }
    } while (processed < ext->extLength);

  FileEntryOnly:
    if( rv == 0 ) {                       /* no errors in data, now verify FileEntry */
      int retries;

      for( retries = 0; retries < 3; retries++ ) {
          if( devicetype == DISK_IMAGE ) {
            printf("Verify %d\n", pbnFE);
            stat = 0;
//          if( pbnFE  == 552 || pbnFE == 553 ) stat = 1;   /* testing only */
          } else 
            stat = readCD(device, sectortype, pbnFE, 1, blockBuffer);

          if( stat == 0 ) {
            setStrictRead(0);
            return 0;
          }
          printf("readError %d : %s\n", pbnFE, get_sense_string());
          pbnFE = getNWA();
          vat[fe->descTag.tagLocation] = pbnFE - pd->partitionStartingLocation;
          writeCDR(fe);
      }
      printf("verifyCDR: verify FE failed 3 times\n"); 
    }

    setStrictRead(0);

    rewriteBlkno = getNWA() + 1 - pd->partitionStartingLocation;        // NWA itself for revised FileEntry

    fe->lengthAllocDescs = 0;
    for( ext = extents; ext->extLength; ext++ ) {
      fe->lengthAllocDescs += sizeof(long_ad);
      if( ext->extLocation.logicalBlockNum != 0 )
          continue;
      ext->extLocation.logicalBlockNum = rewriteBlkno;
      rewriteBlkno += ext->extLength >> 11;
      if( ext->extLength & 2047 )
          break;
    }
    fe->descTag.descCRCLength = sizeof(struct fileEntry) + fe->lengthExtendedAttr + fe->lengthAllocDescs - 16;
    return rv;
}

void readVATtable() {
    uint32_t      blkno;
    struct fileEntry *fe;

    blkno = getNWA() - (devicetype == DISK_IMAGE ? 1 : 8);
    prevVATlbn = blkno;
    fe = (struct fileEntry*)readTaggedBlock(blkno, ABSOLUTE);

    if( fe->descTag.tagIdent != TAG_IDENT_FE ||  fe->icbTag.fileType != 0 )
      fail("VAT ICB not found\n");
      
    CDRuniqueID  = fe->uniqueID;
    sizeVAT = ((fe->informationLength + 4095) & ~2047);
    vat = malloc(sizeVAT);
    memset(vat, 0xFF, sizeVAT);                       // later or not at all
    newVATindex = (fe->informationLength - 36) >> 2;

    if( sizeof(*fe) + fe->lengthExtendedAttr + fe->informationLength <= 2048 ) {
      memcpy(vat, fe->allocDescs + fe->lengthExtendedAttr, fe->informationLength - 36);
    } else {
      readExtents((char*)vat, 1, fe->allocDescs + fe->lengthExtendedAttr);
    }
}


void 
writeVATtable() 
{
    regid   *id;
    struct fileEntry *fe;
    int           stat, i, retries, size;
    uint32_t      startBlk;
    short_ad      *ext;

    retries = 0;

    id = (regid*)(&vat[newVATindex]);
    memset(id, 0, sizeof(regid));
    strcpy(id->ident, UDF_ID_ALLOC);
    *(uint16_t*)id->identSuffix = 0x150;
    id->identSuffix[2] = UDF_OS_CLASS_UNIX;
    id->identSuffix[3] = UDF_OS_ID_LINUX;
    *(uint32_t*)(id+1) = prevVATlbn;

    fe = makeFileEntry();
    size = (newVATindex + 9) << 2;
    fe->informationLength = cpu_to_le64(size);
    fe->descTag.tagSerialNum = lvid->descTag.tagSerialNum;
    fe->icbTag.fileType = ICBTAG_FILE_TYPE_UNDEF;
    fe->fileLinkCount = 0;

    for( retries = 0; retries < 8; retries++ ) {
      startBlk = getNWA();

      if( sizeof(*fe) + size < 2048 ) {
          fe->icbTag.flags = ICBTAG_FLAG_AD_IN_ICB;
          memcpy(fe->allocDescs, vat, size);
          fe->lengthAllocDescs = cpu_to_le32(size);
      } else {
          fe->logicalBlocksRecorded = (size + 2047) >> 11;
          fe->icbTag.flags = ICBTAG_FLAG_AD_SHORT;
          ext = (short_ad*)(fe->allocDescs + fe->lengthExtendedAttr);
          ext->extLength = size;
          ext->extPosition = startBlk  - pd->partitionStartingLocation;
          fe->lengthAllocDescs = cpu_to_le32(16);
      }

      fe->descTag.tagLocation = startBlk  - pd->partitionStartingLocation + fe->logicalBlocksRecorded;
      fe->descTag.descCRCLength = sizeof(*fe) + fe->lengthExtendedAttr + fe->lengthAllocDescs - sizeof(tag);
      setChecksum(&fe->descTag);

      for( i = 0; i < fe->logicalBlocksRecorded; i++ )
          writeCDR(vat + (i<<9));

      writeCDR(fe);

      setStrictRead(1);

      for( i = 0; i <= fe->logicalBlocksRecorded; i++ ) {   // "<=" so including FileEntry 
          if( devicetype == DISK_IMAGE ) {
            printf("Verify %d\n", startBlk+i);
            stat = 0;
          } else
            stat = readCD(device, sectortype, startBlk + i, 1, blockBuffer);

          if( stat != 0 ) {
            printf("writeVATtable verifyError %d : %s\n", startBlk + i, get_sense_string());
            break;
          }
      }
      if( stat == 0 )
          break;
    }

    if( retries == 8 )
      printf("*** writeVATtable rewrite FAILED\nLast VAT was at LBN %d\n", prevVATlbn); 

    setStrictRead(0);
}




Generated by  Doxygen 1.6.0   Back to index