Annotation of uae/filesys.c, revision 1.1

1.1     ! root        1:  /* 
        !             2:   * UAE - The Un*x Amiga Emulator
        !             3:   * 
        !             4:   * Unix file system handler for AmigaDOS
        !             5:   *
        !             6:   * (c) 1996 Ed Hanway
        !             7:   *
        !             8:   * Version 0.1: 28-Jan-1996
        !             9:   *
        !            10:   * Based on example code (c) 1988 The Software Distillery
        !            11:   * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
        !            12:   * (May - August 1989)
        !            13:   *
        !            14:   * Known limitations:
        !            15:   * Does not support ACTION_INHIBIT (big deal).
        !            16:   * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
        !            17:   * Does not actually enforce exclusive locks.
        !            18:   * Does not support removable volumes.
        !            19:   * May not return the correct error code in some cases.
        !            20:   * Does not check for sane values passed by AmigaDOS.  May crash the emulation
        !            21:   * if passed garbage values.
        !            22:   *
        !            23:   * TODO someday:
        !            24:   * Support booting.
        !            25:   * Implement real locking using flock.  Needs test cases.
        !            26:   */
        !            27: 
        !            28: #include <stdio.h>
        !            29: #include <stdlib.h>
        !            30: #include <string.h>
        !            31: #include <strings.h>
        !            32: #include <assert.h>
        !            33: 
        !            34: #ifdef __unix
        !            35: #include <unistd.h>
        !            36: #include <fcntl.h>
        !            37: #include <sys/vfs.h>
        !            38: #include <sys/types.h>
        !            39: #include <sys/stat.h>
        !            40: #ifndef __linux
        !            41: #include <sys/statfs.h>
        !            42: #endif
        !            43: #include <dirent.h>
        !            44: #include <utime.h>
        !            45: #include <errno.h>
        !            46: #endif
        !            47: 
        !            48: #include "config.h"
        !            49: #include "amiga.h"
        !            50: #include "options.h"
        !            51: #include "events.h"
        !            52: #include "memory.h"
        !            53: #include "custom.h"
        !            54: #include "newcpu.h"
        !            55: #include "xwin.h"
        !            56: #include "autoconf.h"
        !            57: #include "filesys.h"
        !            58: 
        !            59: #define MAKE_CASE_INSENSITIVE
        !            60: 
        !            61: typedef struct {
        !            62:     char *devname; /* device name, e.g. UAE0: */
        !            63:     char *volname; /* volume name, e.g. CDROM, WORK, etc. */
        !            64:     char *rootdir; /* root unix directory */
        !            65:     bool readonly; /* disallow write access? */
        !            66: } UnitInfo;
        !            67: 
        !            68: #define MAX_UNITS 20
        !            69: static int num_units = 0;
        !            70: static UnitInfo ui[MAX_UNITS];
        !            71: 
        !            72: static ULONG devnameaddr[100];
        !            73: 
        !            74: static ULONG doslibname, fsdevname, filesysseglist;
        !            75: 
        !            76: /* strdup missing? */
        !            77: static char*
        !            78: my_strdup(const char*s)
        !            79: {
        !            80:     char*x = (char*)malloc(strlen(s) + 1);
        !            81:     strcpy(x, s);
        !            82:     return x;
        !            83: }
        !            84: 
        !            85: 
        !            86: void
        !            87: add_filesys_unit(char *volname, char *rootdir, bool readonly)
        !            88: {
        !            89:     UnitInfo* u;
        !            90:     static char buf[80];
        !            91: 
        !            92:     if (num_units >= MAX_UNITS) {
        !            93:        fprintf(stderr, "Maximum number of unix file systems mounted.\n");
        !            94:        return;
        !            95:     }
        !            96: 
        !            97:     u = &ui[num_units];
        !            98:     sprintf(buf, "UAE%d", num_units);
        !            99:     u->devname = my_strdup(buf);
        !           100:     u->volname = my_strdup(volname);
        !           101:     u->rootdir = my_strdup(rootdir);
        !           102:     u->readonly = readonly;
        !           103: 
        !           104:     num_units++;
        !           105: }
        !           106: 
        !           107: #ifdef TRACING_ENABLED
        !           108: #define TRACE(x)       printf x;
        !           109: #define DUMPLOCK(x)    dumplock(x)
        !           110: #else
        !           111: #define TRACE(x)
        !           112: #define DUMPLOCK(x)
        !           113: #endif
        !           114: 
        !           115: /* minimal AmigaDOS definitions */
        !           116: 
        !           117: /* field offsets in DosPacket */
        !           118: #define dp_Type (8)
        !           119: #define dp_Res1        (12)
        !           120: #define dp_Res2 (16)
        !           121: #define dp_Arg1 (20)
        !           122: #define dp_Arg2 (24)
        !           123: #define dp_Arg3 (28)
        !           124: #define dp_Arg4 (32)
        !           125: 
        !           126: /* result codes */
        !           127: #define DOS_TRUE (-1L)
        !           128: #define DOS_FALSE (0L)
        !           129: 
        !           130: /* packet types */
        !           131: #define ACTION_CURRENT_VOLUME  7
        !           132: #define ACTION_LOCATE_OBJECT   8
        !           133: #define ACTION_RENAME_DISK     9
        !           134: #define ACTION_FREE_LOCK       15
        !           135: #define ACTION_DELETE_OBJECT   16
        !           136: #define ACTION_RENAME_OBJECT   17
        !           137: #define ACTION_COPY_DIR                19
        !           138: #define ACTION_SET_PROTECT     21
        !           139: #define ACTION_CREATE_DIR      22
        !           140: #define ACTION_EXAMINE_OBJECT  23
        !           141: #define ACTION_EXAMINE_NEXT    24
        !           142: #define ACTION_DISK_INFO       25
        !           143: #define ACTION_INFO            26
        !           144: #define ACTION_FLUSH           27
        !           145: #define ACTION_SET_COMMENT     28
        !           146: #define ACTION_PARENT          29
        !           147: #define ACTION_SET_DATE                34
        !           148: #define ACTION_SAME_LOCK       40
        !           149: #define ACTION_FIND_WRITE      1004
        !           150: #define ACTION_FIND_INPUT      1005
        !           151: #define ACTION_FIND_OUTPUT     1006
        !           152: #define ACTION_END             1007
        !           153: #define ACTION_SEEK            1008
        !           154: #define ACTION_IS_FILESYSTEM   1027
        !           155: #define ACTION_READ            'R'
        !           156: #define ACTION_WRITE           'W'
        !           157: 
        !           158: #define DISK_TYPE              (0x444f5301) /* DOS\1 */
        !           159: 
        !           160: /* errors */
        !           161: #define ERROR_NO_FREE_STORE     103
        !           162: #define ERROR_OBJECT_IN_USE    202
        !           163: #define ERROR_OBJECT_EXISTS     203
        !           164: #define ERROR_DIR_NOT_FOUND     204
        !           165: #define ERROR_OBJECT_NOT_FOUND  205
        !           166: #define ERROR_ACTION_NOT_KNOWN  209
        !           167: #define ERROR_OBJECT_WRONG_TYPE 212
        !           168: #define ERROR_DISK_WRITE_PROTECTED 214
        !           169: #define ERROR_DIRECTORY_NOT_EMPTY 216
        !           170: #define ERROR_DEVICE_NOT_MOUNTED 218
        !           171: #define ERROR_SEEK_ERROR       219
        !           172: #define ERROR_DISK_FULL                221
        !           173: #define ERROR_WRITE_PROTECTED 223
        !           174: #define ERROR_NO_MORE_ENTRIES  232
        !           175: #define ERROR_NOT_IMPLEMENTED  236
        !           176: 
        !           177: static long dos_errno(void)
        !           178: {
        !           179:     int e = errno;
        !           180: 
        !           181:     switch(e) {
        !           182:      case ENOMEM:      return ERROR_NO_FREE_STORE;
        !           183:      case EEXIST:      return ERROR_OBJECT_EXISTS;
        !           184:      case EISDIR:      return ERROR_OBJECT_WRONG_TYPE;
        !           185:      case ETXTBSY:     return ERROR_OBJECT_IN_USE;
        !           186:      case EACCES:      return ERROR_WRITE_PROTECTED;
        !           187:      case ENOENT:      return ERROR_OBJECT_NOT_FOUND;
        !           188:      case ENOTDIR:     return ERROR_OBJECT_WRONG_TYPE;
        !           189:      case EROFS:               return ERROR_DISK_WRITE_PROTECTED;
        !           190:      case ENOSPC:      return ERROR_DISK_FULL;
        !           191:      case EBUSY:               return ERROR_OBJECT_IN_USE;
        !           192:      case ENOTEMPTY:   return ERROR_DIRECTORY_NOT_EMPTY;
        !           193:        
        !           194:      default:
        !           195:        TRACE(("Unimplemented error %s\n", strerror(e)));
        !           196:        return ERROR_NOT_IMPLEMENTED;
        !           197:     }
        !           198: }
        !           199: 
        !           200: /* handler state info */
        !           201: 
        !           202: typedef struct _unit {
        !           203:     struct _unit *next;
        !           204: 
        !           205:     /* Amiga stuff */
        !           206:     CPTR       dosbase;
        !           207:     CPTR       volume;
        !           208:     CPTR       port;   /* Our port */
        !           209: 
        !           210:     /* Native stuff */
        !           211:     long       unit;   /* unit number */
        !           212:     UnitInfo   ui;     /* unit startup info */
        !           213: } Unit;
        !           214: 
        !           215: typedef struct {
        !           216:     CPTR addr; /* addr of real packet */
        !           217:     long type;
        !           218:     long res1;
        !           219:     long res2;
        !           220:     long arg1;
        !           221:     long arg2;
        !           222:     long arg3;
        !           223:     long arg4;
        !           224: } DosPacket;
        !           225: 
        !           226: static char *
        !           227: bstr(CPTR addr)
        !           228: {
        !           229:     static char buf[256];
        !           230:     int n = get_byte(addr++);
        !           231:     int i;
        !           232:     for(i = 0; i < n; i++)
        !           233:        buf[i] = get_byte(addr++);
        !           234:     buf[i] = 0;
        !           235:     return buf;
        !           236: }
        !           237: 
        !           238: static Unit *units = NULL;
        !           239: static int unit_num = 0;
        !           240: 
        !           241: static Unit*
        !           242: find_unit(CPTR port)
        !           243: {
        !           244:     Unit* u;
        !           245:     for(u = units; u; u = u->next)
        !           246:        if(u->port == port)
        !           247:            break;
        !           248: 
        !           249:     return u;
        !           250: }
        !           251: 
        !           252: static CPTR DosAllocMem(ULONG len)
        !           253: {
        !           254:     ULONG i;
        !           255:     CPTR addr;
        !           256: 
        !           257:     regs.d[0] = len + 4;
        !           258:     regs.d[1] = 1; /* MEMF_PUBLIC */
        !           259:     addr = CallLib(regs.a[6], -198); /* AllocMem */
        !           260: 
        !           261:     if(addr) {
        !           262:        put_long(addr, len);
        !           263:        addr += 4;
        !           264: 
        !           265:        /* faster to clear memory here rather than use MEMF_CLEAR */
        !           266:        for(i = 0; i < len; i += 4) 
        !           267:            put_long(addr + i, 0);
        !           268:     }
        !           269: 
        !           270:     return addr;
        !           271: }
        !           272: 
        !           273: static void DosFreeMem(CPTR addr)
        !           274: {
        !           275:     addr -= 4;
        !           276:     regs.d[0] = get_long(addr) + 4;
        !           277:     regs.a[1] = addr;
        !           278:     CallLib(regs.a[6], -210); /* FreeMem */
        !           279: }
        !           280: 
        !           281: static void
        !           282: startup(DosPacket* packet)
        !           283: {
        !           284:     int i, namelen;
        !           285:     char* devname = bstr(packet->arg1 << 2);
        !           286:     char* s;
        !           287:     Unit* unit;
        !           288: 
        !           289:     /* find UnitInfo with correct device name */
        !           290:     s = strchr(devname, ':');
        !           291:     if(s) *s = '\0';
        !           292: #if 0 /* Kick 1.3 send us a bogus string. */
        !           293:     for(i = 0; i < num_units; i++) {
        !           294:        if(0 == strcmp(ui[i].devname, devname))
        !           295:            break;
        !           296:     }
        !           297: #endif
        !           298:     
        !           299:     i = 0;
        !           300:     
        !           301:     if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) {
        !           302:        fprintf(stderr, "Failed attempt to mount device %s\n", devname);
        !           303:        packet->res1 = DOS_FALSE;
        !           304:        packet->res2 = ERROR_DEVICE_NOT_MOUNTED;
        !           305:        return;
        !           306:     }
        !           307: 
        !           308:     unit = (Unit *) malloc(sizeof(Unit));
        !           309:     unit->next = units;
        !           310:     units = unit;
        !           311: 
        !           312:     unit->volume = 0;
        !           313:     unit->port = regs.a[5];
        !           314:     unit->unit = unit_num++;
        !           315: 
        !           316:     unit->ui.devname = ui[i].devname;
        !           317:     unit->ui.volname = my_strdup(ui[i].volname); /* might free later for rename */
        !           318:     unit->ui.rootdir = ui[i].rootdir;
        !           319:     unit->ui.readonly = ui[i].readonly;
        !           320: 
        !           321:     TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
        !           322: 
        !           323:     /* fill in our process in the device node */
        !           324:     put_long((packet->arg3 << 2) + 8, unit->port);
        !           325: 
        !           326:     /* open dos.library */
        !           327:     regs.d[0] = 0;
        !           328:     regs.a[1] = doslibname;
        !           329:     unit->dosbase = CallLib(regs.a[6], -552); /* OpenLibrary */
        !           330: 
        !           331:     {
        !           332:            CPTR rootnode = get_long(unit->dosbase + 34);
        !           333:            CPTR dos_info = get_long(rootnode + 24) << 2;
        !           334:            /* make new volume */
        !           335:            unit->volume = DosAllocMem(80 + 1 + 44);
        !           336:            put_long(unit->volume + 4, 2); /* Type = dt_volume */
        !           337:            put_long(unit->volume + 12, 0); /* Lock */
        !           338:            put_long(unit->volume + 16, 3800); /* Creation Date */
        !           339:            put_long(unit->volume + 20, 0);
        !           340:            put_long(unit->volume + 24, 0);
        !           341:            put_long(unit->volume + 28, 0); /* lock list */
        !           342:            put_long(unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
        !           343:            namelen = strlen(unit->ui.volname);
        !           344:            put_byte(unit->volume + 44, namelen);
        !           345:            for(i = 0; i < namelen; i++)
        !           346:                put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
        !           347:                
        !           348:            /* link into DOS list */
        !           349:            put_long(unit->volume, get_long(dos_info + 4));
        !           350:            put_long(dos_info + 4, unit->volume >> 2);
        !           351:        }
        !           352: 
        !           353:     put_long(unit->volume + 8, unit->port);
        !           354:     put_long(unit->volume + 32, DISK_TYPE);
        !           355: 
        !           356:     packet->res1 = DOS_TRUE;
        !           357: }
        !           358: 
        !           359: static void
        !           360: do_info(Unit* unit, DosPacket* packet, CPTR info)
        !           361: {
        !           362:     struct statfs statbuf;
        !           363: #ifdef __linux
        !           364:     if(-1 == statfs(unit->ui.rootdir, &statbuf))
        !           365: #else
        !           366:     if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0))
        !           367: #endif
        !           368:     {
        !           369:        packet->res1 = DOS_FALSE;
        !           370:        packet->res2 = dos_errno();
        !           371:     }
        !           372: 
        !           373:     put_long(info, 0); /* errors */
        !           374:     put_long(info + 4, unit->unit); /* unit number */
        !           375:     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
        !           376:     put_long(info + 12, statbuf.f_blocks); /* numblocks */
        !           377: #ifdef __linux
        !           378:     put_long(info + 16, statbuf.f_blocks - statbuf.f_bavail); /* inuse */
        !           379: #else
        !           380:     put_long(info + 16, statbuf.f_blocks - statbuf.f_bfree); /* inuse */
        !           381: #endif
        !           382:     put_long(info + 20, statbuf.f_bsize); /* bytesperblock */
        !           383:     put_long(info + 24, DISK_TYPE); /* disk type */
        !           384:     put_long(info + 28, unit->volume >> 2); /* volume node */
        !           385:     put_long(info + 32, 0); /* inuse */
        !           386:     packet->res1 = DOS_TRUE;
        !           387: }
        !           388: 
        !           389: static void
        !           390: action_disk_info(Unit* unit, DosPacket* packet)
        !           391: {
        !           392:     TRACE(("ACTION_DISK_INFO\n"));
        !           393:     do_info(unit, packet, packet->arg1 << 2);
        !           394: }
        !           395: 
        !           396: static void
        !           397: action_info(Unit* unit, DosPacket* packet)
        !           398: {
        !           399:     TRACE(("ACTION_INFO\n"));
        !           400:     do_info(unit, packet, packet->arg2 << 2);
        !           401: }
        !           402: 
        !           403: typedef struct {
        !           404:     char *path;
        !           405:     int fd;
        !           406: } Key;
        !           407: 
        !           408: static void
        !           409: free_key(Key*k)
        !           410: {
        !           411:     free(k->path);
        !           412:     free(k);
        !           413: }
        !           414: 
        !           415: static void
        !           416: dumplock(CPTR lock)
        !           417: {
        !           418:     if(!lock) {
        !           419:        fprintf(stderr, "LOCK: 0x0\n");
        !           420:        return;
        !           421:     }
        !           422:     fprintf(stderr,
        !           423:            "LOCK: 0x%lx { next=0x%lx, key=%s, mode=%ld, handler=0x%lx, volume=0x%lx }\n",
        !           424:            lock,
        !           425:            get_long(lock)<<2, ((Key*)get_long(lock+4))->path, get_long(lock+8),
        !           426:            get_long(lock+12), get_long(lock+16));
        !           427: }
        !           428: 
        !           429: static char*
        !           430: get_path(Unit* unit, const char *base, const char *rel)
        !           431: {
        !           432:     static char buf[1024];
        !           433:     char *s = buf;
        !           434:     char *p;
        !           435:     char *r;
        !           436: 
        !           437:     int i;
        !           438: 
        !           439:     TRACE(("get_path(%s,%s)\n", base, rel));
        !           440: 
        !           441:     /* root-relative path? */
        !           442:     for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++);
        !           443:     if(':' == rel[i]) {
        !           444:        base = unit->ui.rootdir; rel += i+1;
        !           445:     }
        !           446: 
        !           447:     while(*base) {
        !           448:        *s++ = *base++;
        !           449:     }
        !           450:     p = s; /* start of relative path */
        !           451:     r = buf + strlen(unit->ui.rootdir); /* end of fixed path */
        !           452:        
        !           453:     while(*rel) {
        !           454:        /* start with a slash? go up a level. */
        !           455:        if('/' == *rel) {
        !           456:            while(s > r && '/' != *s)
        !           457:                s--;
        !           458:            rel++;
        !           459:        } else {
        !           460:            *s++ = '/';
        !           461:            while(*rel && '/' != *rel) {
        !           462:                *s++ = *rel++;
        !           463:            }
        !           464:            if('/' == *rel)
        !           465:                rel++;
        !           466:        }
        !           467:     }
        !           468:        *s = 0;
        !           469: 
        !           470: #ifdef MAKE_CASE_INSENSITIVE
        !           471:     TRACE(("path=\"%s\"\n", buf));
        !           472:     /* go through each section of the path and if it does not exist,
        !           473:      * scan its directory for any case insensitive matches
        !           474:      */
        !           475:     while(*p) {
        !           476:        char *p2 = strchr(p+1, '/');
        !           477:        char oldp2;
        !           478:        if(!p2) {
        !           479:            p2 = p+1;
        !           480:            while(*p2) p2++;
        !           481:        }
        !           482:        oldp2 = *p2;
        !           483:        *p2 = '\0';
        !           484:        if(0 != access(buf, F_OK|R_OK)) {
        !           485:            DIR* dir;
        !           486:            struct dirent* de;
        !           487: 
        !           488:            /* does not exist -- check dir for case insensitive match */
        !           489:            *p++ = '\0'; /* was '/' */
        !           490:            dir = opendir(buf);
        !           491:            if (dir) {
        !           492:                while((de = readdir(dir))) {
        !           493:                    if(0 == strcasecmp(de->d_name, p))
        !           494:                        break;
        !           495:                }
        !           496:                if(de) {
        !           497:                    strcpy(p, de->d_name);
        !           498:                }
        !           499:                closedir(dir);
        !           500:            }
        !           501:            *--p = '/';
        !           502:        }
        !           503:        *p2 = oldp2;
        !           504:        p = p2;
        !           505:     }
        !           506: #endif
        !           507:     TRACE(("path=\"%s\"\n", buf));
        !           508: 
        !           509:     return my_strdup(buf);
        !           510: }
        !           511: 
        !           512: static Key*
        !           513: make_key(Unit* unit, CPTR lock, const char *name)
        !           514: {
        !           515:     Key *k = (Key*)malloc(sizeof(Key));
        !           516: 
        !           517:     k->fd = 0;
        !           518: 
        !           519:     if(!lock) {
        !           520:        k->path = get_path(unit, unit->ui.rootdir, name);
        !           521:     } else {
        !           522:        Key*oldk = (Key*)get_long(lock + 4);
        !           523:        TRACE(("key: 0x%08lx", (ULONG)oldk));
        !           524:        TRACE((" \"%s\"\n", oldk->path));
        !           525:        k->path = get_path(unit, oldk->path, name);
        !           526:     }
        !           527: 
        !           528:     TRACE(("key=\"%s\"\n", k->path));
        !           529:     return k;
        !           530: }
        !           531: 
        !           532: static Key*
        !           533: dup_key(Key*k)
        !           534: {
        !           535:     Key *newk = (Key*)malloc(sizeof(Key));
        !           536:     newk->path = my_strdup(k->path);
        !           537:     newk->fd = 0;
        !           538:     return newk;
        !           539: }
        !           540: 
        !           541: static CPTR
        !           542: make_lock(Unit* unit, Key *key, long mode)
        !           543: {
        !           544:     /* allocate lock */
        !           545:     CPTR lock = DosAllocMem(20);
        !           546: 
        !           547:     put_long(lock + 4, (ULONG) key);
        !           548:     put_long(lock + 8, mode);
        !           549:     put_long(lock + 12, unit->port);
        !           550:     put_long(lock + 16, unit->volume >> 2);
        !           551: 
        !           552:     /* prepend to lock chain */
        !           553:     put_long(lock, get_long(unit->volume + 28));
        !           554:     put_long(unit->volume + 28, lock >> 2);
        !           555: 
        !           556:     DUMPLOCK(lock);
        !           557:     return lock;
        !           558: }
        !           559: 
        !           560: static void
        !           561: free_lock(Unit* unit, CPTR lock)
        !           562: {
        !           563:     if(!lock)
        !           564:        return;
        !           565: 
        !           566:     if(lock == get_long(unit->volume + 28) << 2) {
        !           567:        put_long(unit->volume + 28, get_long(lock));
        !           568:     } else {
        !           569:        CPTR current = get_long(unit->volume + 28);
        !           570:        CPTR next = 0;
        !           571:        while(current) {
        !           572:            next = get_long(current << 2);
        !           573:            if(lock == next << 2)
        !           574:                break;
        !           575:            current = next;
        !           576:        }
        !           577:        put_long(current << 2, get_long(lock));
        !           578:     }
        !           579:     free_key((Key*)get_long(lock + 4));
        !           580:     DosFreeMem(lock);
        !           581: }
        !           582: 
        !           583: static void
        !           584: action_lock(Unit* unit, DosPacket* packet)
        !           585: {
        !           586:     CPTR lock = packet->arg1 << 2;
        !           587:     CPTR name = packet->arg2 << 2;
        !           588:     long mode = packet->arg3;
        !           589:     int access_mode = (mode == -2) ? R_OK : R_OK|W_OK;
        !           590:     Key *k;
        !           591: 
        !           592:     TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n",lock, bstr(name), mode));
        !           593:     DUMPLOCK(lock);
        !           594: 
        !           595:     k = make_key(unit, lock, bstr(name));
        !           596: 
        !           597:     if(k && 0 == access(k->path, access_mode)) {
        !           598:        packet->res1 = make_lock(unit, k, mode) >> 2;
        !           599:     } else {
        !           600:        if(k)
        !           601:            free_key(k);
        !           602:        packet->res1 = 0;
        !           603:        packet->res2 = ERROR_OBJECT_NOT_FOUND;
        !           604:     }
        !           605: }
        !           606: 
        !           607: static void
        !           608: action_free_lock(Unit* unit, DosPacket* packet)
        !           609: {
        !           610:     CPTR lock = packet->arg1 << 2;
        !           611:     TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
        !           612:     DUMPLOCK(lock);
        !           613:     
        !           614:     free_lock(unit, lock);
        !           615:     
        !           616:     packet->res1 = DOS_TRUE;
        !           617: }
        !           618: 
        !           619: static void
        !           620: action_dup_lock(Unit* unit, DosPacket* packet)
        !           621: {
        !           622:     CPTR lock = packet->arg1 << 2;
        !           623: 
        !           624:     TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
        !           625:     DUMPLOCK(lock);
        !           626: 
        !           627:     if(!lock) {
        !           628:        packet->res1 = 0;
        !           629:        return;
        !           630:     }
        !           631: 
        !           632:     {
        !           633:        CPTR oldkey = get_long(lock + 4);
        !           634:        CPTR oldmode = get_long(lock + 8);
        !           635:        packet->res1 = make_lock(unit, dup_key((Key*)oldkey), oldmode) >> 2;
        !           636:     }
        !           637: }
        !           638: 
        !           639: /* convert time_t to/from AmigaDOS time */
        !           640: const int secs_per_day = 24 * 60 * 60;
        !           641: const int diff = (8 * 365 + 2) * (24 * 60 * 60);
        !           642: 
        !           643: static void
        !           644: get_time(time_t t, long* days, long* mins, long* ticks)
        !           645: {
        !           646:     /* time_t is secs since 1-1-1970 */
        !           647:     /* days since 1-1-1978 */
        !           648:     /* mins since midnight */
        !           649:     /* ticks past minute @ 50Hz */
        !           650: 
        !           651:     t -= diff;
        !           652:     *days = t / secs_per_day;
        !           653:     t -= *days * secs_per_day;
        !           654:     *mins = t / 60;
        !           655:     t -= *mins * 60;
        !           656:     *ticks = t * 50;
        !           657: }
        !           658: 
        !           659: static time_t
        !           660: put_time(long days, long mins, long ticks)
        !           661: {
        !           662:     time_t t;
        !           663:     t = ticks / 50;
        !           664:     t += mins * 60;
        !           665:     t += days * secs_per_day;
        !           666:     t += diff;
        !           667:     
        !           668:     return t;
        !           669: }
        !           670: 
        !           671: 
        !           672: typedef struct {
        !           673:     char *path;
        !           674:     DIR* dir;
        !           675: } ExamineKey;
        !           676: 
        !           677: /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
        !           678:  * some of these around
        !           679:  */
        !           680: 
        !           681: #define EXKEYS 100
        !           682: static ExamineKey examine_keys[EXKEYS];
        !           683: static int next_exkey = 0;
        !           684: 
        !           685: static void
        !           686: free_exkey(ExamineKey* ek)
        !           687: {
        !           688:     free(ek->path);
        !           689:     ek->path = 0;
        !           690:     if(ek->dir)
        !           691:        closedir(ek->dir);
        !           692: }
        !           693: 
        !           694: static ExamineKey*
        !           695: new_exkey(char *path)
        !           696: {
        !           697:     ExamineKey* ek= &examine_keys[next_exkey++];
        !           698:     if(next_exkey==EXKEYS)
        !           699:        next_exkey = 0;
        !           700:     if(ek->path) {
        !           701:        free_exkey(ek);
        !           702:     }
        !           703:     ek->path = my_strdup(path);
        !           704:     ek->dir = 0;
        !           705:     return ek;
        !           706: }
        !           707: 
        !           708: static void
        !           709: get_fileinfo(DosPacket* packet, CPTR info, char *buf)
        !           710: {
        !           711:     struct stat statbuf;
        !           712:     long days, mins, ticks;
        !           713: 
        !           714:     if(-1 == stat(buf, &statbuf)) {
        !           715:        packet->res1 = DOS_FALSE;
        !           716:        packet->res2 = dos_errno();
        !           717:     } else {
        !           718:        put_long(info + 4, S_ISDIR(statbuf.st_mode) ? 2 : -3);
        !           719:        {
        !           720:            /* file name */
        !           721:            int i = 8;
        !           722:            int n;
        !           723:            char *x = strrchr(buf,'/');
        !           724:            if(x)
        !           725:                x++;
        !           726:            else
        !           727:                x = buf;
        !           728:            TRACE(("name=\"%s\"\n", x));
        !           729:            n = strlen(x);
        !           730:            if(n > 106) n = 106;
        !           731:            put_byte(info + i++, n);
        !           732:            while(n--)
        !           733:                put_byte(info + i++, *x++);
        !           734:            while(i < 108)
        !           735:                put_byte(info + i++, 0);
        !           736:        }
        !           737:        put_long(info + 116,
        !           738:                 (S_IRUSR & statbuf.st_mode ? 0 : (1<<3)) |
        !           739:                 (S_IWUSR & statbuf.st_mode ? 0 : (1<<2)) |
        !           740:                 (S_IXUSR & statbuf.st_mode ? 0 : (1<<1)) |
        !           741:                 (S_IWUSR & statbuf.st_mode ? 0 : (1<<0)));
        !           742:        put_long(info + 120, S_ISDIR(statbuf.st_mode) ? 2 : -3);
        !           743:        put_long(info + 124, statbuf.st_size);
        !           744:        put_long(info + 128, statbuf.st_blocks);
        !           745:        get_time(statbuf.st_mtime, &days, &mins, &ticks);
        !           746:        put_long(info + 132, days);
        !           747:        put_long(info + 136, mins);
        !           748:        put_long(info + 140, ticks);
        !           749:        put_long(info + 144, 0); /* no comment */
        !           750:        packet->res1 = DOS_TRUE;
        !           751:     }
        !           752: }
        !           753: 
        !           754: static void
        !           755: do_examine(DosPacket* packet, ExamineKey* ek, CPTR info)
        !           756: {
        !           757:     static char buf[1024];
        !           758:     struct dirent* de;
        !           759: 
        !           760:     if(!ek->dir) {
        !           761:        ek->dir = opendir(ek->path);
        !           762:     }
        !           763:     if(!ek->dir) {
        !           764:        free_exkey(ek);
        !           765:        packet->res1 = DOS_FALSE;
        !           766:        packet->res2 = ERROR_NO_MORE_ENTRIES;
        !           767:        return;
        !           768:     }
        !           769:     
        !           770:     de = readdir(ek->dir);
        !           771:     
        !           772:     while(de &&
        !           773:          (0 == strcmp(".", de->d_name) ||
        !           774:           0 == strcmp("..", de->d_name))) 
        !           775:     {
        !           776:        de = readdir(ek->dir);
        !           777:     }
        !           778: 
        !           779:     if(!de) {
        !           780:        TRACE(("no more entries\n"));
        !           781:        free_exkey(ek);
        !           782:        packet->res1 = DOS_FALSE;
        !           783:        packet->res2 = ERROR_NO_MORE_ENTRIES;
        !           784:        return;
        !           785:     }
        !           786: 
        !           787:     TRACE(("entry=\"%s\"\n", de->d_name));
        !           788: 
        !           789:     sprintf(buf, "%s/%s", ek->path, de->d_name);
        !           790: 
        !           791:     get_fileinfo(packet, info, buf);
        !           792: }
        !           793: 
        !           794: static void
        !           795: action_examine_object(Unit* unit, DosPacket* packet)
        !           796: {
        !           797:     CPTR lock = packet->arg1 << 2;
        !           798:     CPTR info = packet->arg2 << 2;
        !           799:     char *path;
        !           800:     ExamineKey* ek;
        !           801:     
        !           802:     TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
        !           803:     DUMPLOCK(lock);
        !           804: 
        !           805:     if(!lock) {
        !           806:        path = unit->ui.rootdir;
        !           807:     } else {
        !           808:        Key*k = (Key *)get_long(lock + 4);
        !           809:        path = k->path;
        !           810:     }
        !           811:     
        !           812:     get_fileinfo(packet, info, path);
        !           813:     ek = new_exkey(path);
        !           814:     put_long(info, (ULONG)ek);
        !           815: }
        !           816: 
        !           817: static void
        !           818: action_examine_next(Unit* unit, DosPacket* packet)
        !           819: {
        !           820:     CPTR lock = packet->arg1 << 2;
        !           821:     CPTR info = packet->arg2 << 2;
        !           822: 
        !           823:     TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
        !           824:     DUMPLOCK(lock);
        !           825: 
        !           826:     do_examine(packet, (ExamineKey*)get_long(info), info);
        !           827: }
        !           828: 
        !           829: static void
        !           830: do_find(Unit* unit, DosPacket* packet, mode_t mode)
        !           831: {
        !           832:     CPTR fh = packet->arg1 << 2;
        !           833:     CPTR lock = packet->arg2 << 2;
        !           834:     CPTR name = packet->arg3 << 2;
        !           835:     Key *k;
        !           836:     struct stat st;
        !           837:     
        !           838:     TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n",fh,lock,bstr(name),mode));
        !           839:     DUMPLOCK(lock);
        !           840: 
        !           841:     k = make_key(unit, lock, bstr(name));
        !           842:     if(!k) {
        !           843:        packet->res1 = DOS_FALSE;
        !           844:        packet->res2 = ERROR_NO_FREE_STORE;
        !           845:        return;
        !           846:     }
        !           847: 
        !           848:     /* Fixme: may not quite be right */
        !           849:     if (0 == stat (k->path, &st)) {
        !           850:        if (S_ISDIR (st.st_mode)) {
        !           851:            packet->res1 = DOS_FALSE;
        !           852:            packet->res2 = ERROR_OBJECT_WRONG_TYPE;
        !           853:            return;
        !           854:        }
        !           855:     }
        !           856: 
        !           857:     k->fd = open(k->path, mode, 0777);
        !           858: 
        !           859:     if(k->fd < 0) {
        !           860:        packet->res1 = DOS_FALSE;
        !           861:        packet->res2 = dos_errno();
        !           862:        free_key(k);
        !           863:        return;
        !           864:     }
        !           865:     success:
        !           866:     put_long(fh+36, (ULONG)k);
        !           867: 
        !           868:     packet->res1 = DOS_TRUE;
        !           869: }
        !           870: 
        !           871: static void
        !           872: action_find_input(Unit* unit, DosPacket* packet)
        !           873: {
        !           874:     do_find(unit, packet, O_RDONLY);
        !           875: }
        !           876: 
        !           877: static void
        !           878: action_find_output(Unit* unit, DosPacket* packet)
        !           879: {
        !           880:     if(unit->ui.readonly) {
        !           881:        packet->res1 = DOS_FALSE;
        !           882:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !           883:        return;
        !           884:     }
        !           885:     do_find(unit, packet, O_WRONLY|O_CREAT|O_TRUNC);
        !           886: }
        !           887: 
        !           888: static void
        !           889: action_find_write(Unit* unit, DosPacket* packet)
        !           890: {
        !           891:     if(unit->ui.readonly) {
        !           892:        packet->res1 = DOS_FALSE;
        !           893:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !           894:        return;
        !           895:     }
        !           896:     do_find(unit, packet, O_RDWR);
        !           897: }
        !           898: 
        !           899: static void
        !           900: action_end(Unit* unit, DosPacket* packet)
        !           901: {
        !           902:     Key*k;
        !           903:     TRACE(("ACTION_END(0x%lx)\n", packet->arg1));
        !           904: 
        !           905:     k = (Key*)(packet->arg1);
        !           906:     close(k->fd);
        !           907:     free_key(k);
        !           908:     packet->res1 = DOS_TRUE;
        !           909: }
        !           910: 
        !           911: static void
        !           912: action_read(Unit* unit, DosPacket* packet)
        !           913: {
        !           914:     Key*k = (Key*)(packet->arg1);
        !           915:     CPTR addr = packet->arg2;
        !           916:     long size = packet->arg3;
        !           917:     int actual;
        !           918:     char *buf;
        !           919:     
        !           920:     TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->path,addr,size));
        !           921:     
        !           922:     /* ugh this is inefficient but easy */
        !           923:     buf = (char *)malloc(size);
        !           924:     if(!buf) {
        !           925:        packet->res1 = -1;
        !           926:        packet->res2 = ERROR_NO_FREE_STORE;
        !           927:        return;
        !           928:     }
        !           929:     
        !           930:     actual = read(k->fd, buf, size);
        !           931: 
        !           932:     packet->res1 = actual;
        !           933: 
        !           934:     if(actual > 0) {
        !           935:        int i;
        !           936:        unsigned char *bp = (unsigned char *)buf;
        !           937:        UWORD *realpt;
        !           938:        if (addr & 1) { /* Eeek! */
        !           939:            actual--;
        !           940:            put_byte(addr, *bp++);
        !           941:            addr++;
        !           942:        }
        !           943:        if (valid_address (addr, actual)) {
        !           944:            realpt = get_real_address (addr);
        !           945:            for (i = 0; i < (actual & ~1); i+=2) {
        !           946:                UWORD data = ((UWORD)(*bp++) << 8);
        !           947:                data |= *bp++;
        !           948:                *realpt++ = data;
        !           949:            }
        !           950:            if (actual & 1)
        !           951:                put_byte (addr + actual - 1, *bp);
        !           952:        } else {
        !           953:           /* fprintf (stderr, "unixfs warning: Bad pointer passed for read\n");*/
        !           954:            for(i = 0; i < actual; i++) 
        !           955:                put_byte(addr + i, buf[i]);
        !           956:        }
        !           957:     } else {
        !           958:        packet->res2 = dos_errno();
        !           959:     }
        !           960:     free(buf);
        !           961: }
        !           962: 
        !           963: static void
        !           964: action_write(Unit* unit, DosPacket* packet)
        !           965: {
        !           966:     Key*k = (Key*)(packet->arg1);
        !           967:     CPTR addr = packet->arg2;
        !           968:     long size = packet->arg3;
        !           969:     char *buf;
        !           970:     int i;
        !           971: 
        !           972:     TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->path,addr,size));
        !           973: 
        !           974:     if(unit->ui.readonly) {
        !           975:        packet->res1 = DOS_FALSE;
        !           976:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !           977:        return;
        !           978:     }
        !           979: 
        !           980:     /* ugh this is inefficient but easy */
        !           981:     buf = (char *)malloc(size);
        !           982:     if(!buf) {
        !           983:        packet->res1 = -1;
        !           984:        packet->res2 = ERROR_NO_FREE_STORE;
        !           985:        return;
        !           986:     }
        !           987:     
        !           988:     for(i = 0; i < size; i++)
        !           989:        buf[i] = get_byte(addr + i);
        !           990: 
        !           991:     packet->res1 = write(k->fd, buf, size);
        !           992:     if(packet->res1 != size)
        !           993:        packet->res2 = dos_errno();
        !           994: 
        !           995:     free(buf);
        !           996: }
        !           997: 
        !           998: static void
        !           999: action_seek(Unit* unit, DosPacket* packet)
        !          1000: {
        !          1001:     Key* k = (Key*) (packet->arg1);
        !          1002:     long pos = packet->arg2;
        !          1003:     long mode = packet->arg3;
        !          1004:     off_t res;
        !          1005:     long old;
        !          1006:     int whence = SEEK_CUR;
        !          1007:     if(mode > 0) whence = SEEK_END;
        !          1008:     if(mode < 0) whence = SEEK_SET;
        !          1009: 
        !          1010:     TRACE(("ACTION_SEEK(%s,%d,%d)\n",k->path,pos,mode));
        !          1011: 
        !          1012:     old = lseek(k->fd, 0, SEEK_CUR);
        !          1013:     res = lseek(k->fd, pos, whence);
        !          1014: 
        !          1015:     if(-1 == res)
        !          1016:        packet->res1 = res;
        !          1017:     else
        !          1018:        packet->res1 = old;
        !          1019: }
        !          1020: 
        !          1021: static void
        !          1022: action_set_protect(Unit* unit, DosPacket* packet)
        !          1023: {
        !          1024:     CPTR lock = packet->arg2 << 2;
        !          1025:     CPTR name = packet->arg3 << 2;
        !          1026:     ULONG mask = packet->arg4;
        !          1027:     struct stat statbuf;
        !          1028:     mode_t mode;
        !          1029:     Key *k;
        !          1030: 
        !          1031:     TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n",lock,bstr(name),mask));
        !          1032: 
        !          1033:     if(unit->ui.readonly) {
        !          1034:        packet->res1 = DOS_FALSE;
        !          1035:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !          1036:        return;
        !          1037:     }
        !          1038: 
        !          1039:     k = make_key(unit, lock, bstr(name));
        !          1040:     if(!k) {
        !          1041:        packet->res1 = DOS_FALSE;
        !          1042:        packet->res2 = ERROR_NO_FREE_STORE;
        !          1043:        return;
        !          1044:     }
        !          1045:                
        !          1046:     if(-1 == stat(k->path, &statbuf)) {
        !          1047:        free_key(k);
        !          1048:        packet->res1 = DOS_FALSE;
        !          1049:        packet->res2 = ERROR_OBJECT_NOT_FOUND;
        !          1050:        return;
        !          1051:     }
        !          1052: 
        !          1053:     mode = statbuf.st_mode;
        !          1054: 
        !          1055:     if(mask & (1 << 3))
        !          1056:        mode &= ~S_IRUSR;
        !          1057:     else
        !          1058:        mode |= S_IRUSR;
        !          1059:     
        !          1060:     if(mask & (1 << 2) || mask & (1 << 0))
        !          1061:        mode &= ~S_IWUSR;
        !          1062:     else
        !          1063:        mode |= S_IWUSR;
        !          1064: 
        !          1065:     if(mask & (1 << 1))
        !          1066:        mode &= ~S_IXUSR;
        !          1067:     else
        !          1068:        mode |= S_IXUSR;
        !          1069: 
        !          1070:     if(-1 == chmod(k->path, mode)) {
        !          1071:        packet->res1 = DOS_FALSE;
        !          1072:        packet->res2 = dos_errno();
        !          1073:     } else {
        !          1074:        packet->res1 = DOS_TRUE;
        !          1075:     }
        !          1076:     free_key(k);
        !          1077: }
        !          1078: 
        !          1079: static void
        !          1080: action_same_lock(Unit* unit, DosPacket* packet)
        !          1081: {
        !          1082:     CPTR lock1 = packet->arg1 << 2;
        !          1083:     CPTR lock2 = packet->arg2 << 2;
        !          1084: 
        !          1085:     TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
        !          1086:     DUMPLOCK(lock1); DUMPLOCK(lock2);
        !          1087: 
        !          1088:     if(!lock1 || !lock2) {
        !          1089:        packet->res1 = (lock1 == lock2) ? DOS_TRUE : DOS_FALSE;
        !          1090:     } else {
        !          1091:        Key* key1 = (Key*) get_long(lock1 + 4);
        !          1092:        Key* key2 = (Key*) get_long(lock2 + 4);
        !          1093:        packet->res1 = (0 == strcmp(key1->path, key2->path)) ? DOS_TRUE : DOS_FALSE;
        !          1094:     }
        !          1095: }
        !          1096: 
        !          1097: static void
        !          1098: action_parent(Unit* unit, DosPacket* packet)
        !          1099: {
        !          1100:     CPTR lock = packet->arg1 << 2;
        !          1101:     Key*k;
        !          1102: 
        !          1103:     TRACE(("ACTION_PARENT(0x%lx)\n",lock));
        !          1104:     
        !          1105:     if(!lock) {
        !          1106:        packet->res1 = 0;
        !          1107:        packet->res2 = 0;
        !          1108:        return;
        !          1109:     }
        !          1110: 
        !          1111:     k = dup_key((Key*) get_long(lock + 4));
        !          1112:     if(0 == strcmp(k->path, unit->ui.rootdir)) {
        !          1113:        free_key(k);
        !          1114:        packet->res1 = 0;
        !          1115:        packet->res2 = 0;
        !          1116:        return;
        !          1117:     }
        !          1118:     {
        !          1119:        char *x = strrchr(k->path,'/');
        !          1120:        if(!x) {
        !          1121:            free_key(k);
        !          1122:            packet->res1 = 0;
        !          1123:            packet->res2 = 0;
        !          1124:            return;
        !          1125:        } else {
        !          1126:            *x = '\0';
        !          1127:        }
        !          1128:     }
        !          1129:     packet->res1 = make_lock(unit, k, -2) >> 2;
        !          1130: }
        !          1131: 
        !          1132: static void
        !          1133: action_create_dir(Unit* unit, DosPacket* packet)
        !          1134: {
        !          1135:     CPTR lock = packet->arg1 << 2;
        !          1136:     CPTR name = packet->arg2 << 2;
        !          1137:     Key* k;
        !          1138: 
        !          1139:     TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n",lock,bstr(name)));
        !          1140: 
        !          1141:     if(unit->ui.readonly) {
        !          1142:        packet->res1 = DOS_FALSE;
        !          1143:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !          1144:        return;
        !          1145:     }
        !          1146: 
        !          1147:     k = make_key(unit, lock, bstr(name));
        !          1148: 
        !          1149:     if(!k) {
        !          1150:        packet->res1 = DOS_FALSE;
        !          1151:        packet->res2 = ERROR_NO_FREE_STORE;
        !          1152:        return;
        !          1153:     }
        !          1154:     if(-1 == mkdir(k->path, 0777)) {
        !          1155:        packet->res1 = DOS_FALSE;
        !          1156:        packet->res2 = dos_errno();
        !          1157:        free_key(k);
        !          1158:        return;
        !          1159:     }
        !          1160:     packet->res1 = make_lock(unit, k, -2) >> 2;
        !          1161: }
        !          1162: 
        !          1163: static void
        !          1164: action_delete_object(Unit* unit, DosPacket* packet)
        !          1165: {
        !          1166:     CPTR lock = packet->arg1 << 2;
        !          1167:     CPTR name = packet->arg2 << 2;
        !          1168:     Key* k;
        !          1169:     struct stat statbuf;
        !          1170: 
        !          1171:     TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n",lock,bstr(name)));
        !          1172: 
        !          1173:     if(unit->ui.readonly) {
        !          1174:        packet->res1 = DOS_FALSE;
        !          1175:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !          1176:        return;
        !          1177:     }
        !          1178: 
        !          1179:     k = make_key(unit, lock, bstr(name));
        !          1180: 
        !          1181:     if(!k) {
        !          1182:        packet->res1 = DOS_FALSE;
        !          1183:        packet->res2 = ERROR_NO_FREE_STORE;
        !          1184:        return;
        !          1185:     }
        !          1186:     if(-1 == stat(k->path, &statbuf)) {
        !          1187:        packet->res1 = DOS_FALSE;
        !          1188:        packet->res2 = dos_errno();
        !          1189:        free_key(k);
        !          1190:        return;
        !          1191:     }
        !          1192:     if(S_ISDIR(statbuf.st_mode)) {
        !          1193:        if(-1 == rmdir(k->path)) {
        !          1194:            packet->res1 = DOS_FALSE;
        !          1195:            packet->res2 = dos_errno();
        !          1196:            free_key(k);
        !          1197:            return;
        !          1198:        }
        !          1199:     } else {
        !          1200:        if(-1 == unlink(k->path)) {
        !          1201:            packet->res1 = DOS_FALSE;
        !          1202:            packet->res2 = dos_errno();
        !          1203:            free_key(k);
        !          1204:            return;
        !          1205:        }
        !          1206:     }
        !          1207:     free_key(k);
        !          1208:     packet->res1 = DOS_TRUE;
        !          1209: }
        !          1210: 
        !          1211: static void
        !          1212: action_set_date(Unit* unit, DosPacket* packet)
        !          1213: {
        !          1214:     CPTR lock = packet->arg2 << 2;
        !          1215:     CPTR name = packet->arg3 << 2;
        !          1216:     CPTR date = packet->arg4;
        !          1217:     Key* k;
        !          1218:     struct utimbuf ut;
        !          1219:     
        !          1220:     TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n",lock,bstr(name)));
        !          1221: 
        !          1222:     if(unit->ui.readonly) {
        !          1223:        packet->res1 = DOS_FALSE;
        !          1224:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !          1225:        return;
        !          1226:     }
        !          1227: 
        !          1228:     ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
        !          1229:     k = make_key(unit, lock, bstr(name));
        !          1230: 
        !          1231:     if(!k) {
        !          1232:        packet->res1 = DOS_FALSE;
        !          1233:        packet->res2 = ERROR_NO_FREE_STORE;
        !          1234:        return;
        !          1235:     }
        !          1236:     if(-1 == utime(k->path, &ut)) {
        !          1237:        packet->res1 = DOS_FALSE;
        !          1238:        packet->res2 = dos_errno();
        !          1239:        free_key(k);
        !          1240:        return;
        !          1241:     }
        !          1242:     free_key(k);
        !          1243:     packet->res1 = DOS_TRUE;
        !          1244: }
        !          1245: 
        !          1246: static void
        !          1247: action_rename_object(Unit* unit, DosPacket* packet)
        !          1248: {
        !          1249:     CPTR lock1 = packet->arg1 << 2;
        !          1250:     CPTR name1 = packet->arg2 << 2;
        !          1251:     Key* k1;
        !          1252:     CPTR lock2 = packet->arg3 << 2;
        !          1253:     CPTR name2 = packet->arg4 << 2;
        !          1254:     Key* k2;
        !          1255: 
        !          1256:     TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",",lock1,bstr(name1)));
        !          1257:     TRACE(("0x%lx,\"%s\")\n",lock2,bstr(name2)));
        !          1258: 
        !          1259:     if(unit->ui.readonly) {
        !          1260:        packet->res1 = DOS_FALSE;
        !          1261:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !          1262:        return;
        !          1263:     }
        !          1264: 
        !          1265:     k1 = make_key(unit, lock1, bstr(name1));
        !          1266:     if(!k1) {
        !          1267:        packet->res1 = DOS_FALSE;
        !          1268:        packet->res2 = ERROR_NO_FREE_STORE;
        !          1269:        return;
        !          1270:     }
        !          1271:     k2 = make_key(unit, lock2, bstr(name2));
        !          1272:     if(!k2) {
        !          1273:        free_key(k1);
        !          1274:        packet->res1 = DOS_FALSE;
        !          1275:        packet->res2 = ERROR_NO_FREE_STORE;
        !          1276:        return;
        !          1277:     }
        !          1278:     
        !          1279:     if(-1 == rename(k1->path, k2->path)) {
        !          1280:        packet->res1 = DOS_FALSE;
        !          1281:        packet->res2 = dos_errno();
        !          1282:        free_key(k1);
        !          1283:        free_key(k2);
        !          1284:        return;
        !          1285:     }
        !          1286:     free_key(k1);
        !          1287:     free_key(k2);
        !          1288:     packet->res1 = DOS_TRUE;
        !          1289: }
        !          1290: 
        !          1291: static void
        !          1292: action_current_volume(Unit* unit, DosPacket* packet)
        !          1293: {
        !          1294:     packet->res1 = unit->volume >> 2;
        !          1295: }
        !          1296: 
        !          1297: static void
        !          1298: action_rename_disk(Unit* unit, DosPacket* packet)
        !          1299: {
        !          1300:     CPTR name = packet->arg1 << 2;
        !          1301:     int i;
        !          1302:     int namelen;
        !          1303: 
        !          1304:     TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr(name)));
        !          1305: 
        !          1306:     if(unit->ui.readonly) {
        !          1307:        packet->res1 = DOS_FALSE;
        !          1308:        packet->res2 = ERROR_DISK_WRITE_PROTECTED;
        !          1309:        return;
        !          1310:     }
        !          1311: 
        !          1312:     /* get volume name */
        !          1313:     namelen = get_byte(name++);
        !          1314:     free(unit->ui.volname);
        !          1315:     unit->ui.volname = (char *) malloc(namelen + 1);
        !          1316:     for(i = 0; i < namelen; i++)
        !          1317:        unit->ui.volname[i] = get_byte(name++);
        !          1318:     unit->ui.volname[i] = 0;
        !          1319:     
        !          1320:     put_byte(unit->volume + 44, namelen);
        !          1321:     for(i = 0; i < namelen; i++)
        !          1322:        put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
        !          1323:     
        !          1324:     packet->res1 = DOS_TRUE;
        !          1325: }
        !          1326: 
        !          1327: static void
        !          1328: action_is_filesystem(Unit* unit, DosPacket* packet)
        !          1329: {
        !          1330:     packet->res1 = DOS_TRUE;
        !          1331: }
        !          1332: 
        !          1333: static void
        !          1334: action_flush(Unit* unit, DosPacket* packet)
        !          1335: {
        !          1336:     /* sync(); */ /* pretty drastic, eh */
        !          1337:     packet->res1 = DOS_TRUE;
        !          1338: }
        !          1339: 
        !          1340: static ULONG
        !          1341: filesys_handler(void)
        !          1342: {
        !          1343:     DosPacket packet;
        !          1344:     Unit *unit = find_unit(regs.a[5]);
        !          1345:        
        !          1346:     /* got DosPacket in A4 */
        !          1347:     packet.addr = regs.a[4];
        !          1348:     packet.type = get_long(packet.addr + dp_Type);
        !          1349:     packet.res1 = get_long(packet.addr + dp_Res1);
        !          1350:     packet.res2 = get_long(packet.addr + dp_Res2);
        !          1351:     packet.arg1 = get_long(packet.addr + dp_Arg1);
        !          1352:     packet.arg2 = get_long(packet.addr + dp_Arg2);
        !          1353:     packet.arg3 = get_long(packet.addr + dp_Arg3);
        !          1354:     packet.arg4 = get_long(packet.addr + dp_Arg4);
        !          1355: 
        !          1356:     if(!unit) {
        !          1357:        startup(&packet);
        !          1358:        put_long(packet.addr + dp_Res1, packet.res1);
        !          1359:        put_long(packet.addr + dp_Res2, packet.res2); 
        !          1360:        return 0;
        !          1361:     }
        !          1362: 
        !          1363:     if(!unit->volume) {
        !          1364:        printf("no volume\n");
        !          1365:        return 0;
        !          1366:     }
        !          1367: 
        !          1368:     switch(packet.type) {
        !          1369:      case ACTION_LOCATE_OBJECT:
        !          1370:        action_lock(unit, &packet);
        !          1371:        break;
        !          1372: 
        !          1373:      case ACTION_FREE_LOCK:
        !          1374:        action_free_lock(unit, &packet);
        !          1375:        break;
        !          1376: 
        !          1377:      case ACTION_COPY_DIR:
        !          1378:        action_dup_lock(unit, &packet);
        !          1379:        break;
        !          1380: 
        !          1381:      case ACTION_DISK_INFO:
        !          1382:        action_disk_info(unit, &packet);
        !          1383:        break;
        !          1384: 
        !          1385:      case ACTION_INFO:
        !          1386:        action_info(unit, &packet);
        !          1387:        break;
        !          1388: 
        !          1389:      case ACTION_EXAMINE_OBJECT:
        !          1390:        action_examine_object(unit, &packet);
        !          1391:        break;
        !          1392: 
        !          1393:      case ACTION_EXAMINE_NEXT:
        !          1394:        action_examine_next(unit, &packet);
        !          1395:        break;
        !          1396: 
        !          1397:      case ACTION_FIND_INPUT:
        !          1398:        action_find_input(unit, &packet);
        !          1399:        break;
        !          1400: 
        !          1401:      case ACTION_FIND_WRITE:
        !          1402:        action_find_write(unit, &packet);
        !          1403:        break;
        !          1404: 
        !          1405:      case ACTION_FIND_OUTPUT:
        !          1406:        action_find_output(unit, &packet);
        !          1407:        break;
        !          1408: 
        !          1409:      case ACTION_END:
        !          1410:        action_end(unit, &packet);
        !          1411:        break;
        !          1412: 
        !          1413:      case ACTION_READ:
        !          1414:        action_read(unit, &packet);
        !          1415:        break;
        !          1416: 
        !          1417:      case ACTION_WRITE:
        !          1418:        action_write(unit, &packet);
        !          1419:        break;
        !          1420:        
        !          1421:      case ACTION_SEEK:
        !          1422:        action_seek(unit, &packet);
        !          1423:        break;
        !          1424:        
        !          1425:      case ACTION_SET_PROTECT:
        !          1426:        action_set_protect(unit, &packet);
        !          1427:        break;
        !          1428:        
        !          1429:      case ACTION_SAME_LOCK:
        !          1430:        action_same_lock(unit, &packet);
        !          1431:        break;
        !          1432:        
        !          1433:      case ACTION_PARENT:
        !          1434:        action_parent(unit, &packet);
        !          1435:        break;
        !          1436:        
        !          1437:      case ACTION_CREATE_DIR:
        !          1438:        action_create_dir(unit, &packet);
        !          1439:        break;
        !          1440:        
        !          1441:      case ACTION_DELETE_OBJECT:
        !          1442:        action_delete_object(unit, &packet);
        !          1443:        break;
        !          1444:        
        !          1445:      case ACTION_RENAME_OBJECT:
        !          1446:        action_rename_object(unit, &packet);
        !          1447:        break;
        !          1448:        
        !          1449:      case ACTION_SET_DATE:
        !          1450:        action_set_date(unit, &packet);
        !          1451:        break;
        !          1452:        
        !          1453:      case ACTION_CURRENT_VOLUME:
        !          1454:        action_current_volume(unit, &packet);
        !          1455:        break;
        !          1456:        
        !          1457:      case ACTION_RENAME_DISK:
        !          1458:        action_rename_disk(unit, &packet);
        !          1459:        break;
        !          1460:        
        !          1461:      case ACTION_IS_FILESYSTEM:
        !          1462:        action_is_filesystem(unit, &packet);
        !          1463:        break;
        !          1464:        
        !          1465:      case ACTION_FLUSH:
        !          1466:        action_flush(unit, &packet);
        !          1467:        break;
        !          1468:        
        !          1469:      default:
        !          1470:        TRACE(("*** UNSUPPORTED PACKET %ld\n", packet.type));
        !          1471:        packet.res1 = DOS_FALSE;
        !          1472:        packet.res2 = ERROR_ACTION_NOT_KNOWN;
        !          1473:        break;
        !          1474:     }
        !          1475: 
        !          1476:     put_long(packet.addr + dp_Res1, packet.res1);
        !          1477:     put_long(packet.addr + dp_Res2, packet.res2); 
        !          1478:     TRACE(("reply: %8lx, %ld\n", packet.res1, packet.res2));
        !          1479: 
        !          1480:     return 0;
        !          1481: }
        !          1482: 
        !          1483: static ULONG
        !          1484: filesys_init(void)
        !          1485: {
        !          1486:     ULONG tmp1, tmp2;
        !          1487:     bool have36 = false;
        !          1488:     int i;
        !          1489: 
        !          1490:     regs.d[0] = 88; regs.d[1] = 1; /* MEMF_PUBLIC */
        !          1491:     tmp1 = CallLib (regs.a[6], -198); /* AllocMem() */
        !          1492:     if (tmp1 == 0) {
        !          1493:        fprintf(stderr, "Not enough memory for filesystem!\n");
        !          1494:        return 0;
        !          1495:     }
        !          1496: 
        !          1497:     /* Open expansion.lib */
        !          1498:     regs.d[0] = 36; /* Let's try this... */
        !          1499:     regs.a[1] = explibname;
        !          1500:     regs.a[4] = CallLib (regs.a[6], -552); /* OpenLibrary() */
        !          1501:     if (regs.a[4])
        !          1502:        have36 = true;
        !          1503:     else {
        !          1504:        regs.d[0] = 0;
        !          1505:        regs.a[1] = explibname;
        !          1506:        regs.a[4] = CallLib (regs.a[6], -552); /* OpenLibrary() */
        !          1507:     }
        !          1508:     put_long (tmp1+4, fsdevname);
        !          1509:     put_long (tmp1+12, 0); /* Device flags */
        !          1510:     put_long (tmp1+16, 16); /* Env. size */
        !          1511:     put_long (tmp1+20, 128); /* 512 bytes/block */
        !          1512:     put_long (tmp1+24, 0); /* unused */
        !          1513:     put_long (tmp1+28, 1); /* heads */
        !          1514:     put_long (tmp1+32, 1); /* unused */
        !          1515:     put_long (tmp1+36, 32); /* secs per track */
        !          1516:     put_long (tmp1+40, 1); /* reserved blocks */
        !          1517:     put_long (tmp1+44, 0); /* unused */
        !          1518:     put_long (tmp1+48, 0); /* interleave */
        !          1519:     put_long (tmp1+52, 0); /* lowCyl */
        !          1520:     put_long (tmp1+56, 511); /* upperCyl */
        !          1521:     put_long (tmp1+60, 0); /* Number of buffers */
        !          1522:     put_long (tmp1+64, 0); /* Buffer mem type */
        !          1523:     put_long (tmp1+68, 0x7FFFFFFF); /* largest transfer */
        !          1524:     put_long (tmp1+72, ~1); /* addMask (?) */
        !          1525:     put_long (tmp1+76, (ULONG)-1); /* bootPri */
        !          1526:     if (have36)
        !          1527:        put_long (tmp1+80, 0x444f5301); /* DOS\1 */
        !          1528:     else
        !          1529:        put_long (tmp1+80, 0x444f5300); /* DOS\0 */
        !          1530:     
        !          1531:     put_long (tmp1+84, 0); /* pad */
        !          1532: 
        !          1533:     /* re-use the same parameter packet to make each
        !          1534:      * dos node, which will then get tweaked
        !          1535:      */
        !          1536:     for(i = 0; i < num_units; i++) {
        !          1537:        put_long (tmp1, devnameaddr[i]);
        !          1538:        put_long (tmp1+8, i); /* Unit no. (not really necessary) */
        !          1539:        regs.a[0] = tmp1;
        !          1540:        tmp2 = CallLib (regs.a[4], -144); /* MakeDosNode() */
        !          1541:        put_long(tmp2+8, 0x0); /* dn_Task */
        !          1542:        put_long(tmp2+16, 0x0); /* dn_Handler */
        !          1543:        put_long(tmp2+20, 4000); /* dn_StackSize */
        !          1544:        put_long(tmp2+32, filesysseglist >> 2); /* dn_SegList */
        !          1545:        put_long(tmp2+36, (ULONG)-1); /* dn_GlobalVec */
        !          1546:        
        !          1547:        regs.a[0] = tmp2;
        !          1548:        regs.d[0] = (ULONG)-1;
        !          1549:        regs.a[1] = 0;
        !          1550:        regs.d[1] = 0;
        !          1551:        CallLib (regs.a[4], -150); /* AddDosNode() */
        !          1552:     }
        !          1553: 
        !          1554:     regs.a[1] = tmp1;
        !          1555:     regs.d[0] = 88;
        !          1556:     CallLib (regs.a[6], -210); /* FreeMem() */
        !          1557: 
        !          1558:     regs.a[1] = regs.a[4];
        !          1559:     CallLib (regs.a[6], -414); /* CloseLibrary() */
        !          1560: 
        !          1561:     return 0;
        !          1562: }
        !          1563: 
        !          1564: void
        !          1565: filesys_install(void)
        !          1566: {
        !          1567:     ULONG begin, end, resname, resid;
        !          1568:     int i;
        !          1569: 
        !          1570:     if(0 == num_units)
        !          1571:        return;
        !          1572: 
        !          1573:     resname = ds("UAEunixfs.resource");
        !          1574:     resid = ds("UAE unixfs 0.1");
        !          1575: 
        !          1576:     doslibname = ds("dos.library");
        !          1577:     fsdevname = ds("unixfs.device"); /* does not really exist */
        !          1578: 
        !          1579:     for(i = 0; i < num_units; i++) {
        !          1580:        devnameaddr[i] = ds(ui[i].devname);
        !          1581:     }
        !          1582: 
        !          1583:     begin = here();
        !          1584:     dw(0x4AFC); /* RTC_MATCHWORD */
        !          1585:     dl(begin); /* our start address */
        !          1586:     dl(0); /* Continue scan here */
        !          1587:     dw(0x0101); /* RTF_COLDSTART; Version 1 */
        !          1588:     dw(0x0805); /* NT_RESOURCE; pri 5 */
        !          1589:     dl(resname); /* name */
        !          1590:     dl(resid); /* ID */
        !          1591:     dl(here() + 4); /* Init area: directly after this */
        !          1592: 
        !          1593:     calltrap(deftrap(filesys_init)); dw(RTS);
        !          1594: 
        !          1595:     /* align */
        !          1596:     align(4);
        !          1597:     /* Fake seglist */
        !          1598:     dl(16);
        !          1599:     filesysseglist = here();
        !          1600:     dl(0); /* NextSeg */
        !          1601: 
        !          1602:     /* start of code */
        !          1603: 
        !          1604:     /* I don't trust calling functions that Wait() directly,
        !          1605:      * so here's a little bit of 68000 code to receive and send our
        !          1606:      * DosPackets
        !          1607:      */
        !          1608:     dw(0x2c79); dl(4);         /* move.l       $4,a6 */
        !          1609:     dw(0x2279); dl(0);         /* move.l       0,a1 */
        !          1610:     dw(0x4eae); dw(0xfeda);    /* jsr          FindTask(a6) */
        !          1611:     dw(0x2040);                                /* move.l       d0,a0 */
        !          1612:     dw(0x4be8); dw(0x005c);    /* lea.l        pr_MsgPort(a0),a5 */
        !          1613:                                        /* loop: */
        !          1614:     dw(0x204d);                                /* move.l       a5,a0 */
        !          1615:     dw(0x4eae); dw(0xfe80);    /* jsr          WaitPort(a6) */
        !          1616:     dw(0x204d);                                /* move.l       a5,a0 */
        !          1617:     dw(0x4eae); dw(0xfe8c);    /* jsr          GetMsg(a6) */
        !          1618:     dw(0x2840);                                /* move.l       d0,a4 */
        !          1619:     dw(0x286c); dw(10);                /* move.l       LN_NAME(a4),a4 */
        !          1620:     calltrap(deftrap(filesys_handler));
        !          1621:     dw(0x226c);        dw(0);          /* move.l       dp_Link(a4),a1 */
        !          1622:     dw(0x206c); dw(4);         /* move.l       dp_Port(a4),a0 */
        !          1623:     dw(0x294d); dw(4);         /* move.l       a5,dp_Port(a4) */
        !          1624:     dw(0x4eae); dw(0xfe92);    /* jsr          PutMsg(a6) */
        !          1625:     dw(0x60d6);                        /* bra.s        loop */
        !          1626: 
        !          1627:     end = here();
        !          1628:     org(begin + 6);
        !          1629:     dl(end);
        !          1630: 
        !          1631:     org(end);
        !          1632: }
        !          1633: 

unix.superglobalmegacorp.com

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