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

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

unix.superglobalmegacorp.com

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