BarryServer : Git

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

// Related

Nucleus

Barry New list iteration in VFS f97b909 (3 years, 3 months ago)
diff --git a/vfs/file.c b/vfs/file.c
index f73c8e1..0d0f31d 100644
--- a/vfs/file.c
+++ b/vfs/file.c
@@ -7,17 +7,21 @@
  * generic version.
  */
 
+#include <string.h>
+#include <sys/stat.h>
 #include <errno.h>
 #include <nucleus/object.h>
 #include <nucleus/vfs.h>
 
 static void file_delete(Object *);
+static void file_copy(Object *, Object *);
 
 /* File object type */
 ObjectType fileType = {
 	.name = "FILE",
 	.size = sizeof(File),
 	.delete = file_delete,
+	.copy = file_copy,
 };
 
 /* Destroy a file */
@@ -31,6 +35,20 @@ file_delete(Object *obj)
 		destroy_list(file->path);
 }
 
+/* Copy a file */
+static void
+file_copy(Object *a, Object *b)
+{
+	File *parent = (void *) a, *child = (void *) b;
+	if (parent->inode)
+		child->inode = copy(parent->inode);
+	child->flags = parent->flags;
+	child->pos = parent->pos;
+	child->ops = parent->ops;
+	if (parent->path)
+		child->path = copy_list(parent->path);
+}
+
 /* Open a file */
 int
 file_open(File *file)
@@ -45,10 +63,43 @@ size_t
 file_read(File *file, char *buf, size_t size)
 {
 	size_t count = 0;
-	if (!file->ops || !file->ops->read)
-		return count;
-	count = file->ops->read(file, buf, size, file->pos);
+	lock(file);
+	/* Irregular files cannot be cached */
+	if (!S_ISREG(file->inode->mode)) {
+		if (file->ops && file->ops->read)
+			count = file->ops->read(file, buf, size, file->pos);
+		goto end;
+	}
+
+	if (file->pos > file->inode->size)
+		goto end;
+	if (file->pos + size > file->inode->size)
+		size = file->inode->size - file->pos;
+
+	/* Read with cache */
+	Page *page;
+	char *data;
+	uint16_t min, indent = file->pos % PAGE_SIZE;
+	while (size) {
+		min = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+		page = find_page(file->inode->pages,
+		                 file->pos + (count % PAGE_SIZE));
+		if (page) {
+			/* Cache hit */
+			data = map_page(page);
+			memcpy(buf + count, data + indent, min);
+		} else if (file->ops && file->ops->read) {
+			/* Cache miss */
+			file->ops->read(file, buf + count, min,
+			                file->pos + count);
+		}
+		indent = 0;
+		size -= min;
+		count += min;
+	}
+end:
 	file->pos += count;
+	unlock(file);
 	return count;
 }
 
@@ -57,9 +108,52 @@ size_t
 file_write(File *file, char *buf, size_t size)
 {
 	size_t count = 0;
-	if (!file->ops || !file->ops->write)
-		return count;
-	count = file->ops->write(file, buf, size, file->pos);
+	lock(file);
+	/* Irregular files cannot be cached */
+	if (!S_ISREG(file->inode->mode)) {
+		if (file->ops && file->ops->write)
+			count = file->ops->write(file, buf, size, file->pos);
+		goto end;
+	}
+
+	if (file->pos + size > file->inode->size)
+		file->inode->size = size + file->pos;
+
+	/* Write with cache */
+	Page *page;
+	char *data;
+	uint16_t min, indent = file->pos % PAGE_SIZE;
+	while (size) {
+		min = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+		page = find_page(file->inode->pages,
+		                 file->pos + (count % PAGE_SIZE));
+		if (page) {
+			/* Cache hit */
+			data = map_page(page);
+			memcpy(data + indent, buf + count, min);
+		} else if (file->ops && file->ops->write) {
+			/* Cache miss */
+			file->ops->read(file, buf + count, min,
+			                file->pos + count);
+		}
+		indent = 0;
+		size -= min;
+		count += min;
+	}
+end:
 	file->pos += count;
+	unlock(file);
 	return count;
 }
+
+/* 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)
+		file->ops->mmap(file, addr, len, offset);
+	else if (S_ISREG(file->inode->mode))
+		file->ops->read(file, addr, len, offset);
+}