1433d6423SLionel Sambuc /* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */
2433d6423SLionel Sambuc
3433d6423SLionel Sambuc #include "inc.h"
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc /*
6433d6423SLionel Sambuc * Create or open a file or directory.
7433d6423SLionel Sambuc */
8433d6423SLionel Sambuc int
vboxfs_open_file(const char * path,int flags,int mode,vboxfs_handle_t * handlep,vboxfs_objinfo_t * infop)9*94e65446SDavid van Moolenbroek vboxfs_open_file(const char *path, int flags, int mode,
10*94e65446SDavid van Moolenbroek vboxfs_handle_t *handlep, vboxfs_objinfo_t *infop)
11433d6423SLionel Sambuc {
12433d6423SLionel Sambuc vbox_param_t param[3];
13433d6423SLionel Sambuc vboxfs_path_t pathbuf;
14433d6423SLionel Sambuc vboxfs_crinfo_t crinfo;
15433d6423SLionel Sambuc int r, dir, rflag, wflag;
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc if ((r = vboxfs_set_path(&pathbuf, path)) != OK)
18433d6423SLionel Sambuc return r;
19433d6423SLionel Sambuc
20433d6423SLionel Sambuc memset(&crinfo, 0, sizeof(crinfo));
21433d6423SLionel Sambuc
22433d6423SLionel Sambuc /*
23433d6423SLionel Sambuc * Note that the mode may not be set at all. If no new file may be
24433d6423SLionel Sambuc * created, this is not a problem. The following test succeeds only if
25433d6423SLionel Sambuc * the caller explicitly specified that a directory is involved.
26433d6423SLionel Sambuc */
27433d6423SLionel Sambuc dir = S_ISDIR(mode);
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc /* Convert open(2) flags to VirtualBox creation flags. */
30433d6423SLionel Sambuc if (flags & O_APPEND)
31433d6423SLionel Sambuc return EINVAL; /* not supported at this time */
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc if (flags & O_CREAT) {
34433d6423SLionel Sambuc crinfo.flags = VBOXFS_CRFLAG_CREATE_IF_NEW;
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc if (flags & O_EXCL)
37433d6423SLionel Sambuc crinfo.flags |= VBOXFS_CRFLAG_FAIL_IF_EXISTS;
38433d6423SLionel Sambuc else if (flags & O_TRUNC)
39433d6423SLionel Sambuc crinfo.flags |= VBOXFS_CRFLAG_TRUNC_IF_EXISTS;
40433d6423SLionel Sambuc else
41433d6423SLionel Sambuc crinfo.flags |= VBOXFS_CRFLAG_OPEN_IF_EXISTS;
42433d6423SLionel Sambuc } else {
43433d6423SLionel Sambuc crinfo.flags = VBOXFS_CRFLAG_FAIL_IF_NEW;
44433d6423SLionel Sambuc
45433d6423SLionel Sambuc if (flags & O_TRUNC)
46433d6423SLionel Sambuc crinfo.flags |= VBOXFS_CRFLAG_TRUNC_IF_EXISTS;
47433d6423SLionel Sambuc else
48433d6423SLionel Sambuc crinfo.flags |= VBOXFS_CRFLAG_OPEN_IF_EXISTS;
49433d6423SLionel Sambuc }
50433d6423SLionel Sambuc
51433d6423SLionel Sambuc /*
52433d6423SLionel Sambuc * If an object information structure is given, open the file only to
53433d6423SLionel Sambuc * retrieve or change its attributes.
54433d6423SLionel Sambuc */
55433d6423SLionel Sambuc if (infop != NULL) {
56433d6423SLionel Sambuc rflag = VBOXFS_CRFLAG_READ_ATTR;
57433d6423SLionel Sambuc wflag = VBOXFS_CRFLAG_WRITE_ATTR;
58433d6423SLionel Sambuc } else {
59433d6423SLionel Sambuc rflag = VBOXFS_CRFLAG_READ;
60433d6423SLionel Sambuc wflag = VBOXFS_CRFLAG_WRITE;
61433d6423SLionel Sambuc }
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc switch (flags & O_ACCMODE) {
64433d6423SLionel Sambuc case O_RDONLY: crinfo.flags |= rflag; break;
65433d6423SLionel Sambuc case O_WRONLY: crinfo.flags |= wflag; break;
66433d6423SLionel Sambuc case O_RDWR: crinfo.flags |= rflag | wflag; break;
67433d6423SLionel Sambuc default: return EINVAL;
68433d6423SLionel Sambuc }
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc if (S_ISDIR(mode))
71433d6423SLionel Sambuc crinfo.flags |= VBOXFS_CRFLAG_DIRECTORY;
72433d6423SLionel Sambuc
73433d6423SLionel Sambuc crinfo.info.attr.mode = VBOXFS_SET_MODE(dir ? S_IFDIR : S_IFREG, mode);
74433d6423SLionel Sambuc crinfo.info.attr.add = VBOXFS_OBJATTR_ADD_NONE;
75433d6423SLionel Sambuc
76433d6423SLionel Sambuc vbox_set_u32(¶m[0], vboxfs_root);
77433d6423SLionel Sambuc vbox_set_ptr(¶m[1], &pathbuf, vboxfs_get_path_size(&pathbuf),
78433d6423SLionel Sambuc VBOX_DIR_OUT);
79433d6423SLionel Sambuc vbox_set_ptr(¶m[2], &crinfo, sizeof(crinfo), VBOX_DIR_INOUT);
80433d6423SLionel Sambuc
81433d6423SLionel Sambuc r = vbox_call(vboxfs_conn, VBOXFS_CALL_CREATE, param, 3, NULL);
82433d6423SLionel Sambuc if (r != OK)
83433d6423SLionel Sambuc return r;
84433d6423SLionel Sambuc
85433d6423SLionel Sambuc if (crinfo.handle == VBOXFS_INVALID_HANDLE) {
86433d6423SLionel Sambuc switch (crinfo.result) {
87433d6423SLionel Sambuc case VBOXFS_PATH_NOT_FOUND:
88433d6423SLionel Sambuc /*
89433d6423SLionel Sambuc * This could also mean ENOTDIR, but there does not
90433d6423SLionel Sambuc * appear to be any way to distinguish that case.
91433d6423SLionel Sambuc * Verifying with extra lookups seems overkill.
92433d6423SLionel Sambuc */
93433d6423SLionel Sambuc case VBOXFS_FILE_NOT_FOUND:
94433d6423SLionel Sambuc return ENOENT;
95433d6423SLionel Sambuc case VBOXFS_FILE_EXISTS:
96433d6423SLionel Sambuc return EEXIST;
97433d6423SLionel Sambuc default:
98433d6423SLionel Sambuc return EIO; /* should never happen */
99433d6423SLionel Sambuc }
100433d6423SLionel Sambuc }
101433d6423SLionel Sambuc
102433d6423SLionel Sambuc *handlep = crinfo.handle;
103433d6423SLionel Sambuc if (infop != NULL)
104433d6423SLionel Sambuc *infop = crinfo.info;
105433d6423SLionel Sambuc return OK;
106433d6423SLionel Sambuc }
107433d6423SLionel Sambuc
108433d6423SLionel Sambuc /*
109433d6423SLionel Sambuc * Close an open file handle.
110433d6423SLionel Sambuc */
111433d6423SLionel Sambuc void
vboxfs_close_file(vboxfs_handle_t handle)112433d6423SLionel Sambuc vboxfs_close_file(vboxfs_handle_t handle)
113433d6423SLionel Sambuc {
114433d6423SLionel Sambuc vbox_param_t param[2];
115433d6423SLionel Sambuc
116433d6423SLionel Sambuc vbox_set_u32(¶m[0], vboxfs_root);
117433d6423SLionel Sambuc vbox_set_u64(¶m[1], handle);
118433d6423SLionel Sambuc
119433d6423SLionel Sambuc /* Ignore errors here. We cannot do anything with them anyway. */
120433d6423SLionel Sambuc (void) vbox_call(vboxfs_conn, VBOXFS_CALL_CLOSE, param, 2, NULL);
121433d6423SLionel Sambuc }
122