FINAL PROJECT

V22.0480-002   Special Topics: Networks
 
Final Project
 
Due Date: Wednesday, May 3

For this assignment, you must implement a "remote file access" application
using RPC.  You should use the default authentication level.
 
You must write 10 procedures, using the .x file specified below.  The
procedures do the following:
 
======================================================================
GETATTR
Takes a filename as an argument, and returns information about that file.
 
LOOKUP
Takes a filename as an argument, and determines if the file exists.  It
returns a Boolean value specifying if the given name is a directory or a file.
 
READ
Takes a filename, an offset, and the number of bytes as arguments.  It
opens the file, seeks to the offset, reads the data, closes the file,
and returns the data.
 
WRITE
Takes a filename, and offset, a count, and data as arguments.  It
opens the file, seeks to the offset, writes the data, and closes the file.
It returns the number of bytes written.
 
CREATE
Takes a filename as an argument and creates the file.
 
REMOVE
Takes a filename as an argument and removes the file.
 
RENAME
Takes two filenames as arguments, and moves the first file to the
second.  If the second file already exits, the routine fails.
 
MKDIR
Takes a directory name as an argument and creates the directory.
 
RMDIR
Takes a directory name as an argument and removes the directory.
The procedure fails if the specified directory is not empty.
 
READDIR
Takes a directory name as an argument.  It returns a linked list of
all elements in that directory.
 
====================================================
 
On the client side, you must write an interactive shell.  The
shell has a concept of the "current directory".  When you start
the shell, the "current directory" is set to ".".  The current
directory is simply a local variable on the client that keeps
track of the logical directory on the server.
 
Your shell must accept the following commands:
 
-------------------------------------
cd
"cd" does not call a remote procedure.  It simply resets the current
directory to ".".
 
-------------------------------------
pwd
"pwd" does not call a remote procedure.  It simply prints the current
directory variable.
 
-------------------------------------
cd dir
"cd dir" calls the LOOKUP procedure.  If dir begins with a /, then
it is passed to the LOOKUP procedure as an argument.  If it does
not start with a /, the operation passes the current directory followed
by a / followed by dir as an argument to LOOKUP.  If LOOKUP says
the argument is a directory, the current directory is set to the
argument passed to LOOKUP.
 
For example, if the current directory is ".", then "cd test" would call
LOOKUP("./test").  If LOOKUP said that "./test" is a directory,
then the client sets the current directory to "./test".
 
Then, if the user entered "cd next", the operation would call
LOOKUP("./test/next") (because "./test" is in the current directory
variable).  If LOOKUP said that "./test/next" is a directory, then
the operation would set the current directory to "./test/next".  If
LOOKUP said that "./test/next" did not exist or was not a directory,
the current directory would remain as "./test" and an error message
would be displayed to the user.
 
Similarly, if the user entered "cd /etc", the operation would call
LOOKUP("/etc").  Because /etc starts with a /, the current directory
is not included in it.  If LOOKUP said that /etc is a directory,
the operation would set the current directory to /etc.
 
-------------------------------------
ls
"ls" calls the READDIR procedure, specifying the current directory
as an argument.  It prints the list returned by READDIR.  For example,
if the current directory is "./x/y/z", the ls command could call
READDIR("./x/y/z").
 
-------------------------------------
ls -l
"ls -l" calls the READDIR procedure, specifying the current directory
as an argument.  Then, for each element of the list returned by
READDIR, it calls GETATTR specifying the current directory followed by
a / followed by the list element.  It displays the information returned
by GETATTR.
 
-------------------------------------
cat file
"cat file" first calls the LOOKUP procedure, specifying the current
directory followed by a / followed by the file.  If the file is
not a directory, it calls GETATTR (with the same argument that
was given to LOOKUP) to get the size of the file. Then, it calls
READ as many times as necessary, displaying the data on each call,
until the entire contents of the file have been displayed.
 
-------------------------------------
mv file1 file2
"mv file1 file2" calls RENAME specifying as arguments the current
directory followed by a / followed by file1 and the current
directory followed by / followed by file2.
 
-------------------------------------
cp file1 file2
"cp file1 file2" first calls the LOOKUP procedure, specifying the
current directory followed by a / followed by file1.  If the file
is a directory the operation fails.  If the file is not a directory,
the operation calls the LOOKUP procedure, specifying the current
directory followed by a / followed by file2.  If file2 is a directory
the operation fails. If file2 exists and is not a directory, the
operation calls REMOVE (specifying the current directory followed
by a / followed by file2) to remove file2.  Next, it calls
GETATTR (with the same argument that was given to the first LOOKUP)
to get the size of the file1.  Then, calls CREATE (with the same
argument that was given to the second LOOKUP) to create file2.
Next, it loops, calling READ to read from file1 and WRITE to write
the data to file2.
 
-------------------------------------
rm file
"rm file" calls the REMOVE function, specifying the current directory
followed by a / followed by the file.
 
-------------------------------------
mkdir dir
"mkdir dir" calls the MKDIR function, specifying the current directory
followed by a / followed by the file.
 
-------------------------------------
rmdir dir
"rmdir dir" calls the RMDIR function, specifying the current directory
followed by a / followed by the file.
 
-------------------------------------
switchto  servername
"switchto servername" does not call a remote procedure.  It stops the
session with the current server and calls clnt_create() to establish
a new session with the specified server.  After establishing the new
session, the current directory is set to ".".
 
-------------------------------------
exit
"exit" ends the shell.
 
 
 
===========================================================
 
Here is an example run:
 
$ myshell courses3
> pwd
.
> ls
abc
dir1
file1
file2
file3
> ls -l
drwxr-xr-x      mpadovan       512  Apr 13 18:34 abc
drwxr-xr-x      mpadovan       512  Apr 13 18:34 dir1
-rw-r--r--      mpadovan         30 Apr 13 18:34 file1
-rw-r--r--      mpadovan         80 Apr 13 18:34 file2
-rw-r--r--      mpadovan         27 Apr 13 18:35 file3
> cd file1
error: file1 is not a directory
> cd abc
> pwd
./abc
> ls
fileone
> cat fileone
Have a nice day.
And remember to start the final project early.
> mv fileone filetwo
> ls
filetwo
> cp filetwo filethree
> ls
filetwo
filethree
> cat filethree
Have a nice day.
And remember to start the final project early.
> mkdir newdir
> cp filethree newdir/filefour
> cd newdir
> pwd
./abc/newdir
> ls
filefour
> cp filefour filefive
> rm filefour
> rm filesix
error: filesix does not exist
> ls
filefive
> cd
> pwd
.
> rmdir abc
error: abc is not empty
> mkdir foo
> ls
abc
dir1
file1
file2
file3
foo
> switchto acf5
> pwd
.
> ls
new1
new2
new3
> exit
 
 
===========================================================
 
Here is the .x file that describes the protocols.  You must use this
.x for this project.
 
 
const MAXDATA           = 50;
const MAXFILENAME       = 300;
 
const OK                = 1;
const DOESNOTEXIST      = 2;
 
struct fattr {
        int size;              /* file size in bytes */
        string permissions<>;  /* permissions as a string */
        string owner<>;        /* owner name */
        string modtime<>;      /* modification time as a string */
};
 
struct filelist {
        string filename<MAXFILENAME>;
        struct filelist *nextp;
};
 
union attrres switch (int status) {
case OK:
        fattr attributes;
default:
        string errmessage<>;
};
 
union lookupres switch (int status) {
case OK:
        bool is_directory;
case DOESNOTEXIST:
        void;
default:
        string errmessage<>;
};
 
union readres switch (int status) {
case OK:
        opaque data<MAXDATA>;
default:
        void;
};
 
union writeres switch (int status) {
case OK:
        int count;
default:
        string errmessage<>;
};
 
union createres switch (int status) {
case OK:
        void;
default:
        string errmessage<>;
};
 
union readdirres switch (int status) {
case OK:
        filelist *filelistp;
default:
        string errmessage<>;
};
 
struct filenamearg {
        string filename<MAXFILENAME>;
};
 
struct readargs {
        string filename<MAXFILENAME>;   /* file name */
        unsigned offset;                /* byte offset in file */
        unsigned count;                 /* read count */
};
 
struct writeargs {
        string filename<MAXFILENAME>;   /* file name */
        int offset;             /* current byte offset in file */
        int count;                      /* write count */
        opaque data<MAXDATA>;
};
 
struct renameargs {
        string from<MAXFILENAME>;
        string to<MAXFILENAME>;
};
 
 
/*
 * Remote file service routines
 */
program FILE_INFO_PROGRAM {
        version FILE_INFO_VERSION {
                attrres
                GETATTR(filenamearg) =  1;
 
                lookupres
                LOOKUP(filenamearg) = 2;
 
                readres
                READ(readargs) = 3;
 
                writeres
                WRITE(writeargs) = 4;
 
                createres
                CREATE(filenamearg) = 5;
 
                createres
                REMOVE(filenamearg) = 6;
 
                createres
                RENAME(renameargs) = 7;
 
                createres
                MKDIR(filenamearg) = 8;
 
                createres
                RMDIR(filenamearg) = 9;
 
                readdirres
                READDIR(filenamearg) = 10;
        } = 2;
} = 0xYourIDHere;