Nucleus
Barry Directory listing in VFS 2d05318 (3 years, 2 months ago)
diff --git a/vfs/files.c b/vfs/files.c
index b830e40..c285e51 100644
--- a/vfs/files.c
+++ b/vfs/files.c
@@ -86,6 +86,33 @@ install_fd(int fd, File *file)
current->files->fd[fd] = file;
}
+/* Duplicate a file descriptor */
+int
+dup(int oldfd)
+{
+ int newfd = allocate_fd();
+ if (newfd == -1)
+ return -EMFILE;
+ return dup2(oldfd, newfd);
+}
+
+/* Duplicate a file descriptor to a new file descriptor */
+int
+dup2(int oldfd, int newfd)
+{
+ /* Check file descriptors */
+ File *oldfile = get_file_by_fd(oldfd);
+ File *newfile = get_file_by_fd(newfd);
+ if (!oldfile || newfd < 0 || newfd >= NFILES)
+ return -EBADF;
+ if (newfd != oldfd) {
+ if (newfile)
+ close(newfd);
+ install_fd(newfd, get(oldfile));
+ }
+ return newfd;
+}
+
/* Close a file */
int
close(int fd)
@@ -113,10 +140,7 @@ read(int fd, void *buf, size_t count)
if (file->inode && S_ISDIR(file->inode->mode))
return -EISDIR;
- lock(file);
- int sz = file_read(file, buf, count);
- unlock(file);
- return sz;
+ return file_read(file, buf, count);
}
/* Write a file */
@@ -135,10 +159,7 @@ write(int fd, void *buf, size_t count)
if (file->inode && S_ISDIR(file->inode->mode))
return -EISDIR;
- lock(file);
- int sz = file_write(file, buf, count);
- unlock(file);
- return sz;
+ return file_write(file, buf, count);
}
/* Move a file's position */
@@ -181,8 +202,39 @@ ioctl(int fd, unsigned long request, ...)
uintptr_t argp = va_arg(args, uintptr_t);
va_end(args);
- lock(file);
- int ret = file_ioctl(file, request, argp);
- unlock(file);
- return ret;
+ return file_ioctl(file, request, argp);
+}
+
+/* Get directory entries */
+size_t
+getdents(int fd, void *buf, size_t count)
+{
+ if (!verify_access(buf, count, PROT_WRITE))
+ return -EFAULT;
+ if (count < sizeof(struct dirent))
+ return -EINVAL;
+
+ int err;
+ size_t i, size = 0;
+ struct dirent *dent = buf;
+ File *file = get_file_by_fd(fd);
+ if (!file)
+ return -EBADF;
+ if (!S_ISDIR(file->inode->mode))
+ return -ENOTDIR;
+
+ /* Read as many entries as possible */
+ for (i = 0; i < count / sizeof(struct dirent); i++) {
+ err = file_readdir(file, dent, i);
+ if (err < 0)
+ goto out;
+ size += sizeof(struct dirent) + dent->d_namelen;
+ *((char *) buf + size - 1) = '\0';
+ dent = (void *) ((char *) buf + size);
+ }
+
+out:
+ if (!i)
+ return err;
+ return size;
}