1 #include "filesys/inode.h"
6 #include "filesys/filesys.h"
7 #include "threads/malloc.h"
9 /* Number of direct sector pointers in an inode. */
10 #define DIRECT_CNT ((DISK_SECTOR_SIZE - sizeof (off_t) - sizeof (size_t)) \
11 / sizeof (disk_sector_t))
14 It is exactly DISK_SECTOR_SIZE bytes long. */
17 off_t length; /* File size in bytes. */
18 size_t sector_cnt; /* File size in sectors. */
19 disk_sector_t sectors[DIRECT_CNT]; /* Sectors allocated for file. */
22 /* In-memory inode. */
25 list_elem elem; /* Element in inode list. */
26 disk_sector_t sector; /* Sector number of disk location. */
27 int open_cnt; /* Number of openers. */
28 bool removed; /* True if deleted, false otherwise. */
29 struct inode_disk data; /* On-disk data. */
32 /* List of open inodes, so that opening a single inode twice
33 returns the same `struct inode'. */
34 struct list open_inodes;
36 static struct inode *alloc_inode (disk_sector_t);
38 /* Initializes the inode module. */
42 list_init (&open_inodes);
45 /* Allocates sectors from bitmap B for the content of a file
46 whose size is LENGTH bytes, and returns a new `struct inode'
47 properly initialized for the file.
48 It is the caller's responsible to write the inode to disk with
49 inode_commit(), as well as the bitmap.
50 If memory or disk allocation fails, returns a null pointer,
51 leaving bitmap B is unchanged. */
53 inode_create (struct bitmap *b, disk_sector_t sector, off_t length)
61 /* Calculate number of sectors to allocate for file data. */
62 sector_cnt = (length / DISK_SECTOR_SIZE) + (length % DISK_SECTOR_SIZE > 0);
63 if (sector_cnt > DIRECT_CNT)
67 idx = alloc_inode (sector);
71 /* Allocate disk sectors. */
72 idx->data.length = length;
73 while (idx->data.sector_cnt < sector_cnt)
75 size_t sector = bitmap_find_and_set (b);
76 if (sector == BITMAP_ERROR)
79 idx->data.sectors[idx->data.sector_cnt++] = sector;
82 /* Zero out the file contents. */
88 zero_sector = calloc (1, DISK_SECTOR_SIZE);
89 if (zero_sector == NULL)
91 for (i = 0; i < sector_cnt; i++)
92 disk_write (filesys_disk, idx->data.sectors[i], zero_sector);
104 /* Reads an inode from SECTOR
105 and returns a `struct inode' that contains it.
106 Returns a null pointer if memory allocation fails. */
108 inode_open (disk_sector_t sector)
113 /* Check whether this inode is already open. */
114 for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
117 idx = list_entry (e, struct inode, elem);
118 if (idx->sector == sector)
125 /* Allocate inode. */
126 idx = alloc_inode (sector);
130 /* Read from disk. */
131 ASSERT (sizeof idx->data == DISK_SECTOR_SIZE);
132 disk_read (filesys_disk, sector, &idx->data);
137 /* Closes inode IDX and writes it to disk.
138 If this was the last reference to IDX, frees its memory.
139 If IDX was also a removed inode, frees its blocks. */
141 inode_close (struct inode *idx)
146 if (--idx->open_cnt == 0)
150 struct bitmap *free_map;
153 free_map = bitmap_create (disk_size (filesys_disk));
154 if (free_map != NULL)
156 bitmap_read (free_map, free_map_file);
158 bitmap_reset (free_map, idx->sector);
159 for (i = 0; i < idx->data.sector_cnt; i++)
160 bitmap_reset (free_map, idx->data.sectors[i]);
162 bitmap_write (free_map, free_map_file);
163 bitmap_destroy (free_map);
166 printf ("inode_close(): can't free blocks");
168 list_remove (&idx->elem);
173 /* Writes IDX to disk. */
175 inode_commit (const struct inode *idx)
177 ASSERT (idx != NULL);
178 ASSERT (sizeof idx->data == DISK_SECTOR_SIZE);
179 disk_write (filesys_disk, idx->sector, &idx->data);
182 /* Marks IDX to be deleted when it is closed by the last caller who
185 inode_remove (struct inode *idx)
187 ASSERT (idx != NULL);
191 /* Returns the disk sector that contains byte offset POS within
192 the file with inode IDX.
193 Returns -1 if IDX does not contain data for a byte at offset
196 inode_byte_to_sector (const struct inode *idx, off_t pos)
200 ASSERT (idx != NULL);
202 i = pos / DISK_SECTOR_SIZE;
203 return i < idx->data.sector_cnt ? idx->data.sectors[i] : (disk_sector_t) -1;
206 /* Returns the length, in bytes, of the file with inode IDX. */
208 inode_length (const struct inode *idx)
210 ASSERT (idx != NULL);
211 return idx->data.length;
214 /* Prints a representation of IDX to the system console. */
216 inode_print (const struct inode *idx)
220 printf ("Inode %"PRDSNu": %"PRDSNu" bytes, %zd sectors (",
221 idx->sector, idx->data.length, idx->data.sector_cnt);
223 /* This loop could be unsafe for large idx->data.sector_cnt, can
225 for (i = 0; i < idx->data.sector_cnt; i++)
229 printf ("%"PRDSNu, idx->data.sectors[i]);
234 /* Returns a newly allocated and initialized inode. */
235 static struct inode *
236 alloc_inode (disk_sector_t sector)
238 /* Allocate memory. */
239 struct inode *idx = calloc (1, sizeof *idx);
244 list_push_front (&open_inodes, &idx->elem);
245 idx->sector = sector;
247 idx->removed = false;