The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/cloudabi/cloudabi_file.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.