home *** CD-ROM | disk | FTP | other *** search
Java Source | 1996-05-23 | 21.1 KB | 756 lines |
- // FileSystem.java
- // A static class containing functions for accessing the filesystem
- import java.io.*;
- import java.util.Vector;
- import java.util.StringTokenizer;
- import JFSdirectory;
- import JFSuser;
- import LineInputStream;
- import LineOutputStream;
-
- public class FileSystem
- {
- static String root = "."; // root dir of JFS
- static JFSfile rootfile; // info about root directory
- static LineOutputStream db = new NullOutputStream();
-
- // init
- // Set the root directory and create the root fileinfo
- static void init(String r)
- {
- root = r;
- rootfile = new JFSfile();
- rootfile.name = "";
- rootfile.type = "jfs/directory";
- rootfile.multiversion = false;
- JFSversion rootver = new JFSversion();
- rootver.number = 1;
- rootver.creator = "root";
- rootver.time = 0;
- rootver.size = 0;
- JFSfileuser rootusr = new JFSfileuser();
- rootusr.name = "all";
- rootusr.rwp = "r";
- rootfile.versions.addElement(rootver);
- rootfile.users.addElement(rootusr);
- }
-
- // simplify
- // Turn a path like //foo///bar/ to /foo/bar
- static String simplify(String s) throws BadPathException
- {
- if (s.length() == 0 || s.charAt(0) != '/')
- throw new BadPathException("Missing / at start of filename");
- if (s.indexOf(',') != -1)
- throw new BadPathException("Filename contains a ,");
- StringTokenizer tok = new StringTokenizer(s,"/");
- if (tok.countTokens() == 0)
- return "/"; // string only contains /'s
- String sim = "";
- while(tok.hasMoreTokens()) {
- String bit = tok.nextToken();
- if (bit.charAt(0) == '.')
- throw new BadPathException("Path component starts "+
- "with a .");
- sim += "/"+bit;
- }
- return sim;
- }
-
- // parent
- // Returns the parent directory from the given string, or an empty
- // string for /
- static String parent(String d) throws BadPathException
- {
- String dir = simplify(d);
- if (dir.equals("/"))
- return "";
- return simplify(dir.substring(0, dir.lastIndexOf('/')+1));
- }
-
- // statfile
- // Return the JFSfile structure for a given filename
- static synchronized JFSfile statfile(String s)
- throws BadPathException
- {
- db.puts("statfile("+s+")");
- String fn = simplify(s);
- if (fn.equals("/"))
- return rootfile;
- else {
- // Get the directory in which this file lies
- String par = parent(fn);
- JFSdirectory dir = getdir(par);
- JFSfile entry = dir.find(fn.substring(fn.lastIndexOf('/')+1));
- if (entry == null)
- throw new BadPathException(s+" not found");
- else
- return entry;
- }
- }
-
- // getdir
- // Returns the JFSdirectory structure for a given filename (which
- // must be a directory). Because the size field is not
- // stored in the .jfs file, it must be filled in here.
- static synchronized JFSdirectory getdir(String s)
- throws BadPathException
- {
- db.puts("getdir("+s+")");
- String path = simplify(s);
- String jfspath = root+path+"/.jfs";
- JFSdirectory dir;
- try {
- LineInputStream jfs = new LineInputStream(
- new FileInputStream(jfspath));
- dir = new JFSdirectory(jfs);
- jfs.close();
- }
- catch(FileNotFoundException e)
- throw new BadPathException("Couldn't find .jfs file "+jfspath);
- catch(IOException e)
- throw new BadPathException("Error reading .jfs file "+jfspath+
- " : "+e.getMessage());
-
- // Get the actual size of every file in the directory, from the
- // local filesystem.
- boolean writeout = false;
- for(int i=0; i<dir.size(); i++) {
- JFSfile entry = dir.find(i);
- String full = root+path+"/"+entry.name;
- for(int j=0; j<entry.versions.size(); j++) {
- JFSversion v = (JFSversion)entry.versions.elementAt(j);
- String fullver = full;
- if (entry.multiversion)
- fullver += ","+String.valueOf(v.number);
- File stat = new File(fullver);
- if (!stat.exists()) {
- // oh no! The local file for this version has
- // been deleted.
- writeout = true;
- if (entry.multiversion) {
- // Just remove a version
- entry.versions.removeElementAt(j--);
- continue;
- }
- else {
- // Remove the whole file
- dir.delete(i--);
- break;
- }
- }
- if (stat.isDirectory())
- v.size = 0;
- else
- v.size = stat.length();
- }
- }
-
- if (writeout) {
- // Because some local files have been deleted, we need to
- // write out this directory again.
- putdir(dir, path);
- }
- return dir;
- }
-
- // getuser
- // Lookup and return a JFSuser structure from the /etc/users file
- static synchronized JFSuser getuser(String name)
- throws BadUserException
- {
- LineInputStream users;
- try
- users = new LineInputStream(new FileInputStream(root+
- "/etc/users"));
- catch(FileNotFoundException e)
- throw new BadUserException(root+"/etc/users file not found");
- while(true) {
- String line = null;
- try line = users.gets();
- catch(IOException e)
- throw new BadUserException("User not found");
- JFSuser u;
- try u = new JFSuser(line);
- catch(IOException e)
- throw new BadUserException("Error reading user : "+
- e.getMessage());
- if (u.name.equals(name)) {
- try users.close();
- catch(IOException e);
- return u;
- }
- }
- }
-
- // getfile
- // Reads and returns the contents of a named file and version.
- // If start and end are not -1, then only part of the file gets read.
- // If version is 0, then assume this is a single-version file
- static synchronized byte []getfile(String f, int ver, int st, int en)
- throws BadPathException
- {
- db.puts("getfile("+f+","+ver+","+st+","+en+")");
- String full = root+simplify(f);
- if (ver > 0)
- full += ","+String.valueOf(ver);
- File fl = new File(full);
- LineInputStream fis;
- try
- fis = new LineInputStream(new FileInputStream(fl));
- catch(FileNotFoundException e)
- throw new BadPathException("Couldn't open file "+full);
- if (st == -1) {
- st = 0;
- en = ((int)fl.length())-1;
- }
- else if (en >= fl.length())
- en = ((int)fl.length())-1;
- byte data[] = new byte[en-st+1];
- try {
- fis.skip(st);
- fis.read(data, 0, data.length);
- }
- catch(IOException e)
- throw new BadPathException("Error reading "+full);
- try fis.close();
- catch(IOException e);
- return data;
- }
-
- // putfile
- // Saves the given data under the given file and version name, and
- // marked as created by the given user.
- // If no file of this name exists, a new directory entry is created.
- // If the file exists but this is a new version, then a new version
- // entry is created.
- // If the file and version both exists, then that version is
- // overwritten.
- // If the version given is non-zero then the file is saved with
- // that version number.
- // If the version is 0, and this is a new file then it is considered
- // to be a single-version file.
- // If the version is 0 and this is an existing file, then a new version
- // > any existing ones is created.
- static synchronized void putfile(String f, int ver, byte data[],
- String user, String type)
- throws BadPathException
- {
- // Find out about existing file
- db.puts("putfile("+f+","+ver+","+user+","+type+")");
- String sim = simplify(f);
- String base = sim.substring(sim.lastIndexOf('/')+1);
- JFSfile oldfileinfo = null;
- try oldfileinfo = statfile(sim);
- catch(BadPathException e);
- if (oldfileinfo != null && oldfileinfo.type.equals("jfs/directory"))
- throw new BadPathException("Is a directory");
- String par = parent(sim);
- JFSdirectory pardir = getdir(par);
- JFSfile oldfile = pardir.find(base);
-
- // Create user and version structures for the new file
- JFSversion nvr = new JFSversion();
- nvr.creator = user;
- nvr.time = System.currentTimeMillis();
- nvr.size = data.length;
-
- // Add the new file to the directory
- String filename = null;
- if (oldfile == null) {
- // totally new file
- JFSfile nfl = new JFSfile();
- nfl.name = base;
- nfl.type = type;
- nfl.multiversion = ver==0 ? false : true;
- nvr.number = nfl.multiversion ? ver : 1;
- nfl.versions.addElement(nvr);
- if (!user.equals("root")) {
- JFSfileuser nfu = new JFSfileuser();
- nfu.name = user;
- nfu.rwp = "rwp";
- nfl.users.addElement(nfu);
- }
- pardir.add(nfl);
- filename = sim + (nfl.multiversion ? ","+nvr.number : "");
- if (nfl.multiversion) updatelink(nfl, sim);
- }
- else if (!oldfile.multiversion) {
- // A single-version file with this name already exists
- String delname = par+"/"+oldfile.name;
- try deletefile(root+"/"+delname);
- catch(BadPathException e)
- ; // doesn't matter if it fails
- pardir.delete(oldfile);
- JFSfile nfl = new JFSfile();
- nfl.name = base;
- nfl.type = type;
- nfl.multiversion = ver==0 ? false : true;
- nvr.number = nfl.multiversion ? ver : 1;
- nfl.versions.addElement(nvr);
- nfl.users = oldfile.users;
- pardir.add(nfl);
- filename = sim + (nfl.multiversion ? ","+nvr.number : "");
- }
- else {
- // A multi-version file with this name already exists
- int verpos = oldfile.versions.size(); // position in array
- if (ver != 0) {
- // find this version number (if it exists)
- for(int i=0; i<oldfile.versions.size(); i++)
- if (((JFSversion)oldfile.versions.elementAt(i)).
- number == ver) {
- verpos = i;
- break;
- }
- }
- else {
- // find the highest version so far
- int max = 0;
- for(int i=0; i<oldfile.versions.size(); i++) {
- int n = ((JFSversion)oldfile.versions.
- elementAt(i)).number;
- if (n > max)
- max = n;
- }
- ver = max+1;
- }
- nvr.number = ver;
- if (verpos == oldfile.versions.size())
- oldfile.versions.addElement(nvr);
- else
- oldfile.versions.setElementAt(nvr, verpos);
- filename = sim + "," + ver;
- updatelink(oldfile,sim);
- }
-
- // Store data into file
- LineOutputStream outfile = null;
- try outfile = new LineOutputStream(
- new FileOutputStream(root+filename));
- catch(IOException e)
- throw new BadPathException("Couldn't create file "+
- root+filename);
- try {
- outfile.write(data);
- outfile.close();
- }
- catch(IOException e)
- throw new BadPathException("Error writing to file "+
- root+filename);
-
- // Write out directory
- putdir(pardir, par);
- }
-
- // putdir
- // Write out a JFSdirectory structure to a .jfs file
- static synchronized void putdir(JFSdirectory d, String n)
- throws BadPathException
- {
- db.puts("putdir("+n+")");
- String full = root+simplify(n)+"/.jfs";
- LineOutputStream outdir = null;
- try outdir = new LineOutputStream(new FileOutputStream(full));
- catch(IOException e)
- throw new BadPathException("Couldn't create .jfs file "+full);
- try {
- d.output(outdir);
- outdir.close();
- }
- catch(IOException e)
- throw new BadPathException("Error writing .jfs file "+full);
- }
-
- // deletefile
- // Delete the given local file. If it is a directory, delete all the
- // files in this directory first.
- // BUG! - File.delete() can't delete directories
- private static synchronized void deletefile(String file)
- throws BadPathException
- {
- db.puts("deletefile("+file+")");
- File fileinfo = new File(file);
- if (fileinfo.isDirectory()) {
- // delete everything in the directory first
- String cont[] = fileinfo.list();
- for(int i=0; i<cont.length; i++)
- deletefile(file+"/"+cont[i]);
- try Runtime.getRuntime().exec("/bin/rmdir "+file).waitFor();
- catch(Exception e)
- throw new BadPathException("rmdir failed");
- }
- else {
- // Just delete the file
- if (!fileinfo.delete())
- throw new BadPathException("delete() failed");
- }
- }
-
- // delete
- // Deletes the given file and version. If v is 0, then all versions
- // of the file are deleted.
- static synchronized void delete(String f, int v)
- throws BadPathException
- {
- db.puts("delete("+f+","+v+")");
- String file = simplify(f);
- if (file.equals("/"))
- throw new BadPathException("Cannot delete the root directory");
- String par = parent(file);
- JFSdirectory pardir = getdir(par);
- JFSfile delfile = pardir.find(file.substring(file.lastIndexOf('/')+1));
- if (delfile == null)
- throw new BadPathException("File not found in parent");
- if (!delfile.multiversion) {
- // single version file
- pardir.files.removeElement(delfile);
- deletefile(root+"/"+file);
- }
- else if (v == 0) {
- // multi-version file, delete all versions
- pardir.files.removeElement(delfile);
- for(int i=0; i<delfile.versions.size(); i++)
- deletefile(root+"/"+file+","+
- ((JFSversion)delfile.versions.
- elementAt(i)).number);
- updatelink(null, file);
- }
- else {
- // delete only one version
- JFSversion dv = null;
- int i;
- for(i=0; i<delfile.versions.size(); i++) {
- JFSversion cv = (JFSversion)delfile.versions.
- elementAt(i);
- if (cv.number == v) {
- dv = cv;
- break;
- }
- }
- if (dv == null)
- throw new BadPathException("Version does not exist");
- if (delfile.versions.size() == 1) {
- // last version gone.. remove this file
- pardir.files.removeElement(delfile);
- updatelink(null, file);
- }
- else {
- // remove just one version from the file
- delfile.versions.removeElementAt(i);
- updatelink(delfile, file);
- }
- deletefile(root+"/"+file+","+dv.number);
- }
-
- // Write out directory
- putdir(pardir, par);
- }
-
- // mkdir
- // Create a directory with the given name, owned by the given user
- static synchronized void mkdir(String d, String user)
- throws BadPathException
- {
- // Get parent dir info
- db.puts("mkdir("+d+","+user+")");
- String dir = simplify(d);
- if (dir.equals("/"))
- throw new BadPathException("Cannot make /");
- String par = parent(dir);
- JFSdirectory parinfo = null;
- try parinfo = getdir(par);
- catch(BadPathException e)
- throw new BadPathException("Parent directory not found");
-
- // Add a new entry to the parent
- String base = dir.substring(dir.lastIndexOf('/')+1);
- if (parinfo.find(base) != null)
- throw new BadPathException("File/directory already exists");
- JFSfile dirinfo = new JFSfile();
- dirinfo.name = base;
- dirinfo.type = "jfs/directory";
- dirinfo.multiversion = false;
- JFSversion dirver = new JFSversion();
- dirver.number = 1;
- dirver.creator = user;
- dirver.time = System.currentTimeMillis();
- dirver.size = 0;
- dirinfo.versions.addElement(dirver);
- if (!user.equals("root")) {
- JFSfileuser dirfu = new JFSfileuser();
- dirfu.name = user;
- dirfu.rwp = "rwp";
- dirinfo.users.addElement(dirfu);
- }
- parinfo.add(dirinfo);
-
- // create a new local directory, and put an empty .jfs file in it
- File dirfile = new File(root+"/"+dir);
- if (!dirfile.mkdir())
- throw new BadPathException("Failed to create local directory");
- FileOutputStream dirjfs = null;
- try {
- dirjfs = new FileOutputStream(root+"/"+dir+"/.jfs");
- dirjfs.close();
- }
- catch(IOException e)
- throw new BadPathException("Failed to create .jfs file");
-
- // write out parent dir
- putdir(parinfo, par);
- }
-
- // copy
- // Copy all versions of a file from the given source to the given
- // destination. The new file is owned by the copying user
- static synchronized void copy(String s, String d, String user)
- throws BadPathException
- {
- // Create new directory entry
- db.puts("copy("+s+","+d+","+user+")");
- String src = simplify(s), dst = simplify(d);
- if (src.equals(dst))
- throw new BadPathException("Source and destination are "+
- "the same");
- JFSfile srcinfo = statfile(src);
- if (srcinfo.type.equals("jfs/directory"))
- throw new BadPathException("Cannot copy directory");
- String par = parent(dst);
- JFSdirectory dirinfo = getdir(par);
- String base = dst.substring(dst.lastIndexOf('/')+1);
- JFSfile oldfile = dirinfo.find(base);
- if (oldfile != null) {
- if (oldfile.type.equals("jfs/directory"))
- throw new BadPathException("Cannot copy to directory");
- dirinfo.delete(oldfile);
- }
- srcinfo.name = base;
- srcinfo.users.removeAllElements();
- JFSfileuser fu = new JFSfileuser();
- fu.name = user;
- fu.rwp = "rwp";
- srcinfo.users.addElement(fu);
- dirinfo.add(srcinfo);
-
- // delete file being overwritten
- try delete(dst, 0);
- catch(BadPathException e);
-
- // copy all versions
- if (!srcinfo.multiversion)
- copyfile(root+"/"+src, root+"/"+dst);
- else {
- for(int i=0; i<srcinfo.versions.size(); i++) {
- int vn = ((JFSversion)srcinfo.versions.elementAt(i)).
- number;
- copyfile(root+"/"+src+","+vn, root+"/"+dst+","+vn);
- }
- updatelink(srcinfo, dst);
- }
-
- // write directory entry to file
- putdir(dirinfo, par);
- }
-
- // copyfile
- // Copy one file to another. Does not copy directories (yet).
- private static synchronized void copyfile(String src, String dst)
- throws BadPathException
- {
- db.puts("copyfile("+src+","+dst+")");
- File srcinfo = new File(src);
- if (srcinfo.isDirectory())
- throw new BadPathException("Cannot copy directories");
-
- // open source and destination files
- FileInputStream srcfile = null;
- try srcfile = new FileInputStream(src);
- catch(FileNotFoundException e)
- throw new BadPathException("Source file not found");
- FileOutputStream dstfile = null;
- try dstfile = new FileOutputStream(dst);
- catch(IOException e)
- throw new BadPathException("Couldn't create destination file");
-
- // copy data until EOF
- byte buf[] = new byte[1024];
- while(true) {
- int rd = 0;
- try rd = srcfile.read(buf);
- catch(IOException e)
- throw new BadPathException("Error reading data");
- if (rd < 0) break; // End of file
- try dstfile.write(buf, 0, rd);
- catch(IOException e)
- throw new BadPathException("Error writing data");
- }
- try {
- srcfile.close();
- dstfile.close();
- }
- catch(IOException e);
- }
-
- // getgroup
- // Returns a vector containing the names of all users who belong
- // to the given group.
- public static synchronized Vector getgroup(String group)
- throws BadGroupException
- {
- db.puts("getgroup("+group+")");
- LineInputStream uf = null;
- try uf = new LineInputStream(new FileInputStream(root+"/etc/users"));
- catch(IOException e)
- throw new BadGroupException("Error opening users file");
- Vector uv = new Vector();
- while(true) {
- String line = null;
- try line = uf.gets();
- catch(IOException e) break;
- JFSuser u = null;
- try u = new JFSuser(line);
- catch(IOException e)
- throw new BadGroupException("Users file format error");
- if (u.ingroup(group))
- uv.addElement(u.name);
- }
- try uf.close();
- catch(IOException e);
- return uv;
- }
-
- // chmod
- // Set or remove the access permissions for a user/group to a file.
- // If perms is non-null, then it gives the new permissions string
- // for the given user to the given file (overwriting any existing
- // permissions)
- // If perms is null, then permissions for that user to the file
- // are removed.
- public static synchronized void chmod(String f, String user, String p)
- throws BadPathException
- {
- db.puts("addfileuser("+f+","+user+","+p+")");
- String file = simplify(f);
- if (file.equals("/"))
- throw new BadPathException("Cannot change permissions of /");
- String par = parent(f);
- JFSdirectory parinfo = getdir(par);
- JFSfile fileinfo = parinfo.find(f.substring(f.lastIndexOf('/')+1));
- if (fileinfo == null)
- throw new BadPathException("File not found");
- for(int i=0; i<fileinfo.users.size(); i++) {
- JFSfileuser fu = (JFSfileuser)fileinfo.users.elementAt(i);
- if (fu.name.equals(user)) {
- fileinfo.users.removeElement(fu);
- break;
- }
- }
- if (p != null) {
- for(int j=0; j<p.length(); j++) {
- char c = p.charAt(j);
- if (c != 'r' && c != 'w' && c != 'p')
- throw new BadPathException("Bogus permissions "+
- "string");
- }
- JFSfileuser fu = new JFSfileuser();
- fu.name = user;
- fu.rwp = p;
- fileinfo.users.addElement(fu);
- }
- putdir(parinfo, par);
- }
-
- // rename
- // Rename all versions of a file to a name new, possibly in a
- // totally different directory.
- static synchronized void rename(String s, String d, String user)
- throws BadPathException
- {
- db.puts("rename("+s+","+d+","+user+")");
-
- // call copy and delete to do most of the work
- copy(s, d, user);
- delete(s, 0);
- }
-
- // putinfo
- // Store a directory entry for a file
- static synchronized void putinfo(String f, JFSfile i)
- throws BadPathException
- {
- String file = simplify(f);
- if (file.equals("/"))
- throw new BadPathException("Cannot change type of /");
- String par = parent(f);
- JFSdirectory parinfo = getdir(par);
- parinfo.replace(i);
- putdir(parinfo, par);
- }
-
- // updatelink
- // For multi-version file stored in the local filesystem as foo,N
- // there should be a symlink from foo to the latest version.
- // updatelink() removes any existing link, and if f is non-null
- // creates the symlink pointing to the latest version.
- // Should be called by the put, delete, copy and rename calls
- static private synchronized void updatelink(JFSfile f, String p)
- throws BadPathException
- {
- db.puts("updatelink("+p+")");
- String path = root+simplify(p);
- try Runtime.getRuntime().exec("/bin/rm "+path).waitFor();
- catch(Exception e);
- if (f == null)
- return; // nothing more to do
- int max = 0;
- for(int i=0; i<f.versions.size(); i++)
- max=Math.max(max, ((JFSversion)f.versions.elementAt(i)).number);
- String base = path.substring(path.lastIndexOf('/')+1);
- try Runtime.getRuntime().exec("/bin/ln -s "+base+","+max+" "+path);
- catch(Exception e)
- throw new BadPathException("ln failed");
- }
-
- }
-
-
- // BadPathException
- // A directory does not exist or is not part of the filesystem
- class BadPathException extends Exception
- {
- BadPathException() { }
- BadPathException(String why)
- {
- super(why);
- }
- }
-
- // BadUserException
- // A user does not exist or has a bogus name
- class BadUserException extends Exception
- {
- BadUserException() { }
- BadUserException(String why) { super(why); }
- }
-
- // BadGroupException
- // A group does not exist or has a bogus name
- class BadGroupException extends Exception
- {
- BadGroupException() { }
- BadGroupException(String why) { super(why); }
- }
-
- // NullOutputStream
- // An output stream that goes nowhere
- class NullOutputStream extends LineOutputStream
- {
- public void write(int b) { }
- public void write(byte b[]) { }
- public void write(byte b[], int off, int len) { }
- public void flush() { }
- public void close() { }
- }
-
-