BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / 2d05318728e0aa3fca502a2aeb1738773fffc98b

// Related

Nucleus

Barry Directory listing in VFS 2d05318 (3 years, 2 months ago)
diff --git a/include/nucleus/vfs.h b/include/nucleus/vfs.h
index 2ab824c..8dd295a 100644
--- a/include/nucleus/vfs.h
+++ b/include/nucleus/vfs.h
@@ -3,6 +3,7 @@
 
 #include <stddef.h>
 #include <sys/types.h>
+#include <dirent.h>
 #include <nucleus/object.h>
 #include <nucleus/memory.h>
 
@@ -87,6 +88,7 @@ struct FileOps {
 	size_t (*write)(File *, char *, size_t, off_t);
 	int (*open)(File *);
 	int (*ioctl)(File *, unsigned long, uintptr_t);
+	int (*readdir)(File *, struct dirent *, off_t);
 	void (*mmap)(File *, void *, size_t, off_t);
 };
 
@@ -122,6 +124,7 @@ int file_open(File *file);
 size_t file_read(File *file, char *buf, size_t count);
 size_t file_write(File *file, char *buf, size_t count);
 int file_ioctl(File *file, unsigned long request, uintptr_t arpg);
+int file_readdir(File *file, struct dirent *dent, off_t index);
 void file_mmap(File *file, void *addr, size_t len, off_t offset);
 /* Files namespace functions */
 File *get_file_by_fd(int fd);
diff --git a/vfs/ext2fs/block.c b/vfs/ext2fs/block.c
index 65ffdae..a084c76 100644
--- a/vfs/ext2fs/block.c
+++ b/vfs/ext2fs/block.c
@@ -1,5 +1,5 @@
 #include <stdint.h>
-#include <nucleus/panic.h>
+#include <nucleus/kernel.h>
 #include <nucleus/vfs.h>
 #include "ext2fs.h"
 
diff --git a/vfs/ext2fs/file.c b/vfs/ext2fs/file.c
index d19df72..a84da51 100644
--- a/vfs/ext2fs/file.c
+++ b/vfs/ext2fs/file.c
@@ -1,14 +1,15 @@
 #include <string.h>
+#include <errno.h>
 #include <nucleus/vfs.h>
 #include "ext2fs.h"
 
 size_t ext2fs_read(File *file, char *buf, size_t size, off_t offset);
-int ext2fs_readdir(File *file, DirEntry *de, off_t index);
+int ext2fs_readdir(File *file, struct dirent *dent, off_t index);
 int ext2fs_open(File *file);
 
 FileOps ext2fsFileOps = {
 	.read = ext2fs_read,
-//	.readdir = ext2fs_readdir,
+	.readdir = ext2fs_readdir,
 	.open = ext2fs_open,
 };
 
@@ -42,8 +43,33 @@ ext2fs_read(File *file, char *buf, size_t size, off_t offset)
 
 /* Read an ext2fs directory entry */
 int
-ext2fs_readdir(File *file, DirEntry *de, off_t index)
+ext2fs_readdir(File *file, struct dirent *dent, off_t index)
 {
+	char buf[PAGE_SIZE];
+	uint32_t block, blk = 0;
+	struct Ext2DirEntry *de;
+	struct Ext2Inode inode;
+	SuperBlock *sb = file->inode->super;
+	ext2fs_read_inode(sb, file->inode->ino, &inode);
+	for (blk = 0; blk < 0xFFFF; blk++) {
+		block = ext2fs_get_data_addr(sb, &inode, blk);
+		if (!block)
+			return -ENOENT;
+		ext2fs_read_block(sb, block, buf);
+		for (de = (struct Ext2DirEntry *) buf;
+		     index && de < (struct Ext2DirEntry *) (buf + PAGE_SIZE);
+		     de = (void *) de + de->size, index--);
+		if (de >= (struct Ext2DirEntry *) (buf + PAGE_SIZE))
+			return -ENOENT;
+		if (!index)
+			break;
+	}
+	if (!de->ino)
+		return -ENOENT;
+	dent->d_ino = de->ino;
+	dent->d_type = de->type;
+	dent->d_namelen = de->namelen + 1;
+	strncpy(dent->d_name, de->name, de->size);
 	return 0;
 }
 
diff --git a/vfs/file.c b/vfs/file.c
index bca19dc..8d7e7cc 100644
--- a/vfs/file.c
+++ b/vfs/file.c
@@ -63,7 +63,6 @@ size_t
 file_read(File *file, char *buf, size_t size)
 {
 	size_t count = 0;
-	lock(file);
 	/* Irregular files cannot be cached */
 	if (!S_ISREG(file->inode->mode)) {
 		if (file->ops && file->ops->read)
@@ -98,6 +97,7 @@ file_read(File *file, char *buf, size_t size)
 		count += min;
 	}
 end:
+	lock(file);
 	file->pos += count;
 	unlock(file);
 	return count;
@@ -108,7 +108,6 @@ size_t
 file_write(File *file, char *buf, size_t size)
 {
 	size_t count = 0;
-	lock(file);
 	/* Irregular files cannot be cached */
 	if (!S_ISREG(file->inode->mode)) {
 		if (file->ops && file->ops->write)
@@ -141,6 +140,7 @@ file_write(File *file, char *buf, size_t size)
 		count += min;
 	}
 end:
+	lock(file);
 	file->pos += count;
 	unlock(file);
 	return count;
@@ -157,6 +157,15 @@ file_ioctl(File *file, unsigned long request, uintptr_t argp)
 	return file->ops->ioctl(file, request, argp);
 }
 
+/* Read a directory entry from a directory */
+int
+file_readdir(File *file, struct dirent *dent, off_t index)
+{
+	if (!file->ops || !file->ops->readdir)
+		return -EINVAL;
+	return file->ops->readdir(file, dent, index);
+}
+
 /* Map a file into memory */
 void
 file_mmap(File *file, void *addr, size_t len, off_t offset)
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;
 }
diff --git a/vfs/stat.c b/vfs/stat.c
new file mode 100644
index 0000000..037a77f
--- /dev/null
+++ b/vfs/stat.c
@@ -0,0 +1,60 @@
+/*
+ * This file implements the stat system call and similar system calls.
+ */
+
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <nucleus/memory.h>
+#include <nucleus/vfs.h>
+
+/* Get file status */
+int
+stat(const char *pathname, struct stat *statbuf)
+{
+	if (!pathname)
+		return -EFAULT;
+	if (!verify_access(pathname, strnlen(pathname, PATH_MAX), PROT_READ))
+		return -EFAULT;
+	Inode *inode = lookup(pathname, NULL);
+	if (!inode)
+		return -ENOENT;
+	if (!statbuf)
+		goto end;
+	if (!verify_access(statbuf, sizeof(struct stat), PROT_WRITE))
+		return -EFAULT;
+	statbuf->st_dev = inode->dev;
+	statbuf->st_ino = inode->ino;
+	statbuf->st_mode = inode->mode;
+	statbuf->st_nlink = inode->nlink;
+	statbuf->st_uid = inode->uid;
+	statbuf->st_gid = inode->gid;
+	statbuf->st_size = inode->size;
+end:
+	put(inode);
+	return 0;
+}
+
+/* Get file status by file descriptor */
+int
+fstat(int fd, struct stat *statbuf)
+{
+	File *file = get_file_by_fd(fd);
+	if (!file)
+		return -EBADF;
+	Inode *inode = get(file->inode);
+	if (!statbuf)
+		goto end;
+	if (!verify_access(statbuf, sizeof(struct stat), PROT_WRITE))
+		return -EFAULT;
+	statbuf->st_dev = inode->dev;
+	statbuf->st_ino = inode->ino;
+	statbuf->st_mode = inode->mode;
+	statbuf->st_nlink = inode->nlink;
+	statbuf->st_uid = inode->uid;
+	statbuf->st_gid = inode->gid;
+	statbuf->st_size = inode->size;
+end:
+	put(inode);
+	return 0;
+}
diff --git a/vfs/vfs.c b/vfs/vfs.c
index cb80052..9f8bc2b 100644
--- a/vfs/vfs.c
+++ b/vfs/vfs.c
@@ -24,7 +24,7 @@ init_vfs(void)
 	register_fstype("ext2fs", ext2fs_mount);
 
 	mount("tmpfs", NULL, "tmpfs", 0, NULL);
-	mkdir("dev", 0);
+	mkdir("dev", 0755);
 	mount("devfs", "/dev", "devfs", 0, NULL);
 }