BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / vfs / file.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/vfs/file.c b/vfs/file.c
new file mode 100644
index 0000000..d3dfdc6
--- /dev/null
+++ b/vfs/file.c
@@ -0,0 +1,181 @@
+/*
+ * This file handles the file operations.  Most of the functions here are just
+ * wrapper around the file operations.  They generally check if the operation
+ * exists and use it if it does.  If it doesn't they may implement a generic
+ * action, or just simply return.  They also perform the necessary validation to
+ * ensure the operation can be called on the particular file.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include "vfs.h"
+#include "inode.h"
+#include "cache.h"
+#include "../mem/heap.h"
+#include "../mem/frame.h"
+#include "../screen.h"
+
+/* Get a File */
+File *
+file_get(File *file)
+{
+	file->usage++;
+	return file;
+}
+
+/* Put a File */
+void
+file_put(File *file)
+{
+	ASSERT(file->usage);
+	if (--file->usage)
+		return;
+	if (file->inode)
+		inode_put(file->inode);
+	if (file->path)
+		destroy_custody_chain(file->path);
+	kfree(file);
+}
+
+/* Read a file */
+size_t
+file_read(File *file, char *buf, size_t size)
+{
+	size_t count = 0;
+	if (!S_ISREG(file->inode->mode)) {
+		if (!file->ops)
+			return count;
+		if (!file->ops->read)
+			return count;
+		count = file->ops->read(file, buf, size, file->pos);
+		file->pos += count;
+		return count;
+	}
+	if (file->pos > file->inode->size)
+		return count;
+	if (size + file->pos > file->inode->size)
+		size = file->inode->size - file->pos;
+
+	uint16_t min, offset = file->pos & 0xFFF;
+	Page *page;
+	page_t oldPage;
+	acquire(&file->lock);
+	while (size) {
+		min = (size > 0x1000) ? 0x1000 : size;
+		page = page_find(file->inode, file->pos + (count & ~0xFFF));
+		if (!page) {
+			if (!file->ops)
+				goto end;
+			if (!file->ops->read)
+				goto end;
+			file->ops->read(file, buf + count, min,
+		                        file->pos + count);
+		} else {
+			acquire(&quickPageLock);
+			oldPage = quick_page(page->frame);
+			memcpy(buf + count, QUICK_PAGE + offset, min);
+			quick_page(oldPage);
+			release(&quickPageLock);
+		}
+		offset = 0;
+end:
+		size -= min;
+		count += min;
+	}
+	file->pos += count;
+	release(&file->lock);
+	return count;
+}
+
+/* Write a file */
+size_t
+file_write(File *file, char *buf, size_t size)
+{
+	size_t count = 0;
+	if (!S_ISREG(file->inode->mode)) {
+		if (!file->ops)
+			return count;
+		if (!file->ops->write)
+			return count;
+		count = file->ops->write(file, buf, size, file->pos);
+		file->pos += count;
+		return count;
+	}
+	if (size + file->pos > file->inode->size)
+		file->inode->size = size + file->pos;
+
+	uint16_t min, offset = file->pos & 0xFFF;
+	Page *page;
+	page_t oldPage;
+	acquire(&file->lock);
+	while (size) {
+		min = (size > 0x1000) ? 0x1000 : size;
+		page = page_find(file->inode, file->pos + (count & ~0xFFF));
+		if (!page) {
+			if (!file->ops)
+				goto end;
+			if (!file->ops->write)
+				goto end;
+			file->ops->write(file, buf + count, min,
+			                 file->pos + count);
+		} else {
+			acquire(&quickPageLock);
+			oldPage = quick_page(page->frame);
+			memcpy(QUICK_PAGE + offset, buf + count, min);
+			quick_page(oldPage);
+			release(&quickPageLock);
+		}
+		offset = 0;
+end:
+		size -= min;
+		count += min;
+	}
+	file->pos += count;
+	release(&file->lock);
+	return count;
+}
+
+/* I/O Control */
+int
+file_ioctl(File *file, unsigned long request, uintptr_t argp)
+{
+	if (!file->ops)
+		return -EINVAL;
+	if (!file->ops->ioctl)
+		return -ENOTTY;
+	return file->ops->ioctl(file, request, argp);
+}
+
+/* Read a directory entry (DirEnt) from a directory */
+int
+file_readdir(File *file, DirEnt *dent, off_t index)
+{
+	if (!file->ops)
+		return -EINVAL;
+	if (!file->ops->readdir)
+		return -EINVAL;
+	return file->ops->readdir(file, dent, index);
+}
+
+/* Open a file */
+int
+file_open(File *file)
+{
+	if (!file->ops)
+		return -EINVAL;
+	if (!file->ops->open)
+		return -EINVAL;
+	return file->ops->open(file);
+}
+
+/* Map a file into memory */
+void
+file_mmap(File *file, void *addr, size_t len, off_t offset)
+{
+	if (!file->ops)
+		return;
+	if (file->ops->mmap)
+		return file->ops->mmap(file, addr, len, offset);
+	if (S_ISREG(file->mode))
+		file->ops->read(file, addr, len, offset);
+}