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);
+}