00001 // filesys.cc 00002 // Routines to manage the overall operation of the file system. 00003 // Implements routines to map from textual file names to files. 00004 // 00005 // Each file in the file system has: 00006 // A file header, stored in a sector on disk 00007 // (the size of the file header data structure is arranged 00008 // to be precisely the size of 1 disk sector) 00009 // A number of data blocks 00010 // An entry in the file system directory 00011 // 00012 // The file system consists of several data structures: 00013 // A bitmap of free disk sectors (cf. bitmap.h) 00014 // A directory of file names and file headers 00015 // 00016 // Both the bitmap and the directory are represented as normal 00017 // files. Their file headers are located in specific sectors 00018 // (sector 0 and sector 1), so that the file system can find them 00019 // on bootup. 00020 // 00021 // The file system assumes that the bitmap and directory files are 00022 // kept "open" continuously while Nachos is running. 00023 // 00024 // For those operations (such as Create, Remove) that modify the 00025 // directory and/or bitmap, if the operation succeeds, the changes 00026 // are written immediately back to disk (the two files are kept 00027 // open during all this time). If the operation fails, and we have 00028 // modified part of the directory and/or bitmap, we simply discard 00029 // the changed version, without writing it back to disk. 00030 // 00031 // Our implementation at this point has the following restrictions: 00032 // 00033 // there is no synchronization for concurrent accesses 00034 // files have a fixed size, set when the file is created 00035 // files cannot be bigger than about 3KB in size 00036 // there is no hierarchical directory structure, and only a limited 00037 // number of files can be added to the system 00038 // there is no attempt to make the system robust to failures 00039 // (if Nachos exits in the middle of an operation that modifies 00040 // the file system, it may corrupt the disk) 00041 // 00042 // Copyright (c) 1992-1993 The Regents of the University of California. 00043 // All rights reserved. See copyright.h for copyright notice and limitation 00044 // of liability and disclaimer of warranty provisions. 00045 #ifndef FILESYS_STUB 00046 00047 #include "copyright.h" 00048 #include "debug.h" 00049 #include "disk.h" 00050 #include "pbitmap.h" 00051 #include "directory.h" 00052 #include "filehdr.h" 00053 #include "filesys.h" 00054 00055 // Sectors containing the file headers for the bitmap of free sectors, 00056 // and the directory of files. These file headers are placed in well-known 00057 // sectors, so that they can be located on boot-up. 00058 #define FreeMapSector 0 00059 #define DirectorySector 1 00060 00061 // Initial file sizes for the bitmap and directory; until the file system 00062 // supports extensible files, the directory size sets the maximum number 00063 // of files that can be loaded onto the disk. 00064 #define FreeMapFileSize (NumSectors / BitsInByte) 00065 #define NumDirEntries 10 00066 #define DirectoryFileSize (sizeof(DirectoryEntry) * NumDirEntries) 00067 00068 //---------------------------------------------------------------------- 00069 // FileSystem::FileSystem 00070 // Initialize the file system. If format = TRUE, the disk has 00071 // nothing on it, and we need to initialize the disk to contain 00072 // an empty directory, and a bitmap of free sectors (with almost but 00073 // not all of the sectors marked as free). 00074 // 00075 // If format = FALSE, we just have to open the files 00076 // representing the bitmap and the directory. 00077 // 00078 // "format" -- should we initialize the disk? 00079 //---------------------------------------------------------------------- 00080 00081 FileSystem::FileSystem(bool format) 00082 { 00083 DEBUG(dbgFile, "Initializing the file system."); 00084 if (format) { 00085 PersistentBitmap *freeMap = new PersistentBitmap(NumSectors); 00086 Directory *directory = new Directory(NumDirEntries); 00087 FileHeader *mapHdr = new FileHeader; 00088 FileHeader *dirHdr = new FileHeader; 00089 00090 DEBUG(dbgFile, "Formatting the file system."); 00091 00092 // First, allocate space for FileHeaders for the directory and bitmap 00093 // (make sure no one else grabs these!) 00094 freeMap->Mark(FreeMapSector); 00095 freeMap->Mark(DirectorySector); 00096 00097 // Second, allocate space for the data blocks containing the contents 00098 // of the directory and bitmap files. There better be enough space! 00099 00100 ASSERT(mapHdr->Allocate(freeMap, FreeMapFileSize)); 00101 ASSERT(dirHdr->Allocate(freeMap, DirectoryFileSize)); 00102 00103 // Flush the bitmap and directory FileHeaders back to disk 00104 // We need to do this before we can "Open" the file, since open 00105 // reads the file header off of disk (and currently the disk has garbage 00106 // on it!). 00107 00108 DEBUG(dbgFile, "Writing headers back to disk."); 00109 mapHdr->WriteBack(FreeMapSector); 00110 dirHdr->WriteBack(DirectorySector); 00111 00112 // OK to open the bitmap and directory files now 00113 // The file system operations assume these two files are left open 00114 // while Nachos is running. 00115 00116 freeMapFile = new OpenFile(FreeMapSector); 00117 directoryFile = new OpenFile(DirectorySector); 00118 00119 // Once we have the files "open", we can write the initial version 00120 // of each file back to disk. The directory at this point is completely 00121 // empty; but the bitmap has been changed to reflect the fact that 00122 // sectors on the disk have been allocated for the file headers and 00123 // to hold the file data for the directory and bitmap. 00124 00125 DEBUG(dbgFile, "Writing bitmap and directory back to disk."); 00126 freeMap->WriteBack(freeMapFile); // flush changes to disk 00127 directory->WriteBack(directoryFile); 00128 00129 if (debug->IsEnabled('f')) { 00130 freeMap->Print(); 00131 directory->Print(); 00132 } 00133 delete freeMap; 00134 delete directory; 00135 delete mapHdr; 00136 delete dirHdr; 00137 } else { 00138 // if we are not formatting the disk, just open the files representing 00139 // the bitmap and directory; these are left open while Nachos is running 00140 freeMapFile = new OpenFile(FreeMapSector); 00141 directoryFile = new OpenFile(DirectorySector); 00142 } 00143 } 00144 00145 //---------------------------------------------------------------------- 00146 // FileSystem::Create 00147 // Create a file in the Nachos file system (similar to UNIX create). 00148 // Since we can't increase the size of files dynamically, we have 00149 // to give Create the initial size of the file. 00150 // 00151 // The steps to create a file are: 00152 // Make sure the file doesn't already exist 00153 // Allocate a sector for the file header 00154 // Allocate space on disk for the data blocks for the file 00155 // Add the name to the directory 00156 // Store the new file header on disk 00157 // Flush the changes to the bitmap and the directory back to disk 00158 // 00159 // Return TRUE if everything goes ok, otherwise, return FALSE. 00160 // 00161 // Create fails if: 00162 // file is already in directory 00163 // no free space for file header 00164 // no free entry for file in directory 00165 // no free space for data blocks for the file 00166 // 00167 // Note that this implementation assumes there is no concurrent access 00168 // to the file system! 00169 // 00170 // "name" -- name of file to be created 00171 // "initialSize" -- size of file to be created 00172 //---------------------------------------------------------------------- 00173 00174 bool 00175 FileSystem::Create(char *name, int initialSize) 00176 { 00177 Directory *directory; 00178 PersistentBitmap *freeMap; 00179 FileHeader *hdr; 00180 int sector; 00181 bool success; 00182 00183 DEBUG(dbgFile, "Creating file " << name << " size " << initialSize); 00184 00185 directory = new Directory(NumDirEntries); 00186 directory->FetchFrom(directoryFile); 00187 00188 if (directory->Find(name) != -1) 00189 success = FALSE; // file is already in directory 00190 else { 00191 freeMap = new PersistentBitmap(freeMapFile,NumSectors); 00192 sector = freeMap->FindAndSet(); // find a sector to hold the file header 00193 if (sector == -1) 00194 success = FALSE; // no free block for file header 00195 else if (!directory->Add(name, sector)) 00196 success = FALSE; // no space in directory 00197 else { 00198 hdr = new FileHeader; 00199 if (!hdr->Allocate(freeMap, initialSize)) 00200 success = FALSE; // no space on disk for data 00201 else { 00202 success = TRUE; 00203 // everthing worked, flush all changes back to disk 00204 hdr->WriteBack(sector); 00205 directory->WriteBack(directoryFile); 00206 freeMap->WriteBack(freeMapFile); 00207 } 00208 delete hdr; 00209 } 00210 delete freeMap; 00211 } 00212 delete directory; 00213 return success; 00214 } 00215 00216 //---------------------------------------------------------------------- 00217 // FileSystem::Open 00218 // Open a file for reading and writing. 00219 // To open a file: 00220 // Find the location of the file's header, using the directory 00221 // Bring the header into memory 00222 // 00223 // "name" -- the text name of the file to be opened 00224 //---------------------------------------------------------------------- 00225 00226 OpenFile * 00227 FileSystem::Open(char *name) 00228 { 00229 Directory *directory = new Directory(NumDirEntries); 00230 OpenFile *openFile = NULL; 00231 int sector; 00232 00233 DEBUG(dbgFile, "Opening file" << name); 00234 directory->FetchFrom(directoryFile); 00235 sector = directory->Find(name); 00236 if (sector >= 0) 00237 openFile = new OpenFile(sector); // name was found in directory 00238 delete directory; 00239 return openFile; // return NULL if not found 00240 } 00241 00242 //---------------------------------------------------------------------- 00243 // FileSystem::Remove 00244 // Delete a file from the file system. This requires: 00245 // Remove it from the directory 00246 // Delete the space for its header 00247 // Delete the space for its data blocks 00248 // Write changes to directory, bitmap back to disk 00249 // 00250 // Return TRUE if the file was deleted, FALSE if the file wasn't 00251 // in the file system. 00252 // 00253 // "name" -- the text name of the file to be removed 00254 //---------------------------------------------------------------------- 00255 00256 bool 00257 FileSystem::Remove(char *name) 00258 { 00259 Directory *directory; 00260 PersistentBitmap *freeMap; 00261 FileHeader *fileHdr; 00262 int sector; 00263 00264 directory = new Directory(NumDirEntries); 00265 directory->FetchFrom(directoryFile); 00266 sector = directory->Find(name); 00267 if (sector == -1) { 00268 delete directory; 00269 return FALSE; // file not found 00270 } 00271 fileHdr = new FileHeader; 00272 fileHdr->FetchFrom(sector); 00273 00274 freeMap = new PersistentBitmap(freeMapFile,NumSectors); 00275 00276 fileHdr->Deallocate(freeMap); // remove data blocks 00277 freeMap->Clear(sector); // remove header block 00278 directory->Remove(name); 00279 00280 freeMap->WriteBack(freeMapFile); // flush to disk 00281 directory->WriteBack(directoryFile); // flush to disk 00282 delete fileHdr; 00283 delete directory; 00284 delete freeMap; 00285 return TRUE; 00286 } 00287 00288 //---------------------------------------------------------------------- 00289 // FileSystem::List 00290 // List all the files in the file system directory. 00291 //---------------------------------------------------------------------- 00292 00293 void 00294 FileSystem::List() 00295 { 00296 Directory *directory = new Directory(NumDirEntries); 00297 00298 directory->FetchFrom(directoryFile); 00299 directory->List(); 00300 delete directory; 00301 } 00302 00303 //---------------------------------------------------------------------- 00304 // FileSystem::Print 00305 // Print everything about the file system: 00306 // the contents of the bitmap 00307 // the contents of the directory 00308 // for each file in the directory, 00309 // the contents of the file header 00310 // the data in the file 00311 //---------------------------------------------------------------------- 00312 00313 void 00314 FileSystem::Print() 00315 { 00316 FileHeader *bitHdr = new FileHeader; 00317 FileHeader *dirHdr = new FileHeader; 00318 PersistentBitmap *freeMap = new PersistentBitmap(freeMapFile,NumSectors); 00319 Directory *directory = new Directory(NumDirEntries); 00320 00321 printf("Bit map file header:\n"); 00322 bitHdr->FetchFrom(FreeMapSector); 00323 bitHdr->Print(); 00324 00325 printf("Directory file header:\n"); 00326 dirHdr->FetchFrom(DirectorySector); 00327 dirHdr->Print(); 00328 00329 freeMap->Print(); 00330 00331 directory->FetchFrom(directoryFile); 00332 directory->Print(); 00333 00334 delete bitHdr; 00335 delete dirHdr; 00336 delete freeMap; 00337 delete directory; 00338 } 00339 00340 #endif // FILESYS_STUB