|
|
1.1 root 1: /*
2: * Creation Date: <2001/05/05 23:33:49 samuel>
3: * Time-stamp: <2004/01/12 10:25:39 samuel>
4: *
5: * /package/hfsplus-files
6: *
7: * HFS+ file system interface (and ROM lookup support)
8: *
9: * Copyright (C) 2001, 2002, 2003, 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 "libhfsp.h"
22: #include "volume.h"
23: #include "record.h"
24: #include "unicode.h"
25: #include "blockiter.h"
26: #include "libc/diskio.h"
27: #include "libc/vsprintf.h"
28:
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"
32:
33: #define FINDER_TYPE 0x464E4452 /* 'FNDR' */
34: #define FINDER_CREATOR 0x4D414353 /* 'MACS' */
35: #define SYSTEM_TYPE 0x7A737973 /* 'zsys' */
36: #define SYSTEM_CREATOR 0x4D414353 /* 'MACS' */
37:
38: #define VOLNAME_SIZE 64
39:
40: extern void hfsp_init( void );
41:
42: typedef struct {
43: record rec;
44: char *path;
45: off_t pos;
46: } hfsp_file_t;
47:
48: typedef struct {
49: volume *vol;
50: hfsp_file_t *hfspfile;
51: } hfsp_info_t;
52:
53: DECLARE_NODE( hfsp, 0, sizeof(hfsp_info_t), "+/packages/hfsplus-files" );
54:
55:
56: /************************************************************************/
57: /* Search implementation */
58: /************************************************************************/
59:
60: typedef int (*match_proc_t)( record *r, record *parent, const void *match_data, hfsp_file_t *pt );
61:
62: static int
63: search_files( record *par, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt )
64: {
65: hfsp_file_t t;
66: record r;
67: int ret = 1;
68:
69: t.path = NULL;
70:
71: record_init_parent( &r, par );
72: do{
73: if( r.record.type == HFSP_FOLDER || r.record.type == HFSP_FILE )
74: ret = (*proc)( &r, par, match_data, &t );
75:
76: if( ret && r.record.type == HFSP_FOLDER && recursive )
77: ret = search_files( &r, 1, proc, match_data, &t );
78:
79: } while( ret && !record_next(&r) );
80:
81: if( !ret && pt ) {
82: char name[256];
83: const char *s2 = t.path ? t.path : "";
84:
85: unicode_uni2asc( name, &r.key.name, sizeof(name));
86:
87: pt->rec = t.rec;
88: pt->path = malloc( strlen(name) + strlen(s2) + 2 );
89: strcpy( pt->path, name );
90: if( strlen(s2) ) {
91: strcat( pt->path, "\\" );
92: strcat( pt->path, s2 );
93: }
94: }
95:
96: if( t.path )
97: free( t.path );
98:
99: return ret;
100: }
101:
102: static int
103: root_search_files( volume *vol, int recursive, match_proc_t proc, const void *match_data, hfsp_file_t *pt )
104: {
105: record r;
106:
107: record_init_root( &r, &vol->catalog );
108: return search_files( &r, recursive, proc, match_data, pt );
109: }
110:
111: static int
112: match_file( record *r, record *parent, const void *match_data, hfsp_file_t *pt )
113: {
114: const char *p = (const char*)match_data;
115: char name[256];
116: int ret=1;
117:
118: if( r->record.type != HFSP_FILE )
119: return 1;
120:
121: (void) unicode_uni2asc(name, &r->key.name, sizeof(name));
122: if( !(ret=strcasecmp(p, name)) && pt )
123: pt->rec = *r;
124:
125: return ret;
126: }
127:
128: static int
129: match_rom( record *r, record *par, const void *match_data, hfsp_file_t *pt )
130: {
131: hfsp_cat_file *file = &r->record.u.file;
132: FInfo *fi = &file->user_info;
133: int ret = 1;
134: char buf[256];
135:
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 );
139:
140: (void) unicode_uni2asc(buf, &r->key.name, sizeof(buf));
141: if( !strcasecmp("BootX", buf) )
142: return 1;
143:
144: if( !ret && pt )
145: pt->rec = *r;
146: }
147: return ret;
148: }
149:
150: static int
151: match_path( record *r, record *par, const void *match_data, hfsp_file_t *pt )
152: {
153: char name[256], *s, *next, *org;
154: int ret=1;
155:
156: next = org = strdup( (char*)match_data );
157: while( (s=strsep( &next, "\\/" )) && !strlen(s) )
158: ;
159: if( !s ) {
160: free( org );
161: return 1;
162: }
163:
164: if( *s == ':' && strlen(s) == 5 ) {
165: if( r->record.type == HFSP_FILE && !next ) {
166: /* match type */
167: hfsp_cat_file *file = &r->record.u.file;
168: FInfo *fi = &file->user_info;
169: int i, type=0;
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 ) {
174: if( pt )
175: pt->rec = *r;
176: ret = 0;
177: }
178: }
179: } else {
180: (void) unicode_uni2asc(name, &r->key.name, sizeof(name));
181:
182: if( !strcasecmp(s, name) ) {
183: if( r->record.type == HFSP_FILE && !next ) {
184: if( pt )
185: pt->rec = *r;
186: ret = 0;
187: } else /* must be a directory */
188: ret = search_files( r, 0, match_path, next, pt );
189: }
190: }
191: free( org );
192: return ret;
193: }
194:
195:
196: /************************************************************************/
197: /* Standard package methods */
198: /************************************************************************/
199:
200: /* ( -- success? ) */
201: static void
202: hfsp_files_open( hfsp_info_t *mi )
203: {
204: int fd;
205: char *path = my_args_copy();
206:
207: if ( ! path )
208: RET( 0 );
209:
210: fd = open_ih( my_parent() );
211: if ( fd == -1 ) {
212: free( path );
213: RET( 0 );
214: }
215:
216: mi->vol = malloc( sizeof(volume) );
217: if (volume_open(mi->vol, fd)) {
218: free( path );
219: close_io( fd );
220: RET( 0 );
221: }
222:
223: mi->hfspfile = malloc( sizeof(hfsp_file_t) );
224:
225: /* Leading \\ means system folder. The finder info block has
226: * the following meaning.
227: *
228: * [0] Prefered boot directory ID
229: * [3] MacOS 9 boot directory ID
230: * [5] MacOS X boot directory ID
231: */
232: if( !strncmp(path, "\\\\", 2) ) {
233: int *p = (int*)&(mi->vol)->vol.finder_info[0];
234: int cnid = p[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] )
237: cnid = p[3];
238: if( record_init_cnid(&(mi->hfspfile->rec), &(mi->vol)->catalog, cnid) )
239: RET ( 0 );
240: path += 2;
241: } else {
242: record_init_root( &(mi->hfspfile->rec), &(mi->vol)->catalog );
243: }
244:
245: if( !search_files(&(mi->hfspfile->rec), 0, match_path, path, mi->hfspfile ) )
246: RET ( -1 );
247:
248: RET ( -1 );
249: }
250:
251: /* ( -- ) */
252: static void
253: hfsp_files_close( hfsp_info_t *mi )
254: {
255: volume_close(mi->vol);
256:
257: if( mi->hfspfile->path )
258: free( mi->hfspfile->path );
259: free( mi->hfspfile );
260: }
261:
262: /* ( buf len -- actlen ) */
263: static void
264: hfsp_files_read( hfsp_info_t *mi )
265: {
266: int count = POP();
267: char *buf = (char *)cell2pointer(POP());
268:
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;
273: blockiter iter;
274: char buf2[blksize];
275: int act_count, curpos=0;
276:
277: blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id );
278: while( curpos + blksize < t->pos ) {
279: if( blockiter_next( &iter ) ) {
280: RET ( -1 );
281: return;
282: }
283: curpos += blksize;
284: }
285: act_count = 0;
286:
287: while( act_count < count ){
288: UInt32 block = blockiter_curr(&iter);
289: int max = blksize, add = 0, size;
290:
291: if( volume_readinbuf( vol, buf2, block ) )
292: break;
293:
294: if( curpos < t->pos ){
295: add += t->pos - curpos;
296: max -= t->pos - curpos;
297: }
298: size = (count-act_count > max)? max : count-act_count;
299: memcpy( (char *)buf + act_count, &buf2[add], size );
300:
301: curpos += blksize;
302: act_count += size;
303:
304: if( blockiter_next( &iter ) )
305: break;
306: }
307:
308: t->pos += act_count;
309:
310: RET ( act_count );
311: }
312:
313: /* ( pos.d -- status ) */
314: static void
315: hfsp_files_seek( hfsp_info_t *mi )
316: {
317: long long pos = DPOP();
318: int offs = (int)pos;
319: int whence = SEEK_SET;
320:
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;
324:
325: if( offs == -1 ) {
326: offs = 0;
327: whence = SEEK_END;
328: }
329:
330: switch( whence ){
331: case SEEK_END:
332: t->pos = total + offs;
333: break;
334: default:
335: case SEEK_SET:
336: t->pos = offs;
337: break;
338: }
339:
340: if( t->pos < 0 )
341: t->pos = 0;
342:
343: if( t->pos > total )
344: t->pos = total;
345:
346: RET ( 0 );
347: }
348:
349: /* ( addr -- size ) */
350: static void
351: hfsp_files_load( hfsp_info_t *mi )
352: {
353: char *buf = (char *)cell2pointer(POP());
354:
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;
360: blockiter iter;
361: char buf2[blksize];
362: int act_count;
363:
364: blockiter_init( &iter, vol, &file->data_fork, HFSP_EXTENT_DATA, file->id );
365:
366: act_count = 0;
367:
368: while( act_count < total ){
369: UInt32 block = blockiter_curr(&iter);
370: int max = blksize, size;
371:
372: if( volume_readinbuf( vol, buf2, block ) )
373: break;
374:
375: size = (total-act_count > max)? max : total-act_count;
376: memcpy( (char *)buf + act_count, &buf2, size );
377:
378: act_count += size;
379:
380: if( blockiter_next( &iter ) )
381: break;
382: }
383:
384: RET ( act_count );
385: }
386:
387: /* ( -- cstr ) */
388: static void
389: hfsp_files_get_fstype( hfsp_info_t *mi )
390: {
391: PUSH( pointer2cell(strdup("HFS+")) );
392: }
393:
394: /* ( -- cstr ) */
395: static void
396: hfsp_files_get_path( hfsp_info_t *mi )
397: {
398: char *buf;
399: hfsp_file_t *t = mi->hfspfile;
400:
401: if( !t->path )
402: RET ( 0 );
403:
404: buf = malloc(strlen(t->path) + 1);
405: strncpy( buf, t->path, strlen(t->path) );
406: buf[strlen(t->path)] = 0;
407:
408: PUSH(pointer2cell(buf));
409: }
410:
411: /* ( -- success? ) */
412: static void
413: hfsp_files_open_nwrom( hfsp_info_t *mi )
414: {
415: /* Switch to an existing ROM image file on the fs! */
416: if( !root_search_files(mi->vol, 1, match_rom, NULL, mi->hfspfile) )
417: RET ( -1 );
418:
419: RET ( 0 );
420: }
421:
422: /* ( -- cstr|0 ) */
423: static void
424: hfsp_files_volume_name( hfsp_info_t *mi )
425: {
426: int fd;
427: char *volname = malloc(VOLNAME_SIZE);
428:
429: fd = open_ih(my_self());
430: if (fd >= 0) {
431: get_hfs_vol_name(fd, volname, VOLNAME_SIZE);
432: close_io(fd);
433: } else {
434: volname[0] = '\0';
435: }
436:
437: PUSH(pointer2cell(volname));
438: }
439:
440: /* static method, ( pathstr len ihandle -- ) */
441: static void
442: hfsp_files_dir( hfsp_info_t *dummy )
443: {
444: forth_printf("dir method not implemented for HFS+ filesystem\n");
445: POP();
446: POP();
447: POP();
448: }
449:
450: /* static method, ( pos.d ih -- flag? ) */
451: static void
452: hfsp_files_probe( hfsp_info_t *dummy )
453: {
454: ihandle_t ih = POP_ih();
455: long long offs = DPOP();
456: int fd, ret = 0;
457:
458: fd = open_ih(ih);
459: if (fd >= 0) {
460: if (volume_probe(fd, offs)) {
461: ret = -1;
462: }
463: close_io(fd);
464: } else {
465: ret = -1;
466: }
467:
468: RET (ret);
469: }
470:
471: static void
472: hfsp_initializer( hfsp_info_t *dummy )
473: {
474: fword("register-fs-package");
475: }
476:
477: NODE_METHODS( hfsp ) = {
478: { "probe", hfsp_files_probe },
479: { "open", hfsp_files_open },
480: { "close", hfsp_files_close },
481: { "read", hfsp_files_read },
482: { "seek", hfsp_files_seek },
483: { "load", hfsp_files_load },
484: { "dir", hfsp_files_dir },
485:
486: /* special */
487: { "open-nwrom", hfsp_files_open_nwrom },
488: { "get-path", hfsp_files_get_path },
489: { "get-fstype", hfsp_files_get_fstype },
490: { "volume-name", hfsp_files_volume_name },
491:
492: { NULL, hfsp_initializer },
493: };
494:
495: void
496: hfsp_init( void )
497: {
498: REGISTER_NODE( hfsp );
499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.