cloudabi_file.c revision 285834
1/*-
2 * Copyright (c) 2015 Nuxi, https://nuxi.nl/
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/sys/compat/cloudabi/cloudabi_file.c 285834 2015-07-24 07:46:02Z ed $");
28
29#include <sys/param.h>
30#include <sys/fcntl.h>
31#include <sys/kernel.h>
32#include <sys/malloc.h>
33#include <sys/namei.h>
34#include <sys/syscallsubr.h>
35
36#include <compat/cloudabi/cloudabi_proto.h>
37#include <compat/cloudabi/cloudabi_syscalldefs.h>
38
39static MALLOC_DEFINE(M_CLOUDABI_PATH, "cloudabipath", "CloudABI pathnames");
40
41/*
42 * Copying pathnames from userspace to kernelspace.
43 *
44 * Unlike most operating systems, CloudABI doesn't use null-terminated
45 * pathname strings. Processes always pass pathnames to the kernel by
46 * providing a base pointer and a length. This has a couple of reasons:
47 *
48 * - It makes it easier to use CloudABI in combination with programming
49 *   languages other than C, that may use non-null terminated strings.
50 * - It allows for calling system calls on individual components of the
51 *   pathname without modifying the input string.
52 *
53 * The function below copies in pathname strings and null-terminates it.
54 * It also ensure that the string itself does not contain any null
55 * bytes.
56 *
57 * TODO(ed): Add an abstraction to vfs_lookup.c that allows us to pass
58 *           in unterminated pathname strings, so we can do away with
59 *           the copying.
60 */
61
62static int
63copyin_path(const char *uaddr, size_t len, char **result)
64{
65	char *buf;
66	int error;
67
68	if (len >= PATH_MAX)
69		return (ENAMETOOLONG);
70	buf = malloc(len + 1, M_CLOUDABI_PATH, M_WAITOK);
71	error = copyin(uaddr, buf, len);
72	if (error != 0) {
73		free(buf, M_CLOUDABI_PATH);
74		return (error);
75	}
76	if (memchr(buf, '\0', len) != NULL) {
77		free(buf, M_CLOUDABI_PATH);
78		return (EINVAL);
79	}
80	buf[len] = '\0';
81	*result = buf;
82	return (0);
83}
84
85static void
86cloudabi_freestr(char *buf)
87{
88
89	free(buf, M_CLOUDABI_PATH);
90}
91
92int
93cloudabi_sys_file_advise(struct thread *td,
94    struct cloudabi_sys_file_advise_args *uap)
95{
96	int advice;
97
98	switch (uap->advice) {
99	case CLOUDABI_ADVICE_DONTNEED:
100		advice = POSIX_FADV_DONTNEED;
101		break;
102	case CLOUDABI_ADVICE_NOREUSE:
103		advice = POSIX_FADV_NOREUSE;
104		break;
105	case CLOUDABI_ADVICE_NORMAL:
106		advice = POSIX_FADV_NORMAL;
107		break;
108	case CLOUDABI_ADVICE_RANDOM:
109		advice = POSIX_FADV_RANDOM;
110		break;
111	case CLOUDABI_ADVICE_SEQUENTIAL:
112		advice = POSIX_FADV_SEQUENTIAL;
113		break;
114	case CLOUDABI_ADVICE_WILLNEED:
115		advice = POSIX_FADV_WILLNEED;
116		break;
117	default:
118		return (EINVAL);
119	}
120
121	return (kern_posix_fadvise(td, uap->fd, uap->offset, uap->len, advice));
122}
123
124int
125cloudabi_sys_file_allocate(struct thread *td,
126    struct cloudabi_sys_file_allocate_args *uap)
127{
128
129	return (kern_posix_fallocate(td, uap->fd, uap->offset, uap->len));
130}
131
132int
133cloudabi_sys_file_create(struct thread *td,
134    struct cloudabi_sys_file_create_args *uap)
135{
136
137	/* Not implemented. */
138	return (ENOSYS);
139}
140
141int
142cloudabi_sys_file_link(struct thread *td,
143    struct cloudabi_sys_file_link_args *uap)
144{
145	char *path1, *path2;
146	int error;
147
148	error = copyin_path(uap->path1, uap->path1len, &path1);
149	if (error != 0)
150		return (error);
151	error = copyin_path(uap->path2, uap->path2len, &path2);
152	if (error != 0) {
153		cloudabi_freestr(path1);
154		return (error);
155	}
156
157	error = kern_linkat(td, uap->fd1, uap->fd2, path1, path2,
158	    UIO_SYSSPACE, (uap->fd1 & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ?
159	    FOLLOW : NOFOLLOW);
160	cloudabi_freestr(path1);
161	cloudabi_freestr(path2);
162	return (error);
163}
164
165int
166cloudabi_sys_file_open(struct thread *td,
167    struct cloudabi_sys_file_open_args *uap)
168{
169
170	/* Not implemented. */
171	return (ENOSYS);
172}
173
174int
175cloudabi_sys_file_readdir(struct thread *td,
176    struct cloudabi_sys_file_readdir_args *uap)
177{
178
179	/* Not implemented. */
180	return (ENOSYS);
181}
182
183int
184cloudabi_sys_file_readlink(struct thread *td,
185    struct cloudabi_sys_file_readlink_args *uap)
186{
187	char *path;
188	int error;
189
190	error = copyin_path(uap->path, uap->pathlen, &path);
191	if (error != 0)
192		return (error);
193
194	error = kern_readlinkat(td, uap->fd, path, UIO_SYSSPACE,
195	    uap->buf, UIO_USERSPACE, uap->bufsize);
196	cloudabi_freestr(path);
197	return (error);
198}
199
200int
201cloudabi_sys_file_rename(struct thread *td,
202    struct cloudabi_sys_file_rename_args *uap)
203{
204	char *old, *new;
205	int error;
206
207	error = copyin_path(uap->old, uap->oldlen, &old);
208	if (error != 0)
209		return (error);
210	error = copyin_path(uap->new, uap->newlen, &new);
211	if (error != 0) {
212		cloudabi_freestr(old);
213		return (error);
214	}
215
216	error = kern_renameat(td, uap->oldfd, old, uap->newfd, new,
217	    UIO_SYSSPACE);
218	cloudabi_freestr(old);
219	cloudabi_freestr(new);
220	return (error);
221}
222
223int
224cloudabi_sys_file_stat_fget(struct thread *td,
225    struct cloudabi_sys_file_stat_fget_args *uap)
226{
227
228	/* Not implemented. */
229	return (ENOSYS);
230}
231
232int
233cloudabi_sys_file_stat_fput(struct thread *td,
234    struct cloudabi_sys_file_stat_fput_args *uap)
235{
236
237	/* Not implemented. */
238	return (ENOSYS);
239}
240
241int
242cloudabi_sys_file_stat_get(struct thread *td,
243    struct cloudabi_sys_file_stat_get_args *uap)
244{
245
246	/* Not implemented. */
247	return (ENOSYS);
248}
249
250int
251cloudabi_sys_file_stat_put(struct thread *td,
252    struct cloudabi_sys_file_stat_put_args *uap)
253{
254
255	/* Not implemented. */
256	return (ENOSYS);
257}
258
259int
260cloudabi_sys_file_symlink(struct thread *td,
261    struct cloudabi_sys_file_symlink_args *uap)
262{
263	char *path1, *path2;
264	int error;
265
266	error = copyin_path(uap->path1, uap->path1len, &path1);
267	if (error != 0)
268		return (error);
269	error = copyin_path(uap->path2, uap->path2len, &path2);
270	if (error != 0) {
271		cloudabi_freestr(path1);
272		return (error);
273	}
274
275	error = kern_symlinkat(td, path1, uap->fd, path2, UIO_SYSSPACE);
276	cloudabi_freestr(path1);
277	cloudabi_freestr(path2);
278	return (error);
279}
280
281int
282cloudabi_sys_file_unlink(struct thread *td,
283    struct cloudabi_sys_file_unlink_args *uap)
284{
285	char *path;
286	int error;
287
288	error = copyin_path(uap->path, uap->pathlen, &path);
289	if (error != 0)
290		return (error);
291
292	if (uap->flag & CLOUDABI_UNLINK_REMOVEDIR)
293		error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE);
294	else
295		error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0);
296	cloudabi_freestr(path);
297	return (error);
298}
299