Annotation of qemu/roms/openbios/fs/hfs/hfs_fs.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.