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

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

unix.superglobalmegacorp.com

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