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
, ulong type
, ulong creator
)
64 if( !(dir
=hfs_opendir(vol
, path
)) )
67 while( ret
&& !hfs_readdir(dir
, &ent
) ) {
68 if( ent
.flags
& HFS_ISDIR
)
70 ret
= !(*(ulong
*)ent
.u
.file
.type
== type
&& *(ulong
*)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
) ) {
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
= *(ulong
*)ent
.u
.file
.type
;
116 creator
= *(ulong
*)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 *)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
)
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 *)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( (ucell
) strdup(buf
+start
) );
469 hfs_files_get_fstype( hfs_info_t
*mi
)
471 PUSH( (ucell
)strdup("HFS") );
476 hfs_files_volume_name( hfs_info_t
*mi
)
479 char *volname
= malloc(VOLNAME_SIZE
);
481 fd
= open_ih(my_self());
482 get_hfs_vol_name(fd
, volname
, VOLNAME_SIZE
);
485 PUSH ((ucell
)volname
);
488 /* static method, ( pathstr len ihandle -- ) */
490 hfs_files_dir( hfs_info_t
*dummy
)
498 ihandle_t ih
= POP();
499 char *path
= pop_fstr_copy();
507 volume
= hfs_mount(fd
, 0);
512 common
= malloc(sizeof(hfscommon
));
514 /* HFS paths are colon separated, not backslash separated */
515 for (i
= 0; i
< strlen(path
); i
++)
519 common
->dir
= hfs_opendir(volume
, path
);
522 while( !hfs_readdir(common
->dir
, &ent
) ) {
523 forth_printf("% 10d ", ent
.u
.file
.dsize
);
524 print_date(ent
.mddate
);
525 if( ent
.flags
& HFS_ISDIR
)
526 forth_printf("%s\\\n", ent
.name
);
528 forth_printf("%s\n", ent
.name
);
531 hfs_closedir( common
->dir
);
532 hfs_umount( volume
);
540 /* static method, ( pos.d ih -- flag? ) */
542 hfs_files_probe( hfs_info_t
*dummy
)
544 ihandle_t ih
= POP_ih();
549 if (hfs_probe(fd
, offs
))
558 hfs_initializer( hfs_info_t
*dummy
)
560 fword("register-fs-package");
563 NODE_METHODS( hfs
) = {
564 { "probe", hfs_files_probe
},
565 { "open", hfs_files_open
},
566 { "close", hfs_files_close
},
567 { "read", hfs_files_read
},
568 { "seek", hfs_files_seek
},
569 { "load", hfs_files_load
},
570 { "dir", hfs_files_dir
},
573 { "open-nwrom", hfs_files_open_nwrom
},
574 { "get-path", hfs_files_get_path
},
575 { "get-fstype", hfs_files_get_fstype
},
576 { "volume-name", hfs_files_volume_name
},
578 { NULL
, hfs_initializer
},
584 REGISTER_NODE( hfs
);