mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-13 09:17:18 +00:00
552 lines
12 KiB
C++
552 lines
12 KiB
C++
#include "MQX_Filesystem.h"
|
|
|
|
#ifdef ACE_MQX
|
|
|
|
#include "ace/OS_NS_unistd.h"
|
|
#include "ace/OS_NS_sys_stat.h"
|
|
|
|
#include <mqx.h>
|
|
#include <fio.h>
|
|
#include <mfs.h>
|
|
|
|
#include <string.h>
|
|
|
|
#ifndef FOPEN_MAX
|
|
# error "FOPEN_MAX, the max number of open files, must be defined"
|
|
#endif
|
|
#if FOPEN_MAX < 3
|
|
# error "FOPEN_MAX is less than 3, no room for standard streams, let alone other files descriptors"
|
|
#endif
|
|
|
|
#define MQX_FILE_ERROR static_cast<size_t>(-1)
|
|
|
|
MQX_Filesystem MQX_Filesystem::instance_;
|
|
|
|
MQX_Filesystem::MQX_Filesystem ()
|
|
: current_fs_ (0)
|
|
, current_fs_name_len_ (0)
|
|
, max_fd_ (255)
|
|
, last_fd_ (-1)
|
|
{
|
|
current_fs_name_[0] = '\0';
|
|
|
|
// Initialize files_
|
|
for (unsigned i = 0; i < FOPEN_MAX; i++)
|
|
{
|
|
files_[i].fd = -1;
|
|
files_[i].mqx_file = 0;
|
|
}
|
|
}
|
|
|
|
void MQX_Filesystem::complete_initialization ()
|
|
{
|
|
// Set the Standard Streams
|
|
files_[0] = {ACE_STDIN, (MQX_FILE_PTR) _io_get_handle (IO_STDIN), true};
|
|
files_[1] = {ACE_STDOUT, (MQX_FILE_PTR) _io_get_handle (IO_STDOUT), true};
|
|
files_[2] = {ACE_STDERR, (MQX_FILE_PTR) _io_get_handle (IO_STDERR), true};
|
|
|
|
/*
|
|
* Try to set the current filesystem. Ignore the error return because if
|
|
* we're missing a filesystem now, it's okay because a filesystem might be
|
|
* added later.
|
|
*/
|
|
reset_state ();
|
|
}
|
|
|
|
bool
|
|
MQX_Filesystem::check_state ()
|
|
{
|
|
if (!_io_is_fs_valid (current_fs_))
|
|
{
|
|
if (reset_state ())
|
|
{
|
|
errno = ENODEV;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
MQX_Filesystem::reset_state ()
|
|
{
|
|
update_fs (_io_get_first_valid_fs ());
|
|
if (current_fs_ != 0)
|
|
chdir ("\\");
|
|
return current_fs_ == 0;
|
|
}
|
|
|
|
void
|
|
MQX_Filesystem::update_fs (MQX_FILE_PTR fs)
|
|
{
|
|
current_fs_ = fs;
|
|
bool invalid = false;
|
|
if (fs == 0)
|
|
invalid = true;
|
|
else if (_io_get_fs_name (fs, current_fs_name_, IOCFG_FS_MAX_DEVLEN) != MQX_OK)
|
|
invalid = true;
|
|
else
|
|
current_fs_name_len_ = strlen (current_fs_name_);
|
|
|
|
if (invalid)
|
|
{
|
|
current_fs_ = 0;
|
|
current_fs_name_[0] = '\0';
|
|
current_fs_name_len_ = 0;
|
|
}
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::open (const char *path, int mode)
|
|
{
|
|
if (check_state ()) return -1;
|
|
|
|
// Convert open mode to fopen mode
|
|
bool r = ACE_BIT_DISABLED (mode, O_RDONLY);
|
|
bool w = ACE_BIT_ENABLED (mode, O_WRONLY);
|
|
bool rw = ACE_BIT_ENABLED (mode, O_RDWR);
|
|
bool a = ACE_BIT_ENABLED (mode, O_CREAT | O_APPEND);
|
|
bool t = ACE_BIT_ENABLED (mode, O_CREAT | O_TRUNC);
|
|
if (!(r || (w && (a || t)) || rw))
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
char cstdlib_mode[4] = {0}; // r/w/a, t/b, +?, null terminator
|
|
cstdlib_mode[0] = r ? 'r' : a ? 'a' : 'w';
|
|
cstdlib_mode[1] = 'b';
|
|
cstdlib_mode[2] = rw ? '+' : '\0';
|
|
|
|
/// Get Absolute Path
|
|
char cwd[FS_FILENAME_SIZE];
|
|
int mqx_error = _io_ioctl (current_fs_, IO_IOCTL_GET_CURRENT_DIR, (uint32_t*) cwd);
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
char abspath[ACE_MQX_ABS_PATH_SIZE];
|
|
mqx_error = _io_rel2abs (abspath, cwd, path, ACE_MQX_ABS_PATH_SIZE, current_fs_name_);
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
|
|
// Set up a new File Entry
|
|
File *file = get_new_file ();
|
|
if (file == 0) return -1;
|
|
|
|
// Call into MQX
|
|
file->mqx_file = _io_fopen (abspath, cstdlib_mode);
|
|
if (file->mqx_file == 0)
|
|
{
|
|
file->fd = -1; // Free File in Our Array
|
|
errno = ACE_OS::mqx_error_to_errno (_task_get_error());
|
|
if (_task_get_error() == FS_FILE_NOT_FOUND)
|
|
_task_set_error(MQX_OK);
|
|
}
|
|
|
|
return file->fd;
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::close (int fd)
|
|
{
|
|
File *file = get_file (fd);
|
|
if (file == 0) return -1;
|
|
int mqx_error = _io_fclose (file->mqx_file);
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t
|
|
MQX_Filesystem::read (int fd, unsigned char *buffer, size_t size)
|
|
{
|
|
File *file = get_file (fd);
|
|
if (file == 0) return MQX_FILE_ERROR;
|
|
int result = _io_read (file->mqx_file, buffer, size);
|
|
if (result == IO_ERROR)
|
|
{
|
|
errno = EIO;
|
|
return MQX_FILE_ERROR;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
size_t
|
|
MQX_Filesystem::write (int fd, const unsigned char *buffer, size_t size)
|
|
{
|
|
File *file = get_file (fd);
|
|
if (file == 0) return MQX_FILE_ERROR;
|
|
int result = _io_write (file->mqx_file, const_cast<unsigned char *> (buffer), size);
|
|
if (result == IO_ERROR)
|
|
{
|
|
errno = EIO;
|
|
return MQX_FILE_ERROR;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
long
|
|
MQX_Filesystem::lseek (int fd, long offset, int whence)
|
|
{
|
|
switch (whence)
|
|
{
|
|
case SEEK_SET:
|
|
whence = IO_SEEK_SET;
|
|
break;
|
|
case SEEK_CUR:
|
|
whence = IO_SEEK_CUR;
|
|
break;
|
|
case SEEK_END:
|
|
whence = IO_SEEK_END;
|
|
break;
|
|
default:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
File *file = get_file (fd);
|
|
if (file == 0) return -1;
|
|
return _io_fseek (file->mqx_file, offset, whence) == MQX_OK ? 0 : -1;
|
|
}
|
|
|
|
char*
|
|
MQX_Filesystem::getcwd (char *buf, size_t size)
|
|
{
|
|
if (check_state ()) return 0;
|
|
if (buf == 0)
|
|
{
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
char curdirtmp[FS_FILENAME_SIZE];
|
|
int mqx_error = _io_ioctl (current_fs_, IO_IOCTL_GET_CURRENT_DIR, (uint32_t*) curdirtmp);
|
|
if (mqx_error != MFS_NO_ERROR)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return 0;
|
|
}
|
|
if ((current_fs_name_len_ + strlen (curdirtmp) + 1) > size)
|
|
{
|
|
errno = ERANGE;
|
|
return 0;
|
|
}
|
|
strcpy (buf, current_fs_name_);
|
|
strcat (buf, curdirtmp);
|
|
return buf;
|
|
}
|
|
|
|
MQX_FILE_PTR
|
|
MQX_Filesystem::resolve_fs (const char *path, int *fs_name_len)
|
|
{
|
|
if (check_state ()) return 0;
|
|
|
|
if (fs_name_len == 0 || path == 0 || path[0] == '\0')
|
|
{
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
MQX_FILE_PTR fs;
|
|
char fs_name[IOCFG_FS_MAX_DEVLEN];
|
|
bool fs_in_path;
|
|
*fs_name_len = _io_get_dev_for_path (
|
|
fs_name, &fs_in_path, IOCFG_FS_MAX_DEVLEN, path, current_fs_name_);
|
|
if (fs_in_path)
|
|
{
|
|
fs = _io_get_fs_by_name (fs_name);
|
|
}
|
|
else if (*fs_name_len)
|
|
{
|
|
fs = current_fs_;
|
|
*fs_name_len = 0;
|
|
}
|
|
else
|
|
{
|
|
errno = EINVAL;
|
|
fs = 0;
|
|
}
|
|
return fs;
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::mkdir (const char *path)
|
|
{
|
|
int fs_name_len;
|
|
MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
|
|
if (fs == 0) return -1;
|
|
int mqx_error = _io_ioctl (
|
|
fs, IO_IOCTL_CREATE_SUBDIR, (uint32_t*) (path + fs_name_len));
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::chdir (const char *path)
|
|
{
|
|
int fs_name_len;
|
|
MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
|
|
if (fs == 0) return -1;
|
|
if (fs != current_fs_) update_fs(fs);
|
|
int mqx_error = _io_ioctl (fs, IO_IOCTL_CHANGE_CURRENT_DIR,
|
|
(uint32_t*) (path + fs_name_len));
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::rmdir (const char *path)
|
|
{
|
|
int fs_name_len;
|
|
MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
|
|
if (fs == 0) return -1;
|
|
int mqx_error = _io_ioctl (fs, IO_IOCTL_REMOVE_SUBDIR,
|
|
(uint32_t*) (path + fs_name_len));
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::unlink (const char *path)
|
|
{
|
|
int fs_name_len;
|
|
MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
|
|
if (fs == 0) return -1;
|
|
int mqx_error = _io_ioctl (fs, IO_IOCTL_DELETE_FILE,
|
|
(uint32_t*) (path + fs_name_len));
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::rename (const char *oldpath, const char *newpath)
|
|
{
|
|
// TODO: Handle Moving Directories?
|
|
int old_fs_name_len;
|
|
MQX_FILE_PTR fs = resolve_fs (oldpath, &old_fs_name_len);
|
|
int new_fs_name_len;
|
|
MQX_FILE_PTR other_fs = resolve_fs (newpath, &new_fs_name_len);
|
|
if (fs == 0 || other_fs == 0) return -1;
|
|
if (fs != other_fs)
|
|
{
|
|
errno = EXDEV;
|
|
return -1;
|
|
}
|
|
|
|
ACE_stat file_status;
|
|
if (this->stat (newpath, &file_status) == 0)
|
|
{
|
|
// New path already exists...
|
|
if (file_status.st_mode & S_IFREG)
|
|
{
|
|
// It's a file, we can delete it.
|
|
if (this->unlink (newpath))
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
else if (file_status.st_mode & S_IFDIR)
|
|
{
|
|
// It's a directory, we can't delete that.
|
|
errno = EEXIST;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
// Unknown type, error
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
MFS_RENAME_PARAM mfs_rename;
|
|
char oldtmp[FS_FILENAME_SIZE];
|
|
strcpy (oldtmp, oldpath + old_fs_name_len);
|
|
mfs_rename.OLD_PATHNAME = oldtmp;
|
|
char newtmp[FS_FILENAME_SIZE];
|
|
strcpy (newtmp, newpath + new_fs_name_len);
|
|
mfs_rename.NEW_PATHNAME = newtmp;
|
|
|
|
int mqx_error = _io_ioctl (fs, IO_IOCTL_RENAME_FILE, (uint32_t*) &mfs_rename);
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
MQX_Filesystem::File *
|
|
MQX_Filesystem::get_file (int fd)
|
|
{
|
|
for (int i = 0; i < FOPEN_MAX; i++)
|
|
{
|
|
if (files_[i].fd == fd) return &files_[i];
|
|
}
|
|
errno = EBADF;
|
|
return 0;
|
|
}
|
|
|
|
MQX_Filesystem::File *
|
|
MQX_Filesystem::get_new_file ()
|
|
{
|
|
// Get Unused File Struct
|
|
File *file = get_file (-1);
|
|
if (file != 0)
|
|
{
|
|
file->mqx_file = 0;
|
|
// Get Unused File Descriptor
|
|
for (int fd = last_fd_ + 1; fd != last_fd_; fd++)
|
|
{
|
|
if (get_file (fd) == 0)
|
|
{
|
|
file->fd = fd;
|
|
last_fd_ = fd;
|
|
return file;
|
|
}
|
|
if (fd == max_fd_) fd = 0;
|
|
}
|
|
}
|
|
errno = ENFILE;
|
|
return 0;
|
|
}
|
|
|
|
static inline int
|
|
mfs_file_attrs_to_stat_mode (int attributes)
|
|
{
|
|
int mode = (attributes & MFS_ATTR_DIR_NAME) ? S_IFDIR : S_IFREG;
|
|
return mode;
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::stat (const char * path, ACE_stat *statbuf)
|
|
{
|
|
if (statbuf == 0)
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
int fs_name_len;
|
|
MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
|
|
if (fs == 0) return -1;
|
|
|
|
statbuf->st_size = 0;
|
|
statbuf->st_mtime = 0;
|
|
statbuf->st_mode = 0;
|
|
statbuf->st_nlink = 0;
|
|
|
|
MFS_SEARCH_PARAM search;
|
|
search.ATTRIBUTE = MFS_SEARCH_ANY;
|
|
char tmppath[ACE_MQX_ABS_PATH_SIZE];
|
|
strcpy (&tmppath[0], path);
|
|
search.WILDCARD = &tmppath[fs_name_len];
|
|
MFS_SEARCH_DATA search_results;
|
|
search.SEARCH_DATA_PTR = &search_results;
|
|
int mqx_error = _io_ioctl (fs, IO_IOCTL_FIND_FIRST_FILE, (uint32_t *) &search);
|
|
if (mqx_error == MFS_NO_ERROR)
|
|
{
|
|
statbuf->st_size = search_results.FILE_SIZE;
|
|
statbuf->st_mode = mfs_file_attrs_to_stat_mode (search_results.ATTRIBUTE);
|
|
statbuf->st_nlink = 1;
|
|
// TODO: statbuf->st_mtime
|
|
return 0;
|
|
}
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
MQX_Filesystem::fstat (int fd, ACE_stat *statbuf)
|
|
{
|
|
if (statbuf == 0)
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
File *file = get_file (fd);
|
|
if (file == 0) return -1;
|
|
|
|
statbuf->st_size = 0;
|
|
statbuf->st_mtime = 0;
|
|
statbuf->st_mode = 0;
|
|
statbuf->st_nlink = 0;
|
|
|
|
if (file->chardev_file)
|
|
{
|
|
statbuf->st_mode &= S_IFCHR;
|
|
return 0;
|
|
}
|
|
|
|
int attributes = 0;
|
|
int mqx_error = _io_ioctl (file->mqx_file, IO_IOCTL_GET_FILE_ATTR, (uint32_t *) &attributes);
|
|
if (mqx_error != MQX_OK)
|
|
{
|
|
errno = ACE_OS::mqx_error_to_errno (mqx_error);
|
|
return -1;
|
|
}
|
|
statbuf->st_mode = mfs_file_attrs_to_stat_mode (attributes);
|
|
statbuf->st_nlink = 1;
|
|
|
|
// TODO: statbuf->st_mtime
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* The following are the function definitions that DLib will use to access MQX
|
|
* IO through MQX_Filesystem.
|
|
*/
|
|
|
|
extern "C" {
|
|
|
|
int __open (const char *filename, int mode)
|
|
{
|
|
return MQX_Filesystem::inst ().open (filename, mode);
|
|
}
|
|
|
|
size_t __read (int handle, unsigned char *buffer, size_t size)
|
|
{
|
|
return MQX_Filesystem::inst ().read (handle, buffer, size);
|
|
}
|
|
|
|
size_t __write (int handle, const unsigned char *buffer, size_t size)
|
|
{
|
|
return MQX_Filesystem::inst ().write (handle, buffer, size);
|
|
}
|
|
|
|
long __lseek (int handle, long offset, int whence)
|
|
{
|
|
return MQX_Filesystem::inst ().lseek (handle, offset, whence);
|
|
}
|
|
|
|
int __close (int handle)
|
|
{
|
|
return MQX_Filesystem::inst ().close (handle);
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
#endif // ACE_MQX
|