--- uae/src/filesys.c 2018/04/24 16:40:09 1.1.1.3 +++ uae/src/filesys.c 2018/04/24 17:22:13 1.1.1.23 @@ -14,7 +14,7 @@ * * Known limitations: * Does not support ACTION_INHIBIT (big deal). - * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK) + * Does not support several 2.0+ packet types. * Does not support removable volumes. * May not return the correct error code in some cases. * Does not check for sane values passed by AmigaDOS. May crash the emulation @@ -27,62 +27,46 @@ #include "sysconfig.h" #include "sysdeps.h" -#include "config.h" +#include "threaddep/thread.h" #include "options.h" #include "uae.h" #include "memory.h" #include "custom.h" -#include "readcpu.h" +#include "events.h" #include "newcpu.h" #include "filesys.h" +#include "traps.h" #include "autoconf.h" -#include "compiler.h" -#include "zfile.h" -#include "threaddep/penguin.h" - -/* #define TRACING_ENABLED */ -#ifdef TRACING_ENABLED -#define TRACE(x) do { sprintf x; write_log(warning_buffer); } while(0) +#include "fsusage.h" +#include "native2amiga.h" +#include "scsidev.h" +#include "fsdb.h" + +/* Count the number of FS packets waiting to be serviced, for the benefit + * of the idle on STOP code. */ +int active_fs_packets; +uae_sem_t packet_counter_sem; + +#define TRACING_ENABLED 0 +#if TRACING_ENABLED +#define TRACE(x) do { write_log x; } while(0) #define DUMPLOCK(u,x) dumplock(u,x) #else #define TRACE(x) #define DUMPLOCK(u,x) #endif -#define MAKE_CASE_INSENSITIVE - -/* errors */ -#define ERROR_NO_FREE_STORE 103 -#define ERROR_OBJECT_IN_USE 202 -#define ERROR_OBJECT_EXISTS 203 -#define ERROR_DIR_NOT_FOUND 204 -#define ERROR_OBJECT_NOT_FOUND 205 -#define ERROR_ACTION_NOT_KNOWN 209 -#define ERROR_INVALID_LOCK 211 -#define ERROR_OBJECT_WRONG_TYPE 212 -#define ERROR_DISK_WRITE_PROTECTED 214 -#define ERROR_DIRECTORY_NOT_EMPTY 216 -#define ERROR_DEVICE_NOT_MOUNTED 218 -#define ERROR_SEEK_ERROR 219 -#define ERROR_DISK_FULL 221 -#define ERROR_DELETE_PROTECTED 222 -#define ERROR_WRITE_PROTECTED 223 -#define ERROR_READ_PROTECTED 224 -#define ERROR_NO_MORE_ENTRIES 232 -#define ERROR_NOT_IMPLEMENTED 236 - -#ifndef DONT_HAVE_POSIX static long dos_errno(void) { int e = errno; - switch(e) { + switch (e) { case ENOMEM: return ERROR_NO_FREE_STORE; case EEXIST: return ERROR_OBJECT_EXISTS; case EACCES: return ERROR_WRITE_PROTECTED; - case ENOENT: return ERROR_OBJECT_NOT_FOUND; + case ENOENT: return ERROR_OBJECT_NOT_AROUND; case ENOTDIR: return ERROR_OBJECT_WRONG_TYPE; - case ENOSPC: return ERROR_DISK_FULL; + case ENOSPC: return ERROR_DISK_IS_FULL; case EBUSY: return ERROR_OBJECT_IN_USE; case EISDIR: return ERROR_OBJECT_WRONG_TYPE; #if defined(ETXTBSY) @@ -98,16 +82,17 @@ static long dos_errno(void) #endif default: - TRACE((warning_buffer, "Unimplemented error %s\n", strerror(e))); + TRACE(("Unimplemented error %s\n", strerror(e))); return ERROR_NOT_IMPLEMENTED; } } -#endif /* * This _should_ be no issue for us, but let's rather use a guaranteed * thread safe function if we have one. - * Well, let's use it once it works. + * This used to be broken in glibc versions <= 2.0.1 (I think). I hope + * no one is using this these days. + * Michael Krause says it's also broken in libc5. ARRRGHHHHHH!!!! */ #if 0 && defined HAVE_READDIR_R @@ -125,22 +110,13 @@ static struct dirent *my_readdir (DIR *d #define my_readdir(dirstream, space) readdir(dirstream) #endif +uaecptr filesys_initcode; +static uae_u32 fsdevname, filesys_configdev; + #define FS_STARTUP 0 #define FS_GO_DOWN 1 -/* AmigaOS "keys" */ -struct a_inode { - struct a_inode *next, *prev; - struct a_inode *parent; - struct a_inode *child, *sibling; /* @@@ implement hash tables or something to make this efficient */ - char *aname; - char *nname; - int amigaos_mode; - int shlock; - uae_u32 uniq; - unsigned int dir:1; - unsigned int elock:1; -}; +#define DEVNAMES_PER_HDF 32 typedef struct { char *devname; /* device name, e.g. UAE0: */ @@ -149,115 +125,333 @@ typedef struct { char *volname; /* volume name, e.g. CDROM, WORK, etc. */ char *rootdir; /* root unix directory */ int readonly; /* disallow write access? */ + int bootpri; int devno; - + struct hardfiledata hf; /* Threading stuff */ smp_comm_pipe *unit_pipe, *back_pipe; - penguin_id tid; + uae_thread_id tid; struct _unit *volatile self; + /* Reset handling */ + uae_sem_t reset_sync_sem; + int reset_state; + + /* RDB stuff */ + uaecptr rdb_devname_amiga[DEVNAMES_PER_HDF]; + int rdb_lowcyl; + int rdb_highcyl; + int rdb_cylblocks; + uae_u8 *rdb_filesysstore; + int rdb_filesyssize; + char *filesysdir; } UnitInfo; #define MAX_UNITS 20 -static int num_units = 0, num_filesys_units = 0; -static UnitInfo ui[MAX_UNITS]; -uaecptr filesys_initcode; -static uae_u32 fsdevname, hardfileseglist, filesys_configdev; -static uaecptr filesys_parampacket; -char * add_filesys_unit(char *volname, char *rootdir, int readonly, - int secspertrack, int surfaces, int reserved) +struct uaedev_mount_info { + int num_units; + UnitInfo ui[MAX_UNITS]; +}; + +static struct uaedev_mount_info *current_mountinfo; + +int nr_units (struct uaedev_mount_info *mountinfo) { - UnitInfo *uip; - if (num_units >= MAX_UNITS) { - return "Maximum number of file systems mounted"; + return mountinfo->num_units; +} + +int hardfile_fs_type (struct uaedev_mount_info *mountinfo, int unit_no) +{ + if (mountinfo->ui[unit_no].volname) + return FILESYS_VIRTUAL; + + if (mountinfo->ui[unit_no].hf.secspertrack == 0) { +#if 0 + if (mountinfo->ui[unit_no].hf.flags & 1) + return FILESYS_HARDDRIVE; +#endif + return FILESYS_HARDFILE_RDB; } - uip = ui + num_units; + return FILESYS_HARDFILE; +} + +static void close_filesys_unit (UnitInfo *uip) +{ + if (uip->hf.fd != 0) + fclose (uip->hf.fd); + if (uip->volname != 0) + free (uip->volname); + if (uip->devname != 0) + free (uip->devname); + if (uip->rootdir != 0) + free (uip->rootdir); + if (uip->unit_pipe) + free (uip->unit_pipe); + if (uip->back_pipe) + free (uip->back_pipe); + + uip->unit_pipe = 0; + uip->back_pipe = 0; + + uip->hf.fd = 0; + uip->volname = 0; + uip->devname = 0; + uip->rootdir = 0; +} + +char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, + char **devname, char **volname, char **rootdir, + int *readonly, int *secspertrack, int *surfaces, int *reserved, + int *cylinders, int *size, int *blocksize, int *bootpri) +{ + UnitInfo *uip = mountinfo->ui + nr; + + if (nr >= mountinfo->num_units) + return "No slot allocated for this unit"; + + *volname = uip->volname ? my_strdup (uip->volname) : 0; + *devname = uip->devname ? my_strdup (uip->devname) : 0; + *rootdir = uip->rootdir ? my_strdup (uip->rootdir) : 0; + *readonly = uip->readonly; + *secspertrack = uip->hf.secspertrack; + *surfaces = uip->hf.surfaces; + *reserved = uip->hf.reservedblocks; + *size = uip->hf.size; + *cylinders = uip->hf.nrcyls; + *blocksize = uip->hf.blocksize; + *bootpri = uip->bootpri; + return 0; +} + +static char *set_filesys_unit_1 (struct uaedev_mount_info *mountinfo, int nr, + const char *devname, const char *volname, const char *rootdir, + int readonly, int secspertrack, int surfaces, int reserved, + int blocksize, int bootpri) +{ + UnitInfo *ui = mountinfo->ui + nr; + + if (nr >= mountinfo->num_units) + return "No slot allocated for this unit"; + + ui->hf.fd = 0; + ui->devname = 0; + ui->volname = 0; + ui->rootdir = 0; + ui->unit_pipe = 0; + ui->back_pipe = 0; + if (volname != 0) { - num_filesys_units++; - uip->volname = my_strdup(volname); - uip->hf.fd = 0; + ui->volname = my_strdup (volname); + ui->hf.fd = 0; } else { - FILE *hf; - - uip->volname = 0; - uip->hf.fd = zfile_open (rootdir, "r+b"); - if (uip->hf.fd == 0) { + ui->volname = 0; + ui->hf.fd = fopen (rootdir, "r+b"); + if (ui->hf.fd == 0) { readonly = 1; - uip->hf.fd = zfile_open (rootdir, "rb"); + ui->hf.fd = fopen (rootdir, "rb"); } - if (uip->hf.fd == 0) { + if (ui->hf.fd == 0) return "Hardfile not found"; - } - if (secspertrack < 1 || secspertrack > 32767 - || surfaces < 1 || surfaces > 1023 - || reserved < 0 || reserved > 1023) { + + if ((secspertrack || surfaces || reserved) + && (secspertrack < 1 || secspertrack > 32767 + || surfaces < 1 || surfaces > 1023 + || reserved < 0 || reserved > 1023 + || (blocksize & (blocksize - 1)) != 0)) + { return "Bad hardfile geometry"; } - fseek (uip->hf.fd, 0, SEEK_END); - uip->hf.size = ftell (uip->hf.fd); - uip->hf.secspertrack = secspertrack; - uip->hf.surfaces = surfaces; - uip->hf.reservedblocks = reserved; - uip->hf.nrcyls = (uip->hf.size >> 9) / (secspertrack * surfaces); - } - uip->rootdir = my_strdup (rootdir); - uip->readonly = readonly; + fseek (ui->hf.fd, 0, SEEK_END); + ui->hf.size = ftell (ui->hf.fd); + ui->hf.secspertrack = secspertrack; + ui->hf.surfaces = surfaces; + ui->hf.reservedblocks = reserved; + ui->hf.nrcyls = (secspertrack * surfaces + ? (ui->hf.size / blocksize) / (secspertrack * surfaces) + : 0); + ui->hf.blocksize = blocksize; + } + ui->self = 0; + ui->reset_state = FS_STARTUP; + ui->rootdir = my_strdup (rootdir); + if (devname != 0 && strlen (devname) != 0) + ui->devname = my_strdup (devname); + ui->readonly = readonly; + if (bootpri < -128) + bootpri = -128; + if (bootpri > 127) + bootpri = 127; + ui->bootpri = bootpri; - num_units++; return 0; } -int kill_filesys_unit (int nr) +char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, + const char *devname, const char *volname, const char *rootdir, + int readonly, int secspertrack, int surfaces, int reserved, + int blocksize, int bootpri) +{ + UnitInfo ui = mountinfo->ui[nr]; + char *result = set_filesys_unit_1 (mountinfo, nr, devname, volname, rootdir, + readonly, secspertrack, surfaces, reserved, + blocksize, bootpri); + if (result) + mountinfo->ui[nr] = ui; + else + close_filesys_unit (&ui); + + return result; +} + +char *add_filesys_unit (struct uaedev_mount_info *mountinfo, + const char *devname, const char *volname, const char *rootdir, + int readonly, int secspertrack, int surfaces, int reserved, + int blocksize, int bootpri) +{ + char *retval; + int nr = mountinfo->num_units; + UnitInfo *uip = mountinfo->ui + nr; + + if (nr >= MAX_UNITS) + return "Maximum number of file systems mounted"; + + mountinfo->num_units++; + retval = set_filesys_unit_1 (mountinfo, nr, devname, volname, rootdir, readonly, + secspertrack, surfaces, reserved, blocksize, + bootpri); + if (retval) + mountinfo->num_units--; + return retval; +} + +int kill_filesys_unit (struct uaedev_mount_info *mountinfo, int nr) { - if (nr > num_units || nr < 0) + UnitInfo *uip = mountinfo->ui; + if (nr >= mountinfo->num_units || nr < 0) return -1; - if (ui[nr].hf.fd != 0) - fclose (ui[nr].hf.fd); - num_units--; - for (; nr < num_units; nr++) { - ui[nr] = ui[nr+1]; + close_filesys_unit (mountinfo->ui + nr); + + mountinfo->num_units--; + for (; nr < mountinfo->num_units; nr++) { + uip[nr] = uip[nr+1]; } return 0; } -struct hardfiledata *get_hardfile_data (int nr) +int move_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, int to) { - if (nr < 0 || nr >= num_units || ui[nr].volname != 0) - return 0; - return &ui[nr].hf; + UnitInfo tmpui; + UnitInfo *uip = mountinfo->ui; + + if (nr >= mountinfo->num_units || nr < 0 + || to >= mountinfo->num_units || to < 0 + || to == nr) + return -1; + tmpui = uip[nr]; + if (to > nr) { + int i; + for (i = nr; i < to; i++) + uip[i] = uip[i + 1]; + } else { + int i; + for (i = nr; i > to; i--) + uip[i] = uip[i - 1]; + } + uip[to] = tmpui; + return 0; } -int sprintf_filesys_unit(char *buffer, int num) +int sprintf_filesys_unit (struct uaedev_mount_info *mountinfo, char *buffer, int num) { - if (num >= num_units) + UnitInfo *uip = mountinfo->ui; + if (num >= mountinfo->num_units) return -1; - - if (ui[num].volname != 0) - sprintf (buffer, "(UAE%d:) Filesystem, %s: %s %s", num, ui[num].volname, - ui[num].rootdir, ui[num].readonly ? "ro" : ""); + + if (uip[num].volname != 0) + sprintf (buffer, "(DH%d:) Filesystem, %s: %s %s", num, uip[num].volname, + uip[num].rootdir, uip[num].readonly ? "ro" : ""); else - sprintf (buffer, "(UAE%d:) Hardfile, \"%s\", size %d bytes", num, - ui[num].rootdir, ui[num].hf.size); + sprintf (buffer, "(DH%d:) Hardfile, \"%s\", size %d bytes", num, + uip[num].rootdir, uip[num].hf.size); return 0; } -void write_filesys_config(FILE *f) +void write_filesys_config (struct uaedev_mount_info *mountinfo, + const char *unexpanded, const char *default_path, FILE *f) { + UnitInfo *uip = mountinfo->ui; int i; - for (i = 0; i < num_units; i++) { - if (ui[i].volname != 0) { - fprintf(f, "-%c %s:%s\n", ui[i].readonly ? 'M' : 'm', - ui[i].volname, ui[i].rootdir); + + for (i = 0; i < mountinfo->num_units; i++) { + char *str; + str = cfgfile_subst_path (default_path, unexpanded, uip[i].rootdir); + if (hardfile_fs_type (mountinfo, i) == FILESYS_VIRTUAL) { + fprintf (f, "filesystem2=%s,%s:%s:%s,%d\n", uip[i].readonly ? "ro" : "rw", + "", uip[i].volname, str, uip[i].bootpri); + fprintf (f, "filesystem=%s,%s:%s\n", uip[i].readonly ? "ro" : "rw", + uip[i].volname, str); } else { - fprintf(f, "-W %d:%d:%d:%s\n", ui[i].hf.secspertrack, - ui[i].hf.surfaces, ui[i].hf.reservedblocks, - ui[i].rootdir); + fprintf (f, "hardfile2=%s,%s:%s,%d,%d,%d,%d,%d,%s,%s\n", + uip[i].readonly ? "ro" : "rw", + "", str, + uip[i].hf.secspertrack, + uip[i].hf.surfaces, uip[i].hf.reservedblocks, + uip[i].hf.blocksize, uip[i].bootpri, "", "uae"); + fprintf (f, "hardfile=%s,%d,%d,%d,%d,%s\n", + uip[i].readonly ? "ro" : "rw", uip[i].hf.secspertrack, + uip[i].hf.surfaces, uip[i].hf.reservedblocks, + uip[i].hf.blocksize, str); } + free (str); + } +} + +struct uaedev_mount_info *alloc_mountinfo (void) +{ + struct uaedev_mount_info *info; + info = (struct uaedev_mount_info *)malloc (sizeof *info); + /* memset (info, 0xaa, sizeof *info);*/ + info->num_units = 0; + return info; +} + +struct uaedev_mount_info *dup_mountinfo (struct uaedev_mount_info *mip) +{ + int i; + struct uaedev_mount_info *i2 = alloc_mountinfo (); + + memcpy (i2, mip, sizeof *i2); + + for (i = 0; i < i2->num_units; i++) { + UnitInfo *uip = i2->ui + i; + if (uip->volname) + uip->volname = my_strdup (uip->volname); + if (uip->rootdir) + uip->rootdir = my_strdup (uip->rootdir); + if (uip->hf.fd) + uip->hf.fd = fdopen ( dup (fileno (uip->hf.fd)), uip->readonly ? "rb" : "r+b"); } + return i2; +} + +void free_mountinfo (struct uaedev_mount_info *mip) +{ + int i; + for (i = 0; i < mip->num_units; i++) + close_filesys_unit (mip->ui + i); + free (mip); +} + +struct hardfiledata *get_hardfile_data (int nr) +{ + UnitInfo *uip = current_mountinfo->ui; + if (nr < 0 || nr >= current_mountinfo->num_units || uip[nr].volname != 0) + return 0; + return &uip[nr].hf; } /* minimal AmigaDOS definitions */ @@ -272,9 +466,15 @@ void write_filesys_config(FILE *f) #define dp_Arg4 32 /* result codes */ -#define DOS_TRUE ((unsigned long)-1L) +#define DOS_TRUE (0xffffffffUL) #define DOS_FALSE (0L) +/* Passed as type to Lock() */ +#define SHARED_LOCK -2 /* File is readable by others */ +#define ACCESS_READ -2 /* Synonym */ +#define EXCLUSIVE_LOCK -1 /* No other access allowed */ +#define ACCESS_WRITE -1 /* Synonym */ + /* packet types */ #define ACTION_CURRENT_VOLUME 7 #define ACTION_LOCATE_OBJECT 8 @@ -325,13 +525,15 @@ void write_filesys_config(FILE *f) typedef struct { uae_u32 uniq; - struct a_inode *aino; - DIR* dir; + /* The directory we're going through. */ + a_inode *aino; + /* The file we're going to look up next. */ + a_inode *curr_file; } ExamineKey; typedef struct key { struct key *next; - struct a_inode *aino; + a_inode *aino; uae_u32 uniq; int fd; off_t file_pos; @@ -350,40 +552,37 @@ typedef struct _unit { struct _unit *next; /* Amiga stuff */ - uaecptr dosbase; - uaecptr volume; - uaecptr port; /* Our port */ - uaecptr locklist; + uaecptr dosbase; + uaecptr volume; + uaecptr port; /* Our port */ + uaecptr locklist; /* Native stuff */ - uae_s32 unit; /* unit number */ - UnitInfo ui; /* unit startup info */ - char tmpbuf3[256]; + uae_s32 unit; /* unit number */ + UnitInfo ui; /* unit startup info */ + char tmpbuf3[256]; /* Dummy message processing */ - uaecptr dummy_message; + uaecptr dummy_message; volatile unsigned int cmds_sent; volatile unsigned int cmds_complete; volatile unsigned int cmds_acked; /* ExKeys */ - ExamineKey examine_keys[EXKEYS]; - int next_exkey; + ExamineKey examine_keys[EXKEYS]; + int next_exkey; + unsigned long total_locked_ainos; /* Keys */ - struct key* keys; - uae_u32 key_uniq; - uae_u32 a_uniq; + struct key *keys; + uae_u32 key_uniq; + uae_u32 a_uniq; - struct a_inode rootnode; + a_inode rootnode; unsigned long aino_cache_size; - struct a_inode *aino_hash[MAX_AINO_HASH]; + a_inode *aino_hash[MAX_AINO_HASH]; unsigned long nr_cache_hits; unsigned long nr_cache_lookups; - - /* Reset handling */ - uae_sem_t reset_sync_sem; - int reset_state; } Unit; typedef uae_u8 *dpacket; @@ -401,11 +600,11 @@ static char *bstr1 (uaecptr addr) { static char buf[256]; int i; - int n = get_byte(addr); + int n = get_byte (addr); addr++; - for(i = 0; i < n; i++, addr++) - buf[i] = get_byte(addr); + for (i = 0; i < n; i++, addr++) + buf[i] = get_byte (addr); buf[i] = 0; return buf; } @@ -413,11 +612,11 @@ static char *bstr1 (uaecptr addr) static char *bstr (Unit *unit, uaecptr addr) { int i; - int n = get_byte(addr); + int n = get_byte (addr); addr++; - for(i = 0; i < n; i++, addr++) - unit->tmpbuf3[i] = get_byte(addr); + for (i = 0; i < n; i++, addr++) + unit->tmpbuf3[i] = get_byte (addr); unit->tmpbuf3[i] = 0; return unit->tmpbuf3; } @@ -429,8 +628,8 @@ static char *bstr_cut (Unit *unit, uaecp int n = get_byte (addr); addr++; - for(i = 0; i < n; i++, addr++) { - uae_u8 c = get_byte(addr); + for (i = 0; i < n; i++, addr++) { + uae_u8 c = get_byte (addr); unit->tmpbuf3[i] = c; if (c == '/' || (c == ':' && colon_seen++ == 0)) p = unit->tmpbuf3 + i + 1; @@ -443,72 +642,16 @@ static Unit *units = 0; static int unit_num = 0; static Unit* -find_unit(uaecptr port) +find_unit (uaecptr port) { Unit* u; - for(u = units; u; u = u->next) - if(u->port == port) + for (u = units; u; u = u->next) + if (u->port == port) break; return u; } -static int get_file_attrs (struct a_inode *aino) -{ - struct stat statbuf; - if (-1 == stat (aino->nname, &statbuf)) - return dos_errno (); - aino->dir = S_ISDIR (statbuf.st_mode) ? 1 : 0; - aino->amigaos_mode = -#ifndef __DOS__ - (S_IXUSR & statbuf.st_mode ? 0 : A_FIBF_EXECUTE) | -#endif - (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_WRITE) | -#if 0 /* This makes it impossible to overwrite those. */ - (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_DELETE) | -#endif - (S_IRUSR & statbuf.st_mode ? 0 : A_FIBF_READ); - return 0; -}; - -static int set_file_attrs (struct a_inode *aino, int mask) -{ - struct stat statbuf; - int mode; - - if (-1 == stat(aino->nname, &statbuf)) - return ERROR_OBJECT_NOT_FOUND; - - mode = statbuf.st_mode; -#ifdef __unix - /* Unix dirs behave differently than AmigaOS ones. Just allow anything. */ - if (aino->dir) { - mask = 0; - } -#endif - if (mask & A_FIBF_READ) - mode &= ~S_IRUSR; - else - mode |= S_IRUSR; - - if ((mask & A_FIBF_WRITE) != 0 || (mask & A_FIBF_DELETE) != 0) - mode &= ~S_IWUSR; - else - mode |= S_IWUSR; - - if (mask & A_FIBF_EXECUTE) - mode &= ~S_IXUSR; - else - mode |= S_IXUSR; - - if (-1 == chmod(aino->nname, mode)) - return dos_errno(); - - aino->amigaos_mode = mask; - - return 0; -} - static void prepare_for_open (char *name) { #if 0 @@ -526,7 +669,7 @@ static void prepare_for_open (char *name #endif } -static void de_recycle_aino (Unit *unit, struct a_inode *aino) +static void de_recycle_aino (Unit *unit, a_inode *aino) { if (aino->next == 0 || aino == &unit->rootnode) return; @@ -536,78 +679,109 @@ static void de_recycle_aino (Unit *unit, unit->aino_cache_size--; } -static void recycle_aino (Unit *unit, struct a_inode *aino) +static void dispose_aino (Unit *unit, a_inode **aip, a_inode *aino) +{ + int hash = aino->uniq % MAX_AINO_HASH; + if (unit->aino_hash[hash] == aino) + unit->aino_hash[hash] = 0; + + if (aino->dirty && aino->parent) + fsdb_dir_writeback (aino->parent); + + *aip = aino->sibling; + if (aino->comment) + free (aino->comment); + free (aino->nname); + free (aino->aname); + free (aino); +} + +static void recycle_aino (Unit *unit, a_inode *new_aino) { - if (aino->dir || aino->shlock > 0 || aino->elock || aino == &unit->rootnode) + if (new_aino->dir || new_aino->shlock > 0 + || new_aino->elock || new_aino == &unit->rootnode) /* Still in use */ return; - /* Chain it into circular list. */ - aino->next = unit->rootnode.next; - aino->prev = &unit->rootnode; - aino->prev->next = aino; - aino->next->prev = aino; - unit->aino_cache_size++; - if (unit->aino_cache_size > 500) { + TRACE (("Recycling; cache size %d, total_locked %d\n", + unit->aino_cache_size, unit->total_locked_ainos)); + if (unit->aino_cache_size > 500 + unit->total_locked_ainos) { /* Reap a few. */ int i = 0; while (i < 50) { - struct a_inode **aip; - aip = &unit->rootnode.prev->parent->child; - for (;;) { - aino = *aip; - if (aino == 0) - break; - - if (aino->next == 0) - aip = &aino->sibling; - else { - int hash = aino->uniq % MAX_AINO_HASH; - if (unit->aino_hash[hash] == aino) - unit->aino_hash[hash] = 0; - - aino->next->prev = aino->prev; - aino->prev->next = aino->next; - *aip = aino->sibling; - i++; - - if (aino->shlock > 0 || aino->elock) - write_log ("panic: freeing locked a_inode!\n"); - - free (aino->nname); - free (aino->aname); - free (aino); + a_inode *parent = unit->rootnode.prev->parent; + a_inode **aip, *old_prev; + aip = &parent->child; + + if (! parent->locked_children) { + for (;;) { + a_inode *aino = *aip; + if (aino == 0) + break; + + /* Not recyclable if next == 0 (i.e., not chained into + recyclable list), or if parent directory is being + ExNext()ed. */ + if (aino->next == 0) { + aip = &aino->sibling; + } else { + if (aino->shlock > 0 || aino->elock) + write_log ("panic: freeing locked a_inode!\n"); + + de_recycle_aino (unit, aino); + dispose_aino (unit, aip, aino); + i++; + } } } + /* In the previous loop, we went through all children of one + parent. Re-arrange the recycled list so that we'll find a + different parent the next time around. */ + old_prev = unit->rootnode.prev; + do { + unit->rootnode.next->prev = unit->rootnode.prev; + unit->rootnode.prev->next = unit->rootnode.next; + unit->rootnode.next = unit->rootnode.prev; + unit->rootnode.prev = unit->rootnode.prev->prev; + unit->rootnode.prev->next = unit->rootnode.next->prev = &unit->rootnode; + } while (unit->rootnode.prev != old_prev + && unit->rootnode.prev->parent == parent); } #if 0 { char buffer[40]; sprintf (buffer, "%d ainos reaped.\n", i); - write_log (buffer); + TRACE ((buffer)); } #endif - unit->aino_cache_size -= i; } + + /* Chain it into circular list. */ + new_aino->next = unit->rootnode.next; + new_aino->prev = &unit->rootnode; + new_aino->prev->next = new_aino; + new_aino->next->prev = new_aino; + unit->aino_cache_size++; } -static void update_child_names (Unit *unit, struct a_inode *a, struct a_inode *parent) +static void update_child_names (Unit *unit, a_inode *a, a_inode *parent) { int l0 = strlen (parent->nname) + 2; while (a != 0) { char *name_start; char *new_name; + char dirsep[2] = { FSDB_DIR_SEPARATOR, '\0' }; a->parent = parent; - name_start = strrchr (a->nname, '/'); + name_start = strrchr (a->nname, FSDB_DIR_SEPARATOR); if (name_start == 0) { write_log ("malformed file name"); } name_start++; new_name = (char *)xmalloc (strlen (name_start) + l0); strcpy (new_name, parent->nname); - strcat (new_name, "/"); + strcat (new_name, dirsep); strcat (new_name, name_start); free (a->nname); a->nname = new_name; @@ -617,21 +791,41 @@ static void update_child_names (Unit *un } } -static void move_aino_children (Unit *unit, struct a_inode *from, struct a_inode *to) +static void move_aino_children (Unit *unit, a_inode *from, a_inode *to) { to->child = from->child; from->child = 0; update_child_names (unit, to->child, to); } -static void delete_aino (Unit *unit, struct a_inode *aino) +static void delete_aino (Unit *unit, a_inode *aino) { - struct a_inode **aip; - int hash; + a_inode **aip; - TRACE((warning_buffer, "deleting aino %x\n", aino->uniq)); + TRACE(("deleting aino %x\n", aino->uniq)); + aino->dirty = 1; + aino->deleted = 1; de_recycle_aino (unit, aino); + + /* If any ExKeys are currently pointing at us, advance them. */ + if (aino->parent->exnext_count > 0) { + int i; + TRACE(("entering exkey validation\n")); + for (i = 0; i < EXKEYS; i++) { + ExamineKey *k = unit->examine_keys + i; + if (k->uniq == 0) + continue; + if (k->aino == aino->parent) { + TRACE(("Same parent found for %d\n", i)); + if (k->curr_file == aino) { + k->curr_file = aino->sibling; + TRACE(("Advancing curr_file\n")); + } + } + } + } + aip = &aino->parent->child; while (*aip != aino && *aip != 0) aip = &(*aip)->sibling; @@ -639,19 +833,13 @@ static void delete_aino (Unit *unit, str write_log ("Couldn't delete aino.\n"); return; } - hash = aino->uniq % MAX_AINO_HASH; - if (unit->aino_hash[hash] == aino) - unit->aino_hash[hash] = 0; - *aip = aino->sibling; - free (aino->nname); - free (aino->aname); - free (aino); + dispose_aino (unit, aip, aino); } -static struct a_inode *lookup_sub (struct a_inode *dir, uae_u32 uniq) +static a_inode *lookup_sub (a_inode *dir, uae_u32 uniq) { - struct a_inode **cp = &dir->child; - struct a_inode *c, *retval; + a_inode **cp = &dir->child; + a_inode *c, *retval; for (;;) { c = *cp; @@ -663,7 +851,7 @@ static struct a_inode *lookup_sub (struc break; } if (c->dir) { - struct a_inode *a = lookup_sub (c, uniq); + a_inode *a = lookup_sub (c, uniq); if (a != 0) { retval = a; break; @@ -671,15 +859,20 @@ static struct a_inode *lookup_sub (struc } cp = &c->sibling; } - *cp = c->sibling; - c->sibling = dir->child; - dir->child = c; + if (! dir->locked_children) { + /* Move to the front to speed up repeated lookups. Don't do this if + an ExNext is going on in this directory, or we'll terminally + confuse it. */ + *cp = c->sibling; + c->sibling = dir->child; + dir->child = c; + } return retval; } -static struct a_inode *lookup_aino (Unit *unit, uae_u32 uniq) +static a_inode *lookup_aino (Unit *unit, uae_u32 uniq) { - struct a_inode *a; + a_inode *a; int hash = uniq % MAX_AINO_HASH; if (uniq == 0) @@ -694,28 +887,82 @@ static struct a_inode *lookup_aino (Unit return a; } +char *build_nname (const char *d, const char *n) +{ + char dsep[2] = { FSDB_DIR_SEPARATOR, '\0' }; + char *p = (char *) xmalloc (strlen (d) + strlen (n) + 2); + strcpy (p, d); + strcat (p, dsep); + strcat (p, n); + return p; +} + +char *build_aname (const char *d, const char *n) +{ + char *p = (char *) xmalloc (strlen (d) + strlen (n) + 2); + strcpy (p, d); + strcat (p, "/"); + strcat (p, n); + return p; +} + /* This gets called to translate an Amiga name that some program used to - * a name that we can use on the native filesystem. */ -static char *get_nname (Unit *unit, struct a_inode *base, char *rel) + * a name that we can use on the native filesystem. */ +static char *get_nname (Unit *unit, a_inode *base, char *rel, + char **modified_rel) { - DIR* dir; - struct dirent* de; + char *found; char *p = 0; - dir = opendir(base->nname); - if (dir) { - struct dirent de_space; - while((de = my_readdir (dir, &de_space))) { - if (strcasecmp(de->d_name, rel) == 0) - break; - } - if (de) { - p = (char *)xmalloc (strlen (de->d_name) + strlen (base->nname) + 2); - strcpy (p, base->nname); - strcat (p, "/"); - strcat (p, de->d_name); - } - closedir(dir); + *modified_rel = 0; + + /* If we have a mapping of some other aname to "rel", we must pretend + * it does not exist. + * This can happen for example if an Amiga program creates a + * file called ".". We can't represent this in our filesystem, + * so we create a special file "uae_xxx" and record the mapping + * aname "." -> nname "uae_xxx" in the database. Then, the Amiga + * program looks up "uae_xxx" (yes, it's contrived). The filesystem + * should not make the uae_xxx file visible to the Amiga side. */ + if (fsdb_used_as_nname (base, rel)) + return 0; + /* A file called "." (or whatever else is invalid on this filesystem) + * does not exist, as far as the Amiga side is concerned. */ + if (fsdb_name_invalid (rel)) + return 0; + + /* See if we have a file that has the same name as the aname we are + * looking for. */ + found = fsdb_search_dir (base->nname, rel); + if (found == 0) + return found; + if (found == rel) + return build_nname (base->nname, rel); + + *modified_rel = found; + return build_nname (base->nname, found); +} + +static char *create_nname (Unit *unit, a_inode *base, char *rel) +{ + char *p; + + /* We are trying to create a file called REL. */ + + /* If the name is used otherwise in the directory (or globally), we + * need a new unique nname. */ + if (fsdb_name_invalid (rel) || fsdb_used_as_nname (base, rel)) { + oh_dear: + p = fsdb_create_unique_nname (base, rel); + return p; + } + p = build_nname (base->nname, rel); + + /* Delete this code once we know everything works. */ + if (access (p, R_OK) >= 0 || errno != ENOENT) { + write_log ("Filesystem in trouble... please report.\n"); + free (p); + goto oh_dear; } return p; } @@ -731,42 +978,13 @@ static char *get_nname (Unit *unit, stru * figure out that this is supposed to be the file "foobar.inf". * DOS sucks... */ -static char *get_aname (Unit *unit, struct a_inode *base, char *rel) +static char *get_aname (Unit *unit, a_inode *base, char *rel) { - char *p = 0; - - p = (char *)xmalloc (strlen (rel) + strlen (base->aname) + 2); - strcpy (p, base->aname); - strcat (p, "/"); - strcat (p, rel); - - return p; + return my_strdup (rel); } -static struct a_inode *new_child_aino (Unit *unit, struct a_inode *base, char *rel, int force) +static void init_child_aino (Unit *unit, a_inode *base, a_inode *aino) { - struct stat statbuf; - char *nn; - struct a_inode *aino; - - nn = get_nname (unit, base, rel); - if (nn == 0 && !force) - return 0; - else if (nn != 0) - force = 0; - - aino = (struct a_inode *)malloc (sizeof (struct a_inode)); - if (aino == 0) - return 0; - aino->aname = my_strdup (rel); - if (nn == 0) { - nn = (char *)xmalloc (strlen (base->nname) + strlen (rel) + 2); - strcpy (nn, base->nname); - strcat (nn, "/"); - strcat (nn, rel); - free (rel); - } - aino->nname = nn; aino->uniq = ++unit->a_uniq; if (unit->a_uniq == 0xFFFFFFFF) { write_log ("Running out of a_inodes (prepare for big trouble)!\n"); @@ -774,31 +992,84 @@ static struct a_inode *new_child_aino (U aino->shlock = 0; aino->elock = 0; + aino->dirty = 0; + aino->deleted = 0; + + /* For directories - this one isn't being ExNext()ed yet. */ + aino->locked_children = 0; + aino->exnext_count = 0; + /* But the parent might be. */ + if (base->exnext_count) { + unit->total_locked_ainos++; + base->locked_children++; + } /* Update tree structure */ aino->parent = base; aino->child = 0; aino->sibling = base->child; base->child = aino; aino->next = aino->prev = 0; +} - if (force == 2) { - aino->dir = 1; - aino->amigaos_mode = 0; - } else if (force == 1) { - aino->dir = 0; - aino->amigaos_mode = 0; - } else { - get_file_attrs (aino); +static a_inode *new_child_aino (Unit *unit, a_inode *base, char *rel) +{ + char *modified_rel; + char *nn; + a_inode *aino; + + TRACE(("new_child_aino %s, %s\n", base->aname, rel)); + + aino = fsdb_lookup_aino_aname (base, rel); + if (aino == 0) { + nn = get_nname (unit, base, rel, &modified_rel); + if (nn == 0) + return 0; + + aino = (a_inode *) xcalloc (sizeof (a_inode), 1); + if (aino == 0) + return 0; + aino->aname = modified_rel ? modified_rel : my_strdup (rel); + aino->nname = nn; + + aino->comment = 0; + aino->has_dbentry = 0; + + fsdb_fill_file_attrs (aino); + if (aino->dir) + fsdb_clean_dir (aino); } + init_child_aino (unit, base, aino); + recycle_aino (unit, aino); - TRACE((warning_buffer, "created aino %x, normal\n", aino->uniq)); + TRACE(("created aino %x, lookup, amigaos_mode %d\n", aino->uniq, aino->amigaos_mode)); return aino; } -static struct a_inode *lookup_child_aino (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err) +static a_inode *create_child_aino (Unit *unit, a_inode *base, char *rel, int isdir) { - struct a_inode *c = base->child; - char *p, *p2; + a_inode *aino = (a_inode *) xcalloc (sizeof (a_inode), 1); + if (aino == 0) + return 0; + + aino->aname = my_strdup (rel); + aino->nname = create_nname (unit, base, rel); + + init_child_aino (unit, base, aino); + aino->amigaos_mode = 0; + aino->dir = isdir; + + aino->comment = 0; + aino->has_dbentry = 0; + aino->dirty = 1; + + recycle_aino (unit, aino); + TRACE(("created aino %x, create\n", aino->uniq)); + return aino; +} + +static a_inode *lookup_child_aino (Unit *unit, a_inode *base, char *rel, uae_u32 *err) +{ + a_inode *c = base->child; int l0 = strlen (rel); if (base->dir == 0) { @@ -808,79 +1079,72 @@ static struct a_inode *lookup_child_aino while (c != 0) { int l1 = strlen (c->aname); - if (l0 <= l1 && strcasecmp (rel, c->aname + l1 - l0) == 0 + if (l0 <= l1 && same_aname (rel, c->aname + l1 - l0) && (l0 == l1 || c->aname[l1-l0-1] == '/')) break; c = c->sibling; } if (c != 0) return c; - c = new_child_aino (unit, base, rel, 0); + c = new_child_aino (unit, base, rel); if (c == 0) - *err = ERROR_OBJECT_NOT_FOUND; + *err = ERROR_OBJECT_NOT_AROUND; return c; } -/* Different version because this one compares with the nname */ -static struct a_inode *lookup_child_aino_for_exnext (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err) +/* Different version because for this one, REL is an nname. */ +static a_inode *lookup_child_aino_for_exnext (Unit *unit, a_inode *base, char *rel, uae_u32 *err) { - struct a_inode *c = base->child; - char *p, *p2; + a_inode *c = base->child; int l0 = strlen (rel); *err = 0; while (c != 0) { int l1 = strlen (c->nname); - if (l0 <= l1 && strcasecmp (rel, c->nname + l1 - l0) == 0 - && (l0 == l1 || c->nname[l1-l0-1] == '/')) + /* Note: using strcmp here. */ + if (l0 <= l1 && strcmp (rel, c->nname + l1 - l0) == 0 + && (l0 == l1 || c->nname[l1-l0-1] == FSDB_DIR_SEPARATOR)) break; c = c->sibling; } if (c != 0) return c; - c = (struct a_inode *)malloc (sizeof (struct a_inode)); - if (c == 0) - *err = ERROR_NO_FREE_STORE; - else { - c->nname = (char *)xmalloc (strlen (base->nname) + l0 + 2); - strcpy (c->nname, base->nname); - strcat (c->nname, "/"); - strcat (c->nname, rel); + c = fsdb_lookup_aino_nname (base, rel); + if (c == 0) { + c = (a_inode *)malloc (sizeof (a_inode)); + if (c == 0) { + *err = ERROR_NO_FREE_STORE; + return 0; + } + + c->nname = build_nname (base->nname, rel); c->aname = get_aname (unit, base, rel); - c->uniq = ++unit->a_uniq; - if (unit->a_uniq == 0xFFFFFFFF) { - write_log ("Running out of a_inodes (prepare for big trouble)!\n"); - } - c->shlock = 0; - c->elock = 0; - - /* Update tree structure */ - c->parent = base; - c->child = 0; - c->sibling = base->child; - base->child = c; - c->next = c->prev = 0; - - get_file_attrs (c); - recycle_aino (unit, c); - TRACE((warning_buffer, "created aino %x, exnext\n", c->uniq)); + c->comment = 0; + c->has_dbentry = 0; + fsdb_fill_file_attrs (c); + if (c->dir) + fsdb_clean_dir (c); } + init_child_aino (unit, base, c); + + recycle_aino (unit, c); + TRACE(("created aino %x, exnext\n", c->uniq)); + return c; } -static struct a_inode *get_aino(Unit* unit, struct a_inode *base, const char *rel, uae_u32 *err) +static a_inode *get_aino (Unit *unit, a_inode *base, const char *rel, uae_u32 *err) { char *tmp; char *p; - char *r; - struct a_inode *curr; + a_inode *curr; int i; *err = 0; - TRACE((warning_buffer, "get_path(%s,%s)\n", base->aname, rel)); + TRACE(("get_path(%s,%s)\n", base->aname, rel)); /* root-relative path? */ - for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++) + for (i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++) ; if (':' == rel[i]) rel += i+1; @@ -889,14 +1153,14 @@ static struct a_inode *get_aino(Unit* un p = tmp; curr = base; - while(*p) { + while (*p) { /* start with a slash? go up a level. */ if (*p == '/') { if (curr->parent != 0) curr = curr->parent; p++; } else { - struct a_inode *next; + a_inode *next; char *component_end; component_end = strchr (p, '/'); @@ -905,7 +1169,7 @@ static struct a_inode *get_aino(Unit* un next = lookup_child_aino (unit, curr, p, err); if (next == 0) { /* if only last component not found, return parent dir. */ - if (*err != ERROR_OBJECT_NOT_FOUND || component_end != 0) + if (*err != ERROR_OBJECT_NOT_AROUND || component_end != 0) curr = 0; /* ? what error is appropriate? */ break; @@ -922,58 +1186,59 @@ static struct a_inode *get_aino(Unit* un return curr; } -static uae_u32 startup_handler (void) +static uae_u32 startup_handler (TrapContext *dummy) { /* Just got the startup packet. It's in A4. DosBase is in A2, * our allocated volume structure is in D6, A5 is a pointer to * our port. */ - uaecptr rootnode = get_long(m68k_areg (regs, 2) + 34); - uaecptr dos_info = get_long(rootnode + 24) << 2; + uaecptr rootnode = get_long (m68k_areg (regs, 2) + 34); + uaecptr dos_info = get_long (rootnode + 24) << 2; uaecptr pkt = m68k_dreg (regs, 3); uaecptr arg2 = get_long (pkt + dp_Arg2); int i, namelen; char* devname = bstr1 (get_long (pkt + dp_Arg1) << 2); char* s; - Unit* unit; + Unit *unit; UnitInfo *uinfo; /* find UnitInfo with correct device name */ - s = strchr(devname, ':'); - if(s) + s = strchr (devname, ':'); + if (s) *s = '\0'; - for(i = 0; i < num_units; i++) { + for (i = 0; i < current_mountinfo->num_units; i++) { /* Hardfile volume name? */ - if (ui[i].volname == 0) + if (current_mountinfo->ui[i].volname == 0) continue; - if (ui[i].startup == arg2) + if (current_mountinfo->ui[i].startup == arg2) break; } - if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) { - sprintf(warning_buffer, "Failed attempt to mount device\n", devname); - write_log (warning_buffer); + if (i == current_mountinfo->num_units + || access (current_mountinfo->ui[i].rootdir, R_OK) != 0) + { + write_log ("Failed attempt to mount device\n", devname); put_long (pkt + dp_Res1, DOS_FALSE); put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED); return 1; } - uinfo = ui + i; + uinfo = current_mountinfo->ui + i; - unit = (Unit *) xmalloc (sizeof (Unit)); + unit = (Unit *) xcalloc (sizeof (Unit), 1); unit->next = units; units = unit; uinfo->self = unit; unit->volume = 0; - unit->reset_state = FS_STARTUP; - unit->port = m68k_areg(regs, 5); + unit->port = m68k_areg (regs, 5); unit->unit = unit_num++; unit->ui.devname = uinfo->devname; unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */ unit->ui.rootdir = uinfo->rootdir; unit->ui.readonly = uinfo->readonly; + unit->ui.bootpri = uinfo->bootpri; unit->ui.unit_pipe = uinfo->unit_pipe; unit->ui.back_pipe = uinfo->back_pipe; unit->cmds_complete = 0; @@ -981,9 +1246,10 @@ static uae_u32 startup_handler (void) unit->cmds_acked = 0; for (i = 0; i < EXKEYS; i++) { unit->examine_keys[i].aino = 0; - unit->examine_keys[i].dir = 0; + unit->examine_keys[i].curr_file = 0; unit->examine_keys[i].uniq = 0; } + unit->total_locked_ainos = 0; unit->next_exkey = 1; unit->keys = 0; unit->a_uniq = unit->key_uniq = 0; @@ -999,17 +1265,19 @@ static uae_u32 startup_handler (void) unit->rootnode.amigaos_mode = 0; unit->rootnode.shlock = 0; unit->rootnode.elock = 0; + unit->rootnode.comment = 0; + unit->rootnode.has_dbentry = 0; unit->aino_cache_size = 0; for (i = 0; i < MAX_AINO_HASH; i++) unit->aino_hash[i] = 0; /* write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/ - TRACE((warning_buffer, "**** STARTUP volume %s\n", unit->ui.volname)); + TRACE(("**** STARTUP volume %s\n", unit->ui.volname)); /* fill in our process in the device node */ put_long ((get_long (pkt + dp_Arg3) << 2) + 8, unit->port); - unit->dosbase = m68k_areg(regs, 2); + unit->dosbase = m68k_areg (regs, 2); /* make new volume */ unit->volume = m68k_areg (regs, 3) + 32; @@ -1031,84 +1299,69 @@ static uae_u32 startup_handler (void) put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */ namelen = strlen (unit->ui.volname); put_byte (unit->volume + 44, namelen); - for(i = 0; i < namelen; i++) + for (i = 0; i < namelen; i++) put_byte (unit->volume + 45 + i, unit->ui.volname[i]); /* link into DOS list */ - put_long (unit->volume, get_long(dos_info + 4)); + put_long (unit->volume, get_long (dos_info + 4)); put_long (dos_info + 4, unit->volume >> 2); put_long (unit->volume + 8, unit->port); put_long (unit->volume + 32, DISK_TYPE); put_long (pkt + dp_Res1, DOS_TRUE); + + fsdb_clean_dir (&unit->rootnode); + return 0; } -#ifdef HAVE_STATFS static void -do_info(Unit* unit, dpacket packet, uaecptr info) +do_info (Unit *unit, dpacket packet, uaecptr info) { - struct statfs statbuf; -#if STATFS_NO_ARGS == 2 - if(-1 == statfs(unit->ui.rootdir, &statbuf)) -#else - if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0)) -#endif - { + struct fs_usage fsu; + + if (get_fs_usage (unit->ui.rootdir, 0, &fsu) != 0) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, dos_errno ()); + return; } - put_long(info, 0); /* errors */ - put_long(info + 4, unit->unit); /* unit number */ - put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state */ - put_long(info + 12, statbuf.f_blocks); /* numblocks */ - put_long(info + 16, statbuf.f_blocks - statbuf.STATBUF_BAVAIL); /* inuse */ - put_long(info + 20, statbuf.f_bsize); /* bytesperblock */ - put_long(info + 24, DISK_TYPE); /* disk type */ - put_long(info + 28, unit->volume >> 2); /* volume node */ - put_long(info + 32, 0); /* inuse */ + fsu.fsu_blocks >>= 1; + fsu.fsu_bavail >>= 1; + put_long (info, 0); /* errors */ + put_long (info + 4, unit->unit); /* unit number */ + put_long (info + 8, unit->ui.readonly ? 80 : 82); /* state */ + put_long (info + 12, fsu.fsu_blocks ); /* numblocks */ + put_long (info + 16, fsu.fsu_blocks - fsu.fsu_bavail); /* inuse */ + put_long (info + 20, 1024); /* bytesperblock */ + put_long (info + 24, DISK_TYPE); /* disk type */ + put_long (info + 28, unit->volume >> 2); /* volume node */ + put_long (info + 32, 0); /* inuse */ PUT_PCK_RES1 (packet, DOS_TRUE); } -#else -static void -do_info(Unit* unit, dpacket packet, uaecptr info) -{ - put_long(info, 0); /* errors */ - put_long(info + 4, unit->unit); /* unit number */ - put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state */ - put_long(info + 12, 256); /* numblocks */ - put_long(info + 16, 128); /* inuse */ - put_long(info + 20, 512); /* bytesperblock */ - put_long(info + 24, DISK_TYPE); /* disk type */ - put_long(info + 28, unit->volume >> 2); /* volume node */ - put_long(info + 32, 0); /* inuse */ - PUT_PCK_RES1 (packet, DOS_TRUE); -} -#endif static void -action_disk_info(Unit* unit, dpacket packet) +action_disk_info (Unit *unit, dpacket packet) { - TRACE((warning_buffer, "ACTION_DISK_INFO\n")); + TRACE(("ACTION_DISK_INFO\n")); do_info(unit, packet, GET_PCK_ARG1 (packet) << 2); } static void -action_info(Unit* unit, dpacket packet) +action_info (Unit *unit, dpacket packet) { - TRACE((warning_buffer, "ACTION_INFO\n")); + TRACE(("ACTION_INFO\n")); do_info(unit, packet, GET_PCK_ARG2 (packet) << 2); } -static void free_key (Unit *unit, Key*k) +static void free_key (Unit *unit, Key *k) { Key *k1; Key *prev = 0; for (k1 = unit->keys; k1; k1 = k1->next) { if (k == k1) { - if(prev) + if (prev) prev->next = k->next; else unit->keys = k->next; @@ -1118,17 +1371,17 @@ static void free_key (Unit *unit, Key*k) } if (k->fd >= 0) - close(k->fd); + close (k->fd); free(k); } -static Key *lookup_key(Unit *unit, uae_u32 uniq) +static Key *lookup_key (Unit *unit, uae_u32 uniq) { Key *k; /* It's hardly worthwhile to optimize this - most of the time there are * only one or zero keys. */ - for(k = unit->keys; k; k = k->next) { + for (k = unit->keys; k; k = k->next) { if (uniq == k->uniq) return k; } @@ -1143,9 +1396,9 @@ static Key *lookup_key(Unit *unit, uae_u return 0; } -static Key *new_key(Unit *unit) +static Key *new_key (Unit *unit) { - Key *k = (Key*) xmalloc(sizeof(Key)); + Key *k = (Key *) xmalloc(sizeof(Key)); k->uniq = ++unit->key_uniq; k->fd = -1; k->file_pos = 0; @@ -1156,51 +1409,51 @@ static Key *new_key(Unit *unit) } static void -dumplock(Unit *unit, uaecptr lock) +dumplock (Unit *unit, uaecptr lock) { - struct a_inode *a; - TRACE((warning_buffer, "LOCK: 0x%lx", lock)); - if(!lock) { - TRACE((warning_buffer, "\n")); + a_inode *a; + TRACE(("LOCK: 0x%lx", lock)); + if (!lock) { + TRACE(("\n")); return; } - TRACE((warning_buffer, "{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ", - get_long(lock) << 2, get_long(lock+8), - get_long(lock+12), get_long(lock+16), - get_long(lock + 4))); + TRACE(("{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ", + get_long (lock) << 2, get_long (lock+8), + get_long (lock+12), get_long (lock+16), + get_long (lock + 4))); a = lookup_aino (unit, get_long (lock + 4)); if (a == 0) { - TRACE((warning_buffer, "not found!")); + TRACE(("not found!")); } else { - TRACE((warning_buffer, "%s", a->nname)); + TRACE(("%s", a->nname)); } - TRACE((warning_buffer, " }\n")); + TRACE((" }\n")); } -static struct a_inode *find_aino(Unit* unit, uaecptr lock, const char *name, uae_u32 *err) +static a_inode *find_aino (Unit *unit, uaecptr lock, const char *name, uae_u32 *err) { - struct a_inode *a; + a_inode *a; if (lock) { - struct a_inode *olda = lookup_aino (unit, get_long(lock + 4)); + a_inode *olda = lookup_aino (unit, get_long (lock + 4)); if (olda == 0) { /* That's the best we can hope to do. */ a = get_aino (unit, &unit->rootnode, name, err); } else { - TRACE((warning_buffer, "aino: 0x%08lx", (unsigned long int)olda->uniq)); - TRACE((warning_buffer, " \"%s\"\n", olda->nname)); + TRACE(("aino: 0x%08lx", (unsigned long int)olda->uniq)); + TRACE((" \"%s\"\n", olda->nname)); a = get_aino (unit, olda, name, err); } } else { a = get_aino (unit, &unit->rootnode, name, err); } if (a) { - TRACE((warning_buffer, "aino=\"%s\"\n", a->nname)); + TRACE(("aino=\"%s\"\n", a->nname)); } return a; } -static uaecptr make_lock (Unit* unit, uae_u32 uniq, long mode) +static uaecptr make_lock (Unit *unit, uae_u32 uniq, long mode) { /* allocate lock from the list kept by the assembly code */ uaecptr lock; @@ -1209,37 +1462,36 @@ static uaecptr make_lock (Unit* unit, ua put_long (unit->locklist, get_long (lock)); lock += 4; - put_long(lock + 4, uniq); - put_long(lock + 8, mode); - put_long(lock + 12, unit->port); - put_long(lock + 16, unit->volume >> 2); + put_long (lock + 4, uniq); + put_long (lock + 8, mode); + put_long (lock + 12, unit->port); + put_long (lock + 16, unit->volume >> 2); /* prepend to lock chain */ - put_long(lock, get_long(unit->volume + 28)); - put_long(unit->volume + 28, lock >> 2); + put_long (lock, get_long (unit->volume + 28)); + put_long (unit->volume + 28, lock >> 2); DUMPLOCK(unit, lock); return lock; } -static void free_lock (Unit* unit, uaecptr lock) +static void free_lock (Unit *unit, uaecptr lock) { - Key *k; - if(!lock) + if (! lock) return; - if (lock == get_long(unit->volume + 28) << 2) { - put_long(unit->volume + 28, get_long(lock)); + if (lock == get_long (unit->volume + 28) << 2) { + put_long (unit->volume + 28, get_long (lock)); } else { - uaecptr current = get_long(unit->volume + 28); + uaecptr current = get_long (unit->volume + 28); uaecptr next = 0; - while(current) { - next = get_long(current << 2); - if(lock == next << 2) + while (current) { + next = get_long (current << 2); + if (lock == next << 2) break; current = next; } - put_long(current << 2, get_long(lock)); + put_long (current << 2, get_long (lock)); } lock -= 4; put_long (lock, get_long (unit->locklist)); @@ -1247,24 +1499,24 @@ static void free_lock (Unit* unit, uaecp } static void -action_lock(Unit* unit, dpacket packet) +action_lock (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; uaecptr name = GET_PCK_ARG2 (packet) << 2; long mode = GET_PCK_ARG3 (packet); - struct a_inode *a; + a_inode *a; uae_u32 err; - if (mode != -2 && mode != -1) { - TRACE((warning_buffer, "Bad mode.\n")); - mode = -2; + if (mode != SHARED_LOCK && mode != EXCLUSIVE_LOCK) { + TRACE(("Bad mode.\n")); + mode = SHARED_LOCK; } - TRACE((warning_buffer, "ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode)); + TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode)); DUMPLOCK(unit, lock); a = find_aino (unit, lock, bstr (unit, name), &err); - if (err == 0 && (a->elock || (mode != -2 && a->shlock > 0))) { + if (err == 0 && (a->elock || (mode != SHARED_LOCK && a->shlock > 0))) { err = ERROR_OBJECT_IN_USE; } /* Lock() doesn't do access checks. */ @@ -1273,7 +1525,7 @@ action_lock(Unit* unit, dpacket packet) PUT_PCK_RES2 (packet, err); return; } - if (mode == -2) + if (mode == SHARED_LOCK) a->shlock++; else a->elock = 1; @@ -1281,17 +1533,17 @@ action_lock(Unit* unit, dpacket packet) PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2); } -static void action_free_lock (Unit* unit, dpacket packet) +static void action_free_lock (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; - struct a_inode *a; - TRACE((warning_buffer, "ACTION_FREE_LOCK(0x%lx)\n", lock)); + a_inode *a; + TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock)); DUMPLOCK(unit, lock); a = lookup_aino (unit, get_long (lock + 4)); if (a == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); return; } if (a->elock) @@ -1305,21 +1557,21 @@ static void action_free_lock (Unit* unit } static void -action_dup_lock(Unit* unit, dpacket packet) +action_dup_lock (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; - struct a_inode *a; - TRACE((warning_buffer, "ACTION_DUP_LOCK(0x%lx)\n", lock)); + a_inode *a; + TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock)); DUMPLOCK(unit, lock); - if(!lock) { + if (!lock) { PUT_PCK_RES1 (packet, 0); return; } a = lookup_aino (unit, get_long (lock + 4)); if (a == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); return; } /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but @@ -1340,7 +1592,7 @@ const int secs_per_day = 24 * 60 * 60; const int diff = (8 * 365 + 2) * (24 * 60 * 60); static void -get_time(time_t t, long* days, long* mins, long* ticks) +get_time (time_t t, long* days, long* mins, long* ticks) { /* time_t is secs since 1-1-1970 */ /* days since 1-1-1978 */ @@ -1356,7 +1608,7 @@ get_time(time_t t, long* days, long* min } static time_t -put_time(long days, long mins, long ticks) +put_time (long days, long mins, long ticks) { time_t t; t = ticks / 50; @@ -1367,19 +1619,38 @@ put_time(long days, long mins, long tick return t; } -static void free_exkey(ExamineKey* ek) +static void free_exkey (Unit *unit, ExamineKey *ek) { + if (--ek->aino->exnext_count == 0) { + TRACE (("Freeing ExKey and reducing total_locked from %d by %d\n", + unit->total_locked_ainos, ek->aino->locked_children)); + unit->total_locked_ainos -= ek->aino->locked_children; + ek->aino->locked_children = 0; + } ek->aino = 0; ek->uniq = 0; - if (ek->dir) - closedir (ek->dir); +} + +static ExamineKey *lookup_exkey (Unit *unit, uae_u32 uniq) +{ + ExamineKey *ek; + int i; + + ek = unit->examine_keys; + for (i = 0; i < EXKEYS; i++, ek++) { + /* Did we find a free one? */ + if (ek->uniq == uniq) + return ek; + } + write_log ("Houston, we have a BIG problem.\n"); + return 0; } /* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */ -static ExamineKey *new_exkey(Unit *unit, struct a_inode *aino) +static ExamineKey *new_exkey (Unit *unit, a_inode *aino) { uae_u32 uniq; - uae_u32 oldest = 0xFFFFFFFF; + uae_u32 oldest = 0xFFFFFFFE; ExamineKey *ek, *oldest_ek = 0; int i; @@ -1399,46 +1670,51 @@ static ExamineKey *new_exkey(Unit *unit, } /* This message should usually be harmless. */ write_log ("Houston, we have a problem.\n"); - free_exkey (oldest_ek); + free_exkey (unit, oldest_ek); ek = oldest_ek; found: uniq = unit->next_exkey; - if (uniq == 0xFFFFFFFF) { + if (uniq >= 0xFFFFFFFE) { /* Things will probably go wrong, but most likely the Amiga will crash * before this happens because of something else. */ uniq = 1; } unit->next_exkey = uniq+1; ek->aino = aino; - ek->dir = 0; + ek->curr_file = 0; ek->uniq = uniq; return ek; } -static ExamineKey *lookup_exkey(Unit *unit, uae_u32 uniq) +static void move_exkeys (Unit *unit, a_inode *from, a_inode *to) { - ExamineKey *ek; int i; - - ek = unit->examine_keys; - for (i = 0; i < EXKEYS; i++, ek++) { - /* Did we find a free one? */ - if (ek->uniq == uniq) - return ek; + unsigned long tmp = 0; + for (i = 0; i < EXKEYS; i++) { + ExamineKey *k = unit->examine_keys + i; + if (k->uniq == 0) + continue; + if (k->aino == from) { + k->aino = to; + tmp++; + } } - write_log ("Houston, we have a BIG problem.\n"); - return 0; + if (tmp != from->exnext_count) + write_log ("filesys.c: Bug in ExNext bookkeeping. BAD.\n"); + to->exnext_count = from->exnext_count; + to->locked_children = from->locked_children; + from->exnext_count = 0; + from->locked_children = 0; } static void -get_fileinfo(Unit *unit, dpacket packet, uaecptr info, struct a_inode *aino) +get_fileinfo (Unit *unit, dpacket packet, uaecptr info, a_inode *aino) { struct stat statbuf; long days, mins, ticks; int i, n; char *x; - uae_u32 err; /* No error checks - this had better work. */ stat (aino->nname, &statbuf); @@ -1449,163 +1725,195 @@ get_fileinfo(Unit *unit, dpacket packet, put_long (info + 120, 1); } else { /* AmigaOS docs say these have to contain the same value. */ - put_long(info + 4, aino->dir ? 2 : -3); - put_long(info + 120, aino->dir ? 2 : -3); - x = strrchr (aino->aname, '/'); - if (x) - x++; - else - x = aino->aname; + put_long (info + 4, aino->dir ? 2 : -3); + put_long (info + 120, aino->dir ? 2 : -3); + x = aino->aname; } - TRACE((warning_buffer, "name=\"%s\"\n", x)); - n = strlen(x); + TRACE(("name=\"%s\"\n", x)); + n = strlen (x); if (n > 106) n = 106; i = 8; - put_byte(info + i, n); i++; - while(n--) - put_byte(info + i, *x), i++, x++; - while(i < 108) - put_byte(info + i, 0), i++; + put_byte (info + i, n); i++; + while (n--) + put_byte (info + i, *x), i++, x++; + while (i < 108) + put_byte (info + i, 0), i++; put_long (info + 116, aino->amigaos_mode); - put_long(info + 124, statbuf.st_size); + put_long (info + 124, statbuf.st_size); #ifdef HAVE_ST_BLOCKS - put_long(info + 128, statbuf.st_blocks); + put_long (info + 128, statbuf.st_blocks); #else - put_long(info + 128, statbuf.st_size / 512 + 1); + put_long (info + 128, statbuf.st_size / 512 + 1); #endif - get_time(statbuf.st_mtime, &days, &mins, &ticks); - put_long(info + 132, days); - put_long(info + 136, mins); - put_long(info + 140, ticks); - put_long(info + 144, 0); /* no comment */ - PUT_PCK_RES1 (packet, DOS_TRUE); -} - -static void do_examine(Unit *unit, dpacket packet, ExamineKey* ek, uaecptr info) -{ - struct dirent de_space; - struct dirent* de; - struct a_inode *aino; - uae_u32 err; - - if (!ek->dir) { - ek->dir = opendir (ek->aino->nname); - } - if (!ek->dir) { - free_exkey (ek); - PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); - return; - } - - de = my_readdir (ek->dir, &de_space); - - while (de && (0 == strcmp(".", de->d_name) - || 0 == strcmp("..", de->d_name))) - { - de = my_readdir (ek->dir, &de_space); - } - - if (!de) { - TRACE((warning_buffer, "no more entries\n")); - free_exkey (ek); - PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); - return; - } - - TRACE((warning_buffer, "entry=\"%s\"\n", de->d_name)); - aino = lookup_child_aino_for_exnext (unit, ek->aino, de->d_name, &err); - if (err != 0) { - write_log ("Severe problem in ExNext.\n"); - free_exkey (ek); - PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, err); - return; + get_time (statbuf.st_mtime, &days, &mins, &ticks); + put_long (info + 132, days); + put_long (info + 136, mins); + put_long (info + 140, ticks); + if (aino->comment == 0) + put_long (info + 144, 0); + else { + TRACE(("comment=\"%s\"\n", aino->comment)); + i = 144; + x = aino->comment; + if (! x) + x = ""; + n = strlen (x); + if (n > 78) + n = 78; + put_byte (info + i, n); i++; + while (n--) + put_byte (info + i, *x), i++, x++; + while (i < 224) + put_byte (info + i, 0), i++; } - get_fileinfo (unit, packet, info, aino); + PUT_PCK_RES1 (packet, DOS_TRUE); } -static void action_examine_object (Unit* unit, dpacket packet) +static void action_examine_object (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; uaecptr info = GET_PCK_ARG2 (packet) << 2; - ExamineKey* ek; - struct a_inode *aino = 0; + a_inode *aino = 0; - TRACE((warning_buffer, "ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info)); + TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info)); DUMPLOCK(unit, lock); if (lock != 0) - aino = lookup_aino (unit, get_long(lock + 4)); + aino = lookup_aino (unit, get_long (lock + 4)); if (aino == 0) aino = &unit->rootnode; get_fileinfo (unit, packet, info, aino); if (aino->dir) { - put_long(info, 0xFFFFFFFF); + put_long (info, 0xFFFFFFFF); } else - put_long(info, 0); + put_long (info, 0); +} + +/* Read a directory's contents, create a_inodes for each file, and + mark them as locked in memory so that recycle_aino will not reap + them. + We do this to avoid problems with the host OS: we don't want to + leave the directory open on the host side until all ExNext()s have + finished - they may never finish! */ + +static void populate_directory (Unit *unit, a_inode *base) +{ + DIR *d = opendir (base->nname); + a_inode *aino; + + for (aino = base->child; aino; aino = aino->sibling) { + base->locked_children++; + unit->total_locked_ainos++; + } + TRACE(("Populating directory, child %p, locked_children %d\n", + base->child, base->locked_children)); + for (;;) { + struct dirent de_space; + struct dirent *de; + uae_u32 err; + + /* Find next file that belongs to the Amiga fs (skipping things + like "..", "." etc. */ + do { + de = my_readdir (d, &de_space); + } while (de && fsdb_name_invalid (de->d_name)); + if (! de) + break; + /* This calls init_child_aino, which will notice that the parent is + being ExNext()ed, and it will increment the locked counts. */ + aino = lookup_child_aino_for_exnext (unit, base, de->d_name, &err); + } + closedir (d); } -static void action_examine_next(Unit* unit, dpacket packet) +static void do_examine (Unit *unit, dpacket packet, ExamineKey *ek, uaecptr info) +{ + if (ek->curr_file == 0) + goto no_more_entries; + + get_fileinfo (unit, packet, info, ek->curr_file); + ek->curr_file = ek->curr_file->sibling; + TRACE (("curr_file set to %p %s\n", ek->curr_file, + ek->curr_file ? ek->curr_file->aname : "NULL")); + return; + + no_more_entries: + TRACE(("no more entries\n")); + free_exkey (unit, ek); + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); +} + +static void action_examine_next (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; uaecptr info = GET_PCK_ARG2 (packet) << 2; - struct a_inode *aino = 0; + a_inode *aino = 0; ExamineKey *ek; uae_u32 uniq; - TRACE((warning_buffer, "ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info)); + TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info)); DUMPLOCK(unit, lock); if (lock != 0) - aino = lookup_aino (unit, get_long(lock + 4)); + aino = lookup_aino (unit, get_long (lock + 4)); if (aino == 0) aino = &unit->rootnode; uniq = get_long (info); if (uniq == 0) { write_log ("ExNext called for a file! (Houston?)\n"); - PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); - return; - } else if (uniq == 0xFFFFFFFF) { - ek = new_exkey(unit, aino); - } else - ek = lookup_exkey (unit, get_long(info)); + goto no_more_entries; + } else if (uniq == 0xFFFFFFFE) + goto no_more_entries; + else if (uniq == 0xFFFFFFFF) { + TRACE(("Creating new ExKey\n")); + ek = new_exkey (unit, aino); + if (ek) { + if (aino->exnext_count++ == 0) + populate_directory (unit, aino); + } + ek->curr_file = aino->child; + TRACE(("Initial curr_file: %p %s\n", ek->curr_file, + ek->curr_file ? ek->curr_file->aname : "NULL")); + } else { + TRACE(("Looking up ExKey\n")); + ek = lookup_exkey (unit, get_long (info)); + } if (ek == 0) { write_log ("Couldn't find a matching ExKey. Prepare for trouble.\n"); - PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); - return; + goto no_more_entries; } - put_long(info, ek->uniq); - do_examine(unit, packet, ek, info); + put_long (info, ek->uniq); + do_examine (unit, packet, ek, info); + return; + + no_more_entries: + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); } -static void do_find (Unit* unit, dpacket packet, int mode, int create, int fallback) +static void do_find (Unit *unit, dpacket packet, int mode, int create, int fallback) { uaecptr fh = GET_PCK_ARG1 (packet) << 2; uaecptr lock = GET_PCK_ARG2 (packet) << 2; uaecptr name = GET_PCK_ARG3 (packet) << 2; - struct a_inode *aino; + a_inode *aino; Key *k; - struct stat st; int fd; - int doserr; uae_u32 err; mode_t openmode; int aino_created = 0; - TRACE((warning_buffer, "ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n", fh, lock, bstr (unit, name), mode)); + TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n", fh, lock, bstr (unit, name), mode)); DUMPLOCK(unit, lock); aino = find_aino (unit, lock, bstr (unit, name), &err); - if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) { + if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) { /* Whatever it is, we can't handle it. */ PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, err); @@ -1660,10 +1968,10 @@ static void do_find (Unit* unit, dpacket return; } else { /* Object does not exist. aino points to containing directory. */ - aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1); + aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 0); if (aino == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */ + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ return; } aino_created = 1; @@ -1683,7 +1991,7 @@ static void do_find (Unit* unit, dpacket if (aino_created) delete_aino (unit, aino); PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, dos_errno()); + PUT_PCK_RES2 (packet, dos_errno ()); return; } k = new_key (unit); @@ -1700,13 +2008,70 @@ static void do_find (Unit* unit, dpacket } static void -action_find_input(Unit* unit, dpacket packet) +action_fh_from_lock (Unit *unit, dpacket packet) +{ + uaecptr fh = GET_PCK_ARG1 (packet) << 2; + uaecptr lock = GET_PCK_ARG2 (packet) << 2; + a_inode *aino; + Key *k; + int fd; + mode_t openmode; + int mode; + + TRACE(("ACTION_FH_FROM_LOCK(0x%lx,0x%lx)\n",fh,lock)); + DUMPLOCK(unit,lock); + + if (!lock) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, 0); + return; + } + + aino = lookup_aino (unit, get_long (lock + 4)); + if (aino == 0) + aino = &unit->rootnode; + mode = aino->amigaos_mode; /* Use same mode for opened filehandle as existing Lock() */ + + prepare_for_open (aino->nname); + TRACE ((" mode is %d\n", mode)); + openmode = (((mode & A_FIBF_READ) ? O_WRONLY + : (mode & A_FIBF_WRITE) ? O_RDONLY + : O_RDWR)); + + /* the files on CD really can have the write-bit set. */ + if (unit->ui.readonly) + openmode = O_RDONLY; + + fd = open (aino->nname, openmode | O_BINARY, 0777); + + if (fd < 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno()); + return; + } + k = new_key (unit); + k->fd = fd; + k->aino = aino; + + put_long (fh+36, k->uniq); + /* I don't think I need to play with shlock count here, because I'm + opening from an existing lock ??? */ + + /* Is this right? I don't completely understand how this works. Do I + also need to free_lock() my lock, since nobody else is going to? */ + de_recycle_aino (unit, aino); + PUT_PCK_RES1 (packet, DOS_TRUE); + /* PUT_PCK_RES2 (packet, k->uniq); - this shouldn't be necessary, try without it */ +} + +static void +action_find_input (Unit *unit, dpacket packet) { do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1); } static void -action_find_output(Unit* unit, dpacket packet) +action_find_output (Unit *unit, dpacket packet) { if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); @@ -1717,7 +2082,7 @@ action_find_output(Unit* unit, dpacket p } static void -action_find_write(Unit* unit, dpacket packet) +action_find_write (Unit *unit, dpacket packet) { if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); @@ -1728,10 +2093,10 @@ action_find_write(Unit* unit, dpacket pa } static void -action_end(Unit* unit, dpacket packet) +action_end (Unit *unit, dpacket packet) { Key *k; - TRACE((warning_buffer, "ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet))); + TRACE(("ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet))); k = lookup_key (unit, GET_PCK_ARG1 (packet)); if (k != 0) { @@ -1747,7 +2112,7 @@ action_end(Unit* unit, dpacket packet) } static void -action_read(Unit* unit, dpacket packet) +action_read (Unit *unit, dpacket packet) { Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); uaecptr addr = GET_PCK_ARG2 (packet); @@ -1759,7 +2124,7 @@ action_read(Unit* unit, dpacket packet) /* PUT_PCK_RES2 (packet, EINVAL); */ return; } - TRACE((warning_buffer, "ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size)); + TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size)); #ifdef RELY_ON_LOADSEG_DETECTION /* HACK HACK HACK HACK * Try to detect a LoadSeg() */ @@ -1789,11 +2154,10 @@ action_read(Unit* unit, dpacket packet) } } else { char *buf; - sprintf (warning_buffer, "unixfs warning: Bad pointer passed for read: %08x\n", addr); - write_log (warning_buffer); + write_log ("unixfs warning: Bad pointer passed for read: %08x\n", addr); /* ugh this is inefficient but easy */ buf = (char *)malloc(size); - if(!buf) { + if (!buf) { PUT_PCK_RES1 (packet, -1); PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE); return; @@ -1806,16 +2170,16 @@ action_read(Unit* unit, dpacket packet) } else { int i; PUT_PCK_RES1 (packet, actual); - for(i = 0; i < actual; i++) - put_byte(addr + i, buf[i]); + for (i = 0; i < actual; i++) + put_byte (addr + i, buf[i]); k->file_pos += actual; } - free(buf); + free (buf); } } static void -action_write(Unit* unit, dpacket packet) +action_write (Unit *unit, dpacket packet) { Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); uaecptr addr = GET_PCK_ARG2 (packet); @@ -1829,7 +2193,7 @@ action_write(Unit* unit, dpacket packet) return; } - TRACE((warning_buffer, "ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size)); + TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size)); if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); @@ -1846,7 +2210,7 @@ action_write(Unit* unit, dpacket packet) } for (i = 0; i < size; i++) - buf[i] = get_byte(addr + i); + buf[i] = get_byte (addr + i); PUT_PCK_RES1 (packet, write(k->fd, buf, size)); if (GET_PCK_RES1 (packet) != size) @@ -1854,13 +2218,13 @@ action_write(Unit* unit, dpacket packet) if (GET_PCK_RES1 (packet) >= 0) k->file_pos += GET_PCK_RES1 (packet); - free(buf); + free (buf); } static void -action_seek(Unit* unit, dpacket packet) +action_seek (Unit *unit, dpacket packet) { - Key* k = lookup_key (unit, GET_PCK_ARG1 (packet)); + Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); long pos = (uae_s32)GET_PCK_ARG2 (packet); long mode = (uae_s32)GET_PCK_ARG3 (packet); off_t res; @@ -1876,9 +2240,25 @@ action_seek(Unit* unit, dpacket packet) if (mode > 0) whence = SEEK_END; if (mode < 0) whence = SEEK_SET; - TRACE((warning_buffer, "ACTION_SEEK(%s,%d,%d)\n", k->aino->nname, pos, mode)); + TRACE(("ACTION_SEEK(%s,%d,%d)\n", k->aino->nname, pos, mode)); old = lseek (k->fd, 0, SEEK_CUR); + { + uae_s32 temppos; + long filesize = lseek (k->fd, 0, SEEK_END); + lseek (k->fd, old, SEEK_SET); + + if (whence == SEEK_CUR) temppos = old + pos; + if (whence == SEEK_SET) temppos = pos; + if (whence == SEEK_END) temppos = filesize + pos; + if (filesize < temppos) { + res = -1; + PUT_PCK_RES1 (packet,res); + PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR); + return; + } + } + res = lseek (k->fd, pos, whence); if (-1 == res) { @@ -1890,16 +2270,15 @@ action_seek(Unit* unit, dpacket packet) } static void -action_set_protect(Unit* unit, dpacket packet) +action_set_protect (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG2 (packet) << 2; uaecptr name = GET_PCK_ARG3 (packet) << 2; uae_u32 mask = GET_PCK_ARG4 (packet); - mode_t mode; - struct a_inode *a; + a_inode *a; uae_u32 err; - TRACE((warning_buffer, "ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask)); + TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask)); if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); @@ -1914,7 +2293,7 @@ action_set_protect(Unit* unit, dpacket p return; } - err = set_file_attrs (a, mask); + err = fsdb_set_file_attrs (a, mask); if (err != 0) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, err); @@ -1923,13 +2302,55 @@ action_set_protect(Unit* unit, dpacket p } } +static void action_set_comment (Unit * unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG2 (packet) << 2; + uaecptr name = GET_PCK_ARG3 (packet) << 2; + uaecptr comment = GET_PCK_ARG4 (packet) << 2; + char *commented; + a_inode *a; + uae_u32 err; + long res1, res2; + + if (unit->ui.readonly) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); + return; + } + + commented = bstr (unit, comment); + commented = strlen (commented) > 0 ? my_strdup (commented) : 0; + TRACE (("ACTION_SET_COMMENT(0x%lx,\"%s\")\n", lock, commented)); + + a = find_aino (unit, lock, bstr (unit, name), &err); + if (err != 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + + maybe_free_and_out: + if (commented) + free (commented); + return; + } + PUT_PCK_RES1 (packet, DOS_TRUE); + PUT_PCK_RES2 (packet, 0); + if (a->comment == 0 && commented == 0) + goto maybe_free_and_out; + if (a->comment != 0 && commented != 0 && strcmp (a->comment, commented) == 0) + goto maybe_free_and_out; + if (a->comment) + free (a->comment); + a->comment = commented; + a->dirty = 1; +} + static void -action_same_lock(Unit* unit, dpacket packet) +action_same_lock (Unit *unit, dpacket packet) { uaecptr lock1 = GET_PCK_ARG1 (packet) << 2; uaecptr lock2 = GET_PCK_ARG2 (packet) << 2; - TRACE((warning_buffer, "ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2)); + TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2)); DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2); if (!lock1 || !lock2) { @@ -1940,20 +2361,78 @@ action_same_lock(Unit* unit, dpacket pac } static void -action_parent(Unit* unit, dpacket packet) +action_change_mode (Unit *unit, dpacket packet) { - uaecptr lock = GET_PCK_ARG1 (packet) << 2; - struct a_inode *a, *olda; +#define CHANGE_LOCK 0 +#define CHANGE_FH 1 + /* will be CHANGE_FH or CHANGE_LOCK value */ + long type = GET_PCK_ARG1 (packet); + /* either a file-handle or lock */ + uaecptr object = GET_PCK_ARG2 (packet) << 2; + /* will be EXCLUSIVE_LOCK/SHARED_LOCK if CHANGE_LOCK, + * or MODE_OLDFILE/MODE_NEWFILE/MODE_READWRITE if CHANGE_FH */ + long mode = GET_PCK_ARG3 (packet); + unsigned long uniq; + a_inode *a = NULL, *olda = NULL; + uae_u32 err = 0; + TRACE(("ACTION_CHANGE_MODE(0x%lx,%d,%d)\n",object,type,mode)); + + if (! object + || (type != CHANGE_FH && type != CHANGE_LOCK)) + { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK); + return; + } - TRACE((warning_buffer, "ACTION_PARENT(0x%lx)\n",lock)); + /* @@@ Brian: shouldn't this be good enough to support + CHANGE_FH? */ + if (type == CHANGE_FH) + mode = (mode == 1006 ? -1 : -2); - if (!lock) { - PUT_PCK_RES1 (packet, 0); - PUT_PCK_RES2 (packet, 0); + if (type == CHANGE_LOCK) + uniq = get_long (object + 4); + else { + Key *k = lookup_key (unit, object); + if (!k) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); + return; + } + uniq = k->aino->uniq; + } + a = lookup_aino (unit, uniq); + + if (! a) + err = ERROR_INVALID_LOCK; + else { + if (mode == -1) { + if (a->shlock > 1) + err = ERROR_OBJECT_IN_USE; + else { + a->shlock = 0; + a->elock = 1; + } + } else { /* Must be SHARED_LOCK == -2 */ + a->elock = 0; + a->shlock++; + } + } + + if (err) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); return; + } else { + de_recycle_aino (unit, a); + PUT_PCK_RES1 (packet, DOS_TRUE); } +} - olda = lookup_aino (unit, get_long(lock + 4)); +static void +action_parent_common (Unit *unit, dpacket packet, unsigned long uniq) +{ + a_inode *olda = lookup_aino (unit, uniq); if (olda == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK); @@ -1976,14 +2455,41 @@ action_parent(Unit* unit, dpacket packet } static void -action_create_dir(Unit* unit, dpacket packet) +action_parent_fh (Unit *unit, dpacket packet) +{ + Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); + if (!k) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); + return; + } + action_parent_common (unit, packet, k->aino->uniq); +} + +static void +action_parent (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + + TRACE(("ACTION_PARENT(0x%lx)\n",lock)); + + if (!lock) { + PUT_PCK_RES1 (packet, 0); + PUT_PCK_RES2 (packet, 0); + return; + } + action_parent_common (unit, packet, get_long (lock + 4)); +} + +static void +action_create_dir (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; uaecptr name = GET_PCK_ARG2 (packet) << 2; - struct a_inode *aino; + a_inode *aino; uae_u32 err; - TRACE((warning_buffer, "ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name))); + TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name))); if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); @@ -1992,7 +2498,7 @@ action_create_dir(Unit* unit, dpacket pa } aino = find_aino (unit, lock, bstr (unit, name), &err); - if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) { + if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, err); return; @@ -2004,10 +2510,10 @@ action_create_dir(Unit* unit, dpacket pa return; } /* Object does not exist. aino points to containing directory. */ - aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 2); + aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1); if (aino == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */ + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ return; } @@ -2022,14 +2528,14 @@ action_create_dir(Unit* unit, dpacket pa } static void -action_examine_fh(Unit* unit, dpacket packet) +action_examine_fh (Unit *unit, dpacket packet) { Key *k; - ExamineKey* ek; - struct a_inode *aino = 0; + a_inode *aino = 0; uaecptr info = GET_PCK_ARG2 (packet) << 2; - TRACE((warning_buffer, "ACTION_EXAMINE_FH(0x%lx,0x%lx)\n", GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) )); + TRACE(("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n", + GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) )); k = lookup_key (unit, GET_PCK_ARG1 (packet)); if (k != 0) @@ -2039,9 +2545,9 @@ action_examine_fh(Unit* unit, dpacket pa get_fileinfo (unit, packet, info, aino); if (aino->dir) - put_long(info, 0xFFFFFFFF); + put_long (info, 0xFFFFFFFF); else - put_long(info, 0); + put_long (info, 0); } /* For a nice example of just how contradictory documentation can be, see the @@ -2049,24 +2555,22 @@ action_examine_fh(Unit* unit, dpacket pa * This implementation tries to mimic the behaviour of the Kick 3.1 ramdisk * (which seems to match the Autodoc description). */ static void -action_set_file_size(Unit* unit, dpacket packet) +action_set_file_size (Unit *unit, dpacket packet) { - int error = 0; - char chunk = 0; Key *k, *k1; off_t offset = GET_PCK_ARG2 (packet); long mode = (uae_s32)GET_PCK_ARG3 (packet); int whence = SEEK_CUR; - + if (mode > 0) whence = SEEK_END; if (mode < 0) whence = SEEK_SET; - TRACE((warning_buffer, "ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n", GET_PCK_ARG1 (packet), offset, mode)); + TRACE(("ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n", GET_PCK_ARG1 (packet), offset, mode)); k = lookup_key (unit, GET_PCK_ARG1 (packet)); if (k == 0) { PUT_PCK_RES1 (packet, DOS_TRUE); - PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); return; } @@ -2086,7 +2590,11 @@ action_set_file_size(Unit* unit, dpacket k->file_pos = offset; lseek (k->fd, k->file_pos, SEEK_SET); - if (truncate (k->aino->nname, k->file_pos) == -1) { + /* Brian: no bug here; the file _must_ be one byte too large after writing + The write is supposed to guarantee that the file can't be smaller than + the requested size, the truncate guarantees that it can't be larger. + If we were to write one byte earlier we'd clobber file data. */ + if (truncate (k->aino->nname, offset) == -1) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, dos_errno ()); return; @@ -2097,14 +2605,14 @@ action_set_file_size(Unit* unit, dpacket } static void -action_delete_object(Unit* unit, dpacket packet) +action_delete_object (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; uaecptr name = GET_PCK_ARG2 (packet) << 2; - struct a_inode *a; + a_inode *a; uae_u32 err; - TRACE((warning_buffer, "ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name))); + TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name))); if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); @@ -2119,12 +2627,19 @@ action_delete_object(Unit* unit, dpacket PUT_PCK_RES2 (packet, err); return; } + if (a->amigaos_mode & A_FIBF_DELETE) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED); + return; + } if (a->shlock > 0 || a->elock) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE); return; } if (a->dir) { + /* This should take care of removing the fsdb if no files remain. */ + fsdb_dir_writeback (a); if (rmdir (a->nname) == -1) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, dos_errno()); @@ -2146,24 +2661,25 @@ action_delete_object(Unit* unit, dpacket } static void -action_set_date(Unit* unit, dpacket packet) +action_set_date (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG2 (packet) << 2; uaecptr name = GET_PCK_ARG3 (packet) << 2; uaecptr date = GET_PCK_ARG4 (packet); - struct a_inode *a; + a_inode *a; struct utimbuf ut; uae_u32 err; - TRACE((warning_buffer, "ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name))); + TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name))); - if(unit->ui.readonly) { + if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); return; } - ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8)); + ut.actime = ut.modtime = put_time(get_long (date), get_long (date + 4), + get_long (date + 8)); a = find_aino (unit, lock, bstr (unit, name), &err); if (err == 0 && utime (a->nname, &ut) == -1) err = dos_errno (); @@ -2175,19 +2691,19 @@ action_set_date(Unit* unit, dpacket pack } static void -action_rename_object(Unit* unit, dpacket packet) +action_rename_object (Unit *unit, dpacket packet) { uaecptr lock1 = GET_PCK_ARG1 (packet) << 2; uaecptr name1 = GET_PCK_ARG2 (packet) << 2; uaecptr lock2 = GET_PCK_ARG3 (packet) << 2; uaecptr name2 = GET_PCK_ARG4 (packet) << 2; - struct a_inode *a1, *a2; + a_inode *a1, *a2; uae_u32 err1, err2; - TRACE((warning_buffer, "ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1))); - TRACE((warning_buffer, "0x%lx,\"%s\")\n", lock2, bstr (unit, name2))); + TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1))); + TRACE(("0x%lx,\"%s\")\n", lock2, bstr (unit, name2))); - if(unit->ui.readonly) { + if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); return; @@ -2199,47 +2715,61 @@ action_rename_object(Unit* unit, dpacket PUT_PCK_RES2 (packet, err1); return; } + /* See whether the other name already exists in the filesystem. */ a2 = find_aino (unit, lock2, bstr (unit, name2), &err2); - if (a2 == 0 || err2 != ERROR_OBJECT_NOT_FOUND) { + if (a2 == a1) { + /* Renaming to the same name, but possibly different case. */ + if (strcmp (a1->aname, bstr_cut (unit, name2)) == 0) { + /* Exact match -> do nothing. */ + PUT_PCK_RES1 (packet, DOS_TRUE); + return; + } + a2 = a2->parent; + } else if (a2 == 0 || err2 != ERROR_OBJECT_NOT_AROUND) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2); return; } - /* Object does not exist. aino points to containing directory. */ - a2 = new_child_aino (unit, a2, my_strdup (bstr_cut (unit, name2)), a1->dir ? 2 : 1); + + a2 = create_child_aino (unit, a2, bstr_cut (unit, name2), a1->dir); if (a2 == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */ + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ return; } /* @@@ what should we do if there are locks on a1? */ - if(-1 == rename(a1->nname, a2->nname)) { + if (-1 == rename (a1->nname, a2->nname)) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, dos_errno()); + PUT_PCK_RES2 (packet, dos_errno ()); return; } + a2->comment = a1->comment; + a1->comment = 0; + a2->amigaos_mode = a1->amigaos_mode; + a2->uniq = a1->uniq; + move_exkeys (unit, a1, a2); move_aino_children (unit, a1, a2); delete_aino (unit, a1); PUT_PCK_RES1 (packet, DOS_TRUE); } static void -action_current_volume(Unit* unit, dpacket packet) +action_current_volume (Unit *unit, dpacket packet) { PUT_PCK_RES1 (packet, unit->volume >> 2); } static void -action_rename_disk(Unit* unit, dpacket packet) +action_rename_disk (Unit *unit, dpacket packet) { uaecptr name = GET_PCK_ARG1 (packet) << 2; int i; int namelen; - TRACE((warning_buffer, "ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name))); + TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name))); - if(unit->ui.readonly) { + if (unit->ui.readonly) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED); return; @@ -2249,25 +2779,25 @@ action_rename_disk(Unit* unit, dpacket p namelen = get_byte (name); name++; free (unit->ui.volname); unit->ui.volname = (char *) xmalloc (namelen + 1); - for(i = 0; i < namelen; i++, name++) + for (i = 0; i < namelen; i++, name++) unit->ui.volname[i] = get_byte (name); unit->ui.volname[i] = 0; put_byte (unit->volume + 44, namelen); - for(i = 0; i < namelen; i++) + for (i = 0; i < namelen; i++) put_byte (unit->volume + 45 + i, unit->ui.volname[i]); PUT_PCK_RES1 (packet, DOS_TRUE); } static void -action_is_filesystem(Unit* unit, dpacket packet) +action_is_filesystem (Unit *unit, dpacket packet) { PUT_PCK_RES1 (packet, DOS_TRUE); } static void -action_flush(Unit* unit, dpacket packet) +action_flush (Unit *unit, dpacket packet) { /* sync(); */ /* pretty drastic, eh */ PUT_PCK_RES1 (packet, DOS_TRUE); @@ -2277,8 +2807,10 @@ action_flush(Unit* unit, dpacket packet) * know whether AmigaOS takes care of that, but this does. */ static uae_sem_t singlethread_int_sem; -static uae_u32 exter_int_helper (void) +static uae_u32 exter_int_helper (TrapContext *dummy) { + UnitInfo *uip = current_mountinfo->ui; + uaecptr port; static int unit_no; switch (m68k_dreg (regs, 0)) { @@ -2304,6 +2836,7 @@ static uae_u32 exter_int_helper (void) * Note that this is called from the main loop, unlike the other cases * in this switch statement which are called from the interrupt handler. */ +#ifdef UAE_FILESYS_THREADS { Unit *unit = find_unit (m68k_areg (regs, 5)); unit->cmds_complete = unit->cmds_acked; @@ -2317,29 +2850,63 @@ static uae_u32 exter_int_helper (void) put_long (m68k_areg (regs, 3), locks); } } +#else + write_log ("exter_int_helper should not be called with arg 1!\n"); +#endif break; case 2: + /* Find work that needs to be done: + * return d0 = 0: none + * d0 = 1: PutMsg(), port in a0, message in a1 + * d0 = 2: Signal(), task in a1, signal set in d1 + * d0 = 3: ReplyMsg(), message in a1 */ + +#ifdef SUPPORT_THREADS + /* First, check signals/messages */ + while (comm_pipe_has_data (&native2amiga_pending)) { + switch (read_comm_pipe_int_blocking (&native2amiga_pending)) { + case 0: /* Signal() */ + m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + m68k_dreg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + return 2; + + case 1: /* PutMsg() */ + m68k_areg (regs, 0) = read_comm_pipe_u32_blocking (&native2amiga_pending); + m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + return 1; + + case 2: /* ReplyMsg() */ + m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending); + return 3; + + default: + write_log ("exter_int_helper: unknown native action\n"); + break; + } + } +#endif + /* Find some unit that needs a message sent, and return its port, * or zero if all are done. * Take care not to dereference self for units that didn't have their * startup packet sent. */ for (;;) { - if (unit_no >= num_units) + if (unit_no >= current_mountinfo->num_units) return 0; - if (ui[unit_no].self != 0 - && ui[unit_no].self->cmds_acked == ui[unit_no].self->cmds_complete - && ui[unit_no].self->cmds_acked != ui[unit_no].self->cmds_sent) + + if (uip[unit_no].self != 0 + && uip[unit_no].self->cmds_acked == uip[unit_no].self->cmds_complete + && uip[unit_no].self->cmds_acked != uip[unit_no].self->cmds_sent) break; unit_no++; } - ui[unit_no].self->cmds_acked = ui[unit_no].self->cmds_sent; - return ui[unit_no++].self->port; - - case 3: - /* Look up a message for a port. */ - { - Unit *unit = find_unit (m68k_areg (regs, 2)); - return unit->dummy_message; + uip[unit_no].self->cmds_acked = uip[unit_no].self->cmds_sent; + port = uip[unit_no].self->port; + if (port) { + m68k_areg (regs, 0) = port; + m68k_areg (regs, 1) = find_unit (port)->dummy_message; + unit_no++; + return 1; } break; case 4: @@ -2359,43 +2926,44 @@ static int handle_packet (Unit *unit, dp uae_s32 type = GET_PCK_TYPE (pck); PUT_PCK_RES2 (pck, 0); switch (type) { - case ACTION_LOCATE_OBJECT: action_lock(unit, pck); break; - case ACTION_FREE_LOCK: action_free_lock(unit, pck); break; - case ACTION_COPY_DIR: action_dup_lock(unit, pck); break; - case ACTION_DISK_INFO: action_disk_info(unit, pck); break; - case ACTION_INFO: action_info(unit, pck); break; - case ACTION_EXAMINE_OBJECT: action_examine_object(unit, pck); break; - case ACTION_EXAMINE_NEXT: action_examine_next(unit, pck); break; - case ACTION_FIND_INPUT: action_find_input(unit, pck); break; - case ACTION_FIND_WRITE: action_find_write(unit, pck); break; - case ACTION_FIND_OUTPUT: action_find_output(unit, pck); break; - case ACTION_END: action_end(unit, pck); break; - case ACTION_READ: action_read(unit, pck); break; - case ACTION_WRITE: action_write(unit, pck); break; - case ACTION_SEEK: action_seek(unit, pck); break; - case ACTION_SET_PROTECT: action_set_protect(unit, pck); break; - case ACTION_SAME_LOCK: action_same_lock(unit, pck); break; - case ACTION_PARENT: action_parent(unit, pck); break; - case ACTION_CREATE_DIR: action_create_dir(unit, pck); break; - case ACTION_DELETE_OBJECT: action_delete_object(unit, pck); break; - case ACTION_RENAME_OBJECT: action_rename_object(unit, pck); break; - case ACTION_SET_DATE: action_set_date(unit, pck); break; - case ACTION_CURRENT_VOLUME: action_current_volume(unit, pck); break; - case ACTION_RENAME_DISK: action_rename_disk(unit, pck); break; - case ACTION_IS_FILESYSTEM: action_is_filesystem(unit, pck); break; - case ACTION_FLUSH: action_flush(unit, pck); break; + case ACTION_LOCATE_OBJECT: action_lock (unit, pck); break; + case ACTION_FREE_LOCK: action_free_lock (unit, pck); break; + case ACTION_COPY_DIR: action_dup_lock (unit, pck); break; + case ACTION_DISK_INFO: action_disk_info (unit, pck); break; + case ACTION_INFO: action_info (unit, pck); break; + case ACTION_EXAMINE_OBJECT: action_examine_object (unit, pck); break; + case ACTION_EXAMINE_NEXT: action_examine_next (unit, pck); break; + case ACTION_FIND_INPUT: action_find_input (unit, pck); break; + case ACTION_FIND_WRITE: action_find_write (unit, pck); break; + case ACTION_FIND_OUTPUT: action_find_output (unit, pck); break; + case ACTION_END: action_end (unit, pck); break; + case ACTION_READ: action_read (unit, pck); break; + case ACTION_WRITE: action_write (unit, pck); break; + case ACTION_SEEK: action_seek (unit, pck); break; + case ACTION_SET_PROTECT: action_set_protect (unit, pck); break; + case ACTION_SET_COMMENT: action_set_comment (unit, pck); break; + case ACTION_SAME_LOCK: action_same_lock (unit, pck); break; + case ACTION_PARENT: action_parent (unit, pck); break; + case ACTION_CREATE_DIR: action_create_dir (unit, pck); break; + case ACTION_DELETE_OBJECT: action_delete_object (unit, pck); break; + case ACTION_RENAME_OBJECT: action_rename_object (unit, pck); break; + case ACTION_SET_DATE: action_set_date (unit, pck); break; + case ACTION_CURRENT_VOLUME: action_current_volume (unit, pck); break; + case ACTION_RENAME_DISK: action_rename_disk (unit, pck); break; + case ACTION_IS_FILESYSTEM: action_is_filesystem (unit, pck); break; + case ACTION_FLUSH: action_flush (unit, pck); break; /* 2.0+ packet types */ - case ACTION_SET_FILE_SIZE: action_set_file_size(unit, pck); break; - case ACTION_EXAMINE_FH: action_examine_fh(unit, pck); break; + case ACTION_SET_FILE_SIZE: action_set_file_size (unit, pck); break; + case ACTION_EXAMINE_FH: action_examine_fh (unit, pck); break; + case ACTION_FH_FROM_LOCK: action_fh_from_lock (unit, pck); break; + case ACTION_CHANGE_MODE: action_change_mode (unit, pck); break; + case ACTION_PARENT_FH: action_parent_fh (unit, pck); break; /* unsupported packets */ case ACTION_LOCK_RECORD: case ACTION_FREE_RECORD: - case ACTION_CHANGE_MODE: - case ACTION_FH_FROM_LOCK: case ACTION_COPY_DIR_FH: - case ACTION_PARENT_FH: case ACTION_EXAMINE_ALL: case ACTION_MAKE_LINK: case ACTION_READ_LINK: @@ -2403,14 +2971,14 @@ static int handle_packet (Unit *unit, dp case ACTION_ADD_NOTIFY: case ACTION_REMOVE_NOTIFY: default: - TRACE((warning_buffer, "*** UNSUPPORTED PACKET %ld\n", type)); + TRACE(("*** UNSUPPORTED PACKET %ld\n", type)); return 0; } return 1; } #ifdef UAE_FILESYS_THREADS -static void *filesys_penguin (void *unit_v) +static void *filesys_thread (void *unit_v) { UnitInfo *ui = (UnitInfo *)unit_v; for (;;) { @@ -2423,13 +2991,13 @@ static void *filesys_penguin (void *unit msg = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe); morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe); - if (ui->self->reset_state == FS_GO_DOWN) { + if (ui->reset_state == FS_GO_DOWN) { if (pck != 0) continue; /* Death message received. */ - uae_sem_post (&ui->self->reset_sync_sem); - /* No more messages should arrive until we restart. */ - continue; + uae_sem_post (&ui->reset_sync_sem); + /* Die. */ + return 0; } put_long (get_long (morelocks), get_long (ui->self->locklist)); @@ -2446,9 +3014,14 @@ static void *filesys_penguin (void *unit /* The message is sent by our interrupt handler, so make sure an interrupt * happens. */ uae_int_requested = 1; + + uae_sem_wait (&packet_counter_sem); + active_fs_packets--; + uae_sem_post (&packet_counter_sem); + /* Send back the locks. */ if (get_long (ui->self->locklist) != 0) - write_comm_pipe_int (ui->back_pipe, (int)(get_long(ui->self->locklist)), 0); + write_comm_pipe_int (ui->back_pipe, (int)(get_long (ui->self->locklist)), 0); put_long (ui->self->locklist, 0); } return 0; @@ -2456,7 +3029,7 @@ static void *filesys_penguin (void *unit #endif /* Talk about spaghetti code... */ -static uae_u32 filesys_handler(void) +static uae_u32 filesys_handler (TrapContext *dummy) { Unit *unit = find_unit (m68k_areg (regs, 5)); uaecptr packet_addr = m68k_dreg (regs, 3); @@ -2470,9 +3043,11 @@ static uae_u32 filesys_handler(void) pck = get_real_address (packet_addr); msg = get_real_address (message_addr); +#if 0 if (unit->reset_state == FS_GO_DOWN) /* You might as well queue it, if you live long enough */ return 1; +#endif do_put_mem_long ((uae_u32 *)(msg + 4), -1); if (!unit || !unit->volume) { @@ -2487,6 +3062,10 @@ static uae_u32 filesys_handler(void) put_long (m68k_areg (regs, 3), get_long (get_long (morelocks))); put_long (get_long (morelocks), 0); + uae_sem_wait (&packet_counter_sem); + active_fs_packets++; + uae_sem_post (&packet_counter_sem); + /* The packet wasn't processed yet. */ do_put_mem_long ((uae_u32 *)(msg + 4), 0); write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)pck, 0); @@ -2502,159 +3081,600 @@ static uae_u32 filesys_handler(void) PUT_PCK_RES1 (pck, DOS_FALSE); PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN); } - TRACE((warning_buffer, "reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck))); + TRACE(("reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck))); error2: return 0; } -void filesys_reset (void) +static int current_deviceno = 0; +static int current_cdrom = 0; + +static void reset_uaedevices (void) { - Unit *u, *u1; + current_deviceno = 0; + current_cdrom = 0; +} + +static void init_filesys_diagentry (void) +{ + do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname); + do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev); + do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname); + do_put_mem_long ((uae_u32 *)(filesysory + 0x210c), current_mountinfo->num_units); +} + +void filesys_start_threads (void) +{ + UnitInfo *uip; int i; - for (i = 0; i < num_units; i++) { - ui[i].self = 0; + current_mountinfo = dup_mountinfo (currprefs.mountinfo); + + reset_uaedevices (); + + uip = current_mountinfo->ui; + for (i = 0; i < current_mountinfo->num_units; i++) { + UnitInfo *ui = &uip[i]; + ui->unit_pipe = 0; + +#ifdef UAE_FILESYS_THREADS + if (hardfile_fs_type (current_mountinfo, i) == FILESYS_VIRTUAL) { + uip[i].unit_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe)); + uip[i].back_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe)); + init_comm_pipe (uip[i].unit_pipe, 50, 3); + init_comm_pipe (uip[i].back_pipe, 50, 1); + uae_start_thread (filesys_thread, (void *)(uip + i), &uip[i].tid); + } +#endif } +} + +void filesys_reset (void) +{ + Unit *u, *u1; + + /* We get called once from customreset at the beginning of the program + * before filesys_start_threads has been called. Survive that. */ + if (current_mountinfo == 0) + return; - for(u = units; u; u = u1) { + for (u = units; u; u = u1) { u1 = u->next; free (u); } unit_num = 0; units = 0; + + free_mountinfo (current_mountinfo); + current_mountinfo = 0; +} + +static void free_all_ainos (Unit *u, a_inode *parent) +{ + a_inode *a; + while (a = parent->child) { + free_all_ainos (u, a); + dispose_aino (u, &parent->child, a); + } } + void filesys_prepare_reset (void) { - Unit *u, *u1; + UnitInfo *uip = current_mountinfo->ui; + Unit *u; int i; #ifdef UAE_FILESYS_THREADS - for (i = 0; i < num_units; i++) { - if (ui[i].self != 0) { - uae_sem_init (&ui[i].self->reset_sync_sem, 0, 0); - ui[i].self->reset_state = FS_GO_DOWN; + for (i = 0; i < current_mountinfo->num_units; i++) { + if (uip[i].unit_pipe != 0) { + uae_sem_init (&uip[i].reset_sync_sem, 0, 0); + uip[i].reset_state = FS_GO_DOWN; /* send death message */ - write_comm_pipe_int (ui[i].unit_pipe, 0, 0); - write_comm_pipe_int (ui[i].unit_pipe, 0, 0); - write_comm_pipe_int (ui[i].unit_pipe, 0, 1); - uae_sem_wait (&ui[i].self->reset_sync_sem); + write_comm_pipe_int (uip[i].unit_pipe, 0, 0); + write_comm_pipe_int (uip[i].unit_pipe, 0, 0); + write_comm_pipe_int (uip[i].unit_pipe, 0, 1); + uae_sem_wait (&uip[i].reset_sync_sem); } } #endif u = units; while (u != 0) { - while (u->rootnode.next != &u->rootnode) { - struct a_inode *a = u->rootnode.next; - u->rootnode.next = a->next; - free (a->nname); - free (a->aname); - free (a); - } + free_all_ainos (u, &u->rootnode); + u->rootnode.next = u->rootnode.prev = &u->rootnode; + u->aino_cache_size = 0; u = u->next; } } -static uae_u32 filesys_diagentry(void) +static uae_u32 filesys_diagentry (TrapContext *dummy) { - uaecptr resaddr = m68k_areg(regs, 2) + 0x10; - - TRACE ((warning_buffer, "filesystem: diagentry called\n")); + uaecptr resaddr = m68k_areg (regs, 2) + 0x10; + uaecptr start = resaddr; + uaecptr residents, tmp; - filesys_configdev = m68k_areg(regs, 3); + TRACE (("filesystem: diagentry called\n")); - do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname); - do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev); - do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname); - do_put_mem_long ((uae_u32 *)(filesysory + 0x210c), num_units); + filesys_configdev = m68k_areg (regs, 3); + init_filesys_diagentry (); uae_sem_init (&singlethread_int_sem, 0, 1); if (ROM_hardfile_resid != 0) { /* Build a struct Resident. This will set up and initialize * the uae.device */ - put_word(resaddr + 0x0, 0x4AFC); - put_long(resaddr + 0x2, resaddr); - put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */ - put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */ - put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */ - put_long(resaddr + 0xE, ROM_hardfile_resname); - put_long(resaddr + 0x12, ROM_hardfile_resid); - put_long(resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */ + put_word (resaddr + 0x0, 0x4AFC); + put_long (resaddr + 0x2, resaddr); + put_long (resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */ + put_word (resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */ + put_word (resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */ + put_long (resaddr + 0xE, ROM_hardfile_resname); + put_long (resaddr + 0x12, ROM_hardfile_resid); + put_long (resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */ } resaddr += 0x1A; + tmp = resaddr; - filesys_reset (); /* The good thing about this function is that it always gets called * when we boot. So we could put all sorts of stuff that wants to be done - * here. */ + * here. + * We can simply add more Resident structures here. Although the Amiga OS + * only knows about the one at address DiagArea + 0x10, we scan for other + * Resident structures and call InitResident() for them at the end of the + * diag entry. */ + + resaddr = scsidev_startup(resaddr); + native2amiga_startup(); + + /* scan for Residents and return pointer to array of them */ + residents = resaddr; + while (tmp < residents && tmp > start) { + if (get_word (tmp) == 0x4AFC && + get_long (tmp + 0x2) == tmp) { + put_word (resaddr, 0x227C); /* movea.l #tmp,a1 */ + put_long (resaddr + 2, tmp); + put_word (resaddr + 6, 0x7200); /* moveq.l #0,d1 */ + put_long (resaddr + 8, 0x4EAEFF9A); /* jsr -$66(a6) ; InitResident */ + resaddr += 12; + tmp = get_long (tmp + 0x6); + } else { + tmp++; + } + } + /* call setup_exter */ + put_word (resaddr + 0, 0x2079); + put_long (resaddr + 2, RTAREA_BASE + 28 + 4); /* move.l RTAREA_BASE+32,a0 */ + put_word (resaddr + 6, 0xd1fc); + put_long (resaddr + 8, RTAREA_BASE + 8 + 4); /* add.l #RTAREA_BASE+12,a0 */ + put_word (resaddr + 12, 0x4e90); /* jsr (a0) */ + put_word (resaddr + 14, 0x7001); /* moveq.l #1,d0 */ + put_word (resaddr + 16, RTS); + m68k_areg (regs, 0) = residents; return 1; } +/* don't forget filesys.asm! */ +#define PP_MAXSIZE 4 * 96 +#define PP_FSSIZE 400 +#define PP_FSPTR 404 +#define PP_FSRES 408 +#define PP_EXPLIB 412 +#define PP_FSHDSTART 416 + +static uae_u32 REGPARAM2 filesys_dev_bootfilesys (TrapContext *dummy) +{ + uaecptr devicenode = m68k_areg (regs, 3); + uaecptr parmpacket = m68k_areg (regs, 1); + uaecptr fsres = get_long (parmpacket + PP_FSRES); + uaecptr fsnode; + uae_u32 dostype, dostype2; + int no = m68k_dreg (regs, 6); + int unit_no = no & 65535; + int type = hardfile_fs_type (current_mountinfo, unit_no); + + if (type == FILESYS_VIRTUAL) + return 0; + dostype = get_long (parmpacket + 80); + fsnode = get_long (fsres + 18); + while (get_long (fsnode)) { + dostype2 = get_long (fsnode + 14); + if (dostype2 == dostype) { + if (get_long (fsnode + 22) & (1 << 7)) { + put_long (devicenode + 32, get_long (fsnode + 54)); /* dn_SegList */ + put_long (devicenode + 36, -1); /* dn_GlobalVec */ + } + return 1; + } + fsnode = get_long (fsnode); + } + return 0; +} + /* Remember a pointer AmigaOS gave us so we can later use it to identify * which unit a given startup message belongs to. */ -static uae_u32 filesys_dev_remember(void) +static uae_u32 filesys_dev_remember (TrapContext *dummy) { - int unit_no = m68k_dreg (regs, 6); + int no = m68k_dreg (regs, 6); + int unit_no = no & 65535; + int sub_no = no >> 16; + UnitInfo *uip = ¤t_mountinfo->ui[unit_no]; uaecptr devicenode = m68k_areg (regs, 3); + uaecptr parmpacket = m68k_areg (regs, 1); - ui[unit_no].startup = get_long (devicenode + 28); + /* copy filesystem loaded from RDB */ + if (get_long (parmpacket + PP_FSPTR)) { + int i; + for (i = 0; i < uip->rdb_filesyssize; i++) + put_byte (get_long (parmpacket + PP_FSPTR) + i, uip->rdb_filesysstore[i]); + free (uip->rdb_filesysstore); + uip->rdb_filesysstore = 0; + uip->rdb_filesyssize = 0; + } + if ((uae_s32)m68k_dreg (regs, 3) >= 0) + uip->startup = get_long (devicenode + 28); return devicenode; } +static int legalrdbblock (UnitInfo *uip, int block) +{ + if (block <= 0) + return 0; + if (block >= uip->hf.size / uip->hf.blocksize) + return 0; + return 1; +} + +static int rl (uae_u8 *p) +{ + return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); +} + +static int rdb_checksum (char *id, uae_u8 *p, int block) +{ + uae_u32 sum = 0; + int i, blocksize; + + if (memcmp (id, p, 4)) + return 0; + blocksize = rl (p + 4); + if (blocksize < 1 || blocksize * 4 > FILESYS_MAX_BLOCKSIZE) + return 0; + for (i = 0; i < blocksize; i++) + sum += rl (p + i * 4); + sum = -sum; + if (sum) { + write_log ("RDB: block %d ('%s') checksum error\n", block, id); + return 0; + } + return 1; +} + +static void dump_partinfo (char *name, int num, uaecptr pp, int partblock) +{ + uae_u32 dostype = get_long (pp + 80); + write_log ("RDB: '%s' dostype=%08.8X. PartBlock=%d\n", name, dostype, partblock); + write_log ("BlockSize: %d, Surfaces: %d, SectorsPerBlock %d\n", + get_long (pp + 20) * 4, get_long (pp + 28), get_long (pp + 32)); + write_log ("SectorsPerTrack: %d, Reserved: %d, LowCyl %d, HighCyl %d\n", + get_long (pp + 36), get_long (pp + 40), get_long (pp + 52), get_long (pp + 56)); + write_log ("Buffers: %d, BufMemType: %08.8x, MaxTransfer: %08.8x, BootPri: %d\n", + get_long (pp + 60), get_long (pp + 64), get_long (pp + 68), get_long (pp + 76)); +} + +static char *device_dupfix (uaecptr expbase, char *devname) +{ + uaecptr bnode, dnode, name; + int len, i, modified; + char dname[256], newname[256]; + + strcpy (newname, devname); + modified = 1; + while (modified) { + modified = 0; + bnode = get_long (expbase + 74); /* expansion.library bootnode list */ + while (get_long (bnode)) { + dnode = get_long (bnode + 16); /* device node */ + name = get_long (dnode + 40) << 2; /* device name BSTR */ + len = get_byte (name); + for (i = 0; i < len; i++) + dname[i] = get_byte (name + 1 + i); + dname[len] = 0; + for (;;) { + if (strcasecmp (newname, dname) == 0) { + if (strlen (newname) > 2 && newname[strlen (newname) - 2] == '_') { + newname[strlen (newname) - 1]++; + } else { + strcat (newname, "_0"); + } + modified = 1; + } else { + break; + } + } + bnode = get_long (bnode); + } + } + return my_strdup (newname); +} + +#define rdbmnt write_log ("Mounting uaehf.device %d (%d) (size=%llu):\n", unit_no, partnum, hfd->size); + +static int rdb_mount (UnitInfo *uip, int unit_no, int partnum, uaecptr parmpacket) +{ + int lastblock = 63, blocksize, readblocksize, badblock, driveinitblock; + uae_u8 bufrdb[FILESYS_MAX_BLOCKSIZE], *buf = 0; + uae_u8 *fsmem = 0; + int rdblock, partblock, fileblock, lsegblock, i; + uae_u32 flags; + struct hardfiledata *hfd = &uip->hf; + uae_u32 dostype; + uaecptr fsres, fsnode; + int err = 0; + int oldversion, oldrevision; + int newversion, newrevision; + + if (hfd->blocksize == 0) { + rdbmnt + write_log ("failed, blocksize == 0\n"); + return -1; + } + if (lastblock * hfd->blocksize > hfd->size) { + rdbmnt + write_log ("failed, too small (%d*%d > %I64u)\n", lastblock, hfd->blocksize, hfd->size); + return -2; + } + for (rdblock = 0; rdblock < lastblock; rdblock++) { + hdf_read (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize); + if (rdb_checksum ("RDSK", bufrdb, rdblock)) + break; + hdf_read (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize); + if (!memcmp ("RDSK", bufrdb, 4)) { + bufrdb[0xdc] = 0; + bufrdb[0xdd] = 0; + bufrdb[0xde] = 0; + bufrdb[0xdf] = 0; +#if 0 + if (rdb_checksum ("RDSK", bufrdb, rdblock)) { + write_log ("Windows 95/98/ME trashed RDB detected, fixing..\n"); + hdf_write (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize); + break; + } +#endif + } + } + if (rdblock == lastblock) { + rdbmnt + write_log ("failed, no RDB detected\n"); + return -2; + } + blocksize = rl (bufrdb + 16); + readblocksize = blocksize > hfd->blocksize ? blocksize : hfd->blocksize; + badblock = rl (bufrdb + 24); + if (badblock != -1) { + rdbmnt + write_log ("RDB: badblock list is not yet supported. Contact the author.\n"); + return -2; + } + driveinitblock = rl (bufrdb + 36); + if (driveinitblock != -1) { + rdbmnt + write_log ("RDB: driveinit is not yet supported. Contact the author.\n"); + return -2; + } + hfd->cylinders = rl (bufrdb + 64); + hfd->sectors = rl (bufrdb + 68); + hfd->heads = rl (bufrdb + 72); + fileblock = rl (bufrdb + 32); + + if (partnum == 0) { + write_log ("RDB: RDSK detected at %d, FSHD=%d, C=%d S=%d H=%d\n", + rdblock, fileblock, hfd->cylinders, hfd->sectors, hfd->heads); + } + + buf = (uae_u8*)xmalloc (readblocksize); + for (i = 0; i <= partnum; i++) { + if (i == 0) + partblock = rl (bufrdb + 28); + else + partblock = rl (buf + 4 * 4); + if (!legalrdbblock (uip, partblock)) { + err = -2; + goto error; + } + memset (buf, 0, readblocksize); + hdf_read (hfd, buf, partblock * hfd->blocksize, readblocksize); + if (!rdb_checksum ("PART", buf, partblock)) { + err = -2; + goto error; + } + } + + rdbmnt + flags = rl (buf + 20); + if (flags & 2) { /* do not mount */ + err = -1; + write_log ("RDB: Automount disabled, not mounting\n"); + goto error; + } + + if (!(flags & 1)) /* not bootable */ + m68k_dreg (regs, 7) = 0; + + buf[37 + buf[36]] = 0; /* zero terminate BSTR */ + uip->rdb_devname_amiga[partnum] + = ds (device_dupfix (get_long (parmpacket + PP_EXPLIB), buf + 37)); + put_long (parmpacket, uip->rdb_devname_amiga[partnum]); /* name */ + put_long (parmpacket + 4, ROM_hardfile_resname); + put_long (parmpacket + 8, uip->devno); + put_long (parmpacket + 12, 0); /* Device flags */ + for (i = 0; i < PP_MAXSIZE; i++) + put_byte (parmpacket + 16 + i, buf[128 + i]); + dump_partinfo (buf + 37, uip->devno, parmpacket, partblock); + dostype = get_long (parmpacket + 80); + + if (dostype == 0) { + write_log ("RDB: mount failed, dostype=0\n"); + err = -1; + goto error; + } + + if (hfd->cylinders * hfd->sectors * hfd->heads * blocksize > hfd->size) + write_log ("RDB: WARNING: end of partition > size of disk!\n"); + + err = 2; + + /* load custom filesystems if needed */ + if (fileblock == -1 || !legalrdbblock (uip, fileblock)) + goto error; + + fsres = get_long (parmpacket + PP_FSRES); + if (!fsres) { + write_log ("RDB: FileSystem.resource not found, this shouldn't happen!\n"); + goto error; + } + fsnode = get_long (fsres + 18); + while (get_long (fsnode)) { + if (get_long (fsnode + 14) == dostype) + break; + fsnode = get_long (fsnode); + } + oldversion = oldrevision = -1; + if (get_long (fsnode)) { + oldversion = get_word (fsnode + 18); + oldrevision = get_word (fsnode + 20); + } else { + fsnode = 0; + } + + for (;;) { + if (fileblock == -1) { + if (!fsnode) + write_log ("RDB: required FS %08.8X not in FileSystem.resource or in RDB\n", dostype); + goto error; + } + if (!legalrdbblock (uip, fileblock)) { + write_log ("RDB: corrupt FSHD pointer %d\n", fileblock); + goto error; + } + memset (buf, 0, readblocksize); + hdf_read (hfd, buf, fileblock * hfd->blocksize, readblocksize); + if (!rdb_checksum ("FSHD", buf, fileblock)) { + write_log ("RDB: checksum error in FSHD block %d\n", fileblock); + goto error; + } + fileblock = rl (buf + 16); + if ((dostype >> 8) == (rl (buf + 32) >> 8)) + break; + } + newversion = (buf[36] << 8) | buf[37]; + newrevision = (buf[38] << 8) | buf[39]; + + write_log ("RDB: RDB filesystem %08.8X version %d.%d\n", dostype, newversion, newrevision); + if (fsnode) { + write_log ("RDB: %08.8X in FileSystem.resouce version %d.%d\n", dostype, oldversion, oldrevision); + } + if (newversion * 65536 + newrevision <= oldversion * 65536 + oldrevision && oldversion >= 0) { + write_log ("RDB: FS in FileSystem.resource is newer or same, ignoring RDB filesystem\n"); + goto error; + } + + for (i = 0; i < 140; i++) + put_byte (parmpacket + PP_FSHDSTART + i, buf[32 + i]); + put_long (parmpacket + PP_FSHDSTART, dostype); + /* we found required FSHD block */ + fsmem = (uae_u8*)xmalloc (262144); + lsegblock = rl (buf + 72); + i = 0; + for (;;) { + int pb = lsegblock; + if (!legalrdbblock (uip, lsegblock)) + goto error; + memset (buf, 0, readblocksize); + hdf_read (hfd, buf, lsegblock * hfd->blocksize, readblocksize); + if (!rdb_checksum ("LSEG", buf, lsegblock)) + goto error; + lsegblock = rl (buf + 16); + if (lsegblock == pb) + goto error; + memcpy (fsmem + i * (blocksize - 20), buf + 20, blocksize - 20); + i++; + if (lsegblock == -1) + break; + } + write_log ("RDB: Filesystem loaded, %d bytes\n", i * (blocksize - 20)); + put_long (parmpacket + PP_FSSIZE, i * (blocksize - 20)); /* RDB filesystem size hack */ + uip->rdb_filesysstore = fsmem; + uip->rdb_filesyssize = i * (blocksize - 20); + free (buf); + return 2; +error: + free (buf); + free (fsmem); + return err; +} + +static void get_new_device (int type, uaecptr parmpacket, char **devname, + uaecptr *devname_amiga, int unit_no) +{ + char buffer[80]; + + sprintf (buffer, "DH%d", unit_no); + + if (*devname == NULL) + *devname = device_dupfix (get_long (parmpacket + PP_EXPLIB), buffer); + *devname_amiga = ds (*devname); + if (type == FILESYS_VIRTUAL) + write_log ("FS: mounted virtual unit %s\n", buffer); + else + write_log ("FS: mounted HDF unit %s\n", buffer); +} + /* Fill in per-unit fields of a parampacket */ -static uae_u32 filesys_dev_storeinfo(void) +static uae_u32 filesys_dev_storeinfo (TrapContext *dummy) { - int unit_no = m68k_dreg (regs, 6); + UnitInfo *uip = current_mountinfo->ui; + int no = m68k_dreg (regs, 6); + int unit_no = no & 65535; + int sub_no = no >> 16; + int type = hardfile_fs_type (current_mountinfo, unit_no); uaecptr parmpacket = m68k_areg (regs, 0); - int is_hardfile = ui[unit_no].volname == 0; - put_long (parmpacket, ui[unit_no].devname_amiga); - put_long (parmpacket + 4, is_hardfile ? ROM_hardfile_resname : fsdevname); - put_long (parmpacket + 8, ui[unit_no].devno); + if (type == FILESYS_HARDFILE_RDB || type == FILESYS_HARDDRIVE) { + /* RDB hardfile */ + uip[unit_no].devno = unit_no; + return rdb_mount (&uip[unit_no], unit_no, sub_no, parmpacket); + } + /* No subunits for normal filesystems and hardfiles. */ + if (sub_no) + return -2; + get_new_device (type, parmpacket, &uip[unit_no].devname, &uip[unit_no].devname_amiga, unit_no); + uip[unit_no].devno = unit_no; + put_long (parmpacket, uip[unit_no].devname_amiga); + put_long (parmpacket + 4, type != FILESYS_VIRTUAL ? ROM_hardfile_resname : fsdevname); + put_long (parmpacket + 8, uip[unit_no].devno); put_long (parmpacket + 12, 0); /* Device flags */ put_long (parmpacket + 16, 16); /* Env. size */ - put_long (parmpacket + 20, 128); /* 512 bytes per block */ + put_long (parmpacket + 20, uip[unit_no].hf.blocksize >> 2); /* longwords per block */ put_long (parmpacket + 24, 0); /* unused */ - put_long (parmpacket + 28, ui[unit_no].hf.surfaces); /* heads */ - put_long (parmpacket + 32, 0); /* unused */ - put_long (parmpacket + 36, ui[unit_no].hf.secspertrack); /* sectors per track */ - put_long (parmpacket + 40, ui[unit_no].hf.reservedblocks); /* reserved blocks */ + put_long (parmpacket + 28, uip[unit_no].hf.surfaces); /* heads */ + put_long (parmpacket + 32, 1); /* sectors per block */ + put_long (parmpacket + 36, uip[unit_no].hf.secspertrack); /* sectors per track */ + put_long (parmpacket + 40, uip[unit_no].hf.reservedblocks); /* reserved blocks */ put_long (parmpacket + 44, 0); /* unused */ put_long (parmpacket + 48, 0); /* interleave */ put_long (parmpacket + 52, 0); /* lowCyl */ - put_long (parmpacket + 56, ui[unit_no].hf.nrcyls - 1); /* hiCyl */ - put_long (parmpacket + 60, 0); /* Number of buffers */ + put_long (parmpacket + 56, uip[unit_no].hf.nrcyls - 1); /* hiCyl */ + put_long (parmpacket + 60, 50); /* Number of buffers */ put_long (parmpacket + 64, 0); /* Buffer mem type */ put_long (parmpacket + 68, 0x7FFFFFFF); /* largest transfer */ put_long (parmpacket + 72, ~1); /* addMask (?) */ - put_long (parmpacket + 76, (uae_u32)-1); /* bootPri */ + put_long (parmpacket + 76, uip[unit_no].bootpri); /* bootPri */ put_long (parmpacket + 80, 0x444f5300); /* DOS\0 */ put_long (parmpacket + 84, 0); /* pad */ - return is_hardfile; -} - -/* Called exactly once, at the time we know that we are actually going - * to run the emulator. */ -void filesys_start_threads (void) -{ - int i; - for (i = 0; i < num_units; i++) { - int is_hardfile = ui[i].volname == 0; - ui[i].unit_pipe = 0; -#ifdef UAE_FILESYS_THREADS - if (!is_hardfile) { - ui[i].unit_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe)); - ui[i].back_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe)); - init_comm_pipe (ui[i].unit_pipe, 50, 3); - init_comm_pipe (ui[i].back_pipe, 50, 1); - start_penguin (filesys_penguin, (void *)(ui + i), &ui[i].tid); - } -#endif - } + return type; } void filesys_install (void) @@ -2662,47 +3682,47 @@ void filesys_install (void) int i; uaecptr loop; - TRACE ((warning_buffer, "Installing filesystem\n")); + TRACE (("Installing filesystem\n")); - ROM_filesys_resname = ds("UAEunixfs.resource"); - ROM_filesys_resid = ds("UAE unixfs 0.4"); + ROM_filesys_resname = ds ("UAEunixfs.resource"); + ROM_filesys_resid = ds ("UAE unixfs 0.4"); - fsdevname = ds("uae.device"); /* does not really exist */ - - for(i = 0; i < num_units; i++) { - ui[i].devno = get_new_device(&ui[i].devname, &ui[i].devname_amiga); - } + fsdevname = ds ("uae.device"); /* does not really exist */ ROM_filesys_diagentry = here(); - calltrap (deftrap(filesys_diagentry)); dw(RTS); + calltrap (deftrap(filesys_diagentry)); + dw (0x4ED0); /* JMP (a0) - jump to code that inits Residents */ loop = here (); + + org (RTAREA_BASE + 0xFF18); + calltrap (deftrap (filesys_dev_bootfilesys)); + dw (RTS); + /* Special trap for the assembly make_dev routine */ - org(0xF0FF20); + org (RTAREA_BASE + 0xFF20); calltrap (deftrap (filesys_dev_remember)); - dw(RTS); + dw (RTS); - org(0xF0FF28); + org (RTAREA_BASE + 0xFF28); calltrap (deftrap (filesys_dev_storeinfo)); - dw(RTS); + dw (RTS); - org(0xF0FF30); + org (RTAREA_BASE + 0xFF30); calltrap (deftrap (filesys_handler)); - dw(RTS); + dw (RTS); - org(0xF0FF40); + org (RTAREA_BASE + 0xFF40); calltrap (deftrap (startup_handler)); - dw(RTS); + dw (RTS); - org(0xF0FF50); + org (RTAREA_BASE + 0xFF50); calltrap (deftrap (exter_int_helper)); - dw(RTS); - - org(0xF0FF70); - calltrap (deftrap (mousehack_helper)); - dw(RTS); + dw (RTS); org (loop); + + uae_sem_init (&packet_counter_sem, 0, 0); } void filesys_install_code (void) @@ -2710,110 +3730,9 @@ void filesys_install_code (void) align(4); /* The last offset comes from the code itself, look for it near the top. */ - filesys_initcode = here() + 8 + 0x6c; - EXPANSION_bootcode = here () + 8 + 0x14; + EXPANSION_bootcode = here () + 8 + 0x1c + 4; /* Ouch. Make sure this is _always_ a multiple of two bytes. */ - db(0x00); db(0x00); db(0x00); db(0x10); db(0x00); db(0x00); db(0x00); db(0x00); - db(0x60); db(0x00); db(0x01); db(0xc0); db(0x00); db(0x00); db(0x01); db(0x2c); - db(0x00); db(0x00); db(0x00); db(0x6c); db(0x00); db(0x00); db(0x00); db(0x28); - db(0x00); db(0x00); db(0x00); db(0x14); db(0x43); db(0xfa); db(0x02); db(0xf9); - db(0x4e); db(0xae); db(0xff); db(0xa0); db(0x20); db(0x40); db(0x20); db(0x28); - db(0x00); db(0x16); db(0x20); db(0x40); db(0x4e); db(0x90); db(0x4e); db(0x75); - db(0x48); db(0xe7); db(0x00); db(0x20); db(0x70); db(0x00); db(0x4e); db(0xb9); - db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x2e); - db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x02); db(0x4e); db(0xb9); - db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x14); - db(0x24); db(0x40); db(0x70); db(0x03); db(0x4e); db(0xb9); db(0x00); db(0xf0); - db(0xff); db(0x50); db(0x20); db(0x4a); db(0x22); db(0x40); db(0x4e); db(0xae); - db(0xfe); db(0x92); db(0x60); db(0xe0); db(0x70); db(0x04); db(0x4e); db(0xb9); - db(0x00); db(0xf0); db(0xff); db(0x50); db(0x70); db(0x01); db(0x4c); db(0xdf); - db(0x04); db(0x00); db(0x4e); db(0x75); db(0x48); db(0xe7); db(0xff); db(0xfe); - db(0x2c); db(0x78); db(0x00); db(0x04); db(0x2a); db(0x79); db(0x00); db(0xf0); - db(0xff); db(0xfc); db(0x43); db(0xfa); db(0x02); db(0x9f); db(0x70); db(0x24); - db(0x7a); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x4a); db(0x80); - db(0x66); db(0x0c); db(0x43); db(0xfa); db(0x02); db(0x8f); db(0x70); db(0x00); - db(0x7a); db(0x01); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x28); db(0x40); - db(0x70); db(0x58); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a); - db(0x26); db(0x40); db(0x7e); db(0x54); db(0x27); db(0xb5); db(0x78); db(0x00); - db(0x78); db(0x00); db(0x59); db(0x87); db(0x64); db(0xf6); db(0x7c); db(0x00); - db(0xbc); db(0xad); db(0x01); db(0x0c); db(0x64); db(0x12); db(0x20); db(0x4b); - db(0x48); db(0xe7); db(0x02); db(0x10); db(0x7e); db(0x01); db(0x61); db(0x6c); - db(0x4c); db(0xdf); db(0x08); db(0x40); db(0x52); db(0x86); db(0x60); db(0xe8); - db(0x2c); db(0x78); db(0x00); db(0x04); db(0x22); db(0x4c); db(0x4e); db(0xae); - db(0xfe); db(0x62); db(0x61); db(0x28); db(0x2c); db(0x78); db(0x00); db(0x04); - db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x80); db(0x72); db(0x03); - db(0x74); db(0xf6); db(0x20); db(0x7c); db(0x00); db(0x20); db(0x00); db(0x00); - db(0x90); db(0x88); db(0x65); db(0x0a); db(0x67); db(0x08); db(0x78); db(0x00); - db(0x22); db(0x44); db(0x4e); db(0xae); db(0xfd); db(0x96); db(0x4c); db(0xdf); - db(0x7f); db(0xff); db(0x4e); db(0x75); db(0x2c); db(0x78); db(0x00); db(0x04); - db(0x70); db(0x1a); db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01); - db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x22); db(0x40); db(0x41); db(0xfa); - db(0x01); db(0xf0); db(0x23); db(0x48); db(0x00); db(0x0a); db(0x41); db(0xfa); - db(0xff); db(0x10); db(0x23); db(0x48); db(0x00); db(0x0e); db(0x41); db(0xfa); - db(0xff); db(0x08); db(0x23); db(0x48); db(0x00); db(0x12); db(0x70); db(0x0d); - db(0x4e); db(0xee); db(0xff); db(0x58); db(0x2a); db(0x79); db(0x00); db(0xf0); - db(0xff); db(0xfc); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x28); - db(0x26); db(0x00); db(0xc0); db(0x85); db(0x66); db(0xbc); db(0x2c); db(0x4c); - db(0x4e); db(0xae); db(0xff); db(0x70); db(0x26); db(0x40); db(0x4e); db(0xb9); - db(0x00); db(0xf0); db(0xff); db(0x20); db(0x70); db(0x00); db(0x27); db(0x40); - db(0x00); db(0x08); db(0x27); db(0x40); db(0x00); db(0x10); db(0x27); db(0x40); - db(0x00); db(0x20); db(0x4a); db(0x83); db(0x66); db(0x1c); db(0x27); db(0x7c); - db(0x00); db(0x00); db(0x0f); db(0xa0); db(0x00); db(0x14); db(0x43); db(0xfa); - db(0xfe); db(0x94); db(0x20); db(0x09); db(0xe4); db(0x88); db(0x27); db(0x40); - db(0x00); db(0x20); db(0x27); db(0x7c); db(0xff); db(0xff); db(0xff); db(0xff); - db(0x00); db(0x24); db(0x4a); db(0x87); db(0x67); db(0x36); db(0x2c); db(0x78); - db(0x00); db(0x04); db(0x70); db(0x14); db(0x72); db(0x00); db(0x4e); db(0xae); - db(0xff); db(0x3a); db(0x22); db(0x40); db(0x70); db(0x00); db(0x22); db(0x80); - db(0x23); db(0x40); db(0x00); db(0x04); db(0x33); db(0x40); db(0x00); db(0x0e); - db(0x30); db(0x3c); db(0x10); db(0xff); db(0x90); db(0x06); db(0x33); db(0x40); - db(0x00); db(0x08); db(0x23); db(0x6d); db(0x01); db(0x04); db(0x00); db(0x0a); - db(0x23); db(0x4b); db(0x00); db(0x10); db(0x41); db(0xec); db(0x00); db(0x4a); - db(0x4e); db(0xee); db(0xfe); db(0xf2); db(0x20); db(0x4b); db(0x72); db(0x00); - db(0x22); db(0x41); db(0x70); db(0xff); db(0x2c); db(0x4c); db(0x4e); db(0xee); - db(0xff); db(0x6a); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x00); - db(0x22); db(0x40); db(0x4e); db(0xae); db(0xfe); db(0xda); db(0x20); db(0x40); - db(0x4b); db(0xe8); db(0x00); db(0x5c); db(0x43); db(0xfa); db(0x01); db(0x39); - db(0x70); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x24); db(0x40); - db(0x20); db(0x3c); db(0x00); db(0x00); db(0x00); db(0x9d); db(0x22); db(0x3c); - db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a); - db(0x26); db(0x40); db(0x7c); db(0x00); db(0x26); db(0x86); db(0x27); db(0x46); - db(0x00); db(0x04); db(0x27); db(0x46); db(0x00); db(0x08); db(0x7a); db(0x00); - db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x80); db(0x20); db(0x4d); - db(0x4e); db(0xae); db(0xfe); db(0x8c); db(0x28); db(0x40); db(0x26); db(0x2c); - db(0x00); db(0x0a); db(0x70); db(0x00); db(0x4e); db(0xb9); db(0x00); db(0xf0); - db(0xff); db(0x40); db(0x60); db(0x74); db(0x20); db(0x4d); db(0x4e); db(0xae); - db(0xfe); db(0x80); db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x8c); - db(0x28); db(0x40); db(0x26); db(0x2c); db(0x00); db(0x0a); db(0x66); db(0x38); - db(0x70); db(0x01); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x50); - db(0x45); db(0xeb); db(0x00); db(0x04); db(0x20); db(0x52); db(0x20); db(0x08); - db(0x67); db(0xda); db(0x22); db(0x50); db(0x20); db(0x40); db(0x20); db(0x28); - db(0x00); db(0x04); db(0x6a); db(0x16); db(0x48); db(0xe7); db(0x00); db(0xc0); - db(0x28); db(0x68); db(0x00); db(0x0a); db(0x61); db(0x40); db(0x53); db(0x85); - db(0x4c); db(0xdf); db(0x03); db(0x00); db(0x24); db(0x89); db(0x20); db(0x49); - db(0x60); db(0xdc); db(0x24); db(0x48); db(0x20); db(0x49); db(0x60); db(0xd6); - db(0xba); db(0xbc); db(0x00); db(0x00); db(0x00); db(0x14); db(0x65); db(0x08); - db(0x70); db(0x01); db(0x29); db(0x40); db(0x00); db(0x04); db(0x60); db(0x0e); - db(0x61); db(0x2a); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x30); - db(0x4a); db(0x80); db(0x67); db(0x0c); db(0x52); db(0x85); db(0x28); db(0xab); - db(0x00); db(0x04); db(0x27); db(0x4c); db(0x00); db(0x04); db(0x60); db(0x8c); - db(0x28); db(0x43); db(0x61); db(0x02); db(0x60); db(0x86); db(0x22); db(0x54); - db(0x20); db(0x6c); db(0x00); db(0x04); db(0x29); db(0x4d); db(0x00); db(0x04); - db(0x4e); db(0xee); db(0xfe); db(0x92); db(0x2f); db(0x05); db(0x7a); db(0xfc); - db(0x24); db(0x53); db(0x2e); db(0x0a); db(0x22); db(0x0a); db(0x67); db(0x0a); - db(0x52); db(0x85); db(0x67); db(0x1e); db(0x22); db(0x4a); db(0x24); db(0x52); - db(0x60); db(0xf2); db(0x52); db(0x85); db(0x67); db(0x3c); db(0x24); db(0x47); - db(0x70); db(0x18); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a); - db(0x52); db(0x46); db(0x24); db(0x40); db(0x24); db(0x87); db(0x2e); db(0x0a); - db(0x60); db(0xe8); db(0x20); db(0x12); db(0x67); db(0x24); db(0x20); db(0x40); - db(0x20); db(0x10); db(0x67); db(0x1e); db(0x20); db(0x40); db(0x20); db(0x10); - db(0x67); db(0x18); db(0x70); db(0x00); db(0x22); db(0x80); db(0x22); db(0x4a); - db(0x24); db(0x51); db(0x70); db(0x18); db(0x4e); db(0xae); db(0xff); db(0x2e); - db(0xdc); db(0xbc); db(0x00); db(0x01); db(0x00); db(0x00); db(0x20); db(0x0a); - db(0x66); db(0xec); db(0x26); db(0x87); db(0x2a); db(0x1f); db(0x4e); db(0x75); - db(0x55); db(0x41); db(0x45); db(0x20); db(0x66); db(0x69); db(0x6c); db(0x65); - db(0x73); db(0x79); db(0x73); db(0x74); db(0x65); db(0x6d); db(0x00); db(0x64); - db(0x6f); db(0x73); db(0x2e); db(0x6c); db(0x69); db(0x62); db(0x72); db(0x61); - db(0x72); db(0x79); db(0x00); db(0x65); db(0x78); db(0x70); db(0x61); db(0x6e); - db(0x73); db(0x69); db(0x6f); db(0x6e); db(0x2e); db(0x6c); db(0x69); db(0x62); - db(0x72); db(0x61); db(0x72); db(0x79); db(0x00); db(0x00); + filesys_initcode = here() + 8 + 0x30 + 4; + + #include "filesys_bootrom.c" }