Annotation of qemu/roms/openbios/fs/hfs/hfs_fs.c, revision 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.