Make tests public. Rewrite most tests. Add tests.
[pintos-anon] / src / filesys / file.c
1 #include "filesys/file.h"
2 #include <debug.h>
3 #include "filesys/inode.h"
4 #include "threads/malloc.h"
5
6 /* An open file. */
7 struct file 
8   {
9     struct inode *inode;        /* File's inode. */
10     off_t pos;                  /* Current position. */
11     bool deny_write;            /* Has file_deny_write() been called? */
12   };
13
14 /* Opens a file for the given INODE, of which it takes ownership,
15    and returns the new file.  Returns a null pointer if an
16    allocation fails or if INODE is null. */
17 struct file *
18 file_open (struct inode *inode) 
19 {
20   struct file *file = calloc (1, sizeof *file);
21   if (inode != NULL && file != NULL)
22     {
23       file->inode = inode;
24       file->pos = 0;
25       file->deny_write = false;
26       return file;
27     }
28   else
29     {
30       inode_close (inode);
31       free (file);
32       return NULL; 
33     }
34 }
35
36 /* Opens and returns a new file for the same inode as FILE.
37    Returns a null pointer if unsuccessful. */
38 struct file *
39 file_reopen (struct file *file) 
40 {
41   return file_open (inode_reopen (file->inode));
42 }
43
44 /* Closes FILE. */
45 void
46 file_close (struct file *file) 
47 {
48   if (file != NULL)
49     {
50       file_allow_write (file);
51       inode_close (file->inode);
52       free (file); 
53     }
54 }
55
56 /* Reads SIZE bytes from FILE into BUFFER,
57    starting at the file's current position.
58    Returns the number of bytes actually read,
59    which may be less than SIZE if end of file is reached.
60    Advances FILE's position by the number of bytes read. */
61 off_t
62 file_read (struct file *file, void *buffer, off_t size) 
63 {
64   off_t bytes_read = inode_read_at (file->inode, buffer, size, file->pos);
65   file->pos += bytes_read;
66   return bytes_read;
67 }
68
69 /* Reads SIZE bytes from FILE into BUFFER,
70    starting at offset FILE_OFS in the file.
71    Returns the number of bytes actually read,
72    which may be less than SIZE if end of file is reached.
73    The file's current position is unaffected. */
74 off_t
75 file_read_at (struct file *file, void *buffer, off_t size, off_t file_ofs) 
76 {
77   return inode_read_at (file->inode, buffer, size, file_ofs);
78 }
79
80 /* Writes SIZE bytes from BUFFER into FILE,
81    starting at the file's current position.
82    Returns the number of bytes actually written,
83    which may be less than SIZE if end of file is reached.
84    (Normally we'd grow the file in that case, but file growth is
85    not yet implemented.)
86    Advances FILE's position by the number of bytes read. */
87 off_t
88 file_write (struct file *file, const void *buffer, off_t size) 
89 {
90   off_t bytes_written = inode_write_at (file->inode, buffer, size, file->pos);
91   file->pos += bytes_written;
92   return bytes_written;
93 }
94
95 /* Writes SIZE bytes from BUFFER into FILE,
96    starting at offset FILE_OFS in the file.
97    Returns the number of bytes actually written,
98    which may be less than SIZE if end of file is reached.
99    (Normally we'd grow the file in that case, but file growth is
100    not yet implemented.)
101    The file's current position is unaffected. */
102 off_t
103 file_write_at (struct file *file, const void *buffer, off_t size,
104                off_t file_ofs) 
105 {
106   return inode_write_at (file->inode, buffer, size, file_ofs);
107 }
108
109 /* Prevents write operations on FILE's underlying inode
110    until file_allow_write() is called or FILE is closed. */
111 void
112 file_deny_write (struct file *file) 
113 {
114   ASSERT (file != NULL);
115   if (!file->deny_write) 
116     {
117       file->deny_write = true;
118       inode_deny_write (file->inode);
119     }
120 }
121
122 /* Re-enables write operations on FILE's underlying inode.
123    (Writes might still be denied by some other file that has the
124    same inode open.) */
125 void
126 file_allow_write (struct file *file) 
127 {
128   ASSERT (file != NULL);
129   if (file->deny_write) 
130     {
131       file->deny_write = false;
132       inode_allow_write (file->inode);
133     }
134 }
135
136 /* Returns the size of FILE in bytes. */
137 off_t
138 file_length (struct file *file) 
139 {
140   ASSERT (file != NULL);
141   return inode_length (file->inode);
142 }
143
144 /* Sets the current position in FILE to NEW_POS bytes from the
145    start of the file. */
146 void
147 file_seek (struct file *file, off_t new_pos)
148 {
149   ASSERT (file != NULL);
150   ASSERT (new_pos >= 0);
151   file->pos = new_pos;
152 }
153
154 /* Returns the current position in FILE as a byte offset from the
155    start of the file. */
156 off_t
157 file_tell (struct file *file) 
158 {
159   ASSERT (file != NULL);
160   return file->pos;
161 }