ast@cs.vu.nl (Andy Tanenbaum) (07/20/88)
Here is an improved version of dosread/dosdir/doswrite modified by Tim
Kachel for hard disks etc. I don't have a DOS partition on any of my
hard disks, so I can't test it easily. If anyone finds any problems, please
post them.
Andy Tanenbaum (ast@cs.vu.nl)
/*
* dosdir - list MS-DOS directories.
* doswrite - write stdin to DOS-file
* dosread - read DOS-file to stdout
*
* Author: Michiel Huisjes.
*
* Usage: dos... [-lra] drive [file/dir]
* l: Give long listing.
* r: List recursively.
* a: Set ASCII bit.
*
* Modified by Tim Kachel 4-88
* drive can be 0,1, a, b, c, d, e, f
* program will automatically configure to different hard disks
* and the partitions for such (could change drive name for
* a send hard disk if you have one)
* (has been tested on a 16 bit FAT AT drive)
* (High density AT diskettes and regular 360K)
* compile with cc -O -i
* hard disk is named /dev/hd_0 to avoid accidents
* To test FAT sizes on your hard disk first try dir -lr c
* (or what ever your dos partition is) if this works
* properly then all the rest should be okay.
* If there are any problems there is debugging information
* in fdinit() -- please let me know of any problems
*/
#include "stat.h"
#define DRIVE0 "/dev/at0"
#define DRIVE1 "/dev/at1"
#define FDRIVE "/dev/hd_0"
#define DDDD 0xFD
#define DDHD 0xF9
#define DDFD 0xF8
#define MAX_CLUSTER_SIZE 4096
#define MAX_FAT_SIZE 23552 /* 46 sectoren */
#define HMASK 0xFF00
#define LMASK 0x00FF
#define MAX_ROOT_ENTRIES 512 /* 32 sectoren */
#define FAT_START 512L /* After bootsector */
#define clus_add(cl_no) ((long) (((long) cl_no - 2L) \
* (long) cluster_size \
+ (long) data_start \
))
struct dir_entry {
unsigned char d_name[8];
unsigned char d_ext[3];
unsigned char d_attribute;
unsigned char d_reserved[10];
unsigned short d_time;
unsigned short d_date;
unsigned short d_cluster;
unsigned long d_size;
};
typedef struct dir_entry DIRECTORY;
#define NOT_USED 0x00
#define ERASED 0xE5
#define DIR 0x2E
#define DIR_SIZE (sizeof (struct dir_entry))
#define SUB_DIR 0x10
#define NIL_DIR ((DIRECTORY *) 0)
#define LAST_CLUSTER 0x0FFF
#define MASK 0xFF8 /* FF8 - FFF are last cluster */
#define FREE 0x000
#define BAD 0xFF0 /* Includes reserved */
#define LAST_16 0xFFFF
#define MASK_16 0xFFF8
#define FREE_16 0x0000
#define BAD_16 0xFFF0 /* Includes reserved */
typedef char BOOL;
#define TRUE 1
#define FALSE 0
#define NIL_PTR ((char *) 0)
#define DOS_TIME 315532800L /* 1970 - 1980 */
#define READ 0
#define WRITE 1
#define disk_read(s, a, b) disk_io(READ, s, a, b)
#define disk_write(s, a, b) disk_io(WRITE, s, a, b)
#define FIND 3
#define LABEL 4
#define ENTRY 5
#define find_entry(d, e, p) directory(d, e, FIND, p)
#define list_dir(d, e, f) (void) directory(d, e, f, NIL_PTR)
#define label() directory(root, root_entries, LABEL, NIL_PTR)
#define new_entry(d, e) directory(d, e, ENTRY, NIL_PTR)
#define is_dir(d) ((d)->d_attribute & SUB_DIR)
#define EOF 0400
#define EOF_MARK '\032'
#define STD_OUT 1
#define flush() print(STD_OUT, NIL_PTR, 0)
short disk;
union tbl
{
unsigned char twelve[4096];
unsigned short sixteen[MAX_FAT_SIZE / 2 ];
} fat;
DIRECTORY root[MAX_ROOT_ENTRIES], save_entry, *directory(), *read_cluster();
char null[MAX_CLUSTER_SIZE], *device, path[128];
short total_clusters, cluster_size, fat_size, root_entries, sub_entries;
BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir, Tfat = TRUE;
unsigned short free_cluster(), next_cluster();
char *make_name(), *num_out(), *slash(), *brk();
long mark, data_start, lseek(), time(), f_start;
leave(nr)
short nr;
{
(void) umount(device);
exit(nr);
}
usage(prog_name)
register char *prog_name;
{
print_string(TRUE, "Usage: %s [%s\n", prog_name,
dos_dir ? "-lr] drive [dir]" : "-a] drive file");
exit(1);
}
main(argc, argv)
int argc;
register char *argv[];
{
register char *arg_ptr = slash(argv[0]);
DIRECTORY *entry;
short index = 1;
char dev_nr;
unsigned char fat_type, fat_check;
BOOL fdisk = FALSE;
int i;
if (!strcmp(arg_ptr, "dosdir"))
dos_dir = TRUE;
else if (!strcmp(arg_ptr, "dosread"))
dos_read = TRUE;
else if (!strcmp(arg_ptr, "doswrite"))
dos_write = TRUE;
else {
print_string(TRUE, "Program should be named dosread, doswrite or dosdir.\n");
exit(1);
}
if (argc == 1)
usage(argv[0]);
if (argv[1][0] == '-') {
for (arg_ptr = &argv[1][1]; *arg_ptr; arg_ptr++) {
if (*arg_ptr == 'l' && dos_dir)
Lflag = TRUE;
else if (*arg_ptr == 'r' && dos_dir)
Rflag = TRUE;
else if (*arg_ptr == 'a' && !dos_dir)
Aflag = TRUE;
else
usage(argv[0]);
}
index++;
}
if (index == argc)
usage(argv[0]);
switch (dev_nr = *argv[index++])
{
case '0':
case 'a': device = DRIVE0; break;
case '1':
case 'b': device = DRIVE1; break;
case 'c':
case 'd':
case 'e':
case 'f': fdisk = TRUE; device = FDRIVE; break;
default : usage(argv[0]);
}
if ((disk = open(device, 2)) < 0) {
print_string(TRUE, "Cannot open %s\n", device);
exit(1);
}
if (fdisk) { /* fixed disk */
fdinit(dev_nr);
disk_read(f_start, &fat_type, sizeof(fat_type));
if (fat_type != DDFD) {
print_string(TRUE, "Fixed disk is not DOS\n");
leave(1);
}
}
else { /* use standard start for floppies */
f_start = FAT_START;
disk_read(f_start, &fat_type, sizeof(fat_type));
if (fat_type == DDDD) { /* Double-sided double-density 9 s/t */
total_clusters = 355; /* 720 - 7 - 2 - 2 - 1 */
cluster_size = 1024; /* 2 sectors per cluster */
fat_size = 1024; /* 2 sectors */
data_start = 6144L; /* Starts on sector #12 */
root_entries = 112;
sub_entries = 32; /* 1024 / 32 */
}
else if (fat_type == DDHD) { /* Double-sided high-density 15 s/t */
total_clusters = 2372; /* 2400 - 14 - 7 - 7 - 1 */
cluster_size = 512; /* 1 sector per cluster */
fat_size = 3584; /* 7 sectors */
data_start = 14848L; /* Starts on sector #29 */
root_entries = 224;
sub_entries = 16; /* 512 / 32 */
}
else {
print_string(TRUE, "Diskette is not DOS 2.0 360K or 1.2M\n");
leave(1);
}
}
disk_read(f_start + (long) fat_size, &fat_check, sizeof(fat_check));
if (fat_check != fat_type) {
print_string(TRUE, "Disk type in FAT copy differs from disk type in FAT original.\n");
leave(1);
}
if (Tfat) /* twelve bit FAT entries */
disk_read(f_start, fat.twelve, fat_size);
else /* sixteen bit */
disk_read(f_start, fat.sixteen, fat_size);
/*******
for (i=0; i<= 30; i++){
printf("%x\t%c", fat.sixteen[i], (i % 10) ? ' ':'\n');
}
leave(1);
/*******/
disk_read(f_start + 2L * (long) fat_size, root, DIR_SIZE * root_entries);
/*******
for (i=0; i<2; i++){
printf("%s d_name\n", root[i].d_name);
printf("%s d_ext\n", root[i].d_ext);
printf("%d d_attr\n", root[i].d_attribute);
printf("%s d_reserved\n", root[i].d_reserved);
printf("%d d_time\n", root[i].d_time);
printf("%d d_date\n", root[i].d_date);
printf("%d d_cluster\n", root[i].d_cluster);
printf("%D d_size\n", root[i].d_size);
}
/*********/
if (dos_dir) {
entry = label();
print_string(FALSE, "Volume in drive %c ", dev_nr);
if (entry == NIL_DIR)
print(STD_OUT, "has no label.\n\n", 0);
else
print_string(FALSE, "is %S\n\n", entry->d_name);
}
if (argv[index] == NIL_PTR) {
if (!dos_dir)
usage(argv[0]);
print(STD_OUT, "Root directory:\n", 0);
list_dir(root, root_entries, FALSE);
free_blocks();
flush();
leave(0);
}
for (arg_ptr = argv[index]; *arg_ptr; arg_ptr++)
if (*arg_ptr == '\\')
*arg_ptr = '/';
else if (*arg_ptr >= 'a' && *arg_ptr <= 'z')
*arg_ptr += ('A' - 'a');
if (*--arg_ptr == '/')
*arg_ptr = '\0'; /* skip trailing '/' */
add_path(argv[index], FALSE);
add_path("/", FALSE);
if (dos_dir)
print_string(FALSE, "Directory %s:\n", path);
entry = find_entry(root, root_entries, argv[index]);
if (dos_dir) {
list_dir(entry, sub_entries, FALSE);
free_blocks();
}
else if (dos_read)
extract(entry);
else {
if (entry != NIL_DIR) {
flush();
if (is_dir(entry))
print_string(TRUE, "%s is a directory.\n", path);
else
print_string(TRUE, "%s already exists.\n", argv[index]);
leave(1);
}
add_path(NIL_PTR, TRUE);
if (*path)
make_file(find_entry(root, root_entries, path),
sub_entries, slash(argv[index]));
else
make_file(root, root_entries, argv[index]);
}
(void) close(disk);
flush();
leave(0);
}
fdinit(part_nr) /* Fixed Disk Initializations */
char part_nr;
{
#define SECSIZE 512 /* sector size */
#define TABLEOFFSET 0x1be /* offset in boot sector*/
/*
* Description of entry in partition table
*/
struct part_entry {
char bootind; /* boot indicator 0/0x80 */
char start_head; /* head value for first sector */
char start_sec; /* sector value for first sector*/
char start_cyl; /* track value for first sector */
char sysind; /* system indicator 00=?? 01=DOS*/
char last_head; /* head value for last sector */
char last_sec; /* sector value for last sector */
char last_cyl; /* track value for last sector */
long lowsec; /* logical first sector */
long size; /* size of partion in sectors */
} *pe;
char secbuf[SECSIZE];
/*
* Description of the boot block
*/
struct {
unsigned char jump[3];
unsigned char oem[8];
unsigned char bytes_sector[2];
unsigned char cluster_size;
unsigned char res_sectors[2];
unsigned char num_fats;
unsigned char root_entries[2];
unsigned char logical_sectors[2];
unsigned char media_type;
unsigned char fat_sectors[2];
unsigned char track_sectors[2];
unsigned char num_heads[2];
unsigned char hidden_sectors[2];
} boot;
short block_size, reserved; long boot_loc;
disk_read(0L, secbuf, SECSIZE); /* get boot sector */
/* offset into boot sector for the partition table */
pe = (struct part_entry *)&secbuf[TABLEOFFSET];
/* get the proper partition */
switch(part_nr) {
case 'f': pe++;
case 'e': pe++;
case 'd': pe++;
case 'c': boot_loc = pe->lowsec * 512L; break;
default: printf("Error: unknown partition\n"); leave();
}
/* now read the boot block for the partition needed */
disk_read(boot_loc, &boot, sizeof(boot));
/* this section can be used to print drive information */
/**************
printf("OEM = %s\n", boot.oem);
printf("Bytes/sector = %d\n",
(boot.bytes_sector[1] << 8 & HMASK) + (boot.bytes_sector[0] & LMASK));
printf("Sectors/cluster = %d\n", boot.cluster_size);
printf("Number of Reserved Clusters = %d\n",
(boot.res_sectors[1] << 8 & HMASK) + (boot.res_sectors[0] & LMASK));
printf("Number of FAT's = %d\n", boot.num_fats);
printf("Number of root-directory entries = %d\n",
(boot.root_entries[1] << 8 & HMASK) + (boot.root_entries[0] & LMASK));
printf("Total sectors in logical volume = %D\n",
(long) (boot.logical_sectors[1] << 8 & HMASK) + (boot.logical_sectors[0] & LMASK));
printf("Media Descriptor = %x\n", boot.media_type);
printf("Number of sectors/FAT = %d\n",
(boot.fat_sectors[1] << 8 & HMASK) + (boot.fat_sectors[0] & LMASK));
printf("Sectors/track = %d\n",
(boot.track_sectors[1] << 8 & HMASK) + (boot.track_sectors[0] & LMASK));
printf("Number of Heads = %d\n",
(boot.num_heads[1] << 8 & HMASK) + (boot.num_heads[0] & LMASK));
printf("Number of hidden sectors = %d\n",
(boot.hidden_sectors[1] << 8 & HMASK) + (boot.hidden_sectors[0] & LMASK));
leave(1);
/**************/
if (boot.media_type != DDFD) {
printf("DISK is not DOS Format.\n");
leave(1);
}
if (boot.num_fats != 2) {
printf("Disk does not have two FAT Tables!\n");
leave(1);
}
block_size = (boot.bytes_sector[1] << 8 & HMASK) +
(boot.bytes_sector[0] & LMASK);
if ((cluster_size = block_size * boot.cluster_size)
> MAX_CLUSTER_SIZE) {
printf("Cluster size is larger than MAX_CLUSTER_SIZE.\n");
leave(1);
}
reserved = ((boot.res_sectors[1] << 8 & HMASK) +
(boot.res_sectors[0] & LMASK));
f_start = boot_loc + (long) block_size * (long) reserved;
root_entries = (boot.root_entries[1] << 8 & HMASK) +
(boot.root_entries[0] & LMASK);
fat_size = (boot.fat_sectors[1] << 8 & HMASK) +
(boot.fat_sectors[0] & LMASK);
/* (sectors - rootdir - fats - reserved) / blocks/cluster */
total_clusters = (int) ((long) ((boot.logical_sectors[1] << 8 & HMASK) +
(boot.logical_sectors[0] & LMASK)) -
(root_entries * 32 / block_size) -
(fat_size * 2) - reserved) / boot.cluster_size;
if (total_clusters > 4096)
Tfat = FALSE; /* sixteen bit fat entries */
if ( (fat_size *= block_size) > MAX_FAT_SIZE) {
printf("Disk FAT is larger than MAX_FAT_SIZE.\n");
leave(1);
}
sub_entries = cluster_size / 32;
data_start = f_start + (long) (fat_size * 2L) +
(long) (root_entries * 32L);
/**********
printf("f_start = %D\n", f_start);
printf("total_clusters = %d\n", total_clusters);
printf("cluster_size = %d\n", cluster_size);
printf("fat_size = %d\n", fat_size);
printf("data_start = %D\n", data_start);
printf("root_entries = %d\n", root_entries);
printf("sub_entries = %d\n", sub_entries);
printf("Tfat = %d\n", Tfat);
leave(1);
/*********/
}
DIRECTORY *directory(dir, entries, function, pathname)
DIRECTORY *dir;
short entries;
BOOL function;
register char *pathname;
{
register DIRECTORY *dir_ptr = dir;
DIRECTORY *mem = NIL_DIR;
unsigned short cl_no = dir->d_cluster;
unsigned short type, last;
char file_name[14];
char *name;
int i = 0;
if (function == FIND) {
while (*pathname != '/' && *pathname && i < 12)
file_name[i++] = *pathname++;
while (*pathname != '/' && *pathname)
pathname++;
file_name[i] = '\0';
}
do {
if (entries != root_entries) {
mem = dir_ptr = read_cluster(cl_no);
last = cl_no;
cl_no = next_cluster(cl_no);
}
for (i = 0; i < entries; i++, dir_ptr++) {
type = dir_ptr->d_name[0] & 0x0FF;
if (function == ENTRY) {
if (type == NOT_USED || type == ERASED) {
mark = lseek(disk, 0L, 1) -
(long) cluster_size +
(long) i * (long) DIR_SIZE;
if (!mem)
mark += (long) cluster_size - (long) (root_entries * sizeof (DIRECTORY));
return dir_ptr;
}
continue;
}
if (type == NOT_USED)
break;
if (dir_ptr->d_attribute & 0x08) {
if (function == LABEL)
return dir_ptr;
continue;
}
if (type == DIR || type == ERASED || function == LABEL)
continue;
type = is_dir(dir_ptr);
name = make_name(dir_ptr, (function == FIND) ?
FALSE : type);
if (function == FIND) {
if (strcmp(file_name, name) != 0)
continue;
if (!type) {
if (dos_dir || *pathname) {
flush();
print_string(TRUE, "Not a directory: %s\n", file_name);
leave(1);
}
}
else if (*pathname == '\0' && dos_read) {
flush();
print_string(TRUE, "%s is a directory.\n", path);
leave(1);
}
if (*pathname) {
dir_ptr = find_entry(dir_ptr,
sub_entries, pathname + 1);
}
if (mem) {
if (dir_ptr) {
bcopy(dir_ptr, &save_entry, DIR_SIZE);
dir_ptr = &save_entry;
}
(void) brk(mem);
}
return dir_ptr;
}
else {
if (function == FALSE)
show(dir_ptr, name);
else if (type) { /* Recursive */
print_string(FALSE, "Directory %s%s:\n", path, name);
add_path(name, FALSE);
list_dir(dir_ptr, sub_entries, FALSE);
add_path(NIL_PTR, FALSE);
}
}
}
if (mem)
(void) brk(mem);
} while ((Tfat && cl_no != LAST_CLUSTER && mem) ||
(!Tfat && cl_no != LAST_16 && mem));
switch (function) {
case FIND:
if (dos_write && *pathname == '\0')
return NIL_DIR;
flush();
print_string(TRUE, "Cannot find `%s'.\n", file_name);
leave(1);
case LABEL:
return NIL_DIR;
case ENTRY:
if (!mem) {
flush();
print_string(TRUE, "No entries left in root directory.\n");
leave(1);
}
cl_no = free_cluster(TRUE);
link_fat(last, cl_no);
if (Tfat)
link_fat(cl_no, LAST_CLUSTER);
else
link_fat(cl_no, LAST_16);
disk_write(clus_add(cl_no), null, cluster_size);
return new_entry(dir, entries);
case FALSE:
if (Rflag) {
print(STD_OUT, "\n", 0);
list_dir(dir, entries, TRUE);
}
}
}
extract(entry)
register DIRECTORY *entry;
{
register unsigned short cl_no = entry->d_cluster;
char buffer[MAX_CLUSTER_SIZE];
short rest;
if (entry->d_size == 0) /* Empty file */
return;
do {
disk_read(clus_add(cl_no), buffer, cluster_size);
rest = (entry->d_size > (long) cluster_size) ? cluster_size : (short) entry->d_size;
print(STD_OUT, buffer, rest);
entry->d_size -= (long) rest;
cl_no = next_cluster(cl_no);
if ((Tfat && cl_no == BAD) || (!Tfat && cl_no == BAD_16)){
flush();
print_string(TRUE, "Reserved cluster value encountered.\n");
leave(1);
}
} while ((Tfat && entry->d_size && cl_no != LAST_CLUSTER) ||
(!Tfat && entry->d_size && cl_no != LAST_16));
if ((Tfat && cl_no != LAST_CLUSTER) || (!Tfat && cl_no != LAST_16))
print_string(TRUE, "Too many clusters allocated for file.\n");
else if (entry->d_size != 0)
print_string(TRUE, "Premature EOF: %L bytes left.\n",
entry->d_size);
}
print(fd, buffer, bytes)
short fd;
register char *buffer;
register short bytes;
{
static short index;
static BOOL lf_pending = FALSE;
static char output[MAX_CLUSTER_SIZE + 1];
if (buffer == NIL_PTR) {
if (dos_read && Aflag && lf_pending) {
output[index++] = '\r';
lf_pending = FALSE;
}
if (write(fd, output, index) != index)
bad();
index = 0;
return;
}
if (bytes == 0)
bytes = strlen(buffer);
while (bytes--) {
if (index >= MAX_CLUSTER_SIZE) {
if (write(fd, output, index) != index)
bad ();
index = 0;
}
if (dos_read && Aflag) {
if (*buffer == '\r') {
if (lf_pending)
output[index++] = *buffer++;
else {
lf_pending = TRUE;
buffer++;
}
}
else if (*buffer == '\n') {
output[index++] = *buffer++;
lf_pending = FALSE;
}
else if (lf_pending) {
output[index++] = '\r';
output[index++] = *buffer++;
}
else if ((output[index++] = *buffer++) == EOF_MARK) {
if (lf_pending) {
output[index - 1] = '\r';
index++;
lf_pending = FALSE;
}
index--;
return;
}
}
else
output[index++] = *buffer++;
}
}
make_file(dir_ptr, entries, name)
DIRECTORY *dir_ptr;
int entries;
char *name;
{
register DIRECTORY *entry = new_entry(dir_ptr, entries);
register char *ptr;
char buffer[MAX_CLUSTER_SIZE];
unsigned short cl_no, next;
short i, r;
long size = 0L;
bcopy(" ",&entry->d_name[0],11); /* clear entry */
for (i = 0, ptr = name; i < 8 && *ptr != '.' && *ptr; i++)
entry->d_name[i] = *ptr++;
while (*ptr != '.' && *ptr)
ptr++;
if (*ptr == '.')
ptr++;
for (i=0;i < 3 && *ptr; i++)
entry->d_ext[i] = *ptr++;
for (i = 0; i < 10; i++)
entry->d_reserved[i] = '\0';
entry->d_attribute = '\0';
entry->d_cluster = 0;
while ((r = fill(buffer)) > 0) {
if ((next = free_cluster(FALSE)) > total_clusters) {
print_string(TRUE, "Disk full. File truncated.\n");
break;
}
disk_write(clus_add(next), buffer, r);
if (entry->d_cluster == 0)
cl_no = entry->d_cluster = next;
else {
link_fat(cl_no, next);
cl_no = next;
}
size += r;
}
if (entry->d_cluster != 0) {
if (Tfat)
link_fat(cl_no, LAST_CLUSTER);
else
link_fat(cl_no, LAST_16);
}
entry->d_size = Aflag ? (size - 1) : size; /* Strip added ^Z */
fill_date(entry);
disk_write(mark, entry, DIR_SIZE);
if (Tfat) {
disk_write(f_start, fat.twelve, fat_size);
disk_write(f_start + (long) fat_size, fat.twelve, fat_size);
} else {
disk_write(f_start, fat.sixteen, fat_size);
disk_write(f_start + (long) fat_size, fat.sixteen, fat_size);
}
}
#define SEC_MIN 60L
#define SEC_HOUR (60L * SEC_MIN)
#define SEC_DAY (24L * SEC_HOUR)
#define SEC_YEAR (365L * SEC_DAY)
#define SEC_LYEAR (366L * SEC_DAY)
short mon_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
fill_date(entry)
DIRECTORY *entry;
{
register long cur_time = time((long *) 0) - DOS_TIME;
unsigned short year = 0, month = 1, day, hour, minutes, seconds;
int i;
long tmp;
if (cur_time < 0) /* Date not set on booting ... */
cur_time = 0;
for (;;) {
tmp = (year % 4 == 0) ? SEC_LYEAR : SEC_YEAR;
if (cur_time < tmp)
break;
cur_time -= tmp;
year++;
}
day = (unsigned short) (cur_time / SEC_DAY);
cur_time -= (long) day *SEC_DAY;
hour = (unsigned short) (cur_time / SEC_HOUR);
cur_time -= (long) hour *SEC_HOUR;
minutes = (unsigned short) (cur_time / SEC_MIN);
cur_time -= (long) minutes *SEC_MIN;
seconds = (unsigned short) cur_time;
mon_len[1] = (year % 4 == 0) ? 29 : 28;
i = 0;
while (day >= mon_len[i]) {
month++;
day -= mon_len[i++];
}
day++;
entry->d_date = (year << 9) | (month << 5) | day;
entry->d_time = (hour << 11) | (minutes << 5) | seconds;
}
char *make_name(dir_ptr, dir_fl)
register DIRECTORY *dir_ptr;
short dir_fl;
{
static char name_buf[14];
register char *ptr = name_buf;
short i;
for (i = 0; i < 8; i++)
*ptr++ = dir_ptr->d_name[i];
while (*--ptr == ' ');
ptr++;
if (dir_ptr->d_ext[0] != ' ') {
*ptr++ = '.';
for (i = 0; i < 3; i++)
*ptr++ = dir_ptr->d_ext[i];
while (*--ptr == ' ');
ptr++;
}
if (dir_fl)
*ptr++ = '/';
*ptr = '\0';
return name_buf;
}
fill(buffer)
register char *buffer;
{
static BOOL eof_mark = FALSE;
char *last = &buffer[cluster_size];
char *begin = buffer;
register short c;
if (eof_mark)
return 0;
while (buffer < last) {
if ((c = get_char()) == EOF) {
eof_mark = TRUE;
if (Aflag)
*buffer++ = EOF_MARK;
break;
}
*buffer++ = c;
}
return (int) (buffer - begin);
}
get_char()
{
static short read_chars, index;
static char input[MAX_CLUSTER_SIZE];
static BOOL new_line = FALSE;
if (new_line == TRUE) {
new_line = FALSE;
return '\n';
}
if (index == read_chars) {
if ((read_chars = read(0, input, cluster_size)) == 0)
return EOF;
index = 0;
}
if (Aflag && input[index] == '\n') {
new_line = TRUE;
index++;
return '\r';
}
return input[index++];
}
#define HOUR 0xF800 /* Upper 5 bits */
#define MIN 0x07E0 /* Middle 6 bits */
#define YEAR 0xFE00 /* Upper 7 bits */
#define MONTH 0x01E0 /* Mid 4 bits */
#define DAY 0x01F /* Lowest 5 bits */
char *month[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
modes(mode)
register unsigned char mode;
{
print_string(FALSE, "\t%c%c%c%c%c", (mode & SUB_DIR) ? 'd' : '-',
(mode & 02) ? 'h' : '-', (mode & 04) ? 's' : '-',
(mode & 01) ? '-' : 'w', (mode & 0x20) ? 'a' : '-');
}
show(dir_ptr, name)
DIRECTORY *dir_ptr;
char *name;
{
register unsigned short e_date = dir_ptr->d_date;
register unsigned short e_time = dir_ptr->d_time;
unsigned short next;
char bname[20];
short i = 0;
while (*name && *name != '/')
bname[i++] = *name++;
bname[i] = '\0';
if (!Lflag) {
print_string(FALSE, "%s\n", bname);
return;
}
modes(dir_ptr->d_attribute);
print_string(FALSE, "\t%s%s", bname, strlen(bname) < 8 ? "\t\t" : "\t");
i = 1;
if (is_dir(dir_ptr)) {
next = dir_ptr->d_cluster;
while (((next = next_cluster(next)) != LAST_CLUSTER && Tfat) ||
(!Tfat && next != LAST_16))
i++;
print_string(FALSE, "%L", (long) i * (long) cluster_size);
}
else
print_string(FALSE, "%L", dir_ptr->d_size);
print_string(FALSE, "\t%N:%N %P %s %d\n", ((e_time & HOUR) >> 11),
((e_time & MIN) >> 5), (e_date & DAY),
month[((e_date & MONTH) >> 5) - 1], ((e_date & YEAR) >> 9) + 1980);
}
free_blocks()
{
register unsigned short cl_no;
register short free = 0;
short bad = 0;
if (Tfat)
for (cl_no = 2; cl_no <= total_clusters; cl_no++) {
switch (next_cluster(cl_no)) {
case FREE:
free++;
break;
case BAD:
bad++;
}
}
else
for (cl_no = 2; cl_no <= total_clusters; cl_no++) {
switch (next_cluster(cl_no)) {
case FREE_16:
free++;
break;
case BAD_16:
bad++;
}
}
print_string(FALSE, "Free space: %L bytes.\n", (long) free * (long) cluster_size);
if (bad)
print_string(FALSE, "Bad sectors: %L bytes.\n", (long) bad * (long) cluster_size);
}
char *num_out(number)
register long number;
{
static char num_buf[13];
char temp[13];
register short i = 0;
short j;
if (number == 0)
temp[i++] = '0';
while (number) {
temp[i++] = (char) (number % 10L + '0');
number /= 10L;
}
for (j = 0; j < 11; j++)
num_buf[j] = temp[i - j - 1];
num_buf[i] = '\0';
return num_buf;
}
/* VARARGS */
print_string(err_fl, fmt, args)
BOOL err_fl;
char *fmt;
int args;
{
char buf[200];
register char *buf_ptr = buf;
char *scan_ptr;
register int *arg_ptr = &args;
short i;
while (*fmt) {
if (*fmt == '%') {
fmt++;
if (*fmt == 'c') {
*buf_ptr++ = (char) *arg_ptr++;
fmt++;
continue;
}
if (*fmt == 'S') {
scan_ptr = (char *) *arg_ptr;
for (i = 0; i < 11; i++)
*buf_ptr++ = *scan_ptr++;
fmt++;
continue;
}
if (*fmt == 's')
scan_ptr = (char *) *arg_ptr;
else if (*fmt == 'L') {
scan_ptr = num_out(*((long *) arg_ptr));
arg_ptr++;
}
else {
scan_ptr = num_out((long) *arg_ptr);
if (*fmt == 'P' && *arg_ptr < 10)
*buf_ptr++ = ' ';
else if (*fmt == 'N' && *arg_ptr < 10)
*buf_ptr++ = '0';
}
while (*buf_ptr++ = *scan_ptr++);
buf_ptr--;
arg_ptr++;
fmt++;
}
else
*buf_ptr++ = *fmt++;
}
*buf_ptr = '\0';
if (err_fl) {
flush();
write(2, buf, (int) (buf_ptr - buf));
}
else
print(STD_OUT, buf, 0);
flush();
}
DIRECTORY *read_cluster(cluster)
register unsigned short cluster;
{
register DIRECTORY *sub_dir;
extern char *sbrk();
if ((sub_dir = (DIRECTORY *) sbrk(cluster_size)) < 0) {
print_string(TRUE, "Cannot set break!\n");
leave(1);
}
disk_read(clus_add(cluster), sub_dir, cluster_size);
return sub_dir;
}
unsigned short free_cluster(leave_fl)
BOOL leave_fl;
{
static unsigned short cl_index = 2;
if (Tfat)
while (cl_index <= total_clusters && next_cluster(cl_index) != FREE)
cl_index++;
else /* Sixteen bit */
while (cl_index <= total_clusters && next_cluster(cl_index) != FREE_16)
cl_index++;
if (leave_fl && cl_index > total_clusters) {
flush();
print_string(TRUE, "Disk full. File not added.\n");
leave(1);
}
return cl_index++;
}
/* ****************FIX FOR SIXTEEN BIT ***************** */
link_fat(cl_1, cl_2)
unsigned short cl_1;
register unsigned short cl_2;
{
if (Tfat) {
register unsigned char *fat_index = &fat.twelve[(cl_1 >> 1) * 3 + 1];
if (cl_1 & 0x01) {
*(fat_index + 1) = cl_2 >> 4;
*fat_index = (*fat_index & 0x0F) | ((cl_2 & 0x0F) << 4);
}
else {
*(fat_index - 1) = cl_2 & 0x0FF;
*fat_index = (*fat_index & 0xF0) | (cl_2 >> 8);
}
}
else {
fat.sixteen[cl_1] = cl_2;
}
}
unsigned short next_cluster(cl_no)
register unsigned short cl_no;
{
if (Tfat) {
register unsigned char *fat_index = &fat.twelve[(cl_no >> 1) * 3 + 1];
if (cl_no & 0x01)
cl_no = (*(fat_index + 1) << 4) | (*fat_index >> 4);
else
cl_no = ((*fat_index & 0x0F) << 8) | *(fat_index - 1);
if ((cl_no & MASK) == MASK)
cl_no = LAST_CLUSTER;
else if ((cl_no & BAD) == BAD)
cl_no = BAD;
}
else {
/*cl_no = fat.sixteen[cl_no << 1];*/
cl_no = fat.sixteen[cl_no];
if ((cl_no & MASK_16) == MASK_16)
cl_no = LAST_16;
else if ((cl_no & BAD_16) == BAD_16)
cl_no = BAD_16;
}
return cl_no;
}
char *slash(str)
register char *str;
{
register char *result = str;
while (*str)
if (*str++ == '/')
result = str;
return result;
}
add_path(file, slash_fl)
register char *file;
BOOL slash_fl;
{
register char *ptr = path;
while (*ptr)
ptr++;
if (file == NIL_PTR) {
ptr--;
do {
ptr--;
} while (*ptr != '/' && ptr != path);
if (ptr != path && !slash_fl)
ptr++;
*ptr = '\0';
}
else
while (*ptr++ = *file++);
}
bcopy(src, dest, bytes)
register char *src, *dest;
short bytes;
{
while (bytes--)
*dest++ = *src++;
}
disk_io(op, seek, address, bytes)
register BOOL op;
unsigned long seek;
DIRECTORY *address;
register unsigned bytes;
{
unsigned int r;
if (lseek(disk, seek, 0) < 0L) {
flush();
print_string(TRUE, "Bad lseek\n");
leave(1);
}
if (op == READ)
r = read(disk, address, bytes);
else
r = write(disk, address, bytes);
if (r != bytes)
bad();
}
bad()
{
flush();
perror("I/O error");
leave(1);
}