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

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

unix.superglobalmegacorp.com

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