Index: head/sys/compat/cloudabi/cloudabi_fd.c
===================================================================
--- head/sys/compat/cloudabi/cloudabi_fd.c
+++ head/sys/compat/cloudabi/cloudabi_fd.c
@@ -27,13 +27,64 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/capsicum.h>
 #include <sys/filedesc.h>
 #include <sys/proc.h>
+#include <sys/socketvar.h>
 #include <sys/syscallsubr.h>
 #include <sys/sysproto.h>
+#include <sys/systm.h>
 #include <sys/unistd.h>
+#include <sys/vnode.h>
 
 #include <compat/cloudabi/cloudabi_proto.h>
+#include <compat/cloudabi/cloudabi_syscalldefs.h>
+#include <compat/cloudabi/cloudabi_util.h>
+
+/* Translation between CloudABI and Capsicum rights. */
+#define RIGHTS_MAPPINGS \
+	MAPPING(CLOUDABI_RIGHT_FD_DATASYNC, CAP_FSYNC)			\
+	MAPPING(CLOUDABI_RIGHT_FD_READ, CAP_READ)			\
+	MAPPING(CLOUDABI_RIGHT_FD_SEEK, CAP_SEEK)			\
+	MAPPING(CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS, CAP_FCNTL)		\
+	MAPPING(CLOUDABI_RIGHT_FD_SYNC, CAP_FSYNC)			\
+	MAPPING(CLOUDABI_RIGHT_FD_TELL, CAP_SEEK_TELL)			\
+	MAPPING(CLOUDABI_RIGHT_FD_WRITE, CAP_WRITE)			\
+	MAPPING(CLOUDABI_RIGHT_FILE_ADVISE)				\
+	MAPPING(CLOUDABI_RIGHT_FILE_ALLOCATE, CAP_WRITE)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY, CAP_MKDIRAT)	\
+	MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FILE, CAP_CREATE)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FIFO, CAP_MKFIFOAT)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_LINK_SOURCE, CAP_LOOKUP)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_LINK_TARGET, CAP_LINKAT)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_OPEN, CAP_LOOKUP)			\
+	MAPPING(CLOUDABI_RIGHT_FILE_READDIR, CAP_READ)			\
+	MAPPING(CLOUDABI_RIGHT_FILE_READLINK, CAP_LOOKUP)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_RENAME_SOURCE, CAP_RENAMEAT)	\
+	MAPPING(CLOUDABI_RIGHT_FILE_RENAME_TARGET, CAP_LINKAT)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_STAT_FGET, CAP_FSTAT)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE, CAP_FTRUNCATE)	\
+	MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES, CAP_FUTIMES)	\
+	MAPPING(CLOUDABI_RIGHT_FILE_STAT_GET, CAP_FSTATAT)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES, CAP_FUTIMESAT)	\
+	MAPPING(CLOUDABI_RIGHT_FILE_SYMLINK, CAP_SYMLINKAT)		\
+	MAPPING(CLOUDABI_RIGHT_FILE_UNLINK, CAP_UNLINKAT)		\
+	MAPPING(CLOUDABI_RIGHT_MEM_MAP, CAP_MMAP)			\
+	MAPPING(CLOUDABI_RIGHT_MEM_MAP_EXEC, CAP_MMAP_X)		\
+	MAPPING(CLOUDABI_RIGHT_POLL_FD_READWRITE, CAP_EVENT)		\
+	MAPPING(CLOUDABI_RIGHT_POLL_MODIFY, CAP_KQUEUE_CHANGE)		\
+	MAPPING(CLOUDABI_RIGHT_POLL_PROC_TERMINATE, CAP_PDWAIT)		\
+	MAPPING(CLOUDABI_RIGHT_POLL_WAIT, CAP_KQUEUE_EVENT)		\
+	MAPPING(CLOUDABI_RIGHT_PROC_EXEC, CAP_FEXECVE)			\
+	MAPPING(CLOUDABI_RIGHT_SOCK_ACCEPT, CAP_ACCEPT)			\
+	MAPPING(CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY, CAP_BINDAT)		\
+	MAPPING(CLOUDABI_RIGHT_SOCK_BIND_SOCKET, CAP_BIND)		\
+	MAPPING(CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY, CAP_CONNECTAT)	\
+	MAPPING(CLOUDABI_RIGHT_SOCK_CONNECT_SOCKET, CAP_CONNECT)	\
+	MAPPING(CLOUDABI_RIGHT_SOCK_LISTEN, CAP_LISTEN)			\
+	MAPPING(CLOUDABI_RIGHT_SOCK_SHUTDOWN, CAP_SHUTDOWN)		\
+	MAPPING(CLOUDABI_RIGHT_SOCK_STAT_GET, CAP_GETPEERNAME,		\
+	    CAP_GETSOCKNAME, CAP_GETSOCKOPT)
 
 int
 cloudabi_sys_fd_close(struct thread *td, struct cloudabi_sys_fd_close_args *uap)
@@ -160,13 +211,214 @@
 	return (sys_lseek(td, &lseek_args));
 }
 
+/* Converts a file descriptor to a CloudABI file descriptor type. */
+cloudabi_filetype_t
+cloudabi_convert_filetype(const struct file *fp)
+{
+	struct socket *so;
+	struct vnode *vp;
+
+	switch (fp->f_type) {
+	case DTYPE_FIFO:
+		return (CLOUDABI_FILETYPE_FIFO);
+	case DTYPE_KQUEUE:
+		return (CLOUDABI_FILETYPE_POLL);
+	case DTYPE_PIPE:
+		return (CLOUDABI_FILETYPE_FIFO);
+	case DTYPE_PROCDESC:
+		return (CLOUDABI_FILETYPE_PROCESS);
+	case DTYPE_SHM:
+		return (CLOUDABI_FILETYPE_SHARED_MEMORY);
+	case DTYPE_SOCKET:
+		so = fp->f_data;
+		switch (so->so_type) {
+		case SOCK_DGRAM:
+			return (CLOUDABI_FILETYPE_SOCKET_DGRAM);
+		case SOCK_SEQPACKET:
+			return (CLOUDABI_FILETYPE_SOCKET_SEQPACKET);
+		case SOCK_STREAM:
+			return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+		default:
+			return (CLOUDABI_FILETYPE_UNKNOWN);
+		}
+	case DTYPE_VNODE:
+		vp = fp->f_vnode;
+		switch (vp->v_type) {
+		case VBLK:
+			return (CLOUDABI_FILETYPE_BLOCK_DEVICE);
+		case VCHR:
+			return (CLOUDABI_FILETYPE_CHARACTER_DEVICE);
+		case VDIR:
+			return (CLOUDABI_FILETYPE_DIRECTORY);
+		case VFIFO:
+			return (CLOUDABI_FILETYPE_FIFO);
+		case VLNK:
+			return (CLOUDABI_FILETYPE_SYMBOLIC_LINK);
+		case VREG:
+			return (CLOUDABI_FILETYPE_REGULAR_FILE);
+		case VSOCK:
+			return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+		default:
+			return (CLOUDABI_FILETYPE_UNKNOWN);
+		}
+	default:
+		return (CLOUDABI_FILETYPE_UNKNOWN);
+	}
+}
+
+/*
+ * Converts FreeBSD's Capsicum rights to CloudABI's set of rights.
+ */
+static void
+convert_capabilities(const cap_rights_t *capabilities,
+    cloudabi_filetype_t filetype, cloudabi_rights_t *base,
+    cloudabi_rights_t *inheriting)
+{
+	cloudabi_rights_t rights;
+
+	/* Convert FreeBSD bits to CloudABI bits. */
+	rights = 0;
+#define MAPPING(cloudabi, ...) do {				\
+	if (cap_rights_is_set(capabilities, ##__VA_ARGS__))	\
+		rights |= (cloudabi);				\
+} while (0);
+	RIGHTS_MAPPINGS
+#undef MAPPING
+
+	/*
+	 * CloudABI has a small number of additional rights bits to
+	 * disambiguate between multiple purposes. Remove the bits that
+	 * don't apply to the type of the file descriptor.
+	 *
+	 * As file descriptor access modes (O_ACCMODE) has been fully
+	 * replaced by rights bits, CloudABI distinguishes between
+	 * rights that apply to the file descriptor itself (base) versus
+	 * rights of new file descriptors derived from them
+	 * (inheriting). The code below approximates the pair by
+	 * decomposing depending on the file descriptor type.
+	 *
+	 * We need to be somewhat accurate about which actions can
+	 * actually be performed on the file descriptor, as functions
+	 * like fcntl(fd, F_GETFL) are emulated on top of this.
+	 */
+	switch (filetype) {
+	case CLOUDABI_FILETYPE_DIRECTORY:
+		*base = rights & (CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS |
+		    CLOUDABI_RIGHT_FD_SYNC | CLOUDABI_RIGHT_FILE_ADVISE |
+		    CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY |
+		    CLOUDABI_RIGHT_FILE_CREATE_FILE |
+		    CLOUDABI_RIGHT_FILE_CREATE_FIFO |
+		    CLOUDABI_RIGHT_FILE_LINK_SOURCE |
+		    CLOUDABI_RIGHT_FILE_LINK_TARGET |
+		    CLOUDABI_RIGHT_FILE_OPEN |
+		    CLOUDABI_RIGHT_FILE_READDIR |
+		    CLOUDABI_RIGHT_FILE_READLINK |
+		    CLOUDABI_RIGHT_FILE_RENAME_SOURCE |
+		    CLOUDABI_RIGHT_FILE_RENAME_TARGET |
+		    CLOUDABI_RIGHT_FILE_STAT_FGET |
+		    CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES |
+		    CLOUDABI_RIGHT_FILE_STAT_GET |
+		    CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES |
+		    CLOUDABI_RIGHT_FILE_SYMLINK |
+		    CLOUDABI_RIGHT_FILE_UNLINK |
+		    CLOUDABI_RIGHT_POLL_FD_READWRITE |
+		    CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY |
+		    CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY);
+		*inheriting = rights;
+		break;
+	case CLOUDABI_FILETYPE_FIFO:
+		*base = rights & ~(CLOUDABI_RIGHT_FILE_ADVISE |
+		    CLOUDABI_RIGHT_FILE_ALLOCATE |
+		    CLOUDABI_RIGHT_FILE_READDIR);
+		*inheriting = 0;
+		break;
+	case CLOUDABI_FILETYPE_POLL:
+		*base = rights & ~CLOUDABI_RIGHT_FILE_ADVISE;
+		*inheriting = 0;
+		break;
+	case CLOUDABI_FILETYPE_PROCESS:
+		*base = rights & ~CLOUDABI_RIGHT_FILE_ADVISE;
+		*inheriting = 0;
+		break;
+	case CLOUDABI_FILETYPE_REGULAR_FILE:
+		*base = rights & ~CLOUDABI_RIGHT_FILE_READDIR;
+		*inheriting = 0;
+		break;
+	case CLOUDABI_FILETYPE_SHARED_MEMORY:
+		*base = rights & ~(CLOUDABI_RIGHT_FD_SEEK |
+		    CLOUDABI_RIGHT_FD_TELL |
+		    CLOUDABI_RIGHT_FILE_ADVISE |
+		    CLOUDABI_RIGHT_FILE_ALLOCATE |
+		    CLOUDABI_RIGHT_FILE_READDIR);
+		*inheriting = 0;
+		break;
+	case CLOUDABI_FILETYPE_SOCKET_DGRAM:
+	case CLOUDABI_FILETYPE_SOCKET_SEQPACKET:
+	case CLOUDABI_FILETYPE_SOCKET_STREAM:
+		*base = rights & (CLOUDABI_RIGHT_FD_READ |
+		    CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS |
+		    CLOUDABI_RIGHT_FD_WRITE |
+		    CLOUDABI_RIGHT_FILE_STAT_FGET |
+		    CLOUDABI_RIGHT_POLL_FD_READWRITE |
+		    CLOUDABI_RIGHT_SOCK_ACCEPT |
+		    CLOUDABI_RIGHT_SOCK_BIND_SOCKET |
+		    CLOUDABI_RIGHT_SOCK_CONNECT_SOCKET |
+		    CLOUDABI_RIGHT_SOCK_LISTEN |
+		    CLOUDABI_RIGHT_SOCK_SHUTDOWN |
+		    CLOUDABI_RIGHT_SOCK_STAT_GET);
+		*inheriting = rights;
+		break;
+	default:
+		*base = rights;
+		*inheriting = 0;
+		break;
+	}
+}
+
 int
 cloudabi_sys_fd_stat_get(struct thread *td,
     struct cloudabi_sys_fd_stat_get_args *uap)
 {
-
-	/* Not implemented. */
-	return (ENOSYS);
+	cloudabi_fdstat_t fsb = {};
+	struct filedesc *fdp;
+	struct file *fp;
+	seq_t seq;
+	cap_rights_t rights;
+	int error, oflags;
+	bool modified;
+
+	/* Obtain file descriptor properties. */
+	fdp = td->td_proc->p_fd;
+	do {
+		error = fget_unlocked(fdp, uap->fd, cap_rights_init(&rights),
+		    &fp, &seq);
+		if (error != 0)
+			return (error);
+		if (fp->f_ops == &badfileops) {
+			fdrop(fp, td);
+			return (EBADF);
+		}
+
+		rights = *cap_rights(fdp, uap->fd);
+		oflags = OFLAGS(fp->f_flag);
+		fsb.fs_filetype = cloudabi_convert_filetype(fp);
+
+		modified = fd_modified(fdp, uap->fd, seq);
+		fdrop(fp, td);
+	} while (modified);
+
+	/* Convert file descriptor flags. */
+	if (oflags & O_APPEND)
+		fsb.fs_flags |= CLOUDABI_FDFLAG_APPEND;
+	if (oflags & O_NONBLOCK)
+		fsb.fs_flags |= CLOUDABI_FDFLAG_NONBLOCK;
+	if (oflags & O_SYNC)
+		fsb.fs_flags |= CLOUDABI_FDFLAG_SYNC;
+
+	/* Convert capabilities to CloudABI rights. */
+	convert_capabilities(&rights, fsb.fs_filetype,
+	    &fsb.fs_rights_base, &fsb.fs_rights_inheriting);
+	return (copyout(&fsb, (void *)uap->buf, sizeof(fsb)));
 }
 
 int
Index: head/sys/compat/cloudabi/cloudabi_file.c
===================================================================
--- head/sys/compat/cloudabi/cloudabi_file.c
+++ head/sys/compat/cloudabi/cloudabi_file.c
@@ -27,14 +27,18 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/capsicum.h>
 #include <sys/fcntl.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
 #include <sys/syscallsubr.h>
 
 #include <compat/cloudabi/cloudabi_proto.h>
 #include <compat/cloudabi/cloudabi_syscalldefs.h>
+#include <compat/cloudabi/cloudabi_util.h>
 
 static MALLOC_DEFINE(M_CLOUDABI_PATH, "cloudabipath", "CloudABI pathnames");
 
@@ -220,13 +224,50 @@
 	return (error);
 }
 
+/* Converts a FreeBSD stat structure to a CloudABI stat structure. */
+static void
+convert_stat(const struct stat *sb, cloudabi_filestat_t *csb)
+{
+	cloudabi_filestat_t res = {
+		.st_dev		= sb->st_dev,
+		.st_ino		= sb->st_ino,
+		.st_nlink	= sb->st_nlink,
+		.st_size	= sb->st_size,
+	};
+
+	cloudabi_convert_timespec(&sb->st_atim, &res.st_atim);
+	cloudabi_convert_timespec(&sb->st_mtim, &res.st_mtim);
+	cloudabi_convert_timespec(&sb->st_ctim, &res.st_ctim);
+	*csb = res;
+}
+
 int
 cloudabi_sys_file_stat_fget(struct thread *td,
     struct cloudabi_sys_file_stat_fget_args *uap)
 {
+	struct stat sb;
+	cloudabi_filestat_t csb;
+	struct file *fp;
+	cap_rights_t rights;
+	cloudabi_filetype_t filetype;
+	int error;
 
-	/* Not implemented. */
-	return (ENOSYS);
+	/* Fetch file descriptor attributes. */
+	error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FSTAT), &fp);
+	if (error != 0)
+		return (error);
+	error = fo_stat(fp, &sb, td->td_ucred, td);
+	if (error != 0) {
+		fdrop(fp, td);
+		return (error);
+	}
+	filetype = cloudabi_convert_filetype(fp);
+	fdrop(fp, td);
+
+	/* Convert attributes to CloudABI's format. */
+	convert_stat(&sb, &csb);
+	csb.st_filetype = filetype;
+	return (copyout(&csb, uap->buf, sizeof(csb)));
 }
 
 int
@@ -242,9 +283,42 @@
 cloudabi_sys_file_stat_get(struct thread *td,
     struct cloudabi_sys_file_stat_get_args *uap)
 {
+	struct stat sb;
+	cloudabi_filestat_t csb;
+	char *path;
+	int error;
 
-	/* Not implemented. */
-	return (ENOSYS);
+	error = copyin_path(uap->path, uap->pathlen, &path);
+	if (error != 0)
+		return (error);
+
+	error = kern_statat(td,
+	    (uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 :
+	    AT_SYMLINK_NOFOLLOW, uap->fd, path, UIO_SYSSPACE, &sb, NULL);
+	cloudabi_freestr(path);
+	if (error != 0)
+		return (error);
+
+	/* Convert results and return them. */
+	convert_stat(&sb, &csb);
+	if (S_ISBLK(sb.st_mode))
+		csb.st_filetype = CLOUDABI_FILETYPE_BLOCK_DEVICE;
+	else if (S_ISCHR(sb.st_mode))
+		csb.st_filetype = CLOUDABI_FILETYPE_CHARACTER_DEVICE;
+	else if (S_ISDIR(sb.st_mode))
+		csb.st_filetype = CLOUDABI_FILETYPE_DIRECTORY;
+	else if (S_ISFIFO(sb.st_mode))
+		csb.st_filetype = CLOUDABI_FILETYPE_FIFO;
+	else if (S_ISREG(sb.st_mode))
+		csb.st_filetype = CLOUDABI_FILETYPE_REGULAR_FILE;
+	else if (S_ISSOCK(sb.st_mode)) {
+		/* Inaccurate, but the best that we can do. */
+		csb.st_filetype = CLOUDABI_FILETYPE_SOCKET_STREAM;
+	} else if (S_ISLNK(sb.st_mode))
+		csb.st_filetype = CLOUDABI_FILETYPE_SYMBOLIC_LINK;
+	else
+		csb.st_filetype = CLOUDABI_FILETYPE_UNKNOWN;
+	return (copyout(&csb, uap->buf, sizeof(csb)));
 }
 
 int
Index: head/sys/compat/cloudabi/cloudabi_util.h
===================================================================
--- head/sys/compat/cloudabi/cloudabi_util.h
+++ head/sys/compat/cloudabi/cloudabi_util.h
@@ -30,6 +30,7 @@
 
 #include <compat/cloudabi/cloudabi_syscalldefs.h>
 
+struct file;
 struct thread;
 struct timespec;
 
@@ -40,6 +41,9 @@
 /* Converts a FreeBSD errno to a CloudABI errno. */
 cloudabi_errno_t cloudabi_convert_errno(int);
 
+/* Converts a file descriptor to a CloudABI file descriptor type. */
+cloudabi_filetype_t cloudabi_convert_filetype(const struct file *);
+
 /* Converts a struct timespec to a CloudABI timestamp. */
 int cloudabi_convert_timespec(const struct timespec *, cloudabi_timestamp_t *);