2 * Creation Date: <2001/05/06 22:47:23 samuel>
3 * Time-stamp: <2004/01/12 10:24:35 samuel>
9 * Copyright (C) 2001-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"
21 #include "libc/vsprintf.h"
22 #include "libc/diskio.h"
25 #define MAC_OS_ROM_CREATOR 0x63687270 /* 'chrp' */
26 #define MAC_OS_ROM_TYPE 0x74627869 /* 'tbxi' */
27 #define MAC_OS_ROM_NAME "Mac OS ROM"
29 #define FINDER_TYPE 0x464E4452 /* 'FNDR' */
30 #define FINDER_CREATOR 0x4D414353 /* 'MACS' */
31 #define SYSTEM_TYPE 0x7A737973 /* 'zsys' */
32 #define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */
34 #define VOLNAME_SIZE 64
36 extern void hfs_init( void );
39 enum { FILE, DIR } type;
51 DECLARE_NODE( hfs, 0, sizeof(hfs_info_t), "+/packages/hfs-files" );
53 /************************************************************************/
54 /* Search Functions */
55 /************************************************************************/
58 _find_file( hfsvol *vol, const char *path, unsigned long type, unsigned long creator )
64 if( !(dir=hfs_opendir(vol, path)) )
67 while( ret && !hfs_readdir(dir, &ent) ) {
68 if( ent.flags & HFS_ISDIR )
70 ret = !(*(unsigned long*)ent.u.file.type == type && *(unsigned long*)ent.u.file.creator == creator );
78 /* ret: 0=success, 1=not_found, 2=not_a_dir */
80 _search( hfsvol *vol, const char *path, const char *sname, hfsfile **ret_fd )
84 int topdir=0, status = 1;
87 strncpy( buf, path, sizeof(buf) );
88 if( buf[strlen(buf)-1] != ':' )
89 strncat( buf, ":", sizeof(buf) );
90 buf[sizeof(buf)-1] = 0;
91 p = buf + strlen( buf );
93 if( !(dir=hfs_opendir(vol, path)) )
96 /* printk("DIRECTORY: %s\n", path ); */
98 while( status && !hfs_readdir(dir, &ent) ) {
99 unsigned long type, creator;
104 strncat( buf, ent.name, sizeof(buf) );
105 if( (status=_search(vol, buf, sname, ret_fd)) != 2 )
111 status = strcasecmp( ent.name, sname );
115 type = *(unsigned long*)ent.u.file.type;
116 creator = *(unsigned long*)ent.u.file.creator;
118 /* look for Mac OS ROM, System and Finder in the same directory */
119 if( type == MAC_OS_ROM_TYPE && creator == MAC_OS_ROM_CREATOR ) {
120 if( strcasecmp(ent.name, MAC_OS_ROM_NAME) )
123 status = _find_file( vol, path, FINDER_TYPE, FINDER_CREATOR )
124 || _find_file( vol, path, SYSTEM_TYPE, SYSTEM_CREATOR );
127 if( !status && topdir && ret_fd && !(*ret_fd=hfs_open(vol, buf)) ) {
128 printk("Unexpected error: failed to open matched ROM\n");
137 _do_search( hfs_info_t *mi, const char *sname )
139 hfsvol *vol = hfs_getvol( NULL );
141 mi->common->type = FILE;
142 (void)_search( vol, ":", sname, &mi->common->file );
144 return mi->common->file;
148 static const int days_month[12] =
149 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
150 static const int days_month_leap[12] =
151 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
153 static inline int is_leap(int year)
155 return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
159 print_date(time_t sec)
161 unsigned int second, minute, hour, month, day, year;
174 year = sec * 100 / 36525;
175 sec -= year * 36525 / 100;
178 days = is_leap(year) ? days_month_leap : days_month;
183 if (sec <= current + days[month]) {
186 current += days[month];
191 day = sec - current + 1;
193 forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
194 year, month, day, hour, minute, second);
199 dir_fs( file_desc_t *fd )
201 hfscommon *common = (hfscommon*)fd;
204 if (common->type != DIR)
208 while( !hfs_readdir(common->dir, &ent) ) {
209 forth_printf("% 10d ", ent.u.file.dsize);
210 print_date(ent.mddate);
211 if( ent.flags & HFS_ISDIR )
212 forth_printf("%s\\\n", ent.name);
214 forth_printf("%s\n", ent.name);
219 /************************************************************************/
220 /* Standard package methods */
221 /************************************************************************/
223 /* ( -- success? ) */
225 hfs_files_open( hfs_info_t *mi )
228 char *path = my_args_copy();
233 fd = open_ih( my_parent() );
239 mi->vol = hfs_mount(fd, 0);
244 if( !strncmp(path, "\\\\", 2) ) {
247 /* \\ is an alias for the (blessed) system folder */
248 if( hfs_vstat(mi->vol, &ent) < 0 || hfs_setcwd(mi->vol, ent.blessed) ) {
254 hfs_chdir( mi->vol, ":" );
257 mi->common = malloc(sizeof(hfscommon));
263 if (strcmp(path, "\\") == 0) {
264 /* root directory is in fact ":" */
265 mi->common->dir = hfs_opendir(mi->vol, ":");
266 mi->common->type = DIR;
271 if (path[strlen(path) - 1] == '\\') {
272 path[strlen(path) - 1] = 0;
279 path = strchr(s, '\\');
280 if( !path || !path[1])
282 n = MIN( sizeof(buf)-1, (path-s) );
286 strncpy( buf, s, n );
288 if( hfs_chdir(mi->vol, buf) ) {
295 /* support the ':filetype' syntax */
297 unsigned long id, oldid = hfs_getcwd(mi->vol);
303 hfs_dirinfo( mi->vol, &id, buf );
304 hfs_setcwd( mi->vol, id );
306 if( !(dir=hfs_opendir(mi->vol, buf)) ) {
311 hfs_setcwd( mi->vol, oldid );
313 while( !hfs_readdir(dir, &ent) ) {
314 if( ent.flags & HFS_ISDIR )
316 if( !strncmp(s, ent.u.file.type, 4) ) {
317 mi->common->type = FILE;
318 mi->common->file = hfs_open( mi->vol, ent.name );
327 mi->common->dir = hfs_opendir(mi->vol, s);
328 if (!mi->common->dir) {
329 mi->common->file = hfs_open( mi->vol, s );
330 if (mi->common->file == NULL) {
335 mi->common->type = FILE;
339 mi->common->type = DIR;
347 hfs_files_close( hfs_info_t *mi )
349 hfscommon *common = mi->common;
350 if (common->type == FILE)
351 hfs_close( common->file );
352 else if (common->type == DIR)
353 hfs_closedir( common->dir );
357 /* ( buf len -- actlen ) */
359 hfs_files_read( hfs_info_t *mi )
362 char *buf = (char *)cell2pointer(POP());
364 hfscommon *common = mi->common;
365 if (common->type != FILE)
368 RET ( hfs_read( common->file, buf, count ) );
371 /* ( pos.d -- status ) */
373 hfs_files_seek( hfs_info_t *mi )
375 long long pos = DPOP();
377 int whence = SEEK_SET;
379 hfscommon *common = mi->common;
381 if (common->type != FILE)
386 whence = HFS_SEEK_END;
390 whence = HFS_SEEK_SET;
394 ret = hfs_seek( common->file, offs, whence );
401 /* ( addr -- size ) */
403 hfs_files_load( hfs_info_t *mi )
405 char *buf = (char *)cell2pointer(POP());
408 hfscommon *common = mi->common;
409 if (common->type != FILE)
412 /* Seek to the end in order to get the file size */
413 hfs_seek(common->file, 0, HFS_SEEK_END);
414 count = common->file->pos;
415 hfs_seek(common->file, 0, HFS_SEEK_SET);
417 RET ( hfs_read( common->file, buf, count ) );
420 /* ( -- success? ) */
422 hfs_files_open_nwrom( hfs_info_t *mi )
424 /* Switch to an existing ROM image file on the fs! */
425 if ( _do_search( mi, NULL ) )
433 hfs_files_get_path( hfs_info_t *mi )
435 char buf[256], buf2[256];
436 hfscommon *common = mi->common;
437 hfsvol *vol = hfs_getvol( NULL );
442 if (common->type != FILE)
445 hfs_fstat( common->file, &ent );
446 start = sizeof(buf) - strlen(ent.name) - 1;
449 strcpy( buf+start, ent.name );
453 for( id=ent.parid ; !hfs_dirinfo(vol, &id, buf2) ; ) {
458 strcpy( buf+ns, buf2 );
459 buf[--ns] = buf[start] = '\\';
461 if( strlen(buf) >= sizeof(buf) )
464 RET( pointer2cell(strdup(buf+start)) );
469 hfs_files_get_fstype( hfs_info_t *mi )
471 PUSH( pointer2cell(strdup("HFS")) );
476 hfs_files_volume_name( hfs_info_t *mi )
479 char *volname = malloc(VOLNAME_SIZE);
481 fd = open_ih(my_self());
483 get_hfs_vol_name(fd, volname, VOLNAME_SIZE);
489 PUSH(pointer2cell(volname));
492 /* static method, ( pathstr len ihandle -- ) */
494 hfs_files_dir( hfs_info_t *dummy )
502 ihandle_t ih = POP();
503 char *path = pop_fstr_copy();
511 volume = hfs_mount(fd, 0);
516 common = malloc(sizeof(hfscommon));
518 /* HFS paths are colon separated, not backslash separated */
519 for (i = 0; i < strlen(path); i++)
523 common->dir = hfs_opendir(volume, path);
526 while( !hfs_readdir(common->dir, &ent) ) {
527 forth_printf("% 10ld ", ent.u.file.dsize);
528 print_date(ent.mddate);
529 if( ent.flags & HFS_ISDIR )
530 forth_printf("%s\\\n", ent.name);
532 forth_printf("%s\n", ent.name);
535 hfs_closedir( common->dir );
536 hfs_umount( volume );
544 /* static method, ( pos.d ih -- flag? ) */
546 hfs_files_probe( hfs_info_t *dummy )
548 ihandle_t ih = POP_ih();
549 long long offs = DPOP();
554 if (hfs_probe(fd, offs)) {
566 hfs_initializer( hfs_info_t *dummy )
568 fword("register-fs-package");
571 NODE_METHODS( hfs ) = {
572 { "probe", hfs_files_probe },
573 { "open", hfs_files_open },
574 { "close", hfs_files_close },
575 { "read", hfs_files_read },
576 { "seek", hfs_files_seek },
577 { "load", hfs_files_load },
578 { "dir", hfs_files_dir },
581 { "open-nwrom", hfs_files_open_nwrom },
582 { "get-path", hfs_files_get_path },
583 { "get-fstype", hfs_files_get_fstype },
584 { "volume-name", hfs_files_volume_name },
586 { NULL, hfs_initializer },
592 REGISTER_NODE( hfs );