Annotation of uae/filesys.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

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