/filesys.cpp
C++ | 10368 lines | 10225 code | 86 blank | 57 comment | 152 complexity | ec14108ce989ddb29ad600a1052dc3f7 MD5 | raw file
- /*
- * UAE - The Un*x Amiga Emulator
- *
- * Unix file system handler for AmigaDOS
- *
- * Copyright 1996 Ed Hanway
- * Copyright 1996, 1997 Bernd Schmidt
- *
- * Version 0.4: 970308
- *
- * Based on example code (c) 1988 The Software Distillery
- * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
- * (May - August 1989)
- *
- * Known limitations:
- * Does not support several (useless) 2.0+ packet types.
- * May not return the correct error code in some cases.
- * Does not check for sane values passed by AmigaDOS. May crash the emulation
- * if passed garbage values.
- * Could do tighter checks on malloc return values.
- * Will probably fail spectacularly in some cases if the filesystem is
- * modified at the same time by another process while UAE is running.
- */
- #include "sysconfig.h"
- #include "sysdeps.h"
- #include "threaddep/thread.h"
- #include "options.h"
- #include "traps.h"
- #include "uae.h"
- #include "memory.h"
- #include "custom.h"
- #include "events.h"
- #include "newcpu.h"
- #include "filesys.h"
- #include "autoconf.h"
- #include "fsusage.h"
- #include "native2amiga.h"
- #include "scsidev.h"
- #include "uaeserial.h"
- #include "fsdb.h"
- #include "zfile.h"
- #include "zarchive.h"
- #include "gui.h"
- #include "gayle.h"
- #include "idecontrollers.h"
- #include "savestate.h"
- #include "a2091.h"
- #include "ncr_scsi.h"
- #include "cdtv.h"
- #include "sana2.h"
- #include "bsdsocket.h"
- #include "uaeresource.h"
- #include "inputdevice.h"
- #include "clipboard.h"
- #include "consolehook.h"
- #include "blkdev.h"
- #include "isofs_api.h"
- #include "scsi.h"
- #include "uaenative.h"
- #include "tabletlibrary.h"
- #include "cia.h"
- #include "picasso96.h"
- #include "cpuboard.h"
- #include "rommgr.h"
- #include "debug.h"
- #include "debugmem.h"
- #ifdef RETROPLATFORM
- #include "rp.h"
- #endif
- #define TRACING_ENABLED 1
- int log_filesys = 0;
- #define TRAPMD 1
- #if TRACING_ENABLED
- #if 0
- #define TRACE(x) if (log_filesys > 0 && (unit->volflags & MYVOLUMEINFO_CDFS)) { write_log x; }
- #else
- #define TRACE(x) if (log_filesys > 0) { write_log x; }
- #endif
- #define TRACEI(x) if (log_filesys > 0) { write_log x; }
- #define TRACE2(x) if (log_filesys >= 2) { write_log x; }
- #define TRACE3(x) if (log_filesys >= 3) { write_log x; }
- #define DUMPLOCK(c,u,x) dumplock(c,u,x)
- #else
- #define TRACE(x)
- #define DUMPLOCK(c,u,x)
- #define TRACE2(x)
- #define TRACE3(x)
- #endif
- #define KS12_BOOT_HACK 1
- #define UNIT_LED(unit) ((unit)->ui.unit_type == UNIT_CDFS ? LED_CD : LED_HD)
- static int bootrom_header;
- static uae_u32 dlg (uae_u32 a)
- {
- return (dbg (a + 0) << 24) | (dbg (a + 1) << 16) | (dbg (a + 2) << 8) | (dbg (a + 3) << 0);
- }
- static void aino_test (a_inode *aino)
- {
- #ifdef AINO_DEBUG
- a_inode *aino2 = aino, *aino3;
- for (;;) {
- if (!aino || !aino->next)
- return;
- if ((aino->checksum1 ^ aino->checksum2) != 0xaaaa5555) {
- write_log (_T("PANIC: corrupted or freed but used aino detected!"), aino);
- }
- aino3 = aino;
- aino = aino->next;
- if (aino->prev != aino3) {
- write_log (_T("PANIC: corrupted aino linking!\n"));
- break;
- }
- if (aino == aino2) break;
- }
- #endif
- }
- static void aino_test_init (a_inode *aino)
- {
- #ifdef AINO_DEBUG
- aino->checksum1 = (uae_u32)aino;
- aino->checksum2 = aino->checksum1 ^ 0xaaaa5555;
- #endif
- }
- #define UAEFS_VERSION "UAE fs 0.6"
- uaecptr filesys_initcode, filesys_initcode_ptr, filesys_initcode_real;
- static uaecptr bootrom_start;
- static uae_u32 fsdevname, fshandlername, filesys_configdev;
- static uae_u32 cdfs_devname, cdfs_handlername;
- static uaecptr afterdos_name, afterdos_id, afterdos_initcode;
- static uaecptr keymaphook_name, keymaphook_id, keymaphook_initcode;
- static uaecptr shell_execute_data, shell_execute_process;
- static int filesys_in_interrupt;
- static uae_u32 mountertask;
- static int automountunit = -1;
- static int autocreatedunit;
- static int cd_unit_offset, cd_unit_number;
- static uaecptr ROM_filesys_doio, ROM_filesys_doio_original;
- static uaecptr ROM_filesys_putmsg, ROM_filesys_putmsg_original;
- static uaecptr ROM_filesys_putmsg_return;
- static uaecptr ROM_filesys_hack_remove;
- static smp_comm_pipe shellexecute_pipe;
- static uae_u32 segtrack_mode = 0;
- #define FS_STARTUP 0
- #define FS_GO_DOWN 1
- #define DEVNAMES_PER_HDF 32
- #define UNIT_FILESYSTEM 0
- #define UNIT_CDFS 1
- typedef struct {
- int unit_type;
- int open; // >0 start as filesystem, <0 = allocated but do not start
- TCHAR *devname; /* device name, e.g. UAE0: */
- uaecptr devname_amiga;
- uaecptr startup;
- uaecptr devicenode;
- uaecptr parmpacket;
- TCHAR *volname; /* volume name, e.g. CDROM, WORK, etc. */
- int volflags; /* volume flags, readonly, stream uaefsdb support */
- TCHAR *rootdir; /* root native directory/hdf. empty drive if invalid path */
- TCHAR *rootdirdiff; /* "diff" file/directory */
- bool readonly; /* disallow write access? */
- bool locked; /* action write protect */
- bool unknown_media; /* ID_UNREADABLE_DISK */
- int bootpri; /* boot priority. -128 = no autoboot, -129 = no mount */
- int devno;
- bool wasisempty; /* if true, this unit was created empty */
- int canremove; /* if >0, this unit can be safely ejected and remounted */
- bool configureddrive; /* if true, this is drive that was manually configured */
- bool inject_icons; /* inject icons if directory filesystem */
- struct hardfiledata hf;
- struct zvolume *zarchive;
- /* Threading stuff */
- smp_comm_pipe *volatile unit_pipe, *volatile back_pipe;
- uae_thread_id tid;
- struct _unit *self;
- /* Reset handling */
- uae_sem_t reset_sync_sem;
- volatile 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;
- TCHAR *filesysdir;
- /* filesystem seglist */
- uaecptr filesysseg;
- uae_u32 rdb_dostype;
- /* CDFS */
- bool cd_open;
- int cddevno;
- void *cdfs_superblock;
- } UnitInfo;
- struct uaedev_mount_info {
- UnitInfo ui[MAX_FILESYSTEM_UNITS];
- };
- static struct uaedev_mount_info mountinfo;
- /* minimal AmigaDOS definitions */
- /* field offsets in DosPacket */
- #define dp_Type 8
- #define dp_Res1 12
- #define dp_Res2 16
- #define dp_Arg1 20
- #define dp_Arg2 24
- #define dp_Arg3 28
- #define dp_Arg4 32
- #define dp_Arg5 36
- #define DP64_INIT -3L
- #define dp64_Type 8
- #define dp64_Res0 12
- #define dp64_Res2 16
- #define dp64_Res1 24
- #define dp64_Arg1 32
- #define dp64_Arg2 40
- #define dp64_Arg3 48
- #define dp64_Arg4 52
- #define dp64_Arg5 56
- #define dp_Max 60
- /* result codes */
- #define DOS_TRUE ((uae_u32)-1L)
- #define DOS_FALSE (0L)
- /* DirEntryTypes */
- #define ST_PIPEFILE -5
- #define ST_LINKFILE -4
- #define ST_FILE -3
- #define ST_ROOT 1
- #define ST_USERDIR 2
- #define ST_SOFTLINK 3
- #define ST_LINKDIR 4
- #if 1
- #define MAXFILESIZE32 (0xffffffff)
- #else
- /* technically correct but most native
- * filesystems don't enforce it
- */
- #define MAXFILESIZE32 (0x7fffffff)
- #endif
- #define MAXFILESIZE32_2G (0x7fffffff)
- /* 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
- #define ACTION_RENAME_DISK 9
- #define ACTION_FREE_LOCK 15
- #define ACTION_DELETE_OBJECT 16
- #define ACTION_RENAME_OBJECT 17
- #define ACTION_MORE_CACHE 18
- #define ACTION_COPY_DIR 19
- #define ACTION_SET_PROTECT 21
- #define ACTION_CREATE_DIR 22
- #define ACTION_EXAMINE_OBJECT 23
- #define ACTION_EXAMINE_NEXT 24
- #define ACTION_DISK_INFO 25
- #define ACTION_INFO 26
- #define ACTION_FLUSH 27
- #define ACTION_SET_COMMENT 28
- #define ACTION_PARENT 29
- #define ACTION_SET_DATE 34
- #define ACTION_FIND_WRITE 1004
- #define ACTION_FIND_INPUT 1005
- #define ACTION_FIND_OUTPUT 1006
- #define ACTION_END 1007
- #define ACTION_SEEK 1008
- #define ACTION_WRITE_PROTECT 1023
- #define ACTION_IS_FILESYSTEM 1027
- #define ACTION_READ 'R'
- #define ACTION_WRITE 'W'
- /* 2.0+ packet types */
- #define ACTION_INHIBIT 31
- #define ACTION_SET_FILE_SIZE 1022
- #define ACTION_LOCK_RECORD 2008
- #define ACTION_FREE_RECORD 2009
- #define ACTION_SAME_LOCK 40
- #define ACTION_CHANGE_MODE 1028
- #define ACTION_FH_FROM_LOCK 1026
- #define ACTION_COPY_DIR_FH 1030
- #define ACTION_PARENT_FH 1031
- #define ACTION_EXAMINE_ALL 1033
- #define ACTION_EXAMINE_FH 1034
- #define ACTION_EXAMINE_ALL_END 1035
- #define ACTION_FORMAT 1020
- #define ACTION_IS_FILESYSTEM 1027
- #define ACTION_ADD_NOTIFY 4097
- #define ACTION_REMOVE_NOTIFY 4098
- #define ACTION_READ_LINK 1024
- /* OS4 64-bit filesize packets */
- #define ACTION_FILESYSTEM_ATTR 3005
- #define ACTION_CHANGE_FILE_POSITION64 8001
- #define ACTION_GET_FILE_POSITION64 8002
- #define ACTION_CHANGE_FILE_SIZE64 8003
- #define ACTION_GET_FILE_SIZE64 8004
- /* MOS 64-bit filesize packets */
- #define ACTION_SEEK64 26400
- #define ACTION_SET_FILE_SIZE64 26401
- #define ACTION_LOCK_RECORD64 26402
- #define ACTION_FREE_RECORD64 26403
- #define ACTION_QUERY_ATTR 26407
- #define ACTION_EXAMINE_OBJECT64 26408
- #define ACTION_EXAMINE_NEXT64 26409
- #define ACTION_EXAMINE_FH64 26410
- /* not supported */
- #define ACTION_MAKE_LINK 1021
- #define DISK_TYPE_DOS 0x444f5300 /* DOS\0 */
- #define DISK_TYPE_DOS_FFS 0x444f5301 /* DOS\1 */
- #define CDFS_DOSTYPE 0x43440000 /* CDxx */
- typedef struct _dpacket {
- uaecptr packet_addr;
- uae_u8 *packet_data;
- uae_u8 packet_array[dp_Max];
- bool need_flush;
- } dpacket;
- typedef struct {
- uae_u32 uniq;
- /* The directory we're going through. */
- a_inode *aino;
- /* The file we're going to look up next. */
- a_inode *curr_file;
- } ExamineKey;
- struct lockrecord
- {
- struct lockrecord *next;
- dpacket *packet;
- uae_u64 pos;
- uae_u64 len;
- uae_u32 mode;
- uae_u32 timeout;
- uae_u32 msg;
- };
- typedef struct key {
- struct key *next;
- a_inode *aino;
- uae_u32 uniq;
- struct fs_filehandle *fd;
- uae_u64 file_pos;
- int dosmode;
- int createmode;
- int notifyactive;
- struct lockrecord *record;
- } Key;
- typedef struct notify {
- struct notify *next;
- uaecptr notifyrequest;
- TCHAR *fullname;
- TCHAR *partname;
- } Notify;
- typedef struct exallkey {
- uae_u32 id;
- struct fs_dirhandle *dirhandle;
- TCHAR *fn;
- uaecptr control;
- } ExAllKey;
- /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
- * some of these around
- */
- #define EXKEYS 128
- #define EXALLKEYS 100
- #define MAX_AINO_HASH 128
- #define NOTIFY_HASH_SIZE 127
- /* handler state info */
- typedef struct _unit {
- struct _unit *next;
- /* Amiga stuff */
- uaecptr dosbase;
- /* volume points to our IO board, always 1:1 mapping */
- uaecptr volume;
- uaecptr port; /* Our port */
- uaecptr locklist;
- /* Native stuff */
- uae_s32 unit; /* unit number */
- UnitInfo ui; /* unit startup info */
- TCHAR tmpbuf3[256];
- /* Dummy message processing */
- 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;
- unsigned int total_locked_ainos;
- /* ExAll */
- ExAllKey exalls[EXALLKEYS];
- int exallid;
- /* Keys */
- struct key *keys;
- struct lockrecord *waitingrecords;
- a_inode rootnode;
- unsigned int aino_cache_size;
- a_inode *aino_hash[MAX_AINO_HASH];
- unsigned int nr_cache_hits;
- unsigned int nr_cache_lookups;
- struct notify *notifyhash[NOTIFY_HASH_SIZE];
- int volflags;
- uae_u32 lockkey;
- bool inhibited;
- bool canremovable;
- /* increase when media is changed.
- * used to detect if cached aino is valid
- */
- int mountcount;
- int mount_changed;
- void *cdfs_superblock;
- TCHAR *mount_volume;
- TCHAR *mount_rootdir;
- bool mount_readonly;
- int mount_flags;
- int reinsertdelay;
- TCHAR *newvolume;
- TCHAR *newrootdir;
- bool newreadonly;
- int newflags;
- } Unit;
- int nr_units (void)
- {
- int cnt = 0;
- for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- if (mountinfo.ui[i].open > 0)
- cnt++;
- }
- return cnt;
- }
- int nr_directory_units (struct uae_prefs *p)
- {
- int cnt = 0;
- if (p) {
- for (int i = 0; i < p->mountitems; i++) {
- if (p->mountconfig[i].ci.controller_type == HD_CONTROLLER_TYPE_UAE)
- cnt++;
- }
- } else {
- for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- if (mountinfo.ui[i].open > 0 && mountinfo.ui[i].hf.ci.controller_type == HD_CONTROLLER_TYPE_UAE)
- cnt++;
- }
- }
- return cnt;
- }
- static int is_virtual (int unit_no)
- {
- int t = is_hardfile (unit_no);
- return t == FILESYS_VIRTUAL || t == FILESYS_CD;
- }
- int is_hardfile (int unit_no)
- {
- if (mountinfo.ui[unit_no].volname || mountinfo.ui[unit_no].wasisempty || mountinfo.ui[unit_no].unknown_media) {
- if (unit_no >= cd_unit_offset && unit_no < cd_unit_offset + cd_unit_number)
- return FILESYS_CD;
- return FILESYS_VIRTUAL;
- }
- if (mountinfo.ui[unit_no].hf.ci.sectors == 0) {
- if (mountinfo.ui[unit_no].hf.flags & 1)
- return FILESYS_HARDDRIVE;
- return FILESYS_HARDFILE_RDB;
- }
- return FILESYS_HARDFILE;
- }
- static void close_filesys_unit (UnitInfo *uip)
- {
- if (!uip->open)
- return;
- if (uip->hf.handle_valid)
- hdf_close (&uip->hf);
- if (uip->volname != 0)
- xfree (uip->volname);
- if (uip->devname != 0)
- xfree (uip->devname);
- if (uip->rootdir != 0)
- xfree (uip->rootdir);
- if (uip->unit_pipe)
- xfree (uip->unit_pipe);
- if (uip->back_pipe)
- xfree (uip->back_pipe);
- if (uip->cd_open) {
- sys_command_close (uip->cddevno);
- isofs_unmount (uip->cdfs_superblock);
- }
- uip->unit_pipe = 0;
- uip->back_pipe = 0;
- uip->hf.handle_valid = 0;
- uip->volname = 0;
- uip->devname = 0;
- uip->rootdir = 0;
- uip->open = 0;
- uip->cd_open = 0;
- }
- static uaedev_config_data *getuci (struct uaedev_config_data *uci, int nr)
- {
- return &uci[nr];
- }
- static UnitInfo *getuip (struct uae_prefs *p, int index)
- {
- if (index < 0)
- return NULL;
- index = p->mountconfig[index].configoffset;
- if (index < 0)
- return NULL;
- return &mountinfo.ui[index];
- }
- static int getuindex (struct uae_prefs *p, int index)
- {
- if (index < 0)
- return -1;
- return p->mountconfig[index].unitnum;
- }
- int get_filesys_unitconfig (struct uae_prefs *p, int index, struct mountedinfo *mi)
- {
- UnitInfo *ui = getuip (p, index);
- struct uaedev_config_data *uci = &p->mountconfig[index];
- UnitInfo uitmp;
- TCHAR filepath[MAX_DPATH];
- memset (mi, 0, sizeof (struct mountedinfo));
- memset (&uitmp, 0, sizeof uitmp);
- _tcscpy(mi->rootdir, uci->ci.rootdir);
- if (!ui) {
- ui = &uitmp;
- if (uci->ci.type == UAEDEV_DIR) {
- cfgfile_resolve_path_out_load(uci->ci.rootdir, filepath, MAX_DPATH, PATH_DIR);
- _tcscpy(mi->rootdir, filepath);
- mi->ismounted = 1;
- if (filepath[0] == 0)
- return FILESYS_VIRTUAL;
- if (my_existsfile (filepath)) {
- mi->ismedia = 1;
- return FILESYS_VIRTUAL;
- }
- if (my_getvolumeinfo (filepath) < 0)
- return -1;
- mi->ismedia = true;
- return FILESYS_VIRTUAL;
- } else if (uci->ci.type == UAEDEV_HDF) {
- cfgfile_resolve_path_out_load(uci->ci.rootdir, filepath, MAX_DPATH, PATH_HDF);
- _tcscpy(mi->rootdir, filepath);
- ui->hf.ci.readonly = true;
- ui->hf.ci.blocksize = uci->ci.blocksize;
- int err = hdf_open (&ui->hf, filepath);
- if (err <= 0) {
- mi->ismedia = false;
- mi->ismounted = true;
- mi->error = err;
- if (uci->ci.reserved == 0 && uci->ci.sectors == 0 && uci->ci.surfaces == 0) {
- if (ui->hf.flags & 1)
- return FILESYS_HARDDRIVE;
- return FILESYS_HARDFILE_RDB;
- }
- return -1;
- }
- mi->ismedia = true;
- if (ui->hf.drive_empty)
- mi->ismedia = 0;
- hdf_close (&ui->hf);
- } else if (uci->ci.type == UAEDEV_CD) {
- cfgfile_resolve_path_out_load(uci->ci.rootdir, filepath, MAX_DPATH, PATH_CD);
- _tcscpy(mi->rootdir, filepath);
- struct device_info di;
- ui->hf.ci.readonly = true;
- ui->hf.ci.blocksize = uci->ci.blocksize;
- mi->size = -1;
- mi->ismounted = true;
- if (blkdev_get_info (p, ui->hf.ci.device_emu_unit, &di)) {
- mi->ismedia = di.media_inserted != 0;
- _tcscpy (mi->rootdir, di.label);
- }
- #if 0
- if (ui->hf.ci.cd_emu_unit == 0)
- _tcscpy (mi->rootdir, _T("CD"));
- else
- _stprintf (mi->rootdir, _T("CD %d"), ui->hf.ci.cd_emu_unit);
- #endif
- }
- } else if (uci->ci.type != UAEDEV_TAPE) {
- if (ui->hf.ci.controller_type == HD_CONTROLLER_TYPE_UAE) { // what is this? || (ui->controller && p->cs_ide)) {
- mi->ismounted = 1;
- if (uci->ci.type == UAEDEV_HDF)
- mi->ismedia = ui->hf.drive_empty ? false : true;
- else
- mi->ismedia = true;
- }
- }
- if (uci->ci.type == UAEDEV_TAPE) {
- cfgfile_resolve_path_out_load(uci->ci.rootdir, filepath, MAX_DPATH, PATH_TAPE);
- _tcscpy(mi->rootdir, filepath);
- struct device_info di;
- int unitnum = getuindex (p, index);
- mi->size = -1;
- mi->ismounted = false;
- if (unitnum >= 0) {
- mi->ismounted = true;
- if (tape_get_info (unitnum, &di)) {
- mi->ismedia = di.media_inserted != 0;
- _tcscpy (mi->rootdir, di.label);
- }
- } else {
- struct scsi_data_tape *tape;
- unitnum = 0;
- tape = tape_alloc (unitnum, filepath, uci->ci.readonly);
- if (tape) {
- if (tape_get_info (unitnum, &di)) {
- mi->ismedia = di.media_inserted != 0;
- _tcscpy (mi->rootdir, di.label);
- }
- tape_free (tape);
- }
- }
- return FILESYS_TAPE;
- }
- if (mi->size < 0)
- return -1;
- mi->size = ui->hf.virtsize;
- if (uci->ci.highcyl) {
- uci->ci.cyls = mi->nrcyls = uci->ci.highcyl;
- } else {
- uci->ci.cyls = mi->nrcyls = (int)(uci->ci.sectors * uci->ci.surfaces ? (ui->hf.virtsize / uci->ci.blocksize) / (uci->ci.sectors * uci->ci.surfaces) : 0);
- }
- if (uci->ci.type == UAEDEV_DIR)
- return FILESYS_VIRTUAL;
- if (uci->ci.reserved == 0 && uci->ci.sectors == 0 && uci->ci.surfaces == 0) {
- if (ui->hf.flags & 1)
- return FILESYS_HARDDRIVE;
- return FILESYS_HARDFILE_RDB;
- }
- return FILESYS_HARDFILE;
- }
- static void stripsemicolon (TCHAR *s)
- {
- if (!s)
- return;
- while (_tcslen(s) > 0 && s[_tcslen(s) - 1] == ':')
- s[_tcslen(s) - 1] = 0;
- }
- static void stripspace (TCHAR *s)
- {
- if (!s)
- return;
- for (int i = 0; i < _tcslen (s); i++) {
- if (s[i] == ' ')
- s[i] = '_';
- }
- }
- static void striplength (TCHAR *s, int len)
- {
- if (!s)
- return;
- if (_tcslen (s) <= len)
- return;
- s[len] = 0;
- }
- static void fixcharset (TCHAR *s)
- {
- char tmp[MAX_DPATH];
- if (!s)
- return;
- ua_fs_copy (tmp, MAX_DPATH, s, '_');
- au_fs_copy (s, strlen (tmp) + 1, tmp);
- }
- TCHAR *validatevolumename (TCHAR *s, const TCHAR *def)
- {
- stripsemicolon (s);
- fixcharset (s);
- striplength (s, 30);
- if (_tcslen(s) == 0 && def) {
- xfree(s);
- s = my_strdup(def);
- }
- return s;
- }
- TCHAR *validatedevicename (TCHAR *s, const TCHAR *def)
- {
- stripsemicolon (s);
- stripspace (s);
- fixcharset (s);
- striplength (s, 30);
- if (_tcslen(s) == 0 && def) {
- xfree(s);
- s = my_strdup(def);
- }
- return s;
- }
- TCHAR *filesys_createvolname (const TCHAR *volname, const TCHAR *rootdir, struct zvolume *zv, const TCHAR *def)
- {
- TCHAR *nvol = NULL;
- int i, archivehd;
- TCHAR *p = NULL;
- TCHAR path[MAX_DPATH];
- cfgfile_resolve_path_out_load(rootdir, path, MAX_DPATH, PATH_DIR);
- archivehd = -1;
- if (my_existsfile (path))
- archivehd = 1;
- else if (my_existsdir (path))
- archivehd = 0;
- if (zv && zv->volumename && _tcslen(zv->volumename) > 0) {
- nvol = my_strdup(zv->volumename);
- nvol = validatevolumename (nvol, def);
- return nvol;
- }
- if ((!volname || _tcslen (volname) == 0) && path && archivehd >= 0) {
- p = my_strdup (path);
- for (i = _tcslen (p) - 1; i >= 0; i--) {
- TCHAR c = p[i];
- if (c == ':' || c == '/' || c == '\\') {
- if (i == _tcslen (p) - 1)
- continue;
- if (!_tcscmp (p + i, _T(":\\"))) {
- xfree (p);
- p = xmalloc (TCHAR, 10);
- p[0] = path[0];
- p[1] = 0;
- i = 0;
- } else {
- i++;
- }
- break;
- }
- }
- if (i >= 0)
- nvol = my_strdup (p + i);
- }
- if (!nvol && archivehd >= 0) {
- if (volname && _tcslen (volname) > 0)
- nvol = my_strdup (volname);
- else
- nvol = my_strdup (def);
- }
- if (!nvol) {
- if (volname && _tcslen (volname))
- nvol = my_strdup (volname);
- else
- nvol = my_strdup (_T(""));
- }
- nvol = validatevolumename (nvol, def);
- xfree (p);
- return nvol;
- }
- static int set_filesys_volume (const TCHAR *rootdir, int *flags, bool *readonly, bool *emptydrive, struct zvolume **zvp)
- {
- *emptydrive = 0;
- if (my_existsfile (rootdir)) {
- struct zvolume *zv;
- zv = zfile_fopen_archive (rootdir);
- if (!zv) {
- error_log (_T("'%s' is not a supported archive file."), rootdir);
- return -1;
- }
- *zvp = zv;
- *flags = MYVOLUMEINFO_ARCHIVE;
- *readonly = 1;
- } else {
- *flags = my_getvolumeinfo (rootdir);
- if (*flags < 0) {
- if (rootdir && rootdir[0])
- error_log (_T("directory '%s' not found, mounting as empty drive."), rootdir);
- *emptydrive = 1;
- *flags = 0;
- } else if ((*flags) & MYVOLUMEINFO_READONLY) {
- error_log (_T("'%s' set to read-only."), rootdir);
- *readonly = 1;
- }
- }
- return 1;
- }
- void uci_set_defaults (struct uaedev_config_info *uci, bool rdb)
- {
- memset (uci, 0, sizeof (struct uaedev_config_info));
- if (!rdb) {
- uci->sectors = 32;
- uci->reserved = 2;
- uci->surfaces = 1;
- }
- uci->blocksize = 512;
- uci->maxtransfer = 0x7fffffff;
- uci->mask = 0xffffffff;
- uci->bufmemtype = 1;
- uci->buffers = 50;
- uci->stacksize = 4000;
- uci->bootpri = 0;
- uci->priority = 10;
- uci->sectorsperblock = 1;
- uci->device_emu_unit = -1;
- }
- static void get_usedblocks(struct fs_usage *fsu, bool fs, int *pblocksize, uae_s64 *pnumblocks, uae_s64 *pinuse, bool reduce)
- {
- uae_s64 numblocks = 0, inuse;
- int blocksize = *pblocksize;
- if (fs && currprefs.filesys_limit) {
- if (fsu->total > (uae_s64)currprefs.filesys_limit * 1024) {
- uae_s64 oldtotal = fsu->total;
- fsu->total = currprefs.filesys_limit * 1024;
- fsu->avail = ((fsu->avail / 1024) * (fsu->total / 1024)) / (oldtotal / 1024);
- fsu->avail *= 1024;
- }
- }
- if (reduce) {
- while (blocksize < 32768 || numblocks == 0) {
- numblocks = fsu->total / blocksize;
- if (numblocks <= 10)
- numblocks = 10;
- // Value that does not overflow when multiplied by 100 (uses 128 to keep it simple)
- if (numblocks < 0x02000000)
- break;
- blocksize *= 2;
- }
- }
- numblocks = fsu->total / blocksize;
- inuse = (numblocks * blocksize - fsu->avail) / blocksize;
- if (inuse > numblocks)
- inuse = numblocks;
- if (pnumblocks)
- *pnumblocks = numblocks;
- if (pinuse)
- *pinuse = inuse;
- if (pblocksize)
- *pblocksize = blocksize;
- }
- static bool get_blocks(const TCHAR *rootdir, int unit, int flags, int *pblocksize, uae_s64 *pnumblocks, uae_s64 *pinuse, bool reduce)
- {
- struct fs_usage fsu;
- int ret;
- bool fs = false;
- int blocksize;
- blocksize = 512;
- if (flags & MYVOLUMEINFO_ARCHIVE) {
- ret = zfile_fs_usage_archive(rootdir, 0, &fsu);
- fs = true;
- } else {
- ret = get_fs_usage(rootdir, 0, &fsu);
- fs = true;
- }
- if (ret)
- return false;
- get_usedblocks(&fsu, fs, &blocksize, pnumblocks, pinuse, reduce);
- if (pblocksize)
- *pblocksize = blocksize;
- return ret == 0;
- }
- static int set_filesys_unit_1 (int nr, struct uaedev_config_info *ci, bool custom)
- {
- UnitInfo *ui;
- int i;
- bool emptydrive = false;
- bool iscd;
- struct uaedev_config_info c;
- memcpy (&c, ci, sizeof (struct uaedev_config_info));
- if (nr < 0) {
- for (nr = 0; nr < MAX_FILESYSTEM_UNITS; nr++) {
- if (!mountinfo.ui[nr].open)
- break;
- }
- if (nr == MAX_FILESYSTEM_UNITS) {
- error_log (_T("No slot allocated for this unit"));
- return -1;
- }
- }
- if (ci->controller_type != HD_CONTROLLER_TYPE_UAE || ci->type == UAEDEV_TAPE) {
- ui = &mountinfo.ui[nr];
- memset (ui, 0, sizeof (UnitInfo));
- memcpy (&ui->hf.ci, &c, sizeof (struct uaedev_config_info));
- ui->readonly = c.readonly;
- ui->unit_type = -1;
- ui->open = -1;
- return nr;
- }
- iscd = nr >= cd_unit_offset && nr < cd_unit_offset + cd_unit_number;
- if (!custom)
- cfgfile_resolve_path_load(c.rootdir, MAX_DPATH, iscd ? PATH_CD : (ci->volname[0] ? PATH_DIR : PATH_HDF));
- for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- if (nr == i || !mountinfo.ui[i].open || mountinfo.ui[i].rootdir == NULL || is_hardfile (i) == FILESYS_CD)
- continue;
- if (_tcslen(c.rootdir) > 0 && samepath(mountinfo.ui[i].rootdir, c.rootdir)) {
- error_log (_T("directory/hardfile '%s' already added."), c.rootdir);
- return -1;
- }
- }
- for (;;) {
- bool retry = false;
- for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- int hf = is_hardfile(i);
- if (nr == i || !mountinfo.ui[i].open || mountinfo.ui[i].rootdir == NULL)
- continue;
- if (hf != FILESYS_HARDDRIVE && hf != FILESYS_HARDFILE && hf != FILESYS_HARDFILE_RDB)
- continue;
- if (mountinfo.ui[i].hf.ci.controller_unit == c.controller_unit) {
- c.controller_unit++;
- if (c.controller_unit >= MAX_FILESYSTEM_UNITS) {
- error_log (_T("directory/hardfile '%s' invalid unit number."), c.rootdir);
- return -1;
- }
- retry = true;
- }
- }
- if (!retry)
- break;
- }
- ui = &mountinfo.ui[nr];
- memset (ui, 0, sizeof (UnitInfo));
- memcpy(&ui->hf.ci, &c, sizeof c);
- if (iscd) {
- ui->unit_type = UNIT_CDFS;
- emptydrive = 1;
- ui->volflags = MYVOLUMEINFO_CDFS | MYVOLUMEINFO_READONLY;
- c.readonly = true;
- } else if (c.volname[0]) {
- int flags = 0;
- uae_s64 numblocks;
- emptydrive = 1;
- if (c.rootdir[0]) {
- if (set_filesys_volume (c.rootdir, &flags, &c.readonly, &emptydrive, &ui->zarchive) < 0)
- return -1;
- }
- ui->volname = filesys_createvolname (c.volname, c.rootdir, ui->zarchive, _T("harddrive"));
- ui->volflags = flags;
- TCHAR *vs = au(UAEFS_VERSION);
- TCHAR *vsp = vs + _tcslen(vs) - 1;
- while (vsp != vs) {
- if (*vsp == ' ') {
- *vsp++ = 0;
- break;
- }
- vsp--;
- }
- _tcscpy(ui->hf.vendor_id, _T("UAE"));
- _tcscpy(ui->hf.product_id, vs);
- _tcscpy(ui->hf.product_rev, vsp);
- xfree(vs);
- ui->hf.ci.unit_feature_level = HD_LEVEL_SCSI_2;
- if (get_blocks(c.rootdir, nr, flags, &ui->hf.ci.blocksize, &numblocks, NULL, false))
- ui->hf.ci.max_lba = numblocks > 0xffffffff ? 0xffffffff : numblocks;
- else
- ui->hf.ci.max_lba = 0x00ffffff;
- } else {
- ui->unit_type = UNIT_FILESYSTEM;
- ui->hf.unitnum = nr;
- ui->volname = 0;
- if (ui->hf.ci.rootdir[0]) {
- if (hdf_open (&ui->hf) <= 0 && !c.readonly) {
- write_log (_T("Attempting to open '%s' in read-only mode.\n"), ui->hf.ci.rootdir);
- ui->hf.ci.readonly = c.readonly = true;
- if (hdf_open (&ui->hf) > 0) {
- error_log (_T("'%s' opened in read-only mode.\n"), ui->hf.ci.rootdir);
- }
- }
- } else {
- // empty drive?
- ui->hf.drive_empty = 1;
- }
- if (!ui->hf.drive_empty) {
- if (ui->hf.handle_valid == 0) {
- error_log (_T("Hardfile '%s' not found."), ui->hf.ci.rootdir);
- goto err;
- }
- if (ui->hf.ci.blocksize > ui->hf.virtsize || ui->hf.virtsize == 0) {
- error_log (_T("Hardfile '%s' too small."), ui->hf.ci.rootdir);
- goto err;
- }
- }
- if ((ui->hf.ci.blocksize & (ui->hf.ci.blocksize - 1)) != 0 || ui->hf.ci.blocksize == 0) {
- error_log (_T("Hardfile '%s' bad blocksize %d."), ui->hf.ci.rootdir, ui->hf.ci.blocksize);
- goto err;
- }
- if ((ui->hf.ci.sectors || ui->hf.ci.surfaces || ui->hf.ci.reserved) &&
- (ui->hf.ci.sectors < 1 || ui->hf.ci.surfaces < 1 || ui->hf.ci.surfaces > 1023 ||
- ui->hf.ci.reserved < 0 || ui->hf.ci.reserved > 1023) != 0) {
- error_log (_T("Hardfile '%s' bad hardfile geometry."), ui->hf.ci.rootdir);
- goto err;
- }
- if (!ui->hf.ci.highcyl) {
- ui->hf.ci.cyls = (int)(ui->hf.ci.sectors * ui->hf.ci.surfaces ? (ui->hf.virtsize / ui->hf.ci.blocksize) / (ui->hf.ci.sectors * ui->hf.ci.surfaces) : 0);
- }
- if (!ui->hf.ci.cyls)
- ui->hf.ci.cyls = ui->hf.ci.highcyl;
- if (!ui->hf.ci.cyls)
- ui->hf.ci.cyls = 1;
- }
- ui->self = 0;
- ui->reset_state = FS_STARTUP;
- ui->wasisempty = emptydrive;
- ui->canremove = emptydrive && (ci->flags & MYVOLUMEINFO_REUSABLE);
- ui->rootdir = my_strdup (c.rootdir);
- ui->devname = my_strdup (c.devname);
- stripsemicolon(ui->devname);
- if (c.filesys[0])
- ui->filesysdir = my_strdup (c.filesys);
- ui->readonly = c.readonly;
- if (c.bootpri < -129)
- c.bootpri = -129;
- if (c.bootpri > 127)
- c.bootpri = 127;
- ui->bootpri = c.bootpri;
- ui->inject_icons = c.inject_icons;
- ui->open = 1;
- return nr;
- err:
- if (ui->hf.handle_valid)
- hdf_close (&ui->hf);
- return -1;
- }
- static int set_filesys_unit (int nr, struct uaedev_config_info *ci, bool custom)
- {
- int ret;
- ret = set_filesys_unit_1 (nr, ci, custom);
- return ret;
- }
- static int add_filesys_unit (struct uaedev_config_info *ci, bool custom)
- {
- int nr;
- if (nr_units () >= MAX_FILESYSTEM_UNITS)
- return -1;
- nr = set_filesys_unit_1 (-1, ci, custom);
- #ifdef RETROPLATFORM
- if (nr >= 0) {
- UnitInfo *ui = &mountinfo.ui[nr];
- rp_hd_device_enable (nr, true);
- if (ui->unit_type == UNIT_CDFS)
- rp_cd_image_change(nr, ci->rootdir);
- else
- rp_harddrive_image_change(nr, ci->readonly, ci->rootdir);
- }
- #endif
- return nr;
- }
- int kill_filesys_unitconfig (struct uae_prefs *p, int nr)
- {
- struct uaedev_config_data *uci;
- if (nr < 0)
- return 0;
- uci = getuci (p->mountconfig, nr);
- hardfile_do_disk_change (uci, 0);
- if (uci->configoffset >= 0 && uci->ci.controller_type == HD_CONTROLLER_TYPE_UAE) {
- filesys_media_change(uci->ci.rootdir, 0, uci);
- } else {
- pcmcia_disk_reinsert(p, &uci->ci, true);
- }
- while (nr < MOUNT_CONFIG_SIZE) {
- memmove (&p->mountconfig[nr], &p->mountconfig[nr + 1], sizeof (struct uaedev_config_data));
- nr++;
- }
- p->mountitems--;
- memset (&p->mountconfig[MOUNT_CONFIG_SIZE - 1], 0, sizeof (struct uaedev_config_data));
- return 1;
- }
- int move_filesys_unitconfig (struct uae_prefs *p, int nr, int to)
- {
- struct uaedev_config_data *uci1, *uci2, tmpuci;
- uci1 = getuci (p->mountconfig, nr);
- uci2 = getuci (p->mountconfig, to);
- if (nr == to)
- return 0;
- memcpy (&tmpuci, uci1, sizeof (struct uaedev_config_data));
- memcpy (uci1, uci2, sizeof (struct uaedev_config_data));
- memcpy (uci2, &tmpuci, sizeof (struct uaedev_config_data));
- return 1;
- }
- static void allocuci (struct uae_prefs *p, int nr, int idx, int unitnum)
- {
- struct uaedev_config_data *uci = &p->mountconfig[nr];
- if (idx >= 0) {
- UnitInfo *ui;
- uci->configoffset = idx;
- ui = &mountinfo.ui[idx];
- ui->configureddrive = 1;
- uci->unitnum = unitnum;
- } else {
- uci->configoffset = -1;
- uci->unitnum = -1;
- }
- }
- static void allocuci (struct uae_prefs *p, int nr, int idx)
- {
- allocuci (p, nr, idx, -1);
- }
- static const TCHAR *getunittype(struct uaedev_config_info *uci)
- {
- return uci->type == UAEDEV_CD ? _T("CD") : (uci->type == UAEDEV_TAPE ? _T("TAPE") : _T("HD"));
- }
- static int cpuboard_hd;
- static romconfig cpuboard_dummy;
- void add_cpuboard_unit(int unit, struct uaedev_config_info *uci, struct romconfig *rc)
- {
- int flags = (uci->controller_type >= HD_CONTROLLER_TYPE_IDE_FIRST && uci->controller_type <= HD_CONTROLLER_TYPE_IDE_LAST) ? EXPANSIONTYPE_IDE : EXPANSIONTYPE_SCSI;
- const struct cpuboardtype *cbt = &cpuboards[currprefs.cpuboard_type];
- cpuboard_hd = 0;
- if (cbt->subtypes) {
- if (cbt->subtypes[currprefs.cpuboard_subtype].add && (cbt->subtypes[currprefs.cpuboard_subtype].deviceflags & flags)) {
- if (unit >= 0) {
- write_log(_T("Adding CPUBoard '%s' %s unit %d ('%s')\n"),
- cbt->subtypes[currprefs.cpuboard_subtype].name,
- getunittype(uci), unit, uci->rootdir);
- }
- cbt->subtypes[currprefs.cpuboard_subtype].add(unit, uci, rc);
- cpuboard_hd = 1;
- }
- }
- }
- static void add_cpuboard_unit_init(void)
- {
- memset(&cpuboard_dummy, 0, sizeof cpuboard_dummy);
- cpuboard_dummy.device_id = 7;
- if (currprefs.cpuboard_type) {
- struct romconfig *rc = get_device_romconfig(&currprefs, ROMTYPE_CPUBOARD, 0);
- if (!rc)
- rc = &cpuboard_dummy;
- const struct cpuboardtype *cbt = &cpuboards[currprefs.cpuboard_type];
- if (cbt->subtypes) {
- if (cbt->subtypes[currprefs.cpuboard_subtype].add) {
- const struct cpuboardsubtype *cst = &cbt->subtypes[currprefs.cpuboard_subtype];
- struct uaedev_config_info ci = { 0 };
- write_log(_T("Initializing CPUBoard '%s' %s controller\n"),
- cst->name, (cst->deviceflags & EXPANSIONTYPE_SCSI) ? _T("SCSI") : _T("IDE"));
- cst->add(-1, &ci, rc);
- }
- }
- }
- }
- static bool add_ide_unit(int type, int unit, struct uaedev_config_info *uci)
- {
- bool added = false;
- if (type >= HD_CONTROLLER_TYPE_IDE_EXPANSION_FIRST && type <= HD_CONTROLLER_TYPE_IDE_LAST) {
- for (int i = 0; expansionroms[i].name; i++) {
- if (i == type - HD_CONTROLLER_TYPE_IDE_EXPANSION_FIRST) {
- const struct expansionromtype *ert = &expansionroms[i];
- if ((ert->deviceflags & 2) && is_board_enabled(&currprefs, ert->romtype, uci->controller_type_unit)) {
- cpuboard_hd = 1;
- if (ert->add) {
- struct romconfig *rc = get_device_romconfig(&currprefs, ert->romtype, uci->controller_type_unit);
- write_log(_T("Adding IDE %s '%s' unit %d ('%s')\n"), getunittype(uci),
- ert->name, unit, uci->rootdir);
- ert->add(unit, uci, rc);
- }
- if (cpuboard_hd)
- added = true;
- }
- }
- }
- }
- return added;
- }
- static bool add_scsi_unit(int type, int unit, struct uaedev_config_info *uci)
- {
- bool added = false;
- if (type >= HD_CONTROLLER_TYPE_SCSI_EXPANSION_FIRST && type <= HD_CONTROLLER_TYPE_SCSI_LAST) {
- for (int i = 0; expansionroms[i].name; i++) {
- if (i == type - HD_CONTROLLER_TYPE_SCSI_EXPANSION_FIRST) {
- const struct expansionromtype *ert = &expansionroms[i];
- if ((ert->deviceflags & 1) && is_board_enabled(&currprefs, ert->romtype, uci->controller_type_unit)) {
- cpuboard_hd = 1;
- if (ert->add) {
- struct romconfig *rc = get_device_romconfig(&currprefs, ert->romtype, uci->controller_type_unit);
- write_log(_T("Adding SCSI %s '%s' unit %d ('%s')\n"), getunittype(uci),
- ert->name, unit, uci->rootdir);
- ert->add(unit, uci, rc);
- }
- if (cpuboard_hd)
- added = true;
- }
- }
- }
- }
- return added;
- }
- static void initialize_mountinfo (void)
- {
- int nr;
- UnitInfo *uip = &mountinfo.ui[0];
- cd_unit_offset = MAX_FILESYSTEM_UNITS;
- autocreatedunit = 0;
- for (nr = 0; nr < currprefs.mountitems; nr++) {
- struct uaedev_config_data *uci = &currprefs.mountconfig[nr];
- if (uci->ci.controller_type == HD_CONTROLLER_TYPE_UAE && (uci->ci.type == UAEDEV_DIR || uci->ci.type == UAEDEV_HDF)) {
- struct uaedev_config_info ci;
- memcpy (&ci, &uci->ci, sizeof (struct uaedev_config_info));
- ci.flags = MYVOLUMEINFO_REUSABLE;
- int idx = set_filesys_unit_1 (-1, &ci, false);
- allocuci (&currprefs, nr, idx);
- }
- }
- filesys_addexternals ();
- nr = nr_units ();
- cd_unit_offset = nr;
- cd_unit_number = 0;
- if (currprefs.scsi && currprefs.win32_automount_cddrives) {
- uae_u32 mask = scsi_get_cd_drive_mask ();
- for (int i = 0; i < 32; i++) {
- if (mask & (1 << i)) {
- struct uaedev_config_info ci = { 0 };
- _stprintf (ci.devname, _T("CD%d"), i);
- cd_unit_number++;
- _tcscpy (ci.rootdir, _T("/"));
- ci.readonly = true;
- ci.sectors = 1;
- ci.surfaces = 1;
- ci.blocksize = 2048;
- int idx = set_filesys_unit_1 (i + cd_unit_offset, &ci, true);
- allocuci (&currprefs, nr, idx);
- nr++;
- }
- }
- }
- for (nr = 0; nr < currprefs.mountitems; nr++) {
- struct uaedev_config_data *uci = &currprefs.mountconfig[nr];
- if (uci->ci.controller_type == HD_CONTROLLER_TYPE_UAE) {
- if (uci->ci.type == UAEDEV_TAPE) {
- struct uaedev_config_info ci;
- memcpy (&ci, &uci->ci, sizeof (struct uaedev_config_info));
- int unitnum = scsi_add_tape (&uci->ci);
- if (unitnum >= 0) {
- int idx = set_filesys_unit_1 (-1, &ci, false);
- allocuci (&currprefs, nr, idx, unitnum);
- }
- }
- }
- }
- // init all controllers first
- add_cpuboard_unit_init();
- for (int i = 0; expansionroms[i].name; i++) {
- const struct expansionromtype *ert = &expansionroms[i];
- for (int j = 0; j < MAX_DUPLICATE_EXPANSION_BOARDS; j++) {
- struct romconfig *rc = get_device_romconfig(&currprefs, ert->romtype, j);
- if ((ert->deviceflags & 3) && rc) {
- if (ert->add) {
- struct uaedev_config_info ci = { 0 };
- ci.controller_type_unit = j;
- ert->add(-1, &ci, rc);
- }
- }
- }
- }
- for (nr = 0; nr < currprefs.mountitems; nr++) {
- struct uaedev_config_info *uci = &currprefs.mountconfig[nr].ci;
- int type = uci->controller_type;
- int unit = uci->controller_unit;
- bool added = false;
- uci->uae_unitnum = nr;
- if (type == HD_CONTROLLER_TYPE_UAE) {
- continue;
- } else if (type != HD_CONTROLLER_TYPE_IDE_AUTO && type >= HD_CONTROLLER_TYPE_IDE_FIRST && type <= HD_CONTROLLER_TYPE_IDE_LAST) {
- added = add_ide_unit(type, unit, uci);
- } else if (type == HD_CONTROLLER_TYPE_IDE_AUTO) {
- for (int st = HD_CONTROLLER_TYPE_IDE_FIRST; st <= HD_CONTROLLER_TYPE_IDE_LAST; st++) {
- added = add_ide_unit(st, unit, uci);
- if (added)
- break;
- }
- } else if (type != HD_CONTROLLER_TYPE_SCSI_AUTO && type >= HD_CONTROLLER_TYPE_SCSI_FIRST && type <= HD_CONTROLLER_TYPE_SCSI_LAST) {
- added = add_scsi_unit(type, unit, uci);
- } else if (type == HD_CONTROLLER_TYPE_SCSI_AUTO) {
- for (int st = HD_CONTROLLER_TYPE_SCSI_FIRST; st <= HD_CONTROLLER_TYPE_SCSI_LAST; st++) {
- added = add_scsi_unit(st, unit, uci);
- if (added)
- break;
- }
- #if 0
- } else if (type == HD_CONTROLLER_TYPE_PCMCIA) {
- if (uci->controller_type_unit == 0) {
- gayle_add_pcmcia_sram_unit (uci);
- added = true;
- } else {
- gayle_add_pcmcia_ide_unit (uci);
- added = true;
- }
- #endif
- }
- if (added)
- allocuci (&currprefs, nr, -1);
- }
-
- }
- int sprintf_filesys_unit (TCHAR *buffer, int num)
- {
- UnitInfo *uip = mountinfo.ui;
- if (uip[num].volname != 0)
- _stprintf (buffer, _T("(DH%d:) Filesystem, %s: %s %s"), num, uip[num].volname,
- uip[num].rootdir, uip[num].readonly ? _T("ro") : _T(""));
- else
- _stprintf (buffer, _T("(DH%d:) Hardfile, \"%s\", size %d Mbytes"), num,
- uip[num].rootdir, (int)(uip[num].hf.virtsize / (1024 * 1024)));
- return 0;
- }
- static void free_mountinfo (void)
- {
- int i;
- for (i = 0; i < MAX_FILESYSTEM_UNITS; i++)
- close_filesys_unit (mountinfo.ui + i);
- gayle_free_units ();
- }
- struct hardfiledata *get_hardfile_data_controller(int nr)
- {
- UnitInfo *uip = mountinfo.ui;
- for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- if (uip[i].open == 0)
- continue;
- if (uip[i].hf.ci.controller_unit == nr && uip[i].hf.ci.type != UAEDEV_DIR)
- return &uip[i].hf;
- }
- for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- if (uip[i].open == 0)
- continue;
- if (uip[i].hf.ci.controller_unit == nr && uip[i].hf.ci.type == UAEDEV_DIR)
- return &uip[i].hf;
- }
- return NULL;
- }
- struct hardfiledata *get_hardfile_data (int nr)
- {
- UnitInfo *uip = mountinfo.ui;
- if (nr < 0 || nr >= MAX_FILESYSTEM_UNITS || uip[nr].open == 0 || is_virtual (nr))
- return NULL;
- return &uip[nr].hf;
- }
- static uae_u32 a_uniq, key_uniq;
- #define PUT_PCK_RES1(p,v) do { put_long_host((p)->packet_data + dp_Res1, (v)); } while (0)
- #define PUT_PCK_RES2(p,v) do { put_long_host((p)->packet_data + dp_Res2, (v)); } while (0)
- #define GET_PCK_TYPE(p) ((uae_s32)(get_long_host((p)->packet_data + dp_Type)))
- #define GET_PCK_RES1(p) ((uae_s32)(get_long_host((p)->packet_data + dp_Res1)))
- #define GET_PCK_RES2(p) ((uae_s32)(get_long_host((p)->packet_data + dp_Res2)))
- #define GET_PCK_ARG1(p) ((uae_s32)(get_long_host((p)->packet_data + dp_Arg1)))
- #define GET_PCK_ARG2(p) ((uae_s32)(get_long_host((p)->packet_data + dp_Arg2)))
- #define GET_PCK_ARG3(p) ((uae_s32)(get_long_host((p)->packet_data + dp_Arg3)))
- #define GET_PCK_ARG4(p) ((uae_s32)(get_long_host((p)->packet_data + dp_Arg4)))
- #define GET_PCK_ARG5(p) ((uae_s32)(get_long_host((p)->packet_data + dp_Arg5)))
- #define PUT_PCK64_RES0(p,v) do { put_long_host((p)->packet_data + dp64_Res0, (v)); } while (0)
- #define PUT_PCK64_RES1(p,v) do { put_long_host((p)->packet_data + dp64_Res1, (((uae_u64)v) >> 32)); put_long_host((p)->packet_data + dp64_Res1 + 4, ((uae_u32)v)); } while (0)
- #define PUT_PCK64_RES2(p,v) do { put_long_host((p)->packet_data + dp64_Res2, (v)); } while (0)
- #define GET_PCK64_TYPE(p) ((uae_s32)(get_long_host((p)->packet_data + dp64_Type)))
- #define GET_PCK64_RES0(p) ((uae_s32)(get_long_host((p)->packet_data + dp64_Res0)))
- #define GET_PCK64_RES1(p) ( (((uae_s64)(get_long_host((p)->packet_data + dp64_Res1))) << 32) | (((uae_s64)(get_long_host((p)->packet_data + dp64_Res1 + 4))) << 0) )
- #define GET_PCK64_ARG1(p) ((uae_s32)(get_long_host((p)->packet_data + dp64_Arg1)))
- #define GET_PCK64_ARG2(p) ( (((uae_s64)(get_long_host((p)->packet_data + dp64_Arg2))) << 32) | (((uae_s64)(get_long_host((p)->packet_data + dp64_Arg2 + 4))) << 0) )
- #define GET_PCK64_ARG3(p) ((uae_s32)(get_long_host((p)->packet_data + dp64_Arg3)))
- #define GET_PCK64_ARG4(p) ((uae_s32)(get_long_host((p)->packet_data + dp64_Arg4)))
- #define GET_PCK64_ARG5(p) ( (((uae_s64)(get_long_host((p)->packet_data + dp64_Arg5))) << 32) | (((uae_s64)(get_long_host((p)->packet_data + dp64_Arg5 + 4))) << 0) )
- static void readdpacket(TrapContext *ctx, dpacket *packet, uaecptr pck)
- {
- // Read enough to get also all 64-bit fields
- packet->packet_addr = pck;
- if (trap_is_indirect() || !valid_address(pck, dp_Max)) {
- trap_get_bytes(ctx, packet->packet_array, pck, dp_Max);
- packet->packet_data = packet->packet_array;
- packet->need_flush = true;
- } else {
- packet->packet_data = get_real_address(pck);
- packet->need_flush = false;
- }
- }
- static void writedpacket(TrapContext *ctx, dpacket *packet)
- {
- if (!packet->need_flush)
- return;
- int type = GET_PCK_TYPE(packet);
- if (type >= 8000 && type < 9000 && GET_PCK64_RES0(packet) == DP64_INIT) {
- // 64-bit RESx fields
- trap_put_bytes(ctx, packet->packet_data + 12, packet->packet_addr + 12, 32 - 12);
- } else {
- // dp_Res1 and dp_Res2
- trap_put_bytes(ctx, packet->packet_data + 12, packet->packet_addr + 12, 20 - 12);
- }
- }
- static void set_quadp(TrapContext *ctx, uaecptr p, uae_s64 v)
- {
- if (!trap_valid_address(ctx, p, 8))
- return;
- trap_put_quad(ctx, p, v);
- }
- static uae_u64 get_quadp(TrapContext *ctx, uaecptr p)
- {
- if (!trap_valid_address(ctx, p, 8))
- return 0;
- return trap_get_quad(ctx, p);
- }
- static int flush_cache (Unit *unit, int num);
- static TCHAR *char1(TrapContext *ctx, uaecptr addr)
- {
- uae_char buf[1024];
- #if TRAPMD
- trap_get_string(ctx, (uae_u8*)buf, addr, sizeof(buf));
- #else
- unsigned int i = 0;
- do {
- buf[i] = trap_get_byte(ctx, addr);
- addr++;
- } while (buf[i++] && i < sizeof (buf));
- #endif
- return au_fs(buf);
- }
- static TCHAR *bstr1(TrapContext *ctx, uaecptr addr)
- {
- uae_char buf[257];
- int n = trap_get_byte(ctx, addr);
- addr++;
- #if TRAPMD
- trap_get_bytes(ctx, (uae_u8*)buf, addr, n);
- #else
- for (int i = 0; i < n; i++, addr++)
- buf[i] = trap_get_byte(ctx, addr);
- #endif
- buf[n] = 0;
- return au_fs(buf);
- }
- static TCHAR *bstr(TrapContext *ctx, Unit *unit, uaecptr addr)
- {
- int n = trap_get_byte(ctx, addr);
- uae_char buf[257];
- addr++;
- #if TRAPMD
- trap_get_bytes(ctx, (uae_u8*)buf, addr, n);
- #else
- for (int i = 0; i < n; i++, addr++)
- buf[i] = trap_get_byte(ctx, addr);
- #endif
- buf[n] = 0;
- au_fs_copy (unit->tmpbuf3, sizeof (unit->tmpbuf3) / sizeof (TCHAR), buf);
- return unit->tmpbuf3;
- }
- static TCHAR *cstr(TrapContext *ctx, Unit *unit, uaecptr addr)
- {
- uae_char buf[257];
- trap_get_string(ctx, buf, addr, sizeof buf);
- au_fs_copy (unit->tmpbuf3, sizeof (unit->tmpbuf3) / sizeof (TCHAR), buf);
- return unit->tmpbuf3;
- }
- static TCHAR *bstr_cut(TrapContext *ctx, Unit *unit, uaecptr addr)
- {
- TCHAR *p = unit->tmpbuf3;
- int i, colon_seen = 0, off;
- int n = trap_get_byte(ctx, addr);
- uae_char buf[257];
- off = 0;
- addr++;
- for (i = 0; i < n; i++, addr++) {
- uae_u8 c = trap_get_byte(ctx, addr);
- buf[i] = c;
- if (c == '/' || (c == ':' && colon_seen++ == 0))
- off = i + 1;
- }
- buf[i] = 0;
- au_fs_copy (unit->tmpbuf3, sizeof (unit->tmpbuf3) / sizeof (TCHAR), buf);
- return &p[off];
- }
- /* convert time_t to/from AmigaDOS time */
- static const uae_s64 msecs_per_day = 24 * 60 * 60 * 1000;
- static const uae_s64 diff = ((8 * 365 + 2) * (24 * 60 * 60)) * (uae_u64)1000;
- void timeval_to_amiga (struct mytimeval *tv, int *days, int *mins, int *ticks, int tickcount)
- {
- /* tv.tv_sec is secs since 1-1-1970 */
- /* days since 1-1-1978 */
- /* mins since midnight */
- /* ticks past minute @ 50Hz */
- uae_s64 t = tv->tv_sec * 1000 + tv->tv_usec / 1000;
- t -= diff;
- if (t < 0)
- t = 0;
- *days = t / msecs_per_day;
- t -= *days * msecs_per_day;
- *mins = t / (60 * 1000);
- t -= *mins * (60 * 1000);
- *ticks = t / (1000 / tickcount);
- }
- void amiga_to_timeval (struct mytimeval *tv, int days, int mins, int ticks, int tickcount)
- {
- uae_s64 t;
- if (days < 0)
- days = 0;
- if (days > 9900 * 365)
- days = 9900 * 365; // in future far enough?
- if (mins < 0 || mins >= 24 * 60)
- mins = 0;
- if (ticks < 0 || ticks >= 60 * tickcount)
- ticks = 0;
- t = ticks * 20;
- t += mins * (60 * 1000);
- t += ((uae_u64)days) * msecs_per_day;
- t += diff;
- tv->tv_sec = t / 1000;
- tv->tv_usec = (t % 1000) * 1000;
- }
- static Unit *units = 0;
- static Unit *find_unit (uaecptr port)
- {
- Unit* u;
- for (u = units; u; u = u->next)
- if (u->port == port)
- break;
- return u;
- }
- static struct fs_dirhandle *fs_opendir (Unit *u, a_inode *aino)
- {
- struct fs_dirhandle *fsd = xmalloc (struct fs_dirhandle, 1);
- fsd->fstype = (u->volflags & MYVOLUMEINFO_ARCHIVE) ? FS_ARCHIVE : ((u->volflags & MYVOLUMEINFO_CDFS) ? FS_CDFS : FS_DIRECTORY);
- if (fsd->fstype == FS_ARCHIVE) {
- fsd->zd = zfile_opendir_archive (aino->nname);
- if (fsd->zd)
- return fsd;
- } else if (fsd->fstype == FS_DIRECTORY) {
- fsd->od = my_opendir (aino->nname);
- if (fsd->od)
- return fsd;
- } else if (fsd->fstype == FS_CDFS) {
- fsd->isod = isofs_opendir (u->ui.cdfs_superblock, aino->uniq_external);
- if (fsd->isod)
- return fsd;
- }
- xfree (fsd);
- return NULL;
- }
- static void fs_closedir (struct fs_dirhandle *fsd)
- {
- if (!fsd)
- return;
- if (fsd->fstype == FS_ARCHIVE)
- zfile_closedir_archive (fsd->zd);
- else if (fsd->fstype == FS_DIRECTORY)
- my_closedir (fsd->od);
- else if (fsd->fstype == FS_CDFS)
- isofs_closedir (fsd->isod);
- xfree (fsd);
- }
- static struct fs_filehandle *fs_openfile (Unit *u, a_inode *aino, int flags)
- {
- struct fs_filehandle *fsf = xmalloc (struct fs_filehandle, 1);
- fsf->fstype = (u->volflags & MYVOLUMEINFO_ARCHIVE) ? FS_ARCHIVE : ((u->volflags & MYVOLUMEINFO_CDFS) ? FS_CDFS : FS_DIRECTORY);
- if (fsf->fstype == FS_ARCHIVE) {
- fsf->zf = zfile_open_archive (aino->nname, flags);
- if (fsf->zf)
- return fsf;
- } else if (fsf->fstype == FS_DIRECTORY) {
- fsf->of = my_open (aino->nname, flags);
- if (fsf->of)
- return fsf;
- } else if (fsf->fstype == FS_CDFS) {
- fsf->isof = isofs_openfile (u->ui.cdfs_superblock, aino->uniq_external, flags);
- if (fsf->isof)
- return fsf;
- }
- xfree (fsf);
- return NULL;
- }
- static void fs_closefile (struct fs_filehandle *fsf)
- {
- if (!fsf)
- return;
- if (fsf->fstype == FS_ARCHIVE) {
- zfile_close_archive (fsf->zf);
- } else if (fsf->fstype == FS_DIRECTORY) {
- my_close (fsf->of);
- } else if (fsf->fstype == FS_CDFS) {
- isofs_closefile (fsf->isof);
- }
- xfree (fsf);
- }
- static unsigned int fs_read (struct fs_filehandle *fsf, void *b, unsigned int size)
- {
- if (fsf->fstype == FS_ARCHIVE)
- return zfile_read_archive (fsf->zf, b, size);
- else if (fsf->fstype == FS_DIRECTORY)
- return my_read (fsf->of, b, size);
- else if (fsf->fstype == FS_CDFS)
- return isofs_read (fsf->isof, b, size);
- return 0;
- }
- static unsigned int fs_write (struct fs_filehandle *fsf, void *b, unsigned int size)
- {
- if (fsf->fstype == FS_DIRECTORY)
- return my_write (fsf->of, b, size);
- return 0;
- }
- /* return value = old position. -1 = error. */
- static uae_s64 fs_lseek64 (struct fs_filehandle *fsf, uae_s64 offset, int whence)
- {
- if (fsf->fstype == FS_ARCHIVE)
- return zfile_lseek_archive (fsf->zf, offset, whence);
- else if (fsf->fstype == FS_DIRECTORY)
- return my_lseek (fsf->of, offset, whence);
- else if (fsf->fstype == FS_CDFS)
- return isofs_lseek (fsf->isof, offset, whence);
- return -1;
- }
- static uae_s32 fs_lseek (struct fs_filehandle *fsf, uae_s32 offset, int whence)
- {
- uae_s64 v = fs_lseek64 (fsf, offset, whence);
- if (v < 0 || v > 0x7fffffff)
- return -1;
- return (uae_s32)v;
- }
- static uae_s64 fs_fsize64 (struct fs_filehandle *fsf)
- {
- if (fsf->fstype == FS_ARCHIVE)
- return zfile_fsize_archive (fsf->zf);
- else if (fsf->fstype == FS_DIRECTORY)
- return my_fsize (fsf->of);
- else if (fsf->fstype == FS_CDFS)
- return isofs_fsize (fsf->isof);
- return -1;
- }
- static uae_u32 fs_fsize (struct fs_filehandle *fsf)
- {
- return (uae_u32)fs_fsize64 (fsf);
- }
- static uae_s64 key_filesize(Key *k)
- {
- if (k->aino->vfso)
- return k->aino->vfso->size;
- return fs_fsize64 (k->fd);
- }
- static uae_s64 key_seek(Key *k, uae_s64 offset, int whence)
- {
- if (k->aino->vfso)
- return k->file_pos;
- return fs_lseek64 (k->fd, offset, whence);
- }
- static void set_highcyl(uaecptr volume, uae_u32 blocks)
- {
- put_long(volume + 184 - 32, blocks);
- }
- static void set_volume_name(Unit *unit, struct mytimeval *tv)
- {
- int namelen;
- int i;
- char *s;
- s = ua_fs (unit->ui.volname, -1);
- namelen = strlen (s);
- if (namelen >= 58)
- namelen = 58;
- put_byte(unit->volume + 64, namelen);
- for (i = 0; i < namelen; i++)
- put_byte(unit->volume + 64 + 1 + i, s[i]);
- put_byte(unit->volume + 64 + 1 + namelen, 0);
- if (tv && (tv->tv_sec || tv->tv_usec)) {
- int days, mins, ticks;
- timeval_to_amiga (tv, &days, &mins, &ticks, 50);
- put_long(unit->volume + 16, days);
- put_long(unit->volume + 20, mins);
- put_long(unit->volume + 24, ticks);
- }
- xfree (s);
- unit->rootnode.aname = unit->ui.volname;
- unit->rootnode.nname = unit->ui.rootdir;
- unit->rootnode.mountcount = unit->mountcount;
- }
- static int filesys_isvolume(Unit *unit)
- {
- if (!unit->volume)
- return 0;
- return get_byte(unit->volume + 64) || unit->ui.unknown_media;
- }
- static void clear_exkeys (Unit *unit)
- {
- int i;
- a_inode *a;
- for (i = 0; i < EXKEYS; i++) {
- unit->examine_keys[i].aino = 0;
- unit->examine_keys[i].curr_file = 0;
- unit->examine_keys[i].uniq = 0;
- }
- for (i = 0; i < EXALLKEYS; i++) {
- fs_closedir (unit->exalls[i].dirhandle);
- unit->exalls[i].dirhandle = NULL;
- xfree (unit->exalls[i].fn);
- unit->exalls[i].fn = NULL;
- unit->exalls[i].id = 0;
- }
- unit->exallid = 0;
- unit->next_exkey = 1;
- a = &unit->rootnode;
- while (a) {
- a->exnext_count = 0;
- if (a->locked_children) {
- a->locked_children = 0;
- unit->total_locked_ainos--;
- }
- a = a->next;
- if (a == &unit->rootnode)
- break;
- }
- }
- static void filesys_delayed_eject(Unit *u)
- {
- if (u->reinsertdelay)
- return;
- u->reinsertdelay = 50;
- u->newreadonly = false;
- xfree(u->newrootdir);
- u->newrootdir = NULL;
- write_log(_T("FILESYS: delayed eject %d\n"), u->unit);
- }
- static void filesys_delayed_change (Unit *u, int frames, const TCHAR *rootdir, const TCHAR *volume, bool readonly, int flags)
- {
- if (u->reinsertdelay)
- return;
- u->reinsertdelay = frames;
- u->newflags = flags;
- u->newreadonly = readonly;
- u->newrootdir = my_strdup (rootdir);
- if (volume)
- u->newvolume = my_strdup (volume);
- filesys_eject (u->unit);
- if (!rootdir || _tcslen (rootdir) == 0)
- u->reinsertdelay = 0;
- if (u->reinsertdelay > 0)
- write_log (_T("FILESYS: delayed insert %d: '%s' ('%s')\n"), u->unit, volume ? volume : _T("<none>"), rootdir);
- }
- int filesys_eject(int nr)
- {
- UnitInfo *ui = &mountinfo.ui[nr];
- Unit *u = ui->self;
- if (!mountertask || u->mount_changed)
- return 0;
- if (ui->open <= 0 || u == NULL)
- return 0;
- if (!is_virtual (nr))
- return 0;
- if (!filesys_isvolume(u))
- return 0;
- u->mount_changed = -1;
- u->mountcount++;
- write_log(_T("FILESYS: volume '%s' removal request\n"), u->ui.volname);
- // -1 = remove, -2 = remove + remove device node
- put_byte(u->volume + 172 - 32, ui->unit_type == UNIT_CDFS ? -1 : -2);
- uae_Signal(get_long(u->volume + 176 - 32), 1 << 13);
- return 1;
- }
- static uae_u32 heartbeat;
- static int heartbeat_count, heartbeat_count_cont;
- static int heartbeat_task;
- bool filesys_heartbeat(void)
- {
- return heartbeat_count_cont > 0;
- }
- // This uses filesystem process to reduce resource usage
- void setsystime (void)
- {
- write_log("SETSYSTIME\n");
- if (!currprefs.tod_hack || !rtarea_bank.baseaddr)
- return;
- write_log("SETSYSTIME2\n");
- heartbeat = get_long_host(rtarea_bank.baseaddr + RTAREA_HEARTBEAT);
- heartbeat_task = 1;
- heartbeat_count = 10;
- }
- static void setsystime_vblank (void)
- {
- Unit *u;
- TrapContext *ctx = NULL;
- for (u = units; u; u = u->next) {
- if (is_virtual(u->unit) && filesys_isvolume(u)) {
- put_byte(u->volume + 173 - 32, get_byte(u->volume + 173 - 32) | 1);
- uae_Signal(get_long(u->volume + 176 - 32), 1 << 13);
- break;
- }
- }
- }
- static uae_u32 REGPARAM2 debugger_helper(TrapContext *ctx)
- {
- int mode = trap_get_dreg(ctx, 1);
- switch (mode)
- {
- case 1:
- // Execute debugger_boot() to get here.
- write_log(_T("debugger #1\n"));
- // return RunCommand(() parameters
- // does nothing if D1 == 0.
- break;
- case 2:
- // called when RunCommand() returns
- // D0 = RunCommand() return code.
- write_log(_T("debugger #2\n"));
- break;
- default:
- write_log(_T("Unknown debugger hook %d\n"), mode);
- return 0;
- }
- return 1;
- }
- static void debugger_boot(void)
- {
- Unit *u;
- TrapContext *ctx = NULL;
- for (u = units; u; u = u->next) {
- if (is_virtual(u->unit) && filesys_isvolume(u)) {
- put_byte(u->volume + 173 - 32, get_byte(u->volume + 173 - 32) | 2);
- uae_Signal(get_long(u->volume + 176 - 32), 1 << 13);
- break;
- }
- }
- }
- int filesys_insert (int nr, const TCHAR *volume, const TCHAR *rootdir, bool readonly, int flags)
- {
- UnitInfo *ui;
- Unit *u;
- TrapContext *ctx = NULL;
- if (!mountertask)
- return 0;
- write_log (_T("filesys_insert(%d,'%s','%s','%d','%d)\n"), nr, volume ? volume : _T("<?>"), rootdir, readonly, flags);
- if (nr < 0) {
- for (u = units; u; u = u->next) {
- if (is_virtual (u->unit)) {
- if (!filesys_isvolume(u) && mountinfo.ui[u->unit].canremove > 0)
- break;
- }
- }
- if (!u) {
- for (u = units; u; u = u->next) {
- if (is_virtual (u->unit)) {
- if (mountinfo.ui[u->unit].canremove > 0)
- break;
- }
- }
- }
- if (!u)
- return 0;
- nr = u->unit;
- ui = &mountinfo.ui[nr];
- } else {
- ui = &mountinfo.ui[nr];
- u = ui->self;
- }
- if (ui->open <= 0 || u == NULL)
- return 0;
- if (u->reinsertdelay)
- return -1;
- if (!is_virtual(nr))
- return 0;
- if (filesys_isvolume(u)) {
- filesys_delayed_change (u, 10, rootdir, volume, readonly, flags);
- return 1 + nr;
- }
- u->mountcount++;
- u->mount_changed = 1;
- u->mount_volume = volume ? my_strdup (volume) : NULL;
- u->mount_rootdir = my_strdup (rootdir);
- u->mount_readonly = readonly;
- u->mount_flags = flags;
- write_log (_T("filesys_insert %d done!\n"), nr);
- put_byte(u->volume + 172 - 32, -3); // wait for insert
- uae_Signal (get_long(u->volume + 176 - 32), 1 << 13);
- return 100 + nr;
- }
- static uae_u32 filesys_media_change_reply (int mode)
- {
- int nr;
- UnitInfo *ui = NULL;
- Unit *u;
- for (nr = 0; nr < MAX_FILESYSTEM_UNITS; nr++) {
- ui = &mountinfo.ui[nr];
- u = ui->self;
- if (u && u->mount_changed)
- break;
- }
- if (nr >= MAX_FILESYSTEM_UNITS) {
- write_log (_T("FILESYS: filesys_media_change_reply without mount_changed flag!?\n"));
- return 0;
- }
- if (u->mount_changed < 0) {
- // eject
- if (mode == 0) {
- write_log (_T("FILESYS: got media change reply, '%s' removal finished\n"), u->ui.volname);
- flush_cache (u, -1);
- isofs_unmount (u->ui.cdfs_superblock);
- ui->cdfs_superblock = u->ui.cdfs_superblock = NULL;
- zfile_fclose_archive (ui->zarchive);
- ui->zarchive = NULL;
- u->ui.unknown_media = false;
- #ifdef RETROPLATFORM
- if (ui->unit_type == UNIT_CDFS)
- rp_cd_image_change (ui->cddevno, NULL);
- else
- rp_harddrive_image_change (nr, false, NULL);
- #endif
- } else {
- u->mount_changed = 0;
- }
- return 1;
- } else if (u->mount_changed > 0) {
- if (mode == 0) {
- // insert
- struct mytimeval ctime = { 0 };
- bool emptydrive = false;
- struct uaedev_config_data *uci = NULL;
- clear_exkeys (u);
- xfree (u->ui.rootdir);
- ui->rootdir = u->ui.rootdir = my_strdup (u->mount_rootdir);
- flush_cache (u, -1);
- xfree (u->ui.volname);
- ui->volname = u->ui.volname = NULL;
- if (ui->unit_type == UNIT_CDFS) {
- uae_u64 uniq;
- ui->cdfs_superblock = u->ui.cdfs_superblock = isofs_mount (ui->cddevno, &uniq);
- u->rootnode.uniq_external = uniq;
- u->ui.unknown_media = true;
- if (!u->ui.cdfs_superblock)
- return 0;
- struct isofs_info ii;
- set_highcyl(u->volume, 0);
- bool r = isofs_mediainfo (ui->cdfs_superblock, &ii);
- if (r && ii.media) {
- u->ui.unknown_media = ii.unknown_media;
- if (!ii.unknown_media) {
- u->ui.volname = ui->volname = my_strdup (ii.volumename);
- ctime.tv_sec = ii.creation;
- ctime.tv_usec = 0;
- set_highcyl(u->volume, ii.blocks);
- #ifdef RETROPLATFORM
- rp_cd_image_change (ui->cddevno, ii.devname);
- #endif
- }
- }
- } else {
- if (set_filesys_volume (u->mount_rootdir, &u->mount_flags, &u->mount_readonly, &emptydrive, &ui->zarchive) < 0)
- return 0;
- if (emptydrive)
- return 0;
- xfree (u->ui.volname);
- ui->volname = u->ui.volname = filesys_createvolname (u->mount_volume, u->mount_rootdir, ui->zarchive, _T("removable"));
- #ifdef RETROPLATFORM
- rp_harddrive_image_change (nr, u->mount_readonly, u->mount_rootdir);
- #endif
- uci = getuci (currprefs.mountconfig, nr);
- }
- if (u->ui.unknown_media) {
- write_log (_T("FILESYS: inserted unreadable volume NR=%d RO=%d\n"), nr, u->mount_readonly);
- } else {
- write_log (_T("FILESYS: inserted volume NR=%d RO=%d '%s' ('%s')\n"), nr, u->mount_readonly, ui->volname, u->mount_rootdir);
- set_volume_name(u, &ctime);
- if (u->mount_flags >= 0)
- ui->volflags = u->volflags = u->ui.volflags = u->mount_flags;
- if (uci != NULL) {
- _tcscpy (uci->ci.volname, ui->volname);
- _tcscpy (uci->ci.rootdir, u->mount_rootdir);
- }
- if (u->mount_flags >= 0) {
- ui->readonly = u->ui.readonly = u->mount_readonly;
- if (uci != NULL)
- uci->ci.readonly = u->mount_readonly;
- }
- put_byte(u->volume + 64, 0);
- put_byte(u->volume + 172 - 32, 1);
- }
-
- xfree (u->mount_volume);
- xfree (u->mount_rootdir);
- u->mount_rootdir = NULL;
- u->mount_volume = NULL;
- } else {
- u->mount_changed = 0;
- }
-
- return 1;
- }
- return 0;
- }
- // if multiple drag&drop mounting, queue them because mounting is async (needs Amiga-side code to run).
- static int media_queued_total;
- static int media_queued_cnt;
- static TCHAR **media_queued_paths;
- int filesys_media_change_queue(const TCHAR *rootdir, int total)
- {
- if (total < 0) {
- media_queued_cnt = 0;
- for (int i = 0; i < media_queued_total; i++) {
- xfree(media_queued_paths[i]);
- }
- xfree(media_queued_paths);
- media_queued_cnt = 0;
- media_queued_total = 0;
- media_queued_paths = NULL;
- return 0;
- }
- if (total == 0) {
- media_queued_cnt = 0;
- return 0;
- }
- if (media_queued_total < total) {
- media_queued_total = total;
- media_queued_paths = xcalloc(TCHAR*, media_queued_total);
- media_queued_cnt = 0;
- }
- media_queued_paths[media_queued_cnt++] = my_strdup(rootdir);
- return 1;
- }
- int filesys_media_change (const TCHAR *rootdir, int inserted, struct uaedev_config_data *uci)
- {
- Unit *u;
- UnitInfo *ui;
- int nr = -1;
- TCHAR volname[MAX_DPATH], *volptr;
- TCHAR devname[MAX_DPATH];
- TrapContext *ctx = NULL;
- if (!mountertask)
- return 0;
- if (automountunit >= 0)
- return -1;
-
- write_log (_T("filesys_media_change('%s',%d,%p)\n"), rootdir, inserted, uci);
-
- nr = -1;
- for (u = units; u; u = u->next) {
- if (is_virtual (u->unit)) {
- ui = &mountinfo.ui[u->unit];
- // inserted >= 2: drag&drop insert, do not replace existing normal drives
- if (inserted < 2 && ui->rootdir && !memcmp (ui->rootdir, rootdir, _tcslen (rootdir)) && _tcslen (rootdir) + 3 >= _tcslen (ui->rootdir)) {
- if (filesys_isvolume(u) && inserted) {
- if (uci)ctx,
- filesys_delayed_change (u, 50, rootdir, uci->ci.volname, uci->ci.readonly, 0);
- return 0;
- }
- nr = u->unit;
- break;
- }
- }
- }
- ui = NULL;
- if (nr >= 0)
- ui = &mountinfo.ui[nr];
- /* only configured drives have automount support if automount is disabled */
- if (!currprefs.win32_automount_removable && (!ui || !ui->configureddrive) && (inserted == 0 || inserted == 1))
- return 0;
- if (nr < 0 && !inserted)
- return 0;
- /* already mounted volume was ejected? */
- if (nr >= 0 && !inserted)
- return filesys_eject (nr);
- if (inserted) {
- struct uaedev_config_info ci = { 0 };
- if (uci) {
- volptr = my_strdup (uci->ci.volname);
- } else {
- struct uaedev_config_info ci2 = { 0 };
- _tcscpy(ci2.rootdir, rootdir);
- target_get_volume_name (&mountinfo, &ci2, 1, 0, -1);
- _tcscpy(volname, ci2.volname);
- volptr = volname;
- if (!volname[0])
- volptr = NULL;
- if (ui && ui->configureddrive && ui->volname) {
- volptr = volname;
- _tcscpy (volptr, ui->volname);
- }
- }
- if (!volptr) {
- volptr = filesys_createvolname (NULL, rootdir, NULL, _T("removable"));
- _tcscpy (volname, volptr);
- xfree (volptr);
- volptr = volname;
- }
- /* new volume inserted and it was previously mounted? */
- if (nr >= 0) {
- if (!filesys_isvolume(u)) /* not going to mount twice */
- return filesys_insert(nr, volptr, rootdir, false, -1);
- return 0;
- }
- if (inserted < 0) /* -1 = only mount if already exists */
- return 0;
- /* new volume inserted and it was not previously mounted?
- * perhaps we have some empty device slots? */
- nr = filesys_insert (-1, volptr, rootdir, 0, 0);
- if (nr >= 100) {
- if (uci)
- uci->configoffset = nr - 100;
- if (inserted == 3 && mountinfo.ui[nr - 100].canremove > 0)
- mountinfo.ui[nr - 100].canremove = -1;
- return nr;
- } else if (nr > 0) {
- if (inserted == 3 && mountinfo.ui[nr - 1].canremove > 0)
- mountinfo.ui[nr - 1].canremove = -1;
- return nr;
- }
- /* nope, uh, need black magic now.. */
- if (uci)
- _tcscpy (devname, uci->ci.devname);
- else
- _stprintf (devname, _T("RDH%d"), autocreatedunit++);
- _tcscpy (ci.devname, devname);
- _tcscpy (ci.volname, volptr);
- _tcscpy (ci.rootdir, rootdir);
- ci.flags = MYVOLUMEINFO_REUSABLE;
- nr = add_filesys_unit (&ci, true);
- if (nr < 0)
- return 0;
- if (inserted == 2)
- mountinfo.ui[nr].canremove = 1;
- if (inserted == 3)
- mountinfo.ui[nr].canremove = -1;
- automountunit = nr;
- uae_Signal (mountertask, 1 << 13);
- /* poof */
- if (uci)
- uci->configoffset = nr;
- return 100 + nr;
- }
- return 0;
- }
- int hardfile_media_change (struct hardfiledata *hfd, struct uaedev_config_info *ci, bool inserted, bool timer)
- {
- if (!hfd)
- return 0;
- if (!timer)
- hfd->reinsertdelay = 0;
- if (hfd->reinsertdelay < 0) {
- hfd->reinsertdelay = 0;
- if (!hfd->isreinsert) {
- hdf_close (hfd);
- hardfile_send_disk_change (hfd, false);
- if (hfd->delayedci.rootdir[0]) {
- hfd->reinsertdelay = 50;
- hfd->isreinsert = true;
- write_log (_T("HARDFILE: delayed insert %d: '%s'\n"), hfd->unitnum, ci->rootdir[0] ? ci->rootdir : _T("<none>"));
- return 0;
- } else {
- return 1;
- }
- }
- memcpy (&hfd->ci, &hfd->delayedci, sizeof (struct uaedev_config_info));
- if (hdf_open (hfd) <= 0) {
- write_log (_T("HARDFILE: '%s' failed to open\n"), hfd->ci.rootdir);
- return 0;
- }
- hardfile_send_disk_change (hfd, true);
- return 1;
- }
- if (ci) {
- memcpy (&hfd->delayedci, ci, sizeof (struct uaedev_config_info));
- if (hfd && !hfd->drive_empty) {
- hfd->reinsertdelay = 50;
- hfd->isreinsert = false;
- write_log (_T("HARDFILE: delayed eject %d: '%s'\n"), hfd->unitnum, hfd->ci.rootdir[0] ? hfd->ci.rootdir : _T("<none>"));
- return 0;
- }
- if (!hfd) {
- return 0;
- }
- hfd->reinsertdelay = 2;
- hfd->isreinsert = true;
- } else {
- if (inserted) {
- hfd->reinsertdelay = 2;
- hfd->isreinsert = true;
- memcpy (&hfd->delayedci, &hfd->ci, sizeof (struct uaedev_config_info));
- } else {
- hfd->reinsertdelay = 2;
- hfd->isreinsert = false;
- memcpy (&hfd->delayedci, &hfd->ci, sizeof (struct uaedev_config_info));
- hfd->delayedci.rootdir[0] = 0;
- }
- }
- return 0;
- }
- #if 0
- int hardfile_remount (int nr)
- {
- /* this does work but every media reinsert duplicates the device.. */
- #if 0
- if (!mountertask)
- return 0;
- automountunit = nr;
- uae_Signal (mountertask, 1 << 13);
- #endif
- return 1;
- }
- #endif
- bool filesys_do_disk_change (int cdunitnum, bool insert)
- {
- int nr = cdunitnum + cd_unit_offset;
- UnitInfo *ui = &mountinfo.ui[nr];
- Unit *u = ui->self;
- TrapContext *ctx = NULL;
- if (!ui->cd_open)
- return false;
- if (insert) {
- if (filesys_isvolume(u))
- return false;
- filesys_insert (nr, NULL, _T("/"), true, MYVOLUMEINFO_CDFS | MYVOLUMEINFO_READONLY);
- return true;
- } else {
- if (!filesys_isvolume(u))
- return false;
- filesys_eject (nr);
- return true;
- }
- }
- /* flags and comments supported? */
- static int fsdb_cando (Unit *unit)
- {
- if (unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS))
- return 1;
- if (currprefs.filesys_custom_uaefsdb && (unit->volflags & MYVOLUMEINFO_STREAMS))
- return 1;
- if (!currprefs.filesys_no_uaefsdb)
- return 1;
- return 0;
- }
- static void prepare_for_open (TCHAR *name)
- {
- }
- static void de_recycle_aino (Unit *unit, a_inode *aino)
- {
- aino_test (aino);
- if (aino->next == 0 || aino == &unit->rootnode)
- return;
- aino->next->prev = aino->prev;
- aino->prev->next = aino->next;
- aino->next = aino->prev = 0;
- unit->aino_cache_size--;
- }
- 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 (unit->volflags & MYVOLUMEINFO_ARCHIVE) {
- ;
- } else if (unit->volflags & MYVOLUMEINFO_CDFS) {
- isofs_dispose_inode (unit->ui.cdfs_superblock, aino->uniq_external);
- }
- xfree (aino->aname);
- xfree (aino->comment);
- xfree (aino->nname);
- xfree (aino);
- }
- 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);
- }
- }
- static int flush_cache (Unit *unit, int num)
- {
- int i = 0;
- int cnt = 100;
- //write_log (_T("FILESYS: flushing cache unit %d (max %d items)\n"), unit->unit, num);
- if (num == 0)
- num = -1;
- while (i < num || num < 0) {
- int ii = i;
- a_inode *parent = unit->rootnode.prev->parent;
- a_inode **aip;
- aip = &parent->child;
- aino_test (parent);
- if (parent && !parent->locked_children) {
- for (;;) {
- a_inode *aino = *aip;
- aino_test (aino);
- 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 (_T("panic: freeing locked a_inode!\n"));
- de_recycle_aino (unit, aino);
- dispose_aino (unit, aip, aino);
- i++;
- }
- }
- }
- { //if (unit->rootnode.next != unit->rootnode.prev) {
- /* 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.
- (infinite loop if there is only one parent?)
- */
- int maxloop = 10000;
- 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 && maxloop-- > 0);
- }
- if (i == ii)
- cnt--;
- if (cnt <= 0)
- break;
- }
- return unit->aino_cache_size > 0 ? 0 : 1;
- }
- static void recycle_aino (Unit *unit, a_inode *new_aino)
- {
- aino_test (new_aino);
- if (new_aino->dir || new_aino->shlock > 0
- || new_aino->elock || new_aino == &unit->rootnode)
- /* Still in use */
- return;
- TRACE3((_T("Recycling; cache size %u, total_locked %d\n"),
- unit->aino_cache_size, unit->total_locked_ainos));
- if (unit->aino_cache_size > 5000 + unit->total_locked_ainos) {
- /* Reap a few. */
- flush_cache (unit, 50);
- #if 0
- {
- TCHAR buffer[40];
- _stprintf (buffer, "%d ainos reaped.\n", i);
- TRACE ((buffer));
- }
- #endif
- }
- aino_test (new_aino);
- /* 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;
- aino_test (new_aino->next);
- aino_test (new_aino->prev);
- unit->aino_cache_size++;
- }
- void filesys_flush_cache (void)
- {
- }
- static void update_child_names (Unit *unit, a_inode *a, a_inode *parent)
- {
- int l0 = _tcslen (parent->nname) + 2;
- while (a != 0) {
- TCHAR *name_start;
- TCHAR *new_name;
- TCHAR dirsep[2] = { FSDB_DIR_SEPARATOR, '\0' };
- a->parent = parent;
- name_start = _tcsrchr (a->nname, FSDB_DIR_SEPARATOR);
- if (name_start == 0) {
- write_log (_T("malformed file name"));
- }
- name_start++;
- new_name = xmalloc (TCHAR, _tcslen (name_start) + l0);
- _tcscpy (new_name, parent->nname);
- _tcscat (new_name, dirsep);
- _tcscat (new_name, name_start);
- xfree (a->nname);
- a->nname = new_name;
- if (a->child)
- update_child_names (unit, a->child, a);
- a = a->sibling;
- }
- }
- static void move_aino_children (Unit *unit, a_inode *from, a_inode *to)
- {
- aino_test (from);
- aino_test (to);
- to->child = from->child;
- from->child = 0;
- update_child_names (unit, to->child, to);
- }
- static void delete_aino (Unit *unit, a_inode *aino)
- {
- a_inode **aip;
- TRACE((_T("deleting aino %x\n"), aino->uniq));
- aino_test (aino);
- 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((_T("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((_T("Same parent found for %d\n"), i));
- if (k->curr_file == aino) {
- k->curr_file = aino->sibling;
- TRACE((_T("Advancing curr_file\n")));
- }
- }
- }
- }
- aip = &aino->parent->child;
- while (*aip != aino && *aip != 0)
- aip = &(*aip)->sibling;
- if (*aip != aino) {
- write_log (_T("Couldn't delete aino.\n"));
- return;
- }
- dispose_aino (unit, aip, aino);
- }
- static a_inode *lookup_sub (a_inode *dir, uae_u32 uniq)
- {
- a_inode **cp = &dir->child;
- a_inode *c, *retval;
- for (;;) {
- c = *cp;
- if (c == 0)
- return 0;
- if (c->uniq == uniq) {
- retval = c;
- break;
- }
- if (c->dir) {
- a_inode *a = lookup_sub (c, uniq);
- if (a != 0) {
- retval = a;
- break;
- }
- }
- cp = &c->sibling;
- }
- 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 a_inode *lookup_aino (Unit *unit, uae_u32 uniq)
- {
- a_inode *a;
- int hash = uniq % MAX_AINO_HASH;
- if (uniq == 0)
- return &unit->rootnode;
- a = unit->aino_hash[hash];
- if (a == 0 || a->uniq != uniq)
- a = lookup_sub (&unit->rootnode, uniq);
- else
- unit->nr_cache_hits++;
- unit->nr_cache_lookups++;
- unit->aino_hash[hash] = a;
- aino_test (a);
- return a;
- }
- static a_inode *aino_from_lock(TrapContext *ctx, Unit *unit, uaecptr lock)
- {
- return lookup_aino (unit, trap_get_long(ctx, lock + 4));
- }
- TCHAR *build_nname (const TCHAR *d, const TCHAR *n)
- {
- TCHAR dsep[2] = { FSDB_DIR_SEPARATOR, 0 };
- TCHAR *p = xmalloc (TCHAR, _tcslen (d) + 1 + _tcslen (n) + 1);
- _tcscpy (p, d);
- _tcscat (p, dsep);
- _tcscat (p, n);
- return p;
- }
- TCHAR *build_aname (const TCHAR *d, const TCHAR *n)
- {
- TCHAR *p = xmalloc (TCHAR, _tcslen (d) + 1 + _tcslen (n) + 1);
- _tcscpy (p, d);
- _tcscat (p, _T("/"));
- _tcscat (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 TCHAR *get_nname (Unit *unit, a_inode *base, TCHAR *rel, TCHAR **modified_rel, uae_u64 *uniq_ext)
- {
- TCHAR *found;
- *modified_rel = 0;
- if (unit->volflags & MYVOLUMEINFO_ARCHIVE) {
- if (zfile_exists_archive (base->nname, rel))
- return build_nname (base->nname, rel);
- return NULL;
- } else if (unit->volflags & MYVOLUMEINFO_CDFS) {
- if (isofs_exists (unit->ui.cdfs_superblock, base->uniq_external, rel, uniq_ext))
- return build_nname (base->nname, rel);
- return NULL;
- }
- aino_test (base);
- /* 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_dir (base, 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 TCHAR *create_nname (Unit *unit, a_inode *base, TCHAR *rel)
- {
- TCHAR *p;
- aino_test (base);
- /* 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 (base, rel) || fsdb_used_as_nname (base, rel)) {
- #if 0
- oh_dear:
- #endif
- if (currprefs.filesys_no_uaefsdb && !(base->volflags & MYVOLUMEINFO_STREAMS)) {
- write_log (_T("illegal filename '%s', no stream supporting filesystem and uaefsdb disabled\n"), rel);
- return 0;
- }
- p = fsdb_create_unique_nname (base, rel);
- return p;
- }
- p = build_nname (base->nname, rel);
- #if 0
- /* Delete this code once we know everything works. */
- if (access (p, R_OK) >= 0 || errno != ENOENT) {
- write_log (_T("Filesystem in trouble... please report.\n"));
- xfree (p);
- goto oh_dear;
- }
- #endif
- return p;
- }
- static int fill_file_attrs (Unit *u, a_inode *base, a_inode *c)
- {
- if (u->volflags & MYVOLUMEINFO_ARCHIVE) {
- int isdir, flags;
- TCHAR *comment;
- zfile_fill_file_attrs_archive (c->nname, &isdir, &flags, &comment);
- c->dir = isdir;
- c->amigaos_mode = 0;
- if (flags >= 0)
- c->amigaos_mode = flags;
- c->comment = comment;
- return 1;
- } else if (u->volflags & MYVOLUMEINFO_CDFS) {
- int isdir, flags;
- TCHAR *comment;
- isofss_fill_file_attrs (u->ui.cdfs_superblock, base->uniq_external, &isdir, &flags, &comment, c->uniq_external);
- c->dir = isdir;
- c->amigaos_mode = 0;
- if (flags >= 0)
- c->amigaos_mode = flags;
- c->comment = comment;
- return 1;
- } else {
- return fsdb_fill_file_attrs (base, c);
- }
- return 0;
- }
- static int test_softlink (a_inode *aino)
- {
- int err;
- if (aino->softlink && my_resolvesoftlink (aino->nname, -1, false))
- err = ERROR_IS_SOFT_LINK;
- else
- err = ERROR_OBJECT_NOT_AROUND;
- return err;
- }
- static void handle_softlink(TrapContext *ctx, Unit *unit, dpacket *packet, a_inode *aino)
- {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, test_softlink (aino));
- }
- /*
- * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object
- * for which we know the name on the native filesystem, but no corresponding
- * Amiga filesystem name.
- * @@@ For DOS filesystems, it might make sense to declare the new name
- * "weak", so that it can get overriden by a subsequent call to get_nname().
- * That way, if someone does "dir :" and there is a file "foobar.inf", and
- * someone else tries to open "foobar.info", get_nname() could maybe made to
- * figure out that this is supposed to be the file "foobar.inf".
- * DOS sucks...
- */
- static TCHAR *get_aname (Unit *unit, a_inode *base, TCHAR *rel)
- {
- return my_strdup (rel);
- }
- static void init_child_aino_tree (Unit *unit, a_inode *base, a_inode *aino)
- {
- /* Update tree structure */
- aino->parent = base;
- aino->child = 0;
- aino->sibling = base->child;
- base->child = aino;
- aino->next = aino->prev = 0;
- aino->volflags = unit->volflags;
- }
- static void init_child_aino (Unit *unit, a_inode *base, a_inode *aino)
- {
- aino->uniq = ++a_uniq;
- if (a_uniq == 0xFFFFFFFF) {
- write_log (_T("Running out of a_inodes (prepare for big trouble)!\n"));
- }
- aino->shlock = 0;
- aino->elock = 0;
- aino->dirty = 0;
- aino->deleted = 0;
- aino->mountcount = unit->mountcount;
- /* 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++;
- }
- init_child_aino_tree (unit, base, aino);
- aino_test_init (aino);
- aino_test (aino);
- }
- static a_inode *new_child_aino (Unit *unit, a_inode *base, TCHAR *rel)
- {
- TCHAR *modified_rel;
- TCHAR *nn;
- a_inode *aino = NULL;
- int isvirtual = unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS);
- TRACE((_T("new_child_aino %s, %s\n"), base->aname, rel));
- if (!isvirtual)
- aino = fsdb_lookup_aino_aname (base, rel);
- if (aino == 0) {
- uae_u64 uniq_ext = 0;
- nn = get_nname (unit, base, rel, &modified_rel, &uniq_ext);
- if (nn == 0)
- return 0;
- aino = xcalloc (a_inode, 1);
- if (aino == 0)
- return 0;
- aino->uniq_external = uniq_ext;
- aino->aname = modified_rel ? modified_rel : my_strdup (rel);
- aino->nname = nn;
- aino->comment = 0;
- aino->has_dbentry = 0;
- if (!fill_file_attrs (unit, base, aino)) {
- xfree (aino);
- return 0;
- }
- if (aino->dir && !isvirtual)
- fsdb_clean_dir (aino);
- }
- init_child_aino (unit, base, aino);
- recycle_aino (unit, aino);
- TRACE((_T("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, TCHAR *rel, int isdir)
- {
- a_inode *aino = xcalloc (a_inode, 1);
- if (aino == 0)
- return 0;
- aino->nname = create_nname (unit, base, rel);
- if (!aino->nname) {
- free (aino);
- return 0;
- }
- aino->aname = my_strdup (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((_T("created aino %x, create\n"), aino->uniq));
- return aino;
- }
- static a_inode *lookup_child_aino (Unit *unit, a_inode *base, TCHAR *rel, int *err)
- {
- a_inode *c = base->child;
- int l0 = _tcslen (rel);
- aino_test (base);
- aino_test (c);
- if (base->dir == 0) {
- *err = ERROR_OBJECT_WRONG_TYPE;
- return 0;
- }
- while (c != 0) {
- int l1 = _tcslen (c->aname);
- if (l0 <= l1 && same_aname (rel, c->aname + l1 - l0)
- && (l0 == l1 || c->aname[l1-l0-1] == '/') && c->mountcount == unit->mountcount)
- break;
- c = c->sibling;
- }
- if (c != 0)
- return c;
- c = new_child_aino (unit, base, rel);
- if (c == 0)
- *err = ERROR_OBJECT_NOT_AROUND;
- return c;
- }
- /* Different version because for this one, REL is an nname. */
- static a_inode *lookup_child_aino_for_exnext (Unit *unit, a_inode *base, TCHAR *rel, uae_u32 *err, uae_u64 uniq_external, struct virtualfilesysobject *vfso)
- {
- a_inode *c = base->child;
- int l0 = _tcslen (rel);
- int isvirtual = unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS);
- aino_test (base);
- aino_test (c);
- *err = 0;
- while (c != 0) {
- int l1 = _tcslen (c->nname);
- /* Note: using _tcscmp here. */
- if (l0 <= l1 && _tcscmp (rel, c->nname + l1 - l0) == 0
- && (l0 == l1 || c->nname[l1-l0-1] == FSDB_DIR_SEPARATOR) && c->mountcount == unit->mountcount)
- break;
- c = c->sibling;
- }
- if (c != 0)
- return c;
- if (!isvirtual && !vfso)
- c = fsdb_lookup_aino_nname (base, rel);
- if (c == 0) {
- c = xcalloc (a_inode, 1);
- 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->comment = 0;
- c->uniq_external = uniq_external;
- c->has_dbentry = 0;
- if (vfso) {
- c->dir = vfso->dir;
- c->comment = my_strdup(vfso->comment);
- c->amigaos_mode = vfso->amigaos_mode;
- c->vfso = vfso;
- } else if (!fill_file_attrs (unit, base, c)) {
- xfree (c);
- *err = ERROR_NO_FREE_STORE;
- return 0;
- }
- if (c->dir && !isvirtual && !vfso)
- fsdb_clean_dir (c);
- }
- init_child_aino (unit, base, c);
- recycle_aino (unit, c);
- TRACE((_T("created aino %s:%d, exnext\n"), c->nname, c->uniq));
- return c;
- }
- static a_inode *get_aino (Unit *unit, a_inode *base, const TCHAR *rel, int *err)
- {
- TCHAR *tmp;
- TCHAR *p;
- a_inode *curr, *prev;
- int i;
- aino_test (base);
- *err = 0;
- TRACE((_T("get_path(%s,%s)\n"), base->aname, rel));
- /* root-relative path? */
- for (i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++)
- ;
- if (':' == rel[i])
- rel += i+1;
- tmp = my_strdup (rel);
- p = tmp;
- curr = base;
- prev = NULL;
- while (*p) {
- /* start with a slash? go up a level. */
- if (*p == '/') {
- if (curr->parent != 0)
- curr = curr->parent;
- p++;
- } else {
- a_inode *next;
- if (prev && prev->softlink) {
- *err = test_softlink (prev);
- curr = NULL;
- break;
- }
- TCHAR *component_end;
- component_end = _tcschr (p, '/');
- if (component_end != 0)
- *component_end = '\0';
- 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_AROUND || component_end != 0)
- curr = NULL;
- /* ? what error is appropriate? */
- break;
- }
- prev = next;
- curr = next;
- if (component_end)
- p = component_end+1;
- else
- break;
- }
- }
- xfree (tmp);
- return curr;
- }
- static uae_u32 notifyhash (const TCHAR *s)
- {
- uae_u32 hash = 0;
- while (*s)
- hash = (hash << 5) + *s++;
- return hash % NOTIFY_HASH_SIZE;
- }
- static Notify *new_notify (Unit *unit, TCHAR *name)
- {
- Notify *n = xmalloc (Notify, 1);
- uae_u32 hash = notifyhash (name);
- n->next = unit->notifyhash[hash];
- unit->notifyhash[hash] = n;
- n->partname = name;
- return n;
- }
- #if 0
- static void free_notify_item (Notify *n)
- {
- xfree (n->fullname);
- xfree (n->partname);
- xfree (n);
- }
- #endif
- static void free_notify (Unit *unit, int hash, Notify *n)
- {
- Notify *n1, *prev = 0;
- for (n1 = unit->notifyhash[hash]; n1; n1 = n1->next) {
- if (n == n1) {
- if (prev)
- prev->next = n->next;
- else
- unit->notifyhash[hash] = n->next;
- break;
- }
- prev = n1;
- }
- }
- static void startup_update_unit (Unit *unit, UnitInfo *uinfo)
- {
- if (!unit)
- return;
- xfree (unit->ui.volname);
- memcpy (&unit->ui, uinfo, sizeof (UnitInfo));
- unit->ui.devname = uinfo->devname;
- unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */
- }
- static Unit *startup_create_unit(TrapContext *ctx, UnitInfo *uinfo, int num)
- {
- int i;
- Unit *unit, *u;
- unit = xcalloc (Unit, 1);
- /* keep list in insertion order */
- u = units;
- if (u) {
- while (u->next)
- u = u->next;
- u->next = unit;
- } else {
- units = unit;
- }
- uinfo->self = unit;
- unit->volume = 0;
- unit->port = trap_get_areg(ctx, 5);
- unit->unit = num;
- startup_update_unit (unit, uinfo);
- unit->cmds_complete = 0;
- unit->cmds_sent = 0;
- unit->cmds_acked = 0;
- clear_exkeys (unit);
- unit->total_locked_ainos = 0;
- unit->keys = 0;
- for (i = 0; i < NOTIFY_HASH_SIZE; i++) {
- Notify *n = unit->notifyhash[i];
- while (n) {
- Notify *n2 = n;
- n = n->next;
- xfree (n2->fullname);
- xfree (n2->partname);
- xfree (n2);
- }
- unit->notifyhash[i] = 0;
- }
- unit->rootnode.aname = uinfo->volname;
- unit->rootnode.nname = uinfo->rootdir;
- unit->rootnode.sibling = 0;
- unit->rootnode.next = unit->rootnode.prev = &unit->rootnode;
- unit->rootnode.uniq = 0;
- unit->rootnode.parent = 0;
- unit->rootnode.child = 0;
- unit->rootnode.dir = 1;
- unit->rootnode.amigaos_mode = 0;
- unit->rootnode.shlock = 0;
- unit->rootnode.elock = 0;
- unit->rootnode.comment = 0;
- unit->rootnode.has_dbentry = 0;
- unit->rootnode.volflags = uinfo->volflags;
- aino_test_init (&unit->rootnode);
- unit->aino_cache_size = 0;
- for (i = 0; i < MAX_AINO_HASH; i++)
- unit->aino_hash[i] = 0;
- return unit;
- }
- static bool mount_cd(UnitInfo *uinfo, int nr, struct mytimeval *ctime, uae_u64 *uniq, uaecptr volume)
- {
- uinfo->cddevno = nr - cd_unit_offset;
- if (!sys_command_open (uinfo->cddevno)) {
- write_log (_T("Failed attempt to open CD unit %d\n"), uinfo->cddevno);
- return false;
- }
- #ifdef RETROPLATFORM
- rp_cd_device_enable (uinfo->cddevno, true);
- #endif
- uinfo->cdfs_superblock = isofs_mount(uinfo->cddevno, uniq);
- uinfo->wasisempty = true;
- struct isofs_info ii;
- if (isofs_mediainfo (uinfo->cdfs_superblock, &ii)) {
- xfree (uinfo->volname);
- if (ii.media) {
- uinfo->wasisempty = false;
- if (!ii.unknown_media) {
- uinfo->volname = my_strdup (ii.volumename);
- if (ctime) {
- ctime->tv_sec = ii.creation;
- ctime->tv_usec = 0;
- }
- set_highcyl(volume, ii.totalblocks);
- #ifdef RETROPLATFORM
- rp_cd_image_change (uinfo->cddevno, ii.devname);
- #endif
- }
- }
- uinfo->unknown_media = ii.unknown_media;
- }
- uinfo->cd_open = true;
- return true;
- }
- #ifdef UAE_FILESYS_THREADS
- static void filesys_thread (void *unit_v);
- #endif
- static void filesys_start_thread (UnitInfo *ui, int nr)
- {
- ui->unit_pipe = 0;
- ui->back_pipe = 0;
- ui->reset_state = FS_STARTUP;
- if (!isrestore ()) {
- ui->startup = 0;
- ui->self = 0;
- }
- #ifdef UAE_FILESYS_THREADS
- if (is_virtual (nr)) {
- ui->unit_pipe = xmalloc (smp_comm_pipe, 1);
- ui->back_pipe = xmalloc (smp_comm_pipe, 1);
- init_comm_pipe (ui->unit_pipe, 400, 3);
- init_comm_pipe (ui->back_pipe, 100, 1);
- uae_start_thread (_T("filesys"), filesys_thread, (void *)ui, &ui->tid);
- }
- #endif
- if (isrestore ()) {
- if (ui->unit_type == UNIT_CDFS) {
- mount_cd(ui, nr, NULL, &ui->self->rootnode.uniq_external, ui->self->volume);
- }
- startup_update_unit (ui->self, ui);
- }
- }
- static uae_u32 REGPARAM2 startup_handler(TrapContext *ctx)
- {
- uae_u32 mode = trap_get_dreg(ctx, 0);
- if (mode == 1) {
- uaecptr addr = 0;
- if (currprefs.uaeboard > 1) {
- // return board ram instead of allocating normal RAM
- addr = uaeboard_alloc_ram(trap_get_dreg(ctx, 1));
- }
- return addr;
- }
- /* Just got the startup packet. It's in D3. DosBase is in A2,
- * our allocated volume structure is in A3, A5 is a pointer to
- * our port. */
- uaecptr rootnode = trap_get_long(ctx, trap_get_areg(ctx, 2) + 34);
- uaecptr dos_info = trap_get_long(ctx, rootnode + 24) << 2;
- uaecptr pkt = trap_get_dreg(ctx, 3);
- uaecptr arg1 = trap_get_long(ctx, pkt + dp_Arg1);
- uaecptr arg2 = trap_get_long(ctx, pkt + dp_Arg2);
- uaecptr arg3 = trap_get_long(ctx, pkt + dp_Arg3);
- uaecptr devnode, volume;
- int nr;
- Unit *unit;
- UnitInfo *uinfo;
- int late = 0;
- int ed, ef;
- uae_u64 uniq = 0;
- uae_u32 cdays;
- struct mytimeval ctime = { 0 };
- // 1.3:
- // dp_Arg1 contains crap (Should be name of device)
- // dp_Arg2 = works as documented
- // dp_Arg3 = NULL (!?). (Should be DeviceNode)
- for (nr = 0; nr < MAX_FILESYSTEM_UNITS; nr++) {
- /* Hardfile volume name? */
- if (mountinfo.ui[nr].open <= 0)
- continue;
- if (!is_virtual (nr))
- continue;
- if (mountinfo.ui[nr].startup == arg2)
- break;
- }
- if (nr == MAX_FILESYSTEM_UNITS) {
- write_log (_T("Attempt to mount unknown filesystem device\n"));
- trap_put_long(ctx, pkt + dp_Res1, DOS_FALSE);
- trap_put_long(ctx, pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
- return 0;
- }
- uinfo = mountinfo.ui + nr;
- //devnode = arg3 << 2;
- devnode = uinfo->devicenode;
- volume = trap_get_areg(ctx, 3) + 32;
- cdays = 3800 + nr;
- if (uinfo->unit_type == UNIT_CDFS) {
- ed = ef = 0;
- if (!mount_cd(uinfo, nr, &ctime, &uniq, volume)) {
- trap_put_long(ctx, pkt + dp_Res1, DOS_FALSE);
- trap_put_long(ctx, pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
- return 0;
- }
- } else {
- ed = my_existsdir (uinfo->rootdir);
- ef = my_existsfile (uinfo->rootdir);
- if (!uinfo->wasisempty && !ef && !ed) {
- write_log (_T("Failed attempt to mount device '%s' (%s)\n"), uinfo->devname, uinfo->rootdir);
- trap_put_long(ctx, pkt + dp_Res1, DOS_FALSE);
- trap_put_long(ctx, pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
- return 0;
- }
- }
- if (!uinfo->unit_pipe) {
- late = 1;
- filesys_start_thread(uinfo, nr);
- }
- unit = startup_create_unit(ctx, uinfo, nr);
- unit->volflags = uinfo->volflags;
- unit->rootnode.uniq_external = uniq;
- /* write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/
- write_log (_T("FS: %s (flags=%08X,E=%d,ED=%d,EF=%d,native='%s') starting..\n"),
- unit->ui.volname, unit->volflags, uinfo->wasisempty, ed, ef, unit->ui.rootdir);
- /* fill in our process in the device node */
- trap_put_long(ctx, devnode + 8, unit->port);
- unit->dosbase = trap_get_areg(ctx, 2);
- /* make new volume */
- unit->volume = volume;
- put_long(unit->volume + 180 - 32, devnode);
- #ifdef UAE_FILESYS_THREADS
- unit->locklist = trap_get_areg(ctx, 3) + 8;
- #else
- unit->locklist = trap_get_areg(ctx, 3);
- #endif
- unit->dummy_message = trap_get_areg(ctx, 3) + 12;
- trap_put_long(ctx, unit->dummy_message + 10, 0);
- /* Prepare volume information */
- put_long(unit->volume + 4, 2); /* Type = dt_volume */
- put_long(unit->volume + 12, 0); /* Lock */
- put_long(unit->volume + 16, cdays); /* Creation Date */
- put_long(unit->volume + 20, 0);
- put_long(unit->volume + 24, 0);
- put_long(unit->volume + 28, 0); /* lock list */
- put_long(unit->volume + 40, (unit->volume + 64) >> 2); /* Name */
- //put_long(unit->volume + 44, 68);
- //put_long(unit->volume + 48, 68);
- put_byte(unit->volume + 64, 0);
- if (!uinfo->wasisempty && !uinfo->unknown_media) {
- int isvirtual = unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS);
- /* Set volume if non-empty */
- set_volume_name(unit, &ctime);
- if (!isvirtual)
- fsdb_clean_dir (&unit->rootnode);
- }
- put_long(unit->volume + 8, unit->port);
- /* not FFS because it is not understood by WB1.x C:Info */
- put_long(unit->volume + 32, DISK_TYPE_DOS);
- trap_put_long(ctx, pkt + dp_Res1, DOS_TRUE);
- return 1 | (late ? 2 : 0);
- }
- static bool is_writeprotected(Unit *unit)
- {
- return unit->ui.readonly || unit->ui.locked || currprefs.harddrive_read_only;
- }
- static void do_info(TrapContext *ctx, Unit *unit, dpacket *packet, uaecptr info, bool disk_info)
- {
- struct fs_usage fsu;
- int ret, err = ERROR_NO_FREE_STORE;
- int blocksize, nr;
- uae_u32 dostype;
- bool fs = false, media = false;
- uae_u8 buf[36] = { 0 }; // InfoData
- blocksize = 512;
- dostype = get_long(unit->volume + 32);
- nr = unit->unit;
- if (unit->volflags & MYVOLUMEINFO_ARCHIVE) {
- ret = zfile_fs_usage_archive (unit->ui.rootdir, 0, &fsu);
- fs = true;
- media = filesys_isvolume(unit) != 0;
- } else if (unit->volflags & MYVOLUMEINFO_CDFS) {
- struct isofs_info ii;
- ret = isofs_mediainfo (unit->ui.cdfs_superblock, &ii) ? 0 : 1;
- if (!ret) {
- media = ii.media;
- nr = unit->unit - cd_unit_offset;
- blocksize = ii.blocksize;
- if (ii.media) {
- fsu.total = ii.blocks * ii.blocksize;
- fsu.avail = 0;
- }
- }
- } else {
- ret = get_fs_usage (unit->ui.rootdir, 0, &fsu);
- if (ret)
- err = dos_errno ();
- fs = true;
- media = filesys_isvolume(unit) != 0;
- }
- if (ret != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- return;
- }
- put_long_host(buf, 0); /* errors */
- put_long_host(buf + 4, nr); /* unit number */
- put_long_host(buf + 8, is_writeprotected(unit) ? 80 : 82); /* state */
- put_long_host(buf + 20, blocksize); /* bytesperblock */
- put_long_host(buf + 32, 0); /* inuse */
- if (unit->ui.unknown_media) {
- if (!disk_info) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_NOT_A_DOS_DISK);
- return;
- }
- put_long_host(buf + 12, 0);
- put_long_host(buf + 16, 0);
- put_long_host(buf + 24, ('B' << 24) | ('A' << 16) | ('D' << 8) | (0 << 0)); /* ID_UNREADABLE_DISK */
- put_long_host(buf + 28, 0);
- } else if (!media) {
- if (!disk_info) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_NO_DISK);
- return;
- }
- put_long_host(buf + 12, 0);
- put_long_host(buf + 16, 0);
- put_long_host(buf + 24, -1); /* ID_NO_DISK_PRESENT */
- put_long_host(buf + 28, 0);
- } else {
- uae_s64 numblocks, inuse;
- get_usedblocks(&fsu, fs, &blocksize, &numblocks, &inuse, true);
- //write_log(_T("total %lld avail %lld Blocks %lld Inuse %lld blocksize %d\n"), fsu.total, fsu.avail, numblocks, inuse, blocksize);
- put_long_host(buf + 12, (uae_u32)numblocks); /* numblocks */
- put_long_host(buf + 16, (uae_u32)inuse); /* inuse */
- put_long_host(buf + 20, blocksize); /* bytesperblock */
- put_long_host(buf + 24, dostype == DISK_TYPE_DOS && kickstart_version >= 36 ? DISK_TYPE_DOS_FFS : dostype); /* disk type */
- put_long_host(buf + 28, unit->volume >> 2); /* volume node */
- put_long_host(buf + 32, (get_long(unit->volume + 28) || unit->keys) ? -1 : 0); /* inuse */
- }
- trap_put_bytes(ctx, buf, info, sizeof buf);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- static void action_disk_info(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- TRACE((_T("ACTION_DISK_INFO\n")));
- do_info(ctx, unit, packet, GET_PCK_ARG1 (packet) << 2, true);
- }
- static void action_info(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- TRACE((_T("ACTION_INFO\n")));
- do_info(ctx, unit, packet, GET_PCK_ARG2 (packet) << 2, false);
- }
- 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)
- prev->next = k->next;
- else
- unit->keys = k->next;
- break;
- }
- prev = k1;
- }
- for (struct lockrecord *lr = k->record; lr;) {
- struct lockrecord *next = lr->next;
- xfree (lr);
- lr = next;
- }
- if (k->fd != NULL)
- fs_closefile (k->fd);
- xfree(k);
- }
- static Key *lookup_key (Unit *unit, uae_u32 uniq)
- {
- Key *k;
- unsigned int total = 0;
- /* 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) {
- total++;
- if (uniq == k->uniq)
- return k;
- }
- write_log (_T("Error: couldn't find key %u / %u!\n"), uniq, total);
- return 0;
- }
- static Key *new_key (Unit *unit)
- {
- Key *k = xcalloc (Key, 1);
- k->uniq = ++key_uniq;
- k->fd = NULL;
- k->file_pos = 0;
- k->next = unit->keys;
- unit->keys = k;
- return k;
- }
- #if TRACING_ENABLED
- static void dumplock(TrapContext *ctx, Unit *unit, uaecptr lock)
- {
- a_inode *a;
- TRACE((_T("LOCK: 0x%x"), lock));
- if (!lock) {
- TRACE((_T("\n")));
- return;
- }
- TRACE((_T("{ next=0x%x, mode=%d, handler=0x%x, volume=0x%x, aino %x "),
- trap_get_long(ctx, lock) << 2, trap_get_long(ctx, lock + 8),
- trap_get_long(ctx, lock + 12), trap_get_long(ctx, lock + 16),
- trap_get_long(ctx, lock + 4)));
- if (log_filesys > 0) {
- a = aino_from_lock(ctx, unit, lock);
- if (a == 0) {
- TRACE((_T("not found!")));
- } else {
- TRACE((_T("%s"), a->nname));
- }
- }
- TRACE((_T(" }\n")));
- }
- #endif
- static a_inode *find_aino(TrapContext* ctx, Unit *unit, uaecptr lock, const TCHAR *name, int *err)
- {
- a_inode *a;
- if (lock) {
- a_inode *olda = aino_from_lock(ctx, unit, lock);
- if (olda == 0) {
- /* That's the best we can hope to do. */
- a = get_aino (unit, &unit->rootnode, name, err);
- } else {
- TRACE((_T("aino: 0x%08lx"), (unsigned long int)olda->uniq));
- TRACE((_T(" \"%s\"\n"), olda->nname));
- a = get_aino (unit, olda, name, err);
- }
- } else {
- a = get_aino (unit, &unit->rootnode, name, err);
- }
- if (a) {
- TRACE((_T("aino=\"%s\"\n"), a->nname));
- }
- aino_test (a);
- return a;
- }
- static uaecptr make_lock(TrapContext *ctx, Unit *unit, uae_u32 uniq, long mode)
- {
- /* allocate lock from the list kept by the assembly code */
- uaecptr lock;
- #if TRAPMD
- struct trapmd md1[] =
- {
- { TRAPCMD_GET_LONG, { unit->locklist }, 1, 0 },
- { TRAPCMD_GET_LONG, { 0 }, 2, 1 },
- { TRAPCMD_PUT_LONG, { unit->locklist, 0 } },
- };
- trap_multi(ctx, md1, sizeof md1 / sizeof(struct trapmd));
- lock = md1[0].params[0] + 4;
- #else
- lock = trap_get_long(ctx, unit->locklist);
- trap_put_long(ctx, unit->locklist, trap_get_long(ctx, lock));
- lock += 4;
- #endif
- #if TRAPMD
- struct trapmd md2[] =
- {
- { TRAPCMD_PUT_LONG, { lock + 4, uniq } },
- { TRAPCMD_PUT_LONG, { lock + 8, mode } },
- { TRAPCMD_PUT_LONG, { lock + 12, unit->port } },
- { TRAPCMD_PUT_LONG, { lock + 16, unit->volume >> 2 } },
- /* prepend to lock chain */
- { TRAPCMD_GET_LONG, { unit->volume + 28 }, 5, 1 },
- { TRAPCMD_PUT_LONG, { lock, 0 } },
- { TRAPCMD_PUT_LONG, { unit->volume + 28, lock >> 2 } }
- };
- trap_multi(ctx, md2, sizeof md2 / sizeof(struct trapmd));
- #else
- trap_put_long(ctx, lock + 4, uniq);
- trap_put_long(ctx, lock + 8, mode);
- trap_put_long(ctx, lock + 12, unit->port);
- trap_put_long(ctx, lock + 16, unit->volume >> 2);
- /* prepend to lock chain */
- trap_put_long(ctx, lock, trap_get_long(ctx, unit->volume + 28));
- trap_put_long(ctx, unit->volume + 28, lock >> 2);
- #endif
- DUMPLOCK(ctx, unit, lock);
- return lock;
- }
- #define NOTIFY_CLASS 0x40000000
- #define NOTIFY_CODE 0x1234
- #define NRF_SEND_MESSAGE 1
- #define NRF_SEND_SIGNAL 2
- #define NRF_WAIT_REPLY 8
- #define NRF_NOTIFY_INITIAL 16
- #define NRF_MAGIC (1 << 31)
- static void notify_send(TrapContext *ctx, Unit *unit, Notify *n)
- {
- uaecptr nr = n->notifyrequest;
- int flags = trap_get_long(ctx, nr + 12);
- if (flags & NRF_SEND_MESSAGE) {
- if (!(flags & NRF_WAIT_REPLY) || ((flags & NRF_WAIT_REPLY) && !(flags & NRF_MAGIC))) {
- uae_NotificationHack (unit->port, nr);
- } else if (flags & NRF_WAIT_REPLY) {
- trap_put_long(ctx, nr + 12, trap_get_long(ctx, nr + 12) | NRF_MAGIC);
- }
- } else if (flags & NRF_SEND_SIGNAL) {
- uae_Signal (trap_get_long(ctx, nr + 16), 1 << trap_get_byte(ctx, nr + 20));
- }
- }
- static void notify_check(TrapContext *ctx, Unit *unit, a_inode *a)
- {
- Notify *n;
- int hash = notifyhash (a->aname);
- for (n = unit->notifyhash[hash]; n; n = n->next) {
- uaecptr nr = n->notifyrequest;
- if (same_aname (n->partname, a->aname)) {
- int err;
- a_inode *a2 = find_aino(ctx, unit, 0, n->fullname, &err);
- if (err == 0 && a == a2)
- notify_send(ctx, unit, n);
- }
- }
- if (a->parent) {
- hash = notifyhash (a->parent->aname);
- for (n = unit->notifyhash[hash]; n; n = n->next) {
- uaecptr nr = n->notifyrequest;
- if (same_aname (n->partname, a->parent->aname)) {
- int err;
- a_inode *a2 = find_aino(ctx, unit, 0, n->fullname, &err);
- if (err == 0 && a->parent == a2)
- notify_send(ctx, unit, n);
- }
- }
- }
- }
- static void action_add_notify(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr nr = GET_PCK_ARG1 (packet);
- int flags;
- Notify *n;
- TCHAR *name, *p, *partname;
- TRACE((_T("ACTION_ADD_NOTIFY\n")));
- name = char1(ctx, trap_get_long(ctx, nr + 4));
- flags = trap_get_long(ctx, nr + 12);
- if (!(flags & (NRF_SEND_MESSAGE | NRF_SEND_SIGNAL))) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_BAD_NUMBER);
- return;
- }
- #if 0
- write_log (_T("Notify:\n"));
- write_log (_T("nr_Name '%s'\n"), char1 (trap_get_long(ctx, nr + 0)));
- write_log (_T("nr_FullName '%s'\n"), name);
- write_log (_T("nr_UserData %08X\n"), trap_get_long(ctx, nr + 8));
- write_log (_T("nr_Flags %08X\n"), flags);
- if (flags & NRF_SEND_MESSAGE) {
- write_log (_T("Message NotifyRequest, port = %08X\n"), trap_get_long(ctx, nr + 16));
- } else if (flags & NRF_SEND_SIGNAL) {
- write_log (_T("Signal NotifyRequest, Task = %08X signal = %d\n"), trap_get_long(ctx, nr + 16), trap_get_long(ctx, nr + 20));
- } else {
- write_log (_T("corrupt NotifyRequest\n"));
- }
- #endif
- p = name + _tcslen (name) - 1;
- if (p[0] == ':')
- p--;
- while (p > name && p[0] != ':' && p[0] != '/')
- p--;
- if (p[0] == ':' || p[0] == '/')
- p++;
- partname = my_strdup (p);
- n = new_notify (unit, partname);
- n->notifyrequest = nr;
- n->fullname = name;
- if (flags & NRF_NOTIFY_INITIAL) {
- int err;
- a_inode *a = find_aino(ctx, unit, 0, n->fullname, &err);
- if (err == 0)
- notify_send(ctx, unit, n);
- }
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- static void action_remove_notify(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr nr = GET_PCK_ARG1 (packet);
- Notify *n;
- int hash;
- TRACE((_T("ACTION_REMOVE_NOTIFY\n")));
- for (hash = 0; hash < NOTIFY_HASH_SIZE; hash++) {
- for (n = unit->notifyhash[hash]; n; n = n->next) {
- if (n->notifyrequest == nr) {
- //write_log (_T("NotifyRequest %08X freed\n"), n->notifyrequest);
- xfree (n->fullname);
- xfree (n->partname);
- free_notify (unit, hash, n);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- return;
- }
- }
- }
- write_log (_T("Tried to free non-existing NotifyRequest %08X\n"), nr);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- static void free_lock(TrapContext *ctx, Unit *unit, uaecptr lock)
- {
- if (! lock)
- return;
- uaecptr curlock = get_long(unit->volume + 28);
- if (lock == curlock << 2) {
- put_long(unit->volume + 28, trap_get_long(ctx, lock));
- } else {
- uaecptr current = curlock;
- uaecptr next = 0;
- while (current) {
- next = trap_get_long(ctx, current << 2);
- if (lock == next << 2)
- break;
- current = next;
- }
- if (!current) {
- write_log (_T("tried to unlock non-existing lock %x\n"), lock);
- return;
- }
- trap_put_long(ctx, current << 2, trap_get_long(ctx, lock));
- }
- lock -= 4;
- #if TRAPMD
- struct trapmd md2[] =
- {
- { TRAPCMD_GET_LONG, { unit->locklist }, 1, 1 },
- { TRAPCMD_PUT_LONG, { lock } },
- { TRAPCMD_PUT_LONG, { unit->locklist, lock } }
- };
- trap_multi(ctx, md2, sizeof md2 / sizeof(struct trapmd));
- #else
- trap_put_long(ctx, lock, trap_get_long(ctx, unit->locklist));
- trap_put_long(ctx, unit->locklist, lock);
- #endif
- }
- static void action_lock(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr name = GET_PCK_ARG2 (packet) << 2;
- int mode = GET_PCK_ARG3 (packet);
- a_inode *a;
- int err;
- if (mode != SHARED_LOCK && mode != EXCLUSIVE_LOCK) {
- TRACE((_T("Bad mode %d (should be %d or %d).\n"), mode, SHARED_LOCK, EXCLUSIVE_LOCK));
- mode = SHARED_LOCK;
- }
- TRACE((_T("ACTION_LOCK(0x%08x, \"%s\", %d)\n"), lock, bstr(ctx, unit, name), mode));
- DUMPLOCK(ctx, unit, lock);
- a = find_aino(ctx, unit, lock, bstr(ctx, unit, name), &err);
- if (err == 0 && a->softlink) {
- err = test_softlink (a);
- }
- if (err == 0 && (a->elock || (mode != SHARED_LOCK && a->shlock > 0))) {
- err = ERROR_OBJECT_IN_USE;
- }
- /* Lock() doesn't do access checks. */
- if (err != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- return;
- }
- if (mode == SHARED_LOCK)
- a->shlock++;
- else
- a->elock = 1;
- de_recycle_aino (unit, a);
- PUT_PCK_RES1(packet, make_lock(ctx, unit, a->uniq, mode) >> 2);
- }
- static void action_read_link_add_parent(Unit *u, a_inode *a, TCHAR *path)
- {
- if (a == NULL)
- return;
- action_read_link_add_parent(u, a->parent, path);
- if (a == &u->rootnode) {
- _tcscat (path, a->aname);
- _tcscat (path, _T(":"));
- } else {
- if (path[0] && path[_tcslen (path) - 1] != ':')
- _tcscat (path, _T("/"));
- _tcscat (path, a->aname);
- }
- }
- #define LINK_HARD 0
- #define LINK_SOFT 1
- static void action_make_link(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr name = GET_PCK_ARG2 (packet) << 2;
- uaecptr target = GET_PCK_ARG3 (packet);
- int type = GET_PCK_ARG4 (packet);
- a_inode *a1, *a2;
- int err;
- TCHAR tmp[256], tmp2[MAX_DPATH], tmp3[MAX_DPATH];
- _tcscpy (tmp, bstr(ctx, unit, name));
- a1 = aino_from_lock(ctx, unit, lock);
- if (type == LINK_HARD) {
- // we don't support hard links
- uaecptr tlock = target << 2;
- a2 = aino_from_lock(ctx, unit, tlock);
- write_log (_T("ACTION_MAKE_LINK(HARD,'%s','%s','%s')\n"),
- a1 ? a1->aname : _T("?"), tmp,
- a2 ? a2->aname : _T("?"));
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_NOT_IMPLEMENTED);
- } else {
- a_inode *a3;
- TCHAR *link = cstr(ctx, unit, target);
- write_log (_T("ACTION_MAKE_LINK(SOFT,'%s','%s','%s')\n"),
- a1 ? a1->aname : _T("?"), tmp, link);
- if (!a1) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
- return;
- }
- // try to find softlink target
- for (Unit *u = units; u; u = u->next) {
- if (u->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS))
- continue;
- a3 = find_aino(ctx, u, 0, link, &err);
- if (err || !a3)
- continue;
- _tcscpy (tmp2, a1->nname);
- _tcscat (tmp2, FSDB_DIR_SEPARATOR_S);
- _tcscat (tmp2, tmp);
- tmp3[0] = 0;
- action_read_link_add_parent (u, a3, tmp3);
- if (!my_createshortcut (tmp2, a3->nname, tmp3)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, dos_errno ());
- }
- return;
- }
- // real Amiga softlinks would accept invalid paths too, we won't.
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
- }
- }
- static void action_read_link(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr name = GET_PCK_ARG2 (packet);
- uaecptr newname = GET_PCK_ARG3 (packet);
- int size = GET_PCK_ARG4 (packet);
- a_inode *a, *matched_aino;
- Unit *u = NULL, *u2 = NULL, *matched_unit;
- int err, i, matched_len;
- TCHAR tmp[MAX_DPATH];
- TCHAR *namep, *extrapath;
- extrapath = NULL;
- namep = cstr(ctx, unit, name);
- for (;;) {
- a = find_aino(ctx, unit, lock, namep, &err);
- if (err != ERROR_IS_SOFT_LINK)
- break;
- for (i = _tcslen (namep) - 1; i > 0; i--) {
- if (namep[i] == '/') {
- namep[i] = 0;
- xfree (extrapath);
- extrapath = my_strdup (namep + i + 1);
- break;
- }
- }
- }
- if (!a->softlink)
- err = ERROR_OBJECT_WRONG_TYPE;
- if (err != 0) {
- xfree(extrapath);
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- return;
- }
- _tcscpy (tmp, a->nname);
- write_log (_T("Resolving softlink '%s'\n"), tmp);
- if (!my_resolvesoftlink (tmp, sizeof tmp / sizeof (TCHAR), false)) {
- xfree(extrapath);
- PUT_PCK_RES1 (packet, DOS_FALSE);
- // not sure what to return
- PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
- return;
- }
- write_log (_T("-> '%s'\n"), tmp);
- matched_aino = NULL;
- matched_unit = NULL;
- err = 0;
- matched_len = 0;
- for (u = units; u; u = u->next) {
- if (!(u->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS))) {
- TCHAR path[MAX_DPATH];
- i = my_issamevolume (u->rootnode.nname, tmp, path);
- if (i > matched_len) {
- a = find_aino(ctx, u, 0, path, &err);
- if (a && !err) {
- write_log (_T("Match found from '%s' (%d)\n"), u->rootnode.aname, i);
- matched_aino = a;
- matched_unit = u;
- matched_len = i;
- }
- }
- }
- }
- if (!matched_aino) {
- xfree(extrapath);
- write_log (_T("Path not found in any mounted drive\n"));
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
- return;
- }
- tmp[0] = 0;
- action_read_link_add_parent (matched_unit, matched_aino, tmp);
- if (extrapath) {
- _tcscat (tmp, _T("/"));
- _tcscat (tmp, extrapath);
- }
- xfree (extrapath);
- write_log (_T("got target '%s'\n"), tmp);
- char *s = ua_fs (tmp, -1);
- for (i = 0; s[i]; i++) {
- if (i >= size - 1)
- break;
- trap_put_byte(ctx, newname + i, s[i]);
- }
- xfree (s);
- trap_put_byte(ctx, newname + i, 0);
- }
- static void action_free_lock(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- a_inode *a;
- TRACE((_T("ACTION_FREE_LOCK(0x%x)\n"), lock));
- DUMPLOCK(ctx, unit, lock);
- a = aino_from_lock(ctx, unit, lock);
- if (a == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
- return;
- }
- if (a->elock)
- a->elock = 0;
- else
- a->shlock--;
- recycle_aino (unit, a);
- free_lock(ctx, unit, lock);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- static uaecptr action_dup_lock_2(TrapContext *ctx, Unit *unit, dpacket *packet, uae_u32 uniq)
- {
- uaecptr out;
- a_inode *a;
- a = lookup_aino (unit, uniq);
- if (a == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
- return 0;
- }
- /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but
- * at least the RAM-Handler seems to allow it. Let's see what happens
- * if we don't. */
- if (a->elock) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
- return 0;
- }
- a->shlock++;
- de_recycle_aino(unit, a);
- out = make_lock(ctx, unit, a->uniq, -2) >> 2;
- PUT_PCK_RES1 (packet, out);
- return out;
- }
- static void action_dup_lock(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- TRACE((_T("ACTION_DUP_LOCK(0x%x)\n"), lock));
- if (!lock) {
- PUT_PCK_RES1 (packet, 0);
- return;
- }
- action_dup_lock_2(ctx, unit, packet, trap_get_long(ctx, lock + 4));
- }
- static void action_lock_from_fh(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
- TRACE((_T("ACTION_COPY_DIR_FH(0x%x,'%s')\n"), GET_PCK_ARG1 (packet), k ? k->aino->aname : _T("<null>")));
- if (k == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- return;
- }
- action_dup_lock_2(ctx, unit, packet, k->aino->uniq);
- }
- static void free_exkey (Unit *unit, a_inode *aino)
- {
- if (--aino->exnext_count == 0) {
- TRACE ((_T("Freeing ExKey and reducing total_locked from %d by %d\n"),
- unit->total_locked_ainos, aino->locked_children));
- unit->total_locked_ainos -= aino->locked_children;
- aino->locked_children = 0;
- }
- }
- static void move_exkeys (Unit *unit, a_inode *from, a_inode *to)
- {
- to->exnext_count = from->exnext_count;
- to->locked_children = from->locked_children;
- from->exnext_count = 0;
- from->locked_children = 0;
- }
- static bool get_statinfo(Unit *unit, a_inode *aino, struct mystat *statbuf)
- {
- bool ok = true;
- memset (statbuf, 0, sizeof(struct mystat));
- /* No error checks - this had better work. */
- if (unit->volflags & MYVOLUMEINFO_ARCHIVE)
- ok = zfile_stat_archive (aino->nname, statbuf) != 0;
- else if (unit->volflags & MYVOLUMEINFO_CDFS)
- ok = isofs_stat (unit->ui.cdfs_superblock, aino->uniq_external, statbuf);
- else
- my_stat (aino->nname, statbuf);
- return ok;
- }
- static void get_fileinfo(TrapContext *ctx, Unit *unit, dpacket *packet, uaecptr info, a_inode *aino, bool longfilesize)
- {
- struct mystat statbuf;
- int days, mins, ticks;
- int i, n, entrytype, blocksize;
- uae_s64 numblocks;
- int fsdb_can = fsdb_cando (unit);
- const TCHAR *xs;
- char *x, *x2;
- uae_u8 *buf;
- uae_u8 buf_array[260] = { 0 };
- if (trap_is_indirect() || !valid_address(info, (sizeof buf_array) - 36) || !real_address_allowed()) {
- buf = buf_array;
- } else {
- buf = get_real_address(info);
- }
- if (aino->vfso) {
- fsdb_can = 1;
- statbuf.mode = aino->vfso->amigaos_mode;
- statbuf.mtime.tv_sec = 0;
- statbuf.mtime.tv_usec = 0;
- statbuf.size = aino->vfso->size;
- } else if (!get_statinfo(unit, aino, &statbuf)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_NOT_A_DOS_DISK);
- return;
- }
- put_long_host(buf + 0, aino->uniq);
- if (aino->parent == 0) {
- /* Guru book says ST_ROOT = 1 (root directory, not currently used)
- * but some programs really expect 2 from root dir..
- */
- entrytype = ST_USERDIR;
- xs = unit->ui.volname;
- } else {
- entrytype = aino->softlink ? ST_SOFTLINK : (aino->dir ? ST_USERDIR : ST_FILE);
- xs = aino->aname;
- }
- put_long_host(buf + 4, entrytype);
- /* AmigaOS docs say these have to contain the same value. */
- put_long_host(buf + 120, entrytype);
- TRACE((_T("name=\"%s\"\n"), xs));
- x2 = x = ua_fs (xs, -1);
- n = strlen (x);
- if (n > 107)
- n = 107;
- if (n > abs(currprefs.filesys_max_name))
- n = abs(currprefs.filesys_max_name);
- i = 8;
- put_byte_host(buf + i, n); i++;
- while (n--)
- put_byte_host(buf + i, *x), i++, x++;
- while (i < 108)
- put_byte_host(buf + i, 0), i++;
- xfree (x2);
- put_long_host(buf + 116, fsdb_can ? aino->amigaos_mode : fsdb_mode_supported (aino));
- if (kickstart_version >= 36) {
- put_word_host(buf + 224, 0); // OwnerUID
- put_word_host(buf + 226, 0); // OwnerGID
- }
- blocksize = (unit->volflags & MYVOLUMEINFO_CDFS) ? 2048 : 512;
- numblocks = (statbuf.size + blocksize - 1) / blocksize;
- put_long_host(buf + 128, numblocks > MAXFILESIZE32 ? MAXFILESIZE32 : numblocks);
- if (longfilesize) {
- /* MorphOS 64-bit file length support */
- put_long_host(buf + 124, statbuf.size > MAXFILESIZE32_2G ? 0 : (uae_u32)statbuf.size);
- put_long_host(buf + 228, statbuf.size >> 32);
- put_long_host(buf + 232, (uae_u32)statbuf.size);
- put_long_host(buf + 236, numblocks >> 32);
- put_long_host(buf + 240, (uae_u32)numblocks);
- } else {
- put_long_host(buf + 124, statbuf.size > MAXFILESIZE32 ? MAXFILESIZE32 : (uae_u32)statbuf.size);
- }
- timeval_to_amiga (&statbuf.mtime, &days, &mins, &ticks, 50);
- put_long_host(buf + 132, days);
- put_long_host(buf + 136, mins);
- put_long_host(buf + 140, ticks);
- if (aino->comment == 0 || !fsdb_can)
- put_long_host(buf + 144, 0);
- else {
- TRACE((_T("comment=\"%s\"\n"), aino->comment));
- i = 144;
- xs = aino->comment;
- if (!xs)
- xs= _T("");
- x2 = x = ua_fs(xs, -1);
- n = strlen(x);
- if (n > 78)
- n = 78;
- put_byte_host(buf + i, n); i++;
- while (n--)
- put_byte_host(buf + i, *x), i++, x++;
- while (i < 224)
- put_byte_host(buf + i, 0), i++;
- xfree (x2);
- }
- if (buf == buf_array) {
- // Must not write Fib_reserved at the end.
- if (kickstart_version >= 36) {
- // FIB + fib_OwnerUID and fib_OwnerGID
- trap_put_bytes(ctx, buf, info, (sizeof buf_array) - 32);
- } else {
- // FIB only
- trap_put_bytes(ctx, buf, info, (sizeof buf_array) - 36);
- }
- }
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- int get_native_path(TrapContext *ctx, uae_u32 lock, TCHAR *out)
- {
- int i = 0;
- for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- if (mountinfo.ui[i].self) {
- a_inode *a = aino_from_lock(ctx, mountinfo.ui[i].self, lock << 2);
- if (a) {
- _tcscpy (out, a->nname);
- return 0;
- }
- }
- }
- return -1;
- }
- #define REC_EXCLUSIVE 0
- #define REC_EXCLUSIVE_IMMED 1
- #define REC_SHARED 2
- #define REC_SHARED_IMMED 3
- static struct lockrecord *new_record (dpacket *packet, uae_u64 pos, uae_u64 len, uae_u32 mode, uae_u32 timeout, uae_u32 msg)
- {
- struct lockrecord *lr = xcalloc (struct lockrecord, 1);
- lr->packet = packet;
- lr->pos = pos;
- lr->len = len;
- lr->mode = mode;
- lr->timeout = timeout * vblank_hz / 50;
- lr->msg = msg;
- return lr;
- }
- static bool record_hit (Unit *unit, Key *k, uae_u64 pos, uae_u64 len, uae_u32 mode)
- {
- bool exclusive = mode == REC_EXCLUSIVE || mode == REC_EXCLUSIVE_IMMED;
- for (Key *k2 = unit->keys; k2; k2 = k2->next) {
- if (k2->aino->uniq == k->aino->uniq) {
- if (k2 == k)
- continue;
- for (struct lockrecord *lr = k2->record; lr; lr = lr->next) {
- bool exclusive2 = lr->mode == REC_EXCLUSIVE || lr->mode == REC_EXCLUSIVE_IMMED;
- if (exclusive || exclusive2) {
- uae_u64 a1 = pos;
- uae_u64 a2 = pos + len;
- uae_u64 b1 = lr->pos;
- uae_u64 b2 = lr->pos + lr->len;
- if (len && lr->len) {
- bool hit = (a1 >= b1 && a1 < b2) || (a2 > b1 && a2 < b2) || (b1 >= a1 && b1 < a2) || (b2 > a1 && b2 < a2);
- if (hit)
- return true;
- }
- }
- }
- }
- }
- return false;
- }
- static void record_timeout(TrapContext *ctx, Unit *unit)
- {
- bool retry = true;
- while (retry) {
- retry = false;
- struct lockrecord *prev = NULL;
- for (struct lockrecord *lr = unit->waitingrecords; lr; lr = lr->next) {
- lr->timeout--;
- if (lr->timeout == 0) {
- Key *k = lookup_key (unit, GET_PCK_ARG1 (lr->packet));
- PUT_PCK_RES1 (lr->packet, DOS_FALSE);
- PUT_PCK_RES2 (lr->packet, ERROR_LOCK_TIMEOUT);
- // mark packet as complete
- trap_put_long(ctx, lr->msg + 4, 0xfffffffe);
- uae_Signal (get_long(unit->volume + 176 - 32), 1 << 13);
- if (prev)
- prev->next = lr->next;
- else
- unit->waitingrecords = lr->next;
- write_log (_T("queued record timed out '%s',%lld,%lld,%d,%d\n"), k ? k->aino->nname : _T("NULL"), lr->pos, lr->len, lr->mode, lr->timeout);
- xfree (lr);
- retry = true;
- break;
- }
- prev = lr;
- }
- }
- }
- static void record_check_waiting(TrapContext *ctx, Unit *unit)
- {
- bool retry = true;
- while (retry) {
- retry = false;
- struct lockrecord *prev = NULL;
- for (struct lockrecord *lr = unit->waitingrecords; lr; lr = lr->next) {
- Key *k = lookup_key (unit, GET_PCK_ARG1 (lr->packet));
- if (!k || !record_hit (unit, k, lr->pos, lr->len, lr->mode)) {
- if (prev)
- prev->next = lr->next;
- else
- unit->waitingrecords = lr->next;
- write_log (_T("queued record released '%s',%llud,%llu,%d,%d\n"), k->aino->nname, lr->pos, lr->len, lr->mode, lr->timeout);
- // mark packet as complete
- trap_put_long(ctx, lr->msg + 4, 0xffffffff);
- xfree (lr);
- retry = true;
- break;
- }
- prev = lr;
- }
- }
- }
- static int action_lock_record(TrapContext *ctx, Unit *unit, dpacket *packet, uae_u32 msg)
- {
- Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
- uae_u32 pos = GET_PCK_ARG2 (packet);
- uae_u32 len = GET_PCK_ARG3 (packet);
- uae_u32 mode = GET_PCK_ARG4 (packet);
- uae_u32 timeout = GET_PCK_ARG5 (packet);
- bool exclusive = mode == REC_EXCLUSIVE || mode == REC_EXCLUSIVE_IMMED;
- write_log (_T("action_lock_record('%s',%d,%d,%d,%d)\n"), k ? k->aino->nname : _T("null"), pos, len, mode, timeout);
- if (!k || mode > REC_SHARED_IMMED) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
- return 1;
- }
- if (mode == REC_EXCLUSIVE_IMMED || mode == REC_SHARED_IMMED)
- timeout = 0;
- if (record_hit (unit, k, pos, len, mode)) {
- if (timeout && msg) {
- // queue it and do not reply
- struct lockrecord *lr = new_record (packet, pos, len, mode, timeout, msg);
- if (unit->waitingrecords) {
- lr->next = unit->waitingrecords;
- unit->waitingrecords = lr;
- } else {
- unit->waitingrecords = lr;
- }
- write_log (_T("-> collision, timeout queued\n"));
- return -1;
- }
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_LOCK_COLLISION);
- write_log (_T("-> ERROR_LOCK_COLLISION\n"));
- return 1;
- }
- struct lockrecord *lr = new_record (packet, pos, len, mode, timeout, 0);
- if (k->record) {
- lr->next = k->record;
- k->record = lr;
- } else {
- k->record = lr;
- }
- PUT_PCK_RES1 (packet, DOS_TRUE);
- write_log (_T("-> OK\n"));
- return 1;
- }
- static void action_free_record(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
- uae_u32 pos = GET_PCK_ARG2 (packet);
- uae_u32 len = GET_PCK_ARG3 (packet);
- write_log (_T("action_free_record('%s',%d,%d)\n"), k ? k->aino->nname : _T("null"), pos, len);
- if (!k) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
- return;
- }
- struct lockrecord *prev = NULL;
- for (struct lockrecord *lr = k->record; lr; lr = lr->next) {
- if (lr->pos == pos && lr->len == len) {
- if (prev)
- prev->next = lr->next;
- else
- k->record = lr->next;
- xfree (lr);
- write_log (_T("->OK\n"));
- record_check_waiting(ctx, unit);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- return;
- }
- }
- write_log (_T("-> ERROR_RECORD_NOT_LOCKED\n"));
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_RECORD_NOT_LOCKED);
- }
- #define EXALL_DEBUG 0
- #define EXALL_END 0xde1111ad
- static ExAllKey *getexall (Unit *unit, uaecptr control, int id)
- {
- int i;
- if (id < 0) {
- for (i = 0; i < EXALLKEYS; i++) {
- if (unit->exalls[i].id == 0) {
- unit->exallid++;
- if (unit->exallid == EXALL_END)
- unit->exallid++;
- unit->exalls[i].id = unit->exallid;
- unit->exalls[i].control = control;
- return &unit->exalls[i];
- }
- }
- } else if (id > 0) {
- for (i = 0; i < EXALLKEYS; i++) {
- if (unit->exalls[i].id == id)
- return &unit->exalls[i];
- }
- }
- return NULL;
- }
- static int exalldo(TrapContext *ctx, uaecptr exalldata, uae_u32 exalldatasize, uae_u32 type, uaecptr control, Unit *unit, a_inode *aino)
- {
- uaecptr exp = exalldata;
- int i;
- int size, size2;
- int entrytype;
- const TCHAR *xs = NULL, *commentx = NULL;
- uae_u32 flags = 15;
- int days, mins, ticks;
- struct mystat statbuf;
- int fsdb_can = fsdb_cando (unit);
- uae_u16 uid = 0, gid = 0;
- char *x = NULL, *comment = NULL;
- int ret = 0;
- memset (&statbuf, 0, sizeof statbuf);
- if (unit->volflags & MYVOLUMEINFO_ARCHIVE)
- zfile_stat_archive (aino->nname, &statbuf);
- else if (unit->volflags & MYVOLUMEINFO_CDFS)
- isofs_stat (unit->ui.cdfs_superblock, aino->uniq_external, &statbuf);
- else
- my_stat (aino->nname, &statbuf);
- if (aino->parent == 0) {
- entrytype = ST_USERDIR;
- xs = unit->ui.volname;
- } else {
- entrytype = aino->softlink ? ST_SOFTLINK : (aino->dir ? ST_USERDIR : ST_FILE);
- xs = aino->aname;
- }
- x = ua_fs (xs, -1);
- size = 0;
- size2 = 4;
- if (type >= 1) {
- size2 += 4;
- size += strlen (x) + 1;
- size = (size + 3) & ~3;
- }
- if (type >= 2)
- size2 += 4;
- if (type >= 3)
- size2 += 4;
- if (type >= 4) {
- flags = fsdb_can ? aino->amigaos_mode : fsdb_mode_supported (aino);
- size2 += 4;
- }
- if (type >= 5) {
- timeval_to_amiga (&statbuf.mtime, &days, &mins, &ticks, 50);
- size2 += 12;
- }
- if (type >= 6) {
- size2 += 4;
- if (aino->comment == 0 || !fsdb_can)
- commentx = _T("");
- else
- commentx = aino->comment;
- comment = ua_fs (commentx, -1);
- size += strlen (comment) + 1;
- size = (size + 3) & ~3;
- }
- if (type >= 7) {
- size2 += 4;
- uid = 0;
- gid = 0;
- }
- if (type >= 8) {
- size2 += 8;
- }
- i = trap_get_long(ctx, control + 0);
- while (i > 0) {
- exp = trap_get_long(ctx, exp); /* ed_Next */
- i--;
- }
- if (exalldata + exalldatasize - exp < size + size2)
- goto end; /* not enough space */
- #if EXALL_DEBUG > 0
- write_log (_T("ID=%d, %d, %08x: '%s'%s\n"),
- trap_get_long(ctx, control + 4), trap_get_long(ctx, control + 0), exp, xs, aino->dir ? _T(" [DIR]") : _T(""));
- #endif
- trap_put_long(ctx, exp, exp + size + size2); /* ed_Next */
- if (type >= 1) {
- trap_put_long(ctx, exp + 4, exp + size2);
- for (i = 0; i <= strlen (x); i++) {
- trap_put_byte(ctx, exp + size2, x[i]);
- size2++;
- }
- }
- if (type >= 2)
- trap_put_long(ctx, exp + 8, entrytype);
- if (type >= 3)
- trap_put_long(ctx, exp + 12, statbuf.size > MAXFILESIZE32 ? MAXFILESIZE32 : statbuf.size);
- if (type >= 4)
- trap_put_long(ctx, exp + 16, flags);
- if (type >= 5) {
- trap_put_long(ctx, exp + 20, days);
- trap_put_long(ctx, exp + 24, mins);
- trap_put_long(ctx, exp + 28, ticks);
- }
- if (type >= 6) {
- trap_put_long(ctx, exp + 32, exp + size2);
- trap_put_byte(ctx, exp + size2, strlen (comment));
- for (i = 0; i <= strlen (comment); i++) {
- trap_put_byte(ctx, exp + size2, comment[i]);
- size2++;
- }
- }
- if (type >= 7) {
- trap_put_word(ctx, exp + 36, uid);
- trap_put_word(ctx, exp + 38, gid);
- }
- if (type >= 8) {
- trap_put_long(ctx, exp + 40, statbuf.size >> 32);
- trap_put_long(ctx, exp + 44, (uae_u32)statbuf.size);
- }
- trap_put_long(ctx, control + 0, trap_get_long(ctx, control + 0) + 1);
- ret = 1;
- end:
- xfree (x);
- xfree (comment);
- return ret;
- }
- static bool filesys_name_invalid(const TCHAR *fn)
- {
- return _tcslen (fn) > currprefs.filesys_max_name;
- }
- static int filesys_readdir(struct fs_dirhandle *d, TCHAR *fn, uae_u64 *uniq)
- {
- int ok = 0;
- if (d->fstype == FS_ARCHIVE)
- ok = zfile_readdir_archive(d->zd, fn);
- else if (d->fstype == FS_DIRECTORY)
- ok = my_readdir(d->od, fn);
- else if (d->fstype == FS_CDFS)
- ok = isofs_readdir(d->isod, fn, uniq);
- return ok;
- }
- static int action_examine_all_do(TrapContext *ctx, Unit *unit, uaecptr lock, ExAllKey *eak, uaecptr exalldata, uae_u32 exalldatasize, uae_u32 type, uaecptr control)
- {
- a_inode *aino, *base = NULL;
- int ok;
- uae_u32 err;
- struct fs_dirhandle *d;
- TCHAR fn[MAX_DPATH];
- if (lock != 0)
- base = aino_from_lock(ctx, unit, lock);
- if (base == 0)
- base = &unit->rootnode;
- for (;;) {
- uae_u64 uniq = 0;
- d = eak->dirhandle;
- if (!eak->fn) {
- do {
- ok = filesys_readdir(d, fn, &uniq);
- } while (ok && d->fstype == FS_DIRECTORY && (filesys_name_invalid (fn) || fsdb_name_invalid_dir (NULL, fn)));
- if (!ok)
- return 0;
- } else {
- _tcscpy (fn, eak->fn);
- xfree (eak->fn);
- eak->fn = NULL;
- }
- aino = lookup_child_aino_for_exnext (unit, base, fn, &err, uniq, NULL);
- if (!aino)
- return 0;
- eak->id = unit->exallid++;
- trap_put_long(ctx, control + 4, eak->id);
- if (!exalldo(ctx, exalldata, exalldatasize, type, control, unit, aino)) {
- eak->fn = my_strdup (fn); /* no space in exallstruct, save current entry */
- break;
- }
- }
- return 1;
- }
- static int action_examine_all_end(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uae_u32 id;
- uae_u32 doserr = 0;
- ExAllKey *eak;
- uaecptr control = GET_PCK_ARG5 (packet);
- if (kickstart_version < 36)
- return 0;
- id = trap_get_long(ctx, control + 4);
- eak = getexall (unit, control, id);
- #if EXALL_DEBUG > 0
- write_log (_T("EXALL_END ID=%d %x\n"), id, eak);
- #endif
- if (!eak) {
- write_log (_T("FILESYS: EXALL_END non-existing ID %d\n"), id);
- doserr = ERROR_OBJECT_WRONG_TYPE;
- } else {
- eak->id = 0;
- fs_closedir (eak->dirhandle);
- xfree (eak->fn);
- eak->fn = NULL;
- eak->dirhandle = NULL;
- }
- if (doserr) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, doserr);
- } else {
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- return 1;
- }
- static int action_examine_all(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr exalldata = GET_PCK_ARG2 (packet);
- uae_u32 exalldatasize = GET_PCK_ARG3 (packet);
- uae_u32 type = GET_PCK_ARG4 (packet);
- uaecptr control = GET_PCK_ARG5 (packet);
- ExAllKey *eak = NULL;
- a_inode *base = NULL;
- struct fs_dirhandle *d;
- int ok, i;
- uaecptr exp;
- uae_u32 id, doserr = ERROR_NO_MORE_ENTRIES;
- ok = 0;
- #if EXALL_DEBUG > 0
- write_log (_T("exall: %08x %08x-%08x %d %d %08x\n"),
- lock, exalldata, exalldata + exalldatasize, exalldatasize, type, control);
- write_log (_T("exall: MatchString %08x, MatchFunc %08x\n"),
- trap_get_long(ctx, control + 8), trap_get_long(ctx, control + 12));
- #endif
- trap_put_long(ctx, control + 0, 0); /* eac_Entries */
- /* EXAMINE ALL might use dos.library MatchPatternNoCase() which is >=36 */
- if (kickstart_version < 36)
- return 0;
- if (type == 0 || type > 8) {
- doserr = ERROR_BAD_NUMBER;
- goto fail;
- }
- PUT_PCK_RES1 (packet, DOS_TRUE);
- id = trap_get_long(ctx, control + 4);
- if (id == EXALL_END) {
- write_log (_T("FILESYS: EXALL called twice with ERROR_NO_MORE_ENTRIES\n"));
- goto fail; /* already ended exall() */
- }
- if (id) {
- eak = getexall (unit, control, id);
- if (!eak) {
- write_log (_T("FILESYS: EXALL non-existing ID %d\n"), id);
- doserr = ERROR_OBJECT_WRONG_TYPE;
- goto fail;
- }
- if (!action_examine_all_do(ctx, unit, lock, eak, exalldata, exalldatasize, type, control))
- goto fail;
- if (trap_get_long(ctx, control + 0) == 0) {
- /* uh, no space for first entry.. */
- doserr = ERROR_NO_FREE_STORE;
- goto fail;
- }
- } else {
- eak = getexall (unit, control, -1);
- if (!eak)
- goto fail;
- if (lock != 0)
- base = aino_from_lock(ctx, unit, lock);
- if (base == 0)
- base = &unit->rootnode;
- #if EXALL_DEBUG > 0
- write_log("exall: ID=%d '%s'\n", eak->id, base->nname);
- #endif
- d = fs_opendir (unit, base);
- if (!d)
- goto fail;
- eak->dirhandle = d;
- trap_put_long(ctx, control + 4, eak->id);
- if (!action_examine_all_do(ctx, unit, lock, eak, exalldata, exalldatasize, type, control))
- goto fail;
- if (trap_get_long(ctx, control + 0) == 0) {
- /* uh, no space for first entry.. */
- doserr = ERROR_NO_FREE_STORE;
- goto fail;
- }
- }
- ok = 1;
- fail:
- /* Clear last ed_Next. This "list" is quite non-Amiga like.. */
- exp = exalldata;
- i = trap_get_long(ctx, control + 0);
- for (;;) {
- if (i <= 1) {
- if (exp)
- trap_put_long(ctx, exp, 0);
- break;
- }
- exp = trap_get_long(ctx, exp); /* ed_Next */
- i--;
- }
- #if EXALL_DEBUG > 0
- write_log("ok=%d, err=%d, eac_Entries = %d\n", ok, ok ? -1 : doserr, trap_get_long(ctx, control + 0));
- #endif
- if (!ok) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, doserr);
- if (eak) {
- eak->id = 0;
- fs_closedir (eak->dirhandle);
- eak->dirhandle = NULL;
- xfree (eak->fn);
- eak->fn = NULL;
- }
- if (doserr == ERROR_NO_MORE_ENTRIES)
- trap_put_long(ctx, control + 4, EXALL_END);
- }
- return 1;
- }
- static uae_u32 exall_helper(TrapContext *ctx)
- {
- int i;
- Unit *u;
- uaecptr pck = trap_get_areg(ctx, 4);
- dpacket packet;
- readdpacket(ctx, &packet, pck);
- uaecptr control = get_long_host(packet.packet_data + dp_Arg5);
- uae_u32 id = trap_get_long(ctx, control + 4);
- #if EXALL_DEBUG > 0
- write_log (_T("FILESYS: EXALL extra round ID=%d\n"), id);
- #endif
- if (id == EXALL_END)
- return 1;
- for (u = units; u; u = u->next) {
- for (i = 0; i < EXALLKEYS; i++) {
- if (u->exalls[i].id == id && u->exalls[i].control == control) {
- action_examine_all(ctx, u, &packet);
- }
- }
- }
- return 1;
- }
- static uae_u32 REGPARAM2 fsmisc_helper(TrapContext *ctx)
- {
- int mode = trap_get_dreg(ctx, 0);
- switch (mode)
- {
- case 0:
- return exall_helper(ctx);
- case 1:
- return filesys_media_change_reply (0);
- case 2:
- return filesys_media_change_reply (1);
- case 3:
- uae_u32 t = getlocaltime ();
- uae_u32 secs = (uae_u32)t - (8 * 365 + 2) * 24 * 60 * 60;
- return secs;
- }
- return 0;
- }
- static void action_examine_object(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr info = GET_PCK_ARG2 (packet) << 2;
- a_inode *aino = 0;
- TRACE((_T("ACTION_EXAMINE_OBJECT(0x%x,0x%x)\n"), lock, info));
- DUMPLOCK(ctx, unit, lock);
- if (lock != 0)
- aino = aino_from_lock(ctx, unit, lock);
- if (aino == 0)
- aino = &unit->rootnode;
- get_fileinfo(ctx, unit, packet, info, aino, false);
- }
- extern unsigned char def_tool[];
- extern unsigned int def_tool_len;
- extern unsigned char def_project[];
- extern unsigned int def_project_len;
- extern unsigned char def_drawer[];
- extern unsigned int def_drawer_len;
- static struct virtualfilesysobject vfso_icon_tool;
- static struct virtualfilesysobject vfso_icon_project;
- static struct virtualfilesysobject vfso_icon_drawer;
- static void load_injected_icon(struct virtualfilesysobject *vfso, const TCHAR *fn, uae_u8 *default_data, int default_size)
- {
- uae_u8 *data = NULL;
- int size;
- xfree(vfso->data);
- if (fn && fn[0])
- data = zfile_load_file(fn, &size);
- if (!data) {
- vfso->data = xmalloc(uae_u8, default_size);
- memcpy(vfso->data, default_data, default_size);
- vfso->size = default_size;
- return;
- }
- vfso->data = data;
- vfso->size = size;
- }
- static void load_injected_icons(void)
- {
- load_injected_icon(&vfso_icon_tool, currprefs.filesys_inject_icons_tool, def_tool, def_tool_len);
- load_injected_icon(&vfso_icon_project, currprefs.filesys_inject_icons_project, def_project, def_project_len);
- load_injected_icon(&vfso_icon_drawer, currprefs.filesys_inject_icons_drawer, def_drawer, def_drawer_len);
- }
- static void inject_icons_to_directory(Unit *unit, a_inode *base)
- {
- for (a_inode *aino = base->child; aino; aino = aino->sibling) {
- int len = _tcslen(aino->aname);
- if (len >= 5 && !_tcsicmp(aino->aname + len - 5, _T(".info")))
- continue;
- TCHAR tmp[256];
- _stprintf(tmp, _T("%s.info"), aino->aname);
- bool match = false;
- for (a_inode *aino2 = base->child; aino2; aino2 = aino2->sibling) {
- if (!_tcsicmp(aino2->aname, tmp))
- match = true;
- }
- if (match)
- continue;
- uae_u32 err;
- struct virtualfilesysobject *vfso;
- if (aino->dir) {
- vfso = &vfso_icon_drawer;
- } else {
- if (aino->amigaos_mode & A_FIBF_EXECUTE)
- vfso = &vfso_icon_project;
- else
- vfso = &vfso_icon_tool;
- }
- lookup_child_aino_for_exnext(unit, base, tmp, &err, 0, vfso);
- }
- }
- /* 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)
- {
- struct fs_dirhandle *d;
- a_inode *aino;
- d = fs_opendir (unit, base);
- if (!d)
- return;
- for (aino = base->child; aino; aino = aino->sibling) {
- base->locked_children++;
- unit->total_locked_ainos++;
- }
- TRACE3((_T("Populating directory, child %s, locked_children %d\n"),
- base->child ? base->child->nname : _T("<NULL>"), base->locked_children));
- for (;;) {
- uae_u64 uniq = 0;
- TCHAR fn[MAX_DPATH];
- int ok;
- uae_u32 err;
- /* Find next file that belongs to the Amiga fs (skipping things
- like "..", "." etc. */
- do {
- ok = filesys_readdir(d, fn, &uniq);
- } while (ok && d->fstype == FS_DIRECTORY && (filesys_name_invalid (fn) || fsdb_name_invalid_dir (NULL, fn)));
- if (!ok)
- 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, fn, &err, uniq, NULL);
- }
- fs_closedir (d);
- if (currprefs.filesys_inject_icons || unit->ui.inject_icons)
- inject_icons_to_directory(unit, base);
- }
- static bool do_examine(TrapContext *ctx, Unit *unit, dpacket *packet, a_inode *aino, uaecptr info, bool longfilesize)
- {
- for (;;) {
- TCHAR *name;
- if (!aino)
- break;
- name = aino->nname;
- get_fileinfo(ctx, unit, packet, info, aino, longfilesize);
- if (!aino->vfso && !(unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS)) && !fsdb_exists(name)) {
- TRACE ((_T("%s orphaned"), name));
- return false;
- }
- return true;
- }
- TRACE((_T("no more entries\n")));
- free_exkey (unit, aino->parent);
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
- return true;
- }
- #define EXNEXT_DEBUG 0
- static void action_examine_next(TrapContext *ctx, Unit *unit, dpacket *packet, bool largefilesize)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr info = GET_PCK_ARG2 (packet) << 2;
- a_inode *aino = 0, *daino = 0;
- uae_u32 uniq;
- TRACE((_T("ACTION_EXAMINE_NEXT(0x%x,0x%x,%d)\n"), lock, info, largefilesize));
- gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
- DUMPLOCK(ctx, unit, lock);
- if (lock != 0)
- aino = aino_from_lock(ctx, unit, lock);
- if (aino == 0)
- aino = &unit->rootnode;
- uniq = trap_get_long(ctx, info);
- for (;;) {
- if (uniq == aino->uniq) {
- // first exnext
- if (!aino->dir) {
- write_log (_T("ExNext called for a file! %s:%d (Houston?)\n"), aino->nname, uniq);
- goto no_more_entries;
- }
- if (aino->exnext_count++ == 0)
- populate_directory (unit, aino);
- if (!aino->child)
- goto no_more_entries;
- daino = aino->child;
- } else {
- daino = lookup_aino(unit, uniq);
- if (!daino) {
- #if EXNEXT_DEBUG
- write_log(_T("EXNEXT but next entry is missing! (%d)\n"), uniq);
- #endif
- // deleted? Look for next larger uniq in same directory.
- daino = aino->child;
- while (daino && uniq >= daino->uniq) {
- daino = daino->sibling;
- }
- #if EXNEXT_DEBUG
- if (daino) {
- write_log(_T("Using next found entry %d\n"), uniq);
- }
- #endif
- // didn't find, what about previous?
- if (!daino) {
- daino = aino->child;
- while (daino && uniq >= daino->uniq) {
- if (daino->sibling && daino->sibling->uniq >= uniq) {
- #if EXNEXT_DEBUG
- write_log(_T("Using previous entry %d\n"), uniq);
- #endif
- break;
- }
- daino = daino->sibling;
- }
- }
- // didn't find any but there are still entries? restart from beginning.
- if (!daino && aino->child) {
- daino = aino->child;
- #if EXNEXT_DEBUG
- write_log(_T("Re-starting from beginning %d\n"), daino->uniq);
- #endif
- }
- } else {
- daino = daino->sibling;
- }
- }
- if (!daino)
- goto no_more_entries;
- if (daino->parent != aino) {
- write_log(_T("Houston, we have a BIG problem. %s is not parent of %s\n"), daino->nname, aino->nname);
- goto no_more_entries;
- }
- uniq = daino->uniq;
- if (daino->mountcount != unit->mountcount)
- continue;
- if (!do_examine(ctx, unit, packet, daino, info, largefilesize))
- continue;
- return;
- }
- no_more_entries:
- free_exkey(unit, aino);
- PUT_PCK_RES1(packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
- }
- static void do_find(TrapContext *ctx, 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;
- a_inode *aino;
- Key *k;
- struct fs_filehandle *fd = NULL;
- int err;
- mode_t openmode;
- int aino_created = 0;
- int isvirtual = unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS);
- TRACE((_T("ACTION_FIND_*(0x%08x,0x%08x,\"%s\",%d,%d)\n"), fh, lock, bstr(ctx, unit, name), mode, create));
- TRACE((_T("fh=%x lock=%x name=%x\n"), fh, lock, name));
- DUMPLOCK(ctx, unit, lock);
- aino = find_aino(ctx, unit, lock, bstr(ctx, unit, name), &err);
- 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);
- return;
- }
- if (aino->softlink) {
- handle_softlink(ctx, unit, packet, aino);
- return;
- }
- if (err == 0) {
- /* Object exists. */
- if (aino->dir) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
- return;
- }
- if (aino->elock || (create == 2 && aino->shlock > 0)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
- return;
- }
- if (create && aino->vfso) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
- return;
- }
- if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
- return;
- }
- if (create != 2) {
- if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || is_writeprotected(unit))
- && fallback)
- {
- mode &= ~A_FIBF_WRITE;
- }
- /* Kick 1.3 doesn't check read and write access bits - maybe it would be
- * simpler just not to do that either. */
- if ((mode & A_FIBF_WRITE) != 0 && is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0
- || mode == 0)
- {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED);
- return;
- }
- if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED);
- return;
- }
- }
- } else if (create == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- return;
- } else {
- /* Object does not exist. aino points to containing directory. */
- aino = create_child_aino(unit, aino, my_strdup (bstr_cut(ctx, unit, name)), 0);
- if (aino == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
- return;
- }
- aino_created = 1;
- }
- prepare_for_open (aino->nname);
- if (!aino->vfso) {
- openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY
- : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY
- : O_RDWR)
- | (create ? O_CREAT : 0)
- | (create == 2 ? O_TRUNC : 0));
- fd = fs_openfile (unit, aino, openmode | O_BINARY);
- if (fd == NULL) {
- if (aino_created)
- delete_aino (unit, aino);
- PUT_PCK_RES1 (packet, DOS_FALSE);
- /* archive and fd == NULL = corrupt archive or out of memory */
- PUT_PCK_RES2 (packet, isvirtual ? ERROR_OBJECT_NOT_AROUND : dos_errno ());
- return;
- }
- }
- k = new_key (unit);
- k->fd = fd;
- k->aino = aino;
- k->dosmode = mode;
- k->createmode = create;
- k->notifyactive = create ? 1 : 0;
- if (create && isvirtual)
- fsdb_set_file_attrs (aino);
- trap_put_long(ctx, fh + 36, k->uniq);
- if (create == 2) {
- aino->elock = 1;
- // clear comment if file already existed
- if (aino->comment) {
- xfree (aino->comment);
- aino->comment = 0;
- }
- fsdb_set_file_attrs (aino);
- } else {
- aino->shlock++;
- }
- de_recycle_aino (unit, aino);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- static void action_fh_from_lock(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr fh = GET_PCK_ARG1 (packet) << 2;
- uaecptr lock = GET_PCK_ARG2 (packet) << 2;
- a_inode *aino;
- Key *k;
- struct fs_filehandle *fd;
- mode_t openmode;
- int mode;
- TRACE((_T("ACTION_FH_FROM_LOCK(0x%x,0x%x)\n"), fh, lock));
- DUMPLOCK(ctx, unit,lock);
- if (!lock) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, 0);
- return;
- }
- aino = aino_from_lock(ctx, unit, lock);
- if (aino == 0)
- aino = &unit->rootnode;
- if (aino->softlink) {
- handle_softlink(ctx, unit, packet, aino);
- return;
- }
- mode = aino->amigaos_mode; /* Use same mode for opened filehandle as existing Lock() */
- prepare_for_open (aino->nname);
- TRACE ((_T(" 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 (is_writeprotected(unit))
- openmode = O_RDONLY;
- fd = fs_openfile (unit, aino, openmode | O_BINARY);
- if (fd == NULL) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- k = new_key (unit);
- k->fd = fd;
- k->aino = aino;
- trap_put_long(ctx, fh + 36, k->uniq);
- /* I don't think I need to play with shlock count here, because I'm
- opening from an existing lock ??? */
- de_recycle_aino (unit, aino);
- free_lock(ctx, unit, lock); /* lock must be unlocked */
- 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(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- do_find(ctx, unit, packet, A_FIBF_READ | A_FIBF_WRITE, 0, 1);
- }
- static void action_find_output(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- do_find(ctx, unit, packet, A_FIBF_READ | A_FIBF_WRITE, 2, 0);
- }
- static void action_find_write(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- do_find(ctx, unit, packet, A_FIBF_READ | A_FIBF_WRITE, 1, 0);
- }
- /* change file/dir's parent dir modification time */
- static void updatedirtime (a_inode *a1, int now)
- {
- struct mystat statbuf;
- if (!a1->parent)
- return;
- if (!now) {
- if (!my_stat (a1->nname, &statbuf))
- return;
- my_utime (a1->parent->nname, &statbuf.mtime);
- } else {
- my_utime (a1->parent->nname, NULL);
- }
- }
- static void action_end(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k;
- TRACE((_T("ACTION_END(0x%x)\n"), GET_PCK_ARG1 (packet)));
- k = lookup_key (unit, GET_PCK_ARG1 (packet));
- if (k != 0) {
- if (k->notifyactive) {
- notify_check(ctx, unit, k->aino);
- updatedirtime (k->aino, 1);
- }
- if (k->aino->elock)
- k->aino->elock = 0;
- else
- k->aino->shlock--;
- recycle_aino (unit, k->aino);
- free_key (unit, k);
- }
- PUT_PCK_RES1 (packet, DOS_TRUE);
- PUT_PCK_RES2 (packet, 0);
- }
- static void action_read(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
- uaecptr addr = GET_PCK_ARG2 (packet);
- uae_u32 size = GET_PCK_ARG3 (packet);
- uae_u32 actual = 0;
- if (k == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- /* PUT_PCK_RES2 (packet, EINVAL); */
- return;
- }
- TRACE((_T("ACTION_READ(%s,0x%x,%d)\n"), k->aino->nname, addr, size));
- gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
- if (size == 0) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, 0);
- } else if (k->aino->vfso) {
- uae_s64 filesize = k->aino->vfso->size;
- for (int i = 0; i < size && k->file_pos < filesize; i++) {
- trap_put_byte(ctx, addr + i, k->aino->vfso->data[k->file_pos]);
- k->file_pos++;
- actual++;
- }
- PUT_PCK_RES1 (packet, actual);
- size = 0;
- } else {
- /* check if filesize < size */
- uae_s64 filesize, cur;
- filesize = key_filesize(k);
- cur = k->file_pos;
- if (size > filesize - cur)
- size = filesize - cur;
- if (size == 0) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, 0);
- } else if (!trap_valid_address(ctx, addr, size)) {
- /* it really crosses memory boundary */
- uae_u8 *buf;
-
- /* ugh this is inefficient but easy */
- if (key_seek(k, k->file_pos, SEEK_SET) < 0) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- buf = xmalloc (uae_u8, size);
- if (!buf) {
- PUT_PCK_RES1 (packet, -1);
- PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
- return;
- }
- actual = fs_read (k->fd, buf, size);
- if ((uae_s32)actual == -1) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, dos_errno ());
- } else {
- PUT_PCK_RES1 (packet, actual);
- trap_put_bytes(ctx, buf, addr, actual);
- k->file_pos += actual;
- }
- xfree (buf);
- size = 0;
- }
- }
- if (size) {
- if (key_seek(k, k->file_pos, SEEK_SET) < 0) {
- PUT_PCK_RES1(packet, 0);
- PUT_PCK_RES2(packet, dos_errno());
- return;
- }
- if (trap_is_indirect() || !real_address_allowed()) {
- uae_u8 buf[RTAREA_TRAP_DATA_EXTRA_SIZE];
- actual = 0;
- while (size > 0) {
- int toread = size > RTAREA_TRAP_DATA_EXTRA_SIZE ? RTAREA_TRAP_DATA_EXTRA_SIZE : size;
- int read = fs_read(k->fd, buf, toread);
- if (read < 0) {
- actual = -1;
- break;
- }
- if (read == 0)
- break;
- trap_put_bytes(ctx, buf, addr, read);
- size -= read;
- addr += read;
- actual += read;
- if (read < toread)
- break;
- }
- } else {
- /* normal fast read */
- uae_u8 *realpt = get_real_address (addr);
- actual = fs_read (k->fd, realpt, size);
- }
- if (actual == 0) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, 0);
- } else if (actual < 0) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, dos_errno ());
- } else {
- PUT_PCK_RES1 (packet, actual);
- k->file_pos += actual;
- }
- }
- TRACE((_T("=%d\n"), actual));
- }
- static void action_write(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
- uaecptr addr = GET_PCK_ARG2 (packet);
- uae_u32 size = GET_PCK_ARG3 (packet);
- uae_u32 actual;
- uae_u8 *buf;
- if (k == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- /* PUT_PCK_RES2 (packet, EINVAL); */
- return;
- }
- gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
- TRACE((_T("ACTION_WRITE(%s,0x%x,%d)\n"), k->aino->nname, addr, size));
- if (is_writeprotected(unit) || k->aino->vfso) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- if (size == 0) {
- actual = 0;
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, 0);
- } else if (trap_valid_address(ctx, addr, size)) {
- if (key_seek(k, k->file_pos, SEEK_SET) < 0) {
- PUT_PCK_RES1(packet, 0);
- PUT_PCK_RES2(packet, dos_errno());
- return;
- }
- if (trap_is_indirect() || !real_address_allowed()) {
- uae_u8 buf[RTAREA_TRAP_DATA_EXTRA_SIZE];
- actual = 0;
- int sizecnt = size;
- while (sizecnt > 0) {
- int towrite = sizecnt > RTAREA_TRAP_DATA_EXTRA_SIZE ? RTAREA_TRAP_DATA_EXTRA_SIZE : sizecnt;
- trap_get_bytes(ctx, buf, addr, towrite);
- int write = fs_write(k->fd, buf, towrite);
- if (write < 0) {
- actual = -1;
- break;
- }
- if (write == 0)
- break;
- sizecnt -= write;
- addr += write;
- actual += write;
- if (write < towrite)
- break;
- }
- } else {
- uae_u8 *realpt = get_real_address (addr);
- actual = fs_write (k->fd, realpt, size);
- }
- } else {
- /* ugh this is inefficient but easy */
- if (key_seek(k, k->file_pos, SEEK_SET) < 0) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- buf = xmalloc (uae_u8, size);
- if (!buf) {
- PUT_PCK_RES1 (packet, -1);
- PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
- return;
- }
- trap_get_bytes(ctx, buf, addr, size);
- actual = fs_write (k->fd, buf, size);
- xfree (buf);
- }
- TRACE((_T("=%d\n"), actual));
- PUT_PCK_RES1 (packet, actual);
- if (actual != size)
- PUT_PCK_RES2 (packet, dos_errno ());
- if ((uae_s32)actual != -1)
- k->file_pos += actual;
- k->notifyactive = 1;
- }
- static void action_seek(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
- int pos = (uae_s32)GET_PCK_ARG2 (packet);
- int mode = (uae_s32)GET_PCK_ARG3 (packet);
- uae_s64 res;
- uae_s64 cur;
- int whence = SEEK_CUR;
- uae_s64 temppos, filesize;
- if (k == 0) {
- PUT_PCK_RES1 (packet, -1);
- PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
- return;
- }
- if (mode > 0)
- whence = SEEK_END;
- if (mode < 0)
- whence = SEEK_SET;
- cur = k->file_pos;
- TRACE((_T("ACTION_SEEK(%s,%d,%d)=%lld\n"), k->aino->nname, pos, mode, cur));
- gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
- filesize = key_filesize(k);
- if (whence == SEEK_CUR)
- temppos = cur + pos;
- if (whence == SEEK_SET)
- temppos = pos;
- if (whence == SEEK_END)
- temppos = filesize + pos;
- if (filesize < temppos || temppos < 0) {
- PUT_PCK_RES1 (packet, -1);
- PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
- return;
- }
- res = key_seek(k, pos, whence);
- if (-1 == res || cur > MAXFILESIZE32) {
- PUT_PCK_RES1 (packet, -1);
- PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
- key_seek(k, cur, SEEK_SET);
- } else {
- PUT_PCK_RES1 (packet, cur);
- k->file_pos = key_seek(k, 0, SEEK_CUR);
- }
- }
- static void action_set_protect(TrapContext *ctx, 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);
- a_inode *a;
- int err;
- TRACE((_T("ACTION_SET_PROTECT(0x%x,\"%s\",0x%x)\n"), lock, bstr(ctx, unit, name), mask));
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- a = find_aino(ctx, unit, lock, bstr(ctx, unit, name), &err);
- if (err != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- return;
- }
- if (a->softlink) {
- handle_softlink(ctx, unit, packet, a);
- return;
- }
- a->amigaos_mode = mask;
- if (!fsdb_cando (unit))
- a->amigaos_mode = fsdb_mode_supported (a);
- err = fsdb_set_file_attrs (a);
- if (err != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- } else {
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- notify_check(ctx, unit, a);
- gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
- }
- static void action_set_comment(TrapContext *ctx, 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;
- TCHAR *commented = NULL;
- a_inode *a;
- int err;
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- if (fsdb_cando (unit)) {
- commented = bstr(ctx, unit, comment);
- if (_tcslen (commented) > 80) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_COMMENT_TOO_BIG);
- return;
- }
- if (_tcslen (commented) > 0) {
- TCHAR *p = commented;
- commented = xmalloc (TCHAR, 81);
- _tcsncpy (commented, p, 80);
- commented[80] = 0;
- } else {
- commented = NULL;
- }
- }
- TRACE ((_T("ACTION_SET_COMMENT(0x%x,\"%s\")\n"), lock, commented));
- a = find_aino(ctx, unit, lock, bstr(ctx, unit, name), &err);
- if (err != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- maybe_free_and_out:
- if (commented)
- xfree (commented);
- return;
- }
- if (a->softlink) {
- handle_softlink(ctx, unit, packet, a);
- goto maybe_free_and_out;
- }
- 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 && _tcscmp (a->comment, commented) == 0)
- goto maybe_free_and_out;
- if (a->comment)
- xfree (a->comment);
- a->comment = commented;
- fsdb_set_file_attrs (a);
- notify_check(ctx, unit, a);
- gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
- }
- static void action_same_lock(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
- uaecptr lock2 = GET_PCK_ARG2 (packet) << 2;
- TRACE((_T("ACTION_SAME_LOCK(0x%x,0x%x)\n"), lock1, lock2));
- DUMPLOCK(ctx, unit, lock1); DUMPLOCK(ctx, unit, lock2);
- if (!lock1 || !lock2) {
- PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE);
- } else {
- PUT_PCK_RES1 (packet, trap_get_long(ctx, lock1 + 4) == trap_get_long(ctx, lock2 + 4) ? DOS_TRUE : DOS_FALSE);
- }
- }
- static void action_change_mode(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- #define CHANGE_LOCK 0
- #define CHANGE_FH 1
- /* will be CHANGE_FH or CHANGE_LOCK value */
- int 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 *
- * Above is wrong, it is always *_LOCK. TW. */
- int mode = GET_PCK_ARG3 (packet);
- unsigned long uniq;
- a_inode *a = NULL, *olda = NULL;
- int err = 0;
- TRACE((_T("ACTION_CHANGE_MODE(0x%x,%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;
- }
- if (type == CHANGE_LOCK) {
- uniq = trap_get_long(ctx, object + 4);
- } else {
- Key *k = lookup_key (unit, trap_get_long(ctx, object + 36));
- 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);
- }
- }
- static void action_parent_common(TrapContext *ctx, 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);
- return;
- }
- if (olda->parent == 0) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, 0);
- return;
- }
- if (olda->parent->elock) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
- return;
- }
- olda->parent->shlock++;
- de_recycle_aino (unit, olda->parent);
- PUT_PCK_RES1(packet, make_lock(ctx, unit, olda->parent->uniq, -2) >> 2);
- }
- static void action_parent_fh(TrapContext *ctx, 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 (ctx, unit, packet, k->aino->uniq);
- }
- static void action_parent(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- TRACE((_T("ACTION_PARENT(0x%x)\n"),lock));
- if (!lock) {
- PUT_PCK_RES1 (packet, 0);
- PUT_PCK_RES2 (packet, 0);
- } else {
- action_parent_common(ctx, unit, packet, trap_get_long(ctx, lock + 4));
- }
- TRACE((_T("=%x %d\n"), GET_PCK_RES1 (packet), GET_PCK_RES2 (packet)));
- }
- static void action_create_dir(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr name = GET_PCK_ARG2 (packet) << 2;
- a_inode *aino;
- int err;
- TRACE((_T("ACTION_CREATE_DIR(0x%x,\"%s\")\n"), lock, bstr(ctx, unit, name)));
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- aino = find_aino(ctx, unit, lock, bstr(ctx, unit, name), &err);
- if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- return;
- }
- if (err == 0) {
- /* Object exists. */
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS);
- return;
- }
- /* Object does not exist. aino points to containing directory. */
- aino = create_child_aino(unit, aino, my_strdup (bstr_cut(ctx, unit, name)), 1);
- if (aino == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
- return;
- }
- if (my_mkdir (aino->nname) == -1) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- aino->shlock = 1;
- fsdb_set_file_attrs (aino);
- de_recycle_aino (unit, aino);
- notify_check(ctx, unit, aino);
- updatedirtime (aino, 0);
- PUT_PCK_RES1(packet, make_lock(ctx, unit, aino->uniq, -2) >> 2);
- gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
- }
- static void action_examine_fh(TrapContext *ctx, Unit *unit, dpacket *packet, bool largefilesize)
- {
- Key *k;
- a_inode *aino = 0;
- uaecptr info = GET_PCK_ARG2 (packet) << 2;
- TRACE((_T("ACTION_EXAMINE_FH(0x%x,0x%x,%d)\n"),
- GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet), largefilesize ));
- k = lookup_key (unit, GET_PCK_ARG1 (packet));
- if (k != 0)
- aino = k->aino;
- if (aino == 0)
- aino = &unit->rootnode;
- get_fileinfo(ctx, unit, packet, info, aino, largefilesize);
- }
- /* For a nice example of just how contradictory documentation can be, see the
- * Autodoc for DOS:SetFileSize and the Packets.txt description of this packet...
- * 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(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k, *k1;
- off_t offset = GET_PCK_ARG2 (packet);
- int mode = (uae_s32)GET_PCK_ARG3 (packet);
- int whence = SEEK_CUR;
- if (mode > 0)
- whence = SEEK_END;
- if (mode < 0)
- whence = SEEK_SET;
- TRACE((_T("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_AROUND);
- return;
- }
- if (k->aino->vfso) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- /* Fail if file is >=2G, it is not safe operation. */
- if (key_filesize(k) > MAXFILESIZE32_2G) {
- PUT_PCK_RES1 (packet, DOS_TRUE);
- PUT_PCK_RES2 (packet, ERROR_BAD_NUMBER); /* ? */
- return;
- }
- gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
- k->notifyactive = 1;
- /* If any open files have file pointers beyond this size, truncate only
- * so far that these pointers do not become invalid. */
- for (k1 = unit->keys; k1; k1 = k1->next) {
- if (k != k1 && k->aino == k1->aino) {
- if (k1->file_pos > offset)
- offset = (off_t)k1->file_pos;
- }
- }
- /* Write one then truncate: that should give the right size in all cases. */
- fs_lseek (k->fd, offset, whence);
- offset = fs_lseek (k->fd, 0, SEEK_CUR);
- fs_write (k->fd, /* whatever */(uae_u8*)&k1, 1);
- if (k->file_pos > offset)
- k->file_pos = offset;
- fs_lseek (k->fd, (off_t)k->file_pos, SEEK_SET);
- /* 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 (my_truncate (k->aino->nname, offset) == -1) {
- PUT_PCK_RES1 (packet, DOS_TRUE);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- PUT_PCK_RES1 (packet, offset);
- PUT_PCK_RES2 (packet, 0);
- }
- static int relock_do(Unit *unit, a_inode *a1)
- {
- Key *k1, *knext;
- int wehavekeys = 0;
- for (k1 = unit->keys; k1; k1 = knext) {
- knext = k1->next;
- if (k1->aino == a1 && k1->fd) {
- wehavekeys++;
- fs_closefile (k1->fd);
- write_log (_T("handle %p freed\n"), k1->fd);
- }
- }
- return wehavekeys;
- }
- static void relock_re (Unit *unit, a_inode *a1, a_inode *a2, int failed)
- {
- Key *k1, *knext;
- for (k1 = unit->keys; k1; k1 = knext) {
- knext = k1->next;
- if (k1->aino == a1 && k1->fd) {
- int mode = (k1->dosmode & A_FIBF_READ) == 0 ? O_WRONLY : (k1->dosmode & A_FIBF_WRITE) == 0 ? O_RDONLY : O_RDWR;
- mode |= O_BINARY;
- if (failed) {
- /* rename still failed, restore fd */
- k1->fd = fs_openfile (unit, a1, mode);
- write_log (_T("restoring old handle '%s' %d\n"), a1->nname, k1->dosmode);
- } else {
- /* transfer fd to new name */
- if (a2) {
- k1->aino = a2;
- k1->fd = fs_openfile (unit, a2, mode);
- write_log (_T("restoring new handle '%s' %d\n"), a2->nname, k1->dosmode);
- } else {
- write_log (_T("no new handle, deleting old lock(s).\n"));
- }
- }
- if (k1->fd == NULL) {
- write_log (_T("relocking failed '%s' -> '%s'\n"), a1->nname, a2->nname);
- free_key (unit, k1);
- } else {
- key_seek(k1, k1->file_pos, SEEK_SET);
- }
- }
- }
- }
- static void action_delete_object(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr name = GET_PCK_ARG2 (packet) << 2;
- a_inode *a;
- int err;
- TRACE((_T("ACTION_DELETE_OBJECT(0x%x,\"%s\")\n"), lock, bstr(ctx, unit, name)));
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- a = find_aino(ctx, unit, lock, bstr(ctx, unit, name), &err);
- if (err != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- 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->vfso) {
- if (a->dir) {
- /* This should take care of removing the fsdb if no files remain. */
- fsdb_dir_writeback (a);
- if (my_rmdir (a->nname) == -1) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- } else {
- if (my_unlink (a->nname, false) == -1) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- }
- }
- notify_check(ctx, unit, a);
- updatedirtime (a, 1);
- if (a->child != 0) {
- write_log (_T("Serious error in action_delete_object.\n"));
- a->deleted = 1;
- } else {
- delete_aino (unit, a);
- }
- PUT_PCK_RES1 (packet, DOS_TRUE);
- gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
- }
- static void action_set_date(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG2 (packet) << 2;
- uaecptr name = GET_PCK_ARG3 (packet) << 2;
- uaecptr date = GET_PCK_ARG4 (packet);
- a_inode *a;
- struct mytimeval tv;
- int err = 0;
- TRACE((_T("ACTION_SET_DATE(0x%x,\"%s\")\n"), lock, bstr(ctx, unit, name)));
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- a = find_aino(ctx, unit, lock, bstr(ctx, unit, name), &err);
- if (err != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- return;
- }
- if (a->softlink) {
- handle_softlink(ctx, unit, packet, a);
- return;
- }
- if (!a->vfso) {
- amiga_to_timeval (&tv, trap_get_long(ctx, date), trap_get_long(ctx, date + 4), trap_get_long(ctx, date + 8), 50);
- //write_log (_T("%llu.%u (%d,%d,%d) %s\n"), tv.tv_sec, tv.tv_usec, trap_get_long(ctx, date), trap_get_long(ctx, date + 4), trap_get_long(ctx, date + 8), a->nname);
- if (!my_utime (a->nname, &tv))
- err = dos_errno ();
- }
- if (err != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err);
- return;
- } else {
- notify_check(ctx, unit, a);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
- }
- static void action_rename_object(TrapContext *ctx, 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;
- a_inode *a1, *a2;
- int err1, err2;
- Key *k1, *knext;
- int wehavekeys = 0;
- TRACE((_T("ACTION_RENAME_OBJECT(0x%x,\"%s\","), lock1, bstr(ctx, unit, name1)));
- TRACE((_T("0x%x,\"%s\")\n"), lock2, bstr(ctx, unit, name2)));
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- a1 = find_aino(ctx, unit, lock1, bstr(ctx, unit, name1), &err1);
- if (err1 != 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, err1);
- return;
- }
- /* rename always fails if file is open for writing */
- for (k1 = unit->keys; k1; k1 = knext) {
- knext = k1->next;
- if (k1->aino == a1 && k1->fd && k1->createmode == 2) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
- return;
- }
- }
- /* See whether the other name already exists in the filesystem. */
- a2 = find_aino(ctx, unit, lock2, bstr(ctx, unit, name2), &err2);
- if (a2 == a1) {
- /* Renaming to the same name, but possibly different case. */
- if (_tcscmp (a1->aname, bstr_cut(ctx, unit, name2)) == 0) {
- /* Exact match -> do nothing. */
- notify_check(ctx, unit, a1);
- updatedirtime (a1, 1);
- 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;
- }
- a2 = create_child_aino (unit, a2, bstr_cut(ctx, unit, name2), a1->dir);
- if (a2 == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
- return;
- }
- if (!a1->vfso) {
- if (-1 == my_rename (a1->nname, a2->nname)) {
- int ret = -1;
- /* maybe we have open file handles that caused failure? */
- write_log (_T("rename '%s' -> '%s' failed, trying relocking..\n"), a1->nname, a2->nname);
- wehavekeys = relock_do (unit, a1);
- /* try again... */
- ret = my_rename (a1->nname, a2->nname);
- /* restore locks */
- relock_re (unit, a1, a2, ret == -1 ? 1 : 0);
- if (ret == -1) {
- delete_aino (unit, a2);
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- }
- }
- notify_check(ctx, unit, a1);
- notify_check(ctx, unit, a2);
- a2->comment = a1->comment;
- a1->comment = 0;
- a2->amigaos_mode = a1->amigaos_mode;
- a2->uniq = a1->uniq;
- a2->elock = a1->elock;
- a2->shlock = a1->shlock;
- a2->has_dbentry = a1->has_dbentry;
- a2->db_offset = a1->db_offset;
- a2->dirty = 0;
- a2->vfso = a1->vfso;
- move_exkeys (unit, a1, a2);
- move_aino_children (unit, a1, a2);
- delete_aino (unit, a1);
- a2->dirty = 1;
- if (a2->parent)
- fsdb_dir_writeback (a2->parent);
- updatedirtime (a2, 1);
- fsdb_set_file_attrs (a2);
- if (a2->elock > 0 || a2->shlock > 0 || wehavekeys > 0)
- de_recycle_aino (unit, a2);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
- }
- static void action_current_volume(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- if (filesys_isvolume(unit))
- PUT_PCK_RES1 (packet, unit->volume >> 2);
- else
- PUT_PCK_RES1 (packet, 0);
- }
- static void action_rename_disk(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr name = GET_PCK_ARG1 (packet) << 2;
- TRACE((_T("ACTION_RENAME_DISK(\"%s\")\n"), bstr(ctx, unit, name)));
- if (is_writeprotected(unit)) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
- return;
- }
- /* get volume name */
- xfree (unit->ui.volname);
- unit->ui.volname = bstr1(ctx, name);
- set_volume_name(unit, 0);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- static void action_is_filesystem(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- TRACE((_T("ACTION_IS_FILESYSTEM()\n")));
- PUT_PCK_RES1 (packet, DOS_TRUE);
- }
- static void action_flush(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- TRACE((_T("ACTION_FLUSH()\n")));
- PUT_PCK_RES1 (packet, DOS_TRUE);
- flush_cache (unit, 0);
- }
- static void action_more_cache(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- TRACE((_T("ACTION_MORE_CACHE()\n")));
- PUT_PCK_RES1 (packet, 50); /* bug but AmigaOS expects it */
- if (GET_PCK_ARG1 (packet) != 0)
- flush_cache (unit, 0);
- }
- static void action_inhibit(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- int old = unit->inhibited;
- PUT_PCK_RES1 (packet, DOS_TRUE);
- flush_cache (unit, 0);
- unit->inhibited = GET_PCK_ARG1 (packet) != 0;
- TRACE((_T("ACTION_INHIBIT(%d:%d)\n"), unit->unit, unit->inhibited));
- if (unit->ui.canremove && !unit->ui.configureddrive && unit->ui.open && old && !GET_PCK_ARG1(packet)) {
- filesys_delayed_eject(unit);
- }
- }
- static void action_write_protect(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- TRACE((_T("ACTION_WRITE_PROTECT()\n")));
- PUT_PCK_RES1 (packet, DOS_TRUE);
- if (GET_PCK_ARG1 (packet)) {
- if (!unit->ui.locked) {
- unit->ui.locked = true;
- unit->lockkey = GET_PCK_ARG2 (packet);
- }
- } else {
- if (unit->ui.locked) {
- if (unit->lockkey == GET_PCK_ARG2 (packet) || unit->lockkey == 0) {
- unit->ui.locked = false;
- } else {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, 0);
- }
- }
- }
- }
- /* OS4 */
- #define TAG_DONE 0
- #define TAG_IGNORE 1
- #define TAG_MORE 2
- #define TAG_SKIP 3
- static void action_filesystem_attr(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- int versize = 0;
- uaecptr verbuffer = 0;
- uaecptr taglist = GET_PCK_ARG1(packet);
- for (;;) {
- uae_u32 tag = trap_get_long(ctx, taglist);
- uae_u32 tagp = taglist + 4;
- if (tag == TAG_DONE)
- break;
- taglist += 8;
- if (tag == TAG_IGNORE)
- continue;
- if (tag == TAG_MORE) {
- uae_u32 val = trap_get_long(ctx, tagp);
- taglist = val;
- continue;
- }
- if (tag == TAG_SKIP) {
- uae_u32 val = trap_get_long(ctx, tagp);
- taglist += val * 8;
- continue;
- }
- uae_u32 retval = 0;
- bool doret = false;
- switch(tag)
- {
- case 0x80002332: // FSA_MaxFileNameLengthR
- retval = currprefs.filesys_max_name;
- doret = true;
- break;
- case 0x80002334: // FSA_VersionNumberR
- retval = (0 << 16) | (5 << 0);
- doret = true;
- break;
- case 0x80002335: // FSA_DOSTypeR
- retval = get_long(unit->volume + 32);
- doret = true;
- break;
- case 0x80002336: // FSA_ActivityFlushTimeoutR
- case 0x80002338: // FSA_InactivityFlushTimeoutR
- retval = 0;
- doret = true;
- break;
- case 0x8000233a: // FSA_MaxRecycledEntriesR
- case 0x8000233c: // FSA_HasRecycledEntriesR
- retval = 0;
- doret = true;
- break;
- case 0x8000233d: // FSA_VersionStringR
- verbuffer = trap_get_long(ctx, tagp);
- break;
- case 0x8000233e: // FSA_VersionStringR_BufSize
- versize = trap_get_long(ctx, tagp);
- break;
- default:
- write_log(_T("action_filesystem_attr unknown tag %08x\n"), tag);
- PUT_PCK64_RES1(packet, DOS_FALSE);
- PUT_PCK64_RES2(packet, ERROR_NOT_IMPLEMENTED);
- return;
- }
- if (doret)
- trap_put_long(ctx, trap_get_long(ctx, tagp), retval);
-
- }
- if (verbuffer && versize) {
- trap_put_string(ctx, UAEFS_VERSION, verbuffer, versize);
- }
- PUT_PCK_RES1(packet, TRUE);
- PUT_PCK_RES2(packet, 0);
- }
- static void action_change_file_position64(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key (unit, GET_PCK64_ARG1 (packet));
- uae_s64 pos = GET_PCK64_ARG2 (packet);
- int mode = (uae_s32)GET_PCK64_ARG3 (packet);
- long whence = SEEK_CUR;
- uae_s64 res, cur;
- PUT_PCK64_RES0 (packet, DP64_INIT);
- if (k == 0) {
- PUT_PCK64_RES1 (packet, DOS_FALSE);
- PUT_PCK64_RES2 (packet, ERROR_INVALID_LOCK);
- return;
- }
- if (mode > 0)
- whence = SEEK_END;
- if (mode < 0)
- whence = SEEK_SET;
- TRACE((_T("ACTION_CHANGE_FILE_POSITION64(%s,%lld,%d)\n"), k->aino->nname, pos, mode));
- gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
- cur = k->file_pos;
- {
- uae_s64 temppos;
- uae_s64 filesize = key_filesize(k);
- if (whence == SEEK_CUR)
- temppos = cur + pos;
- if (whence == SEEK_SET)
- temppos = pos;
- if (whence == SEEK_END)
- temppos = filesize + pos;
- if (filesize < temppos) {
- res = -1;
- PUT_PCK64_RES1 (packet, res);
- PUT_PCK64_RES2 (packet, ERROR_SEEK_ERROR);
- return;
- }
- }
- res = key_seek(k, pos, whence);
- if (-1 == res) {
- PUT_PCK64_RES1 (packet, DOS_FALSE);
- PUT_PCK64_RES2 (packet, ERROR_SEEK_ERROR);
- } else {
- PUT_PCK64_RES1 (packet, TRUE);
- PUT_PCK64_RES2 (packet, 0);
- k->file_pos = key_seek(k, 0, SEEK_CUR);
- }
- TRACE((_T("= oldpos %lld newpos %lld\n"), cur, k->file_pos));
- }
- static void action_get_file_position64(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key (unit, GET_PCK64_ARG1 (packet));
- PUT_PCK64_RES0 (packet, DP64_INIT);
- if (k == 0) {
- PUT_PCK64_RES1 (packet, -1);
- PUT_PCK64_RES2 (packet, ERROR_INVALID_LOCK);
- return;
- }
- TRACE((_T("ACTION_GET_FILE_POSITION64(%s)=%lld\n"), k->aino->nname, k->file_pos));
- PUT_PCK64_RES1 (packet, k->file_pos);
- PUT_PCK64_RES2 (packet, 0);
- }
- static void action_change_file_size64(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k, *k1;
- uae_s64 offset = GET_PCK64_ARG2 (packet);
- int mode = (uae_s32)GET_PCK64_ARG3 (packet);
- int whence = SEEK_CUR;
- PUT_PCK64_RES0 (packet, DP64_INIT);
- if (mode > 0)
- whence = SEEK_END;
- if (mode < 0)
- whence = SEEK_SET;
- TRACE((_T("ACTION_CHANGE_FILE_SIZE64(0x%x, %lld, 0x%x)\n"), GET_PCK64_ARG1 (packet), offset, mode));
- k = lookup_key (unit, GET_PCK64_ARG1 (packet));
- if (k == 0) {
- PUT_PCK64_RES1 (packet, DOS_FALSE);
- PUT_PCK64_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
- return;
- }
- gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
- k->notifyactive = 1;
- /* If any open files have file pointers beyond this size, truncate only
- * so far that these pointers do not become invalid. */
- for (k1 = unit->keys; k1; k1 = k1->next) {
- if (k != k1 && k->aino == k1->aino) {
- if (k1->file_pos > offset)
- offset = k1->file_pos;
- }
- }
- /* Write one then truncate: that should give the right size in all cases. */
- fs_lseek (k->fd, offset, whence);
- offset = key_seek(k, offset, whence);
- fs_write (k->fd, /* whatever */(uae_u8*)&k1, 1);
- if (k->file_pos > offset)
- k->file_pos = offset;
- key_seek(k, k->file_pos, SEEK_SET);
- if (my_truncate (k->aino->nname, offset) == -1) {
- PUT_PCK64_RES1 (packet, DOS_FALSE);
- PUT_PCK64_RES2 (packet, dos_errno ());
- return;
- }
- PUT_PCK64_RES1 (packet, DOS_TRUE);
- PUT_PCK64_RES2 (packet, 0);
- }
- static void action_get_file_size64(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key (unit, GET_PCK64_ARG1 (packet));
- uae_s64 filesize;
- PUT_PCK64_RES0 (packet, DP64_INIT);
- if (k == 0) {
- PUT_PCK64_RES1 (packet, -1);
- PUT_PCK64_RES2 (packet, ERROR_INVALID_LOCK);
- return;
- }
- TRACE((_T("ACTION_GET_FILE_SIZE64(%s)\n"), k->aino->nname));
- filesize = key_filesize(k);
- TRACE((_T("ACTION_GET_FILE_SIZE64(%s)=%lld\n"), k->aino->nname, filesize));
- if (filesize >= 0) {
- PUT_PCK64_RES1 (packet, filesize);
- PUT_PCK64_RES2 (packet, 0);
- return;
- }
- PUT_PCK64_RES1 (packet, -1);
- PUT_PCK64_RES2 (packet, ERROR_SEEK_ERROR);
- }
- /* MOS */
- static void action_examine_object64(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- uaecptr lock = GET_PCK_ARG1 (packet) << 2;
- uaecptr info = GET_PCK_ARG2 (packet) << 2;
- a_inode *aino = 0;
- TRACE((_T("ACTION_EXAMINE_OBJECT(0x%x,0x%x)\n"), lock, info));
- DUMPLOCK(ctx, unit, lock);
- if (lock != 0)
- aino = aino_from_lock(ctx, unit, lock);
- if (aino == 0)
- aino = &unit->rootnode;
- get_fileinfo(ctx, unit, packet, info, aino, true);
- }
- static void action_set_file_size64(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k, *k1;
- uae_s64 offset = get_quadp(ctx, GET_PCK_ARG2 (packet));
- int mode = (uae_s32)GET_PCK_ARG3 (packet);
- int whence = SEEK_CUR;
- if (mode > 0)
- whence = SEEK_END;
- if (mode < 0)
- whence = SEEK_SET;
- TRACE((_T("ACTION_SET_FILE_SIZE64(0x%x, %lld, 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_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
- return;
- }
- gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
- k->notifyactive = 1;
- /* If any open files have file pointers beyond this size, truncate only
- * so far that these pointers do not become invalid. */
- for (k1 = unit->keys; k1; k1 = k1->next) {
- if (k != k1 && k->aino == k1->aino) {
- if (k1->file_pos > offset)
- offset = k1->file_pos;
- }
- }
- /* Write one then truncate: that should give the right size in all cases. */
- fs_lseek (k->fd, offset, whence);
- offset = key_seek(k, offset, whence);
- fs_write (k->fd, /* whatever */(uae_u8*)&k1, 1);
- if (k->file_pos > offset)
- k->file_pos = offset;
- key_seek(k, k->file_pos, SEEK_SET);
- if (my_truncate (k->aino->nname, offset) == -1) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, dos_errno ());
- return;
- }
- PUT_PCK_RES1 (packet, DOS_TRUE);
- set_quadp(ctx, GET_PCK_ARG4(packet), offset);
- }
- static void action_seek64(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key(unit, GET_PCK_ARG1(packet));
- uae_s64 pos = get_quadp(ctx, GET_PCK64_ARG2(packet));
- int mode = GET_PCK_ARG3(packet);
- long whence = SEEK_CUR;
- uae_s64 res, cur;
- if (k == 0) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
- return;
- }
- if (mode > 0)
- whence = SEEK_END;
- if (mode < 0)
- whence = SEEK_SET;
- TRACE((_T("ACTION_SEEK64(%s,%lld,%d)\n"), k->aino->nname, pos, mode));
- gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
- cur = k->file_pos;
- {
- uae_s64 temppos;
- uae_s64 filesize = key_filesize(k);
- if (whence == SEEK_CUR)
- temppos = cur + 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 = key_seek(k, pos, whence);
- if (-1 == res) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
- } else {
- PUT_PCK_RES1 (packet, TRUE);
- set_quadp(ctx, GET_PCK_ARG3(packet), cur);
- k->file_pos = key_seek(k, 0, SEEK_CUR);
- }
- TRACE((_T("= oldpos %lld newpos %lld\n"), cur, k->file_pos));
- }
- static int action_lock_record64(TrapContext *ctx, Unit *unit, dpacket *packet, uae_u32 msg)
- {
- Key *k = lookup_key(unit, GET_PCK_ARG1(packet));
- uae_u64 pos = get_quadp(ctx, GET_PCK_ARG2(packet));
- uae_u64 len = get_quadp(ctx, GET_PCK_ARG3(packet));
- uae_u32 mode = GET_PCK_ARG4(packet);
- uae_u32 timeout = GET_PCK_ARG5(packet);
- bool exclusive = mode == REC_EXCLUSIVE || mode == REC_EXCLUSIVE_IMMED;
- write_log (_T("action_lock_record64('%s',%lld,%lld,%d,%d)\n"), k ? k->aino->nname : _T("null"), pos, len, mode, timeout);
- if (!k || mode > REC_SHARED_IMMED) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
- return 1;
- }
- if (mode == REC_EXCLUSIVE_IMMED || mode == REC_SHARED_IMMED)
- timeout = 0;
- if (record_hit (unit, k, pos, len, mode)) {
- if (timeout && msg) {
- // queue it and do not reply
- struct lockrecord *lr = new_record (packet, pos, len, mode, timeout, msg);
- if (unit->waitingrecords) {
- lr->next = unit->waitingrecords;
- unit->waitingrecords = lr;
- } else {
- unit->waitingrecords = lr;
- }
- write_log (_T("-> collision, timeout queued\n"));
- return -1;
- }
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_LOCK_COLLISION);
- write_log (_T("-> ERROR_LOCK_COLLISION\n"));
- return 1;
- }
- struct lockrecord *lr = new_record(packet, pos, len, mode, timeout, 0);
- if (k->record) {
- lr->next = k->record;
- k->record = lr;
- } else {
- k->record = lr;
- }
- PUT_PCK_RES1 (packet, DOS_TRUE);
- write_log (_T("-> OK\n"));
- return 1;
- }
- static void action_free_record64(TrapContext *ctx, Unit *unit, dpacket *packet)
- {
- Key *k = lookup_key(unit, GET_PCK_ARG1(packet));
- uae_u64 pos = get_quadp(ctx, GET_PCK_ARG2(packet));
- uae_u64 len = get_quadp(ctx, GET_PCK_ARG3 (packet));
- write_log (_T("action_free_record('%s',%lld,%lld)\n"), k ? k->aino->nname : _T("null"), pos, len);
- if (!k) {
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
- return;
- }
- struct lockrecord *prev = NULL;
- for (struct lockrecord *lr = k->record; lr; lr = lr->next) {
- if (lr->pos == pos && lr->len == len) {
- if (prev)
- prev->next = lr->next;
- else
- k->record = lr->next;
- xfree (lr);
- write_log (_T("->OK\n"));
- record_check_waiting(ctx, unit);
- PUT_PCK_RES1 (packet, DOS_TRUE);
- return;
- }
- }
- write_log (_T("-> ERROR_RECORD_NOT_LOCKED\n"));
- PUT_PCK_RES1 (packet, DOS_FALSE);
- PUT_PCK_RES2 (packet, ERROR_RECORD_NOT_LOCKED);
- }
- static int filesys_shellexecute2_process(int mode, TrapContext *ctx);
- /* We don't want multiple interrupts to be active at the same time. I don't
- * know whether AmigaOS takes care of that, but this does. */
- static uae_sem_t singlethread_int_sem;
- #define SHELLEXEC_MAX_CMD_LEN 512
- static uae_u32 REGPARAM2 exter_int_helper(TrapContext *ctx)
- {
- UnitInfo *uip = mountinfo.ui;
- uaecptr port;
- int n = trap_get_dreg(ctx, 0);
- static int unit_no;
- if (n == 20) {
- // d1 = shellexec process
- shell_execute_process = trap_get_dreg(ctx, 1);
- return 0;
- } else if (n == 21) {
- trap_set_areg(ctx, 0, 0);
- if (comm_pipe_has_data(&shellexecute_pipe)) {
- TCHAR *p = (TCHAR*)read_comm_pipe_pvoid_blocking(&shellexecute_pipe);
- if (p) {
- int maxsize = SHELLEXEC_MAX_CMD_LEN - 1;
- if (shell_execute_data) {
- uae_char *src = ua(p);
- uae_u8 *dst = uaeboard_map_ram(shell_execute_data);
- uae_char *srcp = src;
- while (maxsize-- > 0) {
- uae_u8 v = *srcp++;
- *dst++ = v;
- if (!v)
- break;
- }
- *dst = 0;
- xfree(src);
- }
- trap_set_areg(ctx, 0, shell_execute_data);
- }
- xfree(p);
- }
- return 0;
- } else if (n == 22) {
- // ack
- return 0;
- } else if (n >= 30 && n <= 39) {
- return filesys_shellexecute2_process(n, ctx);
- }
- if (n == 1) {
- /* Release a message_lock. This is called as soon as the message is
- * received by the assembly code. We use the opportunity to check
- * whether we have some locks that we can give back to the assembler
- * code.
- * 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(trap_get_areg(ctx, 5));
- uaecptr msg = trap_get_areg(ctx, 4);
- unit->cmds_complete = unit->cmds_acked;
- while (comm_pipe_has_data(unit->ui.back_pipe)) {
- uaecptr locks, lockend, lockv;
- int cnt = 0;
- locks = read_comm_pipe_int_blocking(unit->ui.back_pipe);
- lockend = locks;
- while ((lockv = trap_get_long(ctx, lockend)) != 0) {
- if (lockv == lockend) {
- write_log(_T("filesystem lock queue corrupted!\n"));
- break;
- }
- lockend = lockv;
- cnt++;
- }
- TRACE3((_T("message_lock: %d %x %x %x\n"), cnt, locks, lockend, trap_get_areg(ctx, 3)));
- trap_put_long(ctx, lockend, trap_get_long(ctx, trap_get_areg(ctx, 3)));
- trap_put_long(ctx, trap_get_areg(ctx, 3), locks);
- }
- }
- #else
- write_log(_T("exter_int_helper should not be called with arg 1!\n"));
- #endif
- return 0;
- }
- if (n == 10) {
- if (uae_sem_trywait(&singlethread_int_sem) != 0) {
- /* Pretend it isn't for us. We might get it again later. */
- do_uae_int_requested();
- return 0;
- }
- filesys_in_interrupt++;
- unit_no = 0;
- }
- if (n >= 10) {
- /* 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
- * d0 = 4: Cause(), interrupt in a1
- * d0 = 5: Send FileNofication message, port in a0, notifystruct in a1
- */
- #ifdef SUPPORT_THREADS
- /* First, check signals/messages */
- while (comm_pipe_has_data(&native2amiga_pending)) {
- int cmd = read_comm_pipe_int_blocking(&native2amiga_pending);
- if (cmd & 0x80) {
- cmd &= ~0x80;
- // tell the sender that message was processed
- UAE_PROCESSED func = (UAE_PROCESSED)read_comm_pipe_pvoid_blocking(&native2amiga_pending);
- func(cmd);
- }
- switch (cmd) {
- case 0: /* Signal() */
- trap_set_areg(ctx, 1, read_comm_pipe_u32_blocking(&native2amiga_pending));
- trap_set_dreg(ctx, 1, read_comm_pipe_u32_blocking(&native2amiga_pending));
- return 2;
- case 1: /* PutMsg() */
- trap_set_areg(ctx, 0, read_comm_pipe_u32_blocking(&native2amiga_pending));
- trap_set_areg(ctx, 1, read_comm_pipe_u32_blocking(&native2amiga_pending));
- return 1;
- case 2: /* ReplyMsg() */
- trap_set_areg(ctx, 1, read_comm_pipe_u32_blocking(&native2amiga_pending));
- return 3;
- case 3: /* Cause() */
- trap_set_areg(ctx, 1, read_comm_pipe_u32_blocking(&native2amiga_pending));
- return 4;
- case 4: /* NotifyHack() */
- trap_set_areg(ctx, 0, read_comm_pipe_u32_blocking(&native2amiga_pending));
- trap_set_areg(ctx, 1, read_comm_pipe_u32_blocking(&native2amiga_pending));
- return 5;
- case 5: /* shell execute */
- {
- TCHAR *p = (TCHAR*)read_comm_pipe_pvoid_blocking(&native2amiga_pending);
- write_comm_pipe_pvoid(&shellexecute_pipe, p, 0);
- if (shell_execute_data) {
- if (!shell_execute_process)
- break;
- trap_set_areg(ctx, 1, shell_execute_process - 92);
- trap_set_dreg(ctx, 1, 1 << 13);
- return 2; // signal process
- }
- shell_execute_data = uaeboard_alloc_ram(SHELLEXEC_MAX_CMD_LEN);
- return 6; // create process
- }
- case 6: /* shell execute 2 */
- {
- trap_set_areg(ctx, 0, read_comm_pipe_u32_blocking(&native2amiga_pending));
- return 7;
- }
- default:
- write_log(_T("exter_int_helper: unknown native action %X\n"), cmd);
- 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 >= MAX_FILESYSTEM_UNITS)
- goto end;
- if (uip[unit_no].open > 0 && 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++;
- }
- uip[unit_no].self->cmds_acked = uip[unit_no].self->cmds_sent;
- port = uip[unit_no].self->port;
- if (port) {
- trap_set_areg(ctx, 0, port);
- trap_set_areg(ctx, 1, find_unit(port)->dummy_message);
- unit_no++;
- return 1;
- }
- end:
- /* Exit the interrupt, and release the single-threading lock. */
- filesys_in_interrupt--;
- uae_sem_post(&singlethread_int_sem);
- }
- return 0;
- }
- static int handle_packet(TrapContext *ctx, Unit *unit, dpacket *pck, uae_u32 msg, int isvolume)
- {
- bool noidle = false;
- int ret = 1;
- uae_s32 type = GET_PCK_TYPE (pck);
- PUT_PCK_RES2 (pck, 0);
- TRACE((_T("unit=%p packet=%d\n"), unit, type));
- if (unit->inhibited && isvolume
- && type != ACTION_INHIBIT && type != ACTION_MORE_CACHE
- && type != ACTION_DISK_INFO) {
- PUT_PCK_RES1 (pck, DOS_FALSE);
- PUT_PCK_RES2 (pck, ERROR_NOT_A_DOS_DISK);
- return 1;
- }
- if (type != ACTION_INHIBIT && type != ACTION_CURRENT_VOLUME
- && type != ACTION_IS_FILESYSTEM && type != ACTION_MORE_CACHE
- && type != ACTION_WRITE_PROTECT && type != ACTION_DISK_INFO
- && !isvolume) {
- PUT_PCK_RES1 (pck, DOS_FALSE);
- PUT_PCK_RES2 (pck, unit->ui.unknown_media ? ERROR_NOT_A_DOS_DISK : ERROR_NO_DISK);
- return 1;
- }
- switch (type) {
- case ACTION_LOCATE_OBJECT: action_lock (ctx, unit, pck); break;
- case ACTION_FREE_LOCK: action_free_lock (ctx, unit, pck); break;
- case ACTION_COPY_DIR: action_dup_lock (ctx, unit, pck); break;
- case ACTION_DISK_INFO: action_disk_info (ctx, unit, pck); break;
- case ACTION_INFO: action_info (ctx, unit, pck); break;
- case ACTION_EXAMINE_OBJECT: action_examine_object (ctx, unit, pck); break;
- case ACTION_EXAMINE_NEXT: noidle = true; action_examine_next (ctx, unit, pck, false); break;
- case ACTION_FIND_INPUT: action_find_input (ctx, unit, pck); break;
- case ACTION_FIND_WRITE: action_find_write (ctx, unit, pck); break;
- case ACTION_FIND_OUTPUT: action_find_output (ctx, unit, pck); break;
- case ACTION_END: action_end (ctx, unit, pck); break;
- case ACTION_READ: noidle = true; action_read(ctx, unit, pck); break;
- case ACTION_WRITE: noidle = true; action_write (ctx, unit, pck); break;
- case ACTION_SEEK: action_seek (ctx, unit, pck); break;
- case ACTION_SET_PROTECT: action_set_protect (ctx, unit, pck); break;
- case ACTION_SET_COMMENT: action_set_comment (ctx, unit, pck); break;
- case ACTION_SAME_LOCK: action_same_lock (ctx, unit, pck); break;
- case ACTION_PARENT: action_parent (ctx, unit, pck); break;
- case ACTION_CREATE_DIR: action_create_dir (ctx, unit, pck); break;
- case ACTION_DELETE_OBJECT: action_delete_object (ctx, unit, pck); break;
- case ACTION_RENAME_OBJECT: action_rename_object (ctx, unit, pck); break;
- case ACTION_SET_DATE: action_set_date (ctx, unit, pck); break;
- case ACTION_CURRENT_VOLUME: action_current_volume (ctx, unit, pck); break;
- case ACTION_RENAME_DISK: action_rename_disk (ctx, unit, pck); break;
- case ACTION_IS_FILESYSTEM: action_is_filesystem (ctx, unit, pck); break;
- case ACTION_FLUSH: action_flush (ctx, unit, pck); break;
- case ACTION_MORE_CACHE: action_more_cache (ctx, unit, pck); break;
- case ACTION_INHIBIT: action_inhibit (ctx, unit, pck); break;
- case ACTION_WRITE_PROTECT: action_write_protect (ctx, unit, pck); break;
- /* 2.0+ packet types */
- case ACTION_SET_FILE_SIZE: action_set_file_size (ctx, unit, pck); break;
- case ACTION_EXAMINE_FH: action_examine_fh (ctx, unit, pck, false); break;
- case ACTION_FH_FROM_LOCK: action_fh_from_lock (ctx, unit, pck); break;
- case ACTION_COPY_DIR_FH: action_lock_from_fh (ctx, unit, pck); break;
- case ACTION_CHANGE_MODE: action_change_mode (ctx, unit, pck); break;
- case ACTION_PARENT_FH: action_parent_fh (ctx, unit, pck); break;
- case ACTION_ADD_NOTIFY: action_add_notify (ctx, unit, pck); break;
- case ACTION_REMOVE_NOTIFY: action_remove_notify (ctx, unit, pck); break;
- case ACTION_EXAMINE_ALL: noidle = true; ret = action_examine_all(ctx, unit, pck); break;
- case ACTION_EXAMINE_ALL_END: ret = action_examine_all_end(ctx, unit, pck); break;
- case ACTION_LOCK_RECORD: ret = action_lock_record (ctx, unit, pck, msg); break;
- case ACTION_FREE_RECORD: action_free_record (ctx, unit, pck); break;
- case ACTION_READ_LINK: action_read_link (ctx, unit, pck); break;
- case ACTION_MAKE_LINK: action_make_link (ctx, unit, pck); break;
- /* OS4 packet types */
- case ACTION_FILESYSTEM_ATTR: action_filesystem_attr(ctx, unit, pck); break;
- case ACTION_CHANGE_FILE_POSITION64: action_change_file_position64 (ctx, unit, pck); break;
- case ACTION_GET_FILE_POSITION64: action_get_file_position64 (ctx, unit, pck); break;
- case ACTION_CHANGE_FILE_SIZE64: action_change_file_size64 (ctx, unit, pck); break;
- case ACTION_GET_FILE_SIZE64: action_get_file_size64 (ctx, unit, pck); break;
- /* MOS packet types */
- case ACTION_SEEK64: action_seek64(ctx, unit, pck); break;
- case ACTION_SET_FILE_SIZE64: action_set_file_size64(ctx, unit, pck); break;
- case ACTION_EXAMINE_OBJECT64: action_examine_object64(ctx, unit, pck); break;
- case ACTION_EXAMINE_NEXT64: noidle = true; action_examine_next(ctx, unit, pck, true); break;
- case ACTION_EXAMINE_FH64: action_examine_fh(ctx, unit, pck, true); break;
- case ACTION_LOCK_RECORD64: ret = action_lock_record64(ctx, unit, pck, msg); break;
- case ACTION_FREE_RECORD64: action_free_record64(ctx, unit, pck); break;
- /* unsupported packets */
- case ACTION_FORMAT:
- write_log (_T("FILESYS: UNSUPPORTED PACKET %x\n"), type);
- return 0;
- default:
- write_log (_T("FILESYS: UNKNOWN PACKET %x\n"), type);
- return 0;
- }
- if (noidle) {
- m68k_cancel_idle();
- }
- return ret;
- }
- #ifdef UAE_FILESYS_THREADS
- static int filesys_iteration(UnitInfo *ui)
- {
- uaecptr pck;
- uaecptr msg;
- uae_u32 morelocks;
- TrapContext *ctx;
- ctx = (TrapContext*)read_comm_pipe_pvoid_blocking(ui->unit_pipe);
- pck = read_comm_pipe_u32_blocking(ui->unit_pipe);
- msg = read_comm_pipe_u32_blocking(ui->unit_pipe);
- morelocks = (uae_u32)read_comm_pipe_int_blocking(ui->unit_pipe);
- if (ui->reset_state == FS_GO_DOWN) {
- trap_background_set_complete(ctx);
- if (pck != 0)
- return 1;
- /* Death message received. */
- uae_sem_post (&ui->reset_sync_sem);
- /* Die. */
- return 0;
- }
- dpacket packet;
- readdpacket(ctx, &packet, pck);
- int isvolume = 0;
- #if TRAPMD
- trapmd md[] = {
- { TRAPCMD_GET_LONG, { morelocks }, 2, 0 },
- { TRAPCMD_GET_LONG, { ui->self->locklist }, 2, 1 },
- { TRAPCMD_PUT_LONG },
- { TRAPCMD_PUT_LONG, { ui->self->locklist, morelocks }},
- { ui->self->volume ? TRAPCMD_GET_BYTE : TRAPCMD_NOP, { ui->self->volume + 64 }},
- };
- trap_multi(ctx, md, sizeof md / sizeof(struct trapmd));
- if (ui->self->volume) {
- isvolume = md[4].params[0] || ui->self->ui.unknown_media;
- }
- #else
- trap_put_long(ctx, trap_get_long(ctx, morelocks), trap_get_long(ctx, ui->self->locklist));
- trap_put_long(ctx, ui->self->locklist, morelocks);
- if (ui->self->volume) {
- isvolume = trap_get_byte(ctx, ui->self->volume + 64) || ui->self->ui.unknown_media;
- }
- #endif
- int ret = handle_packet(ctx, ui->self, &packet, msg, isvolume);
- if (!ret) {
- PUT_PCK_RES1 (&packet, DOS_FALSE);
- PUT_PCK_RES2 (&packet, ERROR_ACTION_NOT_KNOWN);
- }
- writedpacket(ctx, &packet);
- trapmd md2[] = {
- { TRAPCMD_PUT_LONG, { msg + 4, 0xffffffff } },
- { TRAPCMD_GET_LONG, { ui->self->locklist } },
- { TRAPCMD_PUT_LONG, { ui->self->locklist, 0 } }
- };
- struct trapmd *mdp;
- int mdcnt;
- if (ret >= 0) {
- mdp = &md2[0];
- mdcnt = 3;
- /* Mark the packet as processed for the list scan in the assembly code. */
- //trap_put_long(ctx, msg + 4, 0xffffffff);
- } else {
- mdp = &md2[1];
- mdcnt = 2;
- }
- /* Acquire the message lock, so that we know we can safely send the message. */
- ui->self->cmds_sent++;
- /* Send back the locks. */
- trap_multi(ctx, mdp, mdcnt);
- if (md2[1].params[0] != 0)
- write_comm_pipe_int(ui->back_pipe, (int)md2[1].params[0], 0);
- /* The message is sent by our interrupt handler, so make sure an interrupt happens. */
- do_uae_int_requested();
- #if 0
- uae_u32 v = trap_get_long(ctx, ui->self->locklist);
- if (v != 0)
- write_comm_pipe_int (ui->back_pipe, (int)v, 0);
- trap_put_long(ctx, ui->self->locklist, 0);
- #endif
- trap_background_set_complete(ctx);
- return 1;
- }
- static void filesys_thread (void *unit_v)
- {
- UnitInfo *ui = (UnitInfo *)unit_v;
- uae_set_thread_priority (NULL, 1);
- for (;;) {
- if (!filesys_iteration(ui)) {
- return;
- }
- }
- }
- #endif
- /* Talk about spaghetti code... */
- static uae_u32 REGPARAM2 filesys_handler(TrapContext *ctx)
- {
- bool packet_valid = false;
- Unit *unit = find_unit(trap_get_areg(ctx, 5));
- uaecptr packet_addr = trap_get_dreg(ctx, 3);
- uaecptr message_addr = trap_get_areg(ctx, 4);
- if (!trap_valid_address(ctx, packet_addr, 36) || !trap_valid_address(ctx, message_addr, 14)) {
- write_log (_T("FILESYS: Bad address %x/%x passed for packet.\n"), packet_addr, message_addr);
- goto error2;
- }
- if (!unit || !unit->volume) {
- write_log (_T("FILESYS: was not initialized.\n"));
- goto error;
- }
- #ifdef UAE_FILESYS_THREADS
- {
- uae_u32 morelocks;
- if (!unit->ui.unit_pipe)
- goto error;
- /* Get two more locks and hand them over to the other thread. */
- #if TRAPMD
- struct trapmd md[] = {
- // morelocks = trap_get_long(ctx, trap_get_areg(ctx, 3));
- /* 0 */ { TRAPCMD_GET_LONG, { trap_get_areg(ctx, 3) }, 1, 0 },
- // morelocksptr = trap_get_long(ctx, morelocks)
- /* 1 */ { TRAPCMD_GET_LONG, { 0 } },
- // result 1 to index 4
- /* 2 */ { TRAPCMD_NOP, { 0 }, 4, 0 },
- // result 1 to index 6
- /* 3 */ { TRAPCMD_NOP, { 0 }, 6, 0 },
- // trap_get_long(ctx, morelocksptr)
- /* 4 */ { TRAPCMD_GET_LONG, { 0 }, 5, 1 },
- // trap_put_long(ctx, trap_get_areg(ctx, 3), result 4
- /* 5 */ { TRAPCMD_PUT_LONG, { trap_get_areg(ctx, 3) } },
- // trap_put_long(ctx, morelocksptr, 0);
- /* 6 */ { TRAPCMD_PUT_LONG, { 0, 0 } },
- // trap_put_long(ctx, message_addr + 4, 0);
- /* 7 */ { TRAPCMD_PUT_LONG, { message_addr + 4, 0 } }
- };
- trap_multi(ctx, md, sizeof md / sizeof(struct trapmd));
- morelocks = md[0].params[0];
- #else
- uae_u32 morelocksptr;
- morelocks = trap_get_long(ctx, trap_get_areg(ctx, 3));
- morelocksptr = trap_get_long(ctx, morelocks);
- trap_put_long(ctx, trap_get_areg(ctx, 3), trap_get_long(ctx, morelocksptr));
- trap_put_long(ctx, morelocksptr, 0);
- /* The packet wasn't processed yet. */
- trap_put_long(ctx, message_addr + 4, 0);
- #endif
- trap_set_background(ctx);
- write_comm_pipe_pvoid(unit->ui.unit_pipe, ctx, 0);
- write_comm_pipe_u32(unit->ui.unit_pipe, packet_addr, 0);
- write_comm_pipe_u32(unit->ui.unit_pipe, message_addr, 0);
- write_comm_pipe_int(unit->ui.unit_pipe, (int)morelocks, 1);
- /* Don't reply yet. */
- return 1;
- }
- #endif
- dpacket packet;
- readdpacket(ctx, &packet, packet_addr);
- packet_valid = true;
- if (! handle_packet(ctx, unit, &packet, 0, filesys_isvolume(unit))) {
- error:
- if (!packet_valid)
- readdpacket(ctx, &packet, packet_addr);
- PUT_PCK_RES1 (&packet, DOS_FALSE);
- PUT_PCK_RES2 (&packet, ERROR_ACTION_NOT_KNOWN);
- }
- TRACE((_T("reply: %8x, %d\n"), GET_PCK_RES1(&packet), GET_PCK_RES2(&packet)));
- writedpacket(ctx, &packet);
- error2:
- trap_put_long(ctx, message_addr + 4, 0xffffffff);
- return 0;
- }
- void filesys_start_threads (void)
- {
- int i;
- filesys_in_interrupt = 0;
- for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- UnitInfo *ui = &mountinfo.ui[i];
- if (ui->open <= 0)
- continue;
- filesys_start_thread (ui, i);
- }
- }
- void filesys_free_handles (void)
- {
- Unit *u, *u1;
- for (u = units; u; u = u1) {
- Key *k1, *knext;
- u1 = u->next;
- for (k1 = u->keys; k1; k1 = knext) {
- knext = k1->next;
- if (k1->fd)
- fs_closefile (k1->fd);
- xfree (k1);
- }
- u->keys = NULL;
- struct lockrecord *lrnext;
- for (struct lockrecord *lr = u->waitingrecords; lr; lr = lrnext) {
- lrnext = lr->next;
- xfree (lr);
- }
- u->waitingrecords = NULL;
- free_all_ainos (u, &u->rootnode);
- u->rootnode.next = u->rootnode.prev = &u->rootnode;
- u->aino_cache_size = 0;
- xfree (u->newrootdir);
- xfree (u->newvolume);
- u->newrootdir = NULL;
- u->newvolume = NULL;
- }
- }
- static void filesys_reset2 (void)
- {
- Unit *u, *u1;
- filesys_free_handles ();
- for (u = units; u; u = u1) {
- u1 = u->next;
- xfree (u);
- }
- units = 0;
- key_uniq = 0;
- a_uniq = 0;
- free_mountinfo ();
- }
- void filesys_reset (void)
- {
- if (isrestore ())
- return;
- load_injected_icons();
- filesys_reset2 ();
- initialize_mountinfo ();
- shell_execute_data = 0;
- shell_execute_process = 0;
- }
- static void filesys_prepare_reset2 (void)
- {
- UnitInfo *uip;
- int i;
- uip = mountinfo.ui;
- #ifdef UAE_FILESYS_THREADS
- for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- if (uip[i].open > 0 && 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_pvoid(uip[i].unit_pipe, NULL, 0);
- 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);
- uae_end_thread (&uip[i].tid);
- }
- }
- #endif
- filesys_free_handles();
- #if 0
- Unit *u;
- u = units;
- while (u != 0) {
- free_all_ainos (u, &u->rootnode);
- u->rootnode.next = u->rootnode.prev = &u->rootnode;
- u->aino_cache_size = 0;
- u = u->next;
- }
- #endif
- }
- void filesys_prepare_reset (void)
- {
- if (isrestore ())
- return;
- filesys_prepare_reset2 ();
- }
- /* don't forget filesys.asm! */
- #define PP_MAXSIZE 4 * 96
- #define PP_FSSIZE 400
- #define PP_FSPTR 404
- #define PP_ADDTOFSRES 408
- #define PP_FSRES 412
- #define PP_FSRES_CREATED 416
- #define PP_DEVICEPROC 420
- #define PP_EXPLIB 424
- #define PP_FSHDSTART 428
- static int trackdisk_hack_state;
- static int putmsg_hack_state;
- static int putmsg_hack_filesystemtask;
- static uae_u32 ks12hack_deviceproc;
- static bool bcplonlydos(void)
- {
- return kickstart_version && kickstart_version < 33;
- }
- static const uae_u8 bootblock_ofs[] = {
- 0x44,0x4f,0x53,0x00,0xc0,0x20,0x0f,0x19,0x00,0x00,0x03,0x70,0x43,0xfa,0x00,0x18,
- 0x4e,0xae,0xff,0xa0,0x4a,0x80,0x67,0x0a,0x20,0x40,0x20,0x68,0x00,0x16,0x70,0x00,
- 0x4e,0x75,0x70,0xff,0x60,0xfa,0x64,0x6f,0x73,0x2e,0x6c,0x69,0x62,0x72,0x61,0x72,
- 0x79
- };
- static uae_u32 REGPARAM2 filesys_putmsg_return(TrapContext *ctx)
- {
- uaecptr message = trap_get_areg(ctx, 1);
- uaecptr dospacket = trap_get_long(ctx, message + 10);
- UnitInfo *uip = mountinfo.ui;
- if (!ks12hack_deviceproc && uip[0].parmpacket)
- ks12hack_deviceproc = trap_get_long(ctx, uip[0].parmpacket + PP_DEVICEPROC);
- if (ks12hack_deviceproc) {
- uae_u32 port = ks12hack_deviceproc;
- if (port) {
- uaecptr proc = trap_get_long(ctx, trap_get_long(ctx, 4) + 276); // ThisTask
- trap_put_long(ctx, proc + 168, port); // pr_FileSystemTask
- trap_set_areg(ctx, 0, port);
- write_log(_T("Pre-KS 1.3 automount hack: patch boot handler process. DP=%08x Proc %08x pr_FileSystemTask=%08x.\n"), dospacket, proc, port);
- }
- }
- return trap_get_dreg(ctx, 0);
- }
- static uae_u32 REGPARAM2 filesys_putmsg(TrapContext *ctx)
- {
- trap_set_areg(ctx, 7, trap_get_areg(ctx, 7) - 4);
- trap_put_long(ctx, trap_get_areg(ctx, 7), trap_get_long(ctx, ROM_filesys_putmsg_original));
- if (putmsg_hack_state) {
- uaecptr message = trap_get_areg(ctx, 1);
- uaecptr dospacket = trap_get_long(ctx, message + 10);
- if (dospacket && !(dospacket & 3) && trap_valid_address(ctx, dospacket, 48)) {
- int type = trap_get_long(ctx, dospacket + 8);
- // write_log(_T("Port=%08x Msg=%08x DP=%08x dp_Link=%08x dp_Port=%08x dp_Type=%d\n"),
- // m68k_areg(regs, 0), m68k_areg(regs, 1), dospacket, get_long(dospacket), get_long(dospacket + 4), type);
- if (type == ACTION_LOCATE_OBJECT) {
- write_log(_T("Pre-KS 1.3 automount hack: init drives.\n"));
- putmsg_hack_state = 0;
- if (putmsg_hack_filesystemtask) {
- trap_set_areg(ctx, 7, trap_get_areg(ctx, 7) - 4);
- trap_put_long(ctx, trap_get_areg(ctx, 7), ROM_filesys_putmsg_return);
- }
- trap_set_areg(ctx, 7, trap_get_areg(ctx, 7) - 4);
- trap_put_long(ctx, trap_get_areg(ctx, 7), filesys_initcode);
- trap_set_areg(ctx, 7, trap_get_areg(ctx, 7) - 4);
- trap_put_long(ctx, trap_get_areg(ctx, 7), ROM_filesys_hack_remove);
- return trap_get_dreg(ctx, 0);
- }
- }
- }
- return trap_get_dreg(ctx, 0);
- }
- static uae_u32 REGPARAM2 filesys_doio(TrapContext *ctx)
- {
- uaecptr ioreq = trap_get_areg(ctx, 1);
- uaecptr unit = trap_get_long(ctx, ioreq + 24); // io_Unit
- if (trackdisk_hack_state && unit && trap_valid_address(ctx, unit, 14)) {
- uaecptr name = trap_get_long(ctx, unit + 10); // ln_Name
- if (name && trap_valid_address(ctx, name, 20)) {
- uae_u8 *addr = get_real_address(name);
- if (!memcmp(addr, "trackdisk.device", 17)) {
- int cmd = trap_get_word(ctx, ioreq + 28); // io_Command
- uaecptr data = trap_get_long(ctx, ioreq + 40);
- int len = trap_get_long(ctx, ioreq + 36);
- //write_log(_T("%08x %d\n"), ioreq, cmd);
- switch (cmd)
- {
- case 2: // CMD_READ
- {
- // trackdisk.device reading boot block
- uae_u8 *d = get_real_address(data);
- memset(d, 0, 1024);
- memcpy(d, bootblock_ofs, sizeof bootblock_ofs);
- trap_put_long(ctx, ioreq + 32, len); // io_Actual
- trackdisk_hack_state = 0;
- write_log(_T("Pre-KS 1.3 automount hack: DF0: boot block faked.\n"));
- }
- break;
- case 9: // TD_MOTOR
- trap_put_long(ctx, ioreq + 32, trackdisk_hack_state < 0 ? 0 : 1);
- trackdisk_hack_state = len ? 1 : -1;
- break;
- case 13: // TD_CHANGENUM
- trap_put_long(ctx, ioreq + 32, 1); // io_Actual
- break;
- case 14: // TD_CHANGESTATE
- trap_put_long(ctx, ioreq + 32, 0);
- break;
- }
- return 0;
- }
- }
- }
- trap_set_areg(ctx, 7, trap_get_areg(ctx, 7) - 4);
- trap_put_long(ctx, trap_get_areg(ctx, 7), trap_get_long(ctx, ROM_filesys_doio_original));
- return 0;
- }
- static uaecptr add_resident(TrapContext *ctx, uaecptr resaddr, uaecptr myres)
- {
- uaecptr sysbase, reslist, prevjmp, resptr;
- uae_s8 myrespri = trap_get_byte(ctx, myres + 13); // rt_Pri
- sysbase = trap_get_long(ctx, 4);
- prevjmp = 0;
- reslist = trap_get_long(ctx, sysbase + 300); // ResModules
- for (;;) {
- resptr = trap_get_long(ctx, reslist);
- if (!resptr)
- break;
- if (resptr & 0x80000000) {
- prevjmp = reslist;
- reslist = resptr & 0x7fffffff;
- continue;
- }
- uae_s8 respri = trap_get_byte(ctx, resptr + 13); // rt_Pri
- uaecptr resname = trap_get_long(ctx, resptr + 14); // rt_Name
- if (resname) {
- uae_char resnamebuf[256];
- trap_get_string(ctx, resnamebuf, resname, sizeof resnamebuf);
- if (myrespri >= respri)
- break;
- }
- prevjmp = 0;
- reslist += 4;
- }
- if (prevjmp) {
- trap_put_long(ctx, prevjmp, 0x80000000 | resaddr);
- } else {
- trap_put_long(ctx, reslist, 0x80000000 | resaddr);
- }
- trap_put_long(ctx, resaddr, myres);
- trap_put_long(ctx, resaddr + 4, resptr);
- trap_put_long(ctx, resaddr + 8, 0x80000000 | (reslist + 4));
- resaddr += 3 * 4;
- return resaddr;
- }
- static uae_u32 REGPARAM2 filesys_diagentry (TrapContext *ctx)
- {
- UnitInfo *uip = mountinfo.ui;
- uaecptr resaddr = trap_get_areg(ctx, 2);
- uaecptr expansion = trap_get_areg(ctx, 5);
- uaecptr first_resident, last_resident, tmp;
- uaecptr resaddr_hack = 0;
- uae_u8 *baseaddr;
- filesys_configdev = trap_get_areg(ctx, 3);
- if (currprefs.uaeboard > 1) {
- baseaddr = uaeboard_bank.baseaddr;
- resaddr += 0x100;
- } else {
- baseaddr = filesys_bank.baseaddr;
- resaddr += 0x10;
- }
- if (baseaddr) {
- put_long_host(baseaddr + 0x2100, EXPANSION_explibname);
- put_long_host(baseaddr + 0x2104, filesys_configdev);
- put_long_host(baseaddr + 0x2108, EXPANSION_doslibname);
- put_word_host(baseaddr + 0x210c, 0);
- put_word_host(baseaddr + 0x210e, nr_units());
- put_word_host(baseaddr + 0x2110, 0);
- put_word_host(baseaddr + 0x2112, 1 | (currprefs.uae_hide_autoconfig || currprefs.uaeboard > 1 ? 16 : 0));
- }
- native2amiga_startup();
- write_log (_T("filesystem: diagentry %08x configdev %08x\n"), resaddr, filesys_configdev);
- first_resident = resaddr;
- if (ROM_hardfile_resid != 0) {
- /* Build a struct Resident. This will set up and initialize
- * the uae.device */
- trap_put_word(ctx, resaddr + 0x0, 0x4AFC);
- trap_put_long(ctx, resaddr + 0x2, resaddr);
- trap_put_long(ctx, resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
- trap_put_word(ctx, resaddr + 0xA, 0x8132); /* RTF_AUTOINIT|RTF_COLDSTART; Version 50 */
- trap_put_word(ctx, resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
- trap_put_long(ctx, resaddr + 0xE, ROM_hardfile_resname);
- trap_put_long(ctx, resaddr + 0x12, ROM_hardfile_resid);
- trap_put_long(ctx, resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */
- }
- resaddr += 0x1A;
- if (!KS12_BOOT_HACK || expansion)
- first_resident = resaddr;
- /* 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.
- * 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 inject them to ResList in priority order
- */
- // KS 2.x RTF_AFTERDOS is broken
- if (kickstart_version >= 39) {
- trap_put_word(ctx, resaddr + 0x0, 0x4afc);
- trap_put_long(ctx, resaddr + 0x2, resaddr);
- trap_put_long(ctx, resaddr + 0x6, resaddr + 0x1A);
- trap_put_word(ctx, resaddr + 0xA, 0x0432); /* RTF_AFTERDOS; Version 50 */
- trap_put_word(ctx, resaddr + 0xC, 0x0000 | AFTERDOS_INIT_PRI); /* NT_UNKNOWN; pri */
- trap_put_long(ctx, resaddr + 0xE, afterdos_name);
- trap_put_long(ctx, resaddr + 0x12, afterdos_id);
- trap_put_long(ctx, resaddr + 0x16, afterdos_initcode);
- resaddr += 0x1A;
- }
- resaddr = uaeres_startup(ctx, resaddr);
- #ifdef BSDSOCKET
- resaddr = bsdlib_startup(ctx, resaddr);
- #endif
- #ifdef WITH_UAENATIVE
- resaddr = uaenative_startup(ctx, resaddr);
- #endif
- #ifdef SCSIEMU
- resaddr = scsidev_startup(ctx, resaddr);
- #endif
- #ifdef SANA2
- resaddr = netdev_startup(ctx, resaddr);
- #endif
- #ifdef UAESERIAL
- resaddr = uaeserialdev_startup(ctx, resaddr);
- #endif
- #ifdef WITH_TABLETLIBRARY
- resaddr = tabletlib_startup(ctx, resaddr);
- #endif
- #ifdef RETROPLATFORM
- if (rp_isactive()) {
- trap_put_word(ctx, resaddr + 0x0, 0x4afc);
- trap_put_long(ctx, resaddr + 0x2, resaddr);
- trap_put_long(ctx, resaddr + 0x6, resaddr + 0x1A);
- trap_put_word(ctx, resaddr + 0xA, 0x0100); /* RTF_COLDSTART; Version 0 */
- trap_put_word(ctx, resaddr + 0xC, 0x0000); /* NT_UNKNOWN; pri */
- trap_put_long(ctx, resaddr + 0xE, keymaphook_name);
- trap_put_long(ctx, resaddr + 0x12, keymaphook_id);
- trap_put_long(ctx, resaddr + 0x16, keymaphook_initcode);
- resaddr += 0x1A;
- }
- #endif
- last_resident = resaddr;
- /* call setup_exter */
- trap_put_word(ctx, resaddr + 0, 0x7000 | (currprefs.uaeboard > 1 ? 3 : 1)); /* moveq #x,d0 */
- trap_put_word(ctx, resaddr + 2, 0x2079); /* move.l RTAREA_BASE+setup_exter,a0 */
- trap_put_long(ctx, resaddr + 4, rtarea_base + bootrom_header + 4 + 5 * 4);
- trap_put_word(ctx, resaddr + 8, 0xd1fc); /* add.l #RTAREA_BASE+bootrom_header,a0 */
- trap_put_long(ctx, resaddr + 10, rtarea_base + bootrom_header);
- trap_put_word(ctx, resaddr + 14, 0x4e90); /* jsr (a0) */
- resaddr += 16;
- trackdisk_hack_state = 0;
- putmsg_hack_state = 0;
- putmsg_hack_filesystemtask = 0;
- ks12hack_deviceproc = 0;
- if (KS12_BOOT_HACK && nr_units() && filesys_configdev == 0 && baseaddr) {
- resaddr_hack = resaddr;
- putmsg_hack_state = -1;
- if (uip[0].bootpri > -128) {
- resaddr += 2 * 22;
- trackdisk_hack_state = -1;
- putmsg_hack_filesystemtask = 1;
- } else {
- resaddr += 1 * 22;
- }
- }
- trap_put_word(ctx, resaddr + 0, 0x7001); /* moveq #1,d0 */
- trap_put_word(ctx, resaddr + 2, RTS);
- resaddr += 4;
- ROM_filesys_doio_original = resaddr;
- ROM_filesys_putmsg_original = resaddr + 4;
- resaddr += 8;
- ROM_filesys_hack_remove = resaddr;
- if (putmsg_hack_state) {
- // remove patches
- put_long(resaddr + 0, 0x48e7fffe); // movem.l d0-d7/a0-a6,-(sp)
- put_word(resaddr + 4, 0x224e); // move.l a6,a1
- resaddr += 6;
- if (trackdisk_hack_state) {
- put_word(resaddr + 0, 0x307c); // move.w #x,a0
- put_word(resaddr + 2, -0x1c8);
- put_word(resaddr + 4, 0x2039); // move.l x,d0
- put_long(resaddr + 6, ROM_filesys_doio_original);
- put_word(resaddr + 10, 0x4eae); // jsr x(a6)
- put_word(resaddr + 12, -0x1a4);
- resaddr += 14;
- }
- put_word(resaddr + 0, 0x307c); // move.w #x,a0
- put_word(resaddr + 2, -0x16e);
- put_word(resaddr + 4, 0x2039); // move.l x,d0
- put_long(resaddr + 6, ROM_filesys_putmsg_original);
- put_word(resaddr + 10, 0x4eae); // jsr x(a6)
- put_word(resaddr + 12, -0x1a4);
- resaddr += 14;
- put_long(resaddr + 0, 0x4cdf7fff); // movem.l (sp)+,d0-d7/a0-a6
- resaddr += 4;
- uaecptr temp = here();
- org(filesys_initcode_ptr);
- dl(resaddr);
- org(temp);
- put_word(resaddr, 0x4e75); // rts
- resaddr += 2;
- uaecptr resaddr_tmp = resaddr;
- resaddr = resaddr_hack;
- if (trackdisk_hack_state) {
- // Pre-KS 1.3 trackdisk.device boot block injection hack. Patch DoIO()
- put_word(resaddr + 0, 0x224e); // move.l a6,a1
- put_word(resaddr + 2, 0x307c); // move.w #x,a0
- put_word(resaddr + 4, -0x1c8);
- put_word(resaddr + 6, 0x203c); // move.l #x,d0
- put_long(resaddr + 8, ROM_filesys_doio);
- put_word(resaddr + 12, 0x4eae); // jsr x(a6)
- put_word(resaddr + 14, -0x1a4);
- put_word(resaddr + 16, 0x23c0); // move.l d0,x
- put_long(resaddr + 18, ROM_filesys_doio_original);
- resaddr += 22;
- }
- // Pre-KS 1.3 automount hack. Patch PutMsg()
- put_word(resaddr + 0, 0x224e); // move.l a6,a1
- put_word(resaddr + 2, 0x307c); // move.w #x,a0
- put_word(resaddr + 4, -0x16e);
- put_word(resaddr + 6, 0x203c); // move.l #x,d0
- put_long(resaddr + 8, ROM_filesys_putmsg);
- put_word(resaddr + 12, 0x4eae); // jsr x(a6)
- put_word(resaddr + 14, -0x1a4);
- put_word(resaddr + 16, 0x23c0); // move.l d0,x
- put_long(resaddr + 18, ROM_filesys_putmsg_original);
- resaddr += 22;
- // filesys.asm make_dev D7
- put_word_host(baseaddr + 0x2112, 1 | 2 | 8 | 16);
- resaddr = resaddr_tmp;
- } else {
- // undo possible KS 1.2 hack
- uaecptr temp = here();
- org(filesys_initcode_ptr);
- dl(filesys_initcode_real);
- org(temp);
- }
- trap_set_areg(ctx, 0, last_resident);
-
- if (currprefs.uae_hide_autoconfig && expansion) {
- bool found = true;
- while (found) {
- uaecptr node = trap_get_long(ctx, expansion + 0x3c);
- found = false;
- while (trap_get_long(ctx, node)) {
- if (trap_get_word(ctx, node + 0x10 + 4) == 2011) {
- uae_u8 prod = trap_get_byte(ctx, node + 0x10 + 1);
- if (prod != 2) {
- // remove all 2011 boards except filesystem
- found = true;
- uaecptr succ = trap_get_long(ctx, node);
- uaecptr pred = trap_get_long(ctx, node + 4);
- trap_put_long(ctx, pred, succ);
- trap_put_long(ctx, succ + 4, pred);
- break;
- }
- // replace filesystem with A590/A2091 IDs..
- trap_put_byte(ctx, node + 0x10 + 1, 3);
- trap_put_word(ctx, node + 0x10 + 4, 514);
- }
- node = trap_get_long(ctx, node);
- }
- }
- }
- tmp = first_resident;
- while (tmp < last_resident && tmp >= first_resident) {
- if (trap_get_word(ctx, tmp) == 0x4AFC && trap_get_long(ctx, tmp + 0x2) == tmp) {
- resaddr = add_resident(ctx, resaddr, tmp);
- tmp = trap_get_long(ctx, tmp + 0x6);
- } else {
- tmp += 2;
- }
- }
- return 1;
- }
- #define FS_TEST_HACK 0
- #if FS_TEST_HACK
- static uae_u32 REGPARAM2 ks13patchstartup(TrapContext *ctx)
- {
- uaecptr startup = trap_get_areg(ctx, 0);
- uaecptr doslib = 0x00c06230;
- uaecptr root = get_long(doslib + 34);
- uaecptr node = (get_long(root + 24) << 2) + 4;
- uaecptr dp_arg2 = get_long(startup + 24);
- for (;;) {
- node = get_long(node) << 2;
- if (!node)
- break;
- if (get_long(node + 4) != 0)
- continue;
- if (get_long(node + 28) != dp_arg2)
- continue;
- put_long(startup + 20, get_long(node + 40)); // dp_Arg1 = dol_Node
- put_long(startup + 28, node >> 2); // dp_Arg3 = dl
- activate_debugger();
- return dp_arg2 << 2;
- }
- return 0;
- }
- static void patchhackfs(uaecptr seg)
- {
- int o = rtarea_base + 0xFEFA;
- put_long(seg + 9806, 0x70ff70ff);
- seg += 9632;
- put_word(seg, 0x4eb9);
- put_long(seg + 2, o);
- put_word(seg + 6, 0x2440); // move.l d0,a2
- org(o);
- calltrap(deftrap2(ks13patchstartup, 0, _T("ks13patchstartup")));
- dw(RTS);
- }
- #endif
- static uae_u32 REGPARAM2 filesys_dev_bootfilesys (TrapContext *ctx)
- {
- uaecptr devicenode = trap_get_areg(ctx, 3);
- uaecptr parmpacket = trap_get_areg(ctx, 1);
- uaecptr fsres = trap_get_long(ctx, parmpacket + PP_FSRES);
- uaecptr fsnode;
- uae_u32 dostype, dostype2;
- int no = trap_get_dreg(ctx, 6) & 0x7fffffff;
- int unit_no = no & 65535;
- UnitInfo *uip = &mountinfo.ui[unit_no];
- int iscd = (trap_get_dreg(ctx, 6) & 0x80000000) != 0 || uip->unit_type == UNIT_CDFS;
- int type;
-
- if (iscd) {
- if (!trap_get_long(ctx, devicenode + 16))
- trap_put_long(ctx, devicenode + 16, cdfs_handlername);
- return 0;
- } else {
- type = is_hardfile (unit_no);
- }
- if (type == FILESYS_VIRTUAL) {
- if (!trap_get_long(ctx, devicenode + 16))
- trap_put_long(ctx, devicenode + 16, fshandlername);
- return 0;
- }
- dostype = trap_get_long(ctx, parmpacket + 80);
- if (trap_get_long(ctx, parmpacket + PP_FSPTR) && !trap_get_long(ctx, parmpacket + PP_ADDTOFSRES)) {
- uaecptr fsptr = trap_get_long(ctx, parmpacket + PP_FSPTR);
- uip->filesysseg = fsptr;
- // filesystem but was not added to fs.resource
- uae_u32 pf = trap_get_long(ctx, parmpacket + PP_FSHDSTART + 8); // fse_PatchFlags
- for (int i = 0; i < 32; i++) {
- if (pf & (1 << i))
- trap_put_long(ctx, devicenode + 4 + i * 4, trap_get_long(ctx, parmpacket + PP_FSHDSTART + 8 + 4 + i * 4));
- }
- uaecptr seglist = fsptr >> 2;
- if (bcplonlydos()) {
- trap_put_long(ctx, devicenode + 4 + 3 * 4, seglist);
- seglist = (trap_get_long(ctx, rtarea_base + bootrom_header + 4 + 6 * 4) + rtarea_base + bootrom_header) >> 2;
- }
- trap_put_long(ctx, devicenode + 4 + 7 * 4, seglist);
- write_log(_T("Filesys %08x entry=%08x\n"), dostype, fsptr);
- return 1;
- }
- fsnode = trap_get_long(ctx, fsres + 18);
- while (trap_get_long(ctx, fsnode)) {
- dostype2 = trap_get_long(ctx, fsnode + 14);
- if (dostype2 == dostype) {
- uae_u32 pf = trap_get_long(ctx, fsnode + 22); // fse_PatchFlags
- for (int i = 0; i < 32; i++) {
- if (pf & (1 << i)) {
- uae_u32 data = trap_get_long(ctx, fsnode + 22 + 4 + i * 4);
- if (i == 7) {
- if (bcplonlydos()) { // seglist
- // point seglist to bcpl wrapper and put original seglist in dn_Handler
- trap_put_long(ctx, devicenode + 4 + 3 * 4, trap_get_long(ctx, fsnode + 22 + 4 + 7 * 4));
- data = (trap_get_long(ctx, rtarea_base + bootrom_header + 4 + 6 * 4) + rtarea_base + bootrom_header) >> 2;
- }
- write_log(_T("Filesys %08x entry=%08x\n"), dostype, data << 2);
- #if FS_TEST_HACK
- patchhackfs(data << 2);
- #endif
- }
- trap_put_long(ctx, devicenode + 4 + i * 4, data);
- }
- }
- return 1;
- }
- fsnode = trap_get_long(ctx, fsnode);
- }
- if (type == FILESYS_HARDFILE) {
- uae_u32 pf = trap_get_long(ctx, parmpacket + PP_FSHDSTART + 8); // fse_PatchFlags
- for (int i = 0; i < 32; i++) {
- if (pf & (1 << i))
- trap_put_long(ctx, devicenode + 4 + i * 4, trap_get_long(ctx, parmpacket + PP_FSHDSTART + 8 + 4 + i * 4));
- }
- trap_put_long(ctx, devicenode + 4 + 7 * 4, 0); // seglist
- }
- uaecptr file_system_proc = trap_get_dreg(ctx, 1);
- if (bcplonlydos() && file_system_proc && trap_get_long(ctx, devicenode + 4 + 7 * 4) == 0) {
- // 1.1 or older, seglist == 0: get ROM OFS seglist from "File System" process.
- // 1.2 and newer automatically use ROM OFS if seglist is zero.
- // d1 = "File System" process pointer.
- uaecptr p = trap_get_long(ctx, file_system_proc + 0x80) << 2; // pr_SegList
- if (p) {
- uae_u32 cnt = trap_get_long(ctx, p);
- if (cnt > 0 && cnt < 16) {
- uaecptr handlerseg = trap_get_long(ctx, p + cnt * 4);
- write_log(_T("Pre-KS 1.2 handler segment %08x.\n"), handlerseg << 2);
- trap_put_long(ctx, devicenode + 4 + 7 * 4, handlerseg);
- }
- }
- }
- return 0;
- }
- // called from bcplwrapper
- static uae_u32 REGPARAM2 filesys_bcpl_wrapper(TrapContext *ctx)
- {
- const int patches[] = { 0x782, 0x7b8, 0x159c, 0x15b4, 0 };
- uaecptr devicenode = trap_get_long(ctx, trap_get_dreg(ctx, 1) + 0x1c) << 2;
- // fetch original seglist from dn_Handler
- uaecptr seglist = trap_get_long(ctx, devicenode + 4 + 3 * 4) << 2;
- uaecptr patchfunc = trap_get_areg(ctx, 1);
- seglist += 4;
- trap_set_areg(ctx, 0, seglist);
- for (int i = 0; patches[i]; i++) {
- int offset = patches[i];
- if (get_long(seglist + offset + 2) != 0x4eaefd90) {
- write_log(_T("FFS patch failed, comparison mismatch.\n"));
- return 0;
- }
- }
- for (int i = 0; patches[i]; i++) {
- int offset = patches[i];
- trap_put_word(ctx, seglist + offset, 0x4eb9);
- trap_put_long(ctx, seglist + offset + 2, patchfunc);
- patchfunc += 4;
- }
- uae_u16 ver = trap_get_word(ctx, trap_get_areg(ctx, 6) + 20);
- if (ver < 31) {
- // OpenLibrary -> OldOpenLibrary
- trap_put_word(ctx, seglist + 0x7f4, -0x198);
- trap_put_word(ctx, seglist + 0x2a6e, -0x198);
- }
- write_log(_T("FFS pre-1.2 patched\n"));
- return 0;
- }
- static uae_u32 REGPARAM2 filesys_init_storeinfo (TrapContext *ctx)
- {
- int ret = -1;
- switch (trap_get_dreg(ctx, 1))
- {
- case 1:
- mountertask = trap_get_areg(ctx, 1);
- #ifdef PICASSO96
- picasso96_alloc(ctx);
- #endif
- break;
- case 2: // new unit number query
- ret = automountunit;
- automountunit = -2;
- break;
- case 3:
- return 0;
- case 4: // mount done (d0=automountunit)
- automountunit = -1;
- return 0;
- }
- return ret;
- }
- /* 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 REGPARAM2 filesys_dev_remember (TrapContext *ctx)
- {
- int no = trap_get_dreg(ctx, 6) & 0x7fffffff;
- int unit_no = no & 65535;
- int sub_no = no >> 16;
- UnitInfo *uip = &mountinfo.ui[unit_no];
- int iscd = (trap_get_dreg(ctx, 6) & 0x80000000) != 0 || uip->unit_type == UNIT_CDFS;
- uaecptr devicenode = trap_get_areg(ctx, 3);
- uaecptr parmpacket = trap_get_areg(ctx, 1);
- int fssize;
- uae_u8 *fs;
- uip->devicenode = devicenode;
- fssize = uip->rdb_filesyssize;
- fs = uip->rdb_filesysstore;
- /* copy filesystem loaded from RDB */
- if (trap_get_long(ctx, parmpacket + PP_FSPTR)) {
- uaecptr addr = trap_get_long(ctx, parmpacket + PP_FSPTR);
- trap_put_bytes(ctx, fs, addr, fssize);
- // filesystem debugging, negative FSSIZE = debug mode.
- if (segtrack_mode & 2) {
- trap_put_long(ctx, parmpacket + PP_FSSIZE, -trap_get_long(ctx, parmpacket + PP_FSSIZE));
- }
- }
- xfree (fs);
- uip->rdb_filesysstore = 0;
- uip->rdb_filesyssize = 0;
- if (trap_get_dreg(ctx, 3) >= 0)
- uip->startup = trap_get_long(ctx, devicenode + 28);
- return devicenode;
- }
- static int legalrdbblock (UnitInfo *uip, int block)
- {
- if (block <= 0)
- return 0;
- if (block >= uip->hf.virtsize / uip->hf.ci.blocksize)
- return 0;
- return 1;
- }
- static uae_u32 rl (uae_u8 *p)
- {
- return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
- }
- static uae_u16 rw (uae_u8 *p)
- {
- return (p[0] << 8) | (p[1]);
- }
- static int rdb_checksum (const uae_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) {
- TCHAR *s = au (id);
- write_log (_T("RDB: block %d ('%s') checksum error\n"), block, s);
- xfree (s);
- return 0;
- }
- return 1;
- }
- static int device_isdup (TrapContext *ctx, uaecptr expbase, TCHAR *devname)
- {
- uaecptr bnode, dnode, name;
- int len, i;
- TCHAR dname[256];
- if (!expbase)
- return 0;
- bnode = trap_get_long(ctx, expbase + 74); /* expansion.library bootnode list */
- while (trap_get_long(ctx, bnode)) {
- dnode = trap_get_long(ctx, bnode + 16); /* device node */
- name = trap_get_long(ctx, dnode + 40) << 2; /* device name BSTR */
- len = trap_get_byte(ctx, name);
- for (i = 0; i < len; i++)
- dname[i] = trap_get_byte(ctx, name + 1 + i);
- dname[len] = 0;
- if (!_tcsicmp(devname, dname))
- return 1;
- bnode = trap_get_long(ctx, bnode);
- }
- return 0;
- }
- static TCHAR *device_dupfix (TrapContext *ctx, uaecptr expbase, TCHAR *devname)
- {
- int modified;
- TCHAR newname[256];
- _tcscpy (newname, devname);
- modified = 1;
- while (modified) {
- modified = 0;
- if (device_isdup (ctx, expbase, newname)) {
- if (_tcslen (newname) > 2 && newname[_tcslen (newname) - 2] == '_') {
- newname[_tcslen (newname) - 1]++;
- } else {
- _tcscat (newname, _T("_0"));
- }
- modified = 1;
- }
- }
- return my_strdup (newname);
- }
- static const TCHAR *dostypes(TCHAR *dt, uae_u32 dostype)
- {
- int j;
- j = 0;
- for (int i = 0; i < 4; i++) {
- uae_u8 c = dostype >> ((3 - i) * 8);
- if (c >= ' ' && c <= 'z') {
- dt[j++] = c;
- } else {
- dt[j++] = '\\';
- _stprintf (&dt[j], _T("%d"), c);
- j += _tcslen (&dt[j]);
- }
- }
- dt[j] = 0;
- return dt;
- }
- static void dump_partinfo (struct hardfiledata *hfd, uae_u8 *pp)
- {
- TCHAR *s;
- uae_u32 dostype;
- uae_u64 size;
- int blocksize, surfaces, spb, spt, reserved;
- int lowcyl, highcyl;
- uae_u32 block, flags;
- uae_u8 buf[512];
- TCHAR dt[32];
- flags = rl (pp + 20);
- pp[37 + pp[36]] = 0;
- s = au ((char*)pp + 37);
- pp += 128;
- dostype = rl (pp + 64);
- spb = rl (pp + 16);
- blocksize = rl (pp + 4) * 4;
- surfaces = rl (pp + 12);
- spt = rl (pp + 20);
- reserved = rl (pp + 24);
- lowcyl = rl (pp + 36);
- highcyl = rl (pp + 40);
- size = ((uae_u64)blocksize) * surfaces * spt * (highcyl - lowcyl + 1);
- write_log (_T("Partition '%s' Dostype=%08X (%s) Flags: %08X\n"), s[0] ? s : _T("_NULL_"), dostype, dostypes (dt, dostype), flags);
- write_log (_T("BlockSize: %d, Surfaces: %d, SectorsPerBlock %d\n"),
- blocksize, surfaces, spb);
- write_log (_T("SectorsPerTrack: %d, Reserved: %d, LowCyl %d, HighCyl %d, Size %dM\n"),
- spt, reserved, lowcyl, highcyl, (uae_u32)(size >> 20));
- write_log (_T("Buffers: %d, BufMemType: %08x, MaxTransfer: %08x, Mask: %08x, BootPri: %d\n"),
- rl (pp + 44), rl (pp + 48), rl (pp + 52), rl (pp + 56), rl (pp + 60));
- write_log (_T("Total blocks: %lld, Total disk blocks: %lld\n"), (uae_s64)surfaces * spt * (highcyl - lowcyl + 1), hfd->virtsize / blocksize);
- if (hfd->drive_empty) {
- write_log (_T("Empty drive\n"));
- } else {
- block = lowcyl * surfaces * spt;
- if (hdf_read (hfd, buf, (uae_u64)blocksize * block, sizeof buf)) {
- write_log (_T("First block %d dostype: %08X (%s)\n"), block, rl (buf), dostypes (dt, rl (buf)));
- } else {
- write_log (_T("First block %d read failed!\n"), block);
- }
- xfree (s);
- if ((uae_u64)highcyl * spt * surfaces * blocksize > hfd->virtsize) {
- write_log (_T("RDB: WARNING: end of partition > size of disk! (%llu > %llu)\n"),
- (uae_u64)highcyl * spt * surfaces * blocksize, hfd->virtsize);
- }
- }
- }
- static void dumprdbblock(const uae_u8 *buf, int block)
- {
- int w = 16;
- write_log(_T("RDB block %d:\n"), block);
- for (int i = 0; i < 512; i += w) {
- TCHAR outbuf[81];
- for (int j = 0; j < w; j++) {
- uae_u8 v = buf[i + j];
- _stprintf(outbuf + 2 * j, _T("%02X"), v);
- outbuf[2 * w + 1 + j] = (v >= 32 && v <= 126) ? v : '.';
- }
- outbuf[2 * w] = ' ';
- outbuf[2 * w + 1 + w] = 0;
- write_log(_T("%s\n"), outbuf);
- }
- }
- static void dump_rdb (UnitInfo *uip, struct hardfiledata *hfd, uae_u8 *bufrdb, uae_u8 *buf, int readblocksize)
- {
- TCHAR dt[32];
- write_log (_T("RDB: HostID: %08x Flags: %08x\n"),
- rl (bufrdb + 3 * 4), rl (bufrdb + 5 * 4));
- write_log (_T("RDB: BL: %d BH: %d LC: %d HC: %d CB: %d HB: %d\n"),
- rl (bufrdb + 128), rl (bufrdb + 132), rl (bufrdb + 136), rl (bufrdb + 140), rl (bufrdb + 144), rl (bufrdb + 152));
- for (int i = 0; i < 100; i++) {
- int partblock;
- if (i == 0)
- partblock = rl (bufrdb + 28);
- else
- partblock = rl (buf + 4 * 4);
- if (partblock == 0xffffffff)
- break;
- write_log (_T("RDB: PART block %d:\n"), partblock);
- if (!legalrdbblock (uip, partblock)) {
- write_log (_T("RDB: corrupt PART pointer %d\n"), partblock);
- dumprdbblock(i == 0 ? bufrdb : buf, partblock);
- break;
- }
- memset (buf, 0, readblocksize);
- hdf_read (hfd, buf, partblock * hfd->ci.blocksize, readblocksize);
- if (!rdb_checksum ("PART", buf, partblock)) {
- write_log (_T("RDB: checksum error PART block %d\n"), partblock);
- dumprdbblock(buf, partblock);
- break;
- }
- dump_partinfo (hfd, buf);
- }
- for (int i = 0; i < 100; i++) {
- int fileblock;
- if (i == 0)
- fileblock = rl (bufrdb + 32);
- else
- fileblock = rl (buf + 4 * 4);
- if (fileblock == 0xffffffff)
- break;
- write_log (_T("RDB: LSEG block %d:\n"), fileblock);
- if (!legalrdbblock (uip, fileblock)) {
- write_log (_T("RDB: corrupt FSHD pointer %d\n"), fileblock);
- dumprdbblock(i == 0 ? bufrdb : buf, fileblock);
- break;
- }
- memset (buf, 0, readblocksize);
- hdf_read (hfd, buf, fileblock * hfd->ci.blocksize, readblocksize);
- if (!rdb_checksum ("FSHD", buf, fileblock)) {
- write_log (_T("RDB: checksum error FSHD block %d\n"), fileblock);
- dumprdbblock(buf, fileblock);
- break;
- }
- uae_u32 dostype = rl (buf + 32);
- int version = (buf[36] << 8) | buf[37];
- int revision = (buf[38] << 8) | buf[39];
- write_log (_T("LSEG: %08x (%s) %d.%d\n"), dostype, dostypes (dt, dostype), version, revision);
- }
- }
- static void get_new_device (TrapContext *ctx, int type, uaecptr parmpacket, TCHAR **devname, uaecptr *devname_amiga, int unit_no)
- {
- TCHAR buffer[80];
- uaecptr expbase = trap_get_long(ctx, parmpacket + PP_EXPLIB);
- if (*devname == 0 || _tcslen (*devname) == 0) {
- int un = unit_no;
- for (;;) {
- _stprintf (buffer, type == FILESYS_CD ? _T("CD%d") : _T("DH%d"), un++);
- if (type == FILESYS_CD)
- *devname = my_strdup (buffer);
- if (!device_isdup(ctx, expbase, buffer))
- break;
- }
- } else {
- _tcscpy (buffer, *devname);
- }
- *devname_amiga = ds (device_dupfix(ctx, expbase, buffer));
- if (type == FILESYS_CD)
- write_log (_T("FS: mounted CD unit %s\n"), buffer);
- else if (type == FILESYS_VIRTUAL)
- write_log (_T("FS: mounted virtual unit %s (%s)\n"), buffer, mountinfo.ui[unit_no].rootdir);
- else
- write_log (_T("FS: mounted HDF unit %s (%04x-%08x, %s)\n"), buffer,
- (uae_u32)(mountinfo.ui[unit_no].hf.virtsize >> 32),
- (uae_u32)(mountinfo.ui[unit_no].hf.virtsize),
- mountinfo.ui[unit_no].rootdir);
- }
- #define rdbmnt write_log (_T("Mounting uaehf.device %d (%d) (size=%llu):\n"), unit_no, partnum, hfd->virtsize)
- static int pt_babe(TrapContext *ctx, uae_u8 *bufrdb, UnitInfo *uip, int unit_no, int partnum, uaecptr parmpacket)
- {
- uae_u8 bufrdb2[FILESYS_MAX_BLOCKSIZE] = { 0 };
- struct hardfiledata *hfd = &uip->hf;
- struct uaedev_config_info *ci = &uip[unit_no].hf.ci;
- uae_u32 bad;
-
- uae_u32 bs = (bufrdb[0x20] << 24) | (bufrdb[0x21] << 16) | (bufrdb[0x22] << 8) | (bufrdb[0x23] << 0);
- int bscnt;
- for (bscnt = 512; bscnt <= 32768; bscnt <<= 1) {
- if (bs == (bscnt >> 2))
- break;
- }
- if (bscnt > 32768)
- return 0;
- bad = rl(bufrdb + 4);
- if (bad) {
- if (bad * hfd->ci.blocksize > FILESYS_MAX_BLOCKSIZE)
- return 0;
- hdf_read_rdb(hfd, bufrdb2, bad * hfd->ci.blocksize, hfd->ci.blocksize);
- if (bufrdb2[0] != 0xBA || bufrdb2[1] != 0xD1)
- return 0;
- }
- if (partnum > 0)
- return -2;
- if (uip->bootpri <= -129) {
- return -1;
- }
- if (bad) {
- uae_u16 badnum = (bufrdb2[2] << 8) | bufrdb2[3];
- if (badnum) {
- write_log(_T("A2090 partition table: bad block table is not empty, bad blocks not yet supported!\n"));
- }
- }
- hfd->rdbcylinders = rl(bufrdb + 0x08);
- hfd->rdbsectors = rw(bufrdb + 0x18);
- hfd->rdbheads = rw(bufrdb + 0x1a);
- write_log (_T("Mounting uaehf.device:%d %d (%d):\n"), uip->hf.ci.controller_unit, unit_no, partnum);
- get_new_device(ctx, FILESYS_HARDFILE_RDB, parmpacket, &uip->devname, &uip->rdb_devname_amiga[partnum], unit_no);
- trap_put_long(ctx, parmpacket, uip->rdb_devname_amiga[partnum]);
- trap_put_long(ctx, parmpacket + 4, ROM_hardfile_resname);
- trap_put_long(ctx, parmpacket + 8, uip->devno);
- trap_put_long(ctx, parmpacket + 12, 0); /* Device flags */
- for (int i = 0; i < 12 * 4; i++)
- trap_put_byte(ctx, parmpacket + 16 + i, bufrdb[0x1c + i]);
- uae_u32 dostype = 0x444f5300;
- if (ci->dostype) // forced dostype?
- dostype = ci->dostype;
- // A2090 Environment Table Size is only 11
- int ts = trap_get_long(ctx, parmpacket + 16 + 0 * 4);
- while (ts < 16) {
- ts++;
- if (ts == 12) // BufMem Type
- trap_put_long(ctx, parmpacket + 16 + 12 * 4, 1);
- if (ts == 13) // Max Transfer
- trap_put_long(ctx, parmpacket + 16 + 13 * 4, 0x7fffffff);
- if (ts == 14) // Mask
- trap_put_long(ctx, parmpacket + 16 + 14 * 4, 0xfffffffe);
- if (ts == 15) // BootPri
- trap_put_long(ctx, parmpacket + 16 + 15 * 4, uip->bootpri);
- if (ts == 16) // DosType
- trap_put_long(ctx, parmpacket + 16 + 16 * 4, dostype);
- }
- trap_put_long(ctx, parmpacket + 16 + 0 * 4, ts);
- uip->rdb_dostype = dostype;
- if (uip->bootpri <= -128) /* not bootable */
- trap_set_dreg(ctx, 7, trap_get_dreg(ctx, 7) & ~1);
- return 2;
- }
- static int pt_rdsk (TrapContext *ctx, uae_u8 *bufrdb, int rdblock, UnitInfo *uip, int unit_no, int partnum, uaecptr parmpacket)
- {
- int blocksize, readblocksize, badblock, driveinitblock;
- TCHAR dt[32];
- uae_u8 *fsmem = 0, *buf = 0;
- int partblock, fileblock, lsegblock;
- uae_u32 flags;
- struct hardfiledata *hfd = &uip->hf;
- uae_u32 dostype;
- uaecptr fsres, fsnode;
- int err = 0;
- int oldversion, oldrevision;
- int newversion, newrevision;
- TCHAR *s;
- bool showdebug = partnum == 0;
- int cnt;
- blocksize = rl (bufrdb + 16);
- readblocksize = blocksize > hfd->ci.blocksize ? blocksize : hfd->ci.blocksize;
- badblock = rl (bufrdb + 24);
- if (badblock != -1) {
- write_log (_T("RDB: badblock list %08x\n"), badblock);
- dumprdbblock(bufrdb, rdblock);
- }
- driveinitblock = rl (bufrdb + 36);
- if (driveinitblock != -1) {
- write_log (_T("RDB: driveinit = %08x\n"), driveinitblock);
- dumprdbblock(bufrdb, rdblock);
- }
- hfd->rdbcylinders = rl (bufrdb + 64);
- hfd->rdbsectors = rl (bufrdb + 68);
- hfd->rdbheads = rl (bufrdb + 72);
- #if 0
- {
- int cyls, secs, heads;
- getchsgeometry_hdf (hfd, hfd->virtsize, &cyls, &secs, &heads);
- if (cyls * secs * heads > hfd->cylinders * hfd->sectors * hfd->heads) {
- hfd->cylinders = cyls;
- hfd->sectors = secs;
- hfd->heads = heads;
- }
- }
- #endif
- fileblock = rl (bufrdb + 32);
- buf = xmalloc (uae_u8, readblocksize);
- if (showdebug) {
- if ((uae_u64)hfd->rdbcylinders * hfd->rdbsectors * hfd->rdbheads * blocksize > hfd->virtsize)
- write_log (_T("RDB: WARNING: RDSK header disk size > disk size! (%llu > %llu)\n"),
- (uae_u64)hfd->rdbcylinders * hfd->rdbsectors * hfd->rdbheads * blocksize, hfd->virtsize);
- write_log (_T("RDSK dump start\n"));
- write_log (_T("RDSK at %d, C=%d S=%d H=%d\n"),
- rdblock, hfd->rdbcylinders, hfd->rdbsectors, hfd->rdbheads);
- dump_rdb (uip, hfd, bufrdb, buf, readblocksize);
- write_log (_T("RDSK dump end\n"));
- }
- for (int 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->ci.blocksize, readblocksize);
- if (!rdb_checksum ("PART", buf, partblock)) {
- err = -2;
- write_log(_T("RDB: checksum error in PART block %d\n"), partblock);
- dumprdbblock(buf, partblock);
- goto error;
- }
- }
- rdbmnt;
- flags = rl (buf + 20);
- if ((flags & 2) || uip->bootpri <= -129) { /* do not mount */
- err = -1;
- write_log (_T("RDB: Automount disabled, not mounting\n"));
- goto error;
- }
- if (!(flags & 1) || uip->bootpri <= -128) /* not bootable */
- trap_set_dreg(ctx, 7, trap_get_dreg(ctx, 7) & ~1);
- buf[37 + buf[36]] = 0; /* zero terminate BSTR */
- s = au ((char*)buf + 37);
- uip->rdb_devname_amiga[partnum] = ds(device_dupfix(ctx, trap_get_long(ctx, parmpacket + PP_EXPLIB), s));
- xfree (s);
- trap_put_long(ctx, parmpacket, uip->rdb_devname_amiga[partnum]); /* name */
- trap_put_long(ctx, parmpacket + 4, ROM_hardfile_resname);
- trap_put_long(ctx, parmpacket + 8, uip->devno);
- trap_put_long(ctx, parmpacket + 12, 0); /* Device flags */
- for (int i = 0; i < (17 + 15) * 4; i++)
- trap_put_byte(ctx, parmpacket + 16 + i, buf[128 + i]);
- dostype = trap_get_long(ctx, parmpacket + 80);
- uip->rdb_dostype = dostype;
- if (dostype == 0) {
- write_log (_T("RDB: mount failed, dostype=0\n"));
- err = -1;
- goto error;
- }
- if (dostype == 0xffffffff) {
- write_log (_T("RDB: WARNING: dostype = 0xFFFFFFFF. FFS bug can report partition in \"no disk inserted\" state!!\n"));
- }
- err = 2;
- /* load custom filesystems if needed */
- if (fileblock == -1 || !legalrdbblock (uip, fileblock))
- goto error;
- fsres = trap_get_long(ctx, parmpacket + PP_FSRES);
- if (!fsres) {
- write_log (_T("RDB: FileSystem.resource not found, this shouldn't happen!\n"));
- goto error;
- }
- fsnode = trap_get_long(ctx, fsres + 18);
- while (trap_get_long(ctx, fsnode)) {
- if (trap_get_long(ctx, fsnode + 14) == dostype)
- break;
- fsnode = trap_get_long(ctx, fsnode);
- }
- oldversion = oldrevision = -1;
- if (trap_get_long(ctx, fsnode)) {
- oldversion = trap_get_word(ctx, fsnode + 18);
- oldrevision = trap_get_word(ctx, fsnode + 20);
- } else {
- fsnode = 0;
- }
- for (;;) {
- if (fileblock == -1) {
- if (!fsnode)
- write_log (_T("RDB: FS %08X (%s) not in FileSystem.resource or in RDB\n"), dostype, dostypes (dt, dostype));
- goto error;
- }
- if (!legalrdbblock (uip, fileblock)) {
- write_log (_T("RDB: corrupt FSHD pointer %d\n"), fileblock);
- goto error;
- }
- memset (buf, 0, readblocksize);
- hdf_read (hfd, buf, fileblock * hfd->ci.blocksize, readblocksize);
- if (!rdb_checksum ("FSHD", buf, fileblock)) {
- write_log (_T("RDB: checksum error in FSHD block %d\n"), fileblock);
- dumprdbblock(buf, fileblock);
- goto error;
- }
- fileblock = rl (buf + 16);
- uae_u32 rdbdostype = rl (buf + 32);
- if (((dostype >> 8) == (rdbdostype >> 8) && (dostype != DISK_TYPE_DOS && (dostype & 0xffffff00) == DISK_TYPE_DOS)) || (dostype == rdbdostype))
- break;
- }
- newversion = (buf[36] << 8) | buf[37];
- newrevision = (buf[38] << 8) | buf[39];
- write_log (_T("RDB: RDB filesystem %08X (%s) version %d.%d\n"), dostype, dostypes (dt, dostype), newversion, newrevision);
- if (fsnode) {
- write_log (_T("RDB: %08X (%s) in FileSystem.resource version %d.%d\n"), dostype, dostypes (dt, dostype), oldversion, oldrevision);
- }
- if (newversion * 65536 + newrevision <= oldversion * 65536 + oldrevision && oldversion >= 0) {
- write_log (_T("RDB: FS in FileSystem.resource is newer or same, ignoring RDB filesystem\n"));
- goto error;
- }
- for (int i = 0; i < 140; i++)
- trap_put_byte(ctx, parmpacket + PP_FSHDSTART + i, buf[32 + i]);
- trap_put_long(ctx, parmpacket + PP_FSHDSTART, dostype);
- /* we found required FSHD block */
- fsmem = xmalloc (uae_u8, 262144);
- lsegblock = rl (buf + 72);
- cnt = 0;
- for (;;) {
- int pb = lsegblock;
- if (!legalrdbblock (uip, lsegblock))
- goto error;
- memset (buf, 0, readblocksize);
- hdf_read (hfd, buf, lsegblock * hfd->ci.blocksize, readblocksize);
- if (!rdb_checksum("LSEG", buf, lsegblock)) {
- write_log(_T("RDB: checksum error in LSEG block %d\n"), lsegblock);
- dumprdbblock(buf, lsegblock);
- goto error;
- }
- lsegblock = rl (buf + 16);
- if (lsegblock == pb)
- goto error;
- if ((cnt + 1) * (blocksize - 20) >= 262144)
- goto error;
- memcpy (fsmem + cnt * (blocksize - 20), buf + 20, blocksize - 20);
- cnt++;
- if (lsegblock == -1)
- break;
- }
- write_log (_T("RDB: Filesystem loaded, %d bytes\n"), cnt * (blocksize - 20));
- trap_put_long(ctx, parmpacket + PP_FSSIZE, cnt * (blocksize - 20)); /* RDB filesystem size hack */
- trap_put_long(ctx, parmpacket + PP_ADDTOFSRES, -1);
- uip->rdb_filesysstore = fsmem;
- uip->rdb_filesyssize = cnt * (blocksize - 20);
- xfree (buf);
- return 2;
- error:
- xfree (buf);
- xfree (fsmem);
- return err;
- }
- static int rdb_mount (TrapContext *ctx, UnitInfo *uip, int unit_no, int partnum, uaecptr parmpacket)
- {
- struct hardfiledata *hfd = &uip->hf;
- int lastblock = 63, rdblock;
- uae_u8 bufrdb[FILESYS_MAX_BLOCKSIZE];
- write_log (_T("%s:\n"), uip->rootdir);
- if (hfd->drive_empty) {
- rdbmnt;
- write_log (_T("ignored, drive is empty\n"));
- return -2;
- }
- if (hfd->ci.blocksize == 0) {
- rdbmnt;
- write_log (_T("failed, blocksize == 0\n"));
- return -1;
- }
- if (lastblock * hfd->ci.blocksize > hfd->virtsize) {
- rdbmnt;
- write_log (_T("failed, too small (%d*%d > %llu)\n"), lastblock, hfd->ci.blocksize, hfd->virtsize);
- return -2;
- }
- if (hfd->ci.blocksize > FILESYS_MAX_BLOCKSIZE) {
- write_log(_T("failed, too large block size %d\n"), hfd->ci.blocksize);
- return -2;
- }
- for (rdblock = 0; rdblock < lastblock; rdblock++) {
- hdf_read_rdb (hfd, bufrdb, rdblock * hfd->ci.blocksize, hfd->ci.blocksize);
- if (rdblock == 0 && bufrdb[0] == 0xBA && bufrdb[1] == 0xBE) {
- // A2090 "BABE" partition table?
- int v = pt_babe(ctx, bufrdb, uip, unit_no, partnum, parmpacket);
- if (v)
- return v;
- continue;
- }
- if (rdb_checksum ("RDSK", bufrdb, rdblock) || rdb_checksum ("CDSK", bufrdb, rdblock)) {
- return pt_rdsk(ctx, bufrdb, rdblock, uip, unit_no, partnum, parmpacket);
- }
- if (!memcmp ("RDSK", bufrdb, 4)) {
- bufrdb[0xdc] = 0;
- bufrdb[0xdd] = 0;
- bufrdb[0xde] = 0;
- bufrdb[0xdf] = 0;
- if (rdb_checksum ("RDSK", bufrdb, rdblock)) {
- write_log (_T("Windows 95/98/ME trashed RDB detected, fixing..\n"));
- hdf_write (hfd, bufrdb, rdblock * hfd->ci.blocksize, hfd->ci.blocksize);
- return pt_rdsk(ctx, bufrdb, rdblock, uip, unit_no, partnum, parmpacket);
- }
- }
- }
- rdbmnt;
- write_log (_T("failed, no supported partition tables detected\n"));
- return -2;
- }
- static void addfakefilesys (TrapContext *ctx, uaecptr parmpacket, uae_u32 dostype, int ver, int rev, struct uaedev_config_info *ci)
- {
- uae_u32 flags;
- flags = 0x180;
- for (int i = 0; i < 140; i++)
- trap_put_byte(ctx, parmpacket + PP_FSHDSTART + i, 0);
- if (dostype) {
- trap_put_long(ctx, parmpacket + 80, dostype);
- trap_put_long(ctx, parmpacket + PP_FSHDSTART, dostype);
- }
- if (ver >= 0 && rev >= 0)
- trap_put_long(ctx, parmpacket + PP_FSHDSTART + 4, (ver << 16) | rev);
- trap_put_long(ctx, parmpacket + PP_FSHDSTART + 12 + 4 * 4, ci->stacksize);
- flags |= 0x10;
- if (ci->bootpri != -129) {
- trap_put_long(ctx, parmpacket + PP_FSHDSTART + 12 + 5 * 4, ci->bootpri);
- flags |= 0x20;
- }
- trap_put_long(ctx, parmpacket + PP_FSHDSTART + 12 + 8 * 4, dostype == DISK_TYPE_DOS || bcplonlydos() ? 0 : -1); // globvec
- // if OFS = seglist -> NULL
- if (dostype == DISK_TYPE_DOS)
- flags &= ~0x080;
- trap_put_long(ctx, parmpacket + PP_FSHDSTART + 8, flags); // patchflags
- }
- static uaecptr getfakefilesysseg (UnitInfo *uip)
- {
- if (uip->filesysdir && _tcslen (uip->filesysdir) > 0) {
- for (int i = 0; &mountinfo.ui[i] != uip; i++) {
- UnitInfo *uip2 = &mountinfo.ui[i];
- if (!uip2->filesysdir)
- continue;
- if (_tcsicmp (uip2->filesysdir, uip->filesysdir) != 0)
- continue;
- if (uip2->filesysseg)
- return uip2->filesysseg;
- }
- }
- return 0;
- }
- static int dofakefilesys (TrapContext *ctx, UnitInfo *uip, uaecptr parmpacket, struct uaedev_config_info *ci)
- {
- int size;
- TCHAR tmp[MAX_DPATH];
- TCHAR dt[32];
- uae_u8 buf[512];
- struct zfile *zf;
- int ver = -1, rev = -1;
- uae_u32 dostype;
- bool autofs = false;
- // we already have custom filesystem loaded for earlier hardfile?
- if (!ci->forceload) {
- uaecptr seg = getfakefilesysseg (uip);
- if (seg) {
- // yes, re-use it.
- trap_put_long(ctx, parmpacket + PP_FSSIZE, 0);
- trap_put_long(ctx, parmpacket + PP_FSPTR, seg);
- trap_put_long(ctx, parmpacket + PP_ADDTOFSRES, 0);
- write_log (_T("RDB: faked RDB filesystem '%s' reused, entry=%08x\n"), uip->filesysdir, seg << 2);
- return FILESYS_HARDFILE;
- }
- }
- if (!ci->dostype) {
- memset (buf, 0, 4);
- hdf_read (&uip->hf, buf, 0, 512);
- dostype = (buf[0] << 24) | (buf[1] << 16) |(buf[2] << 8) | buf[3];
- } else {
- dostype = ci->dostype;
- }
- if (dostype == 0) {
- addfakefilesys(ctx, parmpacket, dostype, ver, rev, ci);
- return FILESYS_HARDFILE;
- }
- if (dostype == DISK_TYPE_DOS && (!uip->filesysdir || !uip->filesysdir[0])) {
- write_log (_T("RDB: OFS, using ROM default FS.\n"));
- return FILESYS_HARDFILE;
- }
- tmp[0] = 0;
- if (uip->filesysdir && _tcslen (uip->filesysdir) > 0) {
- cfgfile_resolve_path_out_load(uip->filesysdir, tmp, MAX_DPATH, PATH_HDF);
- } else if ((dostype & 0xffffff00) == DISK_TYPE_DOS) {
- _tcscpy (tmp, currprefs.romfile);
- int i = _tcslen (tmp);
- while (i > 0 && tmp[i - 1] != '/' && tmp[i - 1] != '\\')
- i--;
- _tcscpy (tmp + i, _T("FastFileSystem"));
- autofs = true;
- }
- if (tmp[0] == 0) {
- write_log (_T("RDB: no filesystem for dostype 0x%08X (%s)\n"), dostype, dostypes (dt, dostype));
- addfakefilesys(ctx, parmpacket, dostype, ver, rev, ci);
- if ((dostype & 0xffffff00) == DISK_TYPE_DOS)
- return FILESYS_HARDFILE;
- write_log (_T("RDB: mounted without filesys\n"));
- return FILESYS_HARDFILE;
- }
- write_log (_T("RDB: fakefilesys, trying to load '%s', dostype 0x%08X (%s)\n"), tmp, dostype, dostypes (dt, dostype));
- zf = zfile_fopen (tmp, _T("rb"), ZFD_NORMAL);
- if (!zf) {
- addfakefilesys(ctx, parmpacket, dostype, ver, rev, ci);
- write_log (_T("RDB: filesys not found, mounted without forced filesys\n"));
- return FILESYS_HARDFILE;
- }
- uae_u32 fsres, fsnode;
- int oldversion = -1;
- int oldrevision = -1;
- fsres = trap_get_long(ctx, parmpacket + PP_FSRES);
- fsnode = trap_get_long(ctx, fsres + 18);
- while (trap_get_long(ctx, fsnode)) {
- uae_u32 fsdostype = trap_get_long(ctx, fsnode + 14);
- if (fsdostype == dostype) {
- oldversion = trap_get_word(ctx, fsnode + 18);
- oldrevision = trap_get_word(ctx, fsnode + 20);
- write_log (_T("RDB: %08X (%s) in FileSystem.resource version %d.%d\n"), dostype, dostypes(dt, dostype), oldversion, oldrevision);
- break;
- }
- fsnode = trap_get_long(ctx, fsnode);
- }
- // if automatically found FastFileSystem, do not replace matching FileSystem.resource FS
- if (autofs && oldversion >= 0) {
- zfile_fclose (zf);
- addfakefilesys(ctx, parmpacket, dostype, ver, rev, ci);
- write_log (_T("RDB: not replacing FileSystem.resource\n"));
- return FILESYS_HARDFILE;
- }
- zfile_fseek (zf, 0, SEEK_END);
- size = zfile_ftell (zf);
- if (size > 0) {
- zfile_fseek (zf, 0, SEEK_SET);
- uip->rdb_filesysstore = xmalloc (uae_u8, size);
- zfile_fread (uip->rdb_filesysstore, size, 1, zf);
- for (int i = 0; i < size - 6; i++) {
- uae_u8 *p = uip->rdb_filesysstore + i;
- if (p[0] == 'V' && p[1] == 'E' && p[2] == 'R' && p[3] == ':' && p[4] == ' ') {
- uae_u8 *p2;
- p += 5;
- p2 = p;
- while (*p2 && p2 - uip->rdb_filesysstore < size)
- p2++;
- if (p2[0] == 0) {
- while (*p && (ver < 0 || rev < 0)) {
- if (*p == ' ') {
- p++;
- ver = atol ((char*)p);
- if (ver < 0)
- ver = 0;
- while (*p) {
- if (*p == ' ')
- break;
- if (*p == '.') {
- p++;
- rev = atol ((char*)p);
- if (rev < 0)
- rev = 0;
- } else {
- p++;
- }
- }
- break;
- } else {
- p++;
- }
- }
- }
- break;
- }
- }
- }
- zfile_fclose (zf);
- uip->rdb_filesyssize = size;
- // DOS\0 is not in fs.resource and fs.resource already existed?
- if (dostype == DISK_TYPE_DOS && oldversion < 0)
- oldversion = 0;
- trap_put_long(ctx, parmpacket + PP_FSSIZE, uip->rdb_filesyssize);
- trap_put_long(ctx, parmpacket + PP_ADDTOFSRES, oldversion < 0 ? -1 : 0);
- addfakefilesys(ctx, parmpacket, dostype, ver, rev, ci);
- write_log (_T("RDB: faked RDB filesystem %08X (%s %d.%d) loaded. ADD2FS=%d\n"), dostype, dostypes (dt, dostype), ver, rev, oldversion < 0 ? 1 : 0);
- return FILESYS_HARDFILE;
- }
-
- /* Fill in per-unit fields of a parampacket */
- static uae_u32 REGPARAM2 filesys_dev_storeinfo (TrapContext *ctx)
- {
- int no = trap_get_dreg(ctx, 6) & 0x7fffffff;
- int unit_no = no & 65535;
- int sub_no = no >> 16;
- int type;
- if (unit_no >= MAX_FILESYSTEM_UNITS)
- return -2;
- if (sub_no >= MAX_FILESYSTEM_UNITS)
- return -2;
- UnitInfo *uip = mountinfo.ui;
- uaecptr parmpacket = trap_get_areg(ctx, 0);
- int iscd = (trap_get_dreg(ctx, 6) & 0x80000000) != 0 || uip[unit_no].unit_type == UNIT_CDFS;
- struct uaedev_config_info *ci = &uip[unit_no].hf.ci;
- uip[unit_no].parmpacket = parmpacket;
- if (!ks12hack_deviceproc)
- ks12hack_deviceproc = trap_get_long(ctx, parmpacket + PP_DEVICEPROC);
- trap_put_long(ctx, parmpacket + PP_DEVICEPROC, 0);
- trap_put_long(ctx, parmpacket + PP_ADDTOFSRES, 0);
- trap_put_long(ctx, parmpacket + PP_FSSIZE, 0);
- if (iscd) {
- TCHAR *cdname = NULL;
- uaecptr cdname_amiga;
- int cd_unit_no = unit_no - cd_unit_offset;
- if (sub_no)
- return -2;
- type = FILESYS_CD;
- get_new_device(ctx, type, parmpacket, &uip[unit_no].devname, &uip[unit_no].devname_amiga, cd_unit_no);
- cdname_amiga = uip[unit_no].devname_amiga;
- uip[unit_no].devno = unit_no;
- type = FILESYS_VIRTUAL;
- gui_flicker_led (LED_CD, cd_unit_no, 0);
- write_log (_T("Mounting uaescsi.device %d: (%d)\n"), cd_unit_no, unit_no);
- trap_put_long(ctx, parmpacket + 0, cdname_amiga);
- trap_put_long(ctx, parmpacket + 4, cdfs_devname);
- trap_put_long(ctx, parmpacket + 8, cd_unit_no);
- trap_put_long(ctx, parmpacket + 12, 0); /* Device flags */
- trap_put_long(ctx, parmpacket + 16, 19); /* Env. size */
- trap_put_long(ctx, parmpacket + 20, 2048 >> 2); /* longwords per block */
- trap_put_long(ctx, parmpacket + 24, 0); /* unused */
- trap_put_long(ctx, parmpacket + 28, 1); /* heads */
- trap_put_long(ctx, parmpacket + 32, 1); /* sectors per block */
- trap_put_long(ctx, parmpacket + 36, 1); /* sectors per track */
- trap_put_long(ctx, parmpacket + 40, 0); /* reserved blocks */
- trap_put_long(ctx, parmpacket + 44, 0); /* unused */
- trap_put_long(ctx, parmpacket + 48, 0); /* interleave */
- trap_put_long(ctx, parmpacket + 52, 0); /* lowCyl */
- trap_put_long(ctx, parmpacket + 56, 0); /* hiCyl */
- trap_put_long(ctx, parmpacket + 60, 50); /* Number of buffers */
- trap_put_long(ctx, parmpacket + 64, 1); /* Buffer mem type */
- trap_put_long(ctx, parmpacket + 68, 0x7FFFFFFE); /* largest transfer */
- trap_put_long(ctx, parmpacket + 72, 0xFFFFFFFE); /* dma mask */
- trap_put_long(ctx, parmpacket + 76, scsi_get_cd_drive_media_mask () & (1 << cd_unit_no) ? -127 : -128); /* bootPri */
- trap_put_long(ctx, parmpacket + 80, CDFS_DOSTYPE | (((cd_unit_no / 10) + '0') << 8) | ((cd_unit_no % 10) + '0'));
- trap_put_long(ctx, parmpacket + 84, 0); /* baud */
- trap_put_long(ctx, parmpacket + 88, 0); /* control */
- trap_put_long(ctx, parmpacket + 92, 0); /* bootblocks */
- return type;
- } else {
- gui_flicker_led (LED_HD, unit_no, 0);
- type = is_hardfile (unit_no);
- if (type == FILESYS_HARDFILE_RDB || type == FILESYS_HARDDRIVE) {
- /* RDB hardfile */
- uip[unit_no].devno = uip[unit_no].hf.ci.controller_unit;
- return rdb_mount(ctx, &uip[unit_no], unit_no, sub_no, parmpacket);
- }
- if (sub_no)
- return -2;
- write_log (_T("Mounting uaehf.device:%d %d (%d):\n"), uip->hf.ci.controller_unit, unit_no, sub_no);
- get_new_device(ctx, type, parmpacket, &uip[unit_no].devname, &uip[unit_no].devname_amiga, unit_no);
- uip[unit_no].devno = uip[unit_no].hf.ci.controller_unit;
- trap_put_long(ctx, parmpacket, uip[unit_no].devname_amiga);
- trap_put_long(ctx, parmpacket + 8, uip[unit_no].devno);
- trap_put_long(ctx, parmpacket + 12, 0); /* Device flags */
- trap_put_long(ctx, parmpacket + 16, 16); /* Env. size */
- trap_put_long(ctx, parmpacket + 24, 0); /* unused */
- trap_put_long(ctx, parmpacket + 44, 0); /* unused */
- trap_put_long(ctx, parmpacket + 48, 0); /* interleave */
- trap_put_long(ctx, parmpacket + 60, 50); /* Number of buffers */
- trap_put_long(ctx, parmpacket + 64, 1); /* Buffer mem type */
- trap_put_long(ctx, parmpacket + 68, 0x7FFFFFFE); /* largest transfer */
- trap_put_long(ctx, parmpacket + 72, 0xFFFFFFFE); /* dma mask */
- trap_put_long(ctx, parmpacket + 76, uip[unit_no].bootpri); /* bootPri */
- if (type == FILESYS_VIRTUAL) {
- // generate some sane-looking geometry if some program really cares..
- uae_s64 hicyl = 100;
- uae_u32 heads = 16;
- if (currprefs.filesys_limit) {
- hicyl = ((currprefs.filesys_limit * 1024) / 512) / (heads * 127);
- } else {
- struct fs_usage fsu;
- if (!get_fs_usage(uip[unit_no].rootdir, 0, &fsu)) {
- for (;;) {
- hicyl = (fsu.total / 512) / (heads * 127);
- if (hicyl < 65536 || heads == 64)
- break;
- heads *= 2;
- }
- }
- }
- trap_put_long(ctx, parmpacket + 4, fsdevname);
- trap_put_long(ctx, parmpacket + 20, 512 >> 2); /* longwords per block */
- trap_put_long(ctx, parmpacket + 28, heads); /* heads */
- trap_put_long(ctx, parmpacket + 32, 1); /* sectors per block */
- trap_put_long(ctx, parmpacket + 36, 127); /* sectors per track */
- trap_put_long(ctx, parmpacket + 40, 2); /* reserved blocks */
- trap_put_long(ctx, parmpacket + 52, 1); /* lowCyl */
- trap_put_long(ctx, parmpacket + 56, (uae_u32)hicyl); /* hiCyl */
- trap_put_long(ctx, parmpacket + 80, DISK_TYPE_DOS); /* DOS\0 */
- } else {
- uae_u8 buf[512];
- trap_put_long(ctx, parmpacket + 4, ROM_hardfile_resname);
- trap_put_long(ctx, parmpacket + 20, ci->blocksize >> 2); /* longwords per block */
- trap_put_long(ctx, parmpacket + 28, ci->surfaces); /* heads */
- trap_put_long(ctx, parmpacket + 32, ci->sectorsperblock); /* sectors per block */
- trap_put_long(ctx, parmpacket + 36, ci->sectors); /* sectors per track */
- trap_put_long(ctx, parmpacket + 40, ci->reserved); /* reserved blocks */
- trap_put_long(ctx, parmpacket + 52, ci->lowcyl); /* lowCyl */
- trap_put_long(ctx, parmpacket + 56, ci->highcyl <= 0 ? ci->cyls - 1 : ci->highcyl - 1); /* hiCyl */
- trap_put_long(ctx, parmpacket + 48, ci->interleave); /* interleave */
- trap_put_long(ctx, parmpacket + 60, ci->buffers); /* Number of buffers */
- trap_put_long(ctx, parmpacket + 64, ci->bufmemtype); /* Buffer mem type */
- trap_put_long(ctx, parmpacket + 68, ci->maxtransfer); /* largest transfer */
- trap_put_long(ctx, parmpacket + 72, ci->mask); /* dma mask */
- trap_put_long(ctx, parmpacket + 80, DISK_TYPE_DOS); /* DOS\0 */
- memset(buf, 0, sizeof buf);
- if (ci->dostype) { // forced dostype?
- trap_put_long(ctx, parmpacket + 80, ci->dostype); /* dostype */
- } else if (hdf_read (&uip[unit_no].hf, buf, 0, sizeof buf)) {
- uae_u32 dt = rl (buf);
- if (dt != 0x00000000 && dt != 0xffffffff)
- trap_put_long(ctx, parmpacket + 80, dt);
- }
- memset(buf, 0, sizeof buf);
- char *s = ua_fs(uip[unit_no].devname, -1);
- buf[36] = strlen(s);
- for (int i = 0; i < buf[36]; i++)
- buf[37 + i] = s[i];
- xfree(s);
- for (int i = 0; i < 80; i++)
- buf[i + 128] = trap_get_byte(ctx, parmpacket + 16 + i);
- dump_partinfo (&uip[unit_no].hf, buf);
- }
- if (type == FILESYS_HARDFILE)
- type = dofakefilesys(ctx, &uip[unit_no], parmpacket, ci);
- if (uip[unit_no].bootpri < -127 || (type == FILESYS_HARDFILE && ci->rootdir[0] == 0))
- trap_set_dreg(ctx, 7, trap_get_dreg(ctx, 7) & ~1); /* do not boot */
- if (uip[unit_no].bootpri < -128)
- return -1; /* do not mount */
- return type;
- }
- }
- static uae_u32 REGPARAM2 mousehack_done (TrapContext *ctx)
- {
- int mode = trap_get_dreg(ctx, 1);
- if (mode < 10) {
- uaecptr diminfo = trap_get_areg(ctx, 2);
- uaecptr dispinfo = trap_get_areg(ctx, 3);
- uaecptr vp = trap_get_areg(ctx, 4);
- return input_mousehack_status(ctx, mode, diminfo, dispinfo, vp, trap_get_dreg(ctx, 2));
- } else if (mode == 10) {
- amiga_clipboard_die(ctx);
- } else if (mode == 11) {
- amiga_clipboard_got_data(ctx, trap_get_areg(ctx, 2), trap_get_dreg(ctx, 2), trap_get_dreg(ctx, 0) + 8);
- } else if (mode == 12) {
- return amiga_clipboard_want_data(ctx);
- } else if (mode == 13) {
- return amiga_clipboard_proc_start(ctx);
- } else if (mode == 14) {
- amiga_clipboard_task_start(ctx, trap_get_dreg(ctx, 0));
- } else if (mode == 15) {
- amiga_clipboard_init(ctx);
- } else if (mode == 16) {
- uaecptr a2 = trap_get_areg(ctx, 2);
- input_mousehack_mouseoffset(a2);
- } else if (mode == 17) {
- uae_u32 v = 0;
- if (currprefs.clipboard_sharing)
- v |= 1;
- if (consolehook_activate())
- v |= 2;
- if (currprefs.uaeboard > 2)
- v |= 4;
- trap_dos_active();
- return v;
- } else if (mode == 18) {
- put_long_host(rtarea_bank.baseaddr + RTAREA_EXTERTASK, trap_get_dreg(ctx, 0));
- put_long_host(rtarea_bank.baseaddr + RTAREA_TRAPTASK, trap_get_dreg(ctx, 2));
- return rtarea_base + RTAREA_HEARTBEAT;
- } else if (mode == 19) {
- // boot rom copy
- // d2 = ram address
- return boot_rom_copy(ctx, trap_get_dreg(ctx, 2), 0);
- } else if (mode == 20) {
- // boot rom copy done
- return boot_rom_copy(ctx, trap_get_dreg(ctx, 2), 1);
- } else if (mode == 21) {
- // keymap hook
- #ifdef RETROPLATFORM
- rp_keymap(ctx, trap_get_areg(ctx, 1), trap_get_dreg(ctx, 0));
- #endif
- return 1;
- } else if (mode == 101) {
- consolehook_ret(ctx, trap_get_areg(ctx, 1), trap_get_areg(ctx, 2));
- } else if (mode == 102) {
- uaecptr ret = consolehook_beginio(ctx, trap_get_areg(ctx, 1));
- trap_put_long(ctx, trap_get_areg(ctx, 7) + 4 * 4, ret);
- } else if (mode == 200) {
- uae_u32 v;
- // a0 = data, d0 = length, a1 = task, d3 = stack size (in), stack ptr (out)
- // a2 = debugdata, d2 = debuglength
- // d4 = flags
- if ((trap_get_dreg(ctx, 4) & 3) != 1) {
- write_log(_T("unsupported uaedbg version\n"));
- return 0;
- }
- uae_u32 stack = trap_get_dreg(ctx, 3);
- v = debugmem_reloc(trap_get_areg(ctx, 0), trap_get_dreg(ctx, 0),
- trap_get_areg(ctx, 2), trap_get_dreg(ctx, 2),
- trap_get_areg(ctx, 1), &stack);
- trap_set_dreg(ctx, 2, stack);
- return v;
- } else if (mode == 201) {
- debugmem_break(8);
- return 1;
- } else if (mode == 202) {
- // a0 = seglist, a1 = name, d2 = lock
- debugmem_addsegs(ctx, trap_get_areg(ctx, 0), trap_get_areg(ctx, 1), trap_get_dreg(ctx, 2), true);
- return 1;
- } else if (mode == 203) {
- // a0 = seglist
- debugmem_remsegs(trap_get_areg(ctx, 0));
- return 1;
- } else if (mode == 204 || mode == 206) {
- // d0 = size, a1 = flags
- uae_u32 v = debugmem_allocmem(mode == 206, trap_get_dreg(ctx, 0), trap_get_areg(ctx, 1), trap_get_areg(ctx, 0));
- if (v) {
- trap_set_areg(ctx, 0, v);
- return v;
- } else {
- trap_set_areg(ctx, 0, 0);
- trap_set_dreg(ctx, 1, trap_get_areg(ctx, 1));
- return trap_get_dreg(ctx, 0);
- }
- } else if (mode == 205 || mode == 207) {
- return debugmem_freemem(mode == 207, trap_get_areg(ctx, 1), trap_get_dreg(ctx, 0), trap_get_areg(ctx, 0));
- } else if (mode == 208) {
- // segtrack: bit 0
- // fsdebug: bit 1
- segtrack_mode = currprefs.debugging_features;
- return segtrack_mode;
- } else if (mode == 209) {
- // called if segtrack was enabled
- return 0;
- } else if (mode == 210) {
- // debug trapcode
- debugmem_trap(trap_get_areg(ctx, 0));
- } else if (mode == 212) {
- // a0 = seglist, a1 = name, d2 = lock
- debugmem_addsegs(ctx, trap_get_areg(ctx, 0), trap_get_areg(ctx, 1), trap_get_dreg(ctx, 2), false);
- return 1;
- } else if (mode == 213) {
- // a0 = seglist
- debugmem_remsegs(trap_get_areg(ctx, 0));
- return 1;
- } else if (mode == 299) {
- return debugmem_exit();
- } else {
- write_log (_T("Unknown mousehack hook %d\n"), mode);
- }
- return 1;
- }
- void filesys_vsync (void)
- {
- TrapContext *ctx = NULL;
- Unit *u;
- if (uae_boot_rom_type <= 0)
- return;
- if (currprefs.uaeboard > 1 && !(uae_int_requested & 1)) {
- bool req = false;
- // check if there is waiting requests without signal
- if (!uae_sem_trywait(&singlethread_int_sem)) {
- if (comm_pipe_has_data(&native2amiga_pending))
- req = true;
- if (!req) {
- UnitInfo *uip = mountinfo.ui;
- int unit_no = 0;
- for (;;) {
- if (unit_no >= MAX_FILESYSTEM_UNITS)
- break;
- if (uip[unit_no].open > 0 && 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++;
- }
- if (unit_no < MAX_FILESYSTEM_UNITS) {
- if (uip[unit_no].self->port)
- req = true;
- }
- }
- uae_sem_post(&singlethread_int_sem);
- if (req)
- do_uae_int_requested();
- }
- }
- if (media_queued_total > 0) {
- if (automountunit == -1) {
- bool cont = true;
- for (u = units; u; u = u->next) {
- if (u->reinsertdelay > 0) {
- cont = false;
- break;
- }
- }
- if (cont) {
- TCHAR *mountpath = media_queued_paths[media_queued_cnt++];
- if (mountpath) {
- filesys_media_change(mountpath, 3, NULL);
- }
- if (media_queued_cnt >= media_queued_total) {
- for (int i = 0; i < media_queued_total; i++) {
- xfree(media_queued_paths[i]);
- }
- xfree(media_queued_paths);
- media_queued_cnt = 0;
- media_queued_total = 0;
- media_queued_paths = NULL;
- for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
- if (mountinfo.ui[i].canremove < 0)
- mountinfo.ui[i].canremove = 1;
- }
- }
- }
- }
- }
- if (heartbeat == get_long_host(rtarea_bank.baseaddr + RTAREA_HEARTBEAT)) {
- if (heartbeat_count > 0)
- heartbeat_count--;
- if (heartbeat_count_cont > 0)
- heartbeat_count_cont--;
- return;
- }
- heartbeat = get_long_host(rtarea_bank.baseaddr + RTAREA_HEARTBEAT);
- heartbeat_count_cont = 10;
- cia_heartbeat ();
- for (u = units; u; u = u->next) {
- if (u->reinsertdelay > 0) {
- u->reinsertdelay--;
- if (u->reinsertdelay == 0) {
- if (u->newrootdir == NULL && u->newvolume == NULL) {
- filesys_eject(u->unit);
- } else {
- filesys_insert(u->unit, u->newvolume, u->newrootdir, u->newreadonly, u->newflags);
- }
- xfree (u->newvolume);
- u->newvolume = NULL;
- xfree (u->newrootdir);
- u->newrootdir = NULL;
- }
- }
- record_timeout(ctx, u);
- }
- for (int i = 0; i < currprefs.mountitems; i++) {
- struct hardfiledata *hfd = get_hardfile_data (currprefs.mountconfig[i].configoffset);
- if (!hfd)
- continue;
- if (hfd->reinsertdelay > 0) {
- hfd->reinsertdelay--;
- if (hfd->reinsertdelay == 0) {
- hfd->reinsertdelay = -1;
- hardfile_media_change (hfd, &hfd->delayedci, true, true);
- }
- }
- }
- if (heartbeat_count <= 0)
- return;
- if (heartbeat_task & 1) {
- setsystime_vblank ();
- heartbeat_task &= ~1;
- }
- }
- void filesys_cleanup(void)
- {
- filesys_free_handles();
- free_mountinfo();
- destroy_comm_pipe(&shellexecute_pipe);
- uae_sem_destroy(&singlethread_int_sem);
- shell_execute_data = 0;
- }
- void filesys_install (void)
- {
- uaecptr loop;
- TRACEI ((_T("Installing filesystem\n")));
- uae_sem_init (&singlethread_int_sem, 0, 1);
- init_comm_pipe(&shellexecute_pipe, 100, 1);
- ROM_filesys_resname = ds_ansi ("UAEfs.resource");
- ROM_filesys_resid = ds_ansi (UAEFS_VERSION);
- fsdevname = ROM_hardfile_resname;
- fshandlername = ds_bstr_ansi ("uaefs");
- cdfs_devname = ds_ansi ("uaescsi.device");
- cdfs_handlername = ds_bstr_ansi ("uaecdfs");
- afterdos_name = ds_ansi("UAE afterdos");
- afterdos_id = ds_ansi("UAE afterdos 0.2");
- keymaphook_name = ds_ansi("UAE keymaphook");
- keymaphook_id = ds_ansi("UAE keymaphook 0.1");
- ROM_filesys_diagentry = here ();
- calltrap (deftrap2 (filesys_diagentry, 0, _T("filesys_diagentry")));
- dw(0x4ED0); /* JMP (a0) - jump to code that inits Residents */
- ROM_filesys_doio = here();
- calltrap(deftrap2(filesys_doio, 0, _T("filesys_doio")));
- dw(RTS);
- ROM_filesys_putmsg = here();
- calltrap(deftrap2(filesys_putmsg, 0, _T("filesys_putmsg")));
- dw(RTS);
- ROM_filesys_putmsg_return = here();
- calltrap(deftrap2(filesys_putmsg_return, 0, _T("filesys_putmsg_return")));
- dw(RTS);
- loop = here ();
- org (rtarea_base + RTAREA_HEARTBEAT);
- dl (0);
- heartbeat = 0;
- heartbeat_task = 0;
- org (rtarea_base + 0xFF18);
- calltrap (deftrap2 (filesys_dev_bootfilesys, 0, _T("filesys_dev_bootfilesys")));
- dw (RTS);
- /* Special trap for the assembly make_dev routine */
- org (rtarea_base + 0xFF20);
- calltrap (deftrap2 (filesys_dev_remember, 0, _T("filesys_dev_remember")));
- dw (RTS);
- org (rtarea_base + 0xFF28);
- calltrap (deftrap2 (filesys_dev_storeinfo, 0, _T("filesys_dev_storeinfo")));
- dw (RTS);
- org (rtarea_base + 0xFF30);
- calltrap (deftrap2 (filesys_handler, 0, _T("filesys_handler")));
- dw (RTS);
- org (rtarea_base + 0xFF38);
- calltrap (deftrapres(mousehack_done, 0, _T("misc_funcs")));
- dw (RTS);
- org (rtarea_base + 0xFF40);
- calltrap (deftrap2 (startup_handler, 0, _T("startup_handler")));
- dw (RTS);
- org (rtarea_base + 0xFF48);
- calltrap (deftrap2 (filesys_init_storeinfo, TRAPFLAG_EXTRA_STACK, _T("filesys_init_storeinfo")));
- dw (RTS);
- org (rtarea_base + 0xFF50);
- calltrap (deftrap2 (exter_int_helper, 0, _T("exter_int_helper")));
- dw (RTS);
- org (rtarea_base + 0xFF58);
- calltrap (deftrap2 (fsmisc_helper, 0, _T("fsmisc_helper")));
- dw (RTS);
- org(rtarea_base + 0xFF68);
- calltrap(deftrap2(filesys_bcpl_wrapper, 0, _T("filesys_bcpl_wrapper")));
- dw(RTS);
- org(rtarea_base + 0xFF78);
- calltrap(deftrap2(debugger_helper, 0, _T("debugger_helper")));
- dw(RTS);
- org (loop);
- create_ks12_boot();
- create_68060_nofpu();
- }
- uaecptr filesys_get_entry(int index)
- {
- return bootrom_start + dlg(bootrom_start + bootrom_header + index * 4 - 4) + bootrom_header - 4;
- }
- void filesys_install_code (void)
- {
- uae_u32 b, items;
- bootrom_header = 3 * 4;
- align(4);
- bootrom_start = here ();
- #include "filesys_bootrom.cpp"
- items = dlg (bootrom_start + 8) & 0xffff;
- /* The last offset comes from the code itself, look for it near the top. */
- EXPANSION_bootcode = bootrom_start + bootrom_header + items * 4 - 4;
- b = bootrom_start + bootrom_header + 3 * 4 - 4;
- filesys_initcode = bootrom_start + dlg (b) + bootrom_header - 4;
- afterdos_initcode = filesys_get_entry(8);
- keymaphook_initcode = filesys_get_entry(11);
- // Fill struct resident
- TCHAR buf[256];
- TCHAR *s = au(UAEFS_VERSION);
- int y, m, d;
- target_getdate(&y, &m, &d);
- _stprintf(buf, _T("%s (%d.%d.%d)\r\n"), s, d, m, y);
- uaecptr idstring = ds(buf);
- xfree(s);
- b = here();
- items = dlg(bootrom_start) * 2;
- for (int i = 0; i < items; i += 2) {
- if (((dbg(bootrom_start + i + 0) << 8) | (dbg(bootrom_start + i + 1) << 0)) == 0x4afc) {
- org(bootrom_start + i + 2);
- dl(bootrom_start + i);
- dl(dlg(here()) + bootrom_start + i); // endskip
- db(0); // flags
- db(1); // version
- db(0); // type
- db(0); // pri
- dl(dlg(here()) + bootrom_start + i); // name
- dl(idstring); // idstring
- dl(dlg(here()) + bootrom_start + i); // init
- break;
- }
- }
- org(b);
- }
- #ifdef _WIN32
- #include "od-win32/win32_filesys.cpp"
- #endif
- static uae_u8 *restore_filesys_hardfile (UnitInfo *ui, uae_u8 *src)
- {
- struct hardfiledata *hfd = &ui->hf;
- TCHAR *s;
- hfd->virtsize = restore_u64 ();
- hfd->offset = restore_u64 ();
- hfd->ci.highcyl = restore_u32 ();
- hfd->ci.sectors = restore_u32 ();
- hfd->ci.surfaces = restore_u32 ();
- hfd->ci.reserved = restore_u32 ();
- hfd->ci.blocksize = restore_u32 ();
- hfd->ci.readonly = restore_u32 () != 0;
- hfd->flags = restore_u32 ();
- hfd->rdbcylinders = restore_u32 ();
- hfd->rdbsectors = restore_u32 ();
- hfd->rdbheads = restore_u32 ();
- s = restore_string ();
- _tcscpy (hfd->vendor_id, s);
- xfree (s);
- s = restore_string ();
- _tcscpy (hfd->product_id, s);
- xfree (s);
- s = restore_string ();
- _tcscpy (hfd->product_rev, s);
- xfree (s);
- s = restore_string ();
- _tcscpy (hfd->ci.devname, s);
- xfree (s);
- return src;
- }
- static uae_u8 *save_filesys_hardfile (UnitInfo *ui, uae_u8 *dst)
- {
- struct hardfiledata *hfd = &ui->hf;
- save_u64 (hfd->virtsize);
- save_u64 (hfd->offset);
- save_u32 (hfd->ci.highcyl);
- save_u32 (hfd->ci.sectors);
- save_u32 (hfd->ci.surfaces);
- save_u32 (hfd->ci.reserved);
- save_u32 (hfd->ci.blocksize);
- save_u32 (hfd->ci.readonly);
- save_u32 (hfd->flags);
- save_u32 (hfd->rdbcylinders);
- save_u32 (hfd->rdbsectors);
- save_u32 (hfd->rdbheads);
- save_string (hfd->vendor_id);
- save_string (hfd->product_id);
- save_string (hfd->product_rev);
- save_string (hfd->ci.devname);
- return dst;
- }
- static a_inode *restore_filesys_get_base (Unit *u, TCHAR *npath)
- {
- TCHAR *path, *p, *p2;
- a_inode *a;
- int cnt, err, i;
- /* no '/' = parent is root */
- if (!_tcschr (npath, '/'))
- return &u->rootnode;
- /* iterate from root to last to previous path part,
- * create ainos if not already created.
- */
- path = xcalloc(TCHAR, _tcslen (npath) + 2);
- cnt = 1;
- for (;;) {
- _tcscpy (path, npath);
- p = path;
- for (i = 0; i < cnt ;i++) {
- if (i > 0)
- p++;
- while (*p != '/' && *p != 0)
- p++;
- }
- if (*p) {
- *p = 0;
- err = 0;
- get_aino (u, &u->rootnode, path, &err);
- if (err) {
- write_log (_T("*** FS: missing path '%s'!\n"), path);
- return NULL;
- }
- cnt++;
- } else {
- break;
- }
- }
- /* find base (parent) of last path part */
- _tcscpy (path, npath);
- p = path;
- a = u->rootnode.child;
- for (;;) {
- if (*p == 0) {
- write_log (_T("*** FS: base aino NOT found '%s' ('%s')\n"), a->nname, npath);
- xfree (path);
- return NULL;
- }
- p2 = p;
- while(*p2 != '/' && *p2 != '\\' && *p2 != 0)
- p2++;
- *p2 = 0;
- while (a) {
- if (!same_aname(p, a->aname)) {
- a = a->sibling;
- continue;
- }
- p = p2 + 1;
- if (*p == 0) {
- write_log (_T("FS: base aino found '%s' ('%s')\n"), a->nname, npath);
- xfree (path);
- return a;
- }
- a = a->child;
- break;
- }
- if (!a) {
- write_log (_T("*** FS: path part '%s' not found ('%s')\n"), p, npath);
- xfree (path);
- return NULL;
- }
- }
- }
- static TCHAR *makenativepath (UnitInfo *ui, TCHAR *apath)
- {
- TCHAR *pn;
- /* create native path. FIXME: handle 'illegal' characters */
- pn = xcalloc (TCHAR, _tcslen (apath) + 1 + _tcslen (ui->rootdir) + 1);
- _stprintf (pn, _T("%s/%s"), ui->rootdir, apath);
- if (FSDB_DIR_SEPARATOR != '/') {
- for (int i = 0; i < _tcslen (pn); i++) {
- if (pn[i] == '/')
- pn[i] = FSDB_DIR_SEPARATOR;
- }
- }
- return pn;
- }
- static uae_u8 *restore_aino (UnitInfo *ui, Unit *u, uae_u8 *src)
- {
- TCHAR *p, *p2, *pn;
- uae_u32 flags;
- int missing;
- a_inode *base, *a;
- missing = 0;
- a = xcalloc (a_inode, 1);
- a->uniq = restore_u64 ();
- a->locked_children = restore_u32 ();
- a->exnext_count = restore_u32 ();
- a->shlock = restore_u32 ();
- flags = restore_u32 ();
- if (flags & 1)
- a->elock = 1;
- if (flags & 4)
- a->uniq_external = restore_u64 ();
- /* full Amiga-side path without drive, eg. "C/SetPatch" */
- p = restore_string ();
- /* root (p = volume label) */
- if (a->uniq == 0) {
- a->nname = my_strdup (ui->rootdir);
- a->aname = p;
- a->dir = 1;
- if (ui->volflags < 0) {
- write_log (_T("FS: Volume '%s' ('%s') missing!\n"), a->aname, a->nname);
- } else {
- a->volflags = ui->volflags;
- recycle_aino (u, a);
- write_log (_T("FS: Lock (root) '%s' ('%s')\n"), a->aname, a->nname);
- }
- return src;
- }
- p2 = _tcsrchr(p, '/');
- if (p2)
- p2++;
- else
- p2 = p;
- pn = makenativepath (ui, p);
- a->nname = pn;
- a->aname = my_strdup (p2);
- /* create path to parent dir */
- if (p2 != p)
- p2[0] = 0;
- /* find parent of a->aname (Already restored previously. I hope..) */
- base = restore_filesys_get_base (u, p);
- xfree(p);
- if (flags & 2) {
- a->dir = 1;
- if (!my_existsdir(a->nname))
- write_log (_T("*** FS: Directory '%s' missing!\n"), a->nname);
- else
- fsdb_clean_dir (a);
- } else {
- if (!my_existsfile(a->nname))
- write_log (_T("*** FS: File '%s' missing!\n"), a->nname);
- }
- if (base) {
- fill_file_attrs (u, base, a);
- init_child_aino_tree (u, base, a);
- } else {
- write_log (_T("*** FS: parent directory missing '%s' ('%s')\n"), a->aname, a->nname);
- missing = 1;
- }
- if (missing) {
- write_log (_T("*** FS: Lock restore failed '%s' ('%s')\n"), a->aname, a->nname);
- xfree (a->nname);
- xfree (a->aname);
- xfree (a);
- } else {
- write_log (_T("FS: Lock '%s' ('%s')\n"), a->aname, a->nname);
- recycle_aino (u, a);
- }
- return src;
- }
- static uae_u8 *restore_key (UnitInfo *ui, Unit *u, uae_u8 *src)
- {
- int uniq;
- TCHAR *p, *pn;
- mode_t openmode;
- int err;
- int missing;
- a_inode *a;
- Key *k;
- uae_u64 savedsize, size, pos;
- missing = 0;
- k = xcalloc (Key, 1);
- k->uniq = restore_u64 ();
- k->file_pos = restore_u32 ();
- k->createmode = restore_u32 ();
- k->dosmode = restore_u32 ();
- savedsize = restore_u32 ();
- uniq = restore_u64 ();
- p = restore_string ();
- pos = restore_u64 ();
- size = restore_u64 ();
- if (size) {
- savedsize = size;
- k->file_pos = pos;
- }
- pn = makenativepath (ui, p);
- openmode = ((k->dosmode & A_FIBF_READ) == 0 ? O_WRONLY
- : (k->dosmode & A_FIBF_WRITE) == 0 ? O_RDONLY
- : O_RDWR);
- write_log (_T("FS: open file '%s' ('%s'), pos=%llu\n"), p, pn, k->file_pos);
- a = get_aino (u, &u->rootnode, p, &err);
- if (!a)
- write_log (_T("*** FS: Open file aino creation failed '%s'\n"), p);
- missing = 1;
- if (a) {
- missing = 0;
- k->aino = a;
- if (a->uniq != uniq)
- write_log (_T("*** FS: Open file '%s' aino id %d != %d\n"), p, uniq, a->uniq);
- if (!my_existsfile (pn)) {
- write_log (_T("*** FS: Open file '%s' is missing, creating dummy file!\n"), p);
- if (savedsize < 10 * 1024 * 1024) {
- k->fd = fs_openfile (u, a, openmode | O_CREAT |O_BINARY);
- if (k->fd) {
- uae_u8 *buf = xcalloc (uae_u8, 10000);
- uae_u64 sp = savedsize;
- while (sp) {
- uae_u32 s = sp >= 10000 ? 10000 : sp;
- fs_write (k->fd, buf, s);
- sp -= s;
- }
- xfree(buf);
- write_log (_T("*** FS: dummy file created\n"));
- } else {
- write_log (_T("*** FS: Open file '%s', couldn't create dummy file!\n"), p);
- }
- } else {
- write_log (_T("*** FS: Too big, ignored\n"));
- }
- } else {
- k->fd = fs_openfile (u, a, openmode | O_BINARY);
- }
- if (!k->fd) {
- write_log (_T("*** FS: Open file '%s' failed to open!\n"), p);
- missing = 1;
- } else {
- uae_s64 s;
- s = key_filesize(k);
- if (s != savedsize)
- write_log (_T("FS: restored file '%s' size changed! orig=%llu, now=%lld!!\n"), p, savedsize, s);
- if (k->file_pos > s) {
- write_log (_T("FS: restored filepos larger than size of file '%s'!! %llu > %lld\n"), p, k->file_pos, s);
- k->file_pos = s;
- }
- key_seek(k, k->file_pos, SEEK_SET);
- }
- }
- xfree (p);
- if (missing) {
- xfree (k);
- } else {
- k->next = u->keys;
- u->keys = k;
- }
- return src;
- }
- static uae_u8 *restore_notify (UnitInfo *ui, Unit *u, uae_u8 *src)
- {
- Notify *n = xcalloc (Notify, 1);
- uae_u32 hash;
- TCHAR *s;
- n->notifyrequest = restore_u32 ();
- s = restore_string ();
- n->fullname = xmalloc (TCHAR, _tcslen (ui->volname) + 2 + _tcslen (s) + 1);
- _stprintf (n->fullname, _T("%s:%s"), ui->volname, s);
- xfree(s);
- s = _tcsrchr (n->fullname, '/');
- if (s)
- s++;
- else
- s = n->fullname;
- n->partname = my_strdup (s);
- hash = notifyhash (n->fullname);
- n->next = u->notifyhash[hash];
- u->notifyhash[hash] = n;
- write_log (_T("FS: notify %08X '%s' '%s'\n"), n->notifyrequest, n->fullname, n->partname);
- return src;
- }
- static uae_u8 *restore_exkey (UnitInfo *ui, Unit *u, uae_u8 *src)
- {
- restore_u64 ();
- restore_u64 ();
- restore_u64 ();
- return src;
- }
- static uae_u8 *restore_filesys_virtual (UnitInfo *ui, uae_u8 *src, int num)
- {
- Unit *u = startup_create_unit(NULL, ui, num);
- int cnt;
- u->dosbase = restore_u32 ();
- u->volume = restore_u32 ();
- u->port = restore_u32 ();
- u->locklist = restore_u32 ();
- u->dummy_message = restore_u32 ();
- u->cmds_sent = restore_u64 ();
- u->cmds_complete = restore_u64 ();
- u->cmds_acked = restore_u64 ();
- u->next_exkey = restore_u32 ();
- u->total_locked_ainos = restore_u32 ();
- u->volflags = ui->volflags;
- cnt = restore_u32 ();
- write_log (_T("FS: restoring %d locks\n"), cnt);
- while (cnt-- > 0)
- src = restore_aino (ui, u, src);
- cnt = restore_u32 ();
- write_log (_T("FS: restoring %d open files\n"), cnt);
- while (cnt-- > 0)
- src = restore_key (ui, u, src);
- cnt = restore_u32 ();
- write_log (_T("FS: restoring %d notifications\n"), cnt);
- while (cnt-- > 0)
- src = restore_notify (ui, u, src);
- cnt = restore_u32 ();
- write_log (_T("FS: restoring %d exkeys\n"), cnt);
- while (cnt-- > 0)
- src = restore_exkey (ui, u, src);
- return src;
- }
- static TCHAR *getfullaname (a_inode *a)
- {
- TCHAR *p;
- int first = 1;
- p = xcalloc (TCHAR, MAX_DPATH);
- while (a) {
- int len = _tcslen (a->aname);
- memmove (p + len + 1, p, (_tcslen (p) + 1) * sizeof (TCHAR));
- memcpy (p, a->aname, len * sizeof (TCHAR));
- if (!first)
- p[len] = '/';
- first = 0;
- a = a->parent;
- if (a && a->uniq == 0)
- return p;
- }
- return p;
- }
- /* scan and save all Lock()'d files */
- static int recurse_aino (UnitInfo *ui, a_inode *a, int cnt, uae_u8 **dstp)
- {
- uae_u8 *dst = NULL;
- int dirty = 0;
- a_inode *a2 = a;
- if (dstp)
- dst = *dstp;
- while (a) {
- //write_log("recurse '%s' '%s' %d %08x\n", a->aname, a->nname, a->uniq, a->parent);
- if (a->elock || a->shlock || a->uniq == 0) {
- if (dst) {
- TCHAR *fn = NULL;
- write_log (_T("uniq=%d %lld s=%d e=%d d=%d '%s' '%s'\n"), a->uniq, a->uniq_external, a->shlock, a->elock, a->dir, a->aname, a->nname);
- if (a->aname) {
- fn = getfullaname (a);
- write_log (_T("->'%s'\n"), fn);
- }
- save_u64 (a->uniq);
- save_u32 (a->locked_children);
- save_u32 (a->exnext_count);
- save_u32 (a->shlock);
- save_u32 ((a->elock ? 1 : 0) | (a->dir ? 2 : 0) | 4);
- save_u64 (a->uniq_external);
- save_string (fn);
- xfree(fn);
- }
- cnt++;
- }
- if (a->dirty)
- dirty = 1;
- if (a->child)
- cnt = recurse_aino (ui, a->child, cnt, &dst);
- a = a->sibling;
- }
- if (dirty && a2->parent)
- fsdb_dir_writeback (a2->parent);
- if (dst)
- *dstp = dst;
- return cnt;
- }
- static uae_u8 *save_key (uae_u8 *dst, Key *k)
- {
- TCHAR *fn = getfullaname (k->aino);
- uae_u64 size;
- save_u64 (k->uniq);
- save_u32 ((uae_u32)k->file_pos);
- save_u32 (k->createmode);
- save_u32 (k->dosmode);
- size = fs_fsize (k->fd);
- save_u32 ((uae_u32)size);
- save_u64 (k->aino->uniq);
- save_string (fn);
- save_u64 (k->file_pos);
- save_u64 (size);
- write_log (_T("'%s' uniq=%d size=%lld seekpos=%lld mode=%d dosmode=%d\n"),
- fn, k->uniq, size, k->file_pos, k->createmode, k->dosmode);
- xfree (fn);
- return dst;
- }
- static uae_u8 *save_notify (UnitInfo *ui, uae_u8 *dst, Notify *n)
- {
- TCHAR *s;
- save_u32 (n->notifyrequest);
- s = n->fullname;
- if (_tcslen (s) >= _tcslen (ui->volname) && !_tcsncmp (n->fullname, ui->volname, _tcslen (ui->volname)))
- s = n->fullname + _tcslen (ui->volname) + 1;
- save_string (s);
- write_log (_T("FS: notify %08X '%s'\n"), n->notifyrequest, n->fullname);
- return dst;
- }
- static uae_u8 *save_exkey (uae_u8 *dst, ExamineKey *ek)
- {
- save_u64 (ek->uniq);
- save_u64 (ek->aino->uniq);
- save_u64 (ek->curr_file->uniq);
- return dst;
- }
- static uae_u8 *save_filesys_virtual (UnitInfo *ui, uae_u8 *dst)
- {
- Unit *u = ui->self;
- Key *k;
- int cnt, i, j;
- write_log (_T("FSSAVE: '%s'\n"), ui->devname);
- save_u32 (u->dosbase);
- save_u32 (u->volume);
- save_u32 (u->port);
- save_u32 (u->locklist);
- save_u32 (u->dummy_message);
- save_u64 (u->cmds_sent);
- save_u64 (u->cmds_complete);
- save_u64 (u->cmds_acked);
- save_u32 (u->next_exkey);
- save_u32 (u->total_locked_ainos);
- cnt = recurse_aino (ui, &u->rootnode, 0, NULL);
- save_u32 (cnt);
- write_log (_T("%d open locks\n"), cnt);
- cnt = recurse_aino (ui, &u->rootnode, 0, &dst);
- cnt = 0;
- for (k = u->keys; k; k = k->next)
- cnt++;
- save_u32 (cnt);
- write_log (_T("%d open files\n"), cnt);
- for (k = u->keys; k; k = k->next)
- dst = save_key (dst, k);
- for (j = 0; j < 2; j++) {
- cnt = 0;
- for (i = 0; i < NOTIFY_HASH_SIZE; i++) {
- Notify *n = u->notifyhash[i];
- while (n) {
- if (j > 0)
- dst = save_notify (ui, dst, n);
- cnt++;
- n = n->next;
- }
- }
- if (j == 0) {
- save_u32 (cnt);
- write_log (_T("%d notify requests\n"), cnt);
- }
- }
- for (j = 0; j < 2; j++) {
- cnt = 0;
- for (i = 0; i < EXKEYS; i++) {
- ExamineKey *ek = &u->examine_keys[i];
- if (ek->uniq) {
- cnt++;
- if (j > 0)
- dst = save_exkey (dst, ek);
- }
- }
- if (j == 0) {
- save_u32 (cnt);
- write_log (_T("%d exkeys\n"), cnt);
- }
- }
- write_log (_T("END\n"));
- return dst;
- }
- static TCHAR *new_filesys_root_path, *new_filesys_fs_path;
- uae_u8 *save_filesys_common (int *len)
- {
- uae_u8 *dstbak, *dst;
- if (nr_units () == 0)
- return NULL;
- dstbak = dst = xmalloc (uae_u8, 1000);
- save_u32 (2);
- save_u64 (a_uniq);
- save_u64 (key_uniq);
- *len = dst - dstbak;
- return dstbak;
- }
- uae_u8 *restore_filesys_common (uae_u8 *src)
- {
- if (restore_u32 () != 2)
- return src;
- cd_unit_offset = MAX_FILESYSTEM_UNITS;
- cd_unit_number = 0;
- filesys_prepare_reset2 ();
- filesys_reset2 ();
- a_uniq = restore_u64 ();
- key_uniq = restore_u64 ();
- xfree(new_filesys_root_path);
- xfree(new_filesys_fs_path);
- new_filesys_root_path = NULL;
- new_filesys_fs_path = NULL;
- return src;
- }
- uae_u8 *save_filesys_paths(int num, int *len)
- {
- uae_u8 *dstbak, *dst;
- UnitInfo *ui;
- int type = is_hardfile(num);
- int ptype;
- ui = &mountinfo.ui[num];
- if (ui->open <= 0)
- return NULL;
- dstbak = dst = xmalloc(uae_u8, 4 + 4 + 2 + 2 * 2 * MAX_DPATH);
- if (type == FILESYS_VIRTUAL || type == FILESYS_CD)
- ptype = SAVESTATE_PATH_VDIR;
- else if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB)
- ptype = SAVESTATE_PATH_HDF;
- else if (type == FILESYS_HARDDRIVE)
- ptype = SAVESTATE_PATH_HD;
- else
- ptype = SAVESTATE_PATH;
- save_u32(0);
- save_u32(ui->devno);
- save_u16(type);
- save_path_full(ui->rootdir, ptype);
- save_path_full(ui->filesysdir, SAVESTATE_PATH);
- *len = dst - dstbak;
- return dstbak;
- }
- uae_u8 *save_filesys (int num, int *len)
- {
- uae_u8 *dstbak, *dst;
- UnitInfo *ui;
- int type = is_hardfile (num);
- int ptype;
- ui = &mountinfo.ui[num];
- if (ui->open <= 0)
- return NULL;
- /* not initialized yet, do not save */
- if ((type == FILESYS_VIRTUAL || type == FILESYS_CD) && ui->self == NULL)
- return NULL;
- write_log (_T("FS_FILESYS: '%s' '%s'\n"), ui->devname, ui->volname ? ui->volname : _T("<no name>"));
- dstbak = dst = xmalloc (uae_u8, 100000);
- save_u32 (2); /* version */
- save_u32 (ui->devno);
- save_u16 (type);
- if (type == FILESYS_VIRTUAL || type == FILESYS_CD)
- ptype = SAVESTATE_PATH_VDIR;
- else if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB)
- ptype = SAVESTATE_PATH_HDF;
- else if (type == FILESYS_HARDDRIVE)
- ptype = SAVESTATE_PATH_HD;
- else
- ptype = SAVESTATE_PATH;
- save_path(ui->rootdir, ptype);
- save_string (ui->devname);
- save_string (ui->volname);
- save_path (ui->filesysdir, SAVESTATE_PATH);
- save_u8 (ui->bootpri);
- save_u8 (ui->readonly);
- save_u32 (ui->startup);
- save_u32 (filesys_configdev);
- if (type == FILESYS_VIRTUAL || type == FILESYS_CD)
- dst = save_filesys_virtual (ui, dst);
- if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB)
- dst = save_filesys_hardfile (ui, dst);
- *len = dst - dstbak;
- return dstbak;
- }
- uae_u8 *restore_filesys_paths(uae_u8 *src)
- {
- restore_u32();
- restore_u32();
- restore_u16();
- new_filesys_root_path = restore_path_full();
- new_filesys_fs_path = restore_path_full();
- return src;
- }
- uae_u8 *restore_filesys (uae_u8 *src)
- {
- int type, devno;
- UnitInfo *ui;
- TCHAR *devname = 0, *volname = 0, *rootdir = 0, *filesysdir = 0;
- uae_u32 startup;
- struct uaedev_config_info *ci;
- if (restore_u32() != 2)
- goto end2;
- devno = restore_u32 ();
- ui = &mountinfo.ui[devno];
- ci = &ui->hf.ci;
- uci_set_defaults (ci, false);
- type = restore_u16 ();
- if (type == FILESYS_VIRTUAL) {
- rootdir = restore_path (SAVESTATE_PATH_VDIR);
- } else if (type == FILESYS_CD) {
- rootdir = restore_path (SAVESTATE_PATH_VDIR);
- if (cd_unit_offset == MAX_FILESYSTEM_UNITS)
- cd_unit_offset = devno;
- cd_unit_number++;
- } else if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB) {
- rootdir = restore_path (SAVESTATE_PATH_HDF);
- } else if (type == FILESYS_HARDDRIVE) {
- rootdir = restore_path (SAVESTATE_PATH_HD);
- } else {
- rootdir = restore_path (SAVESTATE_PATH);
- }
- devname = restore_string ();
- volname = restore_string ();
- filesysdir = restore_path (SAVESTATE_PATH);
- ci->bootpri = restore_u8 ();
- ci->readonly = restore_u8 () != 0;
- startup = restore_u32 ();
- filesys_configdev = restore_u32 ();
- if (new_filesys_root_path) {
- xfree(rootdir);
- rootdir = new_filesys_root_path;
- new_filesys_root_path = NULL;
- }
- if (new_filesys_fs_path) {
- xfree(filesysdir);
- filesysdir = new_filesys_fs_path;
- new_filesys_fs_path = NULL;
- }
- if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB) {
- src = restore_filesys_hardfile (ui, src);
- xfree (volname);
- volname = NULL;
- }
- _tcscpy (ci->rootdir, rootdir);
- _tcscpy (ci->devname, devname);
- _tcscpy (ci->volname, volname ? volname : _T(""));
- _tcscpy (ci->filesys, filesysdir);
- if (set_filesys_unit (devno, ci, false) < 0) {
- write_log (_T("filesys '%s' failed to restore\n"), rootdir);
- goto end;
- }
- ui->devno = devno;
- ui->startup = startup;
- if (type == FILESYS_VIRTUAL || type == FILESYS_CD)
- src = restore_filesys_virtual (ui, src, devno);
- write_log (_T("'%s' restored\n"), rootdir);
- end:
- xfree (rootdir);
- xfree (devname);
- xfree (volname);
- xfree (filesysdir);
- end2:
- xfree(new_filesys_root_path);
- xfree(new_filesys_fs_path);
- new_filesys_root_path = NULL;
- new_filesys_fs_path = NULL;
- return src;
- }
- int save_filesys_cando (void)
- {
- if (nr_units () == 0)
- return -1;
- return filesys_in_interrupt ? 0 : 1;
- }
- #define SE2_MIN_FILE_LENGTH 32
- struct ShellExecute2
- {
- uae_u32 size;
- char *file, *parms, *currentdir;
- char *fileparms;
- uae_u32 stack;
- uae_s32 priority;
- uae_u32 flags;
- uae_u32 id;
- uae_u32 binsize;
- uae_u8 *bin;
- char *tmpout;
- uaecptr aoutbuf;
- char *binname;
- int aoutlen;
- uaecptr process;
- uaecptr buffer;
- uae_u32 exitcode;
- shellexecute2_callback cb;
- char *outbuf;
- int outlen;
- void *userdata;
- };
- #define SHELLEXEC_MAX 2
- static struct ShellExecute2 shellexecute2[SHELLEXEC_MAX];
- static void shellexecute2_free(struct ShellExecute2 *se2)
- {
- xfree(se2->file);
- xfree(se2->currentdir);
- xfree(se2->parms);
- xfree(se2->bin);
- xfree(se2->outbuf);
- memset(se2, 0, sizeof(struct ShellExecute2));
- }
- #define ShellExecute2_Struct_Start (5 * 4)
- #define ShellExecute2_Struct_Start2 (9 * 4)
- static int filesys_shellexecute2_process(int mode, TrapContext *ctx)
- {
- struct ShellExecute2 *se2 = &shellexecute2[0];
- char tmp[256];
- write_log(_T("filesys_shellexecute2_process %d\n"), mode);
- if (mode == 30) {
- // request Amiga side buffer size
- if (se2->bin) {
- xfree(se2->file);
- sprintf(tmp, "T:__uae_bin_%08X_%08x", se2->process, se2->id);
- se2->file = strdup(tmp);
- }
- int size = ShellExecute2_Struct_Start + ShellExecute2_Struct_Start2;
- size += 2 * (strlen(se2->file) + 1);
- size += strlen(se2->currentdir) + 1;
- size += 2 * (strlen(se2->parms) + 1);
- size += 32; // space for tmp_out
- size += 256; // space for out buffer
- size++;
- size += se2->binsize + 4;
- if (se2->binsize) {
- size += 32; // space for bin name
- }
- return size;
- }
- if (mode == 31) {
- // a0 = buffer
- // d1 = process pointer
- se2->buffer = trap_get_areg(ctx, 0);
- se2->process = trap_get_dreg(ctx, 1);
- if (!se2->buffer) {
- // amiga side out of memory
- shellexecute2_free(se2);
- return 0;
- }
- uaecptr dptr = se2->buffer + ShellExecute2_Struct_Start + ShellExecute2_Struct_Start2;
- trap_put_long(ctx, se2->buffer + 4, dptr);
- if (se2->bin) {
- xfree(se2->file);
- sprintf(tmp, "T:__uae_bin_%08X_%08x", se2->process, se2->id);
- se2->file = strdup(tmp);
- trap_put_long(ctx, se2->buffer + 52, dptr);
- }
- dptr += trap_put_string(ctx, se2->file, dptr, -1) + 1;
- trap_put_long(ctx, se2->buffer + 8, dptr);
- dptr += trap_put_string(ctx, se2->parms, dptr, -1) + 1;
- trap_put_long(ctx, se2->buffer + 12, dptr);
- dptr += trap_put_string(ctx, se2->currentdir, dptr, -1) + 1;
- trap_put_long(ctx, se2->buffer + 16, dptr);
- dptr += trap_put_string(ctx, se2->file, dptr, -1) + 1;
- if (se2->parms[0]) {
- trap_put_byte(ctx, dptr - 1, ' ');
- dptr += trap_put_string(ctx, se2->parms, dptr, -1) + 1;
- }
- if (se2->flags & 2) {
- trap_put_long(ctx, se2->buffer + 44, dptr);
- sprintf(tmp, "T:__uae_out_%08X_%08x", se2->process, se2->id);
- dptr += trap_put_string(ctx, tmp, dptr, -1) + 1;
- se2->aoutbuf = dptr;
- trap_put_long(ctx, se2->buffer + 48, dptr);
- dptr += 128 + 1;
- } else {
- trap_put_long(ctx, se2->buffer + 44, 0);
- }
- dptr += 3;
- dptr &= ~3;
- uaecptr ptr = se2->buffer + ShellExecute2_Struct_Start;
- trap_put_long(ctx, ptr, se2->stack);
- ptr += 4;
- trap_put_long(ctx, ptr, se2->priority);
- ptr += 4;
- trap_put_long(ctx, ptr, se2->flags);
- ptr += 4;
- trap_put_long(ctx, ptr, se2->id);
- ptr += 4;
- if (se2->bin) {
- trap_put_long(ctx, ptr, se2->binsize);
- ptr += 4;
- trap_put_long(ctx, ptr, dptr);
- ptr += 4;
- trap_put_bytes(ctx, se2->bin, dptr, se2->binsize);
- dptr += se2->binsize;
- } else {
- trap_put_long(ctx, ptr, 0);
- ptr += 4;
- trap_put_long(ctx, ptr, 0);
- ptr += 4;
- }
- return 1;
- }
- if (mode == 32) {
- // called by new process, requests buffer
- return se2->buffer;
- }
- if (mode == 34) {
- // collect output
- if (se2->aoutbuf) {
- int len = trap_get_dreg(ctx, 1);
- if (len > 0 && len <= 128) {
- int outoffset = se2->aoutlen;
- trap_get_bytes(ctx, tmp, se2->aoutbuf, 128);
- tmp[len] = 0;
- se2->aoutlen += len;
- if (se2->aoutlen + 1 >= se2->outlen) {
- se2->outlen += 1000;
- if (!se2->outbuf) {
- se2->outbuf = xmalloc(char, se2->outlen);
- } else {
- se2->outbuf = xrealloc(char, se2->outbuf, se2->outlen);
- }
- }
- strcpy(se2->outbuf + outoffset, tmp);
- }
- }
- return 1;
- }
- if (mode == 33) {
- // exit status
- // d0 = status
- // a1 = buffer
- se2->exitcode = trap_get_dreg(ctx, 1);
- if (se2->cb) {
- se2->cb(se2->id, se2->exitcode, se2->flags, se2->outbuf, se2->userdata);
- }
- shellexecute2_free(se2);
- }
- return 0;
- }
- static void shellexec2_boot(struct ShellExecute2 *se2)
- {
- if (kickstart_version >= 36) {
- uae_ShellExecute2(se2->id);
- } else {
- Unit *u;
- TrapContext *ctx = NULL;
- for (u = units; u; u = u->next) {
- if (is_virtual(u->unit) && filesys_isvolume(u)) {
- put_byte(u->volume + 173 - 32, get_byte(u->volume + 173 - 32) | 4);
- uae_Signal(get_long(u->volume + 176 - 32), 1 << 13);
- break;
- }
- }
- }
- }
- int filesys_shellexecute2(TCHAR *file, TCHAR *currentdir, TCHAR *parms, uae_u32 stack, uae_s32 priority, uae_u32 id, uae_u32 flags, uae_u8 *bin, uae_u32 binsize, shellexecute2_callback cb, void *userdata)
- {
- struct ShellExecute2 *se2 = &shellexecute2[0];
- if (uae_boot_rom_type <= 0) {
- return 0;
- }
- if (se2->file) {
- return 0;
- }
- se2->file = file ? ua(file) : "";
- se2->currentdir = currentdir ? ua(currentdir) : "";
- se2->parms = parms ? ua(parms) : "";
- se2->id = id;
- se2->stack = stack;
- se2->priority = priority;
- se2->flags = flags;
- if (bin && binsize > 0) {
- se2->bin = xmalloc(uae_u8, binsize);
- memcpy(se2->bin, bin, binsize);
- se2->binsize = binsize;
- }
- se2->cb = cb;
- se2->userdata = userdata;
- shellexec2_boot(se2);
- return 1;
- }