2 * Creation Date: <2001/05/05 23:33:49 samuel>
3 * Time-stamp: <2004/01/12 10:25:39 samuel>
5 * /package/hfsplus-files
7 * HFS+ file system interface (and ROM lookup support)
9 * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
10 * Copyright (C) 2010 Mark Cave-Ayland (mark.cave-ayland@siriusit.co.uk)
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation
19 #include "libopenbios/bindings.h"
25 #include "blockiter.h"
26 #include "libc/diskio.h"
27 #include "libc/vsprintf.h"
29 #define MAC_OS_ROM_CREATOR 0x63687270 /* 'chrp' */
30 #define MAC_OS_ROM_TYPE 0x74627869 /* 'tbxi' */
31 #define MAC_OS_ROM_NAME "Mac OS ROM"
33 #define FINDER_TYPE 0x464E4452 /* 'FNDR' */
34 #define FINDER_CREATOR 0x4D414353 /* 'MACS' */
35 #define SYSTEM_TYPE 0x7A737973 /* 'zsys' */
36 #define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */
38 #define VOLNAME_SIZE 64
40 extern void hfsp_init( void );
50 hfsp_file_t *hfspfile;
53 DECLARE_NODE( hfsp, 0, sizeof(hfsp_info_t), "+/packages/hfsplus-files" );
56 /************************************************************************/
57 /* Search implementation */
58 /************************************************************************/
60 typedef int (*match_proc_t)( record *r, record *parent, const void *match_data, hfsp_file_t *pt );
63 search_files( record *par, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt )
71 record_init_parent( &r, par );
73 if( r.record.type == HFSP_FOLDER || r.record.type == HFSP_FILE )
74 ret = (*proc)( &r, par, match_data, &t );
76 if( ret && r.record.type == HFSP_FOLDER && recursive )
77 ret = search_files( &r, 1, proc, match_data, &t );
79 } while( ret && !record_next(&r) );
83 const char *s2 = t.path ? t.path : "";
85 unicode_uni2asc( name, &r.key.name, sizeof(name));
88 pt->path = malloc( strlen(name) + strlen(s2) + 2 );
89 strcpy( pt->path, name );
91 strcat( pt->path, "\\" );
92 strcat( pt->path, s2 );
103 root_search_files( volume *vol, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt )
107 record_init_root( &r, &vol->catalog );
108 return search_files( &r, recursive, proc, match_data, pt );
112 match_file( record *r, record *parent, const void *match_data, hfsp_file_t *pt )
114 const char *p = (const char*)match_data;
118 if( r->record.type != HFSP_FILE )
121 (void) unicode_uni2asc(name, &r->key.name, sizeof(name));
122 if( !(ret=strcasecmp(p, name)) && pt )
129 match_rom( record *r, record *par, const void *match_data, hfsp_file_t *pt )
131 hfsp_cat_file *file = &r->record.u.file;
132 FInfo *fi = &file->user_info;
136 if( r->record.type == HFSP_FILE && fi->fdCreator == MAC_OS_ROM_CREATOR && fi->fdType == MAC_OS_ROM_TYPE ) {
137 ret = search_files( par, 0, match_file, "System", NULL )
138 || search_files( par, 0, match_file, "Finder", NULL );
140 (void) unicode_uni2asc(buf, &r->key.name, sizeof(buf));
141 if( !strcasecmp("BootX", buf) )
151 match_path( record *r, record *par, const void *match_data, hfsp_file_t *pt )
153 char name[256], *s, *next, *org;
156 next = org = strdup( (char*)match_data );
157 while( (s=strsep( &next, "\\/" )) && !strlen(s) )
164 if( *s == ':' && strlen(s) == 5 ) {
165 if( r->record.type == HFSP_FILE && !next ) {
167 hfsp_cat_file *file = &r->record.u.file;
168 FInfo *fi = &file->user_info;
170 for( i=1; s[i] && i<=4; i++ )
171 type = (type << 8) | s[i];
172 /* printk("fi->fdType: %s / %s\n", s+1, b ); */
173 if( fi->fdType == type ) {
180 (void) unicode_uni2asc(name, &r->key.name, sizeof(name));
182 if( !strcasecmp(s, name) ) {
183 if( r->record.type == HFSP_FILE && !next ) {
187 } else /* must be a directory */
188 ret = search_files( r, 0, match_path, next, pt );
196 /************************************************************************/
197 /* Standard package methods */
198 /************************************************************************/
200 /* ( -- success? ) */
202 hfsp_files_open( hfsp_info_t *mi )
205 char *path = my_args_copy();
210 fd = open_ih( my_parent() );
216 mi->vol = malloc( sizeof(volume) );
217 if (volume_open(mi->vol, fd)) {
223 mi->hfspfile = malloc( sizeof(hfsp_file_t) );
225 /* Leading \\ means system folder. The finder info block has
226 * the following meaning.
228 * [0] Prefered boot directory ID
229 * [3] MacOS 9 boot directory ID
230 * [5] MacOS X boot directory ID
232 if( !strncmp(path, "\\\\", 2) ) {
233 int *p = (int*)&(mi->vol)->vol.finder_info[0];
235 /* printk(" p[0] = %x, p[3] = %x, p[5] = %x\n", p[0], p[3], p[5] ); */
236 if( p[0] == p[5] && p[3] )
238 if( record_init_cnid(&(mi->hfspfile->rec), &(mi->vol)->catalog, cnid) )
242 record_init_root( &(mi->hfspfile->rec), &(mi->vol)->catalog );
245 if( !search_files(&(mi->hfspfile->rec), 0, match_path, path, mi->hfspfile ) )
253 hfsp_files_close( hfsp_info_t *mi )
255 volume_close(mi->vol);
257 if( mi->hfspfile->path )
258 free( mi->hfspfile->path );
259 free( mi->hfspfile );
262 /* ( buf len -- actlen ) */
264 hfsp_files_read( hfsp_info_t *mi )
267 char *buf = (char *)cell2pointer(POP());
269 hfsp_file_t *t = mi->hfspfile;
270 volume *vol = t->rec.tree->vol;
271 UInt32 blksize = vol->blksize;
272 hfsp_cat_file *file = &t->rec.record.u.file;
275 int act_count, curpos=0;
277 blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id );
278 while( curpos + blksize < t->pos ) {
279 if( blockiter_next( &iter ) ) {
287 while( act_count < count ){
288 UInt32 block = blockiter_curr(&iter);
289 int max = blksize, add = 0, size;
291 if( volume_readinbuf( vol, buf2, block ) )
294 if( curpos < t->pos ){
295 add += t->pos - curpos;
296 max -= t->pos - curpos;
298 size = (count-act_count > max)? max : count-act_count;
299 memcpy( (char *)buf + act_count, &buf2[add], size );
304 if( blockiter_next( &iter ) )
313 /* ( pos.d -- status ) */
315 hfsp_files_seek( hfsp_info_t *mi )
317 long long pos = DPOP();
319 int whence = SEEK_SET;
321 hfsp_file_t *t = mi->hfspfile;
322 hfsp_cat_file *file = &t->rec.record.u.file;
323 int total = file->data_fork.total_size;
332 t->pos = total + offs;
349 /* ( addr -- size ) */
351 hfsp_files_load( hfsp_info_t *mi )
353 char *buf = (char *)cell2pointer(POP());
355 hfsp_file_t *t = mi->hfspfile;
356 volume *vol = t->rec.tree->vol;
357 UInt32 blksize = vol->blksize;
358 hfsp_cat_file *file = &t->rec.record.u.file;
359 int total = file->data_fork.total_size;
364 blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id );
368 while( act_count < total ){
369 UInt32 block = blockiter_curr(&iter);
370 int max = blksize, size;
372 if( volume_readinbuf( vol, buf2, block ) )
375 size = (total-act_count > max)? max : total-act_count;
376 memcpy( (char *)buf + act_count, &buf2, size );
380 if( blockiter_next( &iter ) )
389 hfsp_files_get_fstype( hfsp_info_t *mi )
391 PUSH( pointer2cell(strdup("HFS+")) );
396 hfsp_files_get_path( hfsp_info_t *mi )
399 hfsp_file_t *t = mi->hfspfile;
404 buf = malloc(strlen(t->path) + 1);
405 strncpy( buf, t->path, strlen(t->path) );
406 buf[strlen(t->path)] = 0;
408 PUSH(pointer2cell(buf));
411 /* ( -- success? ) */
413 hfsp_files_open_nwrom( hfsp_info_t *mi )
415 /* Switch to an existing ROM image file on the fs! */
416 if( !root_search_files(mi->vol, 1, match_rom, NULL, mi->hfspfile) )
424 hfsp_files_volume_name( hfsp_info_t *mi )
427 char *volname = malloc(VOLNAME_SIZE);
429 fd = open_ih(my_self());
431 get_hfs_vol_name(fd, volname, VOLNAME_SIZE);
437 PUSH(pointer2cell(volname));
440 static const int days_month[12] =
441 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
442 static const int days_month_leap[12] =
443 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
445 static inline int is_leap(int year)
447 return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
451 print_date(uint32_t sec)
453 unsigned int second, minute, hour, month, day, year;
466 year = sec * 100 / 36525;
467 sec -= year * 36525 / 100;
470 days = is_leap(year) ? days_month_leap : days_month;
475 if (sec <= current + days[month]) {
478 current += days[month];
483 day = sec - current + 1;
485 forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
486 year, month, day, hour, minute, second);
489 /* static method, ( pathstr len ihandle -- ) */
491 hfsp_files_dir( hfsp_info_t *dummy )
493 ihandle_t ih = POP_ih();
494 char *path = pop_fstr_copy();
497 record rec, r, folrec;
498 char name[256], *curfol, *tmppath;
506 vol = malloc( sizeof(volume) );
507 if (volume_open(vol, fd)) {
513 /* First move to the specified folder */
514 tmppath = strdup(path);
515 record_init_root( &rec, &vol->catalog );
516 record_init_parent( &r, &rec );
518 /* Remove initial \ or / */
519 curfol = strsep(&tmppath, "\\//");
520 curfol = strsep(&tmppath, "\\//");
523 while (curfol && strlen(curfol)) {
526 if (r.record.type == HFSP_FOLDER) {
527 unicode_uni2asc(name, &r.key.name, sizeof(name));
529 if (!strcmp(name, curfol)) {
534 } while ( !record_next(&r) );
537 forth_printf("Unable to locate path %s on filesystem\n", path);
540 record_init_parent( &r, &folrec );
543 curfol = strsep(&tmppath, "\\//");
546 /* Output the directory contents */
549 unicode_uni2asc(name, &r.key.name, sizeof(name));
551 if (r.record.type == HFSP_FILE) {
552 /* Grab the file entry */
553 hfsp_cat_file *file = &r.record.u.file;
554 forth_printf("% 10lld ", file->data_fork.total_size);
555 print_date(file->create_date);
556 forth_printf(" %s\n", name);
560 if (r.record.type == HFSP_FOLDER) {
561 /* Grab the directory entry */
562 hfsp_cat_folder *folder = &r.record.u.folder;
564 print_date(folder->create_date);
565 forth_printf(" %s\\\n", name);
569 } while ( !record_next(&r) );
572 forth_printf(" (Empty folder)\n");
583 /* static method, ( pos.d ih -- flag? ) */
585 hfsp_files_probe( hfsp_info_t *dummy )
587 ihandle_t ih = POP_ih();
588 long long offs = DPOP();
593 if (volume_probe(fd, offs)) {
605 hfsp_initializer( hfsp_info_t *dummy )
607 fword("register-fs-package");
610 NODE_METHODS( hfsp ) = {
611 { "probe", hfsp_files_probe },
612 { "open", hfsp_files_open },
613 { "close", hfsp_files_close },
614 { "read", hfsp_files_read },
615 { "seek", hfsp_files_seek },
616 { "load", hfsp_files_load },
617 { "dir", hfsp_files_dir },
620 { "open-nwrom", hfsp_files_open_nwrom },
621 { "get-path", hfsp_files_get_path },
622 { "get-fstype", hfsp_files_get_fstype },
623 { "volume-name", hfsp_files_volume_name },
625 { NULL, hfsp_initializer },
631 REGISTER_NODE( hfsp );