dos33fsprogs/utils/prodos-utils/mkprodosfs.c
2024-07-16 14:14:30 -04:00

257 lines
5.9 KiB
C

#include <stdio.h>
#include <string.h> /* strncpy() */
#include <fcntl.h> /* open() */
#include <unistd.h> /* close() */
#include <stdlib.h> /* strtol() */
#include <errno.h>
#include <time.h>
#include "version.h"
#include "prodos.h"
int debug=0;
static int ones_lookup[8]={
0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF,
};
static void usage(char *binary,int help) {
printf("\n%s - version %s\n",binary,VERSION);
printf("\tby Vince Weaver <vince@deater.net>\n");
printf("\thttp://www.deater.net/weave/vmwprod/apple/\n\n");
if (help) {
printf("Usage:\t%s [-b size] [-i interleave] "
"[-s bootsector] device_name\n\n",binary);
printf("\t-b size : size of image, in 512B blocks\n");
printf("\t-i interleave : PRODOS (default) or DOS33\n");
printf("\t-s filename : bootsector\n");
printf("\t-n volume : volume name\n");
printf("\t-2 : prepend a 2mg header\n");
printf("\n\n");
}
exit(0);
return;
}
int main(int argc, char **argv) {
int num_blocks=280;
int fd;
char device[BUFSIZ];
char *endptr;
int i,j,c;
int result;
unsigned char data_buffer[PRODOS_BYTES_PER_BLOCK];
struct voldir_t voldir;
char volname[PRODOS_VOLNAME_LEN];
int volname_len;
int interleave=PRODOS_INTERLEAVE_PRODOS;
int num_voldirs=4,num_bitmaps,num_bitmap_blocks,ones_to_write;
int make_2mg_header=0;
unsigned char header_2mg[64];
strncpy(volname,"EMPTY",6);
volname_len=strlen(volname);
/* Parse Command Line Arguments */
while ((c = getopt (argc, argv,"b:i:s:n:hv2"))!=-1) {
switch (c) {
case 'b':
num_blocks=strtol(optarg,&endptr,10);
if ( endptr == optarg ) usage(argv[0], 1);
break;
case 'i':
if (!strncasecmp(optarg,"prodos",6)) {
interleave=PRODOS_INTERLEAVE_PRODOS;
}
else if (!strncasecmp(optarg,"dos33",5)) {
interleave=PRODOS_INTERLEAVE_DOS33;
}
else {
fprintf(stderr,"Error! Unknown interleave: %s\n",optarg);
}
break;
case 's':
fprintf(stderr,"Error! -s not implemented yet!\n");
break;
case 'n':
memset(volname,0,sizeof(volname));
volname_len=strlen(optarg);
if (volname_len>PRODOS_VOLNAME_LEN) {
fprintf(stderr,"Volname: %s is too long!\n",optarg);
return -1;
}
memcpy(volname,optarg,volname_len);
break;
case '2': make_2mg_header=1;
break;
case 'v': usage(argv[0],0);
case 'h': usage(argv[0],1);
}
}
if (optind==argc) {
printf("Error! Must include device name\n\n");
goto end_of_program;
}
strncpy(device,argv[optind],BUFSIZ-1);
/***********************/
/* Sanity check values */
/***********************/
/* sectors: 2->32 (limited by 4-byte bitfields) */
if ((num_blocks<6) || (num_blocks>65535)) {
printf("Number of blocks must be >6 and <65536\n\n");
goto end_of_program;
}
/* Open device */
fd=open(device,O_RDWR|O_CREAT|O_TRUNC,0666);
if (fd<0) {
fprintf(stderr,"Error opening %s (%s)\n",
device,strerror(errno));
goto end_of_program;
}
/*****************/
/* init voldir */
/*****************/
memset(&voldir,0,sizeof(struct voldir_t));
voldir.fd=fd;
voldir.interleave=interleave;
if (make_2mg_header) {
create_2mg_header(header_2mg,num_blocks);
write(fd,header_2mg,64);
voldir.image_offset=64;
}
else {
voldir.image_offset=0;
}
voldir.storage_type=PRODOS_FILE_VOLUME_HDR;
voldir.name_length=volname_len;
memcpy(voldir.volume_name,volname,volname_len);
voldir.total_blocks=num_blocks;
voldir.version=0;
voldir.min_version=0;
voldir.access=0xc3; // FIXME
voldir.entry_length=0x27;
voldir.entries_per_block=13;
voldir.bit_map_pointer=6;
voldir.creation_time=prodos_time(time(NULL));
voldir.file_count=0;
voldir.next_block=3;
/******************/
/* clear out data */
/******************/
memset(data_buffer,0,PRODOS_BYTES_PER_BLOCK);
/* create image */
for(i=0;i<num_blocks;i++) {
result=prodos_write_block(&voldir,data_buffer,i);
if (result<0) {
fprintf(stderr,"Error writing!\n");
return -1;
}
}
/*********************************/
/* create the voldirs */
/*********************************/
for(i=0;i<num_voldirs;i++) {
memset(data_buffer,0,PRODOS_BYTES_PER_BLOCK);
/* prev */
if (i>0) {
data_buffer[0]=(PRODOS_VOLDIR_KEY_BLOCK+i-1)&0xff;
data_buffer[1]=(PRODOS_VOLDIR_KEY_BLOCK+i-1)>>8;
}
/* next */
if (i<num_voldirs-1) {
data_buffer[2]=(PRODOS_VOLDIR_KEY_BLOCK+i+1)&0xff;
data_buffer[3]=(PRODOS_VOLDIR_KEY_BLOCK+i+1)>>8;
}
result=prodos_write_block(&voldir,data_buffer,i+PRODOS_VOLDIR_KEY_BLOCK);
}
/*********************************/
/* create the bitmaps */
/*********************************/
num_bitmaps=num_blocks/8;
num_bitmap_blocks=1+((num_bitmaps-1)/512);
for(i=0;i<num_bitmap_blocks;i++) {
memset(data_buffer,0,PRODOS_BYTES_PER_BLOCK);
if (i*512*8>num_blocks) {
ones_to_write=512;
}
else {
ones_to_write=num_blocks%(512*8);
}
if (debug) printf("Writing %d ones\n",ones_to_write);
for(j=0;j<ones_to_write/8;j++) {
data_buffer[j]=0xff;
}
if (ones_to_write%8) {
data_buffer[j]=ones_lookup[ones_to_write%8];
}
result=prodos_write_block(&voldir,data_buffer,
PRODOS_VOLDIR_KEY_BLOCK+num_voldirs+i);
if (debug) printf("Wrote bitmap to block $%X\n",
PRODOS_VOLDIR_KEY_BLOCK+num_voldirs+i);
if (result<0) {
fprintf(stderr,"Error writing!\n");
return -1;
}
}
/*********************************/
/* reserve all of the used space */
/*********************************/
prodos_voldir_reserve_block(&voldir,0); // boot sector
prodos_voldir_reserve_block(&voldir,1); // SOS boot sector
for(i=0;i<num_voldirs;i++) {
prodos_voldir_reserve_block(&voldir,
PRODOS_VOLDIR_KEY_BLOCK+i); // 2..5
}
for(i=0;i<num_bitmap_blocks;i++) {
prodos_voldir_reserve_block(&voldir,
PRODOS_VOLDIR_KEY_BLOCK+num_voldirs+i); // 6
}
/*********************************/
/* write out voldir */
/*********************************/
prodos_sync_voldir(&voldir);
close(fd);
end_of_program:
return 0;
}