Project 3 - A Remote File System

Client-Server Interfaces, Spring 2001


Table of Contents

Due Date

This assignment is due on Thursday, 3 May, no later than 2:00 p.m.

See the assignment turn-in page for instructions on turning in your assignment.

The RFS Remote File System

A file is a sequence of zero or more 8-bit bytes. Bytes are indexed as they are in C and C++ arrays: starting from zero and increasing by one for adjacent bytes in the sequence. At any time a file has a length equal to the number of bytes in the sequence. The highest legal index value for a file of length n is n - 1; unlike arrays in C and C++ (and files in Unix), an RFS file cannot be accessed outside the index values [0, n - 1] (except for writes; see below).

The operations permitted on a file are:

rfs::status rfs::open(const string & filename, rfs::flags flags, rfs_id & fid)

Open the file having the name filename. Legal flag values are

rfs::exists_flag - open the named file if it exists; otherwise, do nothing.
rfs::new_flag - create and open the named file if it doesn't exists; otherwise, do nothing.
rfs::read_flag - Open the named file for reading only.
rfs::write_flag - Open the named file for writing only.
If the file is opened successfully, then fid contains a reference to the opened file; otherwise, the contents of fid is undefined.

rfs::status rfs::close(rfs::id fid)

Close the opened file referenced by fid. If the close is successful, the contents of fid is undefined.

rfs::status rfs::write(rfs::id fid, unsigned loc, unsigned cnt, const byte * data)

Starting at the byte pointed to by data, write cnt bytes to the opened file referenced by fid beginning at the byte with index loc. The file index loc may be equal to the file size, in which case the data are appended to the end of the file; otherwise, loc must be in the range [0, n - 1]. If loc + cnt >= n, then the write adds data to the end of the file, as long as loc is a legal value.

A write is atomic over the subsequence of the file involved in the write. If an error occurs, the write leaves the file unchanged.

rfs::status rfs::read(rfs::id fid, unsigned loc, unsigned cnt, byte * data)

Let f be the opened file referenced by fid. Copy the byte values in f referenced by at indices loc through loc + cnt - 1 to the byte addresses starting at the location pointed to by data. Both loc and loc + cnt - 1 must be in the range [0, n - 1], where n is the file size.

A read is atomic over the subsequence of f involved in the read. If an error occurs during a read, the contents of the bytes pointed to by data is undefined.

rfs::status rfs::lock(rfs::id fid, int wait_time, int lock_time)

Let f be the opened file referenced by fid. When lock() returns successfully, the caller has exclusive access to f until the lock is released.

The value wait_time is the number of seconds the caller is willing to wait for the lock; if at least wait_time seconds passes after the call to lock() and the caller still hasn't obtained the lock, lock() returns unsuccessfully. If wait_time is negative, the caller waits indefinitely.

The value lock_time is the number of seconds the caller will hold the the lock once it has been obtained. If at least lock_time seconds passes after lock() successfully returned to the and the caller still hasn't unlocked f, the file is unlocked automatically. If lock_time is negative, the caller locks f indefinitely.

rfs::status rfs::unlock(rfs::id fid)

Unlock the opened, locked file referenced by fid. It is not an error to unlock a file that's automatically been unlocked; it is, however, an error to unlock a file that's not been locked by the caller.

The Project

Implement a version of the RFS that supports location independence. The only thing a client should need to know to access files on an RFS server is the address of the server.

If the client doesn't specify a server address, your implementation should use a default address. The default address can be hardwired, but should also be configured by the environment variable rfs_server_address (note case). The format of a server address is

server-ip-address server-port-number
A client specifies a RFS server address by adding it as a prefix to the name of a file being opened, along with an at-sign character @ to separate the server address from the file name:
server-ip-address server-port-number@filename

Your implementation should include both the client-side routines described above and the server-side CGI programs needed to provide the RFS operations. You must use HTTP as the RFS transport layer; your client-server communication techniques are restricted to the four transfer mechanisms we covered in class:

1. Get
2. Post
3. Content-Type headers
4. Other headers
You can use these four mechanisms however you like (assuming it doesn't choke the HTTP server or CGI programs).

You may implement the client and server side using whatever languages and techniques you feel best, as long as they are or can be easily installed on Unix (VisualBasic is still out). If you're not going to use C or C++ you should let me know as soon as you can so I can figure out how to deal with it and let you know if it's acceptable.

There's a simple, CGI-capable server available in /export/opt/cs-537/p3/thttpd. You are not required to use it, but it's the server I'll be using to test your code. Thttpd doesn't yet support the other headers feature for CGI programs; I'll be modifying it soon so it does, but if you can't wait you can use other servers, such as Apache.

It's not an absolute requirement that you solve the server side of this problem using CGI; however, if you want to use something else we'll have to talk about it first. If this is something you're contemplating, you should probably do it sooner rather than later.

Your implementation of the RFS need not be inter-operable with some other implementation of the RFS.


This page last modified on 5 April 2001.