minix/sound.h minix/spin.h minix/sys_config.h minix/sysinfo.h \
minix/syslib.h minix/sysutil.h minix/timers.h minix/type.h \
minix/tty.h minix/u64.h minix/usb.h minix/usb_ch9.h minix/vbox.h \
- minix/vboxif.h minix/vboxtype.h minix/vm.h \
+ minix/vboxfs.h minix/vboxif.h minix/vboxtype.h minix/vm.h \
minix/vfsif.h minix/vtreefs.h minix/libminixfs.h minix/netsock.h
INCS+= net/gen/arp_io.h net/gen/dhcp.h net/gen/ether.h \
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#ifndef _MINIX_VBOXFS_H
+#define _MINIX_VBOXFS_H
+
+#include <minix/sffs.h>
+
+int vboxfs_init(char *share, const struct sffs_table **tablep,
+ int *case_insens, int *read_only);
+void vboxfs_cleanup(void);
+
+#endif /* _MINIX_VBOXFS_H */
libexec libdevman libusb libminlib libasyn \
libddekit libminixfs libbdev libelf libminc libcrypt libterminfo \
libcurses libvassert libutil libpuffs librefuse libbz2 libarchive \
- libprop libnetsock libsffs libhgfs
+ libprop libnetsock libsffs libhgfs libvboxfs
SUBDIR+= ../external/public-domain/xz/lib
--- /dev/null
+# Makefile for libvboxfs
+.include <bsd.own.mk>
+
+LIB= vboxfs
+
+SRCS= attr.c dir.c file.c handle.c info.c link.c path.c vboxfs.c
+
+.include <bsd.lib.mk>
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#include "inc.h"
+
+/*
+ * Convert a VirtualBox timestamp to a POSIX timespec structure.
+ * VirtualBox' timestamps are in nanoseconds since the UNIX epoch.
+ */
+static void
+get_time(struct timespec *tsp, u64_t nsecs)
+{
+
+ tsp->tv_sec = div64u(nsecs, 1000000000);
+ tsp->tv_nsec = rem64u(nsecs, 1000000000);
+}
+
+/*
+ * Convert a POSIX timespec structure to a VirtualBox timestamp.
+ */
+static u64_t
+set_time(struct timespec *tsp)
+{
+
+ return add64u(mul64u(tsp->tv_sec, 1000000000), tsp->tv_nsec);
+}
+
+/*
+ * Fill the given attribute structure with VirtualBox object information.
+ */
+void
+vboxfs_get_attr(struct sffs_attr *attr, vboxfs_objinfo_t *info)
+{
+
+ if (attr->a_mask & SFFS_ATTR_SIZE)
+ attr->a_size = info->size;
+ if (attr->a_mask & SFFS_ATTR_MODE)
+ attr->a_mode = VBOXFS_GET_MODE(info->attr.mode);
+ if (attr->a_mask & SFFS_ATTR_ATIME)
+ get_time(&attr->a_atime, info->atime);
+ if (attr->a_mask & SFFS_ATTR_MTIME)
+ get_time(&attr->a_mtime, info->mtime);
+ if (attr->a_mask & SFFS_ATTR_CTIME)
+ get_time(&attr->a_ctime, info->ctime);
+ if (attr->a_mask & SFFS_ATTR_CRTIME)
+ get_time(&attr->a_crtime, info->crtime);
+}
+
+/*
+ * Get file attributes.
+ */
+int
+vboxfs_getattr(char *path, struct sffs_attr *attr)
+{
+ vbox_param_t param[3];
+ vboxfs_path_t pathbuf;
+ vboxfs_crinfo_t crinfo;
+ int r;
+
+ if ((r = vboxfs_set_path(&pathbuf, path)) != OK)
+ return r;
+
+ memset(&crinfo, 0, sizeof(crinfo));
+ crinfo.flags = VBOXFS_CRFLAG_LOOKUP;
+ /* crinfo.info.attr.add is not checked */
+
+ vbox_set_u32(¶m[0], vboxfs_root);
+ vbox_set_ptr(¶m[1], &pathbuf, vboxfs_get_path_size(&pathbuf),
+ VBOX_DIR_OUT);
+ vbox_set_ptr(¶m[2], &crinfo, sizeof(crinfo), VBOX_DIR_INOUT);
+
+ r = vbox_call(vboxfs_conn, VBOXFS_CALL_CREATE, param, 3, NULL);
+ if (r != OK)
+ return r;
+
+ switch (crinfo.result) {
+ case VBOXFS_PATH_NOT_FOUND:
+ /* This could also be ENOTDIR. See note in handle.c. */
+ case VBOXFS_FILE_NOT_FOUND:
+ return ENOENT;
+ case VBOXFS_FILE_EXISTS:
+ break; /* success */
+ default:
+ return EIO; /* should never happen */
+ }
+
+ vboxfs_get_attr(attr, &crinfo.info);
+
+ return OK;
+}
+
+/*
+ * Set file size.
+ */
+static int
+set_size(char *path, u64_t size)
+{
+ vboxfs_objinfo_t info;
+ vboxfs_handle_t h;
+ int r;
+
+ if ((r = vboxfs_open_file(path, O_WRONLY, S_IFREG, &h, NULL)) != OK)
+ return r;
+
+ memset(&info, 0, sizeof(info));
+ info.size = size;
+
+ r = vboxfs_getset_info(h, VBOXFS_INFO_SET | VBOXFS_INFO_SIZE, &info,
+ sizeof(info));
+
+ vboxfs_close_file(h);
+
+ return r;
+}
+
+/*
+ * Set file attributes.
+ */
+int
+vboxfs_setattr(char *path, struct sffs_attr *attr)
+{
+ vboxfs_objinfo_t info;
+ vboxfs_handle_t h;
+ int r;
+
+ /*
+ * Setting the size of a path cannot be combined with other attribute
+ * modifications, because we cannot fail atomically.
+ */
+ if (attr->a_mask & SFFS_ATTR_SIZE) {
+ assert(attr->a_mask == SFFS_ATTR_SIZE);
+
+ return set_size(path, attr->a_size);
+ }
+
+ /*
+ * By passing a pointer to an object information structure, we open the
+ * file for attribute manipulation. Note that this call will open the
+ * file as a regular file. This works on directories as well.
+ */
+ if ((r = vboxfs_open_file(path, O_WRONLY, 0, &h, &info)) != OK)
+ return r;
+
+ info.attr.add = VBOXFS_OBJATTR_ADD_NONE;
+
+ /* Update the file's permissions if requested. */
+ if (attr->a_mask & SFFS_ATTR_MODE)
+ info.attr.mode =
+ VBOXFS_SET_MODE(info.attr.mode & S_IFMT, attr->a_mode);
+
+ /*
+ * Update various file times if requested. Not all changes may
+ * be honered. A zero time indicates no change.
+ */
+ info.atime = (attr->a_mask & SFFS_ATTR_ATIME) ?
+ set_time(&attr->a_atime) : 0;
+ info.mtime = (attr->a_mask & SFFS_ATTR_MTIME) ?
+ set_time(&attr->a_ctime) : 0;
+ info.ctime = (attr->a_mask & SFFS_ATTR_CTIME) ?
+ set_time(&attr->a_ctime) : 0;
+ info.crtime = (attr->a_mask & SFFS_ATTR_CRTIME) ?
+ set_time(&attr->a_crtime) : 0;
+
+ r = vboxfs_getset_info(h, VBOXFS_INFO_SET | VBOXFS_INFO_FILE, &info,
+ sizeof(info));
+
+ vboxfs_close_file(h);
+
+ return r;
+}
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#include "inc.h"
+
+/*
+ * Directories will generally be accessed sequentially, but there is no
+ * guarantee that this is actually the case. In particular, multiple user
+ * processes may iterate over the same directory concurrently, and since
+ * process information is lost in the VFS/FS protocol, the result is a
+ * nonsequential pattern on the same single directory handle. Therefore, we
+ * must support random access. Since the VirtualBox shared folders interface
+ * does not allow for random access (the resume point cannot be used for this),
+ * we choose to read in the contents of the directory upon open, and cache it
+ * until the directory is closed again. The risk is that the cached contents
+ * will go stale.
+ *
+ * The directory will always be closed once one reader finishes going through
+ * the entire directory, so the problem is rather limited anyway. Ideally, the
+ * directory contents would be refreshed upon any invalidating local action as
+ * well as after a certain time span (since the file system can be changed from
+ * the host as well). This is currently not implemented, because the odds of
+ * things going wrong are pretty small, and the effects are not devastating.
+ *
+ * The calling functions may also request the same directory entry twice in a
+ * row, because the entry does not fit in the user buffer the first time. The
+ * routines here optimize for repeat-sequential access, while supporting fully
+ * random access as well.
+ */
+
+#define VBOXFS_DIRDATA_SIZE 8192 /* data allocation granularity */
+
+typedef struct vboxfs_dirblock_s {
+ STAILQ_ENTRY(vboxfs_dirblock_s) next;
+ unsigned int count;
+ char data[VBOXFS_DIRDATA_SIZE];
+} vboxfs_dirblock_t;
+
+typedef struct {
+ STAILQ_HEAD(blocks, vboxfs_dirblock_s) blocks;
+ unsigned int index;
+ vboxfs_dirblock_t *block;
+ unsigned int bindex;
+ unsigned int bpos;
+} vboxfs_dirdata_t;
+
+/*
+ * Free the memory allocated for the given directory contents storage.
+ */
+static void
+free_dir(vboxfs_dirdata_t *dirdata)
+{
+ vboxfs_dirblock_t *block;
+
+ while (!STAILQ_EMPTY(&dirdata->blocks)) {
+ block = STAILQ_FIRST(&dirdata->blocks);
+
+ STAILQ_REMOVE_HEAD(&dirdata->blocks, next);
+
+ free(block);
+ }
+
+ free(dirdata);
+}
+
+/*
+ * Read all the contents of the given directory, allocating memory as needed to
+ * store the data.
+ */
+static int
+read_dir(vboxfs_handle_t handle, sffs_dir_t *dirp)
+{
+ vboxfs_dirdata_t *dirdata;
+ vboxfs_dirblock_t *block;
+ vbox_param_t param[8];
+ unsigned int count;
+ int r;
+
+ dirdata = (vboxfs_dirdata_t *) malloc(sizeof(vboxfs_dirdata_t));
+ if (dirdata == NULL)
+ return ENOMEM;
+
+ memset(dirdata, 0, sizeof(*dirdata));
+ STAILQ_INIT(&dirdata->blocks);
+
+ r = OK;
+
+ do {
+ block =
+ (vboxfs_dirblock_t *) malloc(sizeof(vboxfs_dirblock_t));
+ if (block == NULL) {
+ r = ENOMEM;
+ break;
+ }
+
+ vbox_set_u32(¶m[0], vboxfs_root);
+ vbox_set_u64(¶m[1], handle);
+ vbox_set_u32(¶m[2], 0); /* flags */
+ vbox_set_u32(¶m[3], sizeof(block->data));
+ vbox_set_ptr(¶m[4], NULL, 0, VBOX_DIR_OUT);
+ vbox_set_ptr(¶m[5], block->data, sizeof(block->data),
+ VBOX_DIR_IN);
+ vbox_set_u32(¶m[6], 0); /* resume point */
+ vbox_set_u32(¶m[7], 0); /* number of files */
+
+ /* If the call fails, stop. */
+ if ((r = vbox_call(vboxfs_conn, VBOXFS_CALL_LIST, param, 8,
+ NULL)) != OK) {
+ free(block);
+ break;
+ }
+
+ /* If the number of returned files is zero, stop. */
+ if ((count = vbox_get_u32(¶m[7])) == 0) {
+ free(block);
+ break;
+ }
+
+ /*
+ * Add the block to the list. We could realloc() the block to
+ * free unused tail space, but this is not likely to gain us
+ * much in general.
+ */
+ block->count = count;
+ STAILQ_INSERT_TAIL(&dirdata->blocks, block, next);
+
+ /* Continue until a zero resume point is returned. */
+ } while (vbox_get_u32(¶m[6]) != 0);
+
+ if (r != OK) {
+ free_dir(dirdata);
+
+ return r;
+ }
+
+ dirdata->block = STAILQ_FIRST(&dirdata->blocks);
+
+ *dirp = (sffs_dir_t) dirdata;
+
+ return OK;
+}
+
+/*
+ * Open a directory.
+ */
+int
+vboxfs_opendir(char *path, sffs_dir_t *handle)
+{
+ vboxfs_handle_t h;
+ int r;
+
+ /* Open the directory. */
+ if ((r = vboxfs_open_file(path, O_RDONLY, S_IFDIR, &h, NULL)) != OK)
+ return r;
+
+ /*
+ * Upon success, read in the full contents of the directory right away.
+ * If it succeeds, this will also set the caller's directory handle.
+ */
+ r = read_dir(h, handle);
+
+ /* We do not need the directory to be open anymore now. */
+ vboxfs_close_file(h);
+
+ return r;
+}
+
+/*
+ * Read one entry from a directory. On success, copy the name into buf, and
+ * return the requested attributes. If the name (including terminating null)
+ * exceeds size, return ENAMETOOLONG. Do not return dot and dot-dot entries.
+ * Return ENOENT if the index exceeds the number of files.
+ */
+int
+vboxfs_readdir(sffs_dir_t handle, unsigned int index, char *buf, size_t size,
+ struct sffs_attr *attr)
+{
+ vboxfs_dirdata_t *dirdata;
+ vboxfs_dirinfo_t *dirinfo;
+ int r;
+
+ dirdata = (vboxfs_dirdata_t *) handle;
+
+ /*
+ * If the saved index exceeds the requested index, start from the
+ * beginning.
+ */
+ if (dirdata->index > index) {
+ dirdata->index = 0;
+ dirdata->bindex = 0;
+ dirdata->bpos = 0;
+ dirdata->block = STAILQ_FIRST(&dirdata->blocks);
+ }
+
+ /* Loop until we find the requested entry or we run out of entries. */
+ while (dirdata->block != NULL) {
+ dirinfo =
+ (vboxfs_dirinfo_t *) &dirdata->block->data[dirdata->bpos];
+
+ /* Consider all entries that are not dot or dot-dot. */
+ if (dirinfo->name.len > 2 || dirinfo->name.data[0] != '.' ||
+ (dirinfo->name.len == 2 && dirinfo->name.data[1] != '.')) {
+
+ if (dirdata->index == index)
+ break;
+
+ dirdata->index++;
+ }
+
+ /* Advance to the next entry. */
+ dirdata->bpos += offsetof(vboxfs_dirinfo_t, name) +
+ offsetof(vboxfs_path_t, data) + dirinfo->name.size;
+ if (++dirdata->bindex >= dirdata->block->count) {
+ dirdata->block = STAILQ_NEXT(dirdata->block, next);
+ dirdata->bindex = 0;
+ dirdata->bpos = 0;
+ }
+ }
+
+ /* Not enough files to satisfy the request? */
+ if (dirdata->block == NULL)
+ return ENOENT;
+
+ /* Return the information for the file we found. */
+ if ((r = vboxfs_get_path(&dirinfo->name, buf, size)) != OK)
+ return r;
+
+ vboxfs_get_attr(attr, &dirinfo->info);
+
+ return OK;
+}
+
+/*
+ * Close a directory.
+ */
+int
+vboxfs_closedir(sffs_dir_t handle)
+{
+ vboxfs_dirdata_t *dirdata;
+
+ dirdata = (vboxfs_dirdata_t *) handle;
+
+ free_dir(dirdata);
+
+ return OK;
+}
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#include "inc.h"
+
+/*
+ * We perform all file I/O using a local, intermediate buffer. While in theory
+ * it would be possible to perform direct DMA from/to the user process, this
+ * does not work in practice: on short reads, VirtualBox copies back the entire
+ * provided buffer rather than only the part actually filled, resulting in the
+ * unused part of the buffer being clobbered. Marking the buffer as bi-
+ * directional would solve this, except it would also eliminate all the
+ * zero-copy benefits for reads; in addition, it is prevented by the protection
+ * set on the given grant.
+ */
+
+#define VBOXFS_MAX_FILEIO 65536 /* maximum I/O chunk size */
+
+static char iobuf[VBOXFS_MAX_FILEIO];
+
+/*
+ * Open a file.
+ */
+int
+vboxfs_open(char *path, int flags, int mode, sffs_file_t *handle)
+{
+ vboxfs_handle_t *handlep;
+ int r;
+
+ handlep = (vboxfs_handle_t *) malloc(sizeof(*handlep));
+
+ if ((r = vboxfs_open_file(path, flags, mode, handlep, NULL)) != OK) {
+ free(handlep);
+
+ return r;
+ }
+
+ *handle = (sffs_file_t) handlep;
+
+ return OK;
+}
+
+/*
+ * Read or write a chunk from or to a file.
+ */
+static ssize_t
+read_write(vboxfs_handle_t handle, char *buf, size_t size, u64_t pos,
+ int write)
+{
+ vbox_param_t param[5];
+ int r, dir, call;
+
+ dir = write ? VBOX_DIR_OUT : VBOX_DIR_IN;
+ call = write ? VBOXFS_CALL_WRITE : VBOXFS_CALL_READ;
+
+ vbox_set_u32(¶m[0], vboxfs_root);
+ vbox_set_u64(¶m[1], handle);
+ vbox_set_u64(¶m[2], pos);
+ vbox_set_u32(¶m[3], size);
+ vbox_set_ptr(¶m[4], buf, size, dir);
+
+ if ((r = vbox_call(vboxfs_conn, call, param, 5, NULL)) != OK)
+ return r;
+
+ return vbox_get_u32(¶m[3]);
+}
+
+/*
+ * Read from a file.
+ */
+ssize_t
+vboxfs_read(sffs_file_t handle, char *buf, size_t size, u64_t pos)
+{
+ vboxfs_handle_t *handlep;
+
+ handlep = (vboxfs_handle_t *) handle;
+
+ return read_write(*handlep, buf, size, pos, FALSE /*write*/);
+}
+
+/*
+ * Write to a file.
+ */
+ssize_t
+vboxfs_write(sffs_file_t handle, char *buf, size_t len, u64_t pos)
+{
+ vboxfs_handle_t *handlep;
+
+ handlep = (vboxfs_handle_t *) handle;
+
+ return read_write(*handlep, buf, len, pos, TRUE /*write*/);
+}
+
+/*
+ * Close a file handle.
+ */
+int
+vboxfs_close(sffs_file_t handle)
+{
+ vboxfs_handle_t *handlep;
+
+ handlep = (vboxfs_handle_t *) handle;
+
+ vboxfs_close_file(*handlep);
+
+ free(handlep);
+
+ return OK;
+}
+
+/*
+ * Return an internal buffer address and size for I/O operations.
+ */
+size_t
+vboxfs_buffer(char **ptr)
+{
+
+ *ptr = iobuf;
+ return sizeof(iobuf);
+}
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#ifndef _VBOXFS_GLO_H
+#define _VBOXFS_GLO_H
+
+extern vbox_conn_t vboxfs_conn;
+extern vboxfs_root_t vboxfs_root;
+
+#endif /* !_VBOXFS_GLO_H */
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#include "inc.h"
+
+/*
+ * Create or open a file or directory.
+ */
+int
+vboxfs_open_file(char *path, int flags, int mode, vboxfs_handle_t *handlep,
+ vboxfs_objinfo_t *infop)
+{
+ vbox_param_t param[3];
+ vboxfs_path_t pathbuf;
+ vboxfs_crinfo_t crinfo;
+ int r, dir, rflag, wflag;
+
+ if ((r = vboxfs_set_path(&pathbuf, path)) != OK)
+ return r;
+
+ memset(&crinfo, 0, sizeof(crinfo));
+
+ /*
+ * Note that the mode may not be set at all. If no new file may be
+ * created, this is not a problem. The following test succeeds only if
+ * the caller explicitly specified that a directory is involved.
+ */
+ dir = S_ISDIR(mode);
+
+ /* Convert open(2) flags to VirtualBox creation flags. */
+ if (flags & O_APPEND)
+ return EINVAL; /* not supported at this time */
+
+ if (flags & O_CREAT) {
+ crinfo.flags = VBOXFS_CRFLAG_CREATE_IF_NEW;
+
+ if (flags & O_EXCL)
+ crinfo.flags |= VBOXFS_CRFLAG_FAIL_IF_EXISTS;
+ else if (flags & O_TRUNC)
+ crinfo.flags |= VBOXFS_CRFLAG_TRUNC_IF_EXISTS;
+ else
+ crinfo.flags |= VBOXFS_CRFLAG_OPEN_IF_EXISTS;
+ } else {
+ crinfo.flags = VBOXFS_CRFLAG_FAIL_IF_NEW;
+
+ if (flags & O_TRUNC)
+ crinfo.flags |= VBOXFS_CRFLAG_TRUNC_IF_EXISTS;
+ else
+ crinfo.flags |= VBOXFS_CRFLAG_OPEN_IF_EXISTS;
+ }
+
+ /*
+ * If an object information structure is given, open the file only to
+ * retrieve or change its attributes.
+ */
+ if (infop != NULL) {
+ rflag = VBOXFS_CRFLAG_READ_ATTR;
+ wflag = VBOXFS_CRFLAG_WRITE_ATTR;
+ } else {
+ rflag = VBOXFS_CRFLAG_READ;
+ wflag = VBOXFS_CRFLAG_WRITE;
+ }
+
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY: crinfo.flags |= rflag; break;
+ case O_WRONLY: crinfo.flags |= wflag; break;
+ case O_RDWR: crinfo.flags |= rflag | wflag; break;
+ default: return EINVAL;
+ }
+
+ if (S_ISDIR(mode))
+ crinfo.flags |= VBOXFS_CRFLAG_DIRECTORY;
+
+ crinfo.info.attr.mode = VBOXFS_SET_MODE(dir ? S_IFDIR : S_IFREG, mode);
+ crinfo.info.attr.add = VBOXFS_OBJATTR_ADD_NONE;
+
+ vbox_set_u32(¶m[0], vboxfs_root);
+ vbox_set_ptr(¶m[1], &pathbuf, vboxfs_get_path_size(&pathbuf),
+ VBOX_DIR_OUT);
+ vbox_set_ptr(¶m[2], &crinfo, sizeof(crinfo), VBOX_DIR_INOUT);
+
+ r = vbox_call(vboxfs_conn, VBOXFS_CALL_CREATE, param, 3, NULL);
+ if (r != OK)
+ return r;
+
+ if (crinfo.handle == VBOXFS_INVALID_HANDLE) {
+ switch (crinfo.result) {
+ case VBOXFS_PATH_NOT_FOUND:
+ /*
+ * This could also mean ENOTDIR, but there does not
+ * appear to be any way to distinguish that case.
+ * Verifying with extra lookups seems overkill.
+ */
+ case VBOXFS_FILE_NOT_FOUND:
+ return ENOENT;
+ case VBOXFS_FILE_EXISTS:
+ return EEXIST;
+ default:
+ return EIO; /* should never happen */
+ }
+ }
+
+ *handlep = crinfo.handle;
+ if (infop != NULL)
+ *infop = crinfo.info;
+ return OK;
+}
+
+/*
+ * Close an open file handle.
+ */
+void
+vboxfs_close_file(vboxfs_handle_t handle)
+{
+ vbox_param_t param[2];
+
+ vbox_set_u32(¶m[0], vboxfs_root);
+ vbox_set_u64(¶m[1], handle);
+
+ /* Ignore errors here. We cannot do anything with them anyway. */
+ (void) vbox_call(vboxfs_conn, VBOXFS_CALL_CLOSE, param, 2, NULL);
+}
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#ifndef _VBOXFS_INC_H
+#define _VBOXFS_INC_H
+
+#include <minix/drivers.h>
+#include <minix/vbox.h>
+#include <minix/sffs.h>
+#include <minix/vboxfs.h>
+#include <sys/queue.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include "vboxfs.h"
+#include "glo.h"
+#include "proto.h"
+
+#endif /* !_VBOXFS_INC_H */
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#include "inc.h"
+
+/*
+ * Get or set file information.
+ */
+int
+vboxfs_getset_info(vboxfs_handle_t handle, u32_t flags, void *data,
+ size_t size)
+{
+ vbox_param_t param[5];
+
+ vbox_set_u32(¶m[0], vboxfs_root);
+ vbox_set_u64(¶m[1], handle);
+ vbox_set_u32(¶m[2], flags);
+ vbox_set_u32(¶m[3], size);
+ vbox_set_ptr(¶m[4], data, size, VBOX_DIR_INOUT);
+
+ return vbox_call(vboxfs_conn, VBOXFS_CALL_INFO, param, 5, NULL);
+}
+
+/*
+ * Query volume information.
+ */
+int
+vboxfs_query_vol(char *path, vboxfs_volinfo_t *volinfo)
+{
+ vboxfs_handle_t h;
+ int r;
+
+ if ((r = vboxfs_open_file(path, O_RDONLY, 0, &h, NULL)) != OK)
+ return r;
+
+ r = vboxfs_getset_info(h, VBOXFS_INFO_GET | VBOXFS_INFO_VOLUME,
+ volinfo, sizeof(*volinfo));
+
+ vboxfs_close_file(h);
+
+ return r;
+}
+
+/*
+ * Query volume information.
+ */
+int
+vboxfs_queryvol(char *path, u64_t *free, u64_t *total)
+{
+ vboxfs_volinfo_t volinfo;
+ int r;
+
+ if ((r = vboxfs_query_vol(path, &volinfo)) != OK)
+ return r;
+
+ *free = volinfo.free;
+ *total = volinfo.total;
+ return OK;
+}
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#include "inc.h"
+
+/*
+ * Create a directory.
+ */
+int
+vboxfs_mkdir(char *path, int mode)
+{
+ vboxfs_handle_t h;
+ int r;
+
+ assert(S_ISDIR(mode));
+
+ if ((r = vboxfs_open_file(path, O_CREAT | O_EXCL | O_WRONLY, mode, &h,
+ NULL)) != OK)
+ return r;
+
+ vboxfs_close_file(h);
+
+ return r;
+}
+
+/*
+ * Remove a file or directory.
+ */
+static int
+remove_file(char *path, int dir)
+{
+ vbox_param_t param[3];
+ vboxfs_path_t pathbuf;
+ int r;
+
+ if ((r = vboxfs_set_path(&pathbuf, path)) != OK)
+ return r;
+
+ /* FIXME: symbolic links are not supported at all yet */
+ vbox_set_u32(¶m[0], vboxfs_root);
+ vbox_set_ptr(¶m[1], &pathbuf, vboxfs_get_path_size(&pathbuf),
+ VBOX_DIR_OUT);
+ vbox_set_u32(¶m[2], dir ? VBOXFS_REMOVE_DIR : VBOXFS_REMOVE_FILE);
+
+ return vbox_call(vboxfs_conn, VBOXFS_CALL_REMOVE, param, 3, NULL);
+}
+
+/*
+ * Unlink a file.
+ */
+int
+vboxfs_unlink(char *path)
+{
+
+ return remove_file(path, FALSE /*dir*/);
+}
+
+/*
+ * Remove a directory.
+ */
+int
+vboxfs_rmdir(char *path)
+{
+
+ return remove_file(path, TRUE /*dir*/);
+}
+
+/*
+ * Rename a file or directory.
+ */
+static int
+rename_file(char *opath, char *npath, int dir)
+{
+ vbox_param_t param[4];
+ vboxfs_path_t opathbuf, npathbuf;
+ u32_t flags;
+ int r;
+
+ if ((r = vboxfs_set_path(&opathbuf, opath)) != OK)
+ return r;
+
+ if ((r = vboxfs_set_path(&npathbuf, npath)) != OK)
+ return r;
+
+ flags = dir ? VBOXFS_RENAME_DIR : VBOXFS_RENAME_FILE;
+ flags |= VBOXFS_RENAME_REPLACE;
+
+ vbox_set_u32(¶m[0], vboxfs_root);
+ vbox_set_ptr(¶m[1], &opathbuf, vboxfs_get_path_size(&opathbuf),
+ VBOX_DIR_OUT);
+ vbox_set_ptr(¶m[2], &npathbuf, vboxfs_get_path_size(&npathbuf),
+ VBOX_DIR_OUT);
+ vbox_set_u32(¶m[3], flags);
+
+ return vbox_call(vboxfs_conn, VBOXFS_CALL_RENAME, param, 4, NULL);
+}
+
+/*
+ * Rename a file or directory.
+ */
+int
+vboxfs_rename(char *opath, char *npath)
+{
+ int r;
+
+ if ((r = rename_file(opath, npath, FALSE /*dir*/)) != EISDIR)
+ return r;
+
+ return rename_file(opath, npath, TRUE /*dir*/);
+}
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#include "inc.h"
+
+/*
+ * Store a local path name in the given path object, performing any necessary
+ * conversions. The path object is expected to be used read-only, so the size
+ * of the path object is set as small as possible. If 'name' is NULL, the path
+ * will be initialized to the empty string.
+ */
+int
+vboxfs_set_path(vboxfs_path_t *path, char *name)
+{
+ size_t len;
+
+ len = strlen(name);
+
+ /* FIXME: missing UTF-8 conversion */
+
+ if (len >= sizeof(path->data))
+ return ENAMETOOLONG;
+
+ strcpy(path->data, name);
+
+ path->len = len;
+ path->size = len + 1;
+
+ return OK;
+}
+
+/*
+ * Retrieve the path name from the given path object. Make sure the name fits
+ * in the given name buffer first. The given size must include room for a
+ * terminating null character.
+ */
+int
+vboxfs_get_path(vboxfs_path_t *path, char *name, size_t size)
+{
+
+ /* FIXME: missing UTF-8 conversion */
+
+ if (path->len >= size)
+ return ENAMETOOLONG;
+
+ assert(path->data[path->len] == 0);
+
+ strcpy(name, path->data);
+
+ return OK;
+}
+
+/*
+ * Return the byte size of a previously initialized path object.
+ */
+size_t
+vboxfs_get_path_size(vboxfs_path_t *path)
+{
+
+ return offsetof(vboxfs_path_t, data) + path->size;
+}
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#ifndef _VBOXFS_PROTO_H
+#define _VBOXFS_PROTO_H
+
+/* attr.c */
+void vboxfs_get_attr(struct sffs_attr *attr, vboxfs_objinfo_t *info);
+int vboxfs_getattr(char *path, struct sffs_attr *attr);
+int vboxfs_setattr(char *path, struct sffs_attr *attr);
+
+/* dir.c */
+int vboxfs_opendir(char *path, sffs_dir_t *handle);
+int vboxfs_readdir(sffs_dir_t handle, unsigned int index, char *buf,
+ size_t size, struct sffs_attr *attr);
+int vboxfs_closedir(sffs_dir_t handle);
+
+/* file.c */
+int vboxfs_open(char *path, int flags, int mode, sffs_file_t *handle);
+ssize_t vboxfs_read(sffs_file_t handle, char *buf, size_t size, u64_t pos);
+ssize_t vboxfs_write(sffs_file_t handle, char *buf, size_t len, u64_t pos);
+int vboxfs_close(sffs_file_t handle);
+size_t vboxfs_buffer(char **ptr);
+
+/* handle.c */
+int vboxfs_open_file(char *path, int flags, int mode, vboxfs_handle_t *handlep,
+ vboxfs_objinfo_t *infop);
+void vboxfs_close_file(vboxfs_handle_t handle);
+
+/* info.c */
+int vboxfs_getset_info(vboxfs_handle_t handle, u32_t flags, void *data,
+ size_t size);
+int vboxfs_query_vol(char *path, vboxfs_volinfo_t *volinfo);
+int vboxfs_queryvol(char *path, u64_t *free, u64_t *total);
+
+/* link.c */
+int vboxfs_mkdir(char *path, int mode);
+int vboxfs_unlink(char *path);
+int vboxfs_rmdir(char *path);
+int vboxfs_rename(char *opath, char *npath);
+
+/* path.c */
+int vboxfs_set_path(vboxfs_path_t *path, char *name);
+int vboxfs_get_path(vboxfs_path_t *path, char *name, size_t size);
+size_t vboxfs_get_path_size(vboxfs_path_t *path);
+
+#endif /* !_VBOXFS_PROTO_H */
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#include "inc.h"
+
+vbox_conn_t vboxfs_conn;
+vboxfs_root_t vboxfs_root;
+
+static struct sffs_table vboxfs_table = {
+ .t_open = vboxfs_open,
+ .t_read = vboxfs_read,
+ .t_write = vboxfs_write,
+ .t_close = vboxfs_close,
+
+ .t_readbuf = vboxfs_buffer,
+ .t_writebuf = vboxfs_buffer,
+
+ .t_opendir = vboxfs_opendir,
+ .t_readdir = vboxfs_readdir,
+ .t_closedir = vboxfs_closedir,
+
+ .t_getattr = vboxfs_getattr,
+ .t_setattr = vboxfs_setattr,
+
+ .t_mkdir = vboxfs_mkdir,
+ .t_unlink = vboxfs_unlink,
+ .t_rmdir = vboxfs_rmdir,
+ .t_rename = vboxfs_rename,
+
+ .t_queryvol = vboxfs_queryvol
+};
+
+/*
+ * Initialize communication with the VBOX driver, and map the given share.
+ */
+int
+vboxfs_init(char *share, const struct sffs_table **tablep, int *case_insens,
+ int *read_only)
+{
+ vbox_param_t param[4];
+ vboxfs_path_t path;
+ vboxfs_volinfo_t volinfo;
+ int r;
+
+ if ((r = vboxfs_set_path(&path, share)) != OK)
+ return r;
+
+ if ((r = vbox_init()) != OK)
+ return r;
+
+ if ((vboxfs_conn = r = vbox_open("VBoxSharedFolders")) < 0)
+ return r;
+
+ r = vbox_call(vboxfs_conn, VBOXFS_CALL_SET_UTF8, NULL, 0, NULL);
+ if (r != OK) {
+ vbox_close(vboxfs_conn);
+
+ return r;
+ }
+
+ vbox_set_ptr(¶m[0], &path, vboxfs_get_path_size(&path),
+ VBOX_DIR_OUT);
+ vbox_set_u32(¶m[1], 0);
+ vbox_set_u32(¶m[2], '/'); /* path separator */
+ vbox_set_u32(¶m[3], TRUE); /* case sensitivity - no effect? */
+
+ r = vbox_call(vboxfs_conn, VBOXFS_CALL_MAP_FOLDER, param, 4, NULL);
+ if (r != OK) {
+ vbox_close(vboxfs_conn);
+
+ return r;
+ }
+
+ vboxfs_root = vbox_get_u32(¶m[1]);
+
+ /* Gather extra information about the mapped shared. */
+ if (vboxfs_query_vol("", &volinfo) == OK) {
+ *case_insens = !volinfo.props.casesens;
+ *read_only = !!volinfo.props.readonly;
+ }
+
+ *tablep = &vboxfs_table;
+ return OK;
+}
+
+/*
+ * Unmap the share, and disconnect from the VBOX driver.
+ */
+void
+vboxfs_cleanup(void)
+{
+ vbox_param_t param[1];
+
+ vbox_set_u32(¶m[0], vboxfs_root);
+
+ vbox_call(vboxfs_conn, VBOXFS_CALL_UNMAP_FOLDER, param, 1, NULL);
+
+ vbox_close(vboxfs_conn);
+}
--- /dev/null
+/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
+
+#ifndef _VBOXFS_VBOXFS_H
+#define _VBOXFS_VBOXFS_H
+
+#define VBOXFS_CALL_CREATE 3 /* create, open, lookup */
+#define VBOXFS_CALL_CLOSE 4 /* close handle */
+#define VBOXFS_CALL_READ 5 /* read from file */
+#define VBOXFS_CALL_WRITE 6 /* write to file */
+#define VBOXFS_CALL_LIST 8 /* list directory contents */
+#define VBOXFS_CALL_INFO 9 /* get/set file information */
+#define VBOXFS_CALL_REMOVE 11 /* remove file or directory */
+#define VBOXFS_CALL_UNMAP_FOLDER 13 /* unmap folder */
+#define VBOXFS_CALL_RENAME 14 /* rename file or directory */
+#define VBOXFS_CALL_SET_UTF8 16 /* switch to UTF8 */
+#define VBOXFS_CALL_MAP_FOLDER 17 /* map folder */
+
+#define VBOXFS_INVALID_HANDLE ((vboxfs_handle_t) ~0LL)
+
+typedef u32_t vboxfs_root_t;
+typedef u64_t vboxfs_handle_t;
+
+typedef struct {
+ u16_t size;
+ u16_t len;
+ char data[PATH_MAX];
+} vboxfs_path_t;
+
+#define VBOXFS_NO_RESULT 0
+#define VBOXFS_PATH_NOT_FOUND 1
+#define VBOXFS_FILE_NOT_FOUND 2
+#define VBOXFS_FILE_EXISTS 3
+#define VBOXFS_FILE_CREATED 4
+#define VBOXFS_FILE_REPLACED 5
+
+#define VBOXFS_OBJATTR_ADD_NONE 1 /* no other attributes */
+#define VBOXFS_OBJATTR_ADD_UNIX 2 /* POSIX attributes */
+#define VBOXFS_OBJATTR_ADD_EATTR 3 /* extended attributes */
+
+typedef struct {
+ u32_t mode;
+ u32_t add;
+ union {
+ struct {
+ u32_t uid;
+ u32_t gid;
+ u32_t nlinks;
+ u32_t dev;
+ u64_t inode;
+ u32_t flags;
+ u32_t gen;
+ u32_t rdev;
+ };
+ struct {
+ u64_t easize;
+ };
+ };
+} vboxfs_objattr_t;
+
+/* Thankfully, MINIX uses the universal UNIX mode values. */
+#define VBOXFS_GET_MODE(mode) ((mode) & 0xffff)
+#define VBOXFS_SET_MODE(type, perm) ((type) | ((perm) & ALLPERMS))
+
+typedef struct {
+ u64_t size;
+ u64_t disksize;
+ u64_t atime;
+ u64_t mtime;
+ u64_t ctime;
+ u64_t crtime;
+ vboxfs_objattr_t attr;
+} vboxfs_objinfo_t;
+
+#define VBOXFS_CRFLAG_LOOKUP 0x00000001
+#define VBOXFS_CRFLAG_DIRECTORY 0x00000004
+#define VBOXFS_CRFLAG_OPEN_IF_EXISTS 0x00000000
+#define VBOXFS_CRFLAG_FAIL_IF_EXISTS 0x00000010
+#define VBOXFS_CRFLAG_REPLACE_IF_EXISTS 0x00000020
+#define VBOXFS_CRFLAG_TRUNC_IF_EXISTS 0x00000030
+#define VBOXFS_CRFLAG_CREATE_IF_NEW 0x00000000
+#define VBOXFS_CRFLAG_FAIL_IF_NEW 0x00000100
+#define VBOXFS_CRFLAG_READ 0x00001000
+#define VBOXFS_CRFLAG_WRITE 0x00002000
+#define VBOXFS_CRFLAG_APPEND 0x00004000
+#define VBOXFS_CRFLAG_READ_ATTR 0x00010000
+#define VBOXFS_CRFLAG_WRITE_ATTR 0x00020000
+
+typedef struct {
+ vboxfs_handle_t handle;
+ u32_t result;
+ u32_t flags;
+ vboxfs_objinfo_t info;
+} vboxfs_crinfo_t;
+
+typedef struct {
+ vboxfs_objinfo_t info;
+ u16_t shortlen;
+ u16_t shortname[14];
+ vboxfs_path_t name; /* WARNING: name data size is dynamic! */
+} vboxfs_dirinfo_t;
+
+#define VBOXFS_INFO_GET 0x00 /* get file information */
+#define VBOXFS_INFO_SET 0x01 /* set file information */
+
+#define VBOXFS_INFO_SIZE 0x04 /* get/set file size */
+#define VBOXFS_INFO_FILE 0x08 /* get/set file attributes */
+#define VBOXFS_INFO_VOLUME 0x10 /* get volume information */
+
+#define VBOXFS_REMOVE_FILE 0x01 /* remove file */
+#define VBOXFS_REMOVE_DIR 0x02 /* remove directory */
+#define VBOXFS_REMOVE_SYMLINK 0x04 /* remove symbolic link */
+
+#define VBOXFS_RENAME_FILE 0x01 /* rename file */
+#define VBOXFS_RENAME_DIR 0x02 /* rename directory */
+#define VBOXFS_RENAME_REPLACE 0x04 /* replace target if it exists */
+
+typedef struct {
+ u32_t namemax;
+ u8_t remote;
+ u8_t casesens;
+ u8_t readonly;
+ u8_t unicode;
+ u8_t fscomp;
+ u8_t filecomp;
+ u16_t reserved;
+} vboxfs_fsprops_t;
+
+typedef struct {
+ u64_t total;
+ u64_t free;
+ u32_t blocksize;
+ u32_t sectorsize;
+ u32_t serial;
+ vboxfs_fsprops_t props;
+} vboxfs_volinfo_t;
+
+#endif /* !_VBOXFS_VBOXFS_H */
# rumpfs_tmpfs rumpfs_udf rumpfs_ufs
.for _lib in \
c curses blockdriver chardriver netdriver edit end m sys timers util \
- bz2 l audiodriver exec ddekit devman usb elf bdev sffs hgfs
+ bz2 l audiodriver exec ddekit devman usb elf bdev sffs hgfs vboxfs
.ifndef LIB${_lib:tu}
LIB${_lib:tu}= ${DESTDIR}/usr/lib/lib${_lib}.a
.MADE: ${LIB${_lib:tu}} # Note: ${DESTDIR} will be expanded