/* ** Sizeable RAMDisk formatter ** Version 1.10 ** ** Compiled with Turbo C++ 1.0 ** ** Released to PUBLIC DOMAIN by author Marko Kohtala 1991 ** ** Some documentation available in accompanying file SRDISK.DOC. ** If not, contact author by sending E-mail from ** ** Internet, Bitnet etc. to 'mkohtala@niksula.hut.fi' ** CompuServe to '>INTERNET:mkohtala@niksula.hut.fi' ** ** or by calling Airline QBBS, 24H, HST, V.32, V.42, MNP, ** +358-0-8725380, and leaving mail to me, Marko Kohtala. */ #define VERSION "1.10" /* History ** ** 1.00 09-06-91 Initial release ** 1.10 06-09-91 Added full support for multiple FATs. 1.00 had the /F ** switch, but no support for it in formatter. Updated to ** IOCTL_msg versio 1.10 so that media byte is no longer ** used to indicate the media change but to indicate the ** drive is RAM disk. Some minor fixes. */ #include #include #include #include #include #include /* IOCTL_msg exchanged with ramdrive (byte aligned) */ #pragma option -a- #pragma pack(1) const struct IOCTL_msg_hdr_s { /* Header of the structure for comparison */ unsigned short len; /* The size of the structure */ char unused; /* A byte to make it look like boot sector */ char OEM[8]; /* OEM and structure version number */ }; struct IOCTL_msg_s { /* The whole structure */ struct IOCTL_msg_hdr_s hdr; unsigned short bytes_per_sector; unsigned char sectors_per_cluster; unsigned short reserved_sectors; unsigned char FATs; /* Number of FATs on disk */ unsigned short dir_entries; /* Root directory entries */ unsigned short sectors; /* Total number of sectors on disk */ unsigned char media; /* Identifies the media (default 0xFA) */ unsigned short FAT_sectors; /* Sectors in one copy of FAT */ unsigned short disk_size; /* Disk size in kilobytes */ char volume[12]; /* This is returned in the Check Media call */ unsigned char RW_access; signed char media_change; /* -1 if media changed, 1 if not */ unsigned short open_files; /* These last two are not accepted in the */ int (far *IO_entry)(void); /* driver but must be sent anyway */ } IOCTL_msg; #define READ_ACCESS 1 /* Bit masks for RW_access in IOCTL_msg_s */ #define WRITE_ACCESS 2 #pragma pack() #pragma option -a struct IOCTL_msg_hdr_s IOCTL_msg_hdr = { sizeof (struct IOCTL_msg_s), 0x90, "SRD 1.10" }; /* Variables possibly supplied in command line */ int drive=0; int format_f=0; /* Nonzero if new format given */ int force_f=0; /* Nonzero if ok to format */ enum {same, set, clear} write_f = same; /* Write protect flag */ int disk_size=-1; /* Size in kilobytes, -1 not set */ int sector_size=-1; /* Sector size, -1 not set */ int cluster_size=-1; /* Allocation unit size, -1 not set */ int dir_entries=-1; /* Directory entries in root directory, -1 not set */ int FATs=-1; /* FAT copies on the disk */ /* ** SYNTAX */ void print_syntax(void) { fprintf(stderr, "Syntax: SRDISK [[:]] [] [S:]\n" "\t\t[C:] [D:] [F:]\n" "\t\t[/W[-]] [/Y]\n\n" "Cluster and sector sizes may be one of 128, 256, 512, 1024, 2048 or 4096.\n" "The following switches may remain unclear from the above:\n\n" "\t/W[-] Write protect disk, /W- enables writes\n" "\t/Y Yes, to all queries i.e. no talking, just do it\n" "\n"); } /* ** ERROR HANDLING FUNCTIONS */ void syntax(char *err) { fprintf(stderr, "Syntax error: %s\n\n", err); print_syntax(); exit(3); } void fatal(char *err) { fprintf(stderr, "Fatal error: %s\n\n", err); exit(1); } void error(char *err) { fprintf(stderr, "Error: %s\n\n", err); return; } /* ** COMMAND LINE PARSER */ int parse_narg(char *argp, char **next) { int res; if (*argp == ':') argp++; res = strtol(argp, next, 10); if (argp == *next) return -1; return res; } int test_sec_size(int size) { switch(size) { case 128: case 256: case 512: case 1024: case 2048: case 4096: return 0; /* Return 0 for good size */ default: return 1; /* Return 1 for bad size */ } } void parse_cmdline(int argc, char *argv[]) { int arg; char *argp; for(arg=1; arg < argc; arg++) { argp = argv[arg]; while(*argp) { if (*argp == '/' || *argp == '-') { argp++; switch(toupper(*argp++)) { case '?': case 'H': print_syntax(); exit(0); case 'W': switch(*argp) { case '-': argp++; write_f = clear; break; case '+': argp++; default: write_f = set; } break; case 'Y': force_f++; break; case 'S': /* Sector size */ sector_size = parse_narg(argp, &argp); if (test_sec_size(sector_size)) syntax("Invalid sector size"); format_f++; break; case 'C': /* Cluster size */ cluster_size = parse_narg(argp, &argp); if (test_sec_size(cluster_size)) syntax("Invalid cluster size"); format_f++; break; case 'D': /* Directory entries */ dir_entries = parse_narg(argp, &argp); if (dir_entries < -1 || !dir_entries || dir_entries == 1 || dir_entries > 1000) syntax("Invalid number of directory entries"); format_f++; break; case 'F': /* FATs */ FATs = parse_narg(argp, &argp); if (FATs < -1 || !FATs) syntax("Invalid number of FAT copies"); format_f++; break; default: syntax("Unknown switch"); } } else { if (*argp == ' ' || *argp == '\t') argp++; else if (isdigit(*argp)) { disk_size = strtol(argp, &argp, 10); if (disk_size < 0 || disk_size > 32767) syntax("Invalid disk size"); format_f++; } else { if (drive) syntax("Unrecognised character on command line"); drive = toupper(*argp++)-'A'+1; if (drive < 1 || drive > 'Z'-'A'+1) syntax("Invalid drive"); if (*argp == ':') argp++; } } } } } /* ** IOCTL messages */ void read_IOCTL_msg(void) { if (ioctl(drive, 4, &IOCTL_msg, sizeof IOCTL_msg) != sizeof IOCTL_msg || memcmp(&IOCTL_msg, &IOCTL_msg_hdr, sizeof IOCTL_msg_hdr)) fatal("Drive not proper Sizeable RAMDisk"); } int write_IOCTL_msg(void) { if (ioctl(drive, 5, &IOCTL_msg, sizeof (struct IOCTL_msg_s)) != sizeof (struct IOCTL_msg_s)) { error("RAMDisk driver won't accept new setup"); return 1; } return 0; } void print_IOCTL_msg() { int cluster_size = IOCTL_msg.bytes_per_sector * IOCTL_msg.sectors_per_cluster; int dir_sectors = IOCTL_msg.dir_entries * 32 / IOCTL_msg.bytes_per_sector; int clusters = (IOCTL_msg.sectors - IOCTL_msg.reserved_sectors - IOCTL_msg.FAT_sectors * IOCTL_msg.FATs - dir_sectors) / IOCTL_msg.sectors_per_cluster; printf(" Disk size: %iK\n" " Cluster size: %i bytes\n" " Sector size: %i bytes\n" " Directory entries: %i\n" " FAT copies: %i\n" " Bytes available: %li\n" " Write protection: %s\n" #ifdef VERBOSE " Sectors: %i\n" " Reserved sectors: %i\n" " FAT sectors: %i\n" " Directory sectors: %i\n" " Sectors per cluster: %i\n" " Clusters: %i\n" #endif "\n" ,IOCTL_msg.disk_size ,cluster_size ,IOCTL_msg.bytes_per_sector ,IOCTL_msg.dir_entries ,IOCTL_msg.FATs ,(long)clusters*cluster_size ,((IOCTL_msg.RW_access & WRITE_ACCESS) ? "OFF" : "ON") #ifdef VERBOSE ,IOCTL_msg.sectors ,IOCTL_msg.reserved_sectors ,IOCTL_msg.FAT_sectors ,dir_sectors ,IOCTL_msg.sectors_per_cluster ,clusters #endif ); } /* ** Write sectors to disk ** ** Return 0 for success and 1 for failure */ int write_sector(int count, int start, void *buffer) { if (!IOCTL_msg.IO_entry) fatal("Internal error writing sector"); _BH = 1; /* Write */ _CX = count; _DX = start; _ES = FP_SEG(buffer); _DI = FP_OFF(buffer); return IOCTL_msg.IO_entry(); } /* ** INITIALIZE DRIVE */ void init_drive(void) { read_IOCTL_msg(); if (!force_f) { if (IOCTL_msg.disk_size) { printf("Current configuration for drive %c:\n\n", drive-1+'A'); print_IOCTL_msg(); } else printf("Drive %c: disabled\n\n", drive-1+'A'); } } /* ** SET WRITE PROTECT */ void set_write_protect() { switch(write_f) { case set: IOCTL_msg.RW_access &= ~WRITE_ACCESS; if (!write_IOCTL_msg()) printf("Write protect enabled\n\n"); break; case clear: IOCTL_msg.RW_access |= WRITE_ACCESS; if (!write_IOCTL_msg()) printf("Write protect disabled\n\n"); break; } } /* ** FORMAT DISK */ int getYN(void) { int reply; if (force_f) reply = 'Y'; else { do reply = toupper(getch()); while (reply != 'Y' && reply != 'N'); } printf("%c\n\n", reply); if (reply == 'N') return 0; return 1; } int licence_to_kill(void) { if (!force_f) { int reply; printf("\aAbout to destroy all files on drive %c!\n\a" "Continue (Y/N) ? ", drive-1+'A'); if (!getYN()) { printf("\nOperation aborted\n\n"); return 0; } } return 1; } void format_disk(void) { unsigned short old_disk_size = IOCTL_msg.disk_size; unsigned short FAT_sectors; unsigned short data_sectors; unsigned short system_sectors; unsigned short clusters; unsigned short dir_start; unsigned short dir_sectors; unsigned long sectors; ldiv_t ldivr; int Fsec; int i; void *sector; if (!force_f && IOCTL_msg.open_files) { error("Files open on drive"); return; } /* Check disk configuration for changes */ if (disk_size != -1) IOCTL_msg.disk_size = disk_size; if (cluster_size == -1) { cluster_size = IOCTL_msg.bytes_per_sector * IOCTL_msg.sectors_per_cluster; } else { if (cluster_size < IOCTL_msg.bytes_per_sector) cluster_size = IOCTL_msg.bytes_per_sector; IOCTL_msg.sectors_per_cluster = cluster_size / IOCTL_msg.bytes_per_sector; } if (sector_size != -1) IOCTL_msg.bytes_per_sector = sector_size; if (dir_entries != -1) IOCTL_msg.dir_entries = dir_entries; if (FATs != -1) IOCTL_msg.FATs = FATs; /* If Disk will be disabled */ if (!IOCTL_msg.disk_size) { if (!old_disk_size) { /* If was disabled also before */ write_IOCTL_msg(); printf("New configuration saved for later use\n\n"); } else { /* If disk now get's disabled */ if (!licence_to_kill()) return; IOCTL_msg.RW_access = ~READ_ACCESS & ~WRITE_ACCESS; IOCTL_msg.media_change = -1; write_IOCTL_msg(); printf("RAMDisk disabled\n\n"); } return; } /* Count the new BPB for disk and see if it can be made */ /* Make sure sectors are big enough for the disk */ while((sectors = (long)IOCTL_msg.disk_size * 1024 / IOCTL_msg.bytes_per_sector) > 0xFFFFL) IOCTL_msg.bytes_per_sector <<= 1; IOCTL_msg.sectors = sectors; if (cluster_size < IOCTL_msg.bytes_per_sector) cluster_size = IOCTL_msg.bytes_per_sector; IOCTL_msg.sectors_per_cluster = cluster_size / IOCTL_msg.bytes_per_sector; { div_t divr; divr = div(IOCTL_msg.dir_entries * 32, IOCTL_msg.bytes_per_sector); dir_sectors = divr.quot + (divr.rem ? 1 : 0); } system_sectors = IOCTL_msg.reserved_sectors + dir_sectors; data_sectors = IOCTL_msg.sectors - system_sectors; { ldiv_t divr; divr = ldiv((long)3 * data_sectors + 6 * IOCTL_msg.sectors_per_cluster, (long)2 * cluster_size + 3 * IOCTL_msg.FATs); IOCTL_msg.FAT_sectors = divr.quot + (divr.rem ? 1 : 0); } FAT_sectors = IOCTL_msg.FAT_sectors * IOCTL_msg.FATs; system_sectors += FAT_sectors; data_sectors -= FAT_sectors; clusters = data_sectors / IOCTL_msg.sectors_per_cluster; if (IOCTL_msg.sectors <= system_sectors || !clusters) { error("Impossible format for disk"); return; } IOCTL_msg.media_change = -1; /* The media change */ IOCTL_msg.RW_access = (write_f == set ? 0 : WRITE_ACCESS); if (!force_f) { printf("New disk configuration:\n\n"); print_IOCTL_msg(); } if (old_disk_size && !licence_to_kill()) return; sector = malloc(IOCTL_msg.bytes_per_sector); if (!sector) fatal("Insufficient memory"); /* Enable disk */ IOCTL_msg.RW_access |= READ_ACCESS; /* Request the new disk space by sending the BPB */ if (write_IOCTL_msg()) return; /* Return if failed */ /* Write the new disk */ /* Make the boot sector */ memset(sector, 0, IOCTL_msg.bytes_per_sector); memmove(sector, &IOCTL_msg, sizeof IOCTL_msg); *((short *)sector) = 0x1DEB; /* Boot record JMP instruction */ *((short *)sector+12) = 1; /* Sectors per track */ *((short *)sector+13) = 1; /* Sides */ *((short *)sector+14) = 0; /* Hidden sectors */ *(short *)((char *)sector+31) = 0xFEEB; /* Boot code (JMP $) */ write_sector(1, 0, sector); /* Write boot sector */ for (i = 0; i < IOCTL_msg.FATs; i++) { unsigned short sector_n = IOCTL_msg.reserved_sectors + IOCTL_msg.FAT_sectors * i; /* Write 1st FAT sector */ memset(sector, 0, IOCTL_msg.bytes_per_sector); /* Make 1st FAT sector */ ((long *)sector)[0] = 0xFFFF00L | IOCTL_msg.media; write_sector(1, sector_n++, sector); /* Write FAT sectors from 2nd to last */ ((long *)sector)[0] = 0L; for (Fsec = 1; Fsec < IOCTL_msg.FAT_sectors; Fsec++) write_sector(1, sector_n++, sector); } /* Write 1st directory sector */ dir_start = IOCTL_msg.reserved_sectors + FAT_sectors; memcpy(sector, IOCTL_msg.volume, 11); ((char*)sector)[11] = FA_LABEL; write_sector(1, dir_start, sector); /* Write directory sectors from 2nd to last */ memset(sector, 0, 12); for (Fsec = 1; Fsec < dir_sectors; Fsec++) write_sector(1, dir_start+Fsec, sector); free(sector); printf("Disk formatted\n\n"); } /* ** MAIN FUNCTION */ int main(int argc, char *argv[]) { printf("Sizeable RAMDisk Formatter, version "VERSION", " "PUBLIC DOMAIN, 1991\n\n"); parse_cmdline(argc, argv); if (!drive) /* If no drive specified */ drive = getdisk()+1; /* operate on current drive */ init_drive(); if (format_f) format_disk(); else if (write_f != same) set_write_protect(); return 0; }