122 lines
3 KiB
C
122 lines
3 KiB
C
|
/* 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);
|
||
|
}
|