Write a set of C functions to implement a simple file manager.
A file is to appear to the user as a symbolically-named, variable-length, linearly-addressed sequence of bytes. A read or write operation moves a given number of bytes between a file and the user's address space. A file pointer is internally maintained and indicates the place in the file at which all data transfers begin.
Before a read or write operation may be performed, a logical connection must be established between the process and the file. This is known as "opening" the file; the breaking of the connection is called "closing" the file.
The user must be insulated from the details of the implementation of files. Files are stored in not-necessarily contiguous sectors of a disk. Accessing a disk is orders of magnitude slower than accessing main memory. Therefore, it is necessary to transfer some minimum amount of data (such as one sector) between main memory and disk for each disk access. By storing this minimum amount of data in a buffer, many read and write operations will not require an access to disk.
All disks contain 128 sectors and all sectors are 256 bytes.
The file manager supports a single file system per disk and only one file system at a time can be active. The file manager should maintain a single directory for each file system, which will contain information about the files stored in the system. The file manager should maintain the following information for every file in a file system:
The symbolic name is a null-terminated string of ASCII characters. The length of the string (not counting the NULL) is from 0 to 31 characters. Any ASCII character can be in the string (except a NULL).
The file size should be the size of the file in bytes. Since disks have 128 sectors of 256 bytes, the largest file size is 32768 or less. Therefore the file size will fit in a 16-bit integer. On the disk this 16-bit integer should be stored in Big-Endian format.
The physical location of the file is the ordered list of sectors that contain the file. Since disks have 128 sectors, the sector numbers can be stored in an 8-bit integer.
Sector 0 of the disk is reserved to hold control information for the file system. In particular, it should hold a vector of 128 bytes, one per sector. This vector is known as the sector map. If a byte contains 0, then the corresponding sector is free (not being used to store either user-file data or file-system control data). If a byte contains 1, then the corresponding sector is in use to store either user-file data or file-system control data.
The sector map should be stored in the first 128 bytes of sector 0. Each byte in the second 128 bytes should always contain the value 1.
The beginning of the directory should be stored in sector 1.
A directory is a sequence of directory entries. An entry is of arbitrary length and contains the following fields in the following order:
The first directory entry should describe the directory itself. The filename field is unused but should contain an empty string. The file size field should contain the directory size. The first sequence number should be 1. Therefore the directory entry for the directory itself should always be at least six bytes long.
Directory entries for newly created files are always added at the end of the directory. When a file is deleted, the directory is compressed: the entries following the deleted entry are moved up toward the front of the directory and directory length is decreased. (Note: this might free a sector, causing the sector map to be modified.) When a file adds a data sector, and the file's directory entry must be extended, the following directory entries are moved down one byte and the file length is increased by 1. (Note: this might require a sector to be allocated and added to the directory's sector sequence, thus causing both the sector map and the directory's directory entry to be modified.)
Only data for a single file will be stored in an individual sector. That is, a single sector will never contain data from two files (or from the directory and a file). This allows the simple sector map approach described above, but has the disadvantage that there will often be wasted space in the last sector of a file (or the last sector of the directory).
When searching for free sectors (to use either for user files or for the directory), the file manager should always choose the smallest numbered free sector. That is, search the sector map starting with sector 0. (Well, sector 2 actually, since sectors 0 and 1 will always be in use.)
When a new file is created, it is initially empty, which means its length is 0 and its sector sequence is empty. (That is, no data sector is initially allocated for a newly created file.)
When writing to a file, no new data sector is allocated until data is written "off the end" of the last data sector. The allocation of a new data sector requires that the file's directory be extended, which may also require a sector be allocated. The sector for the directory should be allocated after the data sector is allocated.
If a sector needs to be allocated (either because the directory is being extended or a file is being extended) but all sectors are in use, then the primitive (either createFile or writeFile) that is trying to allocate the sector should return the failure code (-1). The exact state of the file system after such an error is implementation defined.
The file manager will also have to maintain in memory a table of open files. Allow a maximum of 10 simultaneously open files. This table will contain the location of the buffer for the file, what mode the file was opened for, the current file position (also known as the file pointer), and possibly other information. The file descriptor used by many of the file-system primitives is an index into this table.
Only one data sector for each open file, one sector of the directory and sector 0 may be buffered in memory. In addition you may keep the directory entry for an open file in memory. Nothing else from the disk should be buffered in memory.
You should try to minimize the number of disk operations. A disk sector that is buffered in memory should only be written back to disk if the sector has been modified since it was loaded into memory.
The following functions will provide the entry points to the file manager:
The file manager will interface to a disk by means of a disk device driver function:
Each file system entry function will be worth 10 points.
The device driver function and some simple tests will be available in ~cs611/public/prog7. Additional hidden tests may be used as well.
Your implementation should be performed using C. Put all your C code in the fs.c file.
Your program will be graded primarily by testing it for correct functionality. However, you may lose points if your program is not properly structured or adequately documented.
Your assignment should be submitted for grading from a
CIS Linux machine (e.g. turing.unh.edu).
Submit a single file, fs.c.
To turn in this assignment, type:
~cs611/bin/submit prog7 fs.c
Do not turn in any other files!
Submissions can be checked by typing:
~cs611/bin/scheck prog7
To receive full credit for the assignment, you must turn in your files prior to 8am on Monday December 15. Late submissions will be accepted at the penalty of 5 points per day up to 8am on Friday December 19. No submissions will be accepted after 8am on Friday December 19!
Your programs will be graded using an CIS Linux machine (e.g. turing.unh.edu) so be sure to test in that environment.
Remember: as always you are expected to do your own work on this assignment.
Comments and questions should be directed to hatcher@unh.edu