BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / 1628fcfdfdf2978ed9ccac96ee7d13bb3dc43a01 / vfs / file.c

// Related

Orion

Barry Adding pipes e59e4fe (2 years, 4 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);
}