158 lines
4.5 KiB
C
158 lines
4.5 KiB
C
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// vfs - Virtual filesystem management
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef EMU_COMPILE
|
|
#error "Hi I forgot to set EMU_COMPILE"
|
|
#endif
|
|
|
|
#include "vfs.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Static information
|
|
//
|
|
|
|
sint32 EMU_CALL vfs_init(void) { return 0; }
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// State information
|
|
//
|
|
#define VFS_MAXPATH (250)
|
|
#define VFS_MAXOPENFILES (32)
|
|
|
|
struct VFS_STATE {
|
|
psx_readfile_t readfile_cb;
|
|
void *readfile_context;
|
|
|
|
sint32 ofs[VFS_MAXOPENFILES];
|
|
sint32 length[VFS_MAXOPENFILES];
|
|
char path[VFS_MAXOPENFILES][VFS_MAXPATH];
|
|
};
|
|
|
|
#define VFSSTATE ((struct VFS_STATE*)(state))
|
|
|
|
uint32 EMU_CALL vfs_get_state_size(void) {
|
|
return sizeof(struct VFS_STATE);
|
|
}
|
|
|
|
void EMU_CALL vfs_clear_state(void *state) {
|
|
memset(VFSSTATE, 0, sizeof(struct VFS_STATE));
|
|
}
|
|
|
|
void EMU_CALL vfs_set_readfile(void *state, psx_readfile_t readfile, void *context) {
|
|
VFSSTATE->readfile_cb = readfile;
|
|
VFSSTATE->readfile_context = context;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// check if the given fd is valid
|
|
//
|
|
static sint32 EMU_CALL isvalidfd(struct VFS_STATE *state, sint32 fd) {
|
|
if(fd < 0 || fd >= VFS_MAXOPENFILES) return 0;
|
|
if(state->path[fd][0] == 0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// open
|
|
//
|
|
sint32 EMU_CALL vfs_open(void *state, const char *path) {
|
|
sint32 l;
|
|
sint32 fd;
|
|
char tempbuf[4];
|
|
if(!(VFSSTATE->readfile_cb)) return -5; // EIO if no callback was set
|
|
if(!path) return -22; // EINVAL if this was NULL for some reason
|
|
if(!path[0]) return -2; // ENOENT if the path is empty
|
|
l = (VFSSTATE->readfile_cb)(
|
|
VFSSTATE->readfile_context,
|
|
path,
|
|
0,
|
|
tempbuf,
|
|
0
|
|
);
|
|
if(l < -1) return -5; // EIO for fatal errors
|
|
if(l == -1) return -2; // ENOENT for not found
|
|
// Otherwise, find a free fd and keep it
|
|
for(fd = 0; fd < VFS_MAXOPENFILES; fd++) {
|
|
if(VFSSTATE->path[fd][0] == 0) break;
|
|
}
|
|
if(fd >= VFS_MAXOPENFILES) return -24; // EMFILE too many open files
|
|
VFSSTATE->ofs[fd] = 0;
|
|
VFSSTATE->length[fd] = l;
|
|
strncpy(VFSSTATE->path[fd], path, VFS_MAXPATH);
|
|
VFSSTATE->path[fd][VFS_MAXPATH-1] = 0;
|
|
return fd;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// close
|
|
//
|
|
sint32 EMU_CALL vfs_close(void *state, sint32 fd) {
|
|
if(!(VFSSTATE->readfile_cb)) return -5; // EIO if no callback was set
|
|
if(!isvalidfd(VFSSTATE, fd)) return -9; // EBADF
|
|
VFSSTATE->path[fd][0] = 0;
|
|
return 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// read
|
|
//
|
|
sint32 EMU_CALL vfs_read(void *state, sint32 fd, char *buffer, sint32 length) {
|
|
sint32 r;
|
|
if(!(VFSSTATE->readfile_cb)) return -5; // EIO if no callback was set
|
|
if(!isvalidfd(VFSSTATE, fd)) return -9; // EBADF
|
|
// if length is 0, just return 0
|
|
if(!length) return 0;
|
|
// if we're past end-of-file, return 0
|
|
if(VFSSTATE->ofs[fd] >= VFSSTATE->length[fd]) return 0;
|
|
// make sure we don't read past the end
|
|
{ sint32 remain = VFSSTATE->length[fd] - VFSSTATE->ofs[fd];
|
|
if(length > remain) length = remain;
|
|
}
|
|
// attempt actual read
|
|
r = (VFSSTATE->readfile_cb)(
|
|
VFSSTATE->readfile_context,
|
|
VFSSTATE->path[fd],
|
|
VFSSTATE->ofs[fd],
|
|
buffer,
|
|
length
|
|
);
|
|
if(r < -1) return -5; // EIO for fatal errors
|
|
if(r == -1) return -2; // ENOENT for not found - weird, but should work
|
|
VFSSTATE->ofs[fd] += r;
|
|
return r;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// lseek
|
|
//
|
|
sint32 EMU_CALL vfs_lseek(void *state, sint32 fd, sint32 offset, sint32 whence) {
|
|
if(!(VFSSTATE->readfile_cb)) return -5; // EIO if no callback was set
|
|
if(!isvalidfd(VFSSTATE, fd)) return -9; // EBADF
|
|
switch(whence) {
|
|
case 0: // SEEK_SET
|
|
break;
|
|
case 1: // SEEK_CUR
|
|
offset += VFSSTATE->ofs[fd];
|
|
break;
|
|
case 2: // SEEK_END
|
|
offset += VFSSTATE->length[fd];
|
|
break;
|
|
default:
|
|
return -22; // EINVAL if whence isn't right
|
|
}
|
|
if(offset < 0) return -22; // EINVAL if offset ends up negative
|
|
VFSSTATE->ofs[fd] = offset;
|
|
return offset;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|