Orion
Barry Adding pipes e59e4fe (3 years, 2 months ago)
/*
* 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->ops && file->ops->release)
file->ops->release(file);
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);
}