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

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

unix.superglobalmegacorp.com

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