// File: FileSystemAbstract.java // // Author: Andrew H. Fagg // 11/15/2 // // To Do: // Implement: // findDirectory() // list() // createDir() // deleteDir() // create() // delete() // read(String name) // read(String name, int offset, int length) // getFileRef() // existsFile() // existsDirectory() // append() // move() // fileCopy() // fileAppend() // deallocBlocks() // allocBlocks() // tree() // import java.util.*; import java.lang.*; import java.io.*; abstract class FileSystemAbstract { protected int f_index; // Set by getFileRef() protected DirectoryBlock db; // Set by getFileRef() protected String fname; // Set by getFileRef() public Disk disk; // Disk reference // public FileSystemAbstract() // // Create the FileSystem structures // // Effects: // 1. Opens the simulated disk // public FileSystemAbstract() { // Create reference to a disk of a specific geometry disk = new Disk("Disk0", 1024, 256); }; // public void format () throws FileSystemException // // Format the file system // // Return = nothing // // Effects: // 1. Block 0 is configured as the root block // 2. Block 1 is the freeListBlk which links all the free blocks // 3. All but the first two blocks are available to be used // // throws FileSystemException if: // 1. An I/O error occurs with the external file system. // final public void format () throws FileSystemException{ disk.format(); }; // protected void checkDirectoryName(String name) throws FileSystemException // // Check the name of the directory. If valid, returns without doing // anything // // Return = nothing // // Effects: // 1. Nothing // // throws FileSystemException if: // 1. the directory name is not valid // final protected void checkDirectoryName(String name) throws FileSystemException { // Check for valid characters if(!name.matches("^[\\w\\._/]*$")) { throw new FileSystemException("Ill-formed file name (" + name + ")."); }; // Check for repeated "/" if(name.matches(".*//.*")) { throw new FileSystemException("Ill-formed file name (" + name + ")."); }; }; //////////////////////////////////////////////////////////////////////// // Technically not FileSystem functions, as they are built upon // file system functionality // // public void fileImport(String fname1, String fname2) // throws FileSystemException // // Import a file from the base file system into our file system // // Effects: // 1. Creates a new file in our file system // 2. If already exists, it is first removed // // Return = nothing // // throws FileSystemException if: // 1. is a directory // 2. The file system is too full to insert the file // 3. The parent directory of is full // 4. does not exist or is not a file // 5. there is a read error on // final public void fileImport(String fname1, String fname2) throws FileSystemException { int i; int len; byte[] buf = new byte[1000]; try { // Open the original file in the base file system FileInputStream f = new FileInputStream(fname1); // Create the new file in the local file system create(fname2); // While there are bytes to read from the base file system while((len=f.read(buf)) > 0) { // Append these bytes to the local file system append(fname2, buf, len); }; f.close(); }catch(IOException e) { // Catch any errors from the import file access throw new FileSystemException("Import file error: " + e); }; }; // public void fileExport(String fname1, String fname2) // throws FileSystemException // // Exports a file from our file system to the base file system // // Effects: // 1. Creates a new file in the base file system. // // Return = nothing // // throws FileSystemException if: // 1. is a directory // 2. There is an error in creating the file in the base file system // 3. does not exist // final public void fileExport(String fname1, String fname2) throws FileSystemException { int i; byte[] buf; try { if(existsFile(fname1)) { // The original file exists // Create the output file in the base system FileOutputStream f = new FileOutputStream(fname2); i = 0; // Read the first 1000 bytes buf = read(fname1, i, 1000); // While there are bytes in the buffer while(buf != null) { // Write the bytes to f.write(buf); // Increment the byte count i += 1000; // Read the next 1000 bytes from the local file system buf = read(fname1, i, 1000); }; f.close(); }else if(existsDirectory(fname1)) { // original was a directory throw new FileSystemException(fname1 + " is a directory."); }else{ // original does not exist throw new FileSystemException(fname1 + " does not exist."); }; }catch(IOException e) { // Catch any errors from the export file access throw new FileSystemException("Export file error: " + e); }; }; // checkDir(int block_num) void checkFile(short blockPtr, int data[]) throws FileSystemException{ int i, count = 0; DirectoryBlock dataBlk = new DirectoryBlock(disk); dataBlk.read(blockPtr); if(blockPtr!=0){ data[blockPtr]++; while(dataBlk.nextBlkPtr != 0){ data[dataBlk.nextBlkPtr]++; dataBlk.read(dataBlk.nextBlkPtr); count++; if(count > 254) throw new FileSystemException("File length longer than Disk Size"); } } } void checkDir(short blockPtr, int dir[], int data[]) throws FileSystemException{ int i; DirectoryBlock dirBlk = new DirectoryBlock(disk); dirBlk.read(blockPtr); for(i=0; i < dirBlk.maxFiles; i++){ if(dirBlk.inodes[i].used_p){ if(dirBlk.inodes[i].file_p){ checkFile(dirBlk.inodes[i].blockPtr, data); } else{ dir[dirBlk.inodes[i].blockPtr]++; checkDir(dirBlk.inodes[i].blockPtr, dir, data); } } } } // Here provide the code for DiskCheck final public void diskCheck() throws FileSystemException { int dir[], free[], data[]; int i, count = 0; dir = new int[disk.numBlocks]; free = new int[disk.numBlocks]; data = new int[disk.numBlocks]; DirectoryBlock freeDataBlk = new DirectoryBlock(disk); dir[0] = 1; free[1] = 1; freeDataBlk.read(1); // first mark all the free blocks while(freeDataBlk.nextBlkPtr != 0){ free[freeDataBlk.nextBlkPtr]++; freeDataBlk.read(freeDataBlk.nextBlkPtr); count++; if(count > 254) throw new FileSystemException("Ilformatted free list"); } // recursively mark the directory and data blocks checkDir((short)0, dir, data); for(i=0; i < disk.numBlocks; i++){ if((dir[i] + free[i] + data[i])!=1){ System.out.print("Block " + i + " is in error: "); throw new FileSystemException("It is marked as a Directory block " + dir[i] + " time(s), Data block " + data[i] + " time(s) and Free block " + free[i] + " times."); } } System.out.println("Congrats: Disk seems clean!!"); } ///////////////////////////////////////////////////////////////////// // To be provided in class FileSystem // private DirectoryBlock findDirectory(String name) // throws FileSystemException // // Return the directory specified by (less the last file // or directory name). // Specified is a file or directory residing in some directory 'dirParent' // Your job is to return a cached copy of that directory 'dirParent'. // Note dirParent could also have a parent directory etc. These are ancestors // of . // // Assumptions: // Specified is a complete path name. So, you start hunting starting // at the root directory which is Block 0 // // Effects: // 1. No changes are made to the file system // 2. If any part of does not exist then 'Directory not found' // error is printed // 3. If any ancestor of is a file 'Specified directory is a file' error // is printed // // throws FileSystemException if: // 1. is not a valid name // 2. there is a read error // 3. if any part of is not found directory does not exist // 4. if while narrowing down to the 'dirParent' any ancestor turns // out to be a file // abstract public DirectoryBlock findDirectory(String name) throws FileSystemException; // public void list(String name) throws FileSystemException // // List a named file or the contents of a named directory. // is an absolute name. // // Return = nothing // // Effects: // 1. No changes are made to the file system // 2. If does not exist, then a 'file not found' // error is printed // // throws FileSystemException if: // 1. is not a valid name // 2. there is a read error // abstract public void list(String name) throws FileSystemException; // public void createDir(String name) throws FileSystemException // // Create a named directory. // is an absolute directory name // // Return = nothing // // Effects: // 1. A new entry is added to the parent directory // 2. A new directory block is allocated // // throws FileSystemException if : // 1. is not a valid name // 2. the parent directory does not exist // 3. The file system is too full to allocate the necessary space // for the new directory // 4. The parent directory does not have enough space. // 5. A file or directory already exists by the same name // abstract public void createDir(String name) throws FileSystemException; // public void deleteDir(String name) throws FileSystemException // // Delete a named diretory. // is an absolute directory name // // Return = nothing // // Effects: // 1. The specified directory block is deallocated // 2. The directory's entry is removed from its parent // // throws FileSystemException if: // 1. is not a valid name // 2. The directory does not exist // 3. The named directory is not empty // 4. The name corresponds to a file // abstract public void deleteDir(String name) throws FileSystemException; // public void create(String name) throws FileSystemException // // Create a named file // is an absolute file name // // Return = nothing // // Effects: // Inserts the file into the parent directory's file list. // The file is of size 0. // If the file already exists, then its contents are removed // (ie it is set back to a file of size 0). // // throws FileSystemException if: // 1. is not a valid name // 2. The directory does not exist // 3. The name corresponds to a directory // 4. The parent directory is full // abstract public void create(String name) throws FileSystemException; // public void delete(String name) throws FileSystemException // // Delete the named file // // Return = nothing // // Effects: // Removes the specified file from its parent directory's list // Releases the data blocks used by the file // // throws FileSystemException if: // 1. is not a valid name // 2. The file does not exist // 3. The name corresponds to a directory // abstract public void delete(String name) throws FileSystemException; // public byte[] read(String name) throws FileSystemException // // Read all of the bytes from a named file. // // Return = the array of bytes (normally). // = null if the file is empty. // // Effects: // None (no changes are made to the file system) // // throws FileSystemException if: // 1. is not a valid name // 2. The file does not exist // 3. The name corresponds to a directory // abstract public byte[] read(String name) throws FileSystemException; // public byte[] read(String name, int offset, int length) // throws FileSystemException // // Read bytes from a file starting at position // (where 0 is the first byte in the file). // // Return = the array of bytes (normally) // = the array of size-offset bytes (if smaller than length) // = null if offset is passed the end of the file. // // Effects: // None (no changes are made to the file system) // // throws FileSystemException if: // 1. is not a valid name // 2. The file does not exist // 3. The name corresponds to a directory // abstract public byte[] read(String name, int offset, int length) throws FileSystemException; // Sets the class global db to the directory block that contains // the file and the global f_index to the matching file // // Note: Globals db and f_index are defined above // // Return = nothing // // Effects: // 1. The global db is set to the directory in which resides // 2. f_index is set to that of the matching file if it exists // (use findName that you implemented in DirectoryBlock.java) // // // throws FileSystemException if: // 1. Unable to find the directory block that contains the file // abstract public void getFileRef(String name) throws FileSystemException; // public boolean existsFile(String name) throws FileSystemException // // Return = true if exists and is a file // // Effects: none // // throws FileSystemException if: // 1. is not a valid file/directory name // abstract public boolean existsFile(String name) throws FileSystemException; // public boolean existsDirectory(String name) throws FileSystemException // // Return = true if exists and is a directory // // Effects: none // // throws FileSystemException if: // 1. is not a valid file/directory name // abstract public boolean existsDirectory(String name) throws FileSystemException; // public void append(String name, byte[] buf, int bufLen) // // Append the first bytes in to file // // Return = nothing // // Effects: // 1. buf[0 ... bufLen-1] are appended to the end of the file // 2. If not enough data blocks can be allocated to fit these // bytes, then NO change is made to the file // // throws FileSystemException if: // 1. does not exist // 2. is a directory // 3. The file system is full (and not enough blocks can be // allocated) // abstract public void append(String name, byte[] buf, int bufLen) throws FileSystemException; // public void move(String name1, String name2) // throws FileSystemException // // Move absolute to absolute // // Notation: assume that = / // Where is the parent directory reference (and may be ""), // and is the local name of the file or directory // // Return = nothing // // Effects: // // If is a file: // If is a file, then the old is removed and // replaced with the contents of // // If does not exist: inherits the contents // of // // If is a directory, then / inherits the // contents of // // If is a directory: // If does not exist, then inherits the // contents of // // If is a directory, then / inherits the // contents of // // throws FileSystemException if: // does not exist // or are not valid names // and are the same object // is a directory, and is a file // is an ancestor of (ie, doing the move would // set up a cycle in the directory structure that would not // be reachable from the root directory). // // HINT: 1. This should behave just like the unix "mv" command // 2. Because there are so many different conditions, // implement this method last. // abstract public void move(String name1, String name2) throws FileSystemException; //////////////////////////////////////////////////////////////////////// // Technically not FileSystem functions, as they are built upon // file system functionality // // public void fileCopy(String fname1, String fname2) // throws FileSystemException // // Copy file to // // Effects: // 1. Creates file and copies the contents of // into the new file // 2. If is a directory, then a file is created within // with the same name as in // // throws FileSystemException if: // 1. Parent directory of is full // 2. File system is full // 3. or are not valid file names // 4. does not exist // 5. is a directory // abstract public void fileCopy(String fname1, String fname2) throws FileSystemException; // public void fileAppend(String fname1, String fname2) // throws FileSystemException // // Append file to // // Effects: // 1. Appends the bytes of onto // // throws FileSystemException if: // 1. or are not valid file names // 2. or do not exist // 3. or are directories // 4. File system is full // abstract public void fileAppend(String fname1, String fname2) throws FileSystemException; // public void DeallocBlocks(short blockPtr) throws FileSystemException; // // Deallocate the set of blocks that are indicated by blockPtr // // Assumptions: // 1. All the blocks linked starting with "blockPtr" are to be // deallocated // 2. The last block in the list of blocks to be deallocated should // point to block 0 // 3. The freeBlk is not already cached to be written to disk. // (as this function reads it, modifies and writes it to disk) // //Note. It is better to add the blocks to be deallocated at the head // of the free list. As the freeList would in general be longer // than the number of blocks to be deallocated. // // Effects: // 1. The last block in the list of blocks to be deallocated now points to // the block that freeListBlk was pointing to // 2. The freeLisBlk should now point to block to be freed. // 3. The changes to this last block and the freeListBlk are written // to disk // // Return = nothing // // FileSystemException is thrown if: // 1. There is a write error. // abstract public void deallocBlocks(short blockPtr) throws FileSystemException; // public short AllocBlocks(int num_blocks) throws FileSystemException; // // Allocate num_blocks that were previously free. // // Assumptions: // // 1. The freeBlk is not already cached to be written to disk. // (as this function reads it, modifies and writes it to disk) // // Effects: // 1. The freeListBlk (Block 1) nextBlkPtr is changed to point to a free Block // 2. The changes are reflected to the disk // 3. The last allocated block has its nextBlkPtr set to 0, and again // the changes are reflected to disk // 3. If there are not "num_blocks" free blocks to allocate // FileSystemException is thrown // 4. FileSystemException is thrown if there is a write error. // // Return = the block number of the first allocated block // // throws FileSystemException if: // 1. There was a write error to the disk // 2. The file system is too full to allocate requested no. the blocks // abstract public short allocBlocks(int num_blocks) throws FileSystemException; // throws FileSystemException; abstract public void tree() throws FileSystemException; };