The existing code in hfsp_volume.c tries to locate the alternate volume header at the block vol->maxblocks - 2. Currently for unwrapped HFS+ volumes, vol->maxblocks is never set from the main volume header once it is located and so it tries to find the backup volume at the (dummy) block 3 which inevitably fails.
On a secondary note until towards the end of the function, volume_open() assumes the block size is 512 bytes. Therefore once we determine the size of the volume from the main volume header in blocks, we need to convert it from the block size indicated in the volume header to a fixed 512 byte block size in order for the alternate volume header to be located correctly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/fs/hfsplus/hfsp_volume.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/openbios-devel/fs/hfsplus/hfsp_volume.c b/openbios-devel/fs/hfsplus/hfsp_volume.c index 802d700..e6d9d60 100644 --- a/openbios-devel/fs/hfsplus/hfsp_volume.c +++ b/openbios-devel/fs/hfsplus/hfsp_volume.c @@ -171,7 +171,9 @@ volume_read_wrapper(volume * vol, hfsp_vh* vh) UInt16 signature; char buf[vol->blksize]; char *p = buf; - + int ret; + UInt64 vol_size; + if( volume_readinbuf(vol, buf, 2) ) // Wrapper or volume header starts here return -1;
@@ -202,7 +204,14 @@ volume_read_wrapper(volume * vol, hfsp_vh* vh) } else if( signature == HFSP_VOLHEAD_SIG) { /* Native HFS+ volume */ p = buf; // Restore to begin of block - return volume_readbuf(vh, p); + ret = volume_readbuf(vh, p); + if( !ret ) { + /* When reading the initial partition we must use 512 byte blocks */ + vol_size = vh->blocksize * vh->total_blocks; + vol->maxblocks = vol_size / HFSP_BLOCKSZ; + } + + return ret; } else HFSP_ERROR(-1, "Neither Wrapper nor native HFS+ volume header found"); fail:
Replace any non-ASCII characters with a ? to prevent display errors when converting from Unicode filenames.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/fs/hfsplus/hfsp_unicode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/openbios-devel/fs/hfsplus/hfsp_unicode.c b/openbios-devel/fs/hfsplus/hfsp_unicode.c index a798085..22da3fa 100644 --- a/openbios-devel/fs/hfsplus/hfsp_unicode.c +++ b/openbios-devel/fs/hfsplus/hfsp_unicode.c @@ -43,7 +43,10 @@ uni2asc( char *astr, const unsigned char *ustr, int ustrlen, int maxlen ) /* might be unrepresentable (or too complicated for us) */ if( ustr[0] || !ustr[1] ) continue; - *astr++ = ustr[1]; + if( ustr[1] < 0x20 || ustr[1] > 0x80 ) + *astr++ = '?'; + else + *astr++ = ustr[1]; len++; } *astr = 0;
Am 18.09.2012 17:31, schrieb Mark Cave-Ayland:
Replace any non-ASCII characters with a ? to prevent display errors when converting from Unicode filenames.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
openbios-devel/fs/hfsplus/hfsp_unicode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/openbios-devel/fs/hfsplus/hfsp_unicode.c b/openbios-devel/fs/hfsplus/hfsp_unicode.c index a798085..22da3fa 100644 --- a/openbios-devel/fs/hfsplus/hfsp_unicode.c +++ b/openbios-devel/fs/hfsplus/hfsp_unicode.c @@ -43,7 +43,10 @@ uni2asc( char *astr, const unsigned char *ustr, int ustrlen, int maxlen ) /* might be unrepresentable (or too complicated for us) */ if( ustr[0] || !ustr[1] ) continue;
*astr++ = ustr[1];
if( ustr[1] < 0x20 || ustr[1] > 0x80 )
ASCII didn't have the upper bit, so >= 0x80 would be more correct. Does this correspond to any "upstream" that we should patch as well?
Do we have any kind of agreed-upon Coding Style for C btw?
Regards, Andreas
*astr++ = '?';
else
len++; } *astr = 0;*astr++ = ustr[1];
On 2012-Oct-3 08:00 , Andreas Färber wrote:
if( ustr[1] < 0x20 || ustr[1] > 0x80 )
ASCII didn't have the upper bit, so >= 0x80 would be more correct. Does this correspond to any "upstream" that we should patch as well?
Since rubout (0x7f) is also not representable, "ustr[1] >= 0x7f" might be even better.
On 03/10/12 16:52, Tarl Neustaedter wrote:
ASCII didn't have the upper bit, so >= 0x80 would be more correct. Does this correspond to any "upstream" that we should patch as well?
Since rubout (0x7f) is also not representable, "ustr[1] >= 0x7f" might be even better.
That's fine with me. It was mainly because some of the "special" directories contained low ASCII which was moving the console cursor around and hence corrupting the display output.
ATB,
Mark.
On 04/10/12 20:33, Mark Cave-Ayland wrote:
Since rubout (0x7f) is also not representable, "ustr[1] >= 0x7f" might be even better.
That's fine with me. It was mainly because some of the "special" directories contained low ASCII which was moving the console cursor around and hence corrupting the display output.
Thanks for the feedback everyone. I've just committed the above version to trunk. Feel free to go and test your favourite HFS+ images with both the dir and boot words.
ATB,
Mark.
On 03/10/12 13:00, Andreas Färber wrote:
Replace any non-ASCII characters with a ? to prevent display errors when converting from Unicode filenames.
Signed-off-by: Mark Cave-Aylandmark.cave-ayland@ilande.co.uk
openbios-devel/fs/hfsplus/hfsp_unicode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/openbios-devel/fs/hfsplus/hfsp_unicode.c b/openbios-devel/fs/hfsplus/hfsp_unicode.c index a798085..22da3fa 100644 --- a/openbios-devel/fs/hfsplus/hfsp_unicode.c +++ b/openbios-devel/fs/hfsplus/hfsp_unicode.c @@ -43,7 +43,10 @@ uni2asc( char *astr, const unsigned char *ustr, int ustrlen, int maxlen ) /* might be unrepresentable (or too complicated for us) */ if( ustr[0] || !ustr[1] ) continue;
*astr++ = ustr[1];
if( ustr[1]< 0x20 || ustr[1]> 0x80 )
ASCII didn't have the upper bit, so>= 0x80 would be more correct. Does this correspond to any "upstream" that we should patch as well?
I'm not sure the official upstream exists anymore, but I took a quick look at the latest Ubuntu packages. There are some very significant differences between what is in OpenBIOS and what is upstream - in particular they've renamed all the files, and they use functions from wchar.h to do the conversion instead. So it's big enough to be a separate task, and well outside the scope of this patch.
Incidentally their "fix" for the incorrect seek offset for the second volume descriptor is ridiculous - instead of parsing the volume for the information and converting based upon the block size in the volume header, they completely break the abstraction and add another optional argument to volume_open() which points to the partition map which is guaranteed to store the offests in 512 byte blocks. If it is specified at open time, it simply overrides the values read from the volume. Sigh.
Do we have any kind of agreed-upon Coding Style for C btw?
For external code sourced elsewhere, I'd say it's blend in with what's around you.
ATB,
Mark.
On 2012-Oct-4 15:31 , Mark Cave-Ayland wrote:
[...] Incidentally their "fix" for the incorrect seek offset for the second volume descriptor is ridiculous - instead of parsing the volume for the information and converting based upon the block size in the volume header, they completely break the abstraction and add another optional argument to volume_open() which points to the partition map which is guaranteed to store the offests in 512 byte blocks. If it is specified at open time, it simply overrides the values read from the volume. Sigh. [...]
Interesting. I just had to fix this last year for Sun(Oracle) on SPARC. With 4k disk block/sectors, offsets in both SMI and EFI/GPT partition tables ( http://en.wikipedia.org/wiki/GUID_Partition_Table ), partitions are given in block numbers dependent on the block size. That is, unless you have access to SCSI so you can find out the block size, you can't interpret the labels properly. Which makes life interesting on CD/DVDs, where the blocksize of the media is not necessarily tied to the block size of the reading device (so for the removable media case alone, we hard-code that block sizes in partition descriptors _are_ 512 bytes even when both agree that they are 2048 bytes).
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/fs/hfsplus/hfsp_fs.c | 140 ++++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 4 deletions(-)
diff --git a/openbios-devel/fs/hfsplus/hfsp_fs.c b/openbios-devel/fs/hfsplus/hfsp_fs.c index 83e4d8d..4cc6ddc 100644 --- a/openbios-devel/fs/hfsplus/hfsp_fs.c +++ b/openbios-devel/fs/hfsplus/hfsp_fs.c @@ -437,14 +437,146 @@ hfsp_files_volume_name( hfsp_info_t *mi ) PUSH(pointer2cell(volname)); }
+static const int days_month[12] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +static const int days_month_leap[12] = + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +static inline int is_leap(int year) +{ + return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); +} + +static void +print_date(uint32_t sec) +{ + unsigned int second, minute, hour, month, day, year; + int current; + const int *days; + + second = sec % 60; + sec /= 60; + + minute = sec % 60; + sec /= 60; + + hour = sec % 24; + sec /= 24; + + year = sec * 100 / 36525; + sec -= year * 36525 / 100; + year += 1904; + + days = is_leap(year) ? days_month_leap : days_month; + + current = 0; + month = 0; + while (month < 12) { + if (sec <= current + days[month]) { + break; + } + current += days[month]; + month++; + } + month++; + + day = sec - current + 1; + + forth_printf("%d-%02d-%02d %02d:%02d:%02d ", + year, month, day, hour, minute, second); +} + /* static method, ( pathstr len ihandle -- ) */ static void hfsp_files_dir( hfsp_info_t *dummy ) { - forth_printf("dir method not implemented for HFS+ filesystem\n"); - POP(); - POP(); - POP(); + ihandle_t ih = POP_ih(); + char *path = pop_fstr_copy(); + int fd, found; + volume *vol; + record rec, r, folrec; + char name[256], *curfol, *tmppath; + + fd = open_ih(ih); + if ( fd == -1 ) { + free( path ); + RET( 0 ); + } + + vol = malloc( sizeof(volume) ); + if (volume_open(vol, fd)) { + free( path ); + close_io( fd ); + RET( 0 ); + } + + /* First move to the specified folder */ + tmppath = strdup(path); + record_init_root( &rec, &vol->catalog ); + record_init_parent( &r, &rec ); + + /* Remove initial \ or / */ + curfol = strsep(&tmppath, "\//"); + curfol = strsep(&tmppath, "\//"); + forth_printf("\n"); + + while (curfol && strlen(curfol)) { + found = 0; + do { + if (r.record.type == HFSP_FOLDER) { + unicode_uni2asc(name, &r.key.name, sizeof(name)); + + if (!strcmp(name, curfol)) { + folrec = r; + found = -1; + } + } + } while ( !record_next(&r) ); + + if (!found) { + forth_printf("Unable to locate path %s on filesystem\n", path); + goto done; + } else { + record_init_parent( &r, &folrec ); + } + + curfol = strsep(&tmppath, "\//"); + } + + /* Output the directory contents */ + found = 0; + do { + unicode_uni2asc(name, &r.key.name, sizeof(name)); + + if (r.record.type == HFSP_FILE) { + /* Grab the file entry */ + hfsp_cat_file *file = &r.record.u.file; + forth_printf("% 10" PRId64 " ", file->data_fork.total_size); + print_date(file->create_date); + forth_printf(" %s\n", name); + found = -1; + } + + if (r.record.type == HFSP_FOLDER) { + /* Grab the directory entry */ + hfsp_cat_folder *folder = &r.record.u.folder; + forth_printf(" 0 "); + print_date(folder->create_date); + forth_printf(" %s\\n", name); + found = -1; + } + + } while ( !record_next(&r) ); + + if (!found) { + forth_printf(" (Empty folder)\n"); + } + +done: + volume_close(vol); + free(path); + if (tmppath) + free(tmppath); }
/* static method, ( pos.d ih -- flag? ) */