From e62b35169cdcd13632ae353b1e5ffde7dec44201 Mon Sep 17 00:00:00 2001 From: Robert de Bath Date: Sat, 23 Jan 1999 13:29:22 +0100 Subject: Import Dev86src-0.14.7.tar.gz --- libc/bios/fs_dos.c | 421 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100644 libc/bios/fs_dos.c (limited to 'libc/bios/fs_dos.c') diff --git a/libc/bios/fs_dos.c b/libc/bios/fs_dos.c new file mode 100644 index 0000000..28ee962 --- /dev/null +++ b/libc/bios/fs_dos.c @@ -0,0 +1,421 @@ + +#include +#include +#include +#include +#include "io.h" +#include "rawio.h" + +#define DONT_BUFFER_FAT + +#define DOS_SECT(P) get_uint(P,0x0B) +#define DOS_CLUST(P) get_byte(P,0x0D) +#define DOS_RESV(P) get_uint(P,0x0E) +#define DOS_NFAT(P) get_byte(P,0x10) +#define DOS_NROOT(P) get_uint(P,0x11) +#define DOS_MAXSECT(P) get_uint(P,0x13) +#define DOS_MEDIA(P) get_byte(P,0x15) +#define DOS_FATLEN(P) get_uint(P,0x16) +#define DOS_SPT(P) get_uint(P,0x18) +#define DOS_HEADS(P) get_uint(P,0x1A) +#define DOS_HIDDEN(P) get_long(P,0x1C) +#define DOS4_MAXSECT(P) get_long(P,0x20) +#define DOS4_PHY_DRIVE(P) get_byte(P,0x24) +#define DOS4_SERIAL(P) get_long(P,0x27) + +/* These assume alignment is not a problem */ +#define get_byte(P,Off) *((unsigned char*)((char*)(P)+(Off))) +#define get_uint(P,Off) *((unsigned short*)((char*)(P)+(Off))) +#define get_long(P,Off) *((long*)((char*)(P)+(Off))) + +static int read_bootblock(); +static int dir_nentry, dir_sect; +static int dos_clust0, dos_spc, dos_fatpos; +static int last_serial = 0; + +#ifdef BUFFER_FAT +static char * fat_buf = 0; +#endif + +struct filestatus { + char fname[12]; + unsigned short first_cluster; + unsigned short cur_cluster; + unsigned short sector_no; + long file_length; +}; + +static int fsdos_read_block(); +static int fsdos_close_file(); + +/* buffer to read into */ +static char sect[512]; + +fsdos_open_file(iob, fname, flags, mode) +ioblock* iob; +char * fname; +int flags; +int mode; +{ + extern union REGS __argr; + char conv_name[12]; + char *d, *s; + int i; + int dodir = 0; + struct filestatus* cur_file; + +#ifdef DEBUG + printf("fsdos_open_file(%x, %s, %d, %d, %d)\n", + iob, fname, flags, mode, sizeof(iob)); +#endif + iob->block_read = fsdos_read_block; + iob->close = fsdos_close_file; + + /* Get the superblock */ + if( read_bootblock() < 0 ) return -1; + + if(strcmp(fname, ".") == 0) + dodir = 1; + else + { + /* Convert the name to MSDOS directory format */ + strcpy(conv_name, " "); + for(s=fname, d=conv_name; *s && *d && *s != '.' && *s != ' '; s++) + { + if( islower(*s) ) *d++ = toupper(*s); + else *d++ = *s; + } + while( *s && *s != '.' ) s++; + strcpy(d=(conv_name+8), " "); + if( *s == '.' ) + { + for(s++; *s && *d; s++) + { + if( islower(*s) ) *d++ = toupper(*s); + else *d++ = *s; + } + } + } +#ifdef DEBUG + printf("fsdos_open_file: converted filename=<%s>\n", conv_name); +#endif + +#ifdef BUFFER_FAT + rawio_read_sector(0, sect); + + if( !dodir ) + { + /* Read in and buffer the FAT */ + if( fat_buf ) free(fat_buf); + fat_buf = malloc(DOS_FATLEN(sect) * 512); + if( fat_buf == 0 ) + { + errno = ENOMEM; + return -1; + } + else + { + int fatsec = DOS_RESV(sect); + int nsec = DOS_FATLEN(sect); + + for(i=0; i>5)&0xF), + ((get_uint(d,24)>>9)&0x7F)+1980, + ((get_uint(d,22)>>11)&0x1F), + ((get_uint(d,22)>>5)&0x3F) + ); + if( *d > ' ' && *d <= '~' ) switch(d[11]&0x18) + { + case 0: + printf("%-8.8s %-3.3s %10ld%s\n", d, d+8, get_long(d,28), dtime); + break; + case 0x10: + printf("%-8.8s %-3.3s %s\n", d, d+8, dtime); + break; + case 8: + if( (d[11] & 7) == 0 ) + printf("%-11.11s %s\n", d, dtime); + break; + } +#if 0 + if( more_strn(lbuf, sizeof(lbuf)) < 0 ) break; +#endif + } + else if( memcmp(d, conv_name, 11) == 0 && (d[11]&0x18) == 0 ) + { /* Name matches and is normal file */ + +#ifdef DEBUG + fprintf(stderr, "dos_open_file: %s worked\n", fname); +#endif + cur_file = malloc(sizeof(*cur_file)); + + iob->context = cur_file; + if (iob->context == NULL) + { + errno = ENOMEM; + return -1; + } + memset(cur_file, '\0', sizeof(*cur_file)); + strcpy(cur_file->fname, conv_name); + cur_file->first_cluster = get_uint(d,26); + cur_file->file_length = get_long(d,28); + + cur_file->cur_cluster = cur_file->first_cluster; + cur_file->sector_no = 0; + + return 0; + } + } + return -1; +} + +fsdos_rewind_file(iob) +ioblock* iob; +{ + struct filestatus* cur_file; + + if (iob == NULL || iob->context == NULL) + { + errno = EBADF; + return -1; + } + + cur_file = (struct filestatus*) iob->context; + /* Is there an opened file ? */ + if( cur_file->fname[0] == 0 ) return -1; + + cur_file->sector_no = 0; + cur_file->cur_cluster = cur_file->first_cluster; + return 0; +} + +static int fsdos_close_file(iob) +ioblock* iob; +{ + struct filestatus* cur_file; + + if (iob == NULL || iob->context == NULL) + { + errno = EBADF; + return -1; + } + cur_file = (struct filestatus*) iob->context; + free(cur_file); + iob->context = NULL; + +#ifdef BUFFER_FAT + if( fat_buf ) free(fat_buf); + fat_buf = 0; +#endif + + rawio_reset_disk(); + return 0; +} + +long +fsdos_file_length(iob) +ioblock* iob; +{ + struct filestatus* cur_file; + + if (iob == NULL || iob->context == NULL) + { + errno = EBADF; + return -1; + } + cur_file = (struct filestatus*) iob->context; + + /* Is there an opened file ? */ + if( cur_file->fname[0] == 0 ) return -1; + + return cur_file->file_length; +} + +static int fsdos_read_block(iob, buffer, block) +ioblock* iob; +char * buffer; +long block; /* ignored for now */ +{ + int s; + char * ptr = buffer; + struct filestatus* cur_file; + long amount_left_in_file; + long amount_to_read; + +#ifdef DEBUG + fprintf(stderr, "rb: iob = %x, buf = %x, block = %ld\n", + iob, buffer, block); +#endif + if (iob == NULL || iob->context == NULL) + { + fprintf(stderr, "rb: no context\n"); + errno = EBADF; + return -1; + } + cur_file = (struct filestatus*) iob->context; + + /* Is there an opened file ? */ + if( cur_file->fname[0] == 0 ) + { +#ifdef DEBUG + fprintf(stderr, "fsdos_read_block: File is not currently open!\n"); +#endif + errno = EBADF; + return -1; + } + + amount_left_in_file = cur_file->file_length - block * 1024; + + if (amount_left_in_file < 0) + { +#ifdef DEBUG + fprintf(stderr, "EOF\n"); +#endif + return 0; + } + + /* Are we before the EOF ? NB: FAT12 ONLY! */ + if( cur_file->cur_cluster >= 0xFF0 || cur_file->cur_cluster < 2 ) + { +#ifdef DEBUG + fprintf(stderr, "Hit end of file; cluster 0x%03x\n", + cur_file->cur_cluster); +#endif + return 0; + } + + for(s=0; s<2; s++) + { + unsigned int sectno; + + if (amount_left_in_file <= 0) + { +#ifdef DEBUG + fprintf(stderr, "r2: Hit end of file\n"); +#endif + break; + } + + sectno = dos_clust0 + + cur_file->cur_cluster * dos_spc + + cur_file->sector_no % dos_spc; + + if (rawio_read_sector(sectno, ptr) <= 0) + { +#ifdef DEBUG + fprintf(stderr, "r2: rawio failed\n"); +#endif + return -1; + } + + cur_file->sector_no++; + if( cur_file->sector_no % dos_spc == 0 ) + { + int odd = (cur_file->cur_cluster&1); + unsigned int val, val2; + + val = cur_file->cur_cluster + (cur_file->cur_cluster>>1); +#ifdef BUFFER_FAT + val2 = get_uint(fat_buf, val); +#else + if (rawio_read_sector(dos_fatpos+(val/512), sect) <= 0) return -1; + if( val%512 == 511 ) + { + val2 = sect[511] & 0xFF; + if (rawio_read_sector(dos_fatpos+(val/512)+1, sect) <= 0) return -1; + val2 |= (sect[0]<<8); + } + else + val2 = get_uint(sect, (val%512)); +#endif + + if( odd ) val2>>=4; + + val2 &= 0xFFF; + + cur_file->cur_cluster = val2; + } + + amount_to_read = amount_left_in_file; + if (amount_to_read > 512) amount_to_read = 512; + ptr += amount_to_read; + amount_left_in_file -= amount_to_read; + } + + return ptr - buffer; +} + +static int read_bootblock() +{ + int rv, media_byte = 0; + +#ifdef DEBUG + printf("fs_dos:read_bootblock:\n"); +#endif + if (rawio_read_sector(1, sect) <= 0) return -1; + media_byte = *(unsigned char*)sect; + + /* Valid media byte ? */ + if( (media_byte & 0xF0) != 0xF0 ) return -1; + if (rawio_read_sector(0, sect) <= 0) return -1; + + if( DOS_MEDIA(sect) != media_byte ) return -1; + if( DOS_SPT(sect) > 63 ) return -1; + if( DOS_SECT(sect) != 512 ) return -1; + + if( last_serial != DOS4_SERIAL(sect) ) fsdos_close_file(); + last_serial = DOS4_SERIAL(sect); + + /* Collect important data */ + dir_sect = DOS_RESV(sect) + DOS_NFAT(sect)*DOS_FATLEN(sect); + dir_nentry = DOS_NROOT(sect); + + dos_fatpos = DOS_RESV(sect); + dos_spc = DOS_CLUST(sect); + if( dos_spc < 1 ) dos_spc = 1; + dos_clust0 = dir_sect + (dir_nentry+15)/16 - 2*dos_spc; + + if( rawio_disk_cyls == 0 ) + { + rawio_disk_spt = DOS_SPT(sect); + rawio_disk_heads = DOS_HEADS(sect); + } + +#ifdef DEBUG + printf("read_bootblock: heads(%d), spt(%d), dir_sect(%d)\n", + rawio_disk_heads, + rawio_disk_spt, + dir_sect); +#endif + return 0; +} -- cgit v1.2.1