Add libvboxfs: VirtualBox shared folders library

This commit is contained in:
David van Moolenbroek 2012-04-09 19:20:37 +02:00
parent ef7b484e5c
commit bb4d055fa6
17 changed files with 1212 additions and 3 deletions

View file

@ -18,7 +18,7 @@ INCS+= minix/acpi.h minix/audio_fw.h minix/bitmap.h \
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 \

12
include/minix/vboxfs.h Normal file
View file

@ -0,0 +1,12 @@
/* 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 */

View file

@ -6,7 +6,7 @@ SUBDIR= csu libcompat_minix libc libblockdriver libchardriver \
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

8
lib/libvboxfs/Makefile Normal file
View file

@ -0,0 +1,8 @@
# 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>

169
lib/libvboxfs/attr.c Normal file
View file

@ -0,0 +1,169 @@
/* 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(&param[0], vboxfs_root);
vbox_set_ptr(&param[1], &pathbuf, vboxfs_get_path_size(&pathbuf),
VBOX_DIR_OUT);
vbox_set_ptr(&param[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;
}

245
lib/libvboxfs/dir.c Normal file
View file

@ -0,0 +1,245 @@
/* 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(&param[0], vboxfs_root);
vbox_set_u64(&param[1], handle);
vbox_set_u32(&param[2], 0); /* flags */
vbox_set_u32(&param[3], sizeof(block->data));
vbox_set_ptr(&param[4], NULL, 0, VBOX_DIR_OUT);
vbox_set_ptr(&param[5], block->data, sizeof(block->data),
VBOX_DIR_IN);
vbox_set_u32(&param[6], 0); /* resume point */
vbox_set_u32(&param[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(&param[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(&param[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;
}

119
lib/libvboxfs/file.c Normal file
View file

@ -0,0 +1,119 @@
/* 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(&param[0], vboxfs_root);
vbox_set_u64(&param[1], handle);
vbox_set_u64(&param[2], pos);
vbox_set_u32(&param[3], size);
vbox_set_ptr(&param[4], buf, size, dir);
if ((r = vbox_call(vboxfs_conn, call, param, 5, NULL)) != OK)
return r;
return vbox_get_u32(&param[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);
}

9
lib/libvboxfs/glo.h Normal file
View file

@ -0,0 +1,9 @@
/* 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 */

121
lib/libvboxfs/handle.c Normal file
View file

@ -0,0 +1,121 @@
/* 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(&param[0], vboxfs_root);
vbox_set_ptr(&param[1], &pathbuf, vboxfs_get_path_size(&pathbuf),
VBOX_DIR_OUT);
vbox_set_ptr(&param[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(&param[0], vboxfs_root);
vbox_set_u64(&param[1], handle);
/* Ignore errors here. We cannot do anything with them anyway. */
(void) vbox_call(vboxfs_conn, VBOXFS_CALL_CLOSE, param, 2, NULL);
}

18
lib/libvboxfs/inc.h Normal file
View file

@ -0,0 +1,18 @@
/* 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 */

58
lib/libvboxfs/info.c Normal file
View file

@ -0,0 +1,58 @@
/* 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(&param[0], vboxfs_root);
vbox_set_u64(&param[1], handle);
vbox_set_u32(&param[2], flags);
vbox_set_u32(&param[3], size);
vbox_set_ptr(&param[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;
}

109
lib/libvboxfs/link.c Normal file
View file

@ -0,0 +1,109 @@
/* 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(&param[0], vboxfs_root);
vbox_set_ptr(&param[1], &pathbuf, vboxfs_get_path_size(&pathbuf),
VBOX_DIR_OUT);
vbox_set_u32(&param[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(&param[0], vboxfs_root);
vbox_set_ptr(&param[1], &opathbuf, vboxfs_get_path_size(&opathbuf),
VBOX_DIR_OUT);
vbox_set_ptr(&param[2], &npathbuf, vboxfs_get_path_size(&npathbuf),
VBOX_DIR_OUT);
vbox_set_u32(&param[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*/);
}

60
lib/libvboxfs/path.c Normal file
View file

@ -0,0 +1,60 @@
/* 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;
}

46
lib/libvboxfs/proto.h Normal file
View file

@ -0,0 +1,46 @@
/* 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 */

98
lib/libvboxfs/vboxfs.c Normal file
View file

@ -0,0 +1,98 @@
/* 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(&param[0], &path, vboxfs_get_path_size(&path),
VBOX_DIR_OUT);
vbox_set_u32(&param[1], 0);
vbox_set_u32(&param[2], '/'); /* path separator */
vbox_set_u32(&param[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(&param[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(&param[0], vboxfs_root);
vbox_call(vboxfs_conn, VBOXFS_CALL_UNMAP_FOLDER, param, 1, NULL);
vbox_close(vboxfs_conn);
}

137
lib/libvboxfs/vboxfs.h Normal file
View file

@ -0,0 +1,137 @@
/* 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 */

View file

@ -59,7 +59,7 @@ MKDEP_SUFFIXES?= .o .ln
# 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