+ goto done;
+ }
+
+ newfd_s = __current->fdtable->fds[newfd];
+ if (newfd_s && (errno = vfs_close(newfd_s->file))) {
+ goto done;
+ }
+
+ if (!(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
+ __current->fdtable->fds[newfd] = newfd_s;
+ return newfd;
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
+{
+ return vfs_dup2(oldfd, newfd);
+}
+
+__DEFINE_LXSYSCALL1(int, dup, int, oldfd)
+{
+ int errno, newfd;
+ struct v_fd *oldfd_s, *newfd_s;
+ if ((errno = vfs_getfd(oldfd, &oldfd_s))) {
+ goto done;
+ }
+
+ if (!(errno = vfs_alloc_fdslot(&newfd)) &&
+ !(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
+ __current->fdtable->fds[newfd] = newfd_s;
+ return newfd;
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int,
+ symlink,
+ const char*,
+ pathname,
+ const char*,
+ link_target)
+{
+ int errno;
+ struct v_dnode* dnode;
+ if ((errno = vfs_walk_proc(pathname, &dnode, NULL, 0))) {
+ goto done;
+ }
+
+ if (errno = vfs_check_writable(dnode)) {
+ goto done;
+ }
+
+ if (!dnode->inode->ops->set_symlink) {
+ errno = ENOTSUP;
+ goto done;
+ }
+
+ lock_inode(dnode->inode);
+
+ errno = dnode->inode->ops->set_symlink(dnode->inode, link_target);
+
+ unlock_inode(dnode->inode);
+
+done:
+ return DO_STATUS(errno);
+}
+
+void
+vfs_ref_dnode(struct v_dnode* dnode)
+{
+ atomic_fetch_add(&dnode->ref_count, 1);
+ mnt_mkbusy(dnode->mnt);
+}
+
+void
+vfs_unref_dnode(struct v_dnode* dnode)
+{
+ atomic_fetch_sub(&dnode->ref_count, 1);
+ mnt_chillax(dnode->mnt);
+}
+
+int
+vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
+{
+ int errno = 0;
+
+ lock_dnode(dnode);
+
+ if (!(dnode->inode->itype & VFS_IFDIR)) {
+ errno = ENOTDIR;
+ goto done;
+ }
+
+ if (proc->cwd) {
+ vfs_unref_dnode(proc->cwd);
+ }
+
+ vfs_ref_dnode(dnode);
+ proc->cwd = dnode;
+
+ unlock_dnode(dnode);
+
+done:
+ return errno;
+}
+
+__DEFINE_LXSYSCALL1(int, chdir, const char*, path)
+{
+ struct v_dnode* dnode;
+ int errno = 0;
+
+ if ((errno = vfs_walk_proc(path, &dnode, NULL, 0))) {
+ goto done;
+ }
+
+ errno = vfs_do_chdir(__current, dnode);
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, fchdir, int, fd)
+{
+ struct v_fd* fd_s;
+ int errno = 0;
+
+ if ((errno = vfs_getfd(fd, &fd_s))) {
+ goto done;
+ }
+
+ errno = vfs_do_chdir(__current, fd_s->file->dnode);
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
+{
+ int errno = 0;
+ char* ret_ptr = 0;
+ if (size < 2) {
+ errno = ERANGE;
+ goto done;
+ }
+
+ size_t len = 0;
+
+ if (!__current->cwd) {
+ *buf = VFS_PATH_DELIM;
+ len = 1;