aboutsummaryrefslogtreecommitdiff
path: root/xdf_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'xdf_io.c')
-rw-r--r--xdf_io.c321
1 files changed, 179 insertions, 142 deletions
diff --git a/xdf_io.c b/xdf_io.c
index db02414..d84fd53 100644
--- a/xdf_io.c
+++ b/xdf_io.c
@@ -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, &sector, &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,
&sector, &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 */
-