summaryrefslogtreecommitdiff
path: root/minix/lib/libvboxfs/handle.c
blob: e0ccd7a99225b8e2f80828baa2a9ed842d3019a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/* Part of libvboxfs - (c) 2012, D.C. van Moolenbroek */

#include "inc.h"

/*
 * Create or open a file or directory.
 */
int
vboxfs_open_file(const 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);
}