/* * Initialize a MSDOS diskette. Get the media signature (1st FAT * entry) and alter the floppy disk controller via 'gdisk' ioctl calls * to match the format of the disk. Sets a bunch of global variables. * Returns 0 on success, or 1 on failure. */ #include #include #include #include "msdos.h" extern int fd, dir_len, dir_start, clus_size, fat_len, num_clus; extern unsigned char *fatbuf; extern char *mcwd; int init(mode) int mode; { int code = 0, buflen; unsigned char read_fat(), fat; char *getenv(), *fixmcwd(), *malloc(); long lseek(); void perror(), exit(); struct gdctl gdbuf; if ((fd = open(FLOPPY, mode)) < 0) { perror("init: open"); exit(1); } /* get the disk controller info */ if (ioctl(fd, GDGETA, &gdbuf) < 0) { perror("init: ioctl"); dismount(); } /* assume some defaults */ gdbuf.params.cyls = 40; /* number of cylinders */ gdbuf.params.heads = 1; /* number of heads */ gdbuf.params.psectrk = 8; /* physical sectors per track */ gdbuf.params.pseccyl = 8; /* physical sectors per cylinder */ gdbuf.params.flags = 1; /* disk type flag */ gdbuf.params.step = 0; /* step rate for controller */ gdbuf.params.sectorsz = 512; /* sector size */ /* set the default parameters */ if (ioctl(fd, GDSETA, &gdbuf) < 0) { perror("init: ioctl"); dismount(); } /* read media signature (1st FAT) */ fat = read_fat(); switch(fat) { case 0xfe: /* 40 trk, 8 sect, 1 side */ dir_start = 3; dir_len = 4; clus_size = 1; fat_len = 1; num_clus = 313; gdbuf.params.heads = 1; gdbuf.params.psectrk = 8; gdbuf.params.pseccyl = 8; break; case 0xff: /* 40 trk, 8 sect, 2 sides */ dir_start = 3; dir_len = 7; clus_size = 2; fat_len = 1; num_clus = 315; gdbuf.params.heads = 2; gdbuf.params.psectrk = 8; gdbuf.params.pseccyl = 16; break; case 0xfc: /* 40 trk, 9 sect, 1 side */ dir_start = 5; dir_len = 4; clus_size = 1; fat_len = 2; num_clus = 351; gdbuf.params.heads = 1; gdbuf.params.psectrk = 9; gdbuf.params.pseccyl = 9; break; case 0xfd: /* 40 trk, 9 sect, 2 sides */ dir_start = 5; dir_len = 7; clus_size = 2; fat_len = 2; num_clus = 354; gdbuf.params.heads = 2; gdbuf.params.psectrk = 9; gdbuf.params.pseccyl = 18; break; default: fprintf(stderr, "Unknown format '%02x'\n", fat); code = 1; break; } if (code) return(1); /* set the new-found parameters */ if (ioctl(fd, GDSETA, &gdbuf) < 0) { perror("init: ioctl"); dismount(); } buflen = fat_len * MSECSIZ; fatbuf = (unsigned char *) malloc(buflen); move(1); /* read the FAT sectors */ if (read(fd, fatbuf, buflen) != buflen) { perror("init: read"); exit(1); } /* set dir_chain to root directory */ reset_dir(); /* get Current Working Directory */ mcwd = fixmcwd(getenv("MCWD")); /* test it out.. */ if (subdir("")) { fprintf(stderr, "Environmental variable MCWD needs updating\n"); exit(1); } return(0); } /* * Dismount the floppy. Useful only if one of the above ioctls fail * and leaves the drive light turned on. */ dismount() { struct gdctl gdbuf; void exit(); ioctl(fd, GDDISMNT, &gdbuf); exit(1); } /* * Move the read/write head to the next location. Tries to optimize * the movement by moving relative to current location. The argument * is a logical sector number. All errors are fatal. */ move(sector) int sector; { long cur_loc, next, lseek(); void exit(), perror(); /* get current location */ if ((cur_loc = lseek(fd, 0L, 1)) < 0) { perror("move: lseek"); exit(1); } next = (long) (MSECSIZ * sector) - cur_loc; /* we're already there */ if (next == 0L) return; /* move to next location */ if (lseek(fd, next, 1) < 0) { perror("move: lseek"); exit(1); } return; } /* * Fix MCWD to be a proper directory name. Always has a leading separator. * Never has a trailing separator (unless it is the path itself). */ char * fixmcwd(dirname) char *dirname; { char *s, *strcpy(), *strcat(), *malloc(); static char *ans; ans = malloc(strlen(dirname)+2); /* add a leading separator */ if (*dirname != '/' && *dirname != '\\') { strcpy(ans, "/"); strcat(ans, dirname); } else strcpy(ans, dirname); /* translate to upper case */ for (s = ans; *s; ++s) { if (islower(*s)) *s = toupper(*s); } /* if separator alone */ if (strlen(ans) == 1) return(ans); /* zap the trailing separator */ s--; if (*s == '/' || *s == '\\') *s = NULL; return(ans); } /* * Read the first byte of the FAT table. This code serves as a media * signature for the diskette. */ unsigned char read_fat() { unsigned char buf[MSECSIZ]; static unsigned char ans; /* move to boot sector */ if (lseek(fd, (long) MSECSIZ, 0) < 0) { perror("init: lseek"); exit(1); } /* read the first FAT sector */ if (read(fd, buf, MSECSIZ) != MSECSIZ) { fprintf(stderr, "Drive empty or latch not closed\n"); exit(1); } ans = buf[0]; return(ans); }