Hi Dick,
On Mon, 2008-12-01 at 23:32 +0100, Gillian Seed wrote:
> 2008/11/30 James Woodcock <[EMAIL PROTECTED]>:
> > Bugs:
> > 1. you don't get an invalid disc error when referencing discs that do
> > not exist. I need to fix that, really.
>
> Can you fix it or does the ArcEmHostFS module need to do some things
> for you? Anyway does the emulator still crash when the patch is
> applied if an non-existence disc is referenced?
I haven't seen it crash recently. But I haven't stressed it out by
trying to write to a non-existent disc.
> > 2. you don't get a permission denied error when trying to create a file
> > on a read-only filesystem.
>
> Same question again. Need the HostFS module be modified for that?
OK, I've done some investigation. The problem with generating errors is
in both hostfs and the ArcEmHostFS module. The only error hostfs passes
up is FILECORE_ERROR_DISCFULL. If you look at hostfs.s, you'll see that
it checks for FILECORE_ERROR_DISCFULL, but nothing else.
It would be good to update the module to handle these errors.
#define FILECORE_ERROR_NOTFOUND 0xd6
#define FILECORE_ERROR_BADDISC 0xc8
#define FILECORE_ERROR_DISCERR 0xc7
#define FILECORE_ERROR_DISCPROT 0xc9
Plus, it would be good to have some sort of generic "unhandled error %x"
type message for all other messages - until hostfs has been updated to
do proper error handling.
I have attached an updated patch that generates a FILECORE_ERROR_BADDISC
error as a response to hostfs_read_dir().
James
Index: cmos.ram
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: rpc.cfg
===================================================================
--- rpc.cfg (revision 137)
+++ rpc.cfg (working copy)
@@ -8,3 +8,13 @@
cpu_type = SA110
mem_size = 16
ipaddress = 172.31.0.1
+hostfs.drive0.name = Boot
+hostfs.drive0.path = ./hostfs
+hostfs.drive0.permissions = read,write
+hostfs.drive1.name = System
+hostfs.drive1.path = /
+hostfs.drive1.permissions = read
+hostfs.drive2.name = Home
+hostfs.drive2.path = ~/rpcemu
+hostfs.drive2.permissions = read,write
+
Index: src/hostfs.c
===================================================================
--- src/hostfs.c (revision 137)
+++ src/hostfs.c (working copy)
@@ -28,15 +28,18 @@
#include "mem.h"
#include "hostfs.h"
+#define WANT_DEFAULT_DISC
+
typedef int bool;
#define true ((bool) 1)
#define false ((bool) 0)
enum OBJECT_TYPE {
- OBJECT_TYPE_NOT_FOUND = 0,
- OBJECT_TYPE_FILE = 1,
- OBJECT_TYPE_DIRECTORY = 2,
+ OBJECT_TYPE_NOT_FOUND = 0,
+ OBJECT_TYPE_FILE = 1,
+ OBJECT_TYPE_DIRECTORY = 2,
+ OBJECT_TYPE_DISC_NOT_FOUND = 3,
};
enum OPEN_MODE {
@@ -55,11 +58,16 @@
enum FILECORE_ERROR {
FILECORE_ERROR_BADRENAME = 0xb0,
+ FILECORE_ERROR_NOPRIV = 0xba,
FILECORE_ERROR_TOOMANYOPEN = 0xc0, /* Too many open files */
FILECORE_ERROR_OPEN = 0xc2, /* File open */
FILECORE_ERROR_LOCKED = 0xc3,
FILECORE_ERROR_EXISTS = 0xc4, /* Already exists */
FILECORE_ERROR_DISCFULL = 0xc6,
+ FILECORE_ERROR_DISCERR = 0xc7,
+ FILECORE_ERROR_BADDISC = 0xc8,
+ FILECORE_ERROR_DISCPROT = 0xc9,
+ FILECORE_ERROR_NOTFOUND = 0xd6,
};
enum RISC_OS_FILE_TYPE {
@@ -74,13 +82,14 @@
ARMword exec;
ARMword length;
ARMword attribs;
+ HOSTFS_Discs *disc_info;
} risc_os_object_info;
/* TODO Avoid duplicate macro with extnrom.c */
#define ROUND_UP_TO_4(x) (((x) + 3) & (~3))
-char HOSTFS_ROOT[512];
-//#define HOSTFS_ROOT "./hostfs"
+#define MAX_HOSTFS_DISCS 10
+HOSTFS_Discs hostfs_discs[MAX_HOSTFS_DISCS];
#define MAX_OPEN_FILES 255
@@ -110,6 +119,69 @@
}
#endif
+int hostfs_initialise()
+{
+ memset(&hostfs_discs, 0, sizeof(hostfs_discs));
+
+ return 0;
+}
+
+int add_hostfs_disc(const char *name, const char *path, const char *permissions)
+{
+ int i;
+ char *c;
+
+ for (i = 0; i < sizeof(hostfs_discs) / sizeof(HOSTFS_Discs); i++) {
+ if (strlen(hostfs_discs[i].disc_name) == 0) {
+ strncpy(hostfs_discs[i].disc_name, name, sizeof(hostfs_discs[i].disc_name)-1);
+ if (*path == '~')
+ rpcemu_os_expand_home_path(path, hostfs_discs[i].hostfs_root, sizeof(hostfs_discs[i].hostfs_root));
+ else
+ strncpy(hostfs_discs[i].hostfs_root, path, sizeof(hostfs_discs[i].hostfs_root)-1);
+ c = hostfs_discs[i].hostfs_root;
+ while (*c != '\0') {
+ if (*c == '\\') {
+ *c = '/';
+ }
+ c++;
+ }
+ if (strstr(permissions, "read"))
+ hostfs_discs[i].permissions |= HOSTFS_DISC_READABLE;
+ if (strstr(permissions, "write"))
+ hostfs_discs[i].permissions |= HOSTFS_DISC_WRITEABLE;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int get_max_hostfs_discs()
+{
+ return MAX_HOSTFS_DISCS;
+}
+
+static HOSTFS_Discs *get_hostfs_disc_info_by_name(const char *disc_name)
+{
+ unsigned int i;
+ for (i = 0; i < sizeof(hostfs_discs) / sizeof(HOSTFS_Discs); i++) {
+ if (strlen(hostfs_discs[i].disc_name) == 0)
+ break;
+ if (strcmp(disc_name, hostfs_discs[i].disc_name) == 0)
+ return &hostfs_discs[i];
+ }
+
+ return NULL;
+}
+
+static HOSTFS_Discs *get_hostfs_disc_info_by_index(int index)
+{
+ if (index >= MAX_HOSTFS_DISCS || index < 0)
+ return NULL;
+
+ return &hostfs_discs[index];
+}
+
/**
* @param buffer_size_needed Required buffer
*/
@@ -257,7 +329,6 @@
static void
name_host_to_riscos(const char *object_name, size_t len, char *riscos_name)
{
- char *s=riscos_name,*s2=object_name;
assert(object_name);
assert(riscos_name);
@@ -291,7 +362,8 @@
static void
hostfs_read_object_info(const char *host_pathname,
char *ro_leaf,
- risc_os_object_info *object_info)
+ risc_os_object_info *object_info,
+ HOSTFS_Discs *disc_info)
{
struct stat info;
ARMword file_type;
@@ -305,6 +377,7 @@
assert(ro_leaf);
assert(object_info);
+ object_info->disc_info = disc_info;
if (stat(host_pathname, &info)) {
/* Error reading info about the object */
@@ -417,7 +490,8 @@
int case_sensitive,
char *host_name,
char *ro_leaf,
- risc_os_object_info *object_info)
+ risc_os_object_info *object_info,
+ HOSTFS_Discs *disc_info)
{
DIR *d;
struct dirent *entry;
@@ -427,6 +501,7 @@
assert(host_name && ro_leaf);
assert(object_info);
+ object_info->disc_info = disc_info;
d = opendir(host_dir_path);
if (!d) {
switch (errno) {
@@ -456,7 +531,7 @@
strcat(entry_path, "/");
strcat(entry_path, entry->d_name);
- hostfs_read_object_info(entry_path, ro_leaf, object_info);
+ hostfs_read_object_info(entry_path, ro_leaf, object_info, disc_info);
/* Ignore entries we can not read information about,
or which are neither regular files or directories */
@@ -514,12 +589,17 @@
char component_name[PATH_MAX]; /* working Host component */
char *component;
const char *ro_path_orig = ro_path;
+ char disc_name[80] = "";
+ int disc_index = -1;
+ char *p;
+ char *endptr;
+ HOSTFS_Discs *hostfs_disc_info = NULL;
assert(ro_path);
assert(host_pathname && ro_leaf);
assert(object_info);
- assert(ro_path[0] == '$');
+ assert(ro_path[0] == '$' || ro_path[0] == ':');
/* Initialise Host pathname */
host_pathname[0] = '\0';
@@ -532,10 +612,51 @@
while (*ro_path) {
//rpclog("%i %c\n",*ro_path,*ro_path);
switch (*ro_path) {
+ case ':':
+ p = strchr(ro_path, '$');
+ if (!p) {
+ object_info->type = OBJECT_TYPE_NOT_FOUND;
+ dbug_hostfs("DISC NOT FOUND %s %s\n",host_pathname,ro_leaf);
+ return;
+ }
+ p--;
+ if (*p != '.') {
+ object_info->type = OBJECT_TYPE_NOT_FOUND;
+ dbug_hostfs("DISC NOT FOUND %s %s\n",host_pathname,ro_leaf);
+ return;
+ }
+ ro_path++;
+ memset(disc_name, 0, sizeof(disc_name));
+ strncpy(disc_name, ro_path, p-ro_path>sizeof(disc_name)?sizeof(disc_name)-1:p-ro_path);
+ disc_index = strtoul(disc_name, &endptr, 10);
+ if (disc_name == endptr) {
+ // disc name is a text based name, not an index
+ disc_index = -1;
+ }
+
+
+ ro_path = p;
+ break;
case '$':
- strcat(host_pathname, HOSTFS_ROOT);
+#ifdef WANT_DEFAULT_DISC
+ // We have neither have a disc name nor index. Use the default disc.
+ if (disc_name[0] == '\0' && disc_index == -1)
+ {
+ disc_index = 0;
+ }
+#endif
+ if (disc_index != -1) {
+ hostfs_disc_info = get_hostfs_disc_info_by_index(disc_index);
+ } else {
+ hostfs_disc_info = get_hostfs_disc_info_by_name(disc_name);
+ if (!hostfs_disc_info) {
+ object_info->type = OBJECT_TYPE_NOT_FOUND;
+ return;
+ }
+ }
+ strcat(host_pathname, hostfs_disc_info->hostfs_root);
- hostfs_read_object_info(host_pathname, ro_leaf, object_info);
+ hostfs_read_object_info(host_pathname, ro_leaf, object_info, hostfs_disc_info);
if (object_info->type == OBJECT_TYPE_NOT_FOUND) {
dbug_hostfs("OBJECT NOT FOUND %s %s\n",host_pathname,ro_leaf);
return;
@@ -552,7 +673,7 @@
*component = '\0'; /* add terminator */
hostfs_path_scan(host_pathname, component_name, 0,
- host_name, ro_leaf, object_info);
+ host_name, ro_leaf, object_info, hostfs_disc_info);
if (object_info->type == OBJECT_TYPE_NOT_FOUND) {
/* This component of the path is invalid */
/* Return what we have of the host_pathname */
@@ -594,7 +715,7 @@
*component = '\0'; /* add terminator */
hostfs_path_scan(host_pathname, component_name, preserve_leaf,
- host_name, ro_leaf, object_info);
+ host_name, ro_leaf, object_info, hostfs_disc_info);
if (object_info->type == OBJECT_TYPE_NOT_FOUND) {
/* This component of the path is invalid */
/* Return what we have of the host_pathname */
@@ -935,6 +1056,7 @@
{
const unsigned BUFSIZE = MINIMUM_BUFFER_SIZE;
char ro_path[PATH_MAX], host_pathname[PATH_MAX], ro_leaf[PATH_MAX];
+ char tmp_pathname[PATH_MAX];
risc_os_object_info object_info;
char host_path[PATH_MAX];
FILE *f;
@@ -961,12 +1083,16 @@
riscos_path_to_host(ro_path, host_path);
dbug_hostfs("\tPATH2 = %s\n", host_path);
- hostfs_path_process(ro_path, 0, host_pathname, ro_leaf, &object_info);
+ hostfs_path_process(ro_path, 0, tmp_pathname, ro_leaf, &object_info);
dbug_hostfs("\tro_path = \"%s\"\n", ro_path);
if (object_info.type != OBJECT_TYPE_NOT_FOUND) {
dbug_hostfs("\thost_pathname = \"%s\"\n\tro_leaf = \"%s\"\n",
host_pathname, ro_leaf);
}
+ if (!(object_info.disc_info && (object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE))) {
+ /* TODO handle error */
+ return;
+ }
if (object_info.type == OBJECT_TYPE_DIRECTORY) {
/* This should never occur as RISC OS checks whether a directory exists
@@ -1053,22 +1179,25 @@
{
char new_pathname[PATH_MAX];
- path_construct(host_pathname, new_pathname, sizeof(new_pathname),
- state->Reg[2], state->Reg[3]);
+ if (object_info.disc_info && (object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE)) {
+ path_construct(host_pathname, new_pathname, sizeof(new_pathname),
+ state->Reg[2], state->Reg[3]);
- if (rename(host_pathname, new_pathname)) {
- /* TODO handle error in renaming */
- }
+ if (rename(host_pathname, new_pathname)) {
+ /* TODO handle error in renaming */
+ }
- /* Update timestamp if necessary */
- if ((state->Reg[2] & 0xfff00000u) == 0xfff00000u) {
- struct utimbuf t;
+ /* Update timestamp if necessary */
+ if ((state->Reg[2] & 0xfff00000u) == 0xfff00000u) {
+ struct utimbuf t;
- t.modtime = hostfs_adfs2host_time(state->Reg[2], state->Reg[3]);
- t.actime = t.modtime;
- utime(new_pathname, &t);
- /* TODO handle error in utime() */
+ t.modtime = hostfs_adfs2host_time(state->Reg[2], state->Reg[3]);
+ t.actime = t.modtime;
+ utime(new_pathname, &t);
+ /* TODO handle error in utime() */
+ }
}
+ /* TOD: handle permission error */
}
/* TODO handle new attribs */
@@ -1131,6 +1260,9 @@
/* TODO Ensure we do not try to delete the root object: i.e. $ */
hostfs_path_process(ro_path, 0, host_pathname, ro_leaf, &object_info);
+ if (!(object_info.disc_info && (object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE))) {
+ return;
+ }
state->Reg[0] = object_info.type;
@@ -1170,9 +1302,12 @@
{
const unsigned BUFSIZE = MINIMUM_BUFFER_SIZE;
char ro_path[PATH_MAX];
+ char ro_leaf[PATH_MAX];
char host_path[PATH_MAX];
+ char tmp_path[PATH_MAX];
FILE *f;
ARMword length;
+ risc_os_object_info object_info;
assert(state);
@@ -1192,6 +1327,11 @@
dbug_hostfs("\tPATH = %s\n", ro_path);
dbug_hostfs("\tPATH2 = %s\n", host_path);
+ hostfs_path_process(ro_path, 0, tmp_path, ro_leaf, &object_info);
+ if (!(object_info.disc_info && (object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE))) {
+ return;
+ }
+
hostfs_ensure_buffer_size(BUFSIZE);
f = fopen(host_path, "wb");
@@ -1221,7 +1361,10 @@
hostfs_file_8_create_dir(ARMul_State *state)
{
char ro_path[PATH_MAX];
+ char ro_leaf[PATH_MAX];
char host_path[PATH_MAX];
+ char tmp_path[PATH_MAX];
+ risc_os_object_info object_info;
int s;
assert(state);
@@ -1239,6 +1382,10 @@
dbug_hostfs("\tPATH = %s\n", ro_path);
dbug_hostfs("\tPATH2 = %s\n", host_path);
+ hostfs_path_process(ro_path, 0, tmp_path, ro_leaf, &object_info);
+ if (!(object_info.disc_info && (object_info.disc_info->permissions & HOSTFS_DISC_WRITEABLE))) {
+ return;
+ }
#if defined __unix || __MACH__
s = mkdir(host_path, 0755);
#else
@@ -1472,6 +1619,12 @@
/* TODO Improve error return */
state->Reg[3] = 0;
state->Reg[4] = (uint32_t)-1;
+ if (object_info.type == OBJECT_TYPE_NOT_FOUND)
+ state->Reg[9] = FILECORE_ERROR_NOTFOUND;
+ else if (object_info.type == OBJECT_TYPE_DISC_NOT_FOUND)
+ state->Reg[9] = FILECORE_ERROR_BADDISC;
+ else
+ state->Reg[9] = FILECORE_ERROR_DISCERR;
return;
}
@@ -1507,7 +1660,7 @@
strcat(entry_path, "/");
strcat(entry_path, entry->d_name);
- hostfs_read_object_info(entry_path, ro_leaf, &object_info);
+ hostfs_read_object_info(entry_path, ro_leaf, &object_info, NULL);
/* Ignore entries we can not read information about,
or which are neither regular files or directories */
@@ -1547,7 +1700,7 @@
strcat(entry_path, "/");
strcat(entry_path, entry->d_name);
- hostfs_read_object_info(entry_path, ro_leaf, &object_info);
+ hostfs_read_object_info(entry_path, ro_leaf, &object_info, NULL);
/* Ignore entries we can not read information about,
or which are neither regular files or directories */
Index: src/hostfs.h
===================================================================
--- src/hostfs.h (revision 137)
+++ src/hostfs.h (working copy)
@@ -15,13 +15,24 @@
#define ARCEM_SWI_NANOSLEEP (ARCEM_SWI_CHUNK + 3)
#define ARCEM_SWI_NETWORK (ARCEM_SWI_CHUNK + 4)
+#define HOSTFS_DISC_WRITEABLE 1
+#define HOSTFS_DISC_READABLE 2
+
typedef uint32_t ARMword;
typedef struct {
uint32_t *Reg;
} ARMul_State;
+typedef struct {
+ char disc_name[80];
+ char hostfs_root[512];
+ int permissions;
+} HOSTFS_Discs;
extern void hostfs(ARMul_State *state);
+int hostfs_initialise();
+int add_hostfs_disc(const char *name, const char *path, const char *permissions);
+int get_max_hostfs_discs();
#define ARMul_LoadWordS(state, address) readmeml(address)
#define ARMul_LoadByte(state, address) readmemb(address)
Index: src/rpcemu.c
===================================================================
--- src/rpcemu.c (revision 137)
+++ src/rpcemu.c (working copy)
@@ -19,6 +19,7 @@
#include "cdrom-iso.h"
#include "podulerom.h"
#include "podules.h"
+#include "hostfs.h"
int cdromtype;
unsigned char flaglookup[16][16];
@@ -59,17 +60,10 @@
int startrpcemu()
{
- int c;
char *p;
get_executable_name(exname,511);
p=get_filename(exname);
*p=0;
- append_filename(HOSTFS_ROOT,exname,"hostfs",511);
- for (c=0;c<511;c++)
- {
- if (HOSTFS_ROOT[c]=='\\')
- HOSTFS_ROOT[c]='/';
- }
initmem();
//printf("Mem inited...\n");
loadroms();
@@ -92,7 +86,6 @@
//printf("About to init video...\n");
initvideo();
//printf("Video inited!\n");
- loadconfig();
initsound();
reallocmem(rammask+1);
initcodeblocks();
@@ -151,6 +144,11 @@
{
char fn[512];
char *p;
+ unsigned int i;
+ char *hostfs_name;
+ char *hostfs_path;
+ char *hostfs_perm;
+ char config_key[80];
append_filename(fn,exname,"rpc.cfg",511);
set_config_file(fn);
p=(char *)get_config_string(NULL,"mem_size",NULL);
@@ -188,6 +186,29 @@
mousehackon=get_config_int(NULL,"mouse_following",1);
username=get_config_string(NULL,"username",NULL);
ipaddress=get_config_string(NULL,"ipaddress",NULL);
+ hostfs_initialise();
+ for (i = 0; i < get_max_hostfs_discs(); i++) {
+ sprintf(config_key, "hostfs.drive%d.name", i);
+ hostfs_name = get_config_string(NULL, config_key, NULL);
+ if (!hostfs_name)
+ break;
+ sprintf(config_key, "hostfs.drive%d.path", i);
+ hostfs_path = get_config_string(NULL, config_key, NULL);
+ if (!hostfs_name) {
+ printf("Error: drive %d has no path\n", i);
+ break;
+ }
+ sprintf(config_key, "hostfs.drive%d.permissions", i);
+ hostfs_perm = get_config_string(NULL, config_key, NULL);
+ if (!hostfs_name) {
+ printf("Error: drive %d has no permissions\n", i);
+ break;
+ }
+ if (add_hostfs_disc(hostfs_name, hostfs_path, hostfs_perm) != 0) {
+ printf("Error: Failed to add hostfs drive %s,%s,%s\n",
+ hostfs_name, hostfs_path, hostfs_perm);
+ }
+ }
}
void saveconfig()
Index: src/rpcemu.h
===================================================================
--- src/rpcemu.h (revision 137)
+++ src/rpcemu.h (working copy)
@@ -125,6 +125,7 @@
extern void wakeupsoundthread();
extern void updateirqs(void);
extern int quited;
+extern char *rpcemu_os_expand_home_path(const char *path, char *buf, int buflen);
extern char exname[512];
extern int timetolive;
Index: src/rpc-win.c
===================================================================
--- src/rpc-win.c (revision 137)
+++ src/rpc-win.c (working copy)
@@ -31,7 +31,20 @@
int updatemips=0;
int vsyncints=0;
+char *rpcemu_os_expand_home_path(const char *path, char *buf, int buflen)
+{
+ buf[buflen-1] = '\0';
+ if (*path != '~') {
+ strncpy(buf, buflen-1, path);
+ } else {
+ // FIXME: Is this correct?
+ snprintf(buf, buflen, "%s%s", getenv("USERPROFILE"), path+1);
+ }
+
+ return buf;
+}
+
void domips(void)
{
mips=(float)inscount/1000000.0f;
@@ -333,6 +346,7 @@
ShowWindow (ghwnd, nFunsterStil);
win_set_window(ghwnd);
allegro_init();
+ loadconfig();
install_keyboard();
install_timer();
install_mouse();
Index: src/rpc-linux.c
===================================================================
--- src/rpc-linux.c (revision 137)
+++ src/rpc-linux.c (working copy)
@@ -10,6 +10,7 @@
#include "vidc20.h"
#include "gui.h"
+extern void loadconfig();
int mousecapture=0;
float mips;
@@ -22,6 +23,19 @@
static uint32_t mipscount;
float mipstotal;
+char *rpcemu_os_expand_home_path(const char *path, char *buf, int buflen)
+{
+ buf[buflen-1] = '\0';
+
+ if (*path != '~') {
+ strncpy(buf, path, buflen-1);
+ } else {
+ snprintf(buf, buflen, "%s%s", getenv("HOME"), path+1);
+ }
+
+ return buf;
+}
+
void *_soundthread(void *p)
{
int c;
@@ -215,6 +229,8 @@
infocus=1;
allegro_init();
+ // load config here before anybody needs it.
+ loadconfig();
LOCK_FUNCTION(close_button_handler);
set_close_button_callback(close_button_handler);
@@ -223,11 +239,12 @@
install_timer();
install_mouse();
+ // Init network before startrpcemu so that we have dropped root privileges before any configuration happens
+ initnetwork();
+
if (startrpcemu())
return -1;
- initnetwork();
-
install_int_ex(domips,MSEC_TO_TIMER(1000));
install_int_ex(vblupdate,BPS_TO_TIMER(refresh));
startsoundthread();
Index: src/iomd.h
===================================================================
--- src/iomd.h (revision 137)
+++ src/iomd.h (working copy)
@@ -36,8 +36,6 @@
extern uint8_t readmb(void);
extern void iomdvsync(int vsync);
-extern char HOSTFS_ROOT[512];
-
extern char discname[2][260];
extern int drawscre;
_______________________________________________
Rpcemu mailing list
[email protected]
http://www.riscos.info/cgi-bin/mailman/listinfo/rpcemu