1: /* 2: * Initialize an MSDOS diskette. Read the boot sector, and switch to the 3: * proper floppy disk device to match the format on the disk. Sets a bunch 4: * of global variables. Returns 0 on success, or 1 on failure. 5: */ 6: 7: #include <stdio.h> 8: #include <ctype.h> 9: #include <sys/types.h> 10: #include <sys/stat.h> 11: #include "msdos.h" 12: 13: #define FULL_CYL 14: #define WORD(x) ((boot->x)[0] + ((boot->x)[1] << 8)) 15: #define DWORD(x) ((boot->x)[0] + ((boot->x)[1] << 8) + ((boot->x)[2] << 16) + ((boot->x)[3] << 24)) 16: 17: unsigned int num_clus; /* total number of cluster */ 18: int num_fat; /* the number of FAT tables */ 19: long disk_offset; /* skip this many bytes */ 20: int fat_bits; /* the FAT encoding scheme */ 21: 22: extern int fd, fat_len, dir_len, dir_start, clus_size, dir_dirty, disk_dirty; 23: extern int fat_error, disk_size; 24: extern long disk_current; 25: extern char *mcwd; 26: extern unsigned char *fat_buf, *disk_buf, *dir_buf; 27: extern struct device devices[]; 28: static struct bootsector *read_boot(); 29: 30: int 31: init(drive, mode) 32: char drive; 33: int mode; 34: { 35: int fat_start, tracks, heads, sectors, old_dos; 36: char *malloc(), *name, *expand(); 37: void perror(), exit(), reset_chain(), free(), fat_read(); 38: struct bootsector *boot; 39: struct device *dev; 40: 41: if (fd != -1) { 42: close(fd); 43: free((char *) fat_buf); 44: free((char *) disk_buf); 45: free((char *) dir_buf); 46: } 47: /* check out the drive letter */ 48: dev = devices; 49: while (dev->drive) { 50: if (dev->drive == drive) 51: break; 52: dev++; 53: } 54: if (!dev->drive) { 55: fprintf(stderr, "Drive '%c:' not supported\n", drive); 56: return(1); 57: } 58: /* open the device */ 59: while (dev->name) { 60: if (dev->drive != drive) 61: break; 62: 63: name = expand(dev->name); 64: if ((fd = open(name, mode | dev->mode)) < 0) { 65: perror("init: open"); 66: exit(1); 67: } 68: /* set default parameters, if needed */ 69: if (dev->gioctl) { 70: if ((*(dev->gioctl)) (fd, dev->tracks, dev->heads, dev->sectors)) 71: goto try_again; 72: } 73: /* read the boot sector */ 74: disk_offset = dev->offset; 75: if ((boot = read_boot()) == NULL) 76: goto try_again; 77: 78: heads = WORD(nheads); 79: sectors = WORD(nsect); 80: if (heads && sectors) 81: tracks = WORD(psect) / (unsigned) (heads * sectors); 82: 83: /* sanity checking */ 84: old_dos = 0; 85: if (!heads || heads > 100 || !sectors || sectors > 500 || tracks > 5000 || !boot->clsiz) { 86: /* 87: * The above technique will fail on diskettes that 88: * have been formatted with very old MSDOS, so we 89: * resort to the old table-driven method using the 90: * media signature (first byte in FAT). 91: */ 92: unsigned char temp[MSECTOR_SIZE]; 93: if (read(fd, (char *) temp, MSECTOR_SIZE) != MSECTOR_SIZE) 94: temp[0] = '0'; 95: 96: switch (temp[0]) { 97: case 0xfe: /* 160k */ 98: tracks = 40; 99: sectors = 8; 100: heads = 1; 101: dir_start = 3; 102: dir_len = 4; 103: clus_size = 1; 104: fat_len = 1; 105: num_clus = 313; 106: break; 107: case 0xfc: /* 180k */ 108: tracks = 40; 109: sectors = 9; 110: heads = 1; 111: dir_start = 5; 112: dir_len = 4; 113: clus_size = 1; 114: fat_len = 2; 115: num_clus = 351; 116: break; 117: case 0xff: /* 320k */ 118: tracks = 40; 119: sectors = 8; 120: heads = 2; 121: dir_start = 3; 122: dir_len = 7; 123: clus_size = 2; 124: fat_len = 1; 125: num_clus = 315; 126: break; 127: case 0xfd: /* 360k */ 128: tracks = 40; 129: sectors = 9; 130: heads = 2; 131: dir_start = 5; 132: dir_len = 7; 133: clus_size = 2; 134: fat_len = 2; 135: num_clus = 354; 136: break; 137: default: 138: fprintf(stderr, "Probable non-MSDOS disk\n"); 139: close(fd); 140: fd = -1; 141: return(1); 142: } 143: fat_start = 1; 144: num_fat = 2; 145: old_dos = 1; 146: } 147: /* check the parameters */ 148: if (dev->tracks && !dev->gioctl) { 149: if (dev->tracks == tracks && dev->heads == heads && dev->sectors == sectors) 150: break; 151: } 152: else 153: break; 154: 155: try_again: close(fd); 156: fd = -1; 157: dev++; 158: } 159: if (fd == -1) { 160: if (boot != NULL && dev->tracks) 161: fprintf(stderr, "No support for %d tracks, %d heads, %d sector diskettes\n", tracks, heads, sectors); 162: return(1); 163: } 164: /* set new parameters, if needed */ 165: if (dev->gioctl) { 166: if ((*(dev->gioctl)) (fd, tracks, heads, sectors)) { 167: fprintf(stderr, "Can't set disk parameters\n"); 168: close(fd); 169: fd = -1; 170: return(1); 171: } 172: } 173: 174: /* 175: * all numbers are in sectors, except num_clus (which is in clusters) 176: */ 177: if (!old_dos) { 178: clus_size = boot->clsiz; 179: fat_start = WORD(nrsvsect); 180: fat_len = WORD(fatlen); 181: dir_start = fat_start + (boot->nfat * fat_len); 182: dir_len = WORD(dirents) * MDIR_SIZE / (unsigned) MSECTOR_SIZE; 183: /* 184: * For DOS partitions > 32M 185: */ 186: if (WORD(psect) == 0) 187: num_clus = (unsigned int) (DWORD(bigsect) - dir_start - dir_len) / clus_size; 188: else 189: num_clus = (unsigned int) (WORD(psect) - dir_start - dir_len) / clus_size; 190: num_fat = boot->nfat; 191: } 192: /* more sanity checking */ 193: if (clus_size * MSECTOR_SIZE > MAX_CLUSTER) { 194: fprintf(stderr, "Cluster size of %d is larger than max of %d\n", clus_size * MSECTOR_SIZE, MAX_CLUSTER); 195: close(fd); 196: fd = -1; 197: return(1); 198: } 199: if (!old_dos && WORD(secsiz) != MSECTOR_SIZE) { 200: fprintf(stderr, "Sector size of %d is not supported\n", WORD(secsiz)); 201: close(fd); 202: fd = -1; 203: return(1); 204: } 205: /* full cylinder buffering */ 206: #ifdef FULL_CYL 207: disk_size = (dev->tracks) ? (sectors * heads) : 1; 208: #else /* FULL_CYL */ 209: disk_size = (dev->tracks) ? sectors : 1; 210: #endif /* FULL_CYL */ 211: 212: /* 213: * The driver in Dell's SVR4 v2.01 is unreliable with large writes. 214: */ 215: #ifdef DELL 216: disk_size = 1; 217: #endif /* DELL */ 218: 219: disk_buf = (unsigned char *) malloc((unsigned int) disk_size * MSECTOR_SIZE); 220: if (disk_buf == NULL) { 221: perror("init: malloc"); 222: exit(1); 223: } 224: /* read the FAT sectors */ 225: disk_current = -1000L; 226: disk_dirty = 0; 227: fat_error = 0; 228: fat_bits = dev->fat_bits; 229: fat_read(fat_start); 230: /* set dir_chain[] to root directory */ 231: dir_dirty = 0; 232: reset_chain(NEW); 233: return(0); 234: } 235: 236: /* 237: * Fix the info in the MCWD file to be a proper directory name. Always 238: * has a leading separator. Never has a trailing separator (unless it is 239: * the path itself). 240: */ 241: 242: char * 243: fix_mcwd() 244: { 245: FILE *fp; 246: struct stat sbuf; 247: char *s, *strcpy(), *strcat(), *mcwd_path, *getenv(), *strncpy(); 248: char buf[BUFSIZ], *file, *expand(); 249: static char ans[MAX_PATH]; 250: long now, time(); 251: 252: mcwd_path = getenv("MCWD"); 253: if (mcwd_path == NULL || *mcwd_path == '\0') 254: mcwd_path = "$HOME/.mcwd"; 255: 256: file = expand(mcwd_path); 257: if (stat(file, &sbuf) < 0) 258: return("A:/"); 259: /* 260: * Ignore the info, if the file is more than 6 hours old 261: */ 262: time(&now); 263: if (now - sbuf.st_mtime > 6 * 60 * 60) { 264: fprintf(stderr, "Warning: \"%s\" is out of date, contents ignored\n", file); 265: return("A:/"); 266: } 267: 268: if (!(fp = fopen(file, "r"))) 269: return("A:/"); 270: 271: if (!fgets(buf, BUFSIZ, fp)) 272: return("A:/"); 273: 274: buf[strlen(buf) -1] = '\0'; 275: fclose(fp); 276: /* drive letter present? */ 277: s = buf; 278: if (buf[0] && buf[1] == ':') { 279: strncpy(ans, buf, 2); 280: ans[2] = '\0'; 281: s = &buf[2]; 282: } 283: else 284: strcpy(ans, "A:"); 285: /* add a leading separator */ 286: if (*s != '/' && *s != '\\') { 287: strcat(ans, "/"); 288: strcat(ans, s); 289: } 290: else 291: strcat(ans, s); 292: /* translate to upper case */ 293: for (s = ans; *s; ++s) { 294: if (islower(*s)) 295: *s = toupper(*s); 296: if (*s == '\\') 297: *s = '/'; 298: } 299: /* if only drive, colon, & separator */ 300: if (strlen(ans) == 3) 301: return(ans); 302: /* zap the trailing separator */ 303: if (*--s == '/') 304: *s = '\0'; 305: return(ans); 306: } 307: 308: /* 309: * Read the boot sector. We glean the disk parameters from this sector. 310: */ 311: 312: static struct bootsector * 313: read_boot() 314: { 315: long lseek(); 316: static struct bootsector boot; 317: 318: if (lseek(fd, disk_offset, 0) < 0) 319: return(NULL); 320: /* read the first sector */ 321: if (read(fd, (char *) &boot, MSECTOR_SIZE) != MSECTOR_SIZE) 322: return(NULL); 323: 324: return(&boot); 325: }