Annotation of uae/src/filesys.c, revision 1.1.1.4

1.1       root        1:  /*
                      2:   * UAE - The Un*x Amiga Emulator
                      3:   *
                      4:   * Unix file system handler for AmigaDOS
                      5:   *
1.1.1.3   root        6:   * Copyright 1996 Ed Hanway
                      7:   * Copyright 1996, 1997 Bernd Schmidt
1.1       root        8:   *
1.1.1.3   root        9:   * Version 0.4: 970308
1.1       root       10:   *
                     11:   * Based on example code (c) 1988 The Software Distillery
                     12:   * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
                     13:   * (May - August 1989)
                     14:   *
                     15:   * Known limitations:
                     16:   * Does not support ACTION_INHIBIT (big deal).
                     17:   * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
                     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.
1.1.1.3   root       22:   * Could do tighter checks on malloc return values.
                     23:   * Will probably fail spectacularly in some cases if the filesystem is
                     24:   * modified at the same time by another process while UAE is running.
1.1       root       25:   */
                     26: 
                     27: #include "sysconfig.h"
                     28: #include "sysdeps.h"
                     29: 
                     30: #include "config.h"
                     31: #include "options.h"
1.1.1.3   root       32: #include "uae.h"
1.1       root       33: #include "memory.h"
                     34: #include "custom.h"
1.1.1.2   root       35: #include "readcpu.h"
1.1       root       36: #include "newcpu.h"
1.1.1.3   root       37: #include "filesys.h"
1.1       root       38: #include "autoconf.h"
                     39: #include "compiler.h"
1.1.1.4 ! root       40: #include "fsusage.h"
1.1.1.3   root       41: #include "threaddep/penguin.h"
1.1       root       42: 
1.1.1.3   root       43: /* #define TRACING_ENABLED */
                     44: #ifdef TRACING_ENABLED
1.1.1.4 ! root       45: #define TRACE(x)       do { write_log x; } while(0)
1.1.1.3   root       46: #define DUMPLOCK(u,x)  dumplock(u,x)
                     47: #else
                     48: #define TRACE(x)
                     49: #define DUMPLOCK(u,x)
                     50: #endif
                     51: 
                     52: #define MAKE_CASE_INSENSITIVE
1.1       root       53: 
1.1.1.3   root       54: /* errors */
                     55: #define ERROR_NO_FREE_STORE            103
                     56: #define ERROR_OBJECT_IN_USE            202
                     57: #define ERROR_OBJECT_EXISTS            203
                     58: #define ERROR_DIR_NOT_FOUND            204
                     59: #define ERROR_OBJECT_NOT_FOUND         205
                     60: #define ERROR_ACTION_NOT_KNOWN         209
                     61: #define ERROR_INVALID_LOCK             211
                     62: #define ERROR_OBJECT_WRONG_TYPE                212
                     63: #define ERROR_DISK_WRITE_PROTECTED     214
                     64: #define ERROR_DIRECTORY_NOT_EMPTY      216
                     65: #define ERROR_DEVICE_NOT_MOUNTED       218
                     66: #define ERROR_SEEK_ERROR               219
                     67: #define ERROR_DISK_FULL                        221
                     68: #define ERROR_DELETE_PROTECTED         222
                     69: #define ERROR_WRITE_PROTECTED          223
                     70: #define ERROR_READ_PROTECTED           224
                     71: #define ERROR_NO_MORE_ENTRIES          232
                     72: #define ERROR_NOT_IMPLEMENTED          236
                     73: 
                     74: #ifndef DONT_HAVE_POSIX
                     75: static long dos_errno(void)
1.1       root       76: {
1.1.1.3   root       77:     int e = errno;
1.1       root       78: 
1.1.1.4 ! root       79:     switch (e) {
1.1.1.3   root       80:      case ENOMEM:      return ERROR_NO_FREE_STORE;
                     81:      case EEXIST:      return ERROR_OBJECT_EXISTS;
                     82:      case EACCES:      return ERROR_WRITE_PROTECTED;
                     83:      case ENOENT:      return ERROR_OBJECT_NOT_FOUND;
                     84:      case ENOTDIR:     return ERROR_OBJECT_WRONG_TYPE;
                     85:      case ENOSPC:      return ERROR_DISK_FULL;
                     86:      case EBUSY:               return ERROR_OBJECT_IN_USE;
                     87:      case EISDIR:      return ERROR_OBJECT_WRONG_TYPE;
                     88: #if defined(ETXTBSY)
                     89:      case ETXTBSY:     return ERROR_OBJECT_IN_USE;
                     90: #endif
                     91: #if defined(EROFS)
                     92:      case EROFS:               return ERROR_DISK_WRITE_PROTECTED;
                     93: #endif
                     94: #if defined(ENOTEMPTY)
                     95: #if ENOTEMPTY != EEXIST
                     96:      case ENOTEMPTY:   return ERROR_DIRECTORY_NOT_EMPTY;
                     97: #endif
                     98: #endif
                     99: 
                    100:      default:
1.1.1.4 ! root      101:        TRACE(("Unimplemented error %s\n", strerror(e)));
1.1.1.3   root      102:        return ERROR_NOT_IMPLEMENTED;
                    103:     }
1.1       root      104: }
                    105: #endif
                    106: 
1.1.1.3   root      107: /*
                    108:  * This _should_ be no issue for us, but let's rather use a guaranteed
                    109:  * thread safe function if we have one.
1.1.1.4 ! root      110:  * This used to be broken in glibc versions <= 2.0.1 (I think). I hope
        !           111:  * no one is using this these days.
        !           112:  * Michael Krause says it's also broken in libc5. ARRRGHHHHHH!!!!
1.1.1.3   root      113:  */
                    114: #if 0 && defined HAVE_READDIR_R
                    115: 
                    116: static struct dirent *my_readdir (DIR *dirstream, struct dirent *space)
                    117: {
                    118:     struct dirent *loc;
                    119:     if (readdir_r (dirstream, space, &loc) == 0) {
                    120:        /* Success */
                    121:        return loc;
                    122:     }
                    123:     return 0;
                    124: }
                    125: 
                    126: #else
                    127: #define my_readdir(dirstream, space) readdir(dirstream)
                    128: #endif
                    129: 
1.1.1.4 ! root      130: uaecptr filesys_initcode;
        !           131: static uae_u32 fsdevname, filesys_configdev;
        !           132: 
1.1.1.3   root      133: #define FS_STARTUP 0
                    134: #define FS_GO_DOWN 1
                    135: 
                    136: /* AmigaOS "keys" */
                    137: struct a_inode {
                    138:     struct a_inode *next, *prev;
                    139:     struct a_inode *parent;
                    140:     struct a_inode *child, *sibling; /* @@@ implement hash tables or something to make this efficient */
                    141:     char *aname;
                    142:     char *nname;
                    143:     int amigaos_mode;
                    144:     int shlock;
                    145:     uae_u32 uniq;
                    146:     unsigned int dir:1;
                    147:     unsigned int elock:1;
                    148: };
1.1       root      149: 
                    150: typedef struct {
                    151:     char *devname; /* device name, e.g. UAE0: */
1.1.1.3   root      152:     uaecptr devname_amiga;
                    153:     uaecptr startup;
1.1       root      154:     char *volname; /* volume name, e.g. CDROM, WORK, etc. */
                    155:     char *rootdir; /* root unix directory */
                    156:     int readonly; /* disallow write access? */
                    157:     int devno;
1.1.1.3   root      158:     
                    159:     struct hardfiledata hf;
                    160: 
                    161:     /* Threading stuff */
                    162:     smp_comm_pipe *unit_pipe, *back_pipe;
                    163:     penguin_id tid;
                    164:     struct _unit *volatile self;
1.1.1.4 ! root      165:     /* Reset handling */
        !           166:     uae_sem_t reset_sync_sem;
        !           167:     int reset_state;
1.1       root      168: } UnitInfo;
                    169: 
                    170: #define MAX_UNITS 20
                    171: 
1.1.1.4 ! root      172: struct uaedev_mount_info {
        !           173:     int num_units;
        !           174:     UnitInfo ui[MAX_UNITS];
        !           175: };
        !           176: 
        !           177: static struct uaedev_mount_info *current_mountinfo;
        !           178: 
        !           179: int nr_units (struct uaedev_mount_info *mountinfo)
        !           180: {
        !           181:     return mountinfo->num_units;
        !           182: }
        !           183: 
        !           184: int is_hardfile (struct uaedev_mount_info *mountinfo, int unit_no)
        !           185: {
        !           186:     return mountinfo->ui[unit_no].volname == 0;
        !           187: }
        !           188: 
        !           189: static void close_filesys_unit (struct uaedev_mount_info *mountinfo, int nr)
        !           190: {
        !           191:     UnitInfo *uip = mountinfo->ui + nr;
        !           192: 
        !           193:     if (uip->hf.fd != 0)
        !           194:        fclose (uip->hf.fd);
        !           195:     if (uip->volname != 0)
        !           196:        free (uip->volname);
        !           197:     if (uip->devname != 0)
        !           198:        free (uip->devname);
        !           199:     if (uip->rootdir != 0)
        !           200:        free (uip->rootdir);
        !           201:     if (uip->unit_pipe)
        !           202:        free (uip->unit_pipe);
        !           203:     if (uip->back_pipe)
        !           204:        free (uip->back_pipe);
        !           205: 
        !           206:     uip->unit_pipe = 0;
        !           207:     uip->back_pipe = 0;
        !           208: 
        !           209:     uip->hf.fd = 0;
        !           210:     uip->volname = 0;
        !           211:     uip->devname = 0;
        !           212:     uip->rootdir = 0;
        !           213: }
        !           214: 
        !           215: char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
        !           216:                        char **volname, char **rootdir, int *readonly,
        !           217:                        int *secspertrack, int *surfaces, int *reserved,
        !           218:                        int *cylinders, int *size)
        !           219: {
        !           220:     UnitInfo *uip = mountinfo->ui + nr;
        !           221: 
        !           222:     if (nr >= mountinfo->num_units)
        !           223:        return "No slot allocated for this unit";
        !           224:     
        !           225:     *volname = uip->volname ? my_strdup (uip->volname) : 0;
        !           226:     *rootdir = uip->rootdir ? my_strdup (uip->rootdir) : 0;
        !           227:     *readonly = uip->readonly;
        !           228:     *secspertrack = uip->hf.secspertrack;
        !           229:     *surfaces = uip->hf.surfaces;
        !           230:     *reserved = uip->hf.reservedblocks;
        !           231:     *size = uip->hf.size;
        !           232:     *cylinders = uip->hf.nrcyls;
        !           233:     return 0;
        !           234: }
        !           235: 
        !           236: char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
        !           237:                        char *volname, char *rootdir, int readonly,
1.1.1.3   root      238:                        int secspertrack, int surfaces, int reserved)
1.1       root      239: {
1.1.1.4 ! root      240:     UnitInfo tmpui;
        !           241: 
        !           242:     if (nr >= mountinfo->num_units)
        !           243:        return "No slot allocated for this unit";
1.1       root      244: 
1.1.1.3   root      245:     if (volname != 0) {
1.1.1.4 ! root      246:        tmpui.volname = my_strdup (volname);
        !           247:        tmpui.hf.fd = 0;
1.1.1.3   root      248:     } else {
1.1.1.4 ! root      249:        tmpui.volname = 0;
        !           250:        tmpui.hf.fd = fopen (rootdir, "r+b");
        !           251:        if (tmpui.hf.fd == 0) {
1.1.1.3   root      252:            readonly = 1;
1.1.1.4 ! root      253:            tmpui.hf.fd = fopen (rootdir, "rb");
1.1.1.3   root      254:        }
1.1.1.4 ! root      255:        if (tmpui.hf.fd == 0)
1.1.1.3   root      256:            return "Hardfile not found";
1.1.1.4 ! root      257: 
1.1.1.3   root      258:        if (secspertrack < 1 || secspertrack > 32767
                    259:            || surfaces < 1 || surfaces > 1023
1.1.1.4 ! root      260:            || reserved < 0 || reserved > 1023)
        !           261:        {
1.1.1.3   root      262:            return "Bad hardfile geometry";
                    263:        }
1.1.1.4 ! root      264:        fseek (tmpui.hf.fd, 0, SEEK_END);
        !           265:        tmpui.hf.size = ftell (tmpui.hf.fd);
        !           266:        tmpui.hf.secspertrack = secspertrack;
        !           267:        tmpui.hf.surfaces = surfaces;
        !           268:        tmpui.hf.reservedblocks = reserved;
        !           269:        tmpui.hf.nrcyls = (tmpui.hf.size >> 9) / (secspertrack * surfaces);
        !           270:     }
        !           271:     tmpui.self = 0;
        !           272:     tmpui.reset_state = FS_STARTUP;
        !           273:     tmpui.rootdir = my_strdup (rootdir);
        !           274:     tmpui.readonly = readonly;
        !           275: 
        !           276:     close_filesys_unit (mountinfo, nr);
        !           277:     mountinfo->ui[nr] = tmpui;
1.1       root      278: 
1.1.1.3   root      279:     return 0;
1.1       root      280: }
1.1.1.4 ! root      281:                                
        !           282: char *add_filesys_unit (struct uaedev_mount_info *mountinfo,
        !           283:                        char *volname, char *rootdir, int readonly,
        !           284:                        int secspertrack, int surfaces, int reserved)
        !           285: {
        !           286:     char *retval;
        !           287:     int nr = mountinfo->num_units;
        !           288:     UnitInfo *uip = mountinfo->ui + nr;
1.1       root      289: 
1.1.1.4 ! root      290:     if (nr >= MAX_UNITS)
        !           291:        return "Maximum number of file systems mounted";
        !           292: 
        !           293:     uip->hf.fd = 0;
        !           294:     uip->devname = 0;
        !           295:     uip->volname = 0;
        !           296:     uip->rootdir = 0;
        !           297:     uip->unit_pipe = 0;
        !           298:     uip->back_pipe = 0;
        !           299: 
        !           300:     mountinfo->num_units++;
        !           301:     retval = set_filesys_unit (mountinfo, nr, volname, rootdir, readonly,
        !           302:                               secspertrack, surfaces, reserved);
        !           303:     if (retval)
        !           304:        mountinfo->num_units--;
        !           305:     return retval;
        !           306: }
        !           307: 
        !           308: int kill_filesys_unit (struct uaedev_mount_info *mountinfo, int nr)
1.1.1.2   root      309: {
1.1.1.4 ! root      310:     UnitInfo *uip = mountinfo->ui;
        !           311:     if (nr >= mountinfo->num_units || nr < 0)
1.1.1.2   root      312:        return -1;
                    313: 
1.1.1.4 ! root      314:     close_filesys_unit (mountinfo, nr);
        !           315: 
        !           316:     mountinfo->num_units--;
        !           317:     for (; nr < mountinfo->num_units; nr++) {
        !           318:        uip[nr] = uip[nr+1];
1.1.1.2   root      319:     }
                    320:     return 0;
                    321: }
                    322: 
1.1.1.4 ! root      323: int move_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, int to)
1.1.1.3   root      324: {
1.1.1.4 ! root      325:     UnitInfo tmpui;
        !           326:     UnitInfo *uip = mountinfo->ui;
        !           327: 
        !           328:     if (nr >= mountinfo->num_units || nr < 0
        !           329:        || to >= mountinfo->num_units || to < 0
        !           330:        || to == nr)
        !           331:        return -1;
        !           332:     tmpui = uip[nr];
        !           333:     if (to > nr) {
        !           334:        int i;
        !           335:        for (i = nr; i < to; i++)
        !           336:            uip[i] = uip[i + 1];
        !           337:     } else {
        !           338:        int i;
        !           339:        for (i = nr; i > to; i--)
        !           340:            uip[i] = uip[i - 1];
        !           341:     }
        !           342:     uip[to] = tmpui;
        !           343:     return 0;
1.1.1.3   root      344: }
                    345: 
1.1.1.4 ! root      346: int sprintf_filesys_unit (struct uaedev_mount_info *mountinfo, char *buffer, int num)
1.1.1.2   root      347: {
1.1.1.4 ! root      348:     UnitInfo *uip = mountinfo->ui;
        !           349:     if (num >= mountinfo->num_units)
1.1.1.2   root      350:        return -1;
1.1.1.4 ! root      351: 
        !           352:     if (uip[num].volname != 0)
        !           353:        sprintf (buffer, "(UAE%d:) Filesystem, %s: %s %s", num, uip[num].volname,
        !           354:                 uip[num].rootdir, uip[num].readonly ? "ro" : "");
1.1.1.2   root      355:     else
1.1.1.3   root      356:        sprintf (buffer, "(UAE%d:) Hardfile, \"%s\", size %d bytes", num,
1.1.1.4 ! root      357:                 uip[num].rootdir, uip[num].hf.size);
1.1.1.2   root      358:     return 0;
                    359: }
                    360: 
1.1.1.4 ! root      361: void write_filesys_config (struct uaedev_mount_info *mountinfo, FILE *f)
1.1       root      362: {
1.1.1.4 ! root      363:     UnitInfo *uip = mountinfo->ui;
1.1       root      364:     int i;
1.1.1.4 ! root      365: 
        !           366:     for (i = 0; i < mountinfo->num_units; i++) {
        !           367:        if (uip[i].volname != 0) {
        !           368:            fprintf (f, "-%c %s:%s\n", uip[i].readonly ? 'M' : 'm',
        !           369:                     uip[i].volname, uip[i].rootdir);
1.1.1.3   root      370:        } else {
1.1.1.4 ! root      371:            fprintf (f, "-W %d:%d:%d:%s\n", uip[i].hf.secspertrack,
        !           372:                     uip[i].hf.surfaces, uip[i].hf.reservedblocks,
        !           373:                     uip[i].rootdir);
1.1       root      374:        }
                    375:     }
                    376: }
                    377: 
1.1.1.4 ! root      378: struct uaedev_mount_info *alloc_mountinfo (void)
        !           379: {
        !           380:     struct uaedev_mount_info *info;
        !           381:     info = (struct uaedev_mount_info *)malloc (sizeof *info);
        !           382:     info->num_units = 0;
        !           383:     return info;
        !           384: }
        !           385: 
        !           386: struct uaedev_mount_info *dup_mountinfo (struct uaedev_mount_info *mip)
        !           387: {
        !           388:     int i;
        !           389:     struct uaedev_mount_info *i2 = alloc_mountinfo ();
        !           390: 
        !           391:     memcpy (i2, mip, sizeof *i2);
        !           392: 
        !           393:     for (i = 0; i < i2->num_units; i++) {
        !           394:        UnitInfo *uip = i2->ui + i;
        !           395:        if (uip->volname)
        !           396:            uip->volname = my_strdup (uip->volname);
        !           397:        if (uip->rootdir)
        !           398:            uip->rootdir = my_strdup (uip->rootdir);
        !           399:        if (uip->hf.fd)
        !           400:            uip->hf.fd = fdopen (fileno (uip->hf.fd), uip->readonly ? "rb" : "r+b");
        !           401:     }
        !           402:     return i2;
        !           403: }
        !           404: 
        !           405: void free_mountinfo (struct uaedev_mount_info *mip)
        !           406: {
        !           407:     int i;
        !           408:     for (i = 0; i < mip->num_units; i++)
        !           409:        close_filesys_unit (mip, i);
        !           410:     free (mip);
        !           411: }
        !           412: 
        !           413: struct hardfiledata *get_hardfile_data (int nr)
        !           414: {
        !           415:     UnitInfo *uip = current_mountinfo->ui;
        !           416:     if (nr < 0 || nr >= current_mountinfo->num_units || uip[nr].volname != 0)
        !           417:        return 0;
        !           418:     return &uip[nr].hf;
        !           419: }
        !           420: 
1.1       root      421: /* minimal AmigaDOS definitions */
                    422: 
                    423: /* field offsets in DosPacket */
1.1.1.3   root      424: #define dp_Type 8
                    425: #define dp_Res1        12
                    426: #define dp_Res2 16
                    427: #define dp_Arg1 20
                    428: #define dp_Arg2 24
                    429: #define dp_Arg3 28
                    430: #define dp_Arg4 32
1.1       root      431: 
                    432: /* result codes */
1.1.1.3   root      433: #define DOS_TRUE ((unsigned long)-1L)
1.1       root      434: #define DOS_FALSE (0L)
                    435: 
                    436: /* packet types */
                    437: #define ACTION_CURRENT_VOLUME  7
                    438: #define ACTION_LOCATE_OBJECT   8
                    439: #define ACTION_RENAME_DISK     9
                    440: #define ACTION_FREE_LOCK       15
                    441: #define ACTION_DELETE_OBJECT   16
                    442: #define ACTION_RENAME_OBJECT   17
                    443: #define ACTION_COPY_DIR                19
                    444: #define ACTION_SET_PROTECT     21
                    445: #define ACTION_CREATE_DIR      22
                    446: #define ACTION_EXAMINE_OBJECT  23
                    447: #define ACTION_EXAMINE_NEXT    24
                    448: #define ACTION_DISK_INFO       25
                    449: #define ACTION_INFO            26
                    450: #define ACTION_FLUSH           27
                    451: #define ACTION_SET_COMMENT     28
                    452: #define ACTION_PARENT          29
                    453: #define ACTION_SET_DATE                34
                    454: #define ACTION_FIND_WRITE      1004
                    455: #define ACTION_FIND_INPUT      1005
                    456: #define ACTION_FIND_OUTPUT     1006
                    457: #define ACTION_END             1007
                    458: #define ACTION_SEEK            1008
                    459: #define ACTION_IS_FILESYSTEM   1027
                    460: #define ACTION_READ            'R'
                    461: #define ACTION_WRITE           'W'
                    462: 
1.1.1.3   root      463: /* 2.0+ packet types */
                    464: #define ACTION_INHIBIT       31
                    465: #define ACTION_SET_FILE_SIZE 1022
                    466: #define ACTION_LOCK_RECORD   2008
                    467: #define ACTION_FREE_RECORD   2009
                    468: #define ACTION_SAME_LOCK     40
                    469: #define ACTION_CHANGE_MODE   1028
                    470: #define ACTION_FH_FROM_LOCK  1026
                    471: #define ACTION_COPY_DIR_FH   1030
                    472: #define ACTION_PARENT_FH     1031
                    473: #define ACTION_EXAMINE_FH    1034
                    474: #define ACTION_EXAMINE_ALL   1033
                    475: #define ACTION_MAKE_LINK     1021
                    476: #define ACTION_READ_LINK     1024
                    477: #define ACTION_FORMAT        1020
                    478: #define ACTION_IS_FILESYSTEM 1027
                    479: #define ACTION_ADD_NOTIFY    4097
                    480: #define ACTION_REMOVE_NOTIFY 4098
1.1       root      481: 
1.1.1.3   root      482: #define DISK_TYPE              0x444f5301 /* DOS\1 */
1.1       root      483: 
1.1.1.3   root      484: typedef struct {
                    485:     uae_u32 uniq;
                    486:     struct a_inode *aino;
                    487:     DIR* dir;
                    488: } ExamineKey;
1.1       root      489: 
1.1.1.3   root      490: typedef struct key {
                    491:     struct key *next;
                    492:     struct a_inode *aino;
                    493:     uae_u32 uniq;
                    494:     int fd;
                    495:     off_t file_pos;
                    496: } Key;
1.1       root      497: 
1.1.1.3   root      498: /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
                    499:  * some of these around
                    500:  */
                    501: 
                    502: #define EXKEYS 100
                    503: #define MAX_AINO_HASH 128
1.1       root      504: 
                    505: /* handler state info */
                    506: 
                    507: typedef struct _unit {
                    508:     struct _unit *next;
                    509: 
                    510:     /* Amiga stuff */
1.1.1.4 ! root      511:     uaecptr dosbase;
        !           512:     uaecptr volume;
        !           513:     uaecptr port;      /* Our port */
        !           514:     uaecptr locklist;
1.1       root      515: 
                    516:     /* Native stuff */
1.1.1.4 ! root      517:     uae_s32 unit;      /* unit number */
        !           518:     UnitInfo ui;       /* unit startup info */
        !           519:     char tmpbuf3[256];
1.1.1.3   root      520: 
                    521:     /* Dummy message processing */
1.1.1.4 ! root      522:     uaecptr dummy_message;
1.1.1.3   root      523:     volatile unsigned int cmds_sent;
                    524:     volatile unsigned int cmds_complete;
                    525:     volatile unsigned int cmds_acked;
                    526: 
                    527:     /* ExKeys */
                    528:     ExamineKey examine_keys[EXKEYS];
1.1.1.4 ! root      529:     int next_exkey;
1.1.1.3   root      530: 
                    531:     /* Keys */
1.1.1.4 ! root      532:     struct key *keys;
        !           533:     uae_u32 key_uniq;
        !           534:     uae_u32 a_uniq;
1.1.1.3   root      535: 
                    536:     struct a_inode rootnode;
                    537:     unsigned long aino_cache_size;
                    538:     struct a_inode *aino_hash[MAX_AINO_HASH];
                    539:     unsigned long nr_cache_hits;
                    540:     unsigned long nr_cache_lookups;
1.1       root      541: } Unit;
                    542: 
1.1.1.3   root      543: typedef uae_u8 *dpacket;
                    544: #define PUT_PCK_RES1(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res1), (v)); } while (0)
                    545: #define PUT_PCK_RES2(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res2), (v)); } while (0)
                    546: #define GET_PCK_TYPE(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Type))))
                    547: #define GET_PCK_RES1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res1))))
                    548: #define GET_PCK_RES2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res2))))
                    549: #define GET_PCK_ARG1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg1))))
                    550: #define GET_PCK_ARG2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg2))))
                    551: #define GET_PCK_ARG3(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg3))))
                    552: #define GET_PCK_ARG4(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg4))))
1.1       root      553: 
1.1.1.3   root      554: static char *bstr1 (uaecptr addr)
1.1       root      555: {
                    556:     static char buf[256];
                    557:     int i;
1.1.1.3   root      558:     int n = get_byte(addr);
                    559:     addr++;
                    560: 
1.1.1.4 ! root      561:     for (i = 0; i < n; i++, addr++)
1.1.1.3   root      562:        buf[i] = get_byte(addr);
1.1       root      563:     buf[i] = 0;
                    564:     return buf;
                    565: }
                    566: 
1.1.1.3   root      567: static char *bstr (Unit *unit, uaecptr addr)
                    568: {
                    569:     int i;
                    570:     int n = get_byte(addr);
                    571: 
                    572:     addr++;
1.1.1.4 ! root      573:     for (i = 0; i < n; i++, addr++)
1.1.1.3   root      574:        unit->tmpbuf3[i] = get_byte(addr);
                    575:     unit->tmpbuf3[i] = 0;
                    576:     return unit->tmpbuf3;
                    577: }
                    578: 
                    579: static char *bstr_cut (Unit *unit, uaecptr addr)
                    580: {
                    581:     char *p = unit->tmpbuf3;
                    582:     int i, colon_seen = 0;
                    583:     int n = get_byte (addr);
                    584: 
                    585:     addr++;
1.1.1.4 ! root      586:     for (i = 0; i < n; i++, addr++) {
1.1.1.3   root      587:        uae_u8 c = get_byte(addr);
                    588:        unit->tmpbuf3[i] = c;
                    589:        if (c == '/' || (c == ':' && colon_seen++ == 0))
                    590:            p = unit->tmpbuf3 + i + 1;
                    591:     }
                    592:     unit->tmpbuf3[i] = 0;
                    593:     return p;
                    594: }
                    595: 
                    596: static Unit *units = 0;
1.1       root      597: static int unit_num = 0;
                    598: 
                    599: static Unit*
1.1.1.4 ! root      600: find_unit (uaecptr port)
1.1       root      601: {
                    602:     Unit* u;
1.1.1.4 ! root      603:     for (u = units; u; u = u->next)
        !           604:        if (u->port == port)
1.1       root      605:            break;
                    606: 
                    607:     return u;
                    608: }
                    609: 
1.1.1.3   root      610: static int get_file_attrs (struct a_inode *aino)
                    611: {
                    612:     struct stat statbuf;
                    613:     if (-1 == stat (aino->nname, &statbuf))
                    614:        return dos_errno ();
                    615:     aino->dir = S_ISDIR (statbuf.st_mode) ? 1 : 0;
                    616:     aino->amigaos_mode =
1.1.1.4 ! root      617: #if !defined __DOS__ && !defined _WIN32
1.1.1.3   root      618:        (S_IXUSR & statbuf.st_mode ? 0 : A_FIBF_EXECUTE) |
                    619: #endif
                    620:        (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_WRITE) |
                    621: #if 0 /* This makes it impossible to overwrite those. */
                    622:        (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_DELETE) |
                    623: #endif
                    624:        (S_IRUSR & statbuf.st_mode ? 0 : A_FIBF_READ);
                    625:     return 0;
                    626: };
                    627: 
                    628: static int set_file_attrs (struct a_inode *aino, int mask)
                    629: {
                    630:     struct stat statbuf;
                    631:     int mode;
                    632: 
                    633:     if (-1 == stat(aino->nname, &statbuf))
                    634:        return ERROR_OBJECT_NOT_FOUND;
                    635: 
                    636:     mode = statbuf.st_mode;
                    637: #ifdef __unix
                    638:     /* Unix dirs behave differently than AmigaOS ones. Just allow anything. */
                    639:     if (aino->dir) {
                    640:        mask = 0;
                    641:     }
                    642: #endif
                    643:     if (mask & A_FIBF_READ)
                    644:        mode &= ~S_IRUSR;
                    645:     else
                    646:        mode |= S_IRUSR;
                    647: 
                    648:     if ((mask & A_FIBF_WRITE) != 0 || (mask & A_FIBF_DELETE) != 0)
                    649:        mode &= ~S_IWUSR;
                    650:     else
                    651:        mode |= S_IWUSR;
                    652: 
                    653:     if (mask & A_FIBF_EXECUTE)
                    654:        mode &= ~S_IXUSR;
                    655:     else
                    656:        mode |= S_IXUSR;
                    657: 
                    658:     if (-1 == chmod(aino->nname, mode))
                    659:        return dos_errno();
                    660: 
                    661:     aino->amigaos_mode = mask;
                    662: 
                    663:     return 0;
                    664: }
                    665: 
                    666: static void prepare_for_open (char *name)
                    667: {
                    668: #if 0
                    669:     struct stat statbuf;
                    670:     int mode;
                    671: 
                    672:     if (-1 == stat (name, &statbuf))
                    673:        return;
                    674: 
                    675:     mode = statbuf.st_mode;
                    676:     mode |= S_IRUSR;
                    677:     mode |= S_IWUSR;
                    678:     mode |= S_IXUSR;
                    679:     chmod (name, mode);
                    680: #endif
                    681: }
                    682: 
                    683: static void de_recycle_aino (Unit *unit, struct a_inode *aino)
1.1       root      684: {
1.1.1.3   root      685:     if (aino->next == 0 || aino == &unit->rootnode)
                    686:        return;
                    687:     aino->next->prev = aino->prev;
                    688:     aino->prev->next = aino->next;
                    689:     aino->next = aino->prev = 0;
                    690:     unit->aino_cache_size--;
                    691: }
                    692: 
                    693: static void recycle_aino (Unit *unit, struct a_inode *aino)
                    694: {
                    695:     if (aino->dir || aino->shlock > 0 || aino->elock || aino == &unit->rootnode)
                    696:        /* Still in use */
                    697:        return;
                    698: 
                    699:     /* Chain it into circular list. */
                    700:     aino->next = unit->rootnode.next;
                    701:     aino->prev = &unit->rootnode;
                    702:     aino->prev->next = aino;
                    703:     aino->next->prev = aino;
                    704:     unit->aino_cache_size++;
                    705:     if (unit->aino_cache_size > 500) {
                    706:        /* Reap a few. */
                    707:        int i = 0;
                    708:        while (i < 50) {
                    709:            struct a_inode **aip;
                    710:            aip = &unit->rootnode.prev->parent->child;
                    711:            for (;;) {
                    712:                aino = *aip;
                    713:                if (aino == 0)
                    714:                    break;
                    715: 
                    716:                if (aino->next == 0)
                    717:                    aip = &aino->sibling;
                    718:                else {
                    719:                    int hash = aino->uniq % MAX_AINO_HASH;
                    720:                    if (unit->aino_hash[hash] == aino)
                    721:                        unit->aino_hash[hash] = 0;
                    722: 
                    723:                    aino->next->prev = aino->prev;
                    724:                    aino->prev->next = aino->next;
                    725:                    *aip = aino->sibling;
                    726:                    i++;
                    727: 
                    728:                    if (aino->shlock > 0 || aino->elock)
                    729:                        write_log ("panic: freeing locked a_inode!\n");
                    730: 
                    731:                    free (aino->nname);
                    732:                    free (aino->aname);
                    733:                    free (aino);
                    734:                }
                    735:            }
                    736:        }
                    737: #if 0
                    738:        {
                    739:            char buffer[40];
                    740:            sprintf (buffer, "%d ainos reaped.\n", i);
                    741:            write_log (buffer);
                    742:        }
                    743: #endif
                    744:        unit->aino_cache_size -= i;
                    745:     }
                    746: }
1.1       root      747: 
1.1.1.3   root      748: static void update_child_names (Unit *unit, struct a_inode *a, struct a_inode *parent)
                    749: {
                    750:     int l0 = strlen (parent->nname) + 2;
1.1       root      751: 
1.1.1.3   root      752:     while (a != 0) {
                    753:        char *name_start;
                    754:        char *new_name;
1.1       root      755: 
1.1.1.3   root      756:        a->parent = parent;
                    757:        name_start = strrchr (a->nname, '/');
                    758:        if (name_start == 0) {
                    759:            write_log ("malformed file name");
                    760:        }
                    761:        name_start++;
                    762:        new_name = (char *)xmalloc (strlen (name_start) + l0);
                    763:        strcpy (new_name, parent->nname);
                    764:        strcat (new_name, "/");
                    765:        strcat (new_name, name_start);
                    766:        free (a->nname);
                    767:        a->nname = new_name;
                    768:        if (a->child)
                    769:            update_child_names (unit, a->child, a);
                    770:        a = a->sibling;
1.1       root      771:     }
1.1.1.3   root      772: }
1.1       root      773: 
1.1.1.3   root      774: static void move_aino_children (Unit *unit, struct a_inode *from, struct a_inode *to)
                    775: {
                    776:     to->child = from->child;
                    777:     from->child = 0;
                    778:     update_child_names (unit, to->child, to);
1.1       root      779: }
                    780: 
1.1.1.3   root      781: static void delete_aino (Unit *unit, struct a_inode *aino)
1.1       root      782: {
1.1.1.3   root      783:     struct a_inode **aip;
                    784:     int hash;
                    785: 
1.1.1.4 ! root      786:     TRACE(("deleting aino %x\n", aino->uniq));
1.1.1.3   root      787: 
                    788:     de_recycle_aino (unit, aino);
                    789:     aip = &aino->parent->child;
                    790:     while (*aip != aino && *aip != 0)
                    791:        aip = &(*aip)->sibling;
                    792:     if (*aip != aino) {
                    793:        write_log ("Couldn't delete aino.\n");
                    794:        return;
                    795:     }
                    796:     hash = aino->uniq % MAX_AINO_HASH;
                    797:     if (unit->aino_hash[hash] == aino)
                    798:        unit->aino_hash[hash] = 0;
                    799:     *aip = aino->sibling;
                    800:     free (aino->nname);
                    801:     free (aino->aname);
                    802:     free (aino);
1.1       root      803: }
                    804: 
1.1.1.3   root      805: static struct a_inode *lookup_sub (struct a_inode *dir, uae_u32 uniq)
                    806: {
                    807:     struct a_inode **cp = &dir->child;
                    808:     struct a_inode *c, *retval;
                    809: 
                    810:     for (;;) {
                    811:        c = *cp;
                    812:        if (c == 0)
                    813:            return 0;
                    814: 
                    815:        if (c->uniq == uniq) {
                    816:            retval = c;
                    817:            break;
                    818:        }
                    819:        if (c->dir) {
                    820:            struct a_inode *a = lookup_sub (c, uniq);
                    821:            if (a != 0) {
                    822:                retval = a;
                    823:                break;
                    824:            }
                    825:        }
                    826:        cp = &c->sibling;
                    827:     }
                    828:     *cp = c->sibling;
                    829:     c->sibling = dir->child;
                    830:     dir->child = c;
                    831:     return retval;
                    832: }
                    833: 
                    834: static struct a_inode *lookup_aino (Unit *unit, uae_u32 uniq)
1.1       root      835: {
1.1.1.3   root      836:     struct a_inode *a;
                    837:     int hash = uniq % MAX_AINO_HASH;
                    838: 
                    839:     if (uniq == 0)
                    840:        return &unit->rootnode;
                    841:     a = unit->aino_hash[hash];
                    842:     if (a == 0 || a->uniq != uniq)
                    843:        a = lookup_sub (&unit->rootnode, uniq);
                    844:     else
                    845:        unit->nr_cache_hits++;
                    846:     unit->nr_cache_lookups++;
                    847:     unit->aino_hash[hash] = a;
                    848:     return a;
                    849: }
                    850: 
                    851: /* This gets called to translate an Amiga name that some program used to
                    852:  * a name that we can use on the native filesystem. */
                    853: static char *get_nname (Unit *unit, struct a_inode *base, char *rel)
                    854: {
                    855:     DIR* dir;
1.1.1.4 ! root      856:     struct dirent *de;
1.1.1.3   root      857:     char *p = 0;
                    858: 
1.1.1.4 ! root      859:     /* Don't allow Unix "." and "..", which confuse AmigaOS and let us
        !           860:      * escape out of the mount point.  */
        !           861:     if (rel[0] == '.'
        !           862:        && (rel[1] == '\0'
        !           863:            || (rel[1] == '.' && rel[2] == '\0')))
        !           864:        return 0;
        !           865: 
        !           866:     dir = opendir (base->nname);
1.1.1.3   root      867:     if (dir) {
                    868:        struct dirent de_space;
1.1.1.4 ! root      869:        while ((de = my_readdir (dir, &de_space))) {
        !           870:            if (strcasecmp (de->d_name, rel) == 0)
1.1.1.3   root      871:                break;
                    872:        }
                    873:        if (de) {
                    874:            p = (char *)xmalloc (strlen (de->d_name) + strlen (base->nname) + 2);
                    875:            strcpy (p, base->nname);
                    876:            strcat (p, "/");
                    877:            strcat (p, de->d_name);
                    878:        }
1.1.1.4 ! root      879:        closedir (dir);
1.1.1.3   root      880:     }
                    881:     return p;
                    882: }
                    883: 
                    884: /*
                    885:  * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object
                    886:  * for which we know the name on the native filesystem, but no corresponding
                    887:  * Amiga filesystem name.
                    888:  * @@@ For DOS filesystems, it might make sense to declare the new name
                    889:  * "weak", so that it can get overriden by a subsequent call to get_nname().
                    890:  * That way, if someone does "dir :" and there is a file "foobar.inf", and
                    891:  * someone else tries to open "foobar.info", get_nname() could maybe made to
                    892:  * figure out that this is supposed to be the file "foobar.inf".
                    893:  * DOS sucks...
                    894:  */
                    895: static char *get_aname (Unit *unit, struct a_inode *base, char *rel)
                    896: {
                    897:     char *p = 0;
                    898: 
                    899:     p = (char *)xmalloc (strlen (rel) + strlen (base->aname) + 2);
                    900:     strcpy (p, base->aname);
                    901:     strcat (p, "/");
                    902:     strcat (p, rel);
                    903: 
                    904:     return p;
                    905: }
                    906: 
                    907: static struct a_inode *new_child_aino (Unit *unit, struct a_inode *base, char *rel, int force)
                    908: {
                    909:     char *nn;
                    910:     struct a_inode *aino;
                    911: 
                    912:     nn = get_nname (unit, base, rel);
                    913:     if (nn == 0 && !force)
                    914:        return 0;
                    915:     else if (nn != 0)
                    916:        force = 0;
                    917: 
                    918:     aino = (struct a_inode *)malloc (sizeof (struct a_inode));
                    919:     if (aino == 0)
                    920:        return 0;
                    921:     aino->aname = my_strdup (rel);
                    922:     if (nn == 0) {
                    923:        nn = (char *)xmalloc (strlen (base->nname) + strlen (rel) + 2);
                    924:        strcpy (nn, base->nname);
                    925:        strcat (nn, "/");
                    926:        strcat (nn, rel);
                    927:        free (rel);
                    928:     }
                    929:     aino->nname = nn;
                    930:     aino->uniq = ++unit->a_uniq;
                    931:     if (unit->a_uniq == 0xFFFFFFFF) {
                    932:        write_log ("Running out of a_inodes (prepare for big trouble)!\n");
                    933:     }
                    934:     aino->shlock = 0;
                    935:     aino->elock = 0;
                    936: 
                    937:     /* Update tree structure */
                    938:     aino->parent = base;
                    939:     aino->child = 0;
                    940:     aino->sibling = base->child;
                    941:     base->child = aino;
                    942:     aino->next = aino->prev = 0;
                    943: 
                    944:     if (force == 2) {
                    945:        aino->dir = 1;
                    946:        aino->amigaos_mode = 0;
                    947:     } else if (force == 1) {
                    948:        aino->dir = 0;
                    949:        aino->amigaos_mode = 0;
                    950:     } else {
                    951:        get_file_attrs (aino);
                    952:     }
                    953:     recycle_aino (unit, aino);
1.1.1.4 ! root      954:     TRACE(("created aino %x, normal\n", aino->uniq));
1.1.1.3   root      955:     return aino;
                    956: }
                    957: 
                    958: static struct a_inode *lookup_child_aino (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err)
                    959: {
                    960:     struct a_inode *c = base->child;
                    961:     int l0 = strlen (rel);
                    962: 
                    963:     if (base->dir == 0) {
                    964:        *err = ERROR_OBJECT_WRONG_TYPE;
                    965:        return 0;
                    966:     }
                    967: 
                    968:     while (c != 0) {
                    969:        int l1 = strlen (c->aname);
                    970:        if (l0 <= l1 && strcasecmp (rel, c->aname + l1 - l0) == 0
                    971:            && (l0 == l1 || c->aname[l1-l0-1] == '/'))
                    972:            break;
                    973:        c = c->sibling;
                    974:     }
                    975:     if (c != 0)
                    976:        return c;
                    977:     c = new_child_aino (unit, base, rel, 0);
                    978:     if (c == 0)
                    979:        *err = ERROR_OBJECT_NOT_FOUND;
                    980:     return c;
                    981: }
                    982: 
                    983: /* Different version because this one compares with the nname */
                    984: static struct a_inode *lookup_child_aino_for_exnext (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err)
                    985: {
                    986:     struct a_inode *c = base->child;
                    987:     int l0 = strlen (rel);
                    988: 
                    989:     *err = 0;
                    990:     while (c != 0) {
                    991:        int l1 = strlen (c->nname);
                    992:        if (l0 <= l1 && strcasecmp (rel, c->nname + l1 - l0) == 0
                    993:            && (l0 == l1 || c->nname[l1-l0-1] == '/'))
                    994:            break;
                    995:        c = c->sibling;
                    996:     }
                    997:     if (c != 0)
                    998:        return c;
                    999:     c = (struct a_inode *)malloc (sizeof (struct a_inode));
                   1000:     if (c == 0)
                   1001:        *err = ERROR_NO_FREE_STORE;
                   1002:     else {
                   1003:        c->nname = (char *)xmalloc (strlen (base->nname) + l0 + 2);
                   1004:        strcpy (c->nname, base->nname);
                   1005:        strcat (c->nname, "/");
                   1006:        strcat (c->nname, rel);
                   1007:        c->aname = get_aname (unit, base, rel);
                   1008:        c->uniq = ++unit->a_uniq;
                   1009:        if (unit->a_uniq == 0xFFFFFFFF) {
                   1010:            write_log ("Running out of a_inodes (prepare for big trouble)!\n");
                   1011:        }
                   1012:        c->shlock = 0;
                   1013:        c->elock = 0;
                   1014: 
                   1015:        /* Update tree structure */
                   1016:        c->parent = base;
                   1017:        c->child = 0;
                   1018:        c->sibling = base->child;
                   1019:        base->child = c;
                   1020:        c->next = c->prev = 0;
                   1021: 
                   1022:        get_file_attrs (c);
                   1023:        recycle_aino (unit, c);
1.1.1.4 ! root     1024:        TRACE(("created aino %x, exnext\n", c->uniq));
1.1.1.3   root     1025:     }
                   1026:     return c;
                   1027: }
                   1028: 
1.1.1.4 ! root     1029: static struct a_inode *get_aino (Unit *unit, struct a_inode *base, const char *rel, uae_u32 *err)
1.1.1.3   root     1030: {
                   1031:     char *tmp;
                   1032:     char *p;
                   1033:     struct a_inode *curr;
                   1034:     int i;
                   1035: 
                   1036:     *err = 0;
1.1.1.4 ! root     1037:     TRACE(("get_path(%s,%s)\n", base->aname, rel));
1.1.1.3   root     1038: 
                   1039:     /* root-relative path? */
1.1.1.4 ! root     1040:     for (i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++)
1.1.1.3   root     1041:        ;
                   1042:     if (':' == rel[i])
                   1043:        rel += i+1;
                   1044: 
                   1045:     tmp = my_strdup (rel);
                   1046:     p = tmp;
                   1047:     curr = base;
                   1048: 
                   1049:     while(*p) {
                   1050:        /* start with a slash? go up a level. */
                   1051:        if (*p == '/') {
                   1052:            if (curr->parent != 0)
                   1053:                curr = curr->parent;
                   1054:            p++;
                   1055:        } else {
                   1056:            struct a_inode *next;
                   1057: 
                   1058:            char *component_end;
                   1059:            component_end = strchr (p, '/');
                   1060:            if (component_end != 0)
                   1061:                *component_end = '\0';
                   1062:            next = lookup_child_aino (unit, curr, p, err);
                   1063:            if (next == 0) {
                   1064:                /* if only last component not found, return parent dir. */
                   1065:                if (*err != ERROR_OBJECT_NOT_FOUND || component_end != 0)
                   1066:                    curr = 0;
                   1067:                /* ? what error is appropriate? */
                   1068:                break;
                   1069:            }
                   1070:            curr = next;
                   1071:            if (component_end)
                   1072:                p = component_end+1;
                   1073:            else
                   1074:                break;
                   1075: 
                   1076:        }
                   1077:     }
                   1078:     free (tmp);
                   1079:     return curr;
                   1080: }
                   1081: 
                   1082: static uae_u32 startup_handler (void)
                   1083: {
                   1084:     /* Just got the startup packet. It's in A4. DosBase is in A2,
                   1085:      * our allocated volume structure is in D6, A5 is a pointer to
                   1086:      * our port. */
                   1087:     uaecptr rootnode = get_long(m68k_areg (regs, 2) + 34);
                   1088:     uaecptr dos_info = get_long(rootnode + 24) << 2;
                   1089:     uaecptr pkt = m68k_dreg (regs, 3);
                   1090:     uaecptr arg2 = get_long (pkt + dp_Arg2);
1.1       root     1091:     int i, namelen;
1.1.1.3   root     1092:     char* devname = bstr1 (get_long (pkt + dp_Arg1) << 2);
1.1       root     1093:     char* s;
1.1.1.4 ! root     1094:     Unit *unit;
1.1.1.3   root     1095:     UnitInfo *uinfo;
1.1       root     1096: 
                   1097:     /* find UnitInfo with correct device name */
1.1.1.4 ! root     1098:     s = strchr (devname, ':');
        !          1099:     if (s)
1.1.1.3   root     1100:        *s = '\0';
1.1       root     1101: 
1.1.1.4 ! root     1102:     for (i = 0; i < current_mountinfo->num_units; i++) {
1.1       root     1103:        /* Hardfile volume name? */
1.1.1.4 ! root     1104:        if (current_mountinfo->ui[i].volname == 0)
1.1       root     1105:            continue;
1.1.1.3   root     1106: 
1.1.1.4 ! root     1107:        if (current_mountinfo->ui[i].startup == arg2)
1.1.1.3   root     1108:            break;
1.1       root     1109:     }
1.1.1.3   root     1110: 
1.1.1.4 ! root     1111:     if (i == current_mountinfo->num_units
        !          1112:        || access (current_mountinfo->ui[i].rootdir, R_OK) != 0)
        !          1113:     {
        !          1114:        write_log ("Failed attempt to mount device\n", devname);
1.1.1.3   root     1115:        put_long (pkt + dp_Res1, DOS_FALSE);
                   1116:        put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
                   1117:        return 1;
1.1       root     1118:     }
1.1.1.4 ! root     1119:     uinfo = current_mountinfo->ui + i;
1.1       root     1120: 
1.1.1.3   root     1121:     unit = (Unit *) xmalloc (sizeof (Unit));
1.1       root     1122:     unit->next = units;
                   1123:     units = unit;
1.1.1.3   root     1124:     uinfo->self = unit;
1.1       root     1125: 
                   1126:     unit->volume = 0;
1.1.1.2   root     1127:     unit->port = m68k_areg(regs, 5);
1.1       root     1128:     unit->unit = unit_num++;
                   1129: 
1.1.1.3   root     1130:     unit->ui.devname = uinfo->devname;
                   1131:     unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */
                   1132:     unit->ui.rootdir = uinfo->rootdir;
                   1133:     unit->ui.readonly = uinfo->readonly;
                   1134:     unit->ui.unit_pipe = uinfo->unit_pipe;
                   1135:     unit->ui.back_pipe = uinfo->back_pipe;
                   1136:     unit->cmds_complete = 0;
                   1137:     unit->cmds_sent = 0;
                   1138:     unit->cmds_acked = 0;
                   1139:     for (i = 0; i < EXKEYS; i++) {
                   1140:        unit->examine_keys[i].aino = 0;
                   1141:        unit->examine_keys[i].dir = 0;
                   1142:        unit->examine_keys[i].uniq = 0;
                   1143:     }
                   1144:     unit->next_exkey = 1;
                   1145:     unit->keys = 0;
                   1146:     unit->a_uniq = unit->key_uniq = 0;
                   1147: 
                   1148:     unit->rootnode.aname = uinfo->volname;
                   1149:     unit->rootnode.nname = uinfo->rootdir;
                   1150:     unit->rootnode.sibling = 0;
                   1151:     unit->rootnode.next = unit->rootnode.prev = &unit->rootnode;
                   1152:     unit->rootnode.uniq = 0;
                   1153:     unit->rootnode.parent = 0;
                   1154:     unit->rootnode.child = 0;
                   1155:     unit->rootnode.dir = 1;
                   1156:     unit->rootnode.amigaos_mode = 0;
                   1157:     unit->rootnode.shlock = 0;
                   1158:     unit->rootnode.elock = 0;
                   1159:     unit->aino_cache_size = 0;
                   1160:     for (i = 0; i < MAX_AINO_HASH; i++)
                   1161:        unit->aino_hash[i] = 0;
                   1162: 
                   1163: /*    write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/
1.1       root     1164: 
1.1.1.4 ! root     1165:     TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
1.1       root     1166: 
                   1167:     /* fill in our process in the device node */
1.1.1.3   root     1168:     put_long ((get_long (pkt + dp_Arg3) << 2) + 8, unit->port);
                   1169:     unit->dosbase = m68k_areg(regs, 2);
1.1       root     1170: 
1.1.1.3   root     1171:     /* make new volume */
                   1172:     unit->volume = m68k_areg (regs, 3) + 32;
                   1173: #ifdef UAE_FILESYS_THREADS
                   1174:     unit->locklist = m68k_areg (regs, 3) + 8;
                   1175: #else
                   1176:     unit->locklist = m68k_areg (regs, 3);
                   1177: #endif
                   1178:     unit->dummy_message = m68k_areg (regs, 3) + 12;
1.1       root     1179: 
1.1.1.3   root     1180:     put_long (unit->dummy_message + 10, 0);
                   1181: 
                   1182:     put_long (unit->volume + 4, 2); /* Type = dt_volume */
                   1183:     put_long (unit->volume + 12, 0); /* Lock */
                   1184:     put_long (unit->volume + 16, 3800); /* Creation Date */
                   1185:     put_long (unit->volume + 20, 0);
                   1186:     put_long (unit->volume + 24, 0);
                   1187:     put_long (unit->volume + 28, 0); /* lock list */
                   1188:     put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
                   1189:     namelen = strlen (unit->ui.volname);
                   1190:     put_byte (unit->volume + 44, namelen);
1.1.1.4 ! root     1191:     for (i = 0; i < namelen; i++)
1.1.1.3   root     1192:        put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
                   1193: 
                   1194:     /* link into DOS list */
                   1195:     put_long (unit->volume, get_long(dos_info + 4));
                   1196:     put_long (dos_info + 4, unit->volume >> 2);
                   1197: 
                   1198:     put_long (unit->volume + 8, unit->port);
                   1199:     put_long (unit->volume + 32, DISK_TYPE);
1.1       root     1200: 
1.1.1.3   root     1201:     put_long (pkt + dp_Res1, DOS_TRUE);
                   1202:     return 0;
1.1       root     1203: }
                   1204: 
                   1205: static void
1.1.1.4 ! root     1206: do_info (Unit *unit, dpacket packet, uaecptr info)
1.1       root     1207: {
1.1.1.4 ! root     1208:     struct fs_usage fsu;
        !          1209:     
        !          1210:     if (get_fs_usage (unit->ui.rootdir, 0, &fsu) != 0) {
1.1.1.3   root     1211:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1212:        PUT_PCK_RES2 (packet, dos_errno ());
1.1.1.4 ! root     1213:        return;
1.1       root     1214:     }
                   1215: 
1.1.1.4 ! root     1216:     fsu.fsu_blocks >>= 1;
        !          1217:     fsu.fsu_bavail >>= 1;
1.1       root     1218:     put_long(info, 0); /* errors */
                   1219:     put_long(info + 4, unit->unit); /* unit number */
                   1220:     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
1.1.1.4 ! root     1221:     put_long(info + 12, fsu.fsu_blocks ); /* numblocks */
        !          1222:     put_long(info + 16, fsu.fsu_blocks - fsu.fsu_bavail); /* inuse */
        !          1223:     put_long(info + 20, 1024); /* bytesperblock */
1.1       root     1224:     put_long(info + 24, DISK_TYPE); /* disk type */
                   1225:     put_long(info + 28, unit->volume >> 2); /* volume node */
                   1226:     put_long(info + 32, 0); /* inuse */
1.1.1.3   root     1227:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     1228: }
                   1229: 
                   1230: static void
1.1.1.4 ! root     1231: action_disk_info (Unit *unit, dpacket packet)
1.1       root     1232: {
1.1.1.4 ! root     1233:     TRACE(("ACTION_DISK_INFO\n"));
1.1.1.3   root     1234:     do_info(unit, packet, GET_PCK_ARG1 (packet) << 2);
1.1       root     1235: }
                   1236: 
                   1237: static void
1.1.1.4 ! root     1238: action_info (Unit *unit, dpacket packet)
1.1       root     1239: {
1.1.1.4 ! root     1240:     TRACE(("ACTION_INFO\n"));
1.1.1.3   root     1241:     do_info(unit, packet, GET_PCK_ARG2 (packet) << 2);
1.1       root     1242: }
                   1243: 
1.1.1.4 ! root     1244: static void free_key (Unit *unit, Key *k)
1.1       root     1245: {
                   1246:     Key *k1;
1.1.1.3   root     1247:     Key *prev = 0;
                   1248:     for (k1 = unit->keys; k1; k1 = k1->next) {
                   1249:        if (k == k1) {
1.1.1.4 ! root     1250:            if (prev)
1.1.1.3   root     1251:                prev->next = k->next;
                   1252:            else
                   1253:                unit->keys = k->next;
                   1254:            break;
                   1255:        }
                   1256:        prev = k1;
1.1       root     1257:     }
                   1258: 
                   1259:     if (k->fd >= 0)
                   1260:        close(k->fd);
1.1.1.3   root     1261: 
1.1       root     1262:     free(k);
                   1263: }
                   1264: 
1.1.1.4 ! root     1265: static Key *lookup_key (Unit *unit, uae_u32 uniq)
1.1       root     1266: {
                   1267:     Key *k;
1.1.1.3   root     1268:     /* It's hardly worthwhile to optimize this - most of the time there are
                   1269:      * only one or zero keys. */
1.1.1.4 ! root     1270:     for (k = unit->keys; k; k = k->next) {
1.1.1.3   root     1271:        if (uniq == k->uniq)
                   1272:            return k;
1.1       root     1273:     }
1.1.1.3   root     1274:     write_log ("Error: couldn't find key!\n");
                   1275: #if 0
1.1       root     1276:     exit(1);
                   1277:     /* NOTREACHED */
1.1.1.3   root     1278: #endif
                   1279:     /* There isn't much hope we will recover. Unix would kill the process,
                   1280:      * AmigaOS gets killed by it. */
                   1281:     write_log ("Better reset that Amiga - the system is messed up.\n");
                   1282:     return 0;
1.1       root     1283: }
                   1284: 
1.1.1.4 ! root     1285: static Key *new_key (Unit *unit)
1.1       root     1286: {
1.1.1.4 ! root     1287:     Key *k = (Key *) xmalloc(sizeof(Key));
1.1.1.3   root     1288:     k->uniq = ++unit->key_uniq;
1.1       root     1289:     k->fd = -1;
                   1290:     k->file_pos = 0;
1.1.1.3   root     1291:     k->next = unit->keys;
                   1292:     unit->keys = k;
1.1       root     1293: 
                   1294:     return k;
                   1295: }
                   1296: 
                   1297: static void
1.1.1.4 ! root     1298: dumplock (Unit *unit, uaecptr lock)
1.1       root     1299: {
1.1.1.3   root     1300:     struct a_inode *a;
1.1.1.4 ! root     1301:     TRACE(("LOCK: 0x%lx", lock));
        !          1302:     if (!lock) {
        !          1303:        TRACE(("\n"));
1.1       root     1304:        return;
                   1305:     }
1.1.1.4 ! root     1306:     TRACE(("{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ",
1.1.1.3   root     1307:           get_long(lock) << 2, get_long(lock+8),
                   1308:           get_long(lock+12), get_long(lock+16),
                   1309:           get_long(lock + 4)));
                   1310:     a = lookup_aino (unit, get_long (lock + 4));
                   1311:     if (a == 0) {
1.1.1.4 ! root     1312:        TRACE(("not found!"));
1.1.1.3   root     1313:     } else {
1.1.1.4 ! root     1314:        TRACE(("%s", a->nname));
1.1.1.3   root     1315:     }
1.1.1.4 ! root     1316:     TRACE((" }\n"));
1.1       root     1317: }
                   1318: 
1.1.1.4 ! root     1319: static struct a_inode *find_aino (Unit *unit, uaecptr lock, const char *name, uae_u32 *err)
1.1       root     1320: {
1.1.1.3   root     1321:     struct a_inode *a;
1.1       root     1322: 
1.1.1.3   root     1323:     if (lock) {
                   1324:        struct a_inode *olda = lookup_aino (unit, get_long(lock + 4));
                   1325:        if (olda == 0) {
                   1326:            /* That's the best we can hope to do. */
                   1327:            a = get_aino (unit, &unit->rootnode, name, err);
1.1       root     1328:        } else {
1.1.1.4 ! root     1329:            TRACE(("aino: 0x%08lx", (unsigned long int)olda->uniq));
        !          1330:            TRACE((" \"%s\"\n", olda->nname));
1.1.1.3   root     1331:            a = get_aino (unit, olda, name, err);
1.1       root     1332:        }
                   1333:     } else {
1.1.1.3   root     1334:        a = get_aino (unit, &unit->rootnode, name, err);
1.1       root     1335:     }
1.1.1.3   root     1336:     if (a) {
1.1.1.4 ! root     1337:        TRACE(("aino=\"%s\"\n", a->nname));
1.1.1.3   root     1338:     }
                   1339:     return a;
1.1       root     1340: }
                   1341: 
1.1.1.4 ! root     1342: static uaecptr make_lock (Unit *unit, uae_u32 uniq, long mode)
1.1       root     1343: {
1.1.1.3   root     1344:     /* allocate lock from the list kept by the assembly code */
                   1345:     uaecptr lock;
1.1       root     1346: 
1.1.1.3   root     1347:     lock = get_long (unit->locklist);
                   1348:     put_long (unit->locklist, get_long (lock));
                   1349:     lock += 4;
1.1       root     1350: 
1.1.1.3   root     1351:     put_long(lock + 4, uniq);
1.1       root     1352:     put_long(lock + 8, mode);
                   1353:     put_long(lock + 12, unit->port);
                   1354:     put_long(lock + 16, unit->volume >> 2);
                   1355: 
                   1356:     /* prepend to lock chain */
                   1357:     put_long(lock, get_long(unit->volume + 28));
                   1358:     put_long(unit->volume + 28, lock >> 2);
                   1359: 
1.1.1.3   root     1360:     DUMPLOCK(unit, lock);
1.1       root     1361:     return lock;
                   1362: }
                   1363: 
1.1.1.4 ! root     1364: static void free_lock (Unit *unit, uaecptr lock)
1.1       root     1365: {
1.1.1.4 ! root     1366:     if (! lock)
1.1       root     1367:        return;
                   1368: 
1.1.1.3   root     1369:     if (lock == get_long(unit->volume + 28) << 2) {
1.1       root     1370:        put_long(unit->volume + 28, get_long(lock));
                   1371:     } else {
1.1.1.3   root     1372:        uaecptr current = get_long(unit->volume + 28);
                   1373:        uaecptr next = 0;
1.1.1.4 ! root     1374:        while (current) {
1.1       root     1375:            next = get_long(current << 2);
1.1.1.4 ! root     1376:            if (lock == next << 2)
1.1       root     1377:                break;
                   1378:            current = next;
                   1379:        }
                   1380:        put_long(current << 2, get_long(lock));
                   1381:     }
1.1.1.3   root     1382:     lock -= 4;
                   1383:     put_long (lock, get_long (unit->locklist));
                   1384:     put_long (unit->locklist, lock);
1.1       root     1385: }
                   1386: 
                   1387: static void
1.1.1.4 ! root     1388: action_lock (Unit *unit, dpacket packet)
1.1       root     1389: {
1.1.1.3   root     1390:     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
                   1391:     uaecptr name = GET_PCK_ARG2 (packet) << 2;
                   1392:     long mode = GET_PCK_ARG3 (packet);
                   1393:     struct a_inode *a;
                   1394:     uae_u32 err;
1.1       root     1395: 
1.1.1.3   root     1396:     if (mode != -2 && mode != -1) {
1.1.1.4 ! root     1397:        TRACE(("Bad mode.\n"));
1.1.1.3   root     1398:        mode = -2;
                   1399:     }
1.1       root     1400: 
1.1.1.4 ! root     1401:     TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode));
1.1.1.3   root     1402:     DUMPLOCK(unit, lock);
1.1       root     1403: 
1.1.1.3   root     1404:     a = find_aino (unit, lock, bstr (unit, name), &err);
                   1405:     if (err == 0 && (a->elock || (mode != -2 && a->shlock > 0))) {
                   1406:        err = ERROR_OBJECT_IN_USE;
1.1       root     1407:     }
1.1.1.3   root     1408:     /* Lock() doesn't do access checks. */
                   1409:     if (err != 0) {
                   1410:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1411:        PUT_PCK_RES2 (packet, err);
                   1412:        return;
                   1413:     }
                   1414:     if (mode == -2)
                   1415:        a->shlock++;
                   1416:     else
                   1417:        a->elock = 1;
                   1418:     de_recycle_aino (unit, a);
                   1419:     PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2);
1.1       root     1420: }
                   1421: 
1.1.1.4 ! root     1422: static void action_free_lock (Unit *unit, dpacket packet)
1.1       root     1423: {
1.1.1.3   root     1424:     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
                   1425:     struct a_inode *a;
1.1.1.4 ! root     1426:     TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
1.1.1.3   root     1427:     DUMPLOCK(unit, lock);
1.1       root     1428: 
1.1.1.3   root     1429:     a = lookup_aino (unit, get_long (lock + 4));
                   1430:     if (a == 0) {
                   1431:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1432:        PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
                   1433:        return;
                   1434:     }
                   1435:     if (a->elock)
                   1436:        a->elock = 0;
                   1437:     else
                   1438:        a->shlock--;
                   1439:     recycle_aino (unit, a);
1.1       root     1440:     free_lock(unit, lock);
                   1441: 
1.1.1.3   root     1442:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     1443: }
                   1444: 
                   1445: static void
1.1.1.4 ! root     1446: action_dup_lock (Unit *unit, dpacket packet)
1.1       root     1447: {
1.1.1.3   root     1448:     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
                   1449:     struct a_inode *a;
1.1.1.4 ! root     1450:     TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
1.1.1.3   root     1451:     DUMPLOCK(unit, lock);
1.1       root     1452: 
1.1.1.4 ! root     1453:     if (!lock) {
1.1.1.3   root     1454:        PUT_PCK_RES1 (packet, 0);
1.1       root     1455:        return;
                   1456:     }
1.1.1.3   root     1457:     a = lookup_aino (unit, get_long (lock + 4));
                   1458:     if (a == 0) {
                   1459:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1460:        PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
                   1461:        return;
1.1       root     1462:     }
1.1.1.3   root     1463:     /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but
                   1464:      * at least the RAM-Handler seems to allow it. Let's see what happens
                   1465:      * if we don't. */
                   1466:     if (a->elock) {
                   1467:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1468:        PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
                   1469:        return;
                   1470:     }
                   1471:     a->shlock++;
                   1472:     de_recycle_aino (unit, a);
                   1473:     PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, -2) >> 2);
1.1       root     1474: }
                   1475: 
                   1476: /* convert time_t to/from AmigaDOS time */
                   1477: const int secs_per_day = 24 * 60 * 60;
                   1478: const int diff = (8 * 365 + 2) * (24 * 60 * 60);
                   1479: 
                   1480: static void
1.1.1.4 ! root     1481: get_time (time_t t, long* days, long* mins, long* ticks)
1.1       root     1482: {
                   1483:     /* time_t is secs since 1-1-1970 */
                   1484:     /* days since 1-1-1978 */
                   1485:     /* mins since midnight */
                   1486:     /* ticks past minute @ 50Hz */
                   1487: 
                   1488:     t -= diff;
                   1489:     *days = t / secs_per_day;
                   1490:     t -= *days * secs_per_day;
                   1491:     *mins = t / 60;
                   1492:     t -= *mins * 60;
                   1493:     *ticks = t * 50;
                   1494: }
                   1495: 
                   1496: static time_t
1.1.1.4 ! root     1497: put_time (long days, long mins, long ticks)
1.1       root     1498: {
                   1499:     time_t t;
                   1500:     t = ticks / 50;
                   1501:     t += mins * 60;
                   1502:     t += days * secs_per_day;
                   1503:     t += diff;
                   1504: 
                   1505:     return t;
                   1506: }
                   1507: 
1.1.1.4 ! root     1508: static void free_exkey (ExamineKey *ek)
1.1       root     1509: {
1.1.1.3   root     1510:     ek->aino = 0;
                   1511:     ek->uniq = 0;
                   1512:     if (ek->dir)
                   1513:        closedir (ek->dir);
1.1       root     1514: }
                   1515: 
1.1.1.3   root     1516: /* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */
1.1.1.4 ! root     1517: static ExamineKey *new_exkey (Unit *unit, struct a_inode *aino)
1.1       root     1518: {
1.1.1.3   root     1519:     uae_u32 uniq;
                   1520:     uae_u32 oldest = 0xFFFFFFFF;
                   1521:     ExamineKey *ek, *oldest_ek = 0;
                   1522:     int i;
                   1523: 
                   1524:     ek = unit->examine_keys;
                   1525:     for (i = 0; i < EXKEYS; i++, ek++) {
                   1526:        /* Did we find a free one? */
                   1527:        if (ek->aino == 0)
                   1528:            continue;
                   1529:        if (ek->uniq < oldest)
                   1530:            oldest = (oldest_ek = ek)->uniq;
                   1531:     }
                   1532:     ek = unit->examine_keys;
                   1533:     for (i = 0; i < EXKEYS; i++, ek++) {
                   1534:        /* Did we find a free one? */
                   1535:        if (ek->aino == 0)
                   1536:            goto found;
                   1537:     }
                   1538:     /* This message should usually be harmless. */
                   1539:     write_log ("Houston, we have a problem.\n");
                   1540:     free_exkey (oldest_ek);
                   1541:     ek = oldest_ek;
                   1542:     found:
                   1543: 
                   1544:     uniq = unit->next_exkey;
                   1545:     if (uniq == 0xFFFFFFFF) {
                   1546:        /* Things will probably go wrong, but most likely the Amiga will crash
                   1547:         * before this happens because of something else. */
                   1548:        uniq = 1;
1.1       root     1549:     }
1.1.1.3   root     1550:     unit->next_exkey = uniq+1;
                   1551:     ek->aino = aino;
1.1       root     1552:     ek->dir = 0;
                   1553:     ek->uniq = uniq;
                   1554:     return ek;
                   1555: }
                   1556: 
1.1.1.4 ! root     1557: static ExamineKey *lookup_exkey (Unit *unit, uae_u32 uniq)
1.1.1.3   root     1558: {
                   1559:     ExamineKey *ek;
                   1560:     int i;
                   1561: 
                   1562:     ek = unit->examine_keys;
                   1563:     for (i = 0; i < EXKEYS; i++, ek++) {
                   1564:        /* Did we find a free one? */
                   1565:        if (ek->uniq == uniq)
                   1566:            return ek;
                   1567:     }
                   1568:     write_log ("Houston, we have a BIG problem.\n");
                   1569:     return 0;
                   1570: }
                   1571: 
1.1       root     1572: static void
1.1.1.4 ! root     1573: get_fileinfo (Unit *unit, dpacket packet, uaecptr info, struct a_inode *aino)
1.1       root     1574: {
                   1575:     struct stat statbuf;
                   1576:     long days, mins, ticks;
1.1.1.3   root     1577:     int i, n;
                   1578:     char *x;
                   1579: 
                   1580:     /* No error checks - this had better work. */
                   1581:     stat (aino->nname, &statbuf);
                   1582: 
                   1583:     if (aino->parent == 0) {
                   1584:        x = unit->ui.volname;
                   1585:        put_long (info + 4, 1);
                   1586:        put_long (info + 120, 1);
1.1       root     1587:     } else {
1.1.1.3   root     1588:        /* AmigaOS docs say these have to contain the same value. */
                   1589:        put_long(info + 4, aino->dir ? 2 : -3);
                   1590:        put_long(info + 120, aino->dir ? 2 : -3);
                   1591:        x = strrchr (aino->aname, '/');
                   1592:        if (x)
                   1593:            x++;
                   1594:        else
                   1595:            x = aino->aname;
                   1596:     }
1.1.1.4 ! root     1597:     TRACE(("name=\"%s\"\n", x));
1.1.1.3   root     1598:     n = strlen(x);
                   1599:     if (n > 106)
                   1600:        n = 106;
                   1601:     i = 8;
                   1602:     put_byte(info + i, n); i++;
                   1603:     while(n--)
                   1604:        put_byte(info + i, *x), i++, x++;
                   1605:     while(i < 108)
                   1606:        put_byte(info + i, 0), i++;
                   1607: 
                   1608:     put_long (info + 116, aino->amigaos_mode);
                   1609:     put_long(info + 124, statbuf.st_size);
1.1       root     1610: #ifdef HAVE_ST_BLOCKS
1.1.1.3   root     1611:     put_long(info + 128, statbuf.st_blocks);
1.1       root     1612: #else
1.1.1.3   root     1613:     put_long(info + 128, statbuf.st_size / 512 + 1);
1.1       root     1614: #endif
1.1.1.3   root     1615:     get_time(statbuf.st_mtime, &days, &mins, &ticks);
                   1616:     put_long(info + 132, days);
                   1617:     put_long(info + 136, mins);
                   1618:     put_long(info + 140, ticks);
                   1619:     put_long(info + 144, 0); /* no comment */
                   1620:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     1621: }
                   1622: 
1.1.1.4 ! root     1623: static void do_examine (Unit *unit, dpacket packet, ExamineKey *ek, uaecptr info)
1.1       root     1624: {
1.1.1.3   root     1625:     struct dirent de_space;
1.1       root     1626:     struct dirent* de;
1.1.1.3   root     1627:     struct a_inode *aino;
                   1628:     uae_u32 err;
1.1       root     1629: 
1.1.1.3   root     1630:     if (!ek->dir) {
                   1631:        ek->dir = opendir (ek->aino->nname);
1.1       root     1632:     }
1.1.1.3   root     1633:     if (!ek->dir) {
                   1634:        free_exkey (ek);
                   1635:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1636:        PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
1.1       root     1637:        return;
                   1638:     }
                   1639: 
1.1.1.3   root     1640:     de = my_readdir (ek->dir, &de_space);
1.1       root     1641: 
1.1.1.3   root     1642:     while (de && (0 == strcmp(".", de->d_name)
1.1.1.4 ! root     1643:                  || 0 == strcmp("..", de->d_name)))
1.1       root     1644:     {
1.1.1.3   root     1645:        de = my_readdir (ek->dir, &de_space);
1.1       root     1646:     }
                   1647: 
1.1.1.3   root     1648:     if (!de) {
1.1.1.4 ! root     1649:        TRACE(("no more entries\n"));
1.1.1.3   root     1650:        free_exkey (ek);
                   1651:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1652:        PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
1.1       root     1653:        return;
                   1654:     }
                   1655: 
1.1.1.4 ! root     1656:     TRACE(("entry=\"%s\"\n", de->d_name));
1.1.1.3   root     1657:     aino = lookup_child_aino_for_exnext (unit, ek->aino, de->d_name, &err);
                   1658:     if (err != 0) {
                   1659:        write_log ("Severe problem in ExNext.\n");
                   1660:        free_exkey (ek);
                   1661:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1662:        PUT_PCK_RES2 (packet, err);
                   1663:        return;
                   1664:     }
                   1665:     get_fileinfo (unit, packet, info, aino);
1.1       root     1666: }
                   1667: 
1.1.1.4 ! root     1668: static void action_examine_object (Unit *unit, dpacket packet)
1.1       root     1669: {
1.1.1.3   root     1670:     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
                   1671:     uaecptr info = GET_PCK_ARG2 (packet) << 2;
                   1672:     struct a_inode *aino = 0;
1.1       root     1673: 
1.1.1.4 ! root     1674:     TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
1.1.1.3   root     1675:     DUMPLOCK(unit, lock);
1.1       root     1676: 
1.1.1.3   root     1677:     if (lock != 0)
                   1678:        aino = lookup_aino (unit, get_long(lock + 4));
                   1679:     if (aino == 0)
                   1680:        aino = &unit->rootnode;
                   1681: 
                   1682:     get_fileinfo (unit, packet, info, aino);
                   1683:     if (aino->dir) {
                   1684:        put_long(info, 0xFFFFFFFF);
                   1685:     } else
                   1686:        put_long(info, 0);
1.1       root     1687: }
                   1688: 
1.1.1.4 ! root     1689: static void action_examine_next (Unit *unit, dpacket packet)
1.1       root     1690: {
1.1.1.3   root     1691:     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
                   1692:     uaecptr info = GET_PCK_ARG2 (packet) << 2;
                   1693:     struct a_inode *aino = 0;
                   1694:     ExamineKey *ek;
                   1695:     uae_u32 uniq;
1.1       root     1696: 
1.1.1.4 ! root     1697:     TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
1.1.1.3   root     1698:     DUMPLOCK(unit, lock);
1.1       root     1699: 
1.1.1.3   root     1700:     if (lock != 0)
                   1701:        aino = lookup_aino (unit, get_long(lock + 4));
                   1702:     if (aino == 0)
                   1703:        aino = &unit->rootnode;
                   1704: 
                   1705:     uniq = get_long (info);
                   1706:     if (uniq == 0) {
                   1707:        write_log ("ExNext called for a file! (Houston?)\n");
                   1708:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1709:        PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
                   1710:        return;
                   1711:     } else if (uniq == 0xFFFFFFFF) {
                   1712:        ek = new_exkey(unit, aino);
                   1713:     } else
                   1714:        ek = lookup_exkey (unit, get_long(info));
                   1715:     if (ek == 0) {
                   1716:        write_log ("Couldn't find a matching ExKey. Prepare for trouble.\n");
                   1717:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1718:        PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
                   1719:        return;
                   1720:     }
                   1721:     put_long(info, ek->uniq);
                   1722:     do_examine(unit, packet, ek, info);
1.1       root     1723: }
                   1724: 
1.1.1.4 ! root     1725: static void do_find (Unit *unit, dpacket packet, int mode, int create, int fallback)
1.1       root     1726: {
1.1.1.3   root     1727:     uaecptr fh = GET_PCK_ARG1 (packet) << 2;
                   1728:     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
                   1729:     uaecptr name = GET_PCK_ARG3 (packet) << 2;
                   1730:     struct a_inode *aino;
1.1       root     1731:     Key *k;
1.1.1.3   root     1732:     int fd;
                   1733:     uae_u32 err;
                   1734:     mode_t openmode;
                   1735:     int aino_created = 0;
                   1736: 
1.1.1.4 ! root     1737:     TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n", fh, lock, bstr (unit, name), mode));
1.1.1.3   root     1738:     DUMPLOCK(unit, lock);
                   1739: 
                   1740:     aino = find_aino (unit, lock, bstr (unit, name), &err);
                   1741: 
                   1742:     if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) {
                   1743:        /* Whatever it is, we can't handle it. */
                   1744:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1745:        PUT_PCK_RES2 (packet, err);
                   1746:        return;
                   1747:     }
                   1748:     if (err == 0) {
                   1749:        /* Object exists. */
                   1750:        if (aino->dir) {
                   1751:            PUT_PCK_RES1 (packet, DOS_FALSE);
                   1752:            PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
                   1753:            return;
                   1754:        }
                   1755:        if (aino->elock || (create == 2 && aino->shlock > 0)) {
                   1756:            PUT_PCK_RES1 (packet, DOS_FALSE);
                   1757:            PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
                   1758:            return;
                   1759:        }
                   1760:        if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) {
                   1761:            PUT_PCK_RES1 (packet, DOS_FALSE);
                   1762:            PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
                   1763:            return;
                   1764:        }
                   1765:        if (create != 2) {
                   1766:            if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || unit->ui.readonly)
                   1767:                && fallback)
                   1768:            {
                   1769:                mode &= ~A_FIBF_WRITE;
                   1770:            }
                   1771:            /* Kick 1.3 doesn't check read and write access bits - maybe it would be
                   1772:             * simpler just not to do that either. */
                   1773:            if ((mode & A_FIBF_WRITE) != 0 && unit->ui.readonly) {
                   1774:                PUT_PCK_RES1 (packet, DOS_FALSE);
                   1775:                PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
                   1776:                return;
                   1777:            }
                   1778:            if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0
                   1779:                || mode == 0)
                   1780:            {
                   1781:                PUT_PCK_RES1 (packet, DOS_FALSE);
                   1782:                PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED);
                   1783:                return;
                   1784:            }
                   1785:            if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) {
                   1786:                PUT_PCK_RES1 (packet, DOS_FALSE);
                   1787:                PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED);
                   1788:                return;
                   1789:            }
                   1790:        }
                   1791:     } else if (create == 0) {
                   1792:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1793:        PUT_PCK_RES2 (packet, err);
1.1       root     1794:        return;
1.1.1.3   root     1795:     } else {
                   1796:        /* Object does not exist. aino points to containing directory. */
                   1797:        aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1);
                   1798:        if (aino == 0) {
                   1799:            PUT_PCK_RES1 (packet, DOS_FALSE);
                   1800:            PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
1.1       root     1801:            return;
                   1802:        }
1.1.1.3   root     1803:        aino_created = 1;
1.1       root     1804:     }
                   1805: 
1.1.1.3   root     1806:     prepare_for_open (aino->nname);
1.1       root     1807: 
1.1.1.3   root     1808:     openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY
                   1809:                 : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY
                   1810:                 : O_RDWR)
                   1811:                | (create ? O_CREAT : 0)
                   1812:                | (create == 2 ? O_TRUNC : 0));
                   1813: 
                   1814:     fd = open (aino->nname, openmode | O_BINARY, 0777);
                   1815: 
                   1816:     if (fd < 0) {
                   1817:        if (aino_created)
                   1818:            delete_aino (unit, aino);
                   1819:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1820:        PUT_PCK_RES2 (packet, dos_errno());
1.1       root     1821:        return;
                   1822:     }
1.1.1.3   root     1823:     k = new_key (unit);
                   1824:     k->fd = fd;
                   1825:     k->aino = aino;
1.1       root     1826: 
1.1.1.3   root     1827:     put_long (fh+36, k->uniq);
                   1828:     if (create == 2)
                   1829:        aino->elock = 1;
                   1830:     else
                   1831:        aino->shlock++;
                   1832:     de_recycle_aino (unit, aino);
                   1833:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     1834: }
                   1835: 
                   1836: static void
1.1.1.4 ! root     1837: action_find_input (Unit *unit, dpacket packet)
1.1       root     1838: {
1.1.1.3   root     1839:     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1);
1.1       root     1840: }
                   1841: 
                   1842: static void
1.1.1.4 ! root     1843: action_find_output (Unit *unit, dpacket packet)
1.1       root     1844: {
1.1.1.3   root     1845:     if (unit->ui.readonly) {
                   1846:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1847:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     1848:        return;
                   1849:     }
1.1.1.3   root     1850:     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 2, 0);
1.1       root     1851: }
                   1852: 
                   1853: static void
1.1.1.4 ! root     1854: action_find_write (Unit *unit, dpacket packet)
1.1       root     1855: {
1.1.1.3   root     1856:     if (unit->ui.readonly) {
                   1857:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1858:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     1859:        return;
                   1860:     }
1.1.1.3   root     1861:     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 1, 0);
1.1       root     1862: }
                   1863: 
                   1864: static void
1.1.1.4 ! root     1865: action_end (Unit *unit, dpacket packet)
1.1       root     1866: {
                   1867:     Key *k;
1.1.1.4 ! root     1868:     TRACE(("ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet)));
1.1       root     1869: 
1.1.1.3   root     1870:     k = lookup_key (unit, GET_PCK_ARG1 (packet));
                   1871:     if (k != 0) {
                   1872:        if (k->aino->elock)
                   1873:            k->aino->elock = 0;
                   1874:        else
                   1875:            k->aino->shlock--;
                   1876:        recycle_aino (unit, k->aino);
                   1877:        free_key (unit, k);
                   1878:     }
                   1879:     PUT_PCK_RES1 (packet, DOS_TRUE);
                   1880:     PUT_PCK_RES2 (packet, 0);
1.1       root     1881: }
                   1882: 
                   1883: static void
1.1.1.4 ! root     1884: action_read (Unit *unit, dpacket packet)
1.1       root     1885: {
1.1.1.3   root     1886:     Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
                   1887:     uaecptr addr = GET_PCK_ARG2 (packet);
                   1888:     long size = (uae_s32)GET_PCK_ARG3 (packet);
1.1       root     1889:     int actual;
                   1890: 
1.1.1.3   root     1891:     if (k == 0) {
                   1892:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1893:        /* PUT_PCK_RES2 (packet, EINVAL); */
                   1894:        return;
                   1895:     }
1.1.1.4 ! root     1896:     TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
1.1       root     1897: #ifdef RELY_ON_LOADSEG_DETECTION
1.1.1.3   root     1898:     /* HACK HACK HACK HACK
1.1       root     1899:      * Try to detect a LoadSeg() */
                   1900:     if (k->file_pos == 0 && size >= 4) {
                   1901:        unsigned char buf[4];
                   1902:        off_t currpos = lseek(k->fd, 0, SEEK_CUR);
                   1903:        read(k->fd, buf, 4);
                   1904:        lseek(k->fd, currpos, SEEK_SET);
                   1905:        if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3)
                   1906:            possible_loadseg();
                   1907:     }
                   1908: #endif
                   1909:     if (valid_address (addr, size)) {
1.1.1.3   root     1910:        uae_u8 *realpt;
1.1       root     1911:        realpt = get_real_address (addr);
                   1912:        actual = read(k->fd, realpt, size);
                   1913: 
1.1.1.2   root     1914:        if (actual == 0) {
1.1.1.3   root     1915:            PUT_PCK_RES1 (packet, 0);
                   1916:            PUT_PCK_RES2 (packet, 0);
1.1.1.2   root     1917:        } else if (actual < 0) {
1.1.1.3   root     1918:            PUT_PCK_RES1 (packet, 0);
                   1919:            PUT_PCK_RES2 (packet, dos_errno());
1.1       root     1920:        } else {
1.1.1.3   root     1921:            PUT_PCK_RES1 (packet, actual);
1.1       root     1922:            k->file_pos += actual;
                   1923:        }
                   1924:     } else {
                   1925:        char *buf;
1.1.1.4 ! root     1926:        write_log ("unixfs warning: Bad pointer passed for read: %08x\n", addr);
1.1       root     1927:        /* ugh this is inefficient but easy */
                   1928:        buf = (char *)malloc(size);
1.1.1.4 ! root     1929:        if (!buf) {
1.1.1.3   root     1930:            PUT_PCK_RES1 (packet, -1);
                   1931:            PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
1.1       root     1932:            return;
                   1933:        }
                   1934:        actual = read(k->fd, buf, size);
                   1935: 
1.1.1.2   root     1936:        if (actual < 0) {
1.1.1.3   root     1937:            PUT_PCK_RES1 (packet, 0);
                   1938:            PUT_PCK_RES2 (packet, dos_errno());
1.1       root     1939:        } else {
                   1940:            int i;
1.1.1.3   root     1941:            PUT_PCK_RES1 (packet, actual);
1.1.1.4 ! root     1942:            for (i = 0; i < actual; i++)
1.1       root     1943:                put_byte(addr + i, buf[i]);
                   1944:            k->file_pos += actual;
                   1945:        }
1.1.1.4 ! root     1946:        free (buf);
1.1       root     1947:     }
                   1948: }
                   1949: 
                   1950: static void
1.1.1.4 ! root     1951: action_write (Unit *unit, dpacket packet)
1.1       root     1952: {
1.1.1.3   root     1953:     Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
                   1954:     uaecptr addr = GET_PCK_ARG2 (packet);
                   1955:     long size = GET_PCK_ARG3 (packet);
1.1       root     1956:     char *buf;
                   1957:     int i;
                   1958: 
1.1.1.3   root     1959:     if (k == 0) {
                   1960:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1961:        /* PUT_PCK_RES2 (packet, EINVAL); */
                   1962:        return;
                   1963:     }
1.1       root     1964: 
1.1.1.4 ! root     1965:     TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
1.1.1.3   root     1966: 
                   1967:     if (unit->ui.readonly) {
                   1968:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   1969:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     1970:        return;
                   1971:     }
                   1972: 
                   1973:     /* ugh this is inefficient but easy */
                   1974:     buf = (char *)malloc(size);
1.1.1.3   root     1975:     if (!buf) {
                   1976:        PUT_PCK_RES1 (packet, -1);
                   1977:        PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
1.1       root     1978:        return;
                   1979:     }
                   1980: 
1.1.1.3   root     1981:     for (i = 0; i < size; i++)
1.1       root     1982:        buf[i] = get_byte(addr + i);
                   1983: 
1.1.1.3   root     1984:     PUT_PCK_RES1 (packet, write(k->fd, buf, size));
                   1985:     if (GET_PCK_RES1 (packet) != size)
                   1986:        PUT_PCK_RES2 (packet, dos_errno ());
                   1987:     if (GET_PCK_RES1 (packet) >= 0)
                   1988:        k->file_pos += GET_PCK_RES1 (packet);
1.1       root     1989: 
1.1.1.4 ! root     1990:     free (buf);
1.1       root     1991: }
                   1992: 
                   1993: static void
1.1.1.4 ! root     1994: action_seek (Unit *unit, dpacket packet)
1.1       root     1995: {
1.1.1.4 ! root     1996:     Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
1.1.1.3   root     1997:     long pos = (uae_s32)GET_PCK_ARG2 (packet);
                   1998:     long mode = (uae_s32)GET_PCK_ARG3 (packet);
1.1       root     1999:     off_t res;
                   2000:     long old;
                   2001:     int whence = SEEK_CUR;
                   2002: 
1.1.1.3   root     2003:     if (k == 0) {
                   2004:        PUT_PCK_RES1 (packet, -1);
                   2005:        PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
                   2006:        return;
                   2007:     }
1.1       root     2008: 
1.1.1.3   root     2009:     if (mode > 0) whence = SEEK_END;
                   2010:     if (mode < 0) whence = SEEK_SET;
1.1       root     2011: 
1.1.1.4 ! root     2012:     TRACE(("ACTION_SEEK(%s,%d,%d)\n", k->aino->nname, pos, mode));
1.1.1.3   root     2013: 
                   2014:     old = lseek (k->fd, 0, SEEK_CUR);
                   2015:     res = lseek (k->fd, pos, whence);
                   2016: 
                   2017:     if (-1 == res) {
                   2018:        PUT_PCK_RES1 (packet, res);
                   2019:        PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
                   2020:     } else
                   2021:        PUT_PCK_RES1 (packet, old);
1.1       root     2022:     k->file_pos = res;
                   2023: }
                   2024: 
                   2025: static void
1.1.1.4 ! root     2026: action_set_protect (Unit *unit, dpacket packet)
1.1       root     2027: {
1.1.1.3   root     2028:     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
                   2029:     uaecptr name = GET_PCK_ARG3 (packet) << 2;
                   2030:     uae_u32 mask = GET_PCK_ARG4 (packet);
                   2031:     struct a_inode *a;
                   2032:     uae_u32 err;
1.1       root     2033: 
1.1.1.4 ! root     2034:     TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask));
1.1       root     2035: 
1.1.1.3   root     2036:     if (unit->ui.readonly) {
                   2037:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2038:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     2039:        return;
                   2040:     }
                   2041: 
1.1.1.3   root     2042:     a = find_aino (unit, lock, bstr (unit, name), &err);
                   2043:     if (err != 0) {
                   2044:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2045:        PUT_PCK_RES2 (packet, err);
1.1       root     2046:        return;
                   2047:     }
                   2048: 
1.1.1.3   root     2049:     err = set_file_attrs (a, mask);
                   2050:     if (err != 0) {
                   2051:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2052:        PUT_PCK_RES2 (packet, err);
                   2053:     } else {
                   2054:        PUT_PCK_RES1 (packet, DOS_TRUE);
1.1.1.2   root     2055:     }
1.1.1.3   root     2056: }
1.1       root     2057: 
1.1.1.3   root     2058: static void
1.1.1.4 ! root     2059: action_same_lock (Unit *unit, dpacket packet)
1.1.1.3   root     2060: {
                   2061:     uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
                   2062:     uaecptr lock2 = GET_PCK_ARG2 (packet) << 2;
1.1       root     2063: 
1.1.1.4 ! root     2064:     TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
1.1.1.3   root     2065:     DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2);
1.1       root     2066: 
1.1.1.3   root     2067:     if (!lock1 || !lock2) {
                   2068:        PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE);
1.1       root     2069:     } else {
1.1.1.3   root     2070:        PUT_PCK_RES1 (packet, get_long (lock1 + 4) == get_long (lock2 + 4) ? DOS_TRUE : DOS_FALSE);
1.1       root     2071:     }
                   2072: }
                   2073: 
                   2074: static void
1.1.1.4 ! root     2075: action_parent (Unit *unit, dpacket packet)
1.1       root     2076: {
1.1.1.3   root     2077:     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1.1.1.4 ! root     2078:     struct a_inode *olda;
1.1       root     2079: 
1.1.1.4 ! root     2080:     TRACE(("ACTION_PARENT(0x%lx)\n",lock));
1.1       root     2081: 
1.1.1.3   root     2082:     if (!lock) {
                   2083:        PUT_PCK_RES1 (packet, 0);
                   2084:        PUT_PCK_RES2 (packet, 0);
                   2085:        return;
                   2086:     }
                   2087: 
                   2088:     olda = lookup_aino (unit, get_long(lock + 4));
                   2089:     if (olda == 0) {
                   2090:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2091:        PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
                   2092:        return;
                   2093:     }
                   2094: 
                   2095:     if (olda->parent == 0) {
                   2096:        PUT_PCK_RES1 (packet, 0);
                   2097:        PUT_PCK_RES2 (packet, 0);
                   2098:        return;
1.1       root     2099:     }
1.1.1.3   root     2100:     if (olda->parent->elock) {
                   2101:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2102:        PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
                   2103:        return;
                   2104:     }
                   2105:     olda->parent->shlock++;
                   2106:     de_recycle_aino (unit, olda->parent);
                   2107:     PUT_PCK_RES1 (packet, make_lock (unit, olda->parent->uniq, -2) >> 2);
1.1       root     2108: }
                   2109: 
                   2110: static void
1.1.1.4 ! root     2111: action_create_dir (Unit *unit, dpacket packet)
1.1       root     2112: {
1.1.1.3   root     2113:     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
                   2114:     uaecptr name = GET_PCK_ARG2 (packet) << 2;
                   2115:     struct a_inode *aino;
                   2116:     uae_u32 err;
1.1       root     2117: 
1.1.1.4 ! root     2118:     TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1       root     2119: 
1.1.1.3   root     2120:     if (unit->ui.readonly) {
                   2121:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2122:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     2123:        return;
                   2124:     }
                   2125: 
1.1.1.3   root     2126:     aino = find_aino (unit, lock, bstr (unit, name), &err);
                   2127:     if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) {
                   2128:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2129:        PUT_PCK_RES2 (packet, err);
1.1       root     2130:        return;
                   2131:     }
1.1.1.3   root     2132:     if (err == 0) {
                   2133:        /* Object exists. */
                   2134:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2135:        PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS);
                   2136:        return;
1.1       root     2137:     }
1.1.1.3   root     2138:     /* Object does not exist. aino points to containing directory. */
                   2139:     aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 2);
                   2140:     if (aino == 0) {
                   2141:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2142:        PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
                   2143:        return;
                   2144:     }
                   2145: 
                   2146:     if (mkdir (aino->nname, 0777) == -1) {
                   2147:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2148:        PUT_PCK_RES2 (packet, dos_errno());
                   2149:        return;
                   2150:     }
                   2151:     aino->shlock = 1;
                   2152:     de_recycle_aino (unit, aino);
                   2153:     PUT_PCK_RES1 (packet, make_lock (unit, aino->uniq, -2) >> 2);
1.1       root     2154: }
                   2155: 
                   2156: static void
1.1.1.4 ! root     2157: action_examine_fh (Unit *unit, dpacket packet)
1.1       root     2158: {
1.1.1.3   root     2159:     Key *k;
                   2160:     struct a_inode *aino = 0;
                   2161:     uaecptr info = GET_PCK_ARG2 (packet) << 2;
1.1       root     2162: 
1.1.1.4 ! root     2163:     TRACE(("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n", GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) ));
1.1       root     2164: 
1.1.1.3   root     2165:     k = lookup_key (unit, GET_PCK_ARG1 (packet));
                   2166:     if (k != 0)
                   2167:        aino = k->aino;
                   2168:     if (aino == 0)
                   2169:        aino = &unit->rootnode;
                   2170: 
                   2171:     get_fileinfo (unit, packet, info, aino);
                   2172:     if (aino->dir)
                   2173:        put_long(info, 0xFFFFFFFF);
                   2174:     else
                   2175:        put_long(info, 0);
                   2176: }
                   2177: 
                   2178: /* For a nice example of just how contradictory documentation can be, see the
                   2179:  * Autodoc for DOS:SetFileSize and the Packets.txt description of this packet...
                   2180:  * This implementation tries to mimic the behaviour of the Kick 3.1 ramdisk
                   2181:  * (which seems to match the Autodoc description). */
                   2182: static void
1.1.1.4 ! root     2183: action_set_file_size (Unit *unit, dpacket packet)
1.1.1.3   root     2184: {
                   2185:     Key *k, *k1;
                   2186:     off_t offset = GET_PCK_ARG2 (packet);
                   2187:     long mode = (uae_s32)GET_PCK_ARG3 (packet);
                   2188:     int whence = SEEK_CUR;
                   2189:     
                   2190:     if (mode > 0) whence = SEEK_END;
                   2191:     if (mode < 0) whence = SEEK_SET;
1.1       root     2192: 
1.1.1.4 ! root     2193:     TRACE(("ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n", GET_PCK_ARG1 (packet), offset, mode));
1.1       root     2194: 
1.1.1.3   root     2195:     k = lookup_key (unit, GET_PCK_ARG1 (packet));
                   2196:     if (k == 0) {
                   2197:        PUT_PCK_RES1 (packet, DOS_TRUE);
                   2198:        PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
1.1       root     2199:        return;
                   2200:     }
1.1.1.3   root     2201: 
                   2202:     /* If any open files have file pointers beyond this size, truncate only
                   2203:      * so far that these pointers do not become invalid.  */
                   2204:     for (k1 = unit->keys; k1; k1 = k1->next) {
                   2205:        if (k != k1 && k->aino == k1->aino) {
                   2206:            if (k1->file_pos > offset)
                   2207:                offset = k1->file_pos;
                   2208:        }
                   2209:     }
                   2210: 
                   2211:     /* Write one then truncate: that should give the right size in all cases.  */
                   2212:     offset = lseek (k->fd, offset, whence);
                   2213:     write (k->fd, /* whatever */(char *)&k1, 1);
                   2214:     if (k->file_pos > offset)
                   2215:        k->file_pos = offset;
                   2216:     lseek (k->fd, k->file_pos, SEEK_SET);
                   2217: 
                   2218:     if (truncate (k->aino->nname, k->file_pos) == -1) {
                   2219:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2220:        PUT_PCK_RES2 (packet, dos_errno ());
1.1       root     2221:        return;
                   2222:     }
1.1.1.3   root     2223: 
                   2224:     PUT_PCK_RES1 (packet, offset);
                   2225:     PUT_PCK_RES2 (packet, 0);
1.1       root     2226: }
                   2227: 
                   2228: static void
1.1.1.4 ! root     2229: action_delete_object (Unit *unit, dpacket packet)
1.1       root     2230: {
1.1.1.3   root     2231:     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
                   2232:     uaecptr name = GET_PCK_ARG2 (packet) << 2;
                   2233:     struct a_inode *a;
                   2234:     uae_u32 err;
1.1       root     2235: 
1.1.1.4 ! root     2236:     TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1       root     2237: 
1.1.1.3   root     2238:     if (unit->ui.readonly) {
                   2239:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2240:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     2241:        return;
                   2242:     }
                   2243: 
1.1.1.3   root     2244:     a = find_aino (unit, lock, bstr (unit, name), &err);
1.1       root     2245: 
1.1.1.3   root     2246:     if (err != 0) {
                   2247:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2248:        PUT_PCK_RES2 (packet, err);
1.1       root     2249:        return;
                   2250:     }
1.1.1.3   root     2251:     if (a->shlock > 0 || a->elock) {
                   2252:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2253:        PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
1.1       root     2254:        return;
                   2255:     }
1.1.1.3   root     2256:     if (a->dir) {
                   2257:        if (rmdir (a->nname) == -1) {
                   2258:            PUT_PCK_RES1 (packet, DOS_FALSE);
                   2259:            PUT_PCK_RES2 (packet, dos_errno());
1.1       root     2260:            return;
                   2261:        }
                   2262:     } else {
1.1.1.3   root     2263:        if (unlink (a->nname) == -1) {
                   2264:            PUT_PCK_RES1 (packet, DOS_FALSE);
                   2265:            PUT_PCK_RES2 (packet, dos_errno());
1.1       root     2266:            return;
                   2267:        }
                   2268:     }
1.1.1.3   root     2269:     if (a->child != 0) {
                   2270:        write_log ("Serious error in action_delete_object.\n");
                   2271:     } else {
                   2272:        delete_aino (unit, a);
                   2273:     }
                   2274:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     2275: }
                   2276: 
                   2277: static void
1.1.1.4 ! root     2278: action_set_date (Unit *unit, dpacket packet)
1.1       root     2279: {
1.1.1.3   root     2280:     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
                   2281:     uaecptr name = GET_PCK_ARG3 (packet) << 2;
                   2282:     uaecptr date = GET_PCK_ARG4 (packet);
                   2283:     struct a_inode *a;
1.1       root     2284:     struct utimbuf ut;
1.1.1.3   root     2285:     uae_u32 err;
1.1       root     2286: 
1.1.1.4 ! root     2287:     TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1       root     2288: 
1.1.1.4 ! root     2289:     if (unit->ui.readonly) {
1.1.1.3   root     2290:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2291:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     2292:        return;
                   2293:     }
                   2294: 
                   2295:     ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
1.1.1.3   root     2296:     a = find_aino (unit, lock, bstr (unit, name), &err);
                   2297:     if (err == 0 && utime (a->nname, &ut) == -1)
                   2298:        err = dos_errno ();
                   2299:     if (err != 0) {
                   2300:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2301:        PUT_PCK_RES2 (packet, err);
                   2302:     } else
                   2303:        PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     2304: }
                   2305: 
                   2306: static void
1.1.1.4 ! root     2307: action_rename_object (Unit *unit, dpacket packet)
1.1       root     2308: {
1.1.1.3   root     2309:     uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
                   2310:     uaecptr name1 = GET_PCK_ARG2 (packet) << 2;
                   2311:     uaecptr lock2 = GET_PCK_ARG3 (packet) << 2;
                   2312:     uaecptr name2 = GET_PCK_ARG4 (packet) << 2;
                   2313:     struct a_inode *a1, *a2;
                   2314:     uae_u32 err1, err2;
1.1       root     2315: 
1.1.1.4 ! root     2316:     TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1)));
        !          2317:     TRACE(("0x%lx,\"%s\")\n", lock2, bstr (unit, name2)));
1.1       root     2318: 
1.1.1.4 ! root     2319:     if (unit->ui.readonly) {
1.1.1.3   root     2320:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2321:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     2322:        return;
                   2323:     }
                   2324: 
1.1.1.3   root     2325:     a1 = find_aino (unit, lock1, bstr (unit, name1), &err1);
                   2326:     if (err1 != 0) {
                   2327:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2328:        PUT_PCK_RES2 (packet, err1);
                   2329:        return;
                   2330:     }
                   2331:     a2 = find_aino (unit, lock2, bstr (unit, name2), &err2);
                   2332:     if (a2 == 0 || err2 != ERROR_OBJECT_NOT_FOUND) {
                   2333:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2334:        PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2);
1.1       root     2335:        return;
                   2336:     }
1.1.1.3   root     2337:     /* Object does not exist. aino points to containing directory. */
                   2338:     a2 = new_child_aino (unit, a2, my_strdup (bstr_cut (unit, name2)), a1->dir ? 2 : 1);
                   2339:     if (a2 == 0) {
                   2340:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2341:        PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
1.1       root     2342:        return;
                   2343:     }
                   2344: 
1.1.1.3   root     2345:     /* @@@ what should we do if there are locks on a1? */
1.1.1.4 ! root     2346:     if (-1 == rename(a1->nname, a2->nname)) {
1.1.1.3   root     2347:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2348:        PUT_PCK_RES2 (packet, dos_errno());
1.1       root     2349:        return;
                   2350:     }
1.1.1.3   root     2351:     move_aino_children (unit, a1, a2);
                   2352:     delete_aino (unit, a1);
                   2353:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     2354: }
                   2355: 
                   2356: static void
1.1.1.4 ! root     2357: action_current_volume (Unit *unit, dpacket packet)
1.1       root     2358: {
1.1.1.3   root     2359:     PUT_PCK_RES1 (packet, unit->volume >> 2);
1.1       root     2360: }
                   2361: 
                   2362: static void
1.1.1.4 ! root     2363: action_rename_disk (Unit *unit, dpacket packet)
1.1       root     2364: {
1.1.1.3   root     2365:     uaecptr name = GET_PCK_ARG1 (packet) << 2;
1.1       root     2366:     int i;
                   2367:     int namelen;
                   2368: 
1.1.1.4 ! root     2369:     TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name)));
1.1       root     2370: 
1.1.1.4 ! root     2371:     if (unit->ui.readonly) {
1.1.1.3   root     2372:        PUT_PCK_RES1 (packet, DOS_FALSE);
                   2373:        PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1       root     2374:        return;
                   2375:     }
                   2376: 
                   2377:     /* get volume name */
1.1.1.3   root     2378:     namelen = get_byte (name); name++;
                   2379:     free (unit->ui.volname);
                   2380:     unit->ui.volname = (char *) xmalloc (namelen + 1);
1.1.1.4 ! root     2381:     for (i = 0; i < namelen; i++, name++)
1.1.1.3   root     2382:        unit->ui.volname[i] = get_byte (name);
1.1       root     2383:     unit->ui.volname[i] = 0;
                   2384: 
1.1.1.3   root     2385:     put_byte (unit->volume + 44, namelen);
1.1.1.4 ! root     2386:     for (i = 0; i < namelen; i++)
1.1.1.3   root     2387:        put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
1.1       root     2388: 
1.1.1.3   root     2389:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     2390: }
                   2391: 
                   2392: static void
1.1.1.4 ! root     2393: action_is_filesystem (Unit *unit, dpacket packet)
1.1       root     2394: {
1.1.1.3   root     2395:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     2396: }
                   2397: 
                   2398: static void
1.1.1.4 ! root     2399: action_flush (Unit *unit, dpacket packet)
1.1       root     2400: {
                   2401:     /* sync(); */ /* pretty drastic, eh */
1.1.1.3   root     2402:     PUT_PCK_RES1 (packet, DOS_TRUE);
1.1       root     2403: }
                   2404: 
1.1.1.3   root     2405: /* We don't want multiple interrupts to be active at the same time. I don't
                   2406:  * know whether AmigaOS takes care of that, but this does. */
                   2407: static uae_sem_t singlethread_int_sem;
                   2408: 
                   2409: static uae_u32 exter_int_helper (void)
                   2410: {
1.1.1.4 ! root     2411:     UnitInfo *uip = current_mountinfo->ui;
1.1.1.3   root     2412:     static int unit_no;
                   2413: 
                   2414:     switch (m68k_dreg (regs, 0)) {
                   2415:      case 0:
                   2416:        /* Determine whether a given EXTER interrupt is for us. */
                   2417:        if (uae_int_requested) {
                   2418:            if (uae_sem_trywait (&singlethread_int_sem) != 0)
                   2419:                /* Pretend it isn't for us. We might get it again later. */
                   2420:                return 0;
                   2421:            /* Clear the interrupt flag _before_ we do any processing.
                   2422:             * That way, we can get too many interrupts, but never not
                   2423:             * enough. */
                   2424:            uae_int_requested = 0;
                   2425:            unit_no = 0;
                   2426:            return 1;
                   2427:        }
1.1       root     2428:        return 0;
1.1.1.3   root     2429:      case 1:
                   2430:        /* Release a message_lock. This is called as soon as the message is
                   2431:         * received by the assembly code. We use the opportunity to check
                   2432:         * whether we have some locks that we can give back to the assembler
                   2433:         * code.
                   2434:         * Note that this is called from the main loop, unlike the other cases
                   2435:         * in this switch statement which are called from the interrupt handler.
                   2436:         */
                   2437:        {
                   2438:            Unit *unit = find_unit (m68k_areg (regs, 5));
                   2439:            unit->cmds_complete = unit->cmds_acked;
                   2440:            while (comm_pipe_has_data (unit->ui.back_pipe)) {
                   2441:                uaecptr locks, lockend;
                   2442:                locks = read_comm_pipe_int_blocking (unit->ui.back_pipe);
                   2443:                lockend = locks;
                   2444:                while (get_long (lockend) != 0)
                   2445:                    lockend = get_long (lockend);
                   2446:                put_long (lockend, get_long (m68k_areg (regs, 3)));
                   2447:                put_long (m68k_areg (regs, 3), locks);
                   2448:            }
                   2449:        }
1.1       root     2450:        break;
1.1.1.3   root     2451:      case 2:
                   2452:        /* Find some unit that needs a message sent, and return its port,
                   2453:         * or zero if all are done.
                   2454:         * Take care not to dereference self for units that didn't have their
                   2455:         * startup packet sent. */
                   2456:        for (;;) {
1.1.1.4 ! root     2457:            if (unit_no >= current_mountinfo->num_units)
1.1.1.3   root     2458:                return 0;
1.1.1.4 ! root     2459:            if (uip[unit_no].self != 0
        !          2460:                && uip[unit_no].self->cmds_acked == uip[unit_no].self->cmds_complete
        !          2461:                && uip[unit_no].self->cmds_acked != uip[unit_no].self->cmds_sent)
1.1.1.3   root     2462:                break;
                   2463:            unit_no++;
                   2464:        }
1.1.1.4 ! root     2465:        uip[unit_no].self->cmds_acked = uip[unit_no].self->cmds_sent;
        !          2466:        return uip[unit_no++].self->port;
1.1       root     2467: 
1.1.1.3   root     2468:      case 3:
                   2469:        /* Look up a message for a port. */
                   2470:        {
                   2471:            Unit *unit = find_unit (m68k_areg (regs, 2));
                   2472:            return unit->dummy_message;
                   2473:        }
1.1       root     2474:        break;
1.1.1.3   root     2475:      case 4:
                   2476:        /* Exit the interrupt, and release the single-threading lock. */
                   2477:        uae_sem_post (&singlethread_int_sem);
1.1       root     2478:        break;
                   2479: 
1.1.1.3   root     2480:      default:
                   2481:        write_log ("Shouldn't happen in exter_int_helper.\n");
1.1       root     2482:        break;
1.1.1.3   root     2483:     }
                   2484:     return 0;
                   2485: }
1.1       root     2486: 
1.1.1.3   root     2487: static int handle_packet (Unit *unit, dpacket pck)
                   2488: {
                   2489:     uae_s32 type = GET_PCK_TYPE (pck);
                   2490:     PUT_PCK_RES2 (pck, 0);
                   2491:     switch (type) {
1.1.1.4 ! root     2492:      case ACTION_LOCATE_OBJECT: action_lock (unit, pck); break;
        !          2493:      case ACTION_FREE_LOCK: action_free_lock (unit, pck); break;
        !          2494:      case ACTION_COPY_DIR: action_dup_lock (unit, pck); break;
        !          2495:      case ACTION_DISK_INFO: action_disk_info (unit, pck); break;
        !          2496:      case ACTION_INFO: action_info (unit, pck); break;
        !          2497:      case ACTION_EXAMINE_OBJECT: action_examine_object (unit, pck); break;
        !          2498:      case ACTION_EXAMINE_NEXT: action_examine_next (unit, pck); break;
        !          2499:      case ACTION_FIND_INPUT: action_find_input (unit, pck); break;
        !          2500:      case ACTION_FIND_WRITE: action_find_write (unit, pck); break;
        !          2501:      case ACTION_FIND_OUTPUT: action_find_output (unit, pck); break;
        !          2502:      case ACTION_END: action_end (unit, pck); break;
        !          2503:      case ACTION_READ: action_read (unit, pck); break;
        !          2504:      case ACTION_WRITE: action_write (unit, pck); break;
        !          2505:      case ACTION_SEEK: action_seek (unit, pck); break;
        !          2506:      case ACTION_SET_PROTECT: action_set_protect (unit, pck); break;
        !          2507:      case ACTION_SAME_LOCK: action_same_lock (unit, pck); break;
        !          2508:      case ACTION_PARENT: action_parent (unit, pck); break;
        !          2509:      case ACTION_CREATE_DIR: action_create_dir (unit, pck); break;
        !          2510:      case ACTION_DELETE_OBJECT: action_delete_object (unit, pck); break;
        !          2511:      case ACTION_RENAME_OBJECT: action_rename_object (unit, pck); break;
        !          2512:      case ACTION_SET_DATE: action_set_date (unit, pck); break;
        !          2513:      case ACTION_CURRENT_VOLUME: action_current_volume (unit, pck); break;
        !          2514:      case ACTION_RENAME_DISK: action_rename_disk (unit, pck); break;
        !          2515:      case ACTION_IS_FILESYSTEM: action_is_filesystem (unit, pck); break;
        !          2516:      case ACTION_FLUSH: action_flush (unit, pck); break;
1.1.1.3   root     2517: 
                   2518:      /* 2.0+ packet types */
1.1.1.4 ! root     2519:      case ACTION_SET_FILE_SIZE: action_set_file_size (unit, pck); break;
        !          2520:      case ACTION_EXAMINE_FH: action_examine_fh (unit, pck); break;
1.1.1.3   root     2521: 
                   2522:      /* unsupported packets */
                   2523:      case ACTION_LOCK_RECORD:
                   2524:      case ACTION_FREE_RECORD:
                   2525:      case ACTION_CHANGE_MODE:
                   2526:      case ACTION_FH_FROM_LOCK:
                   2527:      case ACTION_COPY_DIR_FH:
                   2528:      case ACTION_PARENT_FH:
                   2529:      case ACTION_EXAMINE_ALL:
                   2530:      case ACTION_MAKE_LINK:
                   2531:      case ACTION_READ_LINK:
                   2532:      case ACTION_FORMAT:
                   2533:      case ACTION_ADD_NOTIFY:
                   2534:      case ACTION_REMOVE_NOTIFY:
                   2535:      default:
1.1.1.4 ! root     2536:        TRACE(("*** UNSUPPORTED PACKET %ld\n", type));
1.1.1.3   root     2537:        return 0;
                   2538:     }
                   2539:     return 1;
                   2540: }
1.1       root     2541: 
1.1.1.3   root     2542: #ifdef UAE_FILESYS_THREADS
                   2543: static void *filesys_penguin (void *unit_v)
                   2544: {
                   2545:     UnitInfo *ui = (UnitInfo *)unit_v;
                   2546:     for (;;) {
                   2547:        uae_u8 *pck;
                   2548:        uae_u8 *msg;
                   2549:        uae_u32 morelocks;
                   2550:        int i;
                   2551: 
                   2552:        pck = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
                   2553:        msg = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
                   2554:        morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe);
                   2555: 
1.1.1.4 ! root     2556:        if (ui->reset_state == FS_GO_DOWN) {
1.1.1.3   root     2557:            if (pck != 0)
                   2558:                continue;
                   2559:            /* Death message received. */
1.1.1.4 ! root     2560:            uae_sem_post (&ui->reset_sync_sem);
        !          2561:            /* Die.  */
        !          2562:            return 0;
1.1.1.3   root     2563:        }
1.1       root     2564: 
1.1.1.3   root     2565:        put_long (get_long (morelocks), get_long (ui->self->locklist));
                   2566:        put_long (ui->self->locklist, morelocks);
                   2567:        if (! handle_packet (ui->self, pck)) {
                   2568:            PUT_PCK_RES1 (pck, DOS_FALSE);
                   2569:            PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
                   2570:        }
                   2571:        /* Mark the packet as processed for the list scan in the assembly code. */
                   2572:        do_put_mem_long ((uae_u32 *)(msg + 4), -1);
                   2573:        /* Acquire the message lock, so that we know we can safely send the
                   2574:         * message. */
                   2575:        ui->self->cmds_sent++;
                   2576:        /* The message is sent by our interrupt handler, so make sure an interrupt
                   2577:         * happens. */
                   2578:        uae_int_requested = 1;
                   2579:        /* Send back the locks. */
                   2580:        if (get_long (ui->self->locklist) != 0)
                   2581:            write_comm_pipe_int (ui->back_pipe, (int)(get_long(ui->self->locklist)), 0);
                   2582:        put_long (ui->self->locklist, 0);
                   2583:     }
                   2584:     return 0;
                   2585: }
                   2586: #endif
1.1       root     2587: 
1.1.1.3   root     2588: /* Talk about spaghetti code... */
1.1.1.4 ! root     2589: static uae_u32 filesys_handler (void)
1.1.1.3   root     2590: {
                   2591:     Unit *unit = find_unit (m68k_areg (regs, 5));
                   2592:     uaecptr packet_addr = m68k_dreg (regs, 3);
                   2593:     uaecptr message_addr = m68k_areg (regs, 4);
                   2594:     uae_u8 *pck;
                   2595:     uae_u8 *msg;
                   2596:     if (! valid_address (packet_addr, 36) || ! valid_address (message_addr, 14)) {
                   2597:        write_log ("Bad address passed for packet.\n");
                   2598:        goto error2;
                   2599:     }
                   2600:     pck = get_real_address (packet_addr);
                   2601:     msg = get_real_address (message_addr);
                   2602: 
1.1.1.4 ! root     2603: #if 0
1.1.1.3   root     2604:     if (unit->reset_state == FS_GO_DOWN)
                   2605:        /* You might as well queue it, if you live long enough */
                   2606:        return 1;
1.1.1.4 ! root     2607: #endif
1.1.1.3   root     2608: 
                   2609:     do_put_mem_long ((uae_u32 *)(msg + 4), -1);
                   2610:     if (!unit || !unit->volume) {
                   2611:        write_log ("Filesystem was not initialized.\n");
                   2612:        goto error;
                   2613:     }
                   2614: #ifdef UAE_FILESYS_THREADS
                   2615:     {
                   2616:        /* Get two more locks and hand them over to the other thread. */
                   2617:        uae_u32 morelocks;
                   2618:        morelocks = get_long (m68k_areg (regs, 3));
                   2619:        put_long (m68k_areg (regs, 3), get_long (get_long (morelocks)));
                   2620:        put_long (get_long (morelocks), 0);
                   2621: 
                   2622:        /* The packet wasn't processed yet. */
                   2623:        do_put_mem_long ((uae_u32 *)(msg + 4), 0);
                   2624:        write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)pck, 0);
                   2625:        write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)msg, 0);
                   2626:        write_comm_pipe_int (unit->ui.unit_pipe, (int)morelocks, 1);
                   2627:        /* Don't reply yet. */
                   2628:        return 1;
                   2629:     }
                   2630: #endif
1.1       root     2631: 
1.1.1.3   root     2632:     if (! handle_packet (unit, pck)) {
                   2633:        error:
                   2634:        PUT_PCK_RES1 (pck, DOS_FALSE);
                   2635:        PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
                   2636:     }
1.1.1.4 ! root     2637:     TRACE(("reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck)));
1.1       root     2638: 
1.1.1.3   root     2639:     error2:
1.1       root     2640: 
1.1.1.3   root     2641:     return 0;
                   2642: }
1.1       root     2643: 
1.1.1.4 ! root     2644: void filesys_start_threads (void)
        !          2645: {
        !          2646:     UnitInfo *uip;
        !          2647:     int i;
        !          2648: 
        !          2649:     current_mountinfo = dup_mountinfo (currprefs.mountinfo);
        !          2650: 
        !          2651:     reset_uaedevices ();
        !          2652:     
        !          2653:     uip = current_mountinfo->ui;
        !          2654:     for (i = 0; i < current_mountinfo->num_units; i++) {
        !          2655:        uip[i].unit_pipe = 0;
        !          2656:        uip[i].devno = get_new_device (&uip[i].devname, &uip[i].devname_amiga);
        !          2657: 
        !          2658: #ifdef UAE_FILESYS_THREADS
        !          2659:        if (! is_hardfile (current_mountinfo, i)) {
        !          2660:            uip[i].unit_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
        !          2661:            uip[i].back_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
        !          2662:            init_comm_pipe (uip[i].unit_pipe, 50, 3);
        !          2663:            init_comm_pipe (uip[i].back_pipe, 50, 1);
        !          2664:            start_penguin (filesys_penguin, (void *)(uip + i), &uip[i].tid);
        !          2665:        }
        !          2666: #endif
        !          2667:     }
        !          2668: }
        !          2669: 
1.1.1.3   root     2670: void filesys_reset (void)
                   2671: {
                   2672:     Unit *u, *u1;
                   2673:     int i;
1.1       root     2674: 
1.1.1.4 ! root     2675:     /* We get called once from customreset at the beginning of the program
        !          2676:      * before filesys_start_threads has been called. Survive that.  */
        !          2677:     if (current_mountinfo == 0)
        !          2678:        return;
1.1       root     2679: 
1.1.1.4 ! root     2680:     for (u = units; u; u = u1) {
1.1.1.3   root     2681:        u1 = u->next;
                   2682:        free (u);
1.1       root     2683:     }
1.1.1.3   root     2684:     unit_num = 0;
                   2685:     units = 0;
1.1.1.4 ! root     2686: 
        !          2687:     free_mountinfo (current_mountinfo);
        !          2688:     current_mountinfo = 0;
1.1.1.3   root     2689: }
1.1       root     2690: 
1.1.1.3   root     2691: void filesys_prepare_reset (void)
                   2692: {
1.1.1.4 ! root     2693:     UnitInfo *uip = current_mountinfo->ui;
        !          2694:     Unit *u;
1.1.1.3   root     2695:     int i;
1.1       root     2696: 
1.1.1.3   root     2697: #ifdef UAE_FILESYS_THREADS
1.1.1.4 ! root     2698:     for (i = 0; i < current_mountinfo->num_units; i++) {
        !          2699:        if (uip[i].unit_pipe != 0) {
        !          2700:            uae_sem_init (&uip[i].reset_sync_sem, 0, 0);
        !          2701:            uip[i].reset_state = FS_GO_DOWN;
1.1.1.3   root     2702:            /* send death message */
1.1.1.4 ! root     2703:            write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
        !          2704:            write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
        !          2705:            write_comm_pipe_int (uip[i].unit_pipe, 0, 1);
        !          2706:            uae_sem_wait (&uip[i].reset_sync_sem);
1.1.1.3   root     2707:        }
                   2708:     }
                   2709: #endif
                   2710:     u = units;
                   2711:     while (u != 0) {
                   2712:        while (u->rootnode.next != &u->rootnode) {
                   2713:            struct a_inode *a = u->rootnode.next;
                   2714:            u->rootnode.next = a->next;
                   2715:            free (a->nname);
                   2716:            free (a->aname);
                   2717:            free (a);
                   2718:        }
                   2719:        u = u->next;
                   2720:     }
1.1       root     2721: }
                   2722: 
1.1.1.4 ! root     2723: static uae_u32 filesys_diagentry (void)
1.1       root     2724: {
1.1.1.3   root     2725:     uaecptr resaddr = m68k_areg(regs, 2) + 0x10;
                   2726: 
1.1.1.4 ! root     2727:     TRACE (("filesystem: diagentry called\n"));
1.1.1.3   root     2728: 
1.1.1.2   root     2729:     filesys_configdev = m68k_areg(regs, 3);
1.1.1.3   root     2730: 
                   2731:     do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname);
                   2732:     do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev);
                   2733:     do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname);
1.1.1.4 ! root     2734:     do_put_mem_long ((uae_u32 *)(filesysory + 0x210c), current_mountinfo->num_units);
1.1.1.3   root     2735: 
                   2736:     uae_sem_init (&singlethread_int_sem, 0, 1);
1.1       root     2737:     if (ROM_hardfile_resid != 0) {
                   2738:        /* Build a struct Resident. This will set up and initialize
                   2739:         * the uae.device */
                   2740:        put_word(resaddr + 0x0, 0x4AFC);
                   2741:        put_long(resaddr + 0x2, resaddr);
                   2742:        put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
                   2743:        put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
                   2744:        put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
                   2745:        put_long(resaddr + 0xE, ROM_hardfile_resname);
                   2746:        put_long(resaddr + 0x12, ROM_hardfile_resid);
1.1.1.3   root     2747:        put_long(resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */
1.1       root     2748:     }
                   2749:     resaddr += 0x1A;
                   2750: 
1.1.1.2   root     2751:     /* The good thing about this function is that it always gets called
                   2752:      * when we boot. So we could put all sorts of stuff that wants to be done
                   2753:      * here. */
1.1       root     2754: 
1.1.1.3   root     2755:     return 1;
1.1       root     2756: }
                   2757: 
1.1.1.3   root     2758: /* Remember a pointer AmigaOS gave us so we can later use it to identify
                   2759:  * which unit a given startup message belongs to.  */
1.1.1.4 ! root     2760: static uae_u32 filesys_dev_remember (void)
1.1.1.3   root     2761: {
                   2762:     int unit_no = m68k_dreg (regs, 6);
                   2763:     uaecptr devicenode = m68k_areg (regs, 3);
                   2764: 
1.1.1.4 ! root     2765:     current_mountinfo->ui[unit_no].startup = get_long (devicenode + 28);
1.1.1.3   root     2766:     return devicenode;
                   2767: }
                   2768: 
                   2769: /* Fill in per-unit fields of a parampacket */
1.1.1.4 ! root     2770: static uae_u32 filesys_dev_storeinfo (void)
1.1.1.3   root     2771: {
1.1.1.4 ! root     2772:     UnitInfo *uip = current_mountinfo->ui;
1.1.1.3   root     2773:     int unit_no = m68k_dreg (regs, 6);
                   2774:     uaecptr parmpacket = m68k_areg (regs, 0);
                   2775: 
1.1.1.4 ! root     2776:     put_long (parmpacket, current_mountinfo->ui[unit_no].devname_amiga);
        !          2777:     put_long (parmpacket + 4, is_hardfile (current_mountinfo, unit_no) ? ROM_hardfile_resname : fsdevname);
        !          2778:     put_long (parmpacket + 8, uip[unit_no].devno);
1.1.1.3   root     2779:     put_long (parmpacket + 12, 0); /* Device flags */
                   2780:     put_long (parmpacket + 16, 16); /* Env. size */
                   2781:     put_long (parmpacket + 20, 128); /* 512 bytes per block */
                   2782:     put_long (parmpacket + 24, 0); /* unused */
1.1.1.4 ! root     2783:     put_long (parmpacket + 28, uip[unit_no].hf.surfaces); /* heads */
1.1.1.3   root     2784:     put_long (parmpacket + 32, 0); /* unused */
1.1.1.4 ! root     2785:     put_long (parmpacket + 36, uip[unit_no].hf.secspertrack); /* sectors per track */
        !          2786:     put_long (parmpacket + 40, uip[unit_no].hf.reservedblocks); /* reserved blocks */
1.1.1.3   root     2787:     put_long (parmpacket + 44, 0); /* unused */
                   2788:     put_long (parmpacket + 48, 0); /* interleave */
                   2789:     put_long (parmpacket + 52, 0); /* lowCyl */
1.1.1.4 ! root     2790:     put_long (parmpacket + 56, uip[unit_no].hf.nrcyls - 1); /* hiCyl */
1.1.1.3   root     2791:     put_long (parmpacket + 60, 0); /* Number of buffers */
                   2792:     put_long (parmpacket + 64, 0); /* Buffer mem type */
                   2793:     put_long (parmpacket + 68, 0x7FFFFFFF); /* largest transfer */
                   2794:     put_long (parmpacket + 72, ~1); /* addMask (?) */
                   2795:     put_long (parmpacket + 76, (uae_u32)-1); /* bootPri */
                   2796:     put_long (parmpacket + 80, 0x444f5300); /* DOS\0 */
                   2797:     put_long (parmpacket + 84, 0); /* pad */
                   2798: 
1.1.1.4 ! root     2799:     return is_hardfile (current_mountinfo, unit_no);
1.1       root     2800: }
                   2801: 
1.1.1.3   root     2802: void filesys_install (void)
1.1       root     2803: {
                   2804:     int i;
1.1.1.3   root     2805:     uaecptr loop;
                   2806: 
1.1.1.4 ! root     2807:     TRACE (("Installing filesystem\n"));
1.1       root     2808: 
                   2809:     ROM_filesys_resname = ds("UAEunixfs.resource");
1.1.1.3   root     2810:     ROM_filesys_resid = ds("UAE unixfs 0.4");
1.1       root     2811: 
1.1.1.4 ! root     2812:     fsdevname = ds ("uae.device"); /* does not really exist */
1.1       root     2813: 
                   2814:     ROM_filesys_diagentry = here();
1.1.1.3   root     2815:     calltrap (deftrap(filesys_diagentry)); dw(RTS);
                   2816: 
                   2817:     loop = here ();
                   2818:     /* Special trap for the assembly make_dev routine */
1.1.1.4 ! root     2819:     org (0xF0FF20);
1.1.1.3   root     2820:     calltrap (deftrap (filesys_dev_remember));
1.1.1.4 ! root     2821:     dw (RTS);
1.1.1.3   root     2822: 
1.1.1.4 ! root     2823:     org (0xF0FF28);
1.1.1.3   root     2824:     calltrap (deftrap (filesys_dev_storeinfo));
1.1.1.4 ! root     2825:     dw (RTS);
1.1.1.3   root     2826: 
1.1.1.4 ! root     2827:     org (0xF0FF30);
1.1.1.3   root     2828:     calltrap (deftrap (filesys_handler));
1.1.1.4 ! root     2829:     dw (RTS);
1.1.1.3   root     2830: 
1.1.1.4 ! root     2831:     org (0xF0FF40);
1.1.1.3   root     2832:     calltrap (deftrap (startup_handler));
1.1.1.4 ! root     2833:     dw (RTS);
1.1.1.3   root     2834: 
1.1.1.4 ! root     2835:     org (0xF0FF50);
1.1.1.3   root     2836:     calltrap (deftrap (exter_int_helper));
1.1.1.4 ! root     2837:     dw (RTS);
1.1.1.3   root     2838: 
1.1.1.4 ! root     2839:     org (0xF0FF70);
1.1.1.3   root     2840:     calltrap (deftrap (mousehack_helper));
1.1.1.4 ! root     2841:     dw (RTS);
1.1.1.3   root     2842: 
                   2843:     org (loop);
                   2844: }
                   2845: 
                   2846: void filesys_install_code (void)
                   2847: {
1.1       root     2848:     align(4);
                   2849: 
1.1.1.3   root     2850:     /* The last offset comes from the code itself, look for it near the top. */
                   2851:     filesys_initcode = here() + 8 + 0x6c;
                   2852:     EXPANSION_bootcode = here () + 8 + 0x14;
                   2853:     /* Ouch. Make sure this is _always_ a multiple of two bytes. */
                   2854:  db(0x00); db(0x00); db(0x00); db(0x10); db(0x00); db(0x00); db(0x00); db(0x00);
                   2855:  db(0x60); db(0x00); db(0x01); db(0xc0); db(0x00); db(0x00); db(0x01); db(0x2c);
                   2856:  db(0x00); db(0x00); db(0x00); db(0x6c); db(0x00); db(0x00); db(0x00); db(0x28);
                   2857:  db(0x00); db(0x00); db(0x00); db(0x14); db(0x43); db(0xfa); db(0x02); db(0xf9);
                   2858:  db(0x4e); db(0xae); db(0xff); db(0xa0); db(0x20); db(0x40); db(0x20); db(0x28);
                   2859:  db(0x00); db(0x16); db(0x20); db(0x40); db(0x4e); db(0x90); db(0x4e); db(0x75);
                   2860:  db(0x48); db(0xe7); db(0x00); db(0x20); db(0x70); db(0x00); db(0x4e); db(0xb9);
                   2861:  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x2e);
                   2862:  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x02); db(0x4e); db(0xb9);
                   2863:  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x14);
                   2864:  db(0x24); db(0x40); db(0x70); db(0x03); db(0x4e); db(0xb9); db(0x00); db(0xf0);
                   2865:  db(0xff); db(0x50); db(0x20); db(0x4a); db(0x22); db(0x40); db(0x4e); db(0xae);
                   2866:  db(0xfe); db(0x92); db(0x60); db(0xe0); db(0x70); db(0x04); db(0x4e); db(0xb9);
                   2867:  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x70); db(0x01); db(0x4c); db(0xdf);
                   2868:  db(0x04); db(0x00); db(0x4e); db(0x75); db(0x48); db(0xe7); db(0xff); db(0xfe);
                   2869:  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x2a); db(0x79); db(0x00); db(0xf0);
                   2870:  db(0xff); db(0xfc); db(0x43); db(0xfa); db(0x02); db(0x9f); db(0x70); db(0x24);
                   2871:  db(0x7a); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x4a); db(0x80);
                   2872:  db(0x66); db(0x0c); db(0x43); db(0xfa); db(0x02); db(0x8f); db(0x70); db(0x00);
                   2873:  db(0x7a); db(0x01); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x28); db(0x40);
                   2874:  db(0x70); db(0x58); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
                   2875:  db(0x26); db(0x40); db(0x7e); db(0x54); db(0x27); db(0xb5); db(0x78); db(0x00);
                   2876:  db(0x78); db(0x00); db(0x59); db(0x87); db(0x64); db(0xf6); db(0x7c); db(0x00);
                   2877:  db(0xbc); db(0xad); db(0x01); db(0x0c); db(0x64); db(0x12); db(0x20); db(0x4b);
                   2878:  db(0x48); db(0xe7); db(0x02); db(0x10); db(0x7e); db(0x01); db(0x61); db(0x6c);
                   2879:  db(0x4c); db(0xdf); db(0x08); db(0x40); db(0x52); db(0x86); db(0x60); db(0xe8);
                   2880:  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x22); db(0x4c); db(0x4e); db(0xae);
                   2881:  db(0xfe); db(0x62); db(0x61); db(0x28); db(0x2c); db(0x78); db(0x00); db(0x04);
                   2882:  db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x80); db(0x72); db(0x03);
                   2883:  db(0x74); db(0xf6); db(0x20); db(0x7c); db(0x00); db(0x20); db(0x00); db(0x00);
                   2884:  db(0x90); db(0x88); db(0x65); db(0x0a); db(0x67); db(0x08); db(0x78); db(0x00);
                   2885:  db(0x22); db(0x44); db(0x4e); db(0xae); db(0xfd); db(0x96); db(0x4c); db(0xdf);
                   2886:  db(0x7f); db(0xff); db(0x4e); db(0x75); db(0x2c); db(0x78); db(0x00); db(0x04);
                   2887:  db(0x70); db(0x1a); db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01);
                   2888:  db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x22); db(0x40); db(0x41); db(0xfa);
                   2889:  db(0x01); db(0xf0); db(0x23); db(0x48); db(0x00); db(0x0a); db(0x41); db(0xfa);
                   2890:  db(0xff); db(0x10); db(0x23); db(0x48); db(0x00); db(0x0e); db(0x41); db(0xfa);
                   2891:  db(0xff); db(0x08); db(0x23); db(0x48); db(0x00); db(0x12); db(0x70); db(0x0d);
                   2892:  db(0x4e); db(0xee); db(0xff); db(0x58); db(0x2a); db(0x79); db(0x00); db(0xf0);
                   2893:  db(0xff); db(0xfc); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x28);
                   2894:  db(0x26); db(0x00); db(0xc0); db(0x85); db(0x66); db(0xbc); db(0x2c); db(0x4c);
                   2895:  db(0x4e); db(0xae); db(0xff); db(0x70); db(0x26); db(0x40); db(0x4e); db(0xb9);
                   2896:  db(0x00); db(0xf0); db(0xff); db(0x20); db(0x70); db(0x00); db(0x27); db(0x40);
                   2897:  db(0x00); db(0x08); db(0x27); db(0x40); db(0x00); db(0x10); db(0x27); db(0x40);
                   2898:  db(0x00); db(0x20); db(0x4a); db(0x83); db(0x66); db(0x1c); db(0x27); db(0x7c);
                   2899:  db(0x00); db(0x00); db(0x0f); db(0xa0); db(0x00); db(0x14); db(0x43); db(0xfa);
                   2900:  db(0xfe); db(0x94); db(0x20); db(0x09); db(0xe4); db(0x88); db(0x27); db(0x40);
                   2901:  db(0x00); db(0x20); db(0x27); db(0x7c); db(0xff); db(0xff); db(0xff); db(0xff);
                   2902:  db(0x00); db(0x24); db(0x4a); db(0x87); db(0x67); db(0x36); db(0x2c); db(0x78);
                   2903:  db(0x00); db(0x04); db(0x70); db(0x14); db(0x72); db(0x00); db(0x4e); db(0xae);
                   2904:  db(0xff); db(0x3a); db(0x22); db(0x40); db(0x70); db(0x00); db(0x22); db(0x80);
                   2905:  db(0x23); db(0x40); db(0x00); db(0x04); db(0x33); db(0x40); db(0x00); db(0x0e);
                   2906:  db(0x30); db(0x3c); db(0x10); db(0xff); db(0x90); db(0x06); db(0x33); db(0x40);
                   2907:  db(0x00); db(0x08); db(0x23); db(0x6d); db(0x01); db(0x04); db(0x00); db(0x0a);
                   2908:  db(0x23); db(0x4b); db(0x00); db(0x10); db(0x41); db(0xec); db(0x00); db(0x4a);
                   2909:  db(0x4e); db(0xee); db(0xfe); db(0xf2); db(0x20); db(0x4b); db(0x72); db(0x00);
                   2910:  db(0x22); db(0x41); db(0x70); db(0xff); db(0x2c); db(0x4c); db(0x4e); db(0xee);
                   2911:  db(0xff); db(0x6a); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x00);
                   2912:  db(0x22); db(0x40); db(0x4e); db(0xae); db(0xfe); db(0xda); db(0x20); db(0x40);
                   2913:  db(0x4b); db(0xe8); db(0x00); db(0x5c); db(0x43); db(0xfa); db(0x01); db(0x39);
                   2914:  db(0x70); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x24); db(0x40);
                   2915:  db(0x20); db(0x3c); db(0x00); db(0x00); db(0x00); db(0x9d); db(0x22); db(0x3c);
                   2916:  db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
                   2917:  db(0x26); db(0x40); db(0x7c); db(0x00); db(0x26); db(0x86); db(0x27); db(0x46);
                   2918:  db(0x00); db(0x04); db(0x27); db(0x46); db(0x00); db(0x08); db(0x7a); db(0x00);
                   2919:  db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x80); db(0x20); db(0x4d);
                   2920:  db(0x4e); db(0xae); db(0xfe); db(0x8c); db(0x28); db(0x40); db(0x26); db(0x2c);
                   2921:  db(0x00); db(0x0a); db(0x70); db(0x00); db(0x4e); db(0xb9); db(0x00); db(0xf0);
                   2922:  db(0xff); db(0x40); db(0x60); db(0x74); db(0x20); db(0x4d); db(0x4e); db(0xae);
                   2923:  db(0xfe); db(0x80); db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x8c);
                   2924:  db(0x28); db(0x40); db(0x26); db(0x2c); db(0x00); db(0x0a); db(0x66); db(0x38);
                   2925:  db(0x70); db(0x01); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x50);
                   2926:  db(0x45); db(0xeb); db(0x00); db(0x04); db(0x20); db(0x52); db(0x20); db(0x08);
                   2927:  db(0x67); db(0xda); db(0x22); db(0x50); db(0x20); db(0x40); db(0x20); db(0x28);
                   2928:  db(0x00); db(0x04); db(0x6a); db(0x16); db(0x48); db(0xe7); db(0x00); db(0xc0);
                   2929:  db(0x28); db(0x68); db(0x00); db(0x0a); db(0x61); db(0x40); db(0x53); db(0x85);
                   2930:  db(0x4c); db(0xdf); db(0x03); db(0x00); db(0x24); db(0x89); db(0x20); db(0x49);
                   2931:  db(0x60); db(0xdc); db(0x24); db(0x48); db(0x20); db(0x49); db(0x60); db(0xd6);
                   2932:  db(0xba); db(0xbc); db(0x00); db(0x00); db(0x00); db(0x14); db(0x65); db(0x08);
                   2933:  db(0x70); db(0x01); db(0x29); db(0x40); db(0x00); db(0x04); db(0x60); db(0x0e);
                   2934:  db(0x61); db(0x2a); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x30);
                   2935:  db(0x4a); db(0x80); db(0x67); db(0x0c); db(0x52); db(0x85); db(0x28); db(0xab);
                   2936:  db(0x00); db(0x04); db(0x27); db(0x4c); db(0x00); db(0x04); db(0x60); db(0x8c);
                   2937:  db(0x28); db(0x43); db(0x61); db(0x02); db(0x60); db(0x86); db(0x22); db(0x54);
                   2938:  db(0x20); db(0x6c); db(0x00); db(0x04); db(0x29); db(0x4d); db(0x00); db(0x04);
                   2939:  db(0x4e); db(0xee); db(0xfe); db(0x92); db(0x2f); db(0x05); db(0x7a); db(0xfc);
                   2940:  db(0x24); db(0x53); db(0x2e); db(0x0a); db(0x22); db(0x0a); db(0x67); db(0x0a);
                   2941:  db(0x52); db(0x85); db(0x67); db(0x1e); db(0x22); db(0x4a); db(0x24); db(0x52);
                   2942:  db(0x60); db(0xf2); db(0x52); db(0x85); db(0x67); db(0x3c); db(0x24); db(0x47);
                   2943:  db(0x70); db(0x18); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
                   2944:  db(0x52); db(0x46); db(0x24); db(0x40); db(0x24); db(0x87); db(0x2e); db(0x0a);
                   2945:  db(0x60); db(0xe8); db(0x20); db(0x12); db(0x67); db(0x24); db(0x20); db(0x40);
                   2946:  db(0x20); db(0x10); db(0x67); db(0x1e); db(0x20); db(0x40); db(0x20); db(0x10);
                   2947:  db(0x67); db(0x18); db(0x70); db(0x00); db(0x22); db(0x80); db(0x22); db(0x4a);
                   2948:  db(0x24); db(0x51); db(0x70); db(0x18); db(0x4e); db(0xae); db(0xff); db(0x2e);
                   2949:  db(0xdc); db(0xbc); db(0x00); db(0x01); db(0x00); db(0x00); db(0x20); db(0x0a);
                   2950:  db(0x66); db(0xec); db(0x26); db(0x87); db(0x2a); db(0x1f); db(0x4e); db(0x75);
                   2951:  db(0x55); db(0x41); db(0x45); db(0x20); db(0x66); db(0x69); db(0x6c); db(0x65);
                   2952:  db(0x73); db(0x79); db(0x73); db(0x74); db(0x65); db(0x6d); db(0x00); db(0x64);
                   2953:  db(0x6f); db(0x73); db(0x2e); db(0x6c); db(0x69); db(0x62); db(0x72); db(0x61);
                   2954:  db(0x72); db(0x79); db(0x00); db(0x65); db(0x78); db(0x70); db(0x61); db(0x6e);
                   2955:  db(0x73); db(0x69); db(0x6f); db(0x6e); db(0x2e); db(0x6c); db(0x69); db(0x62);
                   2956:  db(0x72); db(0x61); db(0x72); db(0x79); db(0x00); db(0x00);
1.1       root     2957: }

unix.superglobalmegacorp.com

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