Compare commits

...

6 Commits

Author SHA1 Message Date
michaelangel007 c6b6d387ba Bugfix: Sapling file size can be larger then blocks used on disk. Pad with zeroes when extracting 2023-06-12 23:25:01 -07:00
michaelangel007 741a5cc36f Cleanup 2023-06-12 23:24:15 -07:00
michaelangel007 abb0c97467 Cleanup: Fix missing newline 2023-06-12 23:24:01 -07:00
michaelangel007 23ebbf0331 Add -boot to load/save the boot sector 2023-06-12 23:23:47 -07:00
michaelangel007 0839ab0a3e Load/Save file attrib _META when cp and get 2023-06-12 23:16:55 -07:00
michaelangel007 6a84f16409 Add temp zero sector 2023-06-12 23:13:05 -07:00
3 changed files with 217 additions and 54 deletions

View File

@ -25,6 +25,7 @@
size_t gnDskSize = 0;
uint8_t gaDsk[ DSK_SIZE_32M ];
uint8_t gaTmp[ DSK_SECTOR_SIZE * 2 ];
uint16_t DskGet16( int offset )
{

View File

@ -94,7 +94,7 @@ Is this still needed?
" File type will auto-detected based on filename extension.\n"
" i.e. BAS, BIN, FNT, TXT,SYS, etc.\n"
" -access=$## Set access flags\n"
" NOTE: Defaults to $C3"
" NOTE: Defaults to $C3\n"
" $80 Volume/file can be destroyed\n"
" $40 Volume/file can be renamed\n"
" $20 Volume/file changed since last backup\n"
@ -122,16 +122,18 @@ Is this still needed?
, //CAT_LONG2
" This is an alias for 'catalog'\n"
,// FILE_GET
" [-boot=<file>] Optional: extract boot sector to file\n"
" <path> Path of virtual file to extract\n"
" NOTES:\n"
" The file remains on the virtual volume\n"
" To delete a file see ........: rm\n"
" To delete a sub-directory see: rmdir\n"
, // VOL__INIT
" <path> Name of virtual volume.\n"
" [-boot=<file>] Optional: replace boot sector with file\n"
" -size=140 Format 140 KB (5 1/4\")\n"
" -size=800 Format 800 KB (3 1/2\")\n"
" -size=32 Format 32 MB (Hard Disk)\n"
" <path> Name of virtual volume.\n"
, // CAT__NAMES
" [<path>] Path to sub-directory to view\n"
" Defaults to: /\n"
@ -154,6 +156,7 @@ Is this still needed?
" (Normally a sub-directory must be empty)\n"
, // DIR__DELETE2
" Alias for rmdir\n"
" NOTE: Not implemented yet!\n"
, NULL
};
@ -207,6 +210,12 @@ int usage()
" prodosfs test.dsk init -size=800 /TEST312 # 3 1/2\" (800 KB)\n"
" prodosfs test.dsk init -size=32 /TEST32M #HardDisk ( 32 MB)\n"
"\n"
"To put a (512) boot sector file use -boot with the init command:\n"
" prodosfs test.dsk init -boot=bootsector.bin -size=140 /TEST514\n"
"\n"
"To get a (512) boot sector file use -boot with the cp command:\n"
" prodosfs test.dsk cp -boot=bootsector.bin /TEST514\n"
"\n"
"Examples:\n"
"\n"
" prodosfs test.dsk ls\n"
@ -515,6 +524,8 @@ bool doCopy( ProDOS_FileHeader_t *entry, const char *filename )
}
}
prodos_MetaLoad( &gEntry );
#if DEBUG_MAIN
printf( "File Access: $%02X\n", gEntry.access );
#endif
@ -755,16 +766,14 @@ int main( const int nArg, const char *aArg[] )
#endif
if( pBootSectorFileName )
{
ProDOS_ExtractBootSector( pBootSectorFileName );
// loaded = ProDOS_ReplaceBootSector( pBootSectorFileName );
// if( loaded ) DskSave();
}
else
ProDOS_FileExtract( gpPath ); // pathname_filename
break;
}
case DISK_COMMAND_VOL_INIT:
{
gnDskSize = DSK_SIZE_312; // TODO: --size=140 --size=800 --size=32
if( !DskGetInterleave( gpDskName ) )
errorBadInterleave();
@ -772,6 +781,7 @@ int main( const int nArg, const char *aArg[] )
#if DEBUG_MAIN
printf( "iArg: %d / %d\n", iArg, nArg );
#endif
const char *pBootSectorFileName = NULL;
for( ; iArg < nArg; iArg++ )
{
@ -783,6 +793,14 @@ int main( const int nArg, const char *aArg[] )
if( pArg[0] == '-' )
{
if( strncmp( pArg+1,"boot=", 5 ) == 0 )
{
if( pBootSectorFileName )
printf( "ERROR: Already have boot sector filename. Skipping.\n" );
else
pBootSectorFileName = pArg + 6;
}
else
if( strncmp( pArg+1,"size=", 5 ) == 0 )
{
int size = atoi( pArg + 6 );
@ -812,12 +830,19 @@ int main( const int nArg, const char *aArg[] )
if( gpPath )
{
ProDOS_Init( gpPath );
if( pBootSectorFileName )
{
bool bReplaced = ProDOS_ReplaceBootSector( pBootSectorFileName );
if( !bReplaced )
printf( "ERROR: Couldn't replace boot sector\n" );
}
DskSave();
}
else
return printf( "ERROR: Need virtual volume name. e.g. /TEST\n" );
break;
}
default:
if( (nArg < 2) || !pCommand )

View File

@ -1,4 +1,5 @@
#define DEBUG_ADD 0
#define DEBUG_ATTRIB 0
#define DEBUG_BITMAP 0
#define DEBUG_DATE 0
#define DEBUG_DIR 0
@ -16,7 +17,8 @@
ProDOS_* Public functions
*/
#define min(a,b) ((a < b) ? a : b)
#define max(a,b) ((a < b) ? b : a)
// --- ProDOS crap ---
@ -164,7 +166,7 @@ if( block == PRODOS_ROOT_BLOCK )
struct ProDOS_FileHeader_t
{ ; //Rel Size Hex
uint8_t kind ; // +0 1 $00 \ Hi nibble Storage Type
uint8_t len ; // +0 / Lo nibble
uint8_t len ; // +0 / Lo nibble Filename Length
char name[ 16 ] ; // +1 15 $05 15 on disk but we NULL terminate for convenience
// --- diff from volume ---
uint8_t type ; //+16 1 $10 User Type
@ -670,6 +672,95 @@ if( bitmap )
}
// ------------------------------------------------------------------------
void prodos_MetaGetFileName( ProDOS_FileHeader_t *pEntry, char sAttrib[ PRODOS_MAX_PATH ] )
{
if( !pEntry )
return;
// Attribute meta-data
const char sExt[] = "._META";
const size_t nExt = strlen( sExt );
int nAttrib = string_CopyUpper( sAttrib + 0, pEntry->name, pEntry->len );
/* */ string_CopyUpper( sAttrib + nAttrib, sExt , nExt );
}
// ------------------------------------------------------------------------
bool prodos_MetaLoad(ProDOS_FileHeader_t* pEntry)
{
char sAttrib[ PRODOS_MAX_PATH ];
prodos_MetaGetFileName( pEntry, sAttrib );
printf( "Loading meta... %s\n", sAttrib );
FILE *pFileMeta = fopen( sAttrib, "r" );
if( !pFileMeta )
{
printf( "INFO.: Couldn't open attribute file for reads: %s\n", sAttrib );
return false;
}
int value;
fscanf( pFileMeta, "access = $%X\n", &value ); pEntry->access = value; // 02
fscanf( pFileMeta, "aux = $%X\n", &value ); pEntry->aux = value; // 04
fscanf( pFileMeta, "type = $%X\n", &value ); pEntry->type = value; // 02
fscanf( pFileMeta, "kind = $%X\n", &value ); pEntry->kind = value; // 02
fscanf( pFileMeta, "date = $%X\n", &value ); pEntry->date = value; // 04
fscanf( pFileMeta, "time = $%X\n", &value ); pEntry->time = value; // 04
fscanf( pFileMeta, "version = $%X\n", &value ); pEntry->cur_ver = value; // 02
fscanf( pFileMeta, "minver = $%X\n", &value ); pEntry->min_ver = value; // 02
fscanf( pFileMeta, "moddate = $%X\n", &value ); pEntry->mod_date = value; // 04
fscanf( pFileMeta, "modtime = $%X\n", &value ); pEntry->mod_time = value; // 04
#if DEBUG_ATTRIB
printf( "access = $%02X\n", pEntry->access );
printf( "aux = $%04X\n", pEntry->aux );
printf( "type = $%02X\n", pEntry->type );
printf( "kind = $%02X\n", pEntry->kind );
printf( "date = $%04X\n", pEntry->date );
printf( "time = $%04X\n", pEntry->time );
printf( "version = $%02X\n", pEntry->cur_ver );
printf( "minver = $%02X\n", pEntry->min_ver );
printf( "moddate = $%04X\n", pEntry->mod_date );
printf( "modtime = $%04X\n", pEntry->mod_time );
#endif
fclose( pFileMeta );
return true;
}
// ------------------------------------------------------------------------
bool prodos_MetaSave( ProDOS_FileHeader_t *pEntry )
{
char sAttrib[ PRODOS_MAX_PATH ];
prodos_MetaGetFileName( pEntry, sAttrib );
printf( "Saving meta... %s\n", sAttrib );
FILE *pFileMeta = fopen( sAttrib, "w+b" );
if( !pFileMeta )
{
printf( "ERROR: Couldnt' open attribute file for writing: %s\n", sAttrib );
return false;
}
fprintf( pFileMeta, "access = $%02X\n", pEntry->access );
fprintf( pFileMeta, "aux = $%04X\n", pEntry->aux );
fprintf( pFileMeta, "type = $%02X\n", pEntry->type );
fprintf( pFileMeta, "kind = $%02X\n", pEntry->kind );
fprintf( pFileMeta, "date = $%04X\n", pEntry->date );
fprintf( pFileMeta, "time = $%04X\n", pEntry->time );
fprintf( pFileMeta, "version = $%02X\n", pEntry->cur_ver );
fprintf( pFileMeta, "minver = $%02X\n", pEntry->min_ver );
fprintf( pFileMeta, "moddate = $%04X\n", pEntry->mod_date );
fprintf( pFileMeta, "modtime = $%04X\n", pEntry->mod_time );
fclose( pFileMeta );
return true;
}
// ------------------------------------------------------------------------
void prodos_Summary( ProDOS_VolumeHeader_t *volume, int files, int iFirstFree )
{
@ -1117,6 +1208,9 @@ bool ProDOS_FileAdd( const char *to_path, const char *from_filename, ProDOS_File
int iIndexBase = 0; // Single Index
int iMasterIndex = 0; // master block points to N IndexBlocks
#if DEBUG_ATTRIB
printf( "Source File Size: %06X (%d)\n", nSrcSize, nSrcSize );
#endif
if( nSrcSize > gnDskSize )
{
@ -1304,7 +1398,7 @@ void ProDOS_FileDelete( const char *path )
// Copy a file from the virtual file system back to the host
// ProDOS attributes are saved in file.prodos_meta
// ProDOS attributes are saved in <file>._META
// ========================================================================
bool ProDOS_FileExtract( const char *path )
{
@ -1343,34 +1437,8 @@ bool ProDOS_FileExtract( const char *path )
return false;
}
const char sExt[] = "._meta";
const size_t nExt = strlen( sExt );
/* */ char sAttrib[ PRODOS_MAX_PATH ];
int nAttrib = string_CopyUpper( sAttrib + 0, pEntry->name, pEntry->len );
/* */ string_CopyUpper( sAttrib + nAttrib, sExt , nExt );
printf( "Saving meta... %s\n", sAttrib );
FILE *pFileMeta = fopen( sAttrib, "w+b" );
if( !pFileMeta )
{
printf( "ERROR: Couldnt' open attribute file for writing: %s\n", sAttrib );
if( !prodos_MetaSave( pEntry ) )
return false;
}
// TODO: Sync these up with <file>._META ProDOS_FileExtract() and getCopyConfig()
fprintf( pFileMeta, "access = $%02X\n", pEntry->access );
fprintf( pFileMeta, "aux = $%04X\n", pEntry->aux );
fprintf( pFileMeta, "type = $%02X\n", pEntry->type );
fprintf( pFileMeta, "kind = $%02X\n", pEntry->kind );
fprintf( pFileMeta, "date = $%04X\n", pEntry->date );
fprintf( pFileMeta, "time = $%04X\n", pEntry->time );
fprintf( pFileMeta, "version = $%02X\n", pEntry->cur_ver );
fprintf( pFileMeta, "minver = $%02X\n", pEntry->min_ver );
fprintf( pFileMeta, "moddate = $%04X\n", pEntry->mod_date );
fprintf( pFileMeta, "modtime = $%04X\n", pEntry->mod_time );
fclose( pFileMeta );
int addr = pEntry->inode * PRODOS_BLOCK_SIZE;
int size = pEntry->size;
@ -1385,7 +1453,7 @@ bool ProDOS_FileExtract( const char *path )
printf( "ERROR: Couldn't open data file for writing: %s\n", pEntry->name );
return false;
}
else
{
switch( kind )
{
@ -1397,15 +1465,36 @@ bool ProDOS_FileExtract( const char *path )
case ProDOS_KIND_SAPL: // <= 128 KB
{
int nBlock = pEntry->blocks - 1; // 1st block is index block
int nBytes = size;
#if DEBUG_EXTRACT
printf( "ProDOS File Size: $%06X (%d)\n", size, size );
printf( "i-node (8-bit) : @ $%04X\n" , pEntry->inode );
// printf( "Filename Length : %04X\n", pEntry->len );
printf( "File Blocks : $%04X (%d)\n", pEntry->blocks, pEntry->blocks ); // Includes i-nodes
printf( "Total Blocks : $%04X (%d)\n", nBlock , nBlock );
#endif
for( int iBlock = 0; iBlock < nBlock; iBlock++ )
{
int iDataBlock = DskGetIndexBlock( addr, iBlock );
int iDataOffset = iDataBlock * PRODOS_BLOCK_SIZE;
int nSlack = min( nBytes, PRODOS_BLOCK_SIZE);
nBytes -= PRODOS_BLOCK_SIZE;
#if DEBUG_EXTRACT
int bLastBlock = (iBlock == (nBlock - 1));
printf( "Block: %02X/%02X @ %04X, LastBlock? %d, Bytes: %6d, Slack: %3d\n", iBlock, nBlock-1, iDataBlock, bLastBlock, nBytes + PRODOS_BLOCK_SIZE, nSlack );
#endif
fwrite( &gaDsk[ iDataOffset ], 1, nSlack, pFileData );
}
if( iBlock != nBlock - 1 )
fwrite( &gaDsk[ iDataOffset ], 1, PRODOS_BLOCK_SIZE, pFileData );
else
fwrite( &gaDsk[ iDataOffset ], 1, pEntry->size % PRODOS_BLOCK_SIZE, pFileData );
// File size is larger then blocks used on disk?!
if( nBytes > 0 )
{
// pad with zeroes
#if DEBUG_EXTRACT
int nSlack = min( nBytes, PRODOS_BLOCK_SIZE);
printf( "PADDING extra ZERO Bytes: %6d, Slack: %3d\n", nBytes, nSlack );
#endif
fwrite( &gaTmp, 1, nBytes, pFileData );
}
break;
}
@ -1432,11 +1521,11 @@ void ProDOS_Init( const char *path )
{
// Zero disk
memset( gaDsk, 0, gnDskSize );
memset( gaTmp, 0, PRODOS_BLOCK_SIZE );
// Copy Boot Sector
// TODO: Use ProDOS 2.4.1 boot sector
// Create blocks for root directory
int nRootDirBlocks = 4;
int iPrevDirBlock = 0;
@ -1558,7 +1647,7 @@ void ProDOS_Init( const char *path )
// Read T0S0 and save it to a file on the host
// @returns 0 if succes
// @returns true if succes
// ========================================================================
bool ProDOS_ExtractBootSector( const char *pBootSectorFileName )
{
@ -1570,7 +1659,24 @@ bool ProDOS_ExtractBootSector( const char *pBootSectorFileName )
return false;
}
fwrite( &gaDsk[ 0 ], 1, 256, pDstFile );
const size_t BLOCK_0_BEG = 0x0*DSK_SECTOR_SIZE;
const size_t BLOCK_0_END = 0x1*DSK_SECTOR_SIZE;
fwrite( &gaDsk[ BLOCK_0_BEG ], 1, 256, pDstFile );
fwrite( &gaDsk[ BLOCK_0_END ], 1, 256, pDstFile );
#if _DEBUG
for( int sector = 0; sector < 16; ++sector )
{
printf( "T0S%1X: ", sector );
for( int byte = 0; byte < 4; ++byte )
{
printf( "%02X ", gaDsk[ sector*DSK_SECTOR_SIZE + byte ] );
}
printf( "\n" );
}
#endif
fclose( pDstFile );
return true;
@ -1592,22 +1698,53 @@ bool ProDOS_ReplaceBootSector( const char *pBootSectorFileName )
size_t size = File_Size( pSrcFile );
// size < 256
memset( &gaDsk[ 0 ], 0, 256 );
if( size < 256 )
printf( "INFO.: Boot sector < 256 bytes. Padding boot sector with zeroes.\n" );
const size_t BLOCK_0_BEG = 0x0*DSK_SECTOR_SIZE;
const size_t BLOCK_0_END = 0x1*DSK_SECTOR_SIZE;
// size >= 256
if( size > 255 )
memset( &gaDsk[ BLOCK_0_BEG ], 0, 256 ); // Block 0 Beg = T0S0
memset( &gaDsk[ BLOCK_0_END ], 0, 256 ); // Block 0 End = T0SE
if( size < 512 )
printf( "INFO.: Boot sector < 512 bytes. Padding boot sector with zeroes.\n" );
if( size > 512 )
{
printf( "WARNING: Boot sector > 255 bytes. Truncating to first 256 bytes.\n" );
size = 256;
printf( "WARNING: Boot sector > 512 bytes. Truncating to first 512 bytes.\n" );
size = 512;
}
fread( &gaDsk[ 0 ], 1, size, pSrcFile );
const size_t prefix = min( size , 256 );
const size_t suffix = min( size-256, 256 );
#if _DEBUG
printf( "prefix: $%02X (#%3d)\n", (int) prefix & 0xFF, (int) prefix );
printf( "suffix: $%02X (#%3d)\n", (int) prefix & 0xFF, (int) suffix );
#endif
if( prefix ) fread( &gaDsk[ BLOCK_0_BEG ], 1, prefix, pSrcFile );
if( suffix ) fread( &gaDsk[ BLOCK_0_END ], 1, suffix, pSrcFile );
#if 0
if (size <= 256)
{
fread( &gaDsk[ BLOCK_0_BEG ], 1, size, pSrcFile );
}
else
{
// First 256 bytes to T0S0
fread( &gaDsk[ BLOCK_0_BEG ], 1, 256, pSrcFile );
// Second 256 bytes to T0SE
if( size < 512 )
fread( &gaDsk[ BLOCK_0_END ], 1, size, pSrcFile );
else
fread( &gaDsk[ BLOCK_0_END ], 1, 512, pSrcFile );
}
#endif
fclose( pSrcFile );
// Caller will do: DskSave();
// NOTE: Caller will do: DskSave();
return true;
}