CS611
Programming Assignment 6
Fall 2000


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.

The file manager supports a group of file systems, one per disk. 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 1-9 characters, followed by a period (.), followed by 1-3 characters (the file type, or "extension"). The valid characters in file names are A through Z, a through z, and 0 through 9.

The file size should be the size of the file in bytes. Assuming a fixed-sized sector, the size of the file in sectors can be computed from the size in bytes. The file manager should be capable of handling files sizes from 0 to 4,294,967,295.

The physical location of the file is the ordered list of sectors that contain the file. Assume that a disk has a maximum of 65,536 sectors.

Besides the data that makes up the files, and the above information associated with each file, the file manager will have to maintain the following data:

The following functions will provide the entry points to the file manager:

  1. int createFS(int sectorSize, int sectorCount, DISK disk): Creates a new file system on the given disk with the given sector size and total number of sectors. Returns 1 if successful and 0 if not. (Note: You may assume the sector size will always be 256. That is, for grading purposes the tests will always use a sector size of 256.)

  2. int bootFS(DISK disk): Opens an existing file system on the given disk. Returns 1 if successful and 0 if not. Only one file system at a time can be "booted". That is, it is an error if a second file system is booted without first shutting down the file system that was booted earlier.

  3. int shutdownFS(DISK disk): Closes an existing file system on the given disk. Any persistent data structures must be written to the disk so that the system can be booted at a later time. Returns 1 if successful and 0 if not. It is an error if the user attempts to shutdown a file system with open files.

  4. int openFile(char* name, int mode, DISK disk): Opens the named file on the given disk for the given mode and assigns a file descriptor (fd) to it. The mode must be either READ_MODE, WRITE_MODE or UPDATE_MODE. (UPDATE_MODE means that both reading and writing is allowed.) The file pointer for the file is set to the beginning of the file. If successful, it returns the fd; else it returns -1. To be successful, the file must exist and must not already be open.

  5. int createFile(char* name, int mode, DISK disk): Same as openFile except, if the file exists, it scratches it; and it will create the file if it doesn't already exist. It is an error if the file is already open.

  6. int closeFile(int fd): Closes the file with the given fd. If successful, it returns the fd; else it returns -1.

  7. int readFile(int fd, char* buf, int size): Reads up to size characters from the file specified by the fd into the given buffer. The file pointer is advanced by the amount of data read. If an error occurs, a -1 is returned. If end of file is encountered, read returns zero. Otherwise, the actual number of bytes read is returned. For the read operation to be successful, the file must have been opened with either READ_MODE or UPDATE_MODE.

  8. int writeFile(int fd, char* buf, int size): Writes size characters starting at buf to the file specified by the fd. The file pointer is advanced by the amount of data written. (Data may be written beyond the end of file: the file length is extended.) If an error occurs, -1 is returned. Otherwise, size is returned. For the write operation to be successful, the file must have been opened with either WRITE_MODE or UPDATE_MODE.

  9. int unlinkFile(char* name, DISK disk): Delete the file with the given name from the file system on the given disk. Returns 1 if successful and 0 if not. It is an error to call unlinkFile on an open file.

  10. int lseekFile(int fd, int offset, int sense): Use the given offset to modify the file pointer for the given fd, under control of sense. If sense is equal to 0, the pointer is set to offset, which should be positive. If sense is equal to 1, the offset is added to the current pointer. If successful, it returns the fd; else it returns -1. (An lseek beyond the end of the file is not allowed.)

As you can probably guess, a file descriptor is an index into the table of opened files.

The file manager will interface to a disk by means of a disk device driver function:

The operation must be either READ_SECTOR or WRITE_SECTOR and the given sector is either read into the buffer or the given sector is written from the given buffer. This function does not return anything as any error is fatal, and terminates the program with an error message. This function will be provided to you.

The internal structure of the file manager is entirely up to you. You should give it much thought before starting to code. One of your design objectives should be to make the most efficient use of space (both disk and memory) that you reasonably can. Also, your design should attempt to minimize file access time.

The design of the file system will be worth 50 points. It should be fully documented with a lengthy comment at the top of the file containing your code.

Each file system entry function will be worth 5 points.

The device driver function and some simple tests will be available on alberti in ~cs611/public/prog6.

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 programs should be submitted for grading from a UNH CIS Alpha machine (e.g. alberti.unh.edu). Submit a single file, fs.c. To turn in this assignment, type:
~cs611/bin/submit prog6 fs.c

Submissions can be checked by typing:
~cs611/bin/scheck prog6

To receive full credit for the assignment, you must turn in your files prior to 8am on Monday December 11. Late submissions will be accepted at the penalty of 5% per day up to one week late.

Remember: as always you are expected to do your own work on this assignment.


Last modified on November 27, 2000.

Comments and questions should be directed to pjh@cs.unh.edu