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