|
|
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.