--- uae/src/filesys.c 2018/04/24 16:56:52 1.1.1.10 +++ uae/src/filesys.c 2018/04/24 17:12:40 1.1.1.19 @@ -28,22 +28,22 @@ #include "sysdeps.h" #include "config.h" -#include "threaddep/penguin.h" +#include "threaddep/thread.h" #include "options.h" #include "uae.h" #include "memory.h" #include "custom.h" +#include "events.h" #include "newcpu.h" #include "filesys.h" #include "autoconf.h" -#include "compiler.h" #include "fsusage.h" #include "native2amiga.h" #include "scsidev.h" #include "fsdb.h" -/* #define TRACING_ENABLED */ -#ifdef TRACING_ENABLED +#define TRACING_ENABLED 0 +#if TRACING_ENABLED #define TRACE(x) do { write_log x; } while(0) #define DUMPLOCK(u,x) dumplock(u,x) #else @@ -59,7 +59,7 @@ static long dos_errno(void) 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_IS_FULL; case EBUSY: return ERROR_OBJECT_IN_USE; @@ -124,7 +124,7 @@ typedef struct { /* 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; @@ -351,8 +351,10 @@ void write_filesys_config (struct uaedev fprintf (f, "filesystem=%s,%s:%s\n", uip[i].readonly ? "ro" : "rw", uip[i].volname, str); } else { - fprintf (f, "hardfile=%s,%d,%d,%d,%d,%s\n", uip[i].hf.secspertrack, - uip[i].hf.surfaces, uip[i].hf.reservedblocks, 512, str); + 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); } @@ -417,6 +419,12 @@ struct hardfiledata *get_hardfile_data ( #define DOS_TRUE ((unsigned long)-1L) #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 @@ -467,8 +475,10 @@ struct hardfiledata *get_hardfile_data ( typedef struct { uae_u32 uniq; + /* The directory we're going through. */ a_inode *aino; - DIR* dir; + /* The file we're going to look up next. */ + a_inode *curr_file; } ExamineKey; typedef struct key { @@ -509,8 +519,9 @@ typedef struct _unit { volatile unsigned int cmds_acked; /* ExKeys */ - ExamineKey examine_keys[EXKEYS]; + ExamineKey examine_keys[EXKEYS]; int next_exkey; + unsigned long total_locked_ainos; /* Keys */ struct key *keys; @@ -642,34 +653,53 @@ static void recycle_aino (Unit *unit, a_ /* Still in use */ return; - 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) { + a_inode *parent = unit->rootnode.prev->parent; a_inode **aip; - aip = &unit->rootnode.prev->parent->child; - for (;;) { - a_inode *aino = *aip; - if (aino == 0) - break; - - 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++; + 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. */ + 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->parent == parent); } #if 0 { char buffer[40]; sprintf (buffer, "%d ainos reaped.\n", i); - write_log (buffer); + TRACE ((buffer)); } #endif } @@ -689,16 +719,17 @@ static void update_child_names (Unit *un 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; @@ -718,13 +749,31 @@ static void move_aino_children (Unit *un static void delete_aino (Unit *unit, a_inode *aino) { a_inode **aip; - int hash; 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; @@ -758,9 +807,14 @@ static a_inode *lookup_sub (a_inode *dir } 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; } @@ -889,6 +943,14 @@ static void init_child_aino (Unit *unit, 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; @@ -911,7 +973,7 @@ static a_inode *new_child_aino (Unit *un if (nn == 0) return 0; - aino = (a_inode *) xmalloc (sizeof (a_inode)); + aino = (a_inode *) xcalloc (sizeof (a_inode), 1); if (aino == 0) return 0; aino->aname = modified_rel ? modified_rel : my_strdup (rel); @@ -927,13 +989,13 @@ static a_inode *new_child_aino (Unit *un init_child_aino (unit, base, aino); recycle_aino (unit, aino); - TRACE(("created aino %x, lookup\n", aino->uniq)); + TRACE(("created aino %x, lookup, amigaos_mode %d\n", aino->uniq, aino->amigaos_mode)); return aino; } static a_inode *create_child_aino (Unit *unit, a_inode *base, char *rel, int isdir) { - a_inode *aino = (a_inode *) xmalloc (sizeof (a_inode)); + a_inode *aino = (a_inode *) xcalloc (sizeof (a_inode), 1); if (aino == 0) return 0; @@ -974,7 +1036,7 @@ static a_inode *lookup_child_aino (Unit return c; c = new_child_aino (unit, base, rel); if (c == 0) - *err = ERROR_OBJECT_NOT_FOUND; + *err = ERROR_OBJECT_NOT_AROUND; return c; } @@ -1055,7 +1117,7 @@ static a_inode *get_aino (Unit *unit, a_ 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; @@ -1111,7 +1173,7 @@ static uae_u32 startup_handler (void) } uinfo = current_mountinfo->ui + i; - unit = (Unit *) xmalloc (sizeof (Unit)); + unit = (Unit *) xcalloc (sizeof (Unit), 1); unit->next = units; units = unit; uinfo->self = unit; @@ -1131,9 +1193,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; @@ -1149,6 +1212,8 @@ 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; @@ -1253,7 +1318,7 @@ static void free_key (Unit *unit, Key *k } if (k->fd >= 0) - close(k->fd); + close (k->fd); free(k); } @@ -1389,16 +1454,16 @@ action_lock (Unit *unit, dpacket packet) a_inode *a; uae_u32 err; - if (mode != -2 && mode != -1) { + if (mode != SHARED_LOCK && mode != EXCLUSIVE_LOCK) { TRACE(("Bad mode.\n")); - mode = -2; + mode = SHARED_LOCK; } 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. */ @@ -1407,7 +1472,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; @@ -1425,7 +1490,7 @@ static void action_free_lock (Unit *unit 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) @@ -1453,7 +1518,7 @@ action_dup_lock (Unit *unit, dpacket pac 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 @@ -1501,19 +1566,38 @@ put_time (long days, long mins, long tic 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, a_inode *aino) { uae_u32 uniq; - uae_u32 oldest = 0xFFFFFFFF; + uae_u32 oldest = 0xFFFFFFFE; ExamineKey *ek, *oldest_ek = 0; int i; @@ -1533,36 +1617,42 @@ 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 @@ -1613,7 +1703,10 @@ get_fileinfo (Unit *unit, dpacket packet else { TRACE(("comment=\"%s\"\n", aino->comment)); i = 144; - n = strlen (x = aino->comment); + x = aino->comment; + if (! x) + x = ""; + n = strlen (x); if (n > 78) n = 78; put_byte (info + i, n); i++; @@ -1625,47 +1718,6 @@ get_fileinfo (Unit *unit, dpacket packet 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; - 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; - } - - do { - de = my_readdir (ek->dir, &de_space); - } while (de && fsdb_name_invalid (de->d_name)); - - if (!de) { - TRACE(("no more entries\n")); - free_exkey (ek); - PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES); - return; - } - - TRACE(("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_fileinfo (unit, packet, info, aino); -} - static void action_examine_object (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; @@ -1687,6 +1739,61 @@ static void action_examine_object (Unit 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 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; @@ -1706,21 +1813,34 @@ static void action_examine_next (Unit *u 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 + 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); + 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) @@ -1740,7 +1860,7 @@ static void do_find (Unit *unit, dpacket 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); @@ -1860,9 +1980,9 @@ action_fh_from_lock (Unit *unit, dpacket mode = aino->amigaos_mode; /* Use same mode for opened filehandle as existing Lock() */ prepare_for_open (aino->nname); - - openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY - : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY + 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. */ @@ -2070,6 +2190,22 @@ action_seek (Unit *unit, dpacket packet) 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) { @@ -2187,7 +2323,7 @@ action_change_mode (Unit *unit, dpacket 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)) { @@ -2202,15 +2338,15 @@ action_change_mode (Unit *unit, dpacket mode = (mode == 1006 ? -1 : -2); if (type == CHANGE_LOCK) - uniq = get_long (object + 4); + 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_FOUND); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); return; } - uniq = k->aino->uniq; + uniq = k->aino->uniq; } a = lookup_aino (unit, uniq); @@ -2228,7 +2364,7 @@ action_change_mode (Unit *unit, dpacket a->elock = 0; a->shlock++; } - } + } if (err) { PUT_PCK_RES1 (packet, DOS_FALSE); @@ -2271,7 +2407,7 @@ action_parent_fh (Unit *unit, dpacket pa Key *k = lookup_key (unit, GET_PCK_ARG1 (packet)); if (!k) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND); return; } action_parent_common (unit, packet, k->aino->uniq); @@ -2309,7 +2445,7 @@ action_create_dir (Unit *unit, dpacket p } 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; @@ -2372,7 +2508,7 @@ action_set_file_size (Unit *unit, dpacke 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; @@ -2381,7 +2517,7 @@ action_set_file_size (Unit *unit, dpacke 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; } @@ -2449,6 +2585,8 @@ action_delete_object (Unit *unit, dpacke 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()); @@ -2534,7 +2672,7 @@ action_rename_object (Unit *unit, dpacke return; } a2 = a2->parent; - } else if (a2 == 0 || err2 != ERROR_OBJECT_NOT_FOUND) { + } 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; @@ -2556,6 +2694,8 @@ action_rename_object (Unit *unit, dpacke 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); @@ -2785,7 +2925,7 @@ static int handle_packet (Unit *unit, dp } #ifdef UAE_FILESYS_THREADS -static void *filesys_penguin (void *unit_v) +static void *filesys_thread (void *unit_v) { UnitInfo *ui = (UnitInfo *)unit_v; for (;;) { @@ -2886,6 +3026,40 @@ static uae_u32 filesys_handler (void) return 0; } +static int current_deviceno = 0; +static int current_cdrom = 0; + +static void reset_uaedevices (void) +{ + current_deviceno = 0; + current_cdrom = 0; +} + +static int get_new_device (char **devname, uaecptr *devname_amiga, int cdrom) +{ + int result; + char buffer[80]; + + if (cdrom) { + sprintf (buffer, "CD%d", current_cdrom); + result = current_cdrom++; + } else { + sprintf (buffer, "DH%d", current_deviceno); + result = current_deviceno++; + } + + *devname_amiga = ds (*devname = my_strdup (buffer)); + return result; +} + +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; @@ -2898,7 +3072,7 @@ void filesys_start_threads (void) uip = current_mountinfo->ui; for (i = 0; i < current_mountinfo->num_units; i++) { uip[i].unit_pipe = 0; - uip[i].devno = get_new_device (&uip[i].devname, &uip[i].devname_amiga); + uip[i].devno = get_new_device (&uip[i].devname, &uip[i].devname_amiga, 0); #ifdef UAE_FILESYS_THREADS if (! is_hardfile (current_mountinfo, i)) { @@ -2906,7 +3080,7 @@ void filesys_start_threads (void) 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); - start_penguin (filesys_penguin, (void *)(uip + i), &uip[i].tid); + uae_start_thread (filesys_thread, (void *)(uip + i), &uip[i].tid); } #endif } @@ -2915,7 +3089,6 @@ void filesys_start_threads (void) void filesys_reset (void) { Unit *u, *u1; - int i; /* We get called once from customreset at the beginning of the program * before filesys_start_threads has been called. Survive that. */ @@ -2933,6 +3106,16 @@ void filesys_reset (void) 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) { UnitInfo *uip = current_mountinfo->ui; @@ -2954,15 +3137,9 @@ void filesys_prepare_reset (void) #endif u = units; while (u != 0) { - while (u->rootnode.next != &u->rootnode) { - a_inode *a = u->rootnode.next; - u->rootnode.next = a->next; - if (a->dirty && a->parent) - fsdb_dir_writeback (a->parent); - 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; } } @@ -2977,10 +3154,7 @@ static uae_u32 filesys_diagentry (void) filesys_configdev = m68k_areg (regs, 3); - 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); + init_filesys_diagentry (); uae_sem_init (&singlethread_int_sem, 0, 1); if (ROM_hardfile_resid != 0) { @@ -3024,8 +3198,15 @@ static uae_u32 filesys_diagentry (void) tmp++; } } - put_word (resaddr, 0x7001); /* moveq.l #1,d0 */ - put_word (resaddr + 2, RTS); + /* 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; @@ -3093,23 +3274,23 @@ void filesys_install (void) loop = here (); /* Special trap for the assembly make_dev routine */ - org (0xF0FF20); + org (RTAREA_BASE + 0xFF20); calltrap (deftrap (filesys_dev_remember)); dw (RTS); - org (0xF0FF28); + org (RTAREA_BASE + 0xFF28); calltrap (deftrap (filesys_dev_storeinfo)); dw (RTS); - org (0xF0FF30); + org (RTAREA_BASE + 0xFF30); calltrap (deftrap (filesys_handler)); dw (RTS); - org (0xF0FF40); + org (RTAREA_BASE + 0xFF40); calltrap (deftrap (startup_handler)); dw (RTS); - org (0xF0FF50); + org (RTAREA_BASE + 0xFF50); calltrap (deftrap (exter_int_helper)); dw (RTS); @@ -3121,58 +3302,71 @@ void filesys_install_code (void) align(4); /* The last offset comes from the code itself, look for it near the top. */ - EXPANSION_bootcode = here () + 8 + 0x14; + EXPANSION_bootcode = here () + 8 + 0x14 + 4; /* Ouch. Make sure this is _always_ a multiple of two bytes. */ - filesys_initcode = here() + 8 + 0x28; + filesys_initcode = here() + 8 + 0x28 + 4; + db(0x00); db(0x00); db(0x00); db(0x10); db(0x00); db(0x00); db(0x00); db(0x00); - db(0x60); db(0x00); db(0x01); db(0xd4); db(0x00); db(0x00); db(0x01); db(0x3e); - db(0x00); db(0x00); db(0x00); db(0x28); db(0x00); db(0x00); db(0x00); db(0xbc); - db(0x00); db(0x00); db(0x00); db(0x14); db(0x43); db(0xfa); db(0x03); db(0x11); - 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(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(0xfb); db(0x70); db(0x24); db(0x7a); db(0x00); db(0x4e); db(0xae); + db(0x60); db(0x00); db(0x02); db(0x34); db(0x00); db(0x00); db(0x01); db(0x8c); + db(0x00); db(0x00); db(0x00); db(0x2c); db(0x00); db(0x00); db(0x00); db(0xc4); + db(0x00); db(0x00); db(0x00); db(0x18); db(0x00); db(0x00); db(0x01); db(0x54); + db(0x43); db(0xfa); db(0x03); db(0x89); 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(0xff); db(0xfe); + db(0x2c); db(0x78); db(0x00); db(0x04); db(0x30); db(0x3c); db(0xff); db(0xfc); + db(0x61); db(0x00); db(0x03); db(0x4c); db(0x2a); db(0x50); db(0x43); db(0xfa); + db(0x03); db(0x6f); 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(0xeb); db(0x70); db(0x00); db(0x7a); db(0x01); db(0x4e); db(0xae); + db(0x03); db(0x5f); 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(0x14); db(0x20); db(0x4b); db(0x48); db(0xe7); db(0x02); db(0x10); - db(0x7e); db(0x01); db(0x61); db(0x00); db(0x00); db(0xc2); db(0x4c); db(0xdf); - db(0x08); db(0x40); db(0x52); db(0x86); db(0x60); db(0xe6); db(0x2c); db(0x78); - db(0x00); db(0x04); db(0x22); db(0x4c); db(0x4e); db(0xae); db(0xfe); db(0x62); - db(0x61); db(0x00); db(0x00); db(0x7c); 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(0x64); db(0x18); db(0x20); db(0x4b); db(0x48); db(0xe7); db(0x02); db(0x10); + db(0x2e); db(0x3c); db(0x00); db(0x00); db(0x00); db(0x01); db(0x61); db(0x00); + db(0x01); db(0x04); db(0x4c); db(0xdf); db(0x08); db(0x40); db(0x52); db(0x86); + db(0x60); db(0xe2); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x22); db(0x4c); + db(0x4e); db(0xae); db(0xfe); db(0x62); db(0x30); db(0x3c); db(0xff); db(0x80); + db(0x61); db(0x00); db(0x02); db(0xe4); db(0x4e); db(0x90); 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(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(0x3c); 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(0x0c); db(0x80); db(0x00); db(0x00); db(0x00); db(0x01); db(0x6d); db(0x1e); - db(0x6e); db(0x06); db(0x4e); db(0xae); db(0xfe); db(0x92); db(0x60); db(0xe8); + db(0x30); db(0x3c); db(0xff); db(0x50); db(0x61); db(0x00); db(0x02); db(0xb8); + db(0x70); db(0x00); db(0x4e); db(0x90); db(0x4a); db(0x80); db(0x67); db(0x76); + db(0x2c); db(0x78); db(0x00); db(0x04); db(0x30); db(0x3c); db(0xff); db(0x50); + db(0x61); db(0x00); db(0x02); db(0xa4); db(0x70); db(0x02); db(0x4e); db(0x90); + db(0x0c); db(0x80); db(0x00); db(0x00); db(0x00); db(0x01); db(0x6d); db(0x50); + db(0x6e); db(0x06); db(0x4e); db(0xae); db(0xfe); db(0x92); db(0x60); db(0xe4); db(0x0c); db(0x80); db(0x00); db(0x00); db(0x00); db(0x02); db(0x6e); db(0x08); - db(0x20); db(0x01); db(0x4e); db(0xae); db(0xfe); db(0xbc); db(0x60); db(0xd8); - db(0x4e); db(0xae); db(0xfe); db(0x86); db(0x60); db(0xd2); 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(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(0xf6); db(0x23); db(0x48); db(0x00); db(0x0a); - db(0x41); db(0xfa); db(0xff); db(0x92); db(0x23); db(0x48); db(0x00); db(0x0e); - db(0x41); db(0xfa); db(0xff); db(0x8a); 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(0x00); - db(0xff); db(0x6a); 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(0x20); db(0x01); db(0x4e); db(0xae); db(0xfe); db(0xbc); db(0x60); db(0xd4); + db(0x0c); db(0x80); db(0x00); db(0x00); db(0x00); db(0x03); db(0x6e); db(0x06); + db(0x4e); db(0xae); db(0xfe); db(0x86); db(0x60); db(0xc6); db(0x0c); db(0x80); + db(0x00); db(0x00); db(0x00); db(0x04); db(0x6e); db(0x06); db(0x4e); db(0xae); + db(0xff); db(0x4c); db(0x60); db(0xb8); db(0x48); db(0xe7); db(0x00); db(0x24); + db(0x24); db(0x49); db(0x22); db(0x6a); db(0x00); db(0x14); db(0x2a); db(0x6a); + db(0x00); db(0x18); db(0x2f); db(0x0a); db(0x4e); db(0x95); db(0x24); db(0x1f); + db(0x42); db(0xaa); db(0x00); db(0x18); db(0x4c); db(0xdf); db(0x24); db(0x00); + db(0x30); db(0x3c); db(0xff); db(0x50); db(0x61); db(0x00); db(0x02); db(0x40); + db(0x70); db(0x04); db(0x4e); db(0x90); db(0x70); db(0x01); db(0x4c); db(0xdf); + db(0x04); db(0x00); db(0x4e); db(0x75); 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(0x02); db(0x30); db(0x23); db(0x48); + db(0x00); db(0x0a); db(0x41); db(0xfa); db(0xff); db(0x58); db(0x23); db(0x48); + db(0x00); db(0x0e); db(0x41); db(0xfa); db(0xff); db(0x50); db(0x23); db(0x48); + db(0x00); db(0x12); db(0x13); db(0x7c); db(0x00); db(0xc8); db(0x00); db(0x09); + db(0x13); db(0x7c); db(0x00); db(0x02); db(0x00); db(0x08); db(0x70); db(0x0d); + db(0x4e); db(0xee); db(0xff); db(0x58); db(0x2f); db(0x08); db(0x30); db(0x3c); + db(0xff); db(0xfc); db(0x61); db(0x00); db(0x01); db(0xf2); db(0x2a); db(0x50); + db(0x30); db(0x3c); db(0xff); db(0x28); db(0x61); db(0x00); db(0x01); db(0xe8); + db(0x22); db(0x48); db(0x20); db(0x5f); db(0x4e); db(0x91); db(0x26); db(0x00); + db(0xc0); db(0x85); db(0x66); db(0x00); db(0xff); db(0x16); db(0x2c); db(0x4c); + db(0x4e); db(0xae); db(0xff); db(0x70); db(0x26); db(0x40); db(0x30); db(0x3c); + db(0xff); db(0x20); db(0x61); db(0x00); db(0x01); db(0xca); db(0x4e); db(0x90); 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(0x80); db(0x20); db(0x09); + db(0x00); db(0x14); db(0x43); db(0xfa); db(0xfe); db(0x20); 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); @@ -3186,49 +3380,53 @@ void filesys_install_code (void) 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(0x3d); db(0x70); db(0x00); db(0x4e); db(0xae); + db(0x43); db(0xfa); db(0x01); db(0x59); 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(0x76); - 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(0x28); db(0x40); db(0x26); db(0x2c); db(0x00); db(0x0a); db(0x30); db(0x3c); + db(0xff); db(0x40); db(0x61); db(0x00); db(0x00); db(0xfa); db(0x70); db(0x00); + db(0x4e); db(0x90); db(0x60); db(0x7e); 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(0x3c); + db(0x30); db(0x3c); db(0xff); db(0x50); db(0x61); db(0x00); db(0x00); db(0xd8); + db(0x70); db(0x01); db(0x4e); db(0x90); db(0x45); db(0xeb); db(0x00); db(0x04); + db(0x20); db(0x52); db(0x20); db(0x08); db(0x67); db(0xd6); 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(0x42); db(0x53); db(0x85); db(0x4c); db(0xdf); db(0x03); db(0x00); + db(0x61); db(0x48); 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(0x0c); db(0x85); db(0x00); db(0x00); db(0x00); db(0x14); db(0x65); db(0x00); db(0x00); db(0x0a); 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(0x8a); db(0x28); db(0x43); - db(0x61); db(0x02); db(0x60); db(0x84); 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(0x00); db(0x00); db(0x0c); - db(0x52); db(0x85); db(0x67); db(0x1e); db(0x22); db(0x4a); db(0x24); db(0x52); - db(0x60); db(0xf0); 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(0x06); db(0x86); 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); db(0x00); db(0x00); - db(0x00); db(0x00); db(0x03); db(0xf2); + db(0x29); db(0x40); db(0x00); db(0x04); db(0x60); db(0x12); db(0x61); db(0x30); + db(0x30); db(0x3c); db(0xff); db(0x30); db(0x61); db(0x00); db(0x00); db(0x88); + db(0x4e); db(0x90); 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(0x82); db(0x28); db(0x43); db(0x61); db(0x04); db(0x60); db(0x00); + db(0xff); db(0x7c); 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(0x00); db(0x00); db(0x0c); db(0x52); db(0x85); + db(0x67); db(0x1e); db(0x22); db(0x4a); db(0x24); db(0x52); db(0x60); db(0xf0); + 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(0x06); db(0x86); + 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(0x41); db(0xfa); + db(0xfc); db(0x6c); db(0x02); db(0x80); db(0x00); db(0x00); db(0xff); db(0xff); + db(0xd1); db(0xc0); 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); db(0x00); db(0x00); db(0x00); db(0x00); db(0x03); db(0xf2); + }