provided code
This commit is contained in:
187
src/filesys/file.c
Normal file
187
src/filesys/file.c
Normal file
@@ -0,0 +1,187 @@
|
||||
#include "filesys/file.h"
|
||||
#include <debug.h>
|
||||
#include "filesys/inode.h"
|
||||
#include "threads/malloc.h"
|
||||
#include <hash.h>
|
||||
|
||||
/* An open file. */
|
||||
struct file
|
||||
{
|
||||
struct inode *inode; /* File's inode. */
|
||||
off_t pos; /* Current position. */
|
||||
bool deny_write; /* Has file_deny_write() been called? */
|
||||
};
|
||||
|
||||
/* Opens a file for the given INODE, of which it takes ownership,
|
||||
and returns the new file. Returns a null pointer if an
|
||||
allocation fails or if INODE is null. */
|
||||
struct file *
|
||||
file_open (struct inode *inode)
|
||||
{
|
||||
struct file *file = calloc (1, sizeof *file);
|
||||
if (inode != NULL && file != NULL)
|
||||
{
|
||||
file->inode = inode;
|
||||
file->pos = 0;
|
||||
file->deny_write = false;
|
||||
return file;
|
||||
}
|
||||
else
|
||||
{
|
||||
inode_close (inode);
|
||||
free (file);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Opens and returns a new file for the same inode as FILE.
|
||||
Returns a null pointer if unsuccessful. */
|
||||
struct file *
|
||||
file_reopen (struct file *file)
|
||||
{
|
||||
return file_open (inode_reopen (file->inode));
|
||||
}
|
||||
|
||||
/* Closes FILE. */
|
||||
void
|
||||
file_close (struct file *file)
|
||||
{
|
||||
if (file != NULL)
|
||||
{
|
||||
file_allow_write (file);
|
||||
inode_close (file->inode);
|
||||
free (file);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the inode encapsulated by FILE. */
|
||||
struct inode *
|
||||
file_get_inode (struct file *file)
|
||||
{
|
||||
return file->inode;
|
||||
}
|
||||
|
||||
/* Reads SIZE bytes from FILE into BUFFER,
|
||||
starting at the file's current position.
|
||||
Returns the number of bytes actually read,
|
||||
which may be less than SIZE if end of file is reached.
|
||||
Advances FILE's position by the number of bytes read. */
|
||||
off_t
|
||||
file_read (struct file *file, void *buffer, off_t size)
|
||||
{
|
||||
off_t bytes_read = inode_read_at (file->inode, buffer, size, file->pos);
|
||||
file->pos += bytes_read;
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
/* Reads SIZE bytes from FILE into BUFFER,
|
||||
starting at offset FILE_OFS in the file.
|
||||
Returns the number of bytes actually read,
|
||||
which may be less than SIZE if end of file is reached.
|
||||
The file's current position is unaffected. */
|
||||
off_t
|
||||
file_read_at (struct file *file, void *buffer, off_t size, off_t file_ofs)
|
||||
{
|
||||
return inode_read_at (file->inode, buffer, size, file_ofs);
|
||||
}
|
||||
|
||||
/* Writes SIZE bytes from BUFFER into FILE,
|
||||
starting at the file's current position.
|
||||
Returns the number of bytes actually written,
|
||||
which may be less than SIZE if end of file is reached.
|
||||
(Normally we'd grow the file in that case, but file growth is
|
||||
not yet implemented.)
|
||||
Advances FILE's position by the number of bytes read. */
|
||||
off_t
|
||||
file_write (struct file *file, const void *buffer, off_t size)
|
||||
{
|
||||
off_t bytes_written = inode_write_at (file->inode, buffer, size, file->pos);
|
||||
file->pos += bytes_written;
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
/* Writes SIZE bytes from BUFFER into FILE,
|
||||
starting at offset FILE_OFS in the file.
|
||||
Returns the number of bytes actually written,
|
||||
which may be less than SIZE if end of file is reached.
|
||||
(Normally we'd grow the file in that case, but file growth is
|
||||
not yet implemented.)
|
||||
The file's current position is unaffected. */
|
||||
off_t
|
||||
file_write_at (struct file *file, const void *buffer, off_t size,
|
||||
off_t file_ofs)
|
||||
{
|
||||
return inode_write_at (file->inode, buffer, size, file_ofs);
|
||||
}
|
||||
|
||||
/* Prevents write operations on FILE's underlying inode
|
||||
until file_allow_write() is called or FILE is closed. */
|
||||
void
|
||||
file_deny_write (struct file *file)
|
||||
{
|
||||
ASSERT (file != NULL);
|
||||
if (!file->deny_write)
|
||||
{
|
||||
file->deny_write = true;
|
||||
inode_deny_write (file->inode);
|
||||
}
|
||||
}
|
||||
|
||||
/* Re-enables write operations on FILE's underlying inode.
|
||||
(Writes might still be denied by some other file that has the
|
||||
same inode open.) */
|
||||
void
|
||||
file_allow_write (struct file *file)
|
||||
{
|
||||
ASSERT (file != NULL);
|
||||
if (file->deny_write)
|
||||
{
|
||||
file->deny_write = false;
|
||||
inode_allow_write (file->inode);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the size of FILE in bytes. */
|
||||
off_t
|
||||
file_length (struct file *file)
|
||||
{
|
||||
ASSERT (file != NULL);
|
||||
return inode_length (file->inode);
|
||||
}
|
||||
|
||||
/* Sets the current position in FILE to NEW_POS bytes from the
|
||||
start of the file. */
|
||||
void
|
||||
file_seek (struct file *file, off_t new_pos)
|
||||
{
|
||||
ASSERT (file != NULL);
|
||||
ASSERT (new_pos >= 0);
|
||||
file->pos = new_pos;
|
||||
}
|
||||
|
||||
/* Returns the current position in FILE as a byte offset from the
|
||||
start of the file. */
|
||||
off_t
|
||||
file_tell (struct file *file)
|
||||
{
|
||||
ASSERT (file != NULL);
|
||||
return file->pos;
|
||||
}
|
||||
|
||||
/* Checks if two file structs are referencing the same underlying file */
|
||||
bool
|
||||
file_compare (struct file *file1, struct file *file2)
|
||||
{
|
||||
ASSERT (file1 != NULL);
|
||||
ASSERT (file2 != NULL);
|
||||
|
||||
return file_get_inode(file1) == file_get_inode(file2);
|
||||
}
|
||||
|
||||
/* Hashing function for files in terms of their underlying inodes */
|
||||
unsigned
|
||||
file_hash (struct file *file)
|
||||
{
|
||||
ASSERT (file != NULL);
|
||||
return hash_ptr(file_get_inode(file));
|
||||
}
|
||||
Reference in New Issue
Block a user