-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ADDFILE will create first block as sparse, confusing ProDOS #42
Comments
Also, CHECKVOLUME should flag this issue, and maybe mention a file's sparse blocks in its verbose mode. |
I think this will fix diff --git a/Src/Prodos_Add.c b/Src/Prodos_Add.c
index 483669c..5028640 100644
--- a/Src/Prodos_Add.c
+++ b/Src/Prodos_Add.c
@@ -565,7 +565,9 @@ static void ComputeFileBlockUsage(struct prodos_file *current_file)
for(i=0; i<current_file->data_length; i+=BLOCK_SIZE)
{
/* Recherche les plages de 0 */
- if(i+BLOCK_SIZE <= current_file->data_length)
+ if(i == 0)
+ result = 1; /* Block 0 ne doit pas être Sparse */
+ else if(i+BLOCK_SIZE <= current_file->data_length)
result = memcmp(¤t_file->data[i],empty_block,BLOCK_SIZE);
else
result = memcmp(¤t_file->data[i],empty_block,current_file->data_length-i);
@@ -586,7 +588,9 @@ static void ComputeFileBlockUsage(struct prodos_file *current_file)
for(i=0; i<current_file->resource_length; i+=BLOCK_SIZE)
{
/* Recherche les plages de 0 */
- if(i+BLOCK_SIZE <= current_file->resource_length)
+ if(i == 0)
+ result = 1; /* Block 0 ne doit pas être Sparse */
+ else if(i+BLOCK_SIZE <= current_file->resource_length)
result = memcmp(¤t_file->resource[i],empty_block,BLOCK_SIZE);
else
result = memcmp(¤t_file->resource[i],empty_block,current_file->resource_length-i);
@@ -883,7 +887,9 @@ static WORD CreateSaplingContent(struct prodos_image *current_image, struct prod
for(i=0,j=1,k=0; i<data_length; i+=BLOCK_SIZE,k++)
{
/* Recherche les plages de 0 */
- if(i+BLOCK_SIZE <= data_length)
+ if(i == 0)
+ is_empty = 0; /* Block 0 ne doit pas être Sparse */
+ else if(i+BLOCK_SIZE <= data_length)
is_empty = !memcmp(&data[i],empty_block,BLOCK_SIZE);
else
is_empty = !memcmp(&data[i],empty_block,data_length-i);
@@ -1006,7 +1012,9 @@ static WORD CreateTreeContent(struct prodos_image *current_image, struct prodos_
for(i=0,j=index_data,k=0,l=0; i<data_length; i+=BLOCK_SIZE,k++)
{
/* Recherche les plages de 0 */
- if(i+BLOCK_SIZE <= data_length)
+ if(i == 0)
+ is_empty = 0; /* Block 0 ne doit pas être Sparse */
+ else if(i+BLOCK_SIZE <= data_length)
is_empty = !memcmp(&data[i],empty_block,BLOCK_SIZE);
else
is_empty = !memcmp(&data[i],empty_block,data_length-i); |
Here's a hacky warning that can be added. Not scoped to diff --git a/Src/Dc_Prodos.c b/Src/Dc_Prodos.c
index c979036..8dd6c29 100644
--- a/Src/Dc_Prodos.c
+++ b/Src/Dc_Prodos.c
@@ -1090,6 +1090,9 @@ static int GetFileDataResourceSize(struct prodos_image *current_image, struct fi
if(tab_block[i] == 0)
file_entry->nb_sparse++;
+ if(tab_block[0] == 0)
+ logf_error(" Warning : Block 0 is sparse in file: '%s'.\n", file_entry->file_path);
+
/* Table des blocs utilisés */
file_entry->tab_used_block = BuildUsedBlockTable(nb_block,tab_block,nb_index_block,tab_index_block,&file_entry->nb_used_block);
if(file_entry->tab_used_block == NULL)
@@ -1180,6 +1183,8 @@ static int GetFileDataResourceSize(struct prodos_image *current_image, struct fi
if(tab_block[i] == 0)
file_entry->nb_sparse++;
+ // TODO: Warn if data fork block 0 is sparse?
+
/* Table des blocs utilisés (Data) */
tab_used_block_data = BuildUsedBlockTable(nb_block,tab_block,nb_index_block,tab_index_block,&nb_used_block_data);
if(tab_used_block_data == NULL)
@@ -1250,6 +1255,8 @@ static int GetFileDataResourceSize(struct prodos_image *current_image, struct fi
if(tab_block[i] == 0)
file_entry->nb_sparse++;
+ // TODO: Warn if resource fork block 0 is sparse?
+
/* Table des blocs utilisés (Resource) */
tab_used_block_resource = BuildUsedBlockTable(nb_block,tab_block,nb_index_block,tab_index_block,&nb_used_block_resource);
if(tab_used_block_resource == NULL) |
Note that adding code specifically to |
One thing I'm not sure about - for GS/OS "extended" files - with a data fork and a resource fork - both forks are managed as separate effectively separate seed/sapling/tree. Is the first block of either of those permitted to be "sparse"? I'm guessing no, but I haven't found anything definitive yet in APDA docs.
|
Hi @inexorabletash! Thanks very much for the detailed report!! Would you be so kind as to pull request the patches? I think the rationale about the warnings / first block assumption make sense.
I did some sleuthing in the toolbox reference and found this: I am confused about the "empty" semantics (see My guess is that it isn't inherently prohibited but would probably not be a valid usage in the eyes of the resource manager. |
When checking if a file block can be sparse (i.e. not actually allocated on disk), ensure the test always fails for the first block of the file, as this would violate the ProDOS file system specification, and makes ProDOS-8 unhappy. Additionally, when loading a volume, log if files are encountered that have sparse first blocks. mach-kernel#42
PR added! I chatted with @fadden on Slack and he said he'd had similar issues in CiderPress (fadden/ciderpress#49) which he fixed, and for "extended" files added some similar checks to CiderPress2 (here, here) so I think at least these tools are aligned with the proposed changes here. |
Repro:
Now mount a ProDOS-8 system disk (2.0.3, 2.4.3, shouldn't matter) and the
tmp.po
disk and run BASIC.SYSTEM:Back to the shell:
cadius CHECKVOLUME tmp.po # => Block 0000 is declared FREE in the Bitmap, but used by Boot
Ooops! For even more fun, go back to BASIC.SYSTEM:
Per ProDOS-8 Technical Reference Manual:
So it appears Cadius is violating this filesystem assumption, and it makes ProDOS very sad.
The text was updated successfully, but these errors were encountered: