summaryrefslogtreecommitdiff
path: root/ACE/ace/MQX_Filesystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/MQX_Filesystem.cpp')
-rw-r--r--ACE/ace/MQX_Filesystem.cpp551
1 files changed, 551 insertions, 0 deletions
diff --git a/ACE/ace/MQX_Filesystem.cpp b/ACE/ace/MQX_Filesystem.cpp
new file mode 100644
index 00000000000..3bdbe3cfb31
--- /dev/null
+++ b/ACE/ace/MQX_Filesystem.cpp
@@ -0,0 +1,551 @@
+#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_ (NULL)
+ , 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 = NULL;
+ }
+}
+
+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_ != NULL)
+ chdir ("\\");
+ return current_fs_ == NULL;
+}
+
+void
+MQX_Filesystem::update_fs (MQX_FILE_PTR fs)
+{
+ current_fs_ = fs;
+ bool invalid = false;
+ if (fs == NULL)
+ 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_ = NULL;
+ 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 == NULL) return -1;
+
+ // Call into MQX
+ file->mqx_file = _io_fopen (abspath, cstdlib_mode);
+ if (file->mqx_file == NULL)
+ {
+ 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 == NULL) 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 == NULL) 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 == NULL) 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 == NULL) 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 NULL;
+ if (buf == NULL)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ 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 NULL;
+ }
+ if ((current_fs_name_len_ + strlen (curdirtmp) + 1) > size)
+ {
+ errno = ERANGE;
+ return NULL;
+ }
+ 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 NULL;
+
+ if (fs_name_len == NULL || path == NULL || path[0] == '\0')
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+ 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 = NULL;
+ }
+ 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 == NULL) 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 == NULL) 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 == NULL) 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 == NULL) 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 == NULL || other_fs == NULL) 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 NULL;
+}
+
+MQX_Filesystem::File *
+MQX_Filesystem::get_new_file ()
+{
+ // Get Unused File Struct
+ File *file = get_file (-1);
+ if (file != NULL)
+ {
+ file->mqx_file = NULL;
+ // Get Unused File Descriptor
+ for (int fd = last_fd_ + 1; fd != last_fd_; fd++)
+ {
+ if (get_file (fd) == NULL)
+ {
+ file->fd = fd;
+ last_fd_ = fd;
+ return file;
+ }
+ if (fd == max_fd_) fd = 0;
+ }
+ }
+ errno = ENFILE;
+ return NULL;
+}
+
+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 == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int fs_name_len;
+ MQX_FILE_PTR fs = resolve_fs (path, &fs_name_len);
+ if (fs == NULL) 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 == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ File *file = get_file (fd);
+ if (file == NULL) 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