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: releng/11.1/sys/compat/cloudabi/cloudabi_file.c 316574 2017-04-06 15:10:36Z ed $");
28
29 #include <sys/param.h>
30 #include <sys/capsicum.h>
31 #include <sys/dirent.h>
32 #include <sys/fcntl.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/namei.h>
36 #include <sys/proc.h>
37 #include <sys/stat.h>
38 #include <sys/syscallsubr.h>
39 #include <sys/uio.h>
40 #include <sys/vnode.h>
41
42 #include <contrib/cloudabi/cloudabi_types_common.h>
43
44 #include <compat/cloudabi/cloudabi_proto.h>
45 #include <compat/cloudabi/cloudabi_util.h>
46
47 #include <security/mac/mac_framework.h>
48
49 static MALLOC_DEFINE(M_CLOUDABI_PATH, "cloudabipath", "CloudABI pathnames");
50
51 /*
52 * Copying pathnames from userspace to kernelspace.
53 *
54 * Unlike most operating systems, CloudABI doesn't use null-terminated
55 * pathname strings. Processes always pass pathnames to the kernel by
56 * providing a base pointer and a length. This has a couple of reasons:
57 *
58 * - It makes it easier to use CloudABI in combination with programming
59 * languages other than C, that may use non-null terminated strings.
60 * - It allows for calling system calls on individual components of the
61 * pathname without modifying the input string.
62 *
63 * The function below copies in pathname strings and null-terminates it.
64 * It also ensure that the string itself does not contain any null
65 * bytes.
66 *
67 * TODO(ed): Add an abstraction to vfs_lookup.c that allows us to pass
68 * in unterminated pathname strings, so we can do away with
69 * the copying.
70 */
71
72 static int
73 copyin_path(const char *uaddr, size_t len, char **result)
74 {
75 char *buf;
76 int error;
77
78 if (len >= PATH_MAX)
79 return (ENAMETOOLONG);
80 buf = malloc(len + 1, M_CLOUDABI_PATH, M_WAITOK);
81 error = copyin(uaddr, buf, len);
82 if (error != 0) {
83 free(buf, M_CLOUDABI_PATH);
84 return (error);
85 }
86 if (memchr(buf, '\0', len) != NULL) {
87 free(buf, M_CLOUDABI_PATH);
88 return (EINVAL);
89 }
90 buf[len] = '\0';
91 *result = buf;
92 return (0);
93 }
94
95 static void
96 cloudabi_freestr(char *buf)
97 {
98
99 free(buf, M_CLOUDABI_PATH);
100 }
101
102 int
103 cloudabi_sys_file_advise(struct thread *td,
104 struct cloudabi_sys_file_advise_args *uap)
105 {
106 int advice;
107
108 switch (uap->advice) {
109 case CLOUDABI_ADVICE_DONTNEED:
110 advice = POSIX_FADV_DONTNEED;
111 break;
112 case CLOUDABI_ADVICE_NOREUSE:
113 advice = POSIX_FADV_NOREUSE;
114 break;
115 case CLOUDABI_ADVICE_NORMAL:
116 advice = POSIX_FADV_NORMAL;
117 break;
118 case CLOUDABI_ADVICE_RANDOM:
119 advice = POSIX_FADV_RANDOM;
120 break;
121 case CLOUDABI_ADVICE_SEQUENTIAL:
122 advice = POSIX_FADV_SEQUENTIAL;
123 break;
124 case CLOUDABI_ADVICE_WILLNEED:
125 advice = POSIX_FADV_WILLNEED;
126 break;
127 default:
128 return (EINVAL);
129 }
130
131 return (kern_posix_fadvise(td, uap->fd, uap->offset, uap->len, advice));
132 }
133
134 int
135 cloudabi_sys_file_allocate(struct thread *td,
136 struct cloudabi_sys_file_allocate_args *uap)
137 {
138
139 return (kern_posix_fallocate(td, uap->fd, uap->offset, uap->len));
140 }
141
142 int
143 cloudabi_sys_file_create(struct thread *td,
144 struct cloudabi_sys_file_create_args *uap)
145 {
146 char *path;
147 int error;
148
149 error = copyin_path(uap->path, uap->path_len, &path);
150 if (error != 0)
151 return (error);
152
153 /*
154 * CloudABI processes cannot interact with UNIX credentials and
155 * permissions. Depend on the umask that is set prior to
156 * execution to restrict the file permissions.
157 */
158 switch (uap->type) {
159 case CLOUDABI_FILETYPE_DIRECTORY:
160 error = kern_mkdirat(td, uap->fd, path, UIO_SYSSPACE, 0777);
161 break;
162 case CLOUDABI_FILETYPE_FIFO:
163 error = kern_mkfifoat(td, uap->fd, path, UIO_SYSSPACE, 0666);
164 break;
165 default:
166 error = EINVAL;
167 break;
168 }
169 cloudabi_freestr(path);
170 return (error);
171 }
172
173 int
174 cloudabi_sys_file_link(struct thread *td,
175 struct cloudabi_sys_file_link_args *uap)
176 {
177 char *path1, *path2;
178 int error;
179
180 error = copyin_path(uap->path1, uap->path1_len, &path1);
181 if (error != 0)
182 return (error);
183 error = copyin_path(uap->path2, uap->path2_len, &path2);
184 if (error != 0) {
185 cloudabi_freestr(path1);
186 return (error);
187 }
188
189 error = kern_linkat(td, uap->fd1.fd, uap->fd2, path1, path2,
190 UIO_SYSSPACE, (uap->fd1.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) ?
191 FOLLOW : NOFOLLOW);
192 cloudabi_freestr(path1);
193 cloudabi_freestr(path2);
194 return (error);
195 }
196
197 int
198 cloudabi_sys_file_open(struct thread *td,
199 struct cloudabi_sys_file_open_args *uap)
200 {
201 cloudabi_fdstat_t fds;
202 cap_rights_t rights;
203 struct filecaps fcaps = {};
204 struct nameidata nd;
205 struct file *fp;
206 struct vnode *vp;
207 char *path;
208 int error, fd, fflags;
209 bool read, write;
210
211 error = copyin(uap->fds, &fds, sizeof(fds));
212 if (error != 0)
213 return (error);
214
215 /* All the requested rights should be set on the descriptor. */
216 error = cloudabi_convert_rights(
217 fds.fs_rights_base | fds.fs_rights_inheriting, &rights);
218 if (error != 0)
219 return (error);
220 cap_rights_set(&rights, CAP_LOOKUP);
221
222 /* Convert rights to corresponding access mode. */
223 read = (fds.fs_rights_base & (CLOUDABI_RIGHT_FD_READ |
224 CLOUDABI_RIGHT_FILE_READDIR | CLOUDABI_RIGHT_MEM_MAP_EXEC)) != 0;
225 write = (fds.fs_rights_base & (CLOUDABI_RIGHT_FD_DATASYNC |
226 CLOUDABI_RIGHT_FD_WRITE | CLOUDABI_RIGHT_FILE_ALLOCATE |
227 CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE)) != 0;
228 fflags = write ? read ? FREAD | FWRITE : FWRITE : FREAD;
229
230 /* Convert open flags. */
231 if ((uap->oflags & CLOUDABI_O_CREAT) != 0) {
232 fflags |= O_CREAT;
233 cap_rights_set(&rights, CAP_CREATE);
234 }
235 if ((uap->oflags & CLOUDABI_O_DIRECTORY) != 0)
236 fflags |= O_DIRECTORY;
237 if ((uap->oflags & CLOUDABI_O_EXCL) != 0)
238 fflags |= O_EXCL;
239 if ((uap->oflags & CLOUDABI_O_TRUNC) != 0) {
240 fflags |= O_TRUNC;
241 cap_rights_set(&rights, CAP_FTRUNCATE);
242 }
243 if ((fds.fs_flags & CLOUDABI_FDFLAG_APPEND) != 0)
244 fflags |= O_APPEND;
245 if ((fds.fs_flags & CLOUDABI_FDFLAG_NONBLOCK) != 0)
246 fflags |= O_NONBLOCK;
247 if ((fds.fs_flags & (CLOUDABI_FDFLAG_SYNC | CLOUDABI_FDFLAG_DSYNC |
248 CLOUDABI_FDFLAG_RSYNC)) != 0) {
249 fflags |= O_SYNC;
250 cap_rights_set(&rights, CAP_FSYNC);
251 }
252 if ((uap->dirfd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) == 0)
253 fflags |= O_NOFOLLOW;
254 if (write && (fflags & (O_APPEND | O_TRUNC)) == 0)
255 cap_rights_set(&rights, CAP_SEEK);
256
257 /* Allocate new file descriptor. */
258 error = falloc_noinstall(td, &fp);
259 if (error != 0)
260 return (error);
261 fp->f_flag = fflags & FMASK;
262
263 /* Open path. */
264 error = copyin_path(uap->path, uap->path_len, &path);
265 if (error != 0) {
266 fdrop(fp, td);
267 return (error);
268 }
269 NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, uap->dirfd.fd,
270 &rights, td);
271 error = vn_open(&nd, &fflags, 0777 & ~td->td_proc->p_fd->fd_cmask, fp);
272 cloudabi_freestr(path);
273 if (error != 0) {
274 /* Custom operations provided. */
275 if (error == ENXIO && fp->f_ops != &badfileops)
276 goto success;
277
278 /*
279 * POSIX compliance: return ELOOP in case openat() is
280 * called on a symbolic link and O_NOFOLLOW is set.
281 */
282 if (error == EMLINK)
283 error = ELOOP;
284 fdrop(fp, td);
285 return (error);
286 }
287 NDFREE(&nd, NDF_ONLY_PNBUF);
288 filecaps_free(&nd.ni_filecaps);
289 fp->f_vnode = vp = nd.ni_vp;
290
291 /* Install vnode operations if no custom operations are provided. */
292 if (fp->f_ops == &badfileops) {
293 fp->f_seqcount = 1;
294 finit(fp, (fflags & FMASK) | (fp->f_flag & FHASLOCK),
295 DTYPE_VNODE, vp, &vnops);
296 }
297 VOP_UNLOCK(vp, 0);
298
299 /* Truncate file. */
300 if (fflags & O_TRUNC) {
301 error = fo_truncate(fp, 0, td->td_ucred, td);
302 if (error != 0) {
303 fdrop(fp, td);
304 return (error);
305 }
306 }
307
308 success:
309 /* Determine which Capsicum rights to set on the file descriptor. */
310 cloudabi_remove_conflicting_rights(cloudabi_convert_filetype(fp),
311 &fds.fs_rights_base, &fds.fs_rights_inheriting);
312 cloudabi_convert_rights(fds.fs_rights_base | fds.fs_rights_inheriting,
313 &fcaps.fc_rights);
314 if (cap_rights_is_set(&fcaps.fc_rights))
315 fcaps.fc_fcntls = CAP_FCNTL_SETFL;
316
317 error = finstall(td, fp, &fd, fflags, &fcaps);
318 fdrop(fp, td);
319 if (error != 0)
320 return (error);
321 td->td_retval[0] = fd;
322 return (0);
323 }
324
325 /* Converts a FreeBSD directory entry structure and writes it to userspace. */
326 static int
327 write_dirent(struct dirent *bde, cloudabi_dircookie_t cookie, struct uio *uio)
328 {
329 cloudabi_dirent_t cde = {
330 .d_next = cookie,
331 .d_ino = bde->d_fileno,
332 .d_namlen = bde->d_namlen,
333 };
334 size_t len;
335 int error;
336
337 /* Convert file type. */
338 switch (bde->d_type) {
339 case DT_BLK:
340 cde.d_type = CLOUDABI_FILETYPE_BLOCK_DEVICE;
341 break;
342 case DT_CHR:
343 cde.d_type = CLOUDABI_FILETYPE_CHARACTER_DEVICE;
344 break;
345 case DT_DIR:
346 cde.d_type = CLOUDABI_FILETYPE_DIRECTORY;
347 break;
348 case DT_FIFO:
349 cde.d_type = CLOUDABI_FILETYPE_FIFO;
350 break;
351 case DT_LNK:
352 cde.d_type = CLOUDABI_FILETYPE_SYMBOLIC_LINK;
353 break;
354 case DT_REG:
355 cde.d_type = CLOUDABI_FILETYPE_REGULAR_FILE;
356 break;
357 case DT_SOCK:
358 /* The exact socket type cannot be derived. */
359 cde.d_type = CLOUDABI_FILETYPE_SOCKET_STREAM;
360 break;
361 default:
362 cde.d_type = CLOUDABI_FILETYPE_UNKNOWN;
363 break;
364 }
365
366 /* Write directory entry structure. */
367 len = sizeof(cde) < uio->uio_resid ? sizeof(cde) : uio->uio_resid;
368 error = uiomove(&cde, len, uio);
369 if (error != 0)
370 return (error);
371
372 /* Write filename. */
373 len = bde->d_namlen < uio->uio_resid ? bde->d_namlen : uio->uio_resid;
374 return (uiomove(bde->d_name, len, uio));
375 }
376
377 int
378 cloudabi_sys_file_readdir(struct thread *td,
379 struct cloudabi_sys_file_readdir_args *uap)
380 {
381 struct iovec iov = {
382 .iov_base = uap->buf,
383 .iov_len = uap->buf_len
384 };
385 struct uio uio = {
386 .uio_iov = &iov,
387 .uio_iovcnt = 1,
388 .uio_resid = iov.iov_len,
389 .uio_segflg = UIO_USERSPACE,
390 .uio_rw = UIO_READ,
391 .uio_td = td
392 };
393 struct file *fp;
394 struct vnode *vp;
395 void *readbuf;
396 cap_rights_t rights;
397 cloudabi_dircookie_t offset;
398 int error;
399
400 /* Obtain directory vnode. */
401 error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp);
402 if (error != 0) {
403 if (error == EINVAL)
404 return (ENOTDIR);
405 return (error);
406 }
407 if ((fp->f_flag & FREAD) == 0) {
408 fdrop(fp, td);
409 return (EBADF);
410 }
411
412 /*
413 * Call VOP_READDIR() and convert resulting data until the user
414 * provided buffer is filled.
415 */
416 readbuf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
417 offset = uap->cookie;
418 vp = fp->f_vnode;
419 while (uio.uio_resid > 0) {
420 struct iovec readiov = {
421 .iov_base = readbuf,
422 .iov_len = MAXBSIZE
423 };
424 struct uio readuio = {
425 .uio_iov = &readiov,
426 .uio_iovcnt = 1,
427 .uio_rw = UIO_READ,
428 .uio_segflg = UIO_SYSSPACE,
429 .uio_td = td,
430 .uio_resid = MAXBSIZE,
431 .uio_offset = offset
432 };
433 struct dirent *bde;
434 unsigned long *cookies, *cookie;
435 size_t readbuflen;
436 int eof, ncookies;
437
438 /* Validate file type. */
439 vn_lock(vp, LK_SHARED | LK_RETRY);
440 if (vp->v_type != VDIR) {
441 VOP_UNLOCK(vp, 0);
442 error = ENOTDIR;
443 goto done;
444 }
445 #ifdef MAC
446 error = mac_vnode_check_readdir(td->td_ucred, vp);
447 if (error != 0) {
448 VOP_UNLOCK(vp, 0);
449 goto done;
450 }
451 #endif /* MAC */
452
453 /* Read new directory entries. */
454 cookies = NULL;
455 ncookies = 0;
456 error = VOP_READDIR(vp, &readuio, fp->f_cred, &eof,
457 &ncookies, &cookies);
458 VOP_UNLOCK(vp, 0);
459 if (error != 0)
460 goto done;
461
462 /* Convert entries to CloudABI's format. */
463 readbuflen = MAXBSIZE - readuio.uio_resid;
464 bde = readbuf;
465 cookie = cookies;
466 while (readbuflen >= offsetof(struct dirent, d_name) &&
467 uio.uio_resid > 0 && ncookies > 0) {
468 /* Ensure that the returned offset always increases. */
469 if (readbuflen >= bde->d_reclen && bde->d_fileno != 0 &&
470 *cookie > offset) {
471 error = write_dirent(bde, *cookie, &uio);
472 if (error != 0) {
473 free(cookies, M_TEMP);
474 goto done;
475 }
476 }
477
478 if (offset < *cookie)
479 offset = *cookie;
480 ++cookie;
481 --ncookies;
482 readbuflen -= bde->d_reclen;
483 bde = (struct dirent *)((char *)bde + bde->d_reclen);
484 }
485 free(cookies, M_TEMP);
486 if (eof)
487 break;
488 }
489
490 done:
491 fdrop(fp, td);
492 free(readbuf, M_TEMP);
493 if (error != 0)
494 return (error);
495
496 /* Return number of bytes copied to userspace. */
497 td->td_retval[0] = uap->buf_len - uio.uio_resid;
498 return (0);
499 }
500
501 int
502 cloudabi_sys_file_readlink(struct thread *td,
503 struct cloudabi_sys_file_readlink_args *uap)
504 {
505 char *path;
506 int error;
507
508 error = copyin_path(uap->path, uap->path_len, &path);
509 if (error != 0)
510 return (error);
511
512 error = kern_readlinkat(td, uap->fd, path, UIO_SYSSPACE,
513 uap->buf, UIO_USERSPACE, uap->buf_len);
514 cloudabi_freestr(path);
515 return (error);
516 }
517
518 int
519 cloudabi_sys_file_rename(struct thread *td,
520 struct cloudabi_sys_file_rename_args *uap)
521 {
522 char *old, *new;
523 int error;
524
525 error = copyin_path(uap->path1, uap->path1_len, &old);
526 if (error != 0)
527 return (error);
528 error = copyin_path(uap->path2, uap->path2_len, &new);
529 if (error != 0) {
530 cloudabi_freestr(old);
531 return (error);
532 }
533
534 error = kern_renameat(td, uap->fd1, old, uap->fd2, new,
535 UIO_SYSSPACE);
536 cloudabi_freestr(old);
537 cloudabi_freestr(new);
538 return (error);
539 }
540
541 /* Converts a FreeBSD stat structure to a CloudABI stat structure. */
542 static void
543 convert_stat(const struct stat *sb, cloudabi_filestat_t *csb)
544 {
545 cloudabi_filestat_t res = {
546 .st_dev = sb->st_dev,
547 .st_ino = sb->st_ino,
548 .st_nlink = sb->st_nlink,
549 .st_size = sb->st_size,
550 };
551
552 cloudabi_convert_timespec(&sb->st_atim, &res.st_atim);
553 cloudabi_convert_timespec(&sb->st_mtim, &res.st_mtim);
554 cloudabi_convert_timespec(&sb->st_ctim, &res.st_ctim);
555 *csb = res;
556 }
557
558 int
559 cloudabi_sys_file_stat_fget(struct thread *td,
560 struct cloudabi_sys_file_stat_fget_args *uap)
561 {
562 struct stat sb;
563 cloudabi_filestat_t csb;
564 struct file *fp;
565 cap_rights_t rights;
566 cloudabi_filetype_t filetype;
567 int error;
568
569 /* Fetch file descriptor attributes. */
570 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FSTAT), &fp);
571 if (error != 0)
572 return (error);
573 error = fo_stat(fp, &sb, td->td_ucred, td);
574 if (error != 0) {
575 fdrop(fp, td);
576 return (error);
577 }
578 filetype = cloudabi_convert_filetype(fp);
579 fdrop(fp, td);
580
581 /* Convert attributes to CloudABI's format. */
582 convert_stat(&sb, &csb);
583 csb.st_filetype = filetype;
584 return (copyout(&csb, uap->buf, sizeof(csb)));
585 }
586
587 /* Converts timestamps to arguments to futimens() and utimensat(). */
588 static void
589 convert_utimens_arguments(const cloudabi_filestat_t *fs,
590 cloudabi_fsflags_t flags, struct timespec *ts)
591 {
592
593 if ((flags & CLOUDABI_FILESTAT_ATIM_NOW) != 0) {
594 ts[0].tv_nsec = UTIME_NOW;
595 } else if ((flags & CLOUDABI_FILESTAT_ATIM) != 0) {
596 ts[0].tv_sec = fs->st_atim / 1000000000;
597 ts[0].tv_nsec = fs->st_atim % 1000000000;
598 } else {
599 ts[0].tv_nsec = UTIME_OMIT;
600 }
601
602 if ((flags & CLOUDABI_FILESTAT_MTIM_NOW) != 0) {
603 ts[1].tv_nsec = UTIME_NOW;
604 } else if ((flags & CLOUDABI_FILESTAT_MTIM) != 0) {
605 ts[1].tv_sec = fs->st_mtim / 1000000000;
606 ts[1].tv_nsec = fs->st_mtim % 1000000000;
607 } else {
608 ts[1].tv_nsec = UTIME_OMIT;
609 }
610 }
611
612 int
613 cloudabi_sys_file_stat_fput(struct thread *td,
614 struct cloudabi_sys_file_stat_fput_args *uap)
615 {
616 cloudabi_filestat_t fs;
617 struct timespec ts[2];
618 int error;
619
620 error = copyin(uap->buf, &fs, sizeof(fs));
621 if (error != 0)
622 return (error);
623
624 /*
625 * Only support truncation and timestamp modification separately
626 * for now, to prevent unnecessary code duplication.
627 */
628 if ((uap->flags & CLOUDABI_FILESTAT_SIZE) != 0) {
629 /* Call into kern_ftruncate() for file truncation. */
630 if ((uap->flags & ~CLOUDABI_FILESTAT_SIZE) != 0)
631 return (EINVAL);
632 return (kern_ftruncate(td, uap->fd, fs.st_size));
633 } else if ((uap->flags & (CLOUDABI_FILESTAT_ATIM |
634 CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
635 CLOUDABI_FILESTAT_MTIM_NOW)) != 0) {
636 /* Call into kern_futimens() for timestamp modification. */
637 if ((uap->flags & ~(CLOUDABI_FILESTAT_ATIM |
638 CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
639 CLOUDABI_FILESTAT_MTIM_NOW)) != 0)
640 return (EINVAL);
641 convert_utimens_arguments(&fs, uap->flags, ts);
642 return (kern_futimens(td, uap->fd, ts, UIO_SYSSPACE));
643 }
644 return (EINVAL);
645 }
646
647 int
648 cloudabi_sys_file_stat_get(struct thread *td,
649 struct cloudabi_sys_file_stat_get_args *uap)
650 {
651 struct stat sb;
652 cloudabi_filestat_t csb;
653 char *path;
654 int error;
655
656 error = copyin_path(uap->path, uap->path_len, &path);
657 if (error != 0)
658 return (error);
659
660 error = kern_statat(td,
661 (uap->fd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 :
662 AT_SYMLINK_NOFOLLOW, uap->fd.fd, path, UIO_SYSSPACE, &sb, NULL);
663 cloudabi_freestr(path);
664 if (error != 0)
665 return (error);
666
667 /* Convert results and return them. */
668 convert_stat(&sb, &csb);
669 if (S_ISBLK(sb.st_mode))
670 csb.st_filetype = CLOUDABI_FILETYPE_BLOCK_DEVICE;
671 else if (S_ISCHR(sb.st_mode))
672 csb.st_filetype = CLOUDABI_FILETYPE_CHARACTER_DEVICE;
673 else if (S_ISDIR(sb.st_mode))
674 csb.st_filetype = CLOUDABI_FILETYPE_DIRECTORY;
675 else if (S_ISFIFO(sb.st_mode))
676 csb.st_filetype = CLOUDABI_FILETYPE_FIFO;
677 else if (S_ISREG(sb.st_mode))
678 csb.st_filetype = CLOUDABI_FILETYPE_REGULAR_FILE;
679 else if (S_ISSOCK(sb.st_mode)) {
680 /* Inaccurate, but the best that we can do. */
681 csb.st_filetype = CLOUDABI_FILETYPE_SOCKET_STREAM;
682 } else if (S_ISLNK(sb.st_mode))
683 csb.st_filetype = CLOUDABI_FILETYPE_SYMBOLIC_LINK;
684 else
685 csb.st_filetype = CLOUDABI_FILETYPE_UNKNOWN;
686 return (copyout(&csb, uap->buf, sizeof(csb)));
687 }
688
689 int
690 cloudabi_sys_file_stat_put(struct thread *td,
691 struct cloudabi_sys_file_stat_put_args *uap)
692 {
693 cloudabi_filestat_t fs;
694 struct timespec ts[2];
695 char *path;
696 int error;
697
698 /*
699 * Only support timestamp modification for now, as there is no
700 * truncateat().
701 */
702 if ((uap->flags & ~(CLOUDABI_FILESTAT_ATIM |
703 CLOUDABI_FILESTAT_ATIM_NOW | CLOUDABI_FILESTAT_MTIM |
704 CLOUDABI_FILESTAT_MTIM_NOW)) != 0)
705 return (EINVAL);
706
707 error = copyin(uap->buf, &fs, sizeof(fs));
708 if (error != 0)
709 return (error);
710 error = copyin_path(uap->path, uap->path_len, &path);
711 if (error != 0)
712 return (error);
713
714 convert_utimens_arguments(&fs, uap->flags, ts);
715 error = kern_utimensat(td, uap->fd.fd, path, UIO_SYSSPACE, ts,
716 UIO_SYSSPACE, (uap->fd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) ?
717 0 : AT_SYMLINK_NOFOLLOW);
718 cloudabi_freestr(path);
719 return (error);
720 }
721
722 int
723 cloudabi_sys_file_symlink(struct thread *td,
724 struct cloudabi_sys_file_symlink_args *uap)
725 {
726 char *path1, *path2;
727 int error;
728
729 error = copyin_path(uap->path1, uap->path1_len, &path1);
730 if (error != 0)
731 return (error);
732 error = copyin_path(uap->path2, uap->path2_len, &path2);
733 if (error != 0) {
734 cloudabi_freestr(path1);
735 return (error);
736 }
737
738 error = kern_symlinkat(td, path1, uap->fd, path2, UIO_SYSSPACE);
739 cloudabi_freestr(path1);
740 cloudabi_freestr(path2);
741 return (error);
742 }
743
744 int
745 cloudabi_sys_file_unlink(struct thread *td,
746 struct cloudabi_sys_file_unlink_args *uap)
747 {
748 char *path;
749 int error;
750
751 error = copyin_path(uap->path, uap->path_len, &path);
752 if (error != 0)
753 return (error);
754
755 if (uap->flags & CLOUDABI_UNLINK_REMOVEDIR)
756 error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE);
757 else
758 error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0);
759 cloudabi_freestr(path);
760 return (error);
761 }
Cache object: d1192ab594e7cb432f4c695e635518be
|