Annotation of uae/filesys.c, revision 1.1.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.