|
|
1.1 root 1: /*
2: * Creation Date: <2001/05/06 22:47:23 samuel>
3: * Time-stamp: <2004/01/12 10:24:35 samuel>
4: *
5: * /packages/hfs-files
6: *
7: * HFS world interface
8: *
9: * Copyright (C) 2001-2004 Samuel Rydh ([email protected])
10: * Copyright (C) 2010 Mark Cave-Ayland ([email protected])
11: *
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
15: *
16: */
17:
18: #include "config.h"
19: #include "libopenbios/bindings.h"
20: #include "fs/fs.h"
21: #include "libc/vsprintf.h"
22: #include "libc/diskio.h"
23: #include "libhfs.h"
24:
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"
28:
29: #define FINDER_TYPE 0x464E4452 /* 'FNDR' */
30: #define FINDER_CREATOR 0x4D414353 /* 'MACS' */
31: #define SYSTEM_TYPE 0x7A737973 /* 'zsys' */
32: #define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */
33:
34: #define VOLNAME_SIZE 64
35:
36: extern void hfs_init( void );
37:
38: typedef struct {
39: enum { FILE, DIR } type;
40: union {
41: hfsdir *dir;
42: hfsfile *file;
43: };
44: } hfscommon;
45:
46: typedef struct {
47: hfsvol *vol;
48: hfscommon *common;
49: } hfs_info_t;
50:
51: DECLARE_NODE( hfs, 0, sizeof(hfs_info_t), "+/packages/hfs-files" );
52:
53: /************************************************************************/
54: /* Search Functions */
55: /************************************************************************/
56:
57: static int
58: _find_file( hfsvol *vol, const char *path, unsigned long type, unsigned long creator )
59: {
60: hfsdirent ent;
61: hfsdir *dir;
62: int ret=1;
63:
64: if( !(dir=hfs_opendir(vol, path)) )
65: return 1;
66:
67: while( ret && !hfs_readdir(dir, &ent) ) {
68: if( ent.flags & HFS_ISDIR )
69: continue;
70: ret = !(*(unsigned long*)ent.u.file.type == type && *(unsigned long*)ent.u.file.creator == creator );
71: }
72:
73: hfs_closedir( dir );
74: return ret;
75: }
76:
77:
78: /* ret: 0=success, 1=not_found, 2=not_a_dir */
79: static int
80: _search( hfsvol *vol, const char *path, const char *sname, hfsfile **ret_fd )
81: {
82: hfsdir *dir;
83: hfsdirent ent;
84: int topdir=0, status = 1;
85: char *p, buf[256];
86:
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 );
92:
93: if( !(dir=hfs_opendir(vol, path)) )
94: return 2;
95:
96: /* printk("DIRECTORY: %s\n", path ); */
97:
98: while( status && !hfs_readdir(dir, &ent) ) {
99: unsigned long type, creator;
100:
101: *p = 0;
102: topdir = 0;
103:
104: strncat( buf, ent.name, sizeof(buf) );
105: if( (status=_search(vol, buf, sname, ret_fd)) != 2 )
106: continue;
107: topdir = 1;
108:
109: /* name search? */
110: if( sname ) {
111: status = strcasecmp( ent.name, sname );
112: continue;
113: }
114:
115: type = *(unsigned long*)ent.u.file.type;
116: creator = *(unsigned long*)ent.u.file.creator;
117:
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) )
121: continue;
122:
123: status = _find_file( vol, path, FINDER_TYPE, FINDER_CREATOR )
124: || _find_file( vol, path, SYSTEM_TYPE, SYSTEM_CREATOR );
125: }
126: }
127: if( !status && topdir && ret_fd && !(*ret_fd=hfs_open(vol, buf)) ) {
128: printk("Unexpected error: failed to open matched ROM\n");
129: status = 1;
130: }
131:
132: hfs_closedir( dir );
133: return status;
134: }
135:
136: static hfsfile *
137: _do_search( hfs_info_t *mi, const char *sname )
138: {
139: hfsvol *vol = hfs_getvol( NULL );
140:
141: mi->common->type = FILE;
142: (void)_search( vol, ":", sname, &mi->common->file );
143:
144: return mi->common->file;
145: }
146:
147:
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 };
152:
153: static inline int is_leap(int year)
154: {
155: return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
156: }
157:
158: static void
159: print_date(time_t sec)
160: {
161: unsigned int second, minute, hour, month, day, year;
162: int current;
163: const int *days;
164:
165: second = sec % 60;
166: sec /= 60;
167:
168: minute = sec % 60;
169: sec /= 60;
170:
171: hour = sec % 24;
172: sec /= 24;
173:
174: year = sec * 100 / 36525;
175: sec -= year * 36525 / 100;
176: year += 1970;
177:
178: days = is_leap(year) ? days_month_leap : days_month;
179:
180: current = 0;
181: month = 0;
182: while (month < 12) {
183: if (sec <= current + days[month]) {
184: break;
185: }
186: current += days[month];
187: month++;
188: }
189: month++;
190:
191: day = sec - current + 1;
192:
193: forth_printf("%d-%02d-%02d %02d:%02d:%02d ",
194: year, month, day, hour, minute, second);
195: }
196:
197: /*
198: static void
199: dir_fs( file_desc_t *fd )
200: {
201: hfscommon *common = (hfscommon*)fd;
202: hfsdirent ent;
203:
204: if (common->type != DIR)
205: return;
206:
207: forth_printf("\n");
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);
213: else
214: forth_printf("%s\n", ent.name);
215: }
216: }
217: */
218:
219: /************************************************************************/
220: /* Standard package methods */
221: /************************************************************************/
222:
223: /* ( -- success? ) */
224: static void
225: hfs_files_open( hfs_info_t *mi )
226: {
227: int fd;
228: char *path = my_args_copy();
229:
230: const char *s;
231: char buf[256];
232:
233: fd = open_ih( my_parent() );
234: if ( fd == -1 ) {
235: free( path );
236: RET( 0 );
237: }
238:
239: mi->vol = hfs_mount(fd, 0);
240: if (!mi->vol) {
241: RET( 0 );
242: }
243:
244: if( !strncmp(path, "\\\\", 2) ) {
245: hfsvolent ent;
246:
247: /* \\ is an alias for the (blessed) system folder */
248: if( hfs_vstat(mi->vol, &ent) < 0 || hfs_setcwd(mi->vol, ent.blessed) ) {
249: free(path);
250: RET( -1 );
251: }
252: path += 2;
253: } else {
254: hfs_chdir( mi->vol, ":" );
255: }
256:
257: mi->common = malloc(sizeof(hfscommon));
258: if (!mi->common) {
259: free(path);
260: RET( 0 );
261: }
262:
263: if (strcmp(path, "\\") == 0) {
264: /* root directory is in fact ":" */
265: mi->common->dir = hfs_opendir(mi->vol, ":");
266: mi->common->type = DIR;
267: free(path);
268: RET( -1 );
269: }
270:
271: if (path[strlen(path) - 1] == '\\') {
272: path[strlen(path) - 1] = 0;
273: }
274:
275: for( path-- ;; ) {
276: int n;
277:
278: s = ++path;
279: path = strchr(s, '\\');
280: if( !path || !path[1])
281: break;
282: n = MIN( sizeof(buf)-1, (path-s) );
283: if( !n )
284: continue;
285:
286: strncpy( buf, s, n );
287: buf[n] = 0;
288: if( hfs_chdir(mi->vol, buf) ) {
289: free(mi->common);
290: free(path);
291: RET( 0 );
292: }
293: }
294:
295: /* support the ':filetype' syntax */
296: if( *s == ':' ) {
297: unsigned long id, oldid = hfs_getcwd(mi->vol);
298: hfsdirent ent;
299: hfsdir *dir;
300:
301: s++;
302: id = oldid;
303: hfs_dirinfo( mi->vol, &id, buf );
304: hfs_setcwd( mi->vol, id );
305:
306: if( !(dir=hfs_opendir(mi->vol, buf)) ) {
307: free(mi->common);
308: free(path);
309: RET( 0 );
310: }
311: hfs_setcwd( mi->vol, oldid );
312:
313: while( !hfs_readdir(dir, &ent) ) {
314: if( ent.flags & HFS_ISDIR )
315: continue;
316: if( !strncmp(s, ent.u.file.type, 4) ) {
317: mi->common->type = FILE;
318: mi->common->file = hfs_open( mi->vol, ent.name );
319: break;
320: }
321: }
322: hfs_closedir( dir );
323: free(path);
324: RET( -1 );
325: }
326:
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) {
331: free(mi->common);
332: free(path);
333: RET( 0 );
334: }
335: mi->common->type = FILE;
336: free(path);
337: RET( -1 );
338: }
339: mi->common->type = DIR;
340: free(path);
341:
342: RET( -1 );
343: }
344:
345: /* ( -- ) */
346: static void
347: hfs_files_close( hfs_info_t *mi )
348: {
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 );
354: free(common);
355: }
356:
357: /* ( buf len -- actlen ) */
358: static void
359: hfs_files_read( hfs_info_t *mi )
360: {
361: int count = POP();
362: char *buf = (char *)cell2pointer(POP());
363:
364: hfscommon *common = mi->common;
365: if (common->type != FILE)
366: RET( -1 );
367:
368: RET ( hfs_read( common->file, buf, count ) );
369: }
370:
371: /* ( pos.d -- status ) */
372: static void
373: hfs_files_seek( hfs_info_t *mi )
374: {
375: long long pos = DPOP();
376: int offs = (int)pos;
377: int whence = SEEK_SET;
378: int ret;
379: hfscommon *common = mi->common;
380:
381: if (common->type != FILE)
382: RET( -1 );
383:
384: switch( whence ) {
385: case SEEK_END:
386: whence = HFS_SEEK_END;
387: break;
388: default:
389: case SEEK_SET:
390: whence = HFS_SEEK_SET;
391: break;
392: }
393:
394: ret = hfs_seek( common->file, offs, whence );
395: if (ret != -1)
396: RET( 0 );
397: else
398: RET( -1 );
399: }
400:
401: /* ( addr -- size ) */
402: static void
403: hfs_files_load( hfs_info_t *mi )
404: {
405: char *buf = (char *)cell2pointer(POP());
406: int count;
407:
408: hfscommon *common = mi->common;
409: if (common->type != FILE)
410: RET( -1 );
411:
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);
416:
417: RET ( hfs_read( common->file, buf, count ) );
418: }
419:
420: /* ( -- success? ) */
421: static void
422: hfs_files_open_nwrom( hfs_info_t *mi )
423: {
424: /* Switch to an existing ROM image file on the fs! */
425: if ( _do_search( mi, NULL ) )
426: RET( -1 );
427:
428: RET( 0 );
429: }
430:
431: /* ( -- cstr ) */
432: static void
433: hfs_files_get_path( hfs_info_t *mi )
434: {
435: char buf[256], buf2[256];
436: hfscommon *common = mi->common;
437: hfsvol *vol = hfs_getvol( NULL );
438: hfsdirent ent;
439: int start, ns;
440: unsigned long id;
441:
442: if (common->type != FILE)
443: RET( 0 );
444:
445: hfs_fstat( common->file, &ent );
446: start = sizeof(buf) - strlen(ent.name) - 1;
447: if( start <= 0 )
448: RET ( 0 );
449: strcpy( buf+start, ent.name );
450: buf[--start] = '\\';
451:
452: ns = start;
453: for( id=ent.parid ; !hfs_dirinfo(vol, &id, buf2) ; ) {
454: start = ns;
455: ns -= strlen(buf2);
456: if( ns <= 0 )
457: RET( 0 );
458: strcpy( buf+ns, buf2 );
459: buf[--ns] = buf[start] = '\\';
460: }
461: if( strlen(buf) >= sizeof(buf) )
462: RET( 0 );
463:
464: RET( pointer2cell(strdup(buf+start)) );
465: }
466:
467: /* ( -- cstr ) */
468: static void
469: hfs_files_get_fstype( hfs_info_t *mi )
470: {
471: PUSH( pointer2cell(strdup("HFS")) );
472: }
473:
474: /* ( -- cstr|0 ) */
475: static void
476: hfs_files_volume_name( hfs_info_t *mi )
477: {
478: int fd;
479: char *volname = malloc(VOLNAME_SIZE);
480:
481: fd = open_ih(my_self());
482: if (fd >= 0) {
483: get_hfs_vol_name(fd, volname, VOLNAME_SIZE);
484: close_io(fd);
485: } else {
486: volname[0] = '\0';
487: }
488:
489: PUSH(pointer2cell(volname));
490: }
491:
492: /* static method, ( pathstr len ihandle -- ) */
493: static void
494: hfs_files_dir( hfs_info_t *dummy )
495: {
496: hfsvol *volume;
497: hfscommon *common;
498: hfsdirent ent;
499: int i;
500: int fd;
501:
502: ihandle_t ih = POP();
503: char *path = pop_fstr_copy();
504:
505: fd = open_ih( ih );
506: if ( fd == -1 ) {
507: free( path );
508: return;
509: }
510:
511: volume = hfs_mount(fd, 0);
512: if (!volume) {
513: return;
514: }
515:
516: common = malloc(sizeof(hfscommon));
517:
518: /* HFS paths are colon separated, not backslash separated */
519: for (i = 0; i < strlen(path); i++)
520: if (path[i] == '\\')
521: path[i] = ':';
522:
523: common->dir = hfs_opendir(volume, path);
524:
525: forth_printf("\n");
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);
531: else
532: forth_printf("%s\n", ent.name);
533: }
534:
535: hfs_closedir( common->dir );
536: hfs_umount( volume );
537:
538: close_io( fd );
539:
540: free( common );
541: free( path );
542: }
543:
544: /* static method, ( pos.d ih -- flag? ) */
545: static void
546: hfs_files_probe( hfs_info_t *dummy )
547: {
548: ihandle_t ih = POP_ih();
549: long long offs = DPOP();
550: int fd, ret = 0;
551:
552: fd = open_ih(ih);
553: if (fd >= 0) {
554: if (hfs_probe(fd, offs)) {
555: ret = -1;
556: }
557: close_io(fd);
558: } else {
559: ret = -1;
560: }
561:
562: RET (ret);
563: }
564:
565: static void
566: hfs_initializer( hfs_info_t *dummy )
567: {
568: fword("register-fs-package");
569: }
570:
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 },
579:
580: /* special */
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 },
585:
586: { NULL, hfs_initializer },
587: };
588:
589: void
590: hfs_init( void )
591: {
592: REGISTER_NODE( hfs );
593: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.