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

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

unix.superglobalmegacorp.com

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