Friday, May 11, 2003 at 1:00 am.
There will be no extensions on the due date for this project
The new version is available in ~cs537-1/public/project5/FileTester.java.
out.printf("\\%03o", Integer.toString(b, 8));It should be
out.printf("\\%03o", b);A corrected version is available in ~cs537-1/public/project5/FileTester.java.
cd ~/private mkdir p5 cd p5 cp ~cs537-1/public/project5/* . makeThe following documentation has been revised as follows:
FastDisk.java differs from Disk.java in that it has a buffer cache and elevator scheduling algorithm built in. (Actually, that's a lie. It just doesn't simulate any delays, but you can pretend that it has buffering and scheduling built in.) The methods beginRead and beginWrite of Disk.java have been replaced by new methods read and write that perform the operation so quickly that when they return, the operation is complete. There is no need to do any buffering or scheduling of your own, and no need to deal with disk interrupts.
Although the new disk is fast, it is not very big. All block numbers are
represented as short integers, so the largest possible disk has
32,767 blocks (16 megabytes, if BLOCK_SIZE is 512).
File System API
This filesystem will allow users to read, write, create, and delete
files on disk.
Because the disk is so small (and to make your life easier), each file,
symlink, or directory is just one block long!
There is a tree-structured directory system and symbolic links,
just like in Unix, but unlike Unix there are no “hard” links.
Files are identified by pathnames, which are readable character strings
possibly containing slashes (/).
If p is a pathname, we use the notation prefix(p) to mean the
part of p up to the last slash in p (or “.”
if p does not contain any slashes).
There is a current working directory (cwd).
Unlike Unix, which has a cwd for each process, there is just one cwd that
applies to all system calls.
Pathnames that start with a slash are absolute pathnames;
they are resolved relative to the root directory.
Pathnames that do not start with a slash are resolved relative to the
current working directory.
On startup, the cwd is the root directory.
You must implement the 11 system calls format, chdir, create, read, write, delete, mkdir, rmdir, symlink, readlink, and readdir, described below.
Each of these system calls returns 0 for success and -1 if there is an error. For debugging purposes, you many want to print an error message before returning -1.
IMPORTANT: You do not have to worry about race conditions for this project. You may assume there is just one instance of FileTester running, doing one kernel operation at a time. You had enough problems dealing with race conditions on projects 2, 3, and 4.The first few block of the disk contain a free map, which is a big array of bits, with one bit for each block on the disk. The bit is 1 if the block is currently allocated and 0 if it is free (available for allocation). The blocks of the free map itself are always marked as “allocated”. Each remaining block is marked “allocated” if and only if contains a directory, symlink, or ordinary file. There are 8 bits in a byte, so the map will need diskSize/8 bytes, or diskSize/(8*BLOCK_SIZE) blocks, where this value needs to be rounded up to the nearest integer value. For example, with BLOCK_SIZE == 512 and diskSize == 10000, 10000/(8*512) = 2.44..., so three blocks will be required:
byte[] freeMap = new byte[3 * BLOCK_SIZE];Within each byte, bits are numbered from low to high, so the low-order bit of freeMap[0] describes the state of block 0, the next lowest-order bit describes block 1, and so on. In general, block i of the disk is free (unused) if and only if
((freeMap[i/8] >> (i % 8)) & 1) == 0
The rest of the blocks on the disk may be allocated to hold directories, symlinks, or ordinary files. The fact that a block is allocated is indicated by the free map, but the kind of file it holds can only be determined by its position in the directory tree. The allocated blocks are organized as a tree. Internal nodes are directories, and the leaves are symlinks and ordinary files. The root directory is the first block following the free map.
A directory consists of a sequence of 16-byte entries. Each entry contains a two-byte block number, a one-byte type flag and a thirteen-byte name. The block number is calcuated by the formula
b = ((b0 & 0xff) << 8) + (b1 & 0xff),where b0 and b1 are the first two bytes in the entry. We say that the entry “points to” block b. If b == 0 the entry is unused. The third byte of the entry indicates the type of block b: ‘O’ means “orinary file”, ‘D’ means “directory”, and ‘L’ means “symlink”. The remaining bytes hold the name of the entry, one character per byte. If the name is less than 13 characters long, it is padded with trailing null bytes (bytes with the value 0, not '0' characters). Each directory contains two entries with the names “.” and “..”, which point to the directory itself and the directory's parent in the directory tree. (As a special case, “..” in the root directory points to the root directory). If these are the only allocated entries in the directory, we say the directory is “empty”. With the exception of the root directory block, each allocated block on disk should be pointed to by exactly one directory entry other than “.” or “..”. In other words, this file system does not support “hard links”.
A symlink contains a pathname, with one character per byte. If the the length of the pathname is less than BLOCK_SIZE, it is padded with null bytes. An “ordinary” file contains “user” data. When it is created, it is filled with null bytes. Otherwise, the kernel should make no assumptions about its contents.
Disk routines only work on arrays of bytes. In order to read and write directories and symlinks, you'll have to convert shorts and Strings to bytes, and vice versa. You should write some functions to perform these conversion, because you will do them many times. Here is some code to get you started.
/** Store a 16-bit integer into a byte array. * @param n the integer to be stored * @param buf the byte array into which it should be stored * @param offset the index of the first byte to be modified */ static void pack(short n, byte[] buf, int offset) { buf[offset] = (byte)(n >> 8); buf[offset+1] = (byte)n; } /** Convert a field in a byte array to an integer. * @param buf the byte array containing the data. * @param offset the location in the array where the data starts. * @return the short integer value. */ static short unpackShort(byte[] buf, int offset) { return (short) (((buf[offset] & 0xff) << 8) + (buf[offset+1] & 0xff)); }To convert between byte arrays and Strings, use the String constructor String(byte[] bytes, int offset, int length) and the method String.getBytes(). When converting from bytes to Strings, be careful not to include any trailing null bytes used for padding.
The Shell of project 4 is replaced in this project with a program called FileTester, which is a command interpreter specifically designed for testing your file system. This program is meant to be specified as the “shell” to the Kernel by typing
java Boot cacheSize FastDisk size FileTesterwhere size is the size of the simulated disk, in blocks, and cacheSize is any integer (it is ignored for this project). For example, you might try
java Boot 1 FastDisk 100 FileTesterIf a (Unix) file named DISK exists in the current directory, it should be the result of any earlier run with the same size parameter. Otherwise, a new DISK will be created. The first block will be filled with null bytes, and the rest will contain random data. In this case, you should be careful that the first command you type is format.
You can also run the program to take its commands from a script, as in
java Boot 1 FastDisk 100 FileTester test1.scriptInput lines starting with “/*” or “//” are ignored (the latter are echoed to the output). Other lines have the format
command [ args ]Most of the commands correspond to system calls. Type “help” for a list. By longstanding tradition, some of the commands have slightly different names from the methods they call
There are also a few special cases.
command method rm delete cd chdir ln symlink
private short namei(short start, String[] path)to simplify walking the directory tree. This method takes a starting point in the file-system tree (as the block number of a directory) and walks through the file system following the path indicated by the strings in path. The resulting value is a “pointer” to the end of the path.
Copyright © 1996-2007 by Marvin Solomon.