pintos: Avoid literal control character in Perl variable name.
[pintos-anon] / src / filesys / file.c
index e8818c0029383a7d3a0f139963874bf81021dbc2..d5fc10de15004e98d4f8490aa8a7ec8a4c7efcff 100644 (file)
 #include "filesys/file.h"
 #include <debug.h>
-#include <string.h>
-#include "filesys/directory.h"
 #include "filesys/inode.h"
-#include "filesys/filesys.h"
 #include "threads/malloc.h"
 
 /* An open file. */
 struct file 
   {
     struct inode *inode;        /* File's inode. */
-    uint8_t *bounce;            /* Bounce buffer for reads and writes. */
     off_t pos;                  /* Current position. */
+    bool deny_write;            /* Has file_deny_write() been called? */
   };
 
-/* Opens and returns the file whose inode is in sector
-   INODE_SECTOR.  Returns a null pointer if unsuccessful. */
+/* 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 (disk_sector_t inode_sector
+file_open (struct inode *inode
 {
   struct file *file = calloc (1, sizeof *file);
-  if (file == NULL)
-    return NULL;
-  
-  file->inode = inode_open (inode_sector);
-  file->bounce = malloc (DISK_SECTOR_SIZE);
-  file->pos = 0;
-  if (file->inode == NULL || file->bounce == NULL)
+  if (inode != NULL && file != NULL)
     {
-      inode_close (file->inode);
-      free (file->bounce);
-      return NULL;
+      file->inode = inode;
+      file->pos = 0;
+      file->deny_write = false;
+      return file;
+    }
+  else
+    {
+      inode_close (inode);
+      free (file);
+      return NULL; 
     }
+}
 
-  return file;
+/* 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)
-    return;
-  
-  inode_close (file->inode);
-  free (file->bounce);
-  free (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,
-   and advances the current position.
+   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. */
+   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 = file_read_at (file, buffer, size, file->pos);
+  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.
-   The file's current position is unaffected
    Returns the number of bytes actually read,
-   which may be less than SIZE if end of file is reached. */
+   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) 
+file_read_at (struct file *file, void *buffer, off_t size, off_t file_ofs) 
 {
-  uint8_t *buffer = buffer_;
-  off_t bytes_read = 0;
-
-  while (size > 0) 
-    {
-      /* Disk sector to read, starting byte offset within sector. */
-      disk_sector_t sector_idx;
-      int sector_ofs = file_ofs % DISK_SECTOR_SIZE;
-
-      /* Bytes left in file, bytes left in sector, lesser of the two. */
-      off_t file_left = inode_length (file->inode) - file_ofs;
-      int sector_left = DISK_SECTOR_SIZE - sector_ofs;
-      int min_left = file_left < sector_left ? file_left : sector_left;
-
-      /* Number of bytes to actually copy out of this sector. */
-      int chunk_size = size < min_left ? size : min_left;
-      if (chunk_size <= 0)
-        break;
-
-      /* Read sector into bounce buffer, then copy into caller's
-         buffer. */
-      sector_idx = inode_byte_to_sector (file->inode, file_ofs);
-      disk_read (filesys_disk, sector_idx, file->bounce);
-      memcpy (buffer + bytes_read, file->bounce + sector_ofs, chunk_size);
-
-      /* Advance. */
-      size -= chunk_size;
-      file_ofs += chunk_size;
-      bytes_read += chunk_size;
-    }
-
-  return bytes_read;
+  return inode_read_at (file->inode, buffer, size, file_ofs);
 }
 
 /* Writes SIZE bytes from BUFFER into FILE,
-   starting at the file's current position,
-   and advances the current position.
+   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.) */
+   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 = file_write_at (file, buffer, size, file->pos);
+  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.
-   The file's current position is unaffected
    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.) */
+   not yet implemented.)
+   The file's current position is unaffected. */
 off_t
-file_write_at (struct file *file, const void *buffer_, off_t size,
+file_write_at (struct file *file, const void *buffer, off_t size,
                off_t file_ofs) 
 {
-  const uint8_t *buffer = buffer_;
-  off_t bytes_written = 0;
+  return inode_write_at (file->inode, buffer, size, file_ofs);
+}
 
-  while (size > 0) 
+/* 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) 
     {
-      /* Sector to write, starting byte offset within sector. */
-      off_t sector_idx;
-      int sector_ofs = file_ofs % DISK_SECTOR_SIZE;
-
-      /* Bytes left in file, bytes left in sector, lesser of the two. */
-      off_t file_left = inode_length (file->inode) - file_ofs;
-      int sector_left = DISK_SECTOR_SIZE - sector_ofs;
-      int min_left = file_left < sector_left ? file_left : sector_left;
-
-      /* Number of bytes to actually write into this sector. */
-      int chunk_size = size < min_left ? size : min_left;
-      if (chunk_size <= 0)
-        break;
-
-      /* If the sector contains data before or after the chunk
-         we're writing, then we need to read in the sector
-         first.  Otherwise we start with a sector of all zeros. */
-      sector_idx = inode_byte_to_sector (file->inode, file_ofs);
-      if (sector_ofs > 0 || chunk_size < sector_left)
-        disk_read (filesys_disk, sector_idx, file->bounce);
-      else
-        memset (file->bounce, 0, DISK_SECTOR_SIZE);
-      memcpy (file->bounce + sector_ofs, buffer + bytes_written, chunk_size);
-      disk_write (filesys_disk, sector_idx, file->bounce);
-
-      /* Advance. */
-      size -= chunk_size;
-      file_ofs += chunk_size;
-      bytes_written += chunk_size;
+      file->deny_write = true;
+      inode_deny_write (file->inode);
     }
+}
 
-  return bytes_written;
+/* 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. */
@@ -177,14 +148,14 @@ file_length (struct file *file)
   return inode_length (file->inode);
 }
 
-/* Sets the current position in FILE to an offset of FILE_OFS
-   bytes from the start of the file. */
+/* Sets the current position in FILE to NEW_POS bytes from the
+   start of the file. */
 void
-file_seek (struct file *file, off_t file_ofs) 
+file_seek (struct file *file, off_t new_pos)
 {
   ASSERT (file != NULL);
-  ASSERT (file_ofs >= 0);
-  file->pos = file_ofs;
+  ASSERT (new_pos >= 0);
+  file->pos = new_pos;
 }
 
 /* Returns the current position in FILE as a byte offset from the