home *** CD-ROM | disk | FTP | other *** search
- /*
- ** ReSizeable RAMDisk formatter
- ** Version 1.20
- **
- ** Compiled with Borland C++ 2.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.20"
-
- /* 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.
-
- 1.20 04-10-1991
-
- - Fixed name of program by adding the missing 'Re' to 'Sizeable'.
-
- - Added 16 bit FAT support; more 'sizeable' disks that had over 4077
- clusters were not operational. Due to DOS's inconsistent behaviour,
- disks with over 4077 and under 4088 clusters (or over 65518, possible
- with 128 byte clusters and 8M disk size) are avoided by making
- clusters bigger.
-
- - Added DOS lookalike disk formats via switch /F.
-
- - The FAT number is now defined via switch /A instead of /F.
-
- - The time of format is stored in volume label.
-
- - Upgraded to IOCTL_msg version 1.20 which tells the type of memory used
- by the driver.
-
- - Disallow sectors greater than 512 bytes as DOS can not handle them
- properly but rather crashes when it encounters them.
-
- - Allow clusters up to 8 kilobytes.
-
- - Enhanced help.
-
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <io.h>
- #include <dir.h>
- #include <dos.h>
- #include <string.h>
- #include <time.h>
-
- /* 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 */
- unsigned char memory_type; /* Types of memory the driver uses */
- } IOCTL_msg;
-
- #define READ_ACCESS 1 /* Bit masks for RW_access in IOCTL_msg_s */
- #define WRITE_ACCESS 2
-
- #define XMS_MEMORY 1 /* Different memory types supported bit masks */
- #define EMS_MEMORY 2
- #define CONV_MEMORY 4
- #define BSW_MEMORY 8
- #define UNKNOWN_MEMORY 0xF0
-
- #pragma pack()
- #pragma option -a
-
- struct IOCTL_msg_hdr_s IOCTL_msg_hdr =
- {
- sizeof (struct IOCTL_msg_s),
- 0x90,
- "SRD 1.20"
- };
-
- /* 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 */
- int media=-1; /* New media */
- int sec_per_track=9; /* Sectors per track */
- int sides=1; /* Sides on disk */
-
- /*
- ** SYNTAX
- */
-
- void print_syntax(void)
- {
- fputs(
- "Syntax: SRDISK [<drive letter>[:]] [<size>] [/S:<sector size>]\n"
- "\t\t[/C:<cluster size>] [/D:<dir entries>] [/A:<FAT copies>]\n"
- "\t\t[/F:<DOS disk size>] [/W[-]] [/Y] [/?]\n\n"
- "Anything inside [] is optional, the brackets must not be typed.\n"
- "'<something>' must be replaced by what something tells.\n\n"
- "<drive letter> specifies the drive that is the RAM disk.\n"
- "<size> determines the disk size in kilobytes.\n"
- "/S:<sector size> is a power of 2 in range from 128 to 512 bytes.\n"
- "/C:<cluster size> is a power of 2 in range from 128 to 8192 bytes.\n"
- "/D:<dir entries> is the maximum number of entries in the root directory.\n"
- "/A:<FAT copies> number of File Allocation Tables on disk. 1 is enough.\n"
- "/F:<DOS disk size> may be one of 160, 180, 320, 360, 720, 1200, 1440.\n"
- "\tThe disk attributes (including media byte) will be set according\n"
- "\tto the matching DOS disk format.\n"
- "/W Write protect disk, /W- enables writes.\n"
- "/Y Yes, to all queries and quiet mode for batch file operation.\n"
- "/? This help.\n"
- "\n", stderr);
- }
-
- /*
- ** 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 ispow2(int size)
- {
- int cmp;
- for (cmp = 128; cmp; cmp <<=1)
- if (cmp == size) return 1;
- return 0;
- }
-
- void set_DOS_disk(int size)
- {
- static struct {
- int disk_size;
- int media;
- int cluster_size;
- int dir_entries;
- int sec_per_track;
- int sides;
- } dos_disk[] = {
- { 160, 0xFE, 512, 64, 8, 1 },
- { 180, 0xFC, 512, 64, 9, 1 },
- { 320, 0xFF,1024, 112, 8, 2 },
- { 360, 0xFD,1024, 112, 9, 2 },
- { 720, 0xF9,1024, 112, 9, 2 },
- { 1200, 0xF9, 512, 224, 15, 2 },
- { 1440, 0xF0, 512, 224, 18, 2 },
- {0}
- };
- int i;
-
- for (i=0; dos_disk[i].disk_size; i++)
- if (dos_disk[i].disk_size == size) {
- disk_size = size;
- cluster_size = dos_disk[i].cluster_size;
- dir_entries = dos_disk[i].dir_entries;
- media = dos_disk[i].media;
- sec_per_track = dos_disk[i].sec_per_track;
- sides = dos_disk[i].sides;
- FATs = 2;
- sector_size = 512;
- format_f++;
- return;
- }
-
- syntax("Unknown DOS disk 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 (!ispow2(sector_size) || sector_size > 512)
- syntax("Invalid sector size");
- format_f++;
- break;
- case 'C': /* Cluster size */
- cluster_size = parse_narg(argp, &argp);
- if (!ispow2(cluster_size) || cluster_size > 8192)
- 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 'A': /* FATs */
- FATs = parse_narg(argp, &argp);
- if (FATs < -1 || !FATs)
- syntax("Invalid number of FAT copies");
- format_f++;
- break;
- case 'F': /* DOS disk format */
- disk_size = parse_narg(argp, &argp);
- set_DOS_disk(disk_size);
- 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++;
- }
- }
- }
- }
- }
-
- /*
- ** DOS time format conversions
- */
-
- unsigned long DOS_time(time_t time)
- {
- struct tm *ltime;
- union {
- struct {
- unsigned short sec2 : 5,
- min : 6,
- hour : 5;
- unsigned short day : 5,
- month : 4,
- year : 7;
- } f;
- unsigned long l;
- } file_time;
-
- ltime = localtime(&time);
- file_time.f.sec2 = ltime->tm_sec;
- file_time.f.min = ltime->tm_min;
- file_time.f.hour = ltime->tm_hour;
- file_time.f.day = ltime->tm_mday;
- file_time.f.month = ltime->tm_mon + 1;
- file_time.f.year = ltime->tm_year - 80;
-
- return file_time.l;
- }
-
- /*
- ** 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 ReSizeable RAMDisk");
- }
-
- int write_IOCTL_msg(void)
- {
- if (ioctl(drive, 5, &IOCTL_msg, sizeof (struct IOCTL_msg_s))
- != sizeof (struct IOCTL_msg_s))
- {
- error("Out of memory?");
- return 1;
- }
- return 0;
- }
-
- void print_IOCTL_msg(void)
- {
- 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');
- printf(" Usable memory types:");
- if (IOCTL_msg.memory_type & XMS_MEMORY) printf(" XMS");
- if (IOCTL_msg.memory_type & EMS_MEMORY) printf(" EMS");
- if (IOCTL_msg.memory_type & CONV_MEMORY) printf(" conventional");
- if (IOCTL_msg.memory_type & BSW_MEMORY) printf(" BankSwitch");
- if (IOCTL_msg.memory_type & UNKNOWN_MEMORY) printf(" unknown");
- printf("\n");
- 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;
- int FAT_type = 12; /* By default try to use 12 bit FAT */
- 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;
- unsigned char *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;
-
- IOCTL_msg.media = media == -1 ? 0xFA : media;
-
-
- /* 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;
-
- { div_t divr;
- divr = div(IOCTL_msg.dir_entries * 32, IOCTL_msg.bytes_per_sector);
- dir_sectors = divr.quot + (divr.rem ? 1 : 0);
- }
-
- count_clusters:
- system_sectors = IOCTL_msg.reserved_sectors + dir_sectors;
- data_sectors = IOCTL_msg.sectors - system_sectors;
-
- IOCTL_msg.sectors_per_cluster = cluster_size / IOCTL_msg.bytes_per_sector;
-
- { ldiv_t divr;
- divr = ldiv(((long)data_sectors + 2 * IOCTL_msg.sectors_per_cluster) * FAT_type,
- (long)8 * cluster_size + IOCTL_msg.FATs * FAT_type);
- 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;
-
- /* Make sure we use the right FAT type */
- if (FAT_type < 16 && clusters > 4077) {
- FAT_type = 16;
- goto count_clusters;
- }
- if (FAT_type > 12 && clusters < 4088 || clusters > 65518) {
- FAT_type = 12;
- cluster_size <<= 1;
- goto count_clusters;
- }
-
- 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 = 0x34EB; /* Boot record JMP instruction */
- *(short *)(sector+24) = sec_per_track; /* Sectors per track */
- *(short *)(sector+26) = sides; /* Sides */
- *(short *)(sector+28) = 0; /* Hidden sectors */
- *(short *)(sector+54) = 0xFEEB; /* Boot code (JMP $) */
- *(short *)(sector+IOCTL_msg.bytes_per_sector-2) = 0xAA55; /* Validity code */
- 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 */
- ((unsigned long *)sector)[0] =
- (FAT_type == 12 ? 0xFFFF00L : 0xFFFFFF00L) | 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);
- sector[11] = FA_LABEL;
- *(unsigned long *)(sector+22) = DOS_time(time(NULL));
- write_sector(1, dir_start, sector);
-
- /* Write directory sectors from 2nd to last */
- memset(sector, 0, 16);
- 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("ReSizeable RAMDisk Formatter, version "VERSION", "
- "PUBLIC DOMAIN, 1991\n\n");
-
- if (argc > 1) parse_cmdline(argc, argv);
- else printf("For help type 'SRDISK /?'.\n\n");
-
- if (!drive) /* If no drive specified */
- drive = getdisk()+1; /* operate on current drive */
-
- init_drive(); /* Get current settings and display it */
-
- if (format_f) format_disk();
- else
- if (write_f != same) set_write_protect();
-
- return 0;
- }
-