1 #include <inc/string.h>
5 // --------------------------------------------------------------
7 // --------------------------------------------------------------
9 // Validate the file system super-block.
13 if (super
->s_magic
!= FS_MAGIC
)
14 panic("bad file system magic number");
16 if (super
->s_nblocks
> DISKSIZE
/BLKSIZE
)
17 panic("file system is too large");
19 cprintf("superblock is good\n");
22 // --------------------------------------------------------------
24 // --------------------------------------------------------------
26 // Check to see if the block bitmap indicates that block 'blockno' is free.
27 // Return 1 if the block is free, 0 if not.
29 block_is_free(uint32_t blockno
)
31 if (super
== 0 || blockno
>= super
->s_nblocks
)
33 if (bitmap
[blockno
/ 32] & (1 << (blockno
% 32)))
38 // Mark a block free in the bitmap
40 free_block(uint32_t blockno
)
42 // Blockno zero is the null pointer of block numbers.
44 panic("attempt to free zero block");
45 bitmap
[blockno
/32] |= 1<<(blockno
%32);
48 // Search the bitmap for a free block and allocate it. When you
49 // allocate a block, immediately flush the changed bitmap block
52 // Return block number allocated on success,
53 // -E_NO_DISK if we are out of blocks.
55 // Hint: use free_block as an example for manipulating the bitmap.
59 // The bitmap consists of one or more blocks. A single bitmap block
60 // contains the in-use bits for BLKBITSIZE blocks. There are
61 // super->s_nblocks blocks in the disk altogether.
63 // LAB 5: Your code here.
64 panic("alloc_block not implemented");
68 // Validate the file system bitmap.
70 // Check that all reserved blocks -- 0, 1, and the bitmap blocks themselves --
71 // are all marked as in-use.
77 // Make sure all bitmap blocks are marked in-use
78 for (i
= 0; i
* BLKBITSIZE
< super
->s_nblocks
; i
++)
79 assert(!block_is_free(2+i
));
81 // Make sure the reserved and root blocks are marked in-use.
82 assert(!block_is_free(0));
83 assert(!block_is_free(1));
85 cprintf("bitmap is good\n");
88 // --------------------------------------------------------------
89 // File system structures
90 // --------------------------------------------------------------
92 // Initialize the file system
96 static_assert(sizeof(struct File
) == 256);
98 // Find a JOS disk. Use the second IDE disk (number 1) if available.
99 if (ide_probe_disk1())
106 // Set "super" to point to the super block.
108 // Set "bitmap" to the beginning of the first bitmap block.
109 bitmap
= diskaddr(2);
115 // Find the disk block number slot for the 'filebno'th block in file 'f'.
116 // Set '*ppdiskbno' to point to that slot.
117 // The slot will be one of the f->f_direct[] entries,
118 // or an entry in the indirect block.
119 // When 'alloc' is set, this function will allocate an indirect block
123 // 0 on success (but note that *ppdiskbno might equal 0).
124 // -E_NOT_FOUND if the function needed to allocate an indirect block, but
126 // -E_NO_DISK if there's no space on the disk for an indirect block.
127 // -E_INVAL if filebno is out of range (it's >= NDIRECT + NINDIRECT).
129 // Analogy: This is like pgdir_walk for files.
130 // Hint: Don't forget to clear any block you allocate.
132 file_block_walk(struct File
*f
, uint32_t filebno
, uint32_t **ppdiskbno
, bool alloc
)
134 // LAB 5: Your code here.
135 panic("file_block_walk not implemented");
138 // Set *blk to the address in memory where the filebno'th
139 // block of file 'f' would be mapped.
140 // Allocate the block if it doesn't yet exist.
142 // Returns 0 on success, < 0 on error. Errors are:
143 // -E_NO_DISK if a block needed to be allocated but the disk is full.
144 // -E_INVAL if filebno is out of range.
146 // Hint: Use file_block_walk and alloc_block.
148 file_get_block(struct File
*f
, uint32_t filebno
, char **blk
)
150 // LAB 5: Your code here.
151 panic("file_get_block not implemented");
154 // Try to find a file named "name" in dir. If so, set *file to it.
156 // Returns 0 and sets *file on success, < 0 on error. Errors are:
157 // -E_NOT_FOUND if the file is not found
159 dir_lookup(struct File
*dir
, const char *name
, struct File
**file
)
162 uint32_t i
, j
, nblock
;
166 // Search dir for name.
167 // We maintain the invariant that the size of a directory-file
168 // is always a multiple of the file system's block size.
169 assert((dir
->f_size
% BLKSIZE
) == 0);
170 nblock
= dir
->f_size
/ BLKSIZE
;
171 for (i
= 0; i
< nblock
; i
++) {
172 if ((r
= file_get_block(dir
, i
, &blk
)) < 0)
174 f
= (struct File
*) blk
;
175 for (j
= 0; j
< BLKFILES
; j
++)
176 if (strcmp(f
[j
].f_name
, name
) == 0) {
184 // Set *file to point at a free File structure in dir. The caller is
185 // responsible for filling in the File fields.
187 dir_alloc_file(struct File
*dir
, struct File
**file
)
190 uint32_t nblock
, i
, j
;
194 assert((dir
->f_size
% BLKSIZE
) == 0);
195 nblock
= dir
->f_size
/ BLKSIZE
;
196 for (i
= 0; i
< nblock
; i
++) {
197 if ((r
= file_get_block(dir
, i
, &blk
)) < 0)
199 f
= (struct File
*) blk
;
200 for (j
= 0; j
< BLKFILES
; j
++)
201 if (f
[j
].f_name
[0] == '\0') {
206 dir
->f_size
+= BLKSIZE
;
207 if ((r
= file_get_block(dir
, i
, &blk
)) < 0)
209 f
= (struct File
*) blk
;
214 // Skip over slashes.
216 skip_slash(const char *p
)
223 // Evaluate a path name, starting at the root.
224 // On success, set *pf to the file we found
225 // and set *pdir to the directory the file is in.
226 // If we cannot find the file but find the directory
227 // it should be in, set *pdir and copy the final path
228 // element into lastelem.
230 walk_path(const char *path
, struct File
**pdir
, struct File
**pf
, char *lastelem
)
233 char name
[MAXNAMELEN
];
234 struct File
*dir
, *f
;
238 // return -E_BAD_PATH;
239 path
= skip_slash(path
);
247 while (*path
!= '\0') {
250 while (*path
!= '/' && *path
!= '\0')
252 if (path
- p
>= MAXNAMELEN
)
254 memmove(name
, p
, path
- p
);
255 name
[path
- p
] = '\0';
256 path
= skip_slash(path
);
258 if (dir
->f_type
!= FTYPE_DIR
)
261 if ((r
= dir_lookup(dir
, name
, &f
)) < 0) {
262 if (r
== -E_NOT_FOUND
&& *path
== '\0') {
266 strcpy(lastelem
, name
);
279 // --------------------------------------------------------------
281 // --------------------------------------------------------------
283 // Create "path". On success set *pf to point at the file and return 0.
284 // On error return < 0.
286 file_create(const char *path
, struct File
**pf
)
288 char name
[MAXNAMELEN
];
290 struct File
*dir
, *f
;
292 if ((r
= walk_path(path
, &dir
, &f
, name
)) == 0)
293 return -E_FILE_EXISTS
;
294 if (r
!= -E_NOT_FOUND
|| dir
== 0)
296 if ((r
= dir_alloc_file(dir
, &f
)) < 0)
298 strcpy(f
->f_name
, name
);
304 // Open "path". On success set *pf to point at the file and return 0.
305 // On error return < 0.
307 file_open(const char *path
, struct File
**pf
)
309 return walk_path(path
, 0, pf
, 0);
312 // Read count bytes from f into buf, starting from seek position
313 // offset. This meant to mimic the standard pread function.
314 // Returns the number of bytes read, < 0 on error.
316 file_read(struct File
*f
, void *buf
, size_t count
, off_t offset
)
322 if (offset
>= f
->f_size
)
325 count
= MIN(count
, f
->f_size
- offset
);
327 for (pos
= offset
; pos
< offset
+ count
; ) {
328 if ((r
= file_get_block(f
, pos
/ BLKSIZE
, &blk
)) < 0)
330 bn
= MIN(BLKSIZE
- pos
% BLKSIZE
, offset
+ count
- pos
);
331 memmove(buf
, blk
+ pos
% BLKSIZE
, bn
);
339 // Write count bytes from buf into f, starting at seek position
340 // offset. This is meant to mimic the standard pwrite function.
341 // Extends the file if necessary.
342 // Returns the number of bytes written, < 0 on error.
344 file_write(struct File
*f
, const void *buf
, size_t count
, off_t offset
)
350 // Extend file if necessary
351 if (offset
+ count
> f
->f_size
)
352 if ((r
= file_set_size(f
, offset
+ count
)) < 0)
355 for (pos
= offset
; pos
< offset
+ count
; ) {
356 if ((r
= file_get_block(f
, pos
/ BLKSIZE
, &blk
)) < 0)
358 bn
= MIN(BLKSIZE
- pos
% BLKSIZE
, offset
+ count
- pos
);
359 memmove(blk
+ pos
% BLKSIZE
, buf
, bn
);
367 // Remove a block from file f. If it's not there, just silently succeed.
368 // Returns 0 on success, < 0 on error.
370 file_free_block(struct File
*f
, uint32_t filebno
)
375 if ((r
= file_block_walk(f
, filebno
, &ptr
, 0)) < 0)
384 // Remove any blocks currently used by file 'f',
385 // but not necessary for a file of size 'newsize'.
386 // For both the old and new sizes, figure out the number of blocks required,
387 // and then clear the blocks from new_nblocks to old_nblocks.
388 // If the new_nblocks is no more than NDIRECT, and the indirect block has
389 // been allocated (f->f_indirect != 0), then free the indirect block too.
390 // (Remember to clear the f->f_indirect pointer so you'll know
391 // whether it's valid!)
392 // Do not change f->f_size.
394 file_truncate_blocks(struct File
*f
, off_t newsize
)
397 uint32_t bno
, old_nblocks
, new_nblocks
;
399 old_nblocks
= (f
->f_size
+ BLKSIZE
- 1) / BLKSIZE
;
400 new_nblocks
= (newsize
+ BLKSIZE
- 1) / BLKSIZE
;
401 for (bno
= new_nblocks
; bno
< old_nblocks
; bno
++)
402 if ((r
= file_free_block(f
, bno
)) < 0)
403 cprintf("warning: file_free_block: %e", r
);
405 if (new_nblocks
<= NDIRECT
&& f
->f_indirect
) {
406 free_block(f
->f_indirect
);
411 // Set the size of file f, truncating or extending as necessary.
413 file_set_size(struct File
*f
, off_t newsize
)
415 if (f
->f_size
> newsize
)
416 file_truncate_blocks(f
, newsize
);
422 // Flush the contents and metadata of file f out to disk.
423 // Loop over all the blocks in file.
424 // Translate the file block number into a disk block number
425 // and then check whether that disk block is dirty. If so, write it out.
427 file_flush(struct File
*f
)
432 for (i
= 0; i
< (f
->f_size
+ BLKSIZE
- 1) / BLKSIZE
; i
++) {
433 if (file_block_walk(f
, i
, &pdiskbno
, 0) < 0 ||
434 pdiskbno
== NULL
|| *pdiskbno
== 0)
436 flush_block(diskaddr(*pdiskbno
));
440 flush_block(diskaddr(f
->f_indirect
));
443 // Remove a file by truncating it and then zeroing the name.
445 file_remove(const char *path
)
450 if ((r
= walk_path(path
, 0, &f
, 0)) < 0)
453 file_truncate_blocks(f
, 0);
461 // Sync the entire file system. A big hammer.
466 for (i
= 1; i
< super
->s_nblocks
; i
++)
467 flush_block(diskaddr(i
));