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

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

unix.superglobalmegacorp.com

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