diff options
Diffstat (limited to 'xdf_io.c')
-rw-r--r-- | xdf_io.c | 321 |
1 files changed, 179 insertions, 142 deletions
@@ -72,7 +72,7 @@ static struct { typedef struct { unsigned char begin; /* where it begins */ - unsigned char end; + unsigned char end; unsigned char sector; unsigned char sizecode; @@ -85,23 +85,21 @@ typedef struct { typedef struct Xdf_t { - Class_t *Class; - int refs; - Stream_t *Next; - Stream_t *Buffer; + struct Stream_t head; int fd; char *buffer; - - int current_track; - + + bool track_valid; + uint8_t current_track; + sector_map_t *map; - int track_size; + uint32_t track_size; int track0_size; - int sector_size; - unsigned int FatSize; - unsigned int RootDirSize; + uint16_t sector_size; + uint8_t FatSize; + uint16_t RootDirSize; TrackMap_t *track_map; unsigned char last_sector; @@ -141,7 +139,7 @@ static int analyze_reply(RawRequest_t *raw_cmd, int do_print) } } } - + static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr, @@ -149,7 +147,7 @@ static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr, { int j; int ret=-1; - + if(!nr) return 0; for (j=0; j< retries; j++){ @@ -178,28 +176,28 @@ static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr, #define END(x) (This->track_map[(x)].end) #define BEGIN(x) (This->track_map[(x)].begin) -static int add_to_request(Xdf_t *This, int ptr, +static int add_to_request(Xdf_t *This, unsigned char ptr, RawRequest_t *request, int *nr, int direction, Compactify_t *compactify) { #if 0 if(direction == MT_WRITE) { - printf("writing %d: %d %d %d %d [%02x]\n", + printf("writing %d: %u %d %d %d [%02x]\n", ptr, This->current_track, REC.head, REC.sector, REC.sizecode, *(This->buffer + ptr * This->sector_size)); } else - printf(" load %d.%d\n", This->current_track, ptr); + printf(" load %d.%u\n", This->current_track, ptr); #endif if(REC.phantom) { - if(direction== MT_READ) + if(direction== MT_READ) memset(This->buffer + ptr * This->sector_size, 0, - 128 << REC.sizecode); + 128u << REC.sizecode); return 0; } - + if(*nr && - RR_SIZECODE(request+(*nr)-1) == REC.sizecode && + RR_SIZECODE(request+(*nr)-1) == REC.sizecode && compactify->head == REC.head && compactify->ptr + 1 == ptr && compactify->sector +1 == REC.sector) { @@ -211,7 +209,7 @@ static int add_to_request(Xdf_t *This, int ptr, RR_SETDRIVE(request+(*nr), This->drive); RR_SETRATE(request+(*nr), This->rate); RR_SETTRACK(request+(*nr), This->current_track); - RR_SETPTRACK(request+(*nr), + RR_SETPTRACK(request+(*nr), This->current_track << This->stretch); RR_SETHEAD(request+(*nr), REC.head); RR_SETSECTOR(request+(*nr), REC.sector); @@ -228,7 +226,7 @@ static int add_to_request(Xdf_t *This, int ptr, } -static void add_to_request_if_invalid(Xdf_t *This, int ptr, +static void add_to_request_if_invalid(Xdf_t *This, unsigned char ptr, RawRequest_t *request, int *nr, Compactify_t *compactify) { @@ -238,23 +236,25 @@ static void add_to_request_if_invalid(Xdf_t *This, int ptr, } -static void adjust_bounds(Xdf_t *This, off_t *begin, off_t *end) +static void adjust_bounds(Xdf_t *This, uint32_t ibegin, uint32_t iend, + uint8_t *begin, uint8_t *end) { /* translates begin and end from byte to sectors */ - *begin = *begin / This->sector_size; - *end = (*end + This->sector_size - 1) / This->sector_size; + *begin = (uint8_t) (ibegin / This->sector_size); + *end = (uint8_t) ((iend + This->sector_size - 1) / This->sector_size); } static __inline__ int try_flush_dirty(Xdf_t *This) { - int ptr, nr, bytes; + unsigned char ptr; + int nr, bytes; RawRequest_t requests[100]; Compactify_t compactify; - if(This->current_track < 0) + if(!This->track_valid) return 0; - + nr = 0; for(ptr=0; ptr < This->last_sector; ptr=REC.end) if(REC.dirty) @@ -282,25 +282,27 @@ static __inline__ int try_flush_dirty(Xdf_t *This) static int flush_dirty(Xdf_t *This) -{ +{ int ret; while((ret = try_flush_dirty(This))) { - if(ret < 0) + if(ret < 0) return ret; } return 0; } -static int load_data(Xdf_t *This, off_t begin, off_t end, int retries) +static ssize_t load_data(Xdf_t *This, uint32_t ibegin, uint32_t iend, + int retries) { - int ptr, nr, bytes; + unsigned char ptr; + int nr, bytes; RawRequest_t requests[100]; Compactify_t compactify; + unsigned char begin, end; + adjust_bounds(This, ibegin, iend, &begin, &end); - adjust_bounds(This, &begin, &end); - ptr = begin; nr = 0; for(ptr=REC.begin; ptr < end ; ptr = REC.end) @@ -324,12 +326,13 @@ static int load_data(Xdf_t *This, off_t begin, off_t end, int retries) return end * This->sector_size; } -static void mark_dirty(Xdf_t *This, off_t begin, off_t end) +static void mark_dirty(Xdf_t *This, uint32_t ibegin, uint32_t iend) { int ptr; + unsigned char begin, end; + + adjust_bounds(This, ibegin, iend, &begin, &end); - adjust_bounds(This, &begin, &end); - ptr = begin; for(ptr=REC.begin; ptr < end ; ptr = REC.end) { REC.valid = 1; @@ -339,15 +342,11 @@ static void mark_dirty(Xdf_t *This, off_t begin, off_t end) } -static int load_bounds(Xdf_t *This, off_t begin, off_t end) +static ssize_t load_bounds(Xdf_t *This, uint32_t begin, uint32_t end) { - off_t lbegin, lend; - int endp1, endp2; - - lbegin = begin; - lend = end; + unsigned char lbegin, lend; - adjust_bounds(This, &lbegin, &lend); + adjust_bounds(This, begin, end, &lbegin, &lend); if(begin != BEGIN(lbegin) * This->sector_size && end != BEGIN(lend) * This->sector_size && @@ -356,24 +355,44 @@ static int load_bounds(Xdf_t *This, off_t begin, off_t end) return load_data(This, begin, end, 4); if(begin != BEGIN(lbegin) * This->sector_size) { - endp1 = load_data(This, begin, begin, 4); - if(endp1 < 0) - return endp1; + ssize_t ret = load_data(This, begin, begin, 4); + if(ret < 0) + return ret; } if(end != BEGIN(lend) * This->sector_size) { - endp2 = load_data(This, end, end, 4); - if(endp2 < 0) + ssize_t ret = load_data(This, end, end, 4); + if(ret < 0) return BEGIN(lend) * This->sector_size; } return lend * This->sector_size; } +/* Fill out a map that is just sufficient to read boot sector */ +static void fill_boot(Xdf_t *This) +{ + uint8_t ptr=0; + + REC.head = 0; + REC.sector = 129; + REC.phantom = 0; + + REC.begin = ptr; + REC.end = ptr+1; + + REC.sizecode = 2; + + REC.valid = 0; + REC.dirty = 0; + This->last_sector=1; + This->current_track=0; +} + -static int fill_t0(Xdf_t *This, int ptr, unsigned int size, - int *sector, int *head) +static uint8_t fill_t0(Xdf_t *This, uint8_t ptr, unsigned int size, + uint8_t *sector, uint8_t *head) { - int n; + unsigned int n; for(n = 0; n < size; ptr++,n++) { REC.head = *head; @@ -389,48 +408,56 @@ static int fill_t0(Xdf_t *This, int ptr, unsigned int size, } -static int fill_phantoms(Xdf_t *This, int ptr, unsigned int size) +static uint8_t fill_phantoms(Xdf_t *This, uint8_t ptr, uint8_t size) { - int n; + unsigned int n; for(n = 0; n < size; ptr++,n++) REC.phantom = 1; return ptr; } -static void decompose(Xdf_t *This, int where, int len, off_t *begin, - off_t *end, int boot) +static int decompose(Xdf_t *This, mt_off_t iwhere, size_t len, + uint32_t *begin, uint32_t *end, uint8_t boot) { - int ptr, track; + uint8_t ptr; sector_map_t *map; - int lbegin, lend; - - track = where / This->track_size / 1024; - - *begin = where - track * This->track_size * 1024; - *end = where + len - track * This->track_size * 1024; - maximize(*end, This->track_size * 1024); + uint8_t lbegin, lend; + uint32_t track_size = This->track_size * 1024; + + smt_off_t track = (smt_off_t) iwhere / track_size; + uint32_t where = (smt_off_t) iwhere % track_size; + + *begin = where; + if(where + len > track_size) + *end = track_size; + else + *end = (uint32_t) (where + len); if(This->current_track == track && !boot) /* already OK, return immediately */ - return; + return 0; if(!boot) flush_dirty(This); - This->current_track = track; + if(track >= 80) + return -1; + This->current_track = (uint8_t) track; + This->track_valid = true; if(track) { for(ptr=0, map=This->map; map->size; map++) { /* iterate through all sectors */ lbegin = ptr; - lend = ptr + (128 << map->size) / This->sector_size; + lend = ptr + + (uint8_t) ((128u<<map->size)/This->sector_size); for( ; ptr < lend ; ptr++) { REC.begin = lbegin; REC.end = lend; - + REC.head = map->head; REC.sector = map->size + 128; REC.sizecode = map->size; - + REC.valid = 0; REC.dirty = 0; REC.phantom = 0; @@ -438,7 +465,7 @@ static void decompose(Xdf_t *This, int where, int len, off_t *begin, } REC.begin = REC.end = ptr; } else { - int sector, head; + uint8_t sector, head; head = 0; sector = 0; @@ -446,9 +473,9 @@ static void decompose(Xdf_t *This, int where, int len, off_t *begin, for(ptr=boot; ptr < 2 * This->track_size; ptr++) { REC.begin = ptr; REC.end = ptr+1; - + REC.sizecode = 2; - + REC.valid = 0; REC.dirty = 0; } @@ -461,7 +488,7 @@ static void decompose(Xdf_t *This, int where, int len, off_t *begin, /* root dir */ ptr=fill_t0(This, ptr, This->RootDirSize, §or, &head); - + /* "bad sectors" at the beginning of the fs */ ptr=fill_phantoms(This, ptr, 5); @@ -475,44 +502,57 @@ static void decompose(Xdf_t *This, int where, int len, off_t *begin, §or, &head); } This->last_sector = ptr; + return 0; } -static int xdf_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) -{ - off_t begin, end; - size_t len2; +static ssize_t xdf_pread(Stream_t *Stream, char *buf, + mt_off_t where, size_t len) +{ + uint32_t begin, end; + ssize_t ret; DeclareThis(Xdf_t); - decompose(This, truncBytes32(where), len, &begin, &end, 0); - len2 = load_data(This, begin, end, 4); - len2 -= begin; - maximize(len, len2); + if(decompose(This, truncBytes32(where), len, &begin, &end, 0) < 0) + /* Read beyond end of device */ + return 0; + ret = load_data(This, begin, end, 4); + if(ret < 0 || (size_t) ret < begin) + return -1; + maximize(len, (size_t) ret - begin); memcpy(buf, This->buffer + begin, len); - return end - begin; + return (ssize_t) (end - begin); } -static int xdf_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) -{ - off_t begin, end; - size_t len2; +static ssize_t xdf_pwrite(Stream_t *Stream, char *buf, + mt_off_t where, size_t len) +{ + uint32_t begin, end; + ssize_t len2; DeclareThis(Xdf_t); - decompose(This, truncBytes32(where), len, &begin, &end, 0); + if(decompose(This, truncBytes32(where), len, &begin, &end, 0) < 0) { + /* Write beyond end of device */ + errno = EFBIG; + return -1; + } + len2 = load_bounds(This, begin, end); - smaximize(end, (off_t)len2); + if(len2 < 0) + return -1; + maximize(end, (uint32_t)len2); len2 -= begin; - sizemaximize(len, (off_t)len2); + maximize(len, (size_t) len2); memcpy(This->buffer + begin, buf, len); mark_dirty(This, begin, end); - return end - begin; + return (ssize_t) (end - begin); } static int xdf_flush(Stream_t *Stream) { DeclareThis(Xdf_t); - return flush_dirty(This); + return flush_dirty(This); } static int xdf_free(Stream_t *Stream) @@ -524,12 +564,9 @@ static int xdf_free(Stream_t *Stream) } -static int check_geom(struct device *dev, int media, union bootsector *boot) +static int check_geom(Xdf_t *This, struct device *dev) { - int sect; - - if(media >= 0xfc && media <= 0xff) - return 1; /* old DOS */ + unsigned int sect; if (!IS_MFORMAT_ONLY(dev)) { if(compare(dev->sectors, 19) && @@ -538,79 +575,81 @@ static int check_geom(struct device *dev, int media, union bootsector *boot) compare(dev->sectors, 46) && compare(dev->sectors, 48)) return 1; - + /* check against contradictory info from configuration file */ if(compare(dev->heads, 2)) return 1; } /* check against info from boot */ - if(boot) { - sect = WORD(nsect); + if(This) { + sect = This->track_size; if((sect != 19 && sect != 23 && sect != 24 && sect != 46 && sect != 48) || - (!IS_MFORMAT_ONLY(dev) && compare(dev->sectors, sect)) || - WORD(nheads) !=2) - return 1; + (!IS_MFORMAT_ONLY(dev) && compare(dev->sectors, sect))) + return 1; } return 0; } -static void set_geom(union bootsector *boot, struct device *dev) +static void set_geom(Xdf_t *This, struct device *dev) { /* fill in config info to be returned to user */ dev->heads = 2; dev->use_2m = 0xff; - if(boot) { - dev->sectors = WORD(nsect); - if(WORD(psect)) - dev->tracks = WORD(psect) / dev->sectors / 2; - } + dev->sectors = (uint16_t) This->track_size; + dev->tracks = 80; } -static int config_geom(Stream_t *Stream UNUSEDP, struct device *dev, - struct device *orig_dev UNUSEDP, int media, - union bootsector *boot) +static int config_geom(Stream_t *Stream UNUSEDP, struct device *dev, + struct device *orig_dev UNUSEDP) { - if(check_geom(dev, media, boot)) + DeclareThis(Xdf_t); + if(check_geom(This, dev)) return 1; - set_geom(boot,dev); + set_geom(This, dev); return 0; } static Class_t XdfClass = { - xdf_read, - xdf_write, - xdf_flush, - xdf_free, - config_geom, + 0, + 0, + xdf_pread, + xdf_pwrite, + xdf_flush, + xdf_free, + config_geom, 0, /* get_data */ 0, /* pre-allocate */ 0, /* get_dosConvert */ 0 /* discard */ }; -Stream_t *XdfOpen(struct device *dev, char *name, +Stream_t *XdfOpen(struct device *dev, const char *name, int mode, char *errmsg, struct xdf_info *info) { Xdf_t *This; - off_t begin, end; + uint32_t begin, end; union bootsector *boot; unsigned int type; + uint16_t fatSize; - if(dev && (!SHOULD_USE_XDF(dev) || check_geom(dev, 0, 0))) + if(dev && ((!SHOULD_USE_XDF(dev) && !getenv("MTOOLS_USE_XDF")) || + check_geom(NULL, dev))) return NULL; This = New(Xdf_t); if (!This) return NULL; + init_head(&This->head, &XdfClass, NULL); - This->Class = &XdfClass; This->sector_size = 512; This->stretch = 0; precmd(dev); - This->fd = open(name, mode | dev->mode | O_EXCL | O_NDELAY); + This->fd = open(name, + ((mode | dev->mode) & ~O_ACCMODE) | + O_EXCL | O_NDELAY | O_RDWR); if(This->fd < 0) { #ifdef HAVE_SNPRINTF snprintf(errmsg,199,"xdf floppy: open: \"%s\"", strerror(errno)); @@ -630,7 +669,7 @@ Stream_t *XdfOpen(struct device *dev, char *name, if (!This->buffer) goto exit_1; - This->current_track = -1; + This->track_valid = false; This->track_map = (TrackMap_t *) calloc(96, sizeof(TrackMap_t)); if(!This->track_map) @@ -639,31 +678,33 @@ Stream_t *XdfOpen(struct device *dev, char *name, /* lock the device on writes */ if (lock_dev(This->fd, mode == O_RDWR, dev)) { #ifdef HAVE_SNPRINTF - snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:", + snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:", dev->name); #else - sprintf(errmsg,"xdf floppy: device \"%s\" busy:", + sprintf(errmsg,"xdf floppy: device \"%s\" busy:", dev->name); #endif goto exit_3; } /* Before reading the boot sector, assume dummy values suitable - * for reading at least the boot sector */ - This->track_size = 11; - This->track0_size = 6; + * for reading just the boot sector */ + fill_boot(This); This->rate = 0; - This->FatSize = 9; - This->RootDirSize = 1; - decompose(This, 0, 512, &begin, &end, 0); - if (load_data(This, 0, 1, 1) < 0 ) { + if (load_data(This, 0, 1, 4) < 0 ) { This->rate = 0x43; - if(load_data(This, 0, 1, 1) < 0) + if(load_data(This, 0, 1, 4) < 0) goto exit_3; } boot = (union bootsector *) This->buffer; - This->FatSize = WORD(fatlen); + + fatSize = WORD(fatlen); + if(fatSize > UINT8_MAX) { + fprintf(stderr, "Fat size %d too large\n", fatSize); + exit(1); + } + This->FatSize = (uint8_t) fatSize; This->RootDirSize = WORD(dirents)/16; This->track_size = WORD(nsect); for(type=0; type < NUMBER(xdf_table); type++) { @@ -685,12 +726,9 @@ Stream_t *XdfOpen(struct device *dev, char *name, } decompose(This, 0, 512, &begin, &end, 1); - This->refs = 1; - This->Next = 0; - This->Buffer = 0; if(dev) - set_geom(boot, dev); - return (Stream_t *) This; + set_geom(This, dev); + return &This->head; exit_3: Free(This->track_map); @@ -706,4 +744,3 @@ exit_0: #endif /* Algorithms can't be patented */ - |