cloudabi_file.c revision 285834
1285307Sed/*-
2285307Sed * Copyright (c) 2015 Nuxi, https://nuxi.nl/
3285307Sed *
4285307Sed * Redistribution and use in source and binary forms, with or without
5285307Sed * modification, are permitted provided that the following conditions
6285307Sed * are met:
7285307Sed * 1. Redistributions of source code must retain the above copyright
8285307Sed *    notice, this list of conditions and the following disclaimer.
9285307Sed * 2. Redistributions in binary form must reproduce the above copyright
10285307Sed *    notice, this list of conditions and the following disclaimer in the
11285307Sed *    documentation and/or other materials provided with the distribution.
12285307Sed *
13285307Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14285307Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15285307Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16285307Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17285307Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18285307Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19285307Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20285307Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21285307Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22285307Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23285307Sed * SUCH DAMAGE.
24285307Sed */
25285307Sed
26285307Sed#include <sys/cdefs.h>
27285307Sed__FBSDID("$FreeBSD: head/sys/compat/cloudabi/cloudabi_file.c 285834 2015-07-24 07:46:02Z ed $");
28285307Sed
29285596Sed#include <sys/param.h>
30285596Sed#include <sys/fcntl.h>
31285834Sed#include <sys/kernel.h>
32285834Sed#include <sys/malloc.h>
33285834Sed#include <sys/namei.h>
34285596Sed#include <sys/syscallsubr.h>
35285596Sed
36285307Sed#include <compat/cloudabi/cloudabi_proto.h>
37285596Sed#include <compat/cloudabi/cloudabi_syscalldefs.h>
38285307Sed
39285834Sedstatic MALLOC_DEFINE(M_CLOUDABI_PATH, "cloudabipath", "CloudABI pathnames");
40285834Sed
41285834Sed/*
42285834Sed * Copying pathnames from userspace to kernelspace.
43285834Sed *
44285834Sed * Unlike most operating systems, CloudABI doesn't use null-terminated
45285834Sed * pathname strings. Processes always pass pathnames to the kernel by
46285834Sed * providing a base pointer and a length. This has a couple of reasons:
47285834Sed *
48285834Sed * - It makes it easier to use CloudABI in combination with programming
49285834Sed *   languages other than C, that may use non-null terminated strings.
50285834Sed * - It allows for calling system calls on individual components of the
51285834Sed *   pathname without modifying the input string.
52285834Sed *
53285834Sed * The function below copies in pathname strings and null-terminates it.
54285834Sed * It also ensure that the string itself does not contain any null
55285834Sed * bytes.
56285834Sed *
57285834Sed * TODO(ed): Add an abstraction to vfs_lookup.c that allows us to pass
58285834Sed *           in unterminated pathname strings, so we can do away with
59285834Sed *           the copying.
60285834Sed */
61285834Sed
62285834Sedstatic int
63285834Sedcopyin_path(const char *uaddr, size_t len, char **result)
64285834Sed{
65285834Sed	char *buf;
66285834Sed	int error;
67285834Sed
68285834Sed	if (len >= PATH_MAX)
69285834Sed		return (ENAMETOOLONG);
70285834Sed	buf = malloc(len + 1, M_CLOUDABI_PATH, M_WAITOK);
71285834Sed	error = copyin(uaddr, buf, len);
72285834Sed	if (error != 0) {
73285834Sed		free(buf, M_CLOUDABI_PATH);
74285834Sed		return (error);
75285834Sed	}
76285834Sed	if (memchr(buf, '\0', len) != NULL) {
77285834Sed		free(buf, M_CLOUDABI_PATH);
78285834Sed		return (EINVAL);
79285834Sed	}
80285834Sed	buf[len] = '\0';
81285834Sed	*result = buf;
82285834Sed	return (0);
83285834Sed}
84285834Sed
85285834Sedstatic void
86285834Sedcloudabi_freestr(char *buf)
87285834Sed{
88285834Sed
89285834Sed	free(buf, M_CLOUDABI_PATH);
90285834Sed}
91285834Sed
92285307Sedint
93285307Sedcloudabi_sys_file_advise(struct thread *td,
94285307Sed    struct cloudabi_sys_file_advise_args *uap)
95285307Sed{
96285596Sed	int advice;
97285307Sed
98285596Sed	switch (uap->advice) {
99285596Sed	case CLOUDABI_ADVICE_DONTNEED:
100285596Sed		advice = POSIX_FADV_DONTNEED;
101285596Sed		break;
102285596Sed	case CLOUDABI_ADVICE_NOREUSE:
103285596Sed		advice = POSIX_FADV_NOREUSE;
104285596Sed		break;
105285596Sed	case CLOUDABI_ADVICE_NORMAL:
106285596Sed		advice = POSIX_FADV_NORMAL;
107285596Sed		break;
108285596Sed	case CLOUDABI_ADVICE_RANDOM:
109285596Sed		advice = POSIX_FADV_RANDOM;
110285596Sed		break;
111285596Sed	case CLOUDABI_ADVICE_SEQUENTIAL:
112285596Sed		advice = POSIX_FADV_SEQUENTIAL;
113285596Sed		break;
114285596Sed	case CLOUDABI_ADVICE_WILLNEED:
115285596Sed		advice = POSIX_FADV_WILLNEED;
116285596Sed		break;
117285596Sed	default:
118285596Sed		return (EINVAL);
119285596Sed	}
120285596Sed
121285596Sed	return (kern_posix_fadvise(td, uap->fd, uap->offset, uap->len, advice));
122285307Sed}
123285307Sed
124285307Sedint
125285307Sedcloudabi_sys_file_allocate(struct thread *td,
126285307Sed    struct cloudabi_sys_file_allocate_args *uap)
127285307Sed{
128285307Sed
129285596Sed	return (kern_posix_fallocate(td, uap->fd, uap->offset, uap->len));
130285307Sed}
131285307Sed
132285307Sedint
133285307Sedcloudabi_sys_file_create(struct thread *td,
134285307Sed    struct cloudabi_sys_file_create_args *uap)
135285307Sed{
136285307Sed
137285307Sed	/* Not implemented. */
138285307Sed	return (ENOSYS);
139285307Sed}
140285307Sed
141285307Sedint
142285307Sedcloudabi_sys_file_link(struct thread *td,
143285307Sed    struct cloudabi_sys_file_link_args *uap)
144285307Sed{
145285834Sed	char *path1, *path2;
146285834Sed	int error;
147285307Sed
148285834Sed	error = copyin_path(uap->path1, uap->path1len, &path1);
149285834Sed	if (error != 0)
150285834Sed		return (error);
151285834Sed	error = copyin_path(uap->path2, uap->path2len, &path2);
152285834Sed	if (error != 0) {
153285834Sed		cloudabi_freestr(path1);
154285834Sed		return (error);
155285834Sed	}
156285834Sed
157285834Sed	error = kern_linkat(td, uap->fd1, uap->fd2, path1, path2,
158285834Sed	    UIO_SYSSPACE, (uap->fd1 & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ?
159285834Sed	    FOLLOW : NOFOLLOW);
160285834Sed	cloudabi_freestr(path1);
161285834Sed	cloudabi_freestr(path2);
162285834Sed	return (error);
163285307Sed}
164285307Sed
165285307Sedint
166285307Sedcloudabi_sys_file_open(struct thread *td,
167285307Sed    struct cloudabi_sys_file_open_args *uap)
168285307Sed{
169285307Sed
170285307Sed	/* Not implemented. */
171285307Sed	return (ENOSYS);
172285307Sed}
173285307Sed
174285307Sedint
175285307Sedcloudabi_sys_file_readdir(struct thread *td,
176285307Sed    struct cloudabi_sys_file_readdir_args *uap)
177285307Sed{
178285307Sed
179285307Sed	/* Not implemented. */
180285307Sed	return (ENOSYS);
181285307Sed}
182285307Sed
183285307Sedint
184285307Sedcloudabi_sys_file_readlink(struct thread *td,
185285307Sed    struct cloudabi_sys_file_readlink_args *uap)
186285307Sed{
187285834Sed	char *path;
188285834Sed	int error;
189285307Sed
190285834Sed	error = copyin_path(uap->path, uap->pathlen, &path);
191285834Sed	if (error != 0)
192285834Sed		return (error);
193285834Sed
194285834Sed	error = kern_readlinkat(td, uap->fd, path, UIO_SYSSPACE,
195285834Sed	    uap->buf, UIO_USERSPACE, uap->bufsize);
196285834Sed	cloudabi_freestr(path);
197285834Sed	return (error);
198285307Sed}
199285307Sed
200285307Sedint
201285307Sedcloudabi_sys_file_rename(struct thread *td,
202285307Sed    struct cloudabi_sys_file_rename_args *uap)
203285307Sed{
204285834Sed	char *old, *new;
205285834Sed	int error;
206285307Sed
207285834Sed	error = copyin_path(uap->old, uap->oldlen, &old);
208285834Sed	if (error != 0)
209285834Sed		return (error);
210285834Sed	error = copyin_path(uap->new, uap->newlen, &new);
211285834Sed	if (error != 0) {
212285834Sed		cloudabi_freestr(old);
213285834Sed		return (error);
214285834Sed	}
215285834Sed
216285834Sed	error = kern_renameat(td, uap->oldfd, old, uap->newfd, new,
217285834Sed	    UIO_SYSSPACE);
218285834Sed	cloudabi_freestr(old);
219285834Sed	cloudabi_freestr(new);
220285834Sed	return (error);
221285307Sed}
222285307Sed
223285307Sedint
224285307Sedcloudabi_sys_file_stat_fget(struct thread *td,
225285307Sed    struct cloudabi_sys_file_stat_fget_args *uap)
226285307Sed{
227285307Sed
228285307Sed	/* Not implemented. */
229285307Sed	return (ENOSYS);
230285307Sed}
231285307Sed
232285307Sedint
233285307Sedcloudabi_sys_file_stat_fput(struct thread *td,
234285307Sed    struct cloudabi_sys_file_stat_fput_args *uap)
235285307Sed{
236285307Sed
237285307Sed	/* Not implemented. */
238285307Sed	return (ENOSYS);
239285307Sed}
240285307Sed
241285307Sedint
242285307Sedcloudabi_sys_file_stat_get(struct thread *td,
243285307Sed    struct cloudabi_sys_file_stat_get_args *uap)
244285307Sed{
245285307Sed
246285307Sed	/* Not implemented. */
247285307Sed	return (ENOSYS);
248285307Sed}
249285307Sed
250285307Sedint
251285307Sedcloudabi_sys_file_stat_put(struct thread *td,
252285307Sed    struct cloudabi_sys_file_stat_put_args *uap)
253285307Sed{
254285307Sed
255285307Sed	/* Not implemented. */
256285307Sed	return (ENOSYS);
257285307Sed}
258285307Sed
259285307Sedint
260285307Sedcloudabi_sys_file_symlink(struct thread *td,
261285307Sed    struct cloudabi_sys_file_symlink_args *uap)
262285307Sed{
263285834Sed	char *path1, *path2;
264285834Sed	int error;
265285307Sed
266285834Sed	error = copyin_path(uap->path1, uap->path1len, &path1);
267285834Sed	if (error != 0)
268285834Sed		return (error);
269285834Sed	error = copyin_path(uap->path2, uap->path2len, &path2);
270285834Sed	if (error != 0) {
271285834Sed		cloudabi_freestr(path1);
272285834Sed		return (error);
273285834Sed	}
274285834Sed
275285834Sed	error = kern_symlinkat(td, path1, uap->fd, path2, UIO_SYSSPACE);
276285834Sed	cloudabi_freestr(path1);
277285834Sed	cloudabi_freestr(path2);
278285834Sed	return (error);
279285307Sed}
280285307Sed
281285307Sedint
282285307Sedcloudabi_sys_file_unlink(struct thread *td,
283285307Sed    struct cloudabi_sys_file_unlink_args *uap)
284285307Sed{
285285834Sed	char *path;
286285834Sed	int error;
287285307Sed
288285834Sed	error = copyin_path(uap->path, uap->pathlen, &path);
289285834Sed	if (error != 0)
290285834Sed		return (error);
291285834Sed
292285834Sed	if (uap->flag & CLOUDABI_UNLINK_REMOVEDIR)
293285834Sed		error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE);
294285834Sed	else
295285834Sed		error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0);
296285834Sed	cloudabi_freestr(path);
297285834Sed	return (error);
298285307Sed}
299