📄 wrudf-cdrw.c
字号:
/* wrufd-cdrw.c * * PURPOSE * Lowlevel IO routines. * To minimise reading and writing packets wrudf uses a few 64kb packetbuffers. * Blocks to be read are preferentially taken from those buffers and updates written * to the buffers. Buffers that are in-use will not be discarded. * When a new buffer is required preferentially an unused not-dirty buffer gets overwritten. * If not available, then a unused dirty buffer gets written and is then reused. * If no such buffer can be found the system panics. * * CONTACTS * E-mail regarding this program may be directed to * e.fennema@dataweb.nl * * COPYRIGHT * This file is distributed under the terms of the GNU General Public * License (GPL). Copies of the GPL can be obtained from: * ftp://prep.ai.mit.edu/pub/gnu/GPL * * (C) 2001 Enno Fennema * * HISTORY * 16 Aug 01 ef Created. */#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <linux/cdrom.h> /* for CDROM_DRIVE_STATUS */#include "wrudf.h"#include "ide-pc.h"#include "bswap.h"#define MAXPKTBUFS 4struct packetbuf { uint32_t inuse; uint32_t dirty; uint32_t bufNum; uint32_t start; uint8_t *pkt;};int lastTrack;struct cdrom_trackinfo ti;struct read_error_recovery_params *rerp;u_char *rerp_buffer;struct cdrom_cacheparams *cp;u_char *cp_buffer;struct packetbuf pktbuf[MAXPKTBUFS+1]; /* last one special use */uint8_t *verifyBuffer; /* for verify only */uint8_t *blockBuffer;uint32_t trackStart;uint32_t trackSize;int sectortype; /* from track info for readCD() *//* declarations */struct packetbuf* findBuf(uint32_t blkno);int readPacket(struct packetbuf* pb);int writePacket(struct packetbuf* pb);/* markBlock() * FREE or ALLOC block in spacemap */void markBlock(enum markAction action, uint32_t blkno) { uint8_t *bm; uint8_t mask; spaceMapDirty = 1; bm = spaceMap->bitmap + (blkno >> 3); mask = 1 << (blkno & 7); if( action == FREE ) { *bm |= mask; lvid->freeSpaceTable[pd->partitionNumber]++; } else { *bm &= ~mask; lvid->freeSpaceTable[pd->partitionNumber]--; }}/* GetExtents() * Try to find unallocated blocks for 'requestedLength' bytes in the rewriteable partition * Return short_ad's of lbns in the physical partition together satisfying that request * Last extent has length < n * 2048; if exact multiple of 2048 the a final length 0 short_ad * * Return value: lenAllocDescs if extents found, 0 if not. */int getExtents(uint32_t requestedLength, short_ad *extents) { uint32_t blkno, lengthFound = 0; short_ad *ext; uint32_t mask, *bm; if( medium == CDR ) { /* check space availability */ extents->extLength = requestedLength; extents->extPosition = getNWA() - pd->partitionStartingLocation; if( (requestedLength & 2047) == 0 ) { extents[1].extPosition = 0; extents[1].extLength = 0; return 16; } else return 8; } // clear extents ext = extents; ext->extLength = 0; bm = ((uint32_t*)spaceMap->bitmap) - 1; mask = 0; blkno = 0xFFFFFFFF; while( lengthFound < requestedLength ) { blkno++; mask <<= 1; if( mask == 0 ) { bm++; mask = 1; // check bm within limits } if( (*bm & mask) == 0 ) { // if allocated if( ext->extLength != 0 ) { ext++; if( ext - extents > 31 ) { printf("GetExtents: Too many extents\n"); return 0; } ext->extLength = 0; } continue; } if( ext->extLength == 0 ) ext->extPosition = blkno; lengthFound += 2048; ext->extLength += 2048; } if( requestedLength != lengthFound ) { ext->extLength = ((ext->extLength & ~2047) | (requestedLength & 2047)) - 2048; } else { ext++; ext->extLength = 0; ext->extPosition = 0; } return (uint8_t*)ext - (uint8_t*)extents + sizeof(short_ad);}intfreeShortExtents(short_ad* extents) { uint32_t blkno, lengthFreed; short_ad* ext; for( ext = extents; extents->extLength != 0; ext++ ) { blkno = ext->extPosition; for( lengthFreed = 0 ; lengthFreed < ext->extLength; lengthFreed += 2048 ) { markBlock(FREE, blkno); blkno++; } if( ext->extLength & 2047 || (ext+1)->extLength == 0 ) break; } return CMND_OK;} int freeLongExtents(long_ad* extents) { uint32_t blkno, lengthFreed; long_ad* ext; for( ext = extents; extents->extLength != 0; ext++ ) { if( ext->extLocation.partitionReferenceNum != pd->partitionNumber ) fail("freeLongExtents: Not RW partition\n"); blkno = ext->extLocation.logicalBlockNum; for( lengthFreed = 0 ; lengthFreed < ext->extLength; lengthFreed += 2048 ) { markBlock(FREE, blkno); blkno++; } if( ext->extLength & 2047 || (ext+1)->extLength == 0 ) break; } return CMND_OK;}/* getUnallocSpaceExtent() * Only used to get new extent for LVID sequence * (Could use to extend sparing blocks as well) */void getUnallocSpaceExtent(int requestLength, int requestAfter, extent_ad *alloc) { int i, n; alloc->extLength = alloc->extLocation = 0; n = (requestLength + 2047) & ~2047; for( i = 0; i < usd->numAllocDescs; i++ ) { if( usd->allocDescs[i].extLocation > requestAfter ) { if( usd->allocDescs[i].extLength >= requestLength ) { alloc->extLocation = usd->allocDescs[i].extLocation; alloc->extLength = n; usd->allocDescs[i].extLocation += n >> 11; usd->allocDescs[i].extLength -= n; usdDirty = 1; return; } else { alloc->extLocation = usd->allocDescs[i].extLocation; alloc->extLength = usd->allocDescs[i].extLength; usd->numAllocDescs--; for ( ; i < usd->numAllocDescs; i++ ) usd->allocDescs[i] = usd->allocDescs[i+1]; usdDirty = 1; return; } } } if( requestAfter > 0 ) getUnallocSpaceExtent( requestLength, 0, alloc);} void setChecksum(void *descriptor) { uint32_t sum; int i; tag *descTag = (tag*) descriptor; descTag->descCRC = udf_crc((uint8_t*)descTag + sizeof(tag), descTag->descCRCLength, 0); descTag->tagChecksum = sum = 0; for( i = 0; i < 16; i++ ) sum += *((uint8_t*)descTag + i); descTag->tagChecksum = (uint8_t) sum;}void updateTimestamp(time_t t, uint32_t ut) { struct timeval timev; struct tm time; int offset; if( t == 0 ) { gettimeofday(&timev, NULL); } else { timev.tv_sec = t; timev.tv_usec = ut; } localtime_r( &timev.tv_sec, &time); offset = time.tm_gmtoff / 60; timeStamp.typeAndTimezone = 0x1000 + (offset & 0x0FFF); /* 1/3.7.1 */ timeStamp.year = time.tm_year + 1900; timeStamp.month = time.tm_mon + 1;; timeStamp.day = time.tm_mday; timeStamp.hour = time.tm_hour; timeStamp.minute = time.tm_min; timeStamp.second = time.tm_sec; timeStamp.centiseconds = timev.tv_usec / 10000; timeStamp.hundredsOfMicroseconds = (timev.tv_usec / 100) % 100; timeStamp.microseconds = timev.tv_usec % 100 ;}void setStrictRead(int yes) { if( device == DISK_IMAGE ) return; synchronize_cache(device); if( yes ) { rerp->error_recovery_param = 0x04; rerp->retry_count = 2; cp->rcd = 1; } else { rerp->error_recovery_param = 0x00; // back to default rerp->retry_count = 5; cp->rcd = 0; } mode_select(device, rerp_buffer); mode_select(device, cp_buffer);}uint32_t getPhysical(uint32_t lbn, uint16_t part) { if( part == 0xFFFF ) return lbn; if( part == virtualPartitionNum ) lbn = vat[lbn]; return lbn + pd->partitionStartingLocation;}int cmpBlk(const void* a, const void* b) { /* compare routine for sparing table lookup */ if( *(uint32_t*)a < ((struct sparingEntry*)b)->origLocation ) return -1; if( *(uint32_t*)a > ((struct sparingEntry*)b)->origLocation ) return 1; return 0;}/* If the original packet occurs in the Sparing Table return the mappedLocation * else return the original packet address unchanged. */uint32_t lookupSparingTable(uint32_t original) { struct sparingEntry* se; if( !st ) // no sparing table found return original; se = bsearch(&original, st->mapEntry, usedSparingEntries, sizeof(struct sparingEntry), cmpBlk); if( se ) return se->mappedLocation; else return original;}/* Make an entry in the Sparing Table for packet 'original' and * return the mappedLocation */uint32_t newSparingTableEntry(uint32_t original) { struct sparingEntry *se, newEntry, swapEntry; uint32_t mapped; int i; if( !st ) { printf("No sparing table provided\n"); return INVALID; } if( usedSparingEntries == st->reallocationTableLen ) { fail("SparingTable full\n"); } se = bsearch(&original, &st->mapEntry[0], usedSparingEntries, sizeof(struct sparingEntry), cmpBlk); if( se ) { /* sparing a sparing packet */ se->origLocation = 0xFFFFFFF0; } newEntry.origLocation = original; newEntry.mappedLocation = mapped = st->mapEntry[usedSparingEntries].mappedLocation; for( i = 0; i < usedSparingEntries; i++ ) { if( st->mapEntry[i].origLocation < original ) continue; } for( ; i <= usedSparingEntries; i++ ) { swapEntry = st->mapEntry[i]; st->mapEntry[i] = newEntry; newEntry = swapEntry; } usedSparingEntries++; st->sequenceNum++; sparingTableDirty = 1;#ifdef DEBUG printf("Sparing %d to %d\n", original, mapped);#endif return mapped;}/* updateSparingTable() * Only done when quitting. * Do not verify writing as that would change the table again. */void updateSparingTable() { int i, pbn, stat; struct generic_desc *p; struct packetbuf *pb; struct sparablePartitionMap *spm = (struct sparablePartitionMap*)lvd->partitionMaps; for( i = 0; i <= 4; i++ ) { pbn = spm->locSparingTable[i]; if( pbn == 0 ) return; p = readBlock(pbn, ABSOLUTE); pb = findBuf(pbn); memcpy(p, st, sizeof(struct sparingTable) + st->reallocationTableLen * sizeof(struct sparingEntry)); p->descTag.tagLocation = pbn; p->descTag.descCRCLength = sizeof(struct sparingTable) + st->reallocationTableLen * sizeof(struct sparingEntry) - sizeof(tag); setChecksum(p); if( devicetype != DISK_IMAGE ) { stat = writeCD(device, pbn, 32, pb->pkt); if( stat ) printf("Write SparingTable at %d: %s\n", pbn, get_sense_string()); } else { // DISK_IMAGE stat= lseek(device, 2048 * pbn, SEEK_SET); stat = write(device, pb->pkt, 32 * 2048); if( stat < 0 ) fail("writeSparingTable at %d: %m\n", pbn); } }}int readPacket(struct packetbuf* pb) { int stat; uint32_t physical; physical = lookupSparingTable(pb->start); if( devicetype != DISK_IMAGE ) { stat = readCD(device, sectortype, physical, 32, pb->pkt); if( stat ) printf("readPacket: readCD %s\n", get_sense_string()); } else { stat = lseek(device, 2048 * physical, SEEK_SET); stat = read(device, pb->pkt, 32 * 2048); if( stat != 32 * 2048 ) fail("readPacket: read failed %m\n"); } return stat;} int writePacket(struct packetbuf* pb) { int stat, retry; uint32_t physical; pb->dirty = 0; physical = lookupSparingTable(pb->start); if( devicetype != DISK_IMAGE ) { for(retry = 0; retry < 2; retry++ ) { if( retry != 0 ) physical = newSparingTableEntry(pb->start); stat = writeCD(device, physical, 32, pb->pkt); if( stat ) fail("writePacket: writeCD %s\n", get_sense_string()); // must now verify write operation and spare if necessary // My HP8100 does not support Verify or WriteAndVerify // Use ReadCD with strict Read Error Recovery Parameters setStrictRead(1); stat = readCD(device, sectortype, physical, 32, verifyBuffer); if( stat == 0 ) { setStrictRead(0); return 0; } printf("writePacket: verify %s\n", get_sense_string());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -