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 00046 #include "copyright.h" 00047 00048 #include "disk.h" 00049 #include "bitmap.h" 00050 #include "directory.h" 00051 #include "filehdr.h" 00052 #include "filesys.h" 00053 00054 // Sectors containing the file headers for the bitmap of free sectors, 00055 // and the directory of files. These file headers are placed in well-known 00056 // sectors, so that they can be located on boot-up. 00057 #define FreeMapSector 0 00058 #define DirectorySector 1 00059 00060 // Initial file sizes for the bitmap and directory; until the file system 00061 // supports extensible files, the directory size sets the maximum number 00062 // of files that can be loaded onto the disk. 00063 #define FreeMapFileSize (NumSectors / BitsInByte) 00064 #define NumDirEntries 10 00065 #define DirectoryFileSize (sizeof(DirectoryEntry) * NumDirEntries) 00066 00067 //---------------------------------------------------------------------- 00068 // FileSystem::FileSystem 00069 // Initialize the file system. If format = TRUE, the disk has 00070 // nothing on it, and we need to initialize the disk to contain 00071 // an empty directory, and a bitmap of free sectors (with almost but 00072 // not all of the sectors marked as free). 00073 // 00074 // If format = FALSE, we just have to open the files 00075 // representing the bitmap and the directory. 00076 // 00077 // "format" -- should we initialize the disk? 00078 //---------------------------------------------------------------------- 00079 00080 FileSystem::FileSystem(bool format) 00081 { 00082 DEBUG('f', "Initializing the file system.\n"); 00083 if (format) { 00084 BitMap *freeMap = new BitMap(NumSectors); 00085 Directory *directory = new Directory(NumDirEntries); 00086 FileHeader *mapHdr = new FileHeader; 00087 FileHeader *dirHdr = new FileHeader; 00088 00089 DEBUG('f', "Formatting the file system.\n"); 00090 00091 // First, allocate space for FileHeaders for the directory and bitmap 00092 // (make sure no one else grabs these!) 00093 freeMap->Mark(FreeMapSector); 00094 freeMap->Mark(DirectorySector); 00095 00096 // Second, allocate space for the data blocks containing the contents 00097 // of the directory and bitmap files. There better be enough space! 00098 00099 ASSERT(mapHdr->Allocate(freeMap, FreeMapFileSize)); 00100 ASSERT(dirHdr->Allocate(freeMap, DirectoryFileSize)); 00101 00102 // Flush the bitmap and directory FileHeaders back to disk 00103 // We need to do this before we can "Open" the file, since open 00104 // reads the file header off of disk (and currently the disk has garbage 00105 // on it!). 00106 00107 DEBUG('f', "Writing headers back to disk.\n"); 00108 mapHdr->WriteBack(FreeMapSector); 00109 dirHdr->WriteBack(DirectorySector); 00110 00111 // OK to open the bitmap and directory files now 00112 // The file system operations assume these two files are left open 00113 // while Nachos is running. 00114 00115 freeMapFile = new OpenFile(FreeMapSector); 00116 directoryFile = new OpenFile(DirectorySector); 00117 00118 // Once we have the files "open", we can write the initial version 00119 // of each file back to disk. The directory at this point is completely 00120 // empty; but the bitmap has been changed to reflect the fact that 00121 // sectors on the disk have been allocated for the file headers and 00122 // to hold the file data for the directory and bitmap. 00123 00124 DEBUG('f', "Writing bitmap and directory back to disk.\n"); 00125 freeMap->WriteBack(freeMapFile); // flush changes to disk 00126 directory->WriteBack(directoryFile); 00127 00128 if (DebugIsEnabled('f')) { 00129 freeMap->Print(); 00130 directory->Print(); 00131 00132 delete freeMap; 00133 delete directory; 00134 delete mapHdr; 00135 delete dirHdr; 00136 } 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 BitMap *freeMap; 00179 FileHeader *hdr; 00180 int sector; 00181 bool success; 00182 00183 DEBUG('f', "Creating file %s, size %d\n", name, 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 BitMap(NumSectors); 00192 freeMap->FetchFrom(freeMapFile); 00193 sector = freeMap->Find(); // find a sector to hold the file header 00194 if (sector == -1) 00195 success = FALSE; // no free block for file header 00196 else if (!directory->Add(name, sector)) 00197 success = FALSE; // no space in directory 00198 else { 00199 hdr = new FileHeader; 00200 if (!hdr->Allocate(freeMap, initialSize)) 00201 success = FALSE; // no space on disk for data 00202 else { 00203 success = TRUE; 00204 // everthing worked, flush all changes back to disk 00205 hdr->WriteBack(sector); 00206 directory->WriteBack(directoryFile); 00207 freeMap->WriteBack(freeMapFile); 00208 } 00209 delete hdr; 00210 } 00211 delete freeMap; 00212 } 00213 delete directory; 00214 return success; 00215 } 00216 00217 //---------------------------------------------------------------------- 00218 // FileSystem::Open 00219 // Open a file for reading and writing. 00220 // To open a file: 00221 // Find the location of the file's header, using the directory 00222 // Bring the header into memory 00223 // 00224 // "name" -- the text name of the file to be opened 00225 //---------------------------------------------------------------------- 00226 00227 OpenFile * 00228 FileSystem::Open(char *name) 00229 { 00230 Directory *directory = new Directory(NumDirEntries); 00231 OpenFile *openFile = NULL; 00232 int sector; 00233 00234 DEBUG('f', "Opening file %s\n", name); 00235 directory->FetchFrom(directoryFile); 00236 sector = directory->Find(name); 00237 if (sector >= 0) 00238 openFile = new OpenFile(sector); // name was found in directory 00239 delete directory; 00240 return openFile; // return NULL if not found 00241 } 00242 00243 //---------------------------------------------------------------------- 00244 // FileSystem::Remove 00245 // Delete a file from the file system. This requires: 00246 // Remove it from the directory 00247 // Delete the space for its header 00248 // Delete the space for its data blocks 00249 // Write changes to directory, bitmap back to disk 00250 // 00251 // Return TRUE if the file was deleted, FALSE if the file wasn't 00252 // in the file system. 00253 // 00254 // "name" -- the text name of the file to be removed 00255 //---------------------------------------------------------------------- 00256 00257 bool 00258 FileSystem::Remove(char *name) 00259 { 00260 Directory *directory; 00261 BitMap *freeMap; 00262 FileHeader *fileHdr; 00263 int sector; 00264 00265 directory = new Directory(NumDirEntries); 00266 directory->FetchFrom(directoryFile); 00267 sector = directory->Find(name); 00268 if (sector == -1) { 00269 delete directory; 00270 return FALSE; // file not found 00271 } 00272 fileHdr = new FileHeader; 00273 fileHdr->FetchFrom(sector); 00274 00275 freeMap = new BitMap(NumSectors); 00276 freeMap->FetchFrom(freeMapFile); 00277 00278 fileHdr->Deallocate(freeMap); // remove data blocks 00279 freeMap->Clear(sector); // remove header block 00280 directory->Remove(name); 00281 00282 freeMap->WriteBack(freeMapFile); // flush to disk 00283 directory->WriteBack(directoryFile); // flush to disk 00284 delete fileHdr; 00285 delete directory; 00286 delete freeMap; 00287 return TRUE; 00288 } 00289 00290 //---------------------------------------------------------------------- 00291 // FileSystem::List 00292 // List all the files in the file system directory. 00293 //---------------------------------------------------------------------- 00294 00295 void 00296 FileSystem::List() 00297 { 00298 Directory *directory = new Directory(NumDirEntries); 00299 00300 directory->FetchFrom(directoryFile); 00301 directory->List(); 00302 delete directory; 00303 } 00304 00305 //---------------------------------------------------------------------- 00306 // FileSystem::Print 00307 // Print everything about the file system: 00308 // the contents of the bitmap 00309 // the contents of the directory 00310 // for each file in the directory, 00311 // the contents of the file header 00312 // the data in the file 00313 //---------------------------------------------------------------------- 00314 00315 void 00316 FileSystem::Print() 00317 { 00318 FileHeader *bitHdr = new FileHeader; 00319 FileHeader *dirHdr = new FileHeader; 00320 BitMap *freeMap = new BitMap(NumSectors); 00321 Directory *directory = new Directory(NumDirEntries); 00322 00323 printf("Bit map file header:\n"); 00324 bitHdr->FetchFrom(FreeMapSector); 00325 bitHdr->Print(); 00326 00327 printf("Directory file header:\n"); 00328 dirHdr->FetchFrom(DirectorySector); 00329 dirHdr->Print(); 00330 00331 freeMap->FetchFrom(freeMapFile); 00332 freeMap->Print(); 00333 00334 directory->FetchFrom(directoryFile); 00335 directory->Print(); 00336 00337 delete bitHdr; 00338 delete dirHdr; 00339 delete freeMap; 00340 delete directory; 00341 }
1.2.14 written by Dimitri van Heesch,
© 1997-2002