#include #include #include #include "RamDisk.h" #define LIST_END -1 // Use this constant to end free lists of file descriptor entries and #define NO_FILE -1 // Use this constant to invalidate file descriptors #define NO_BLOCK ((BlockPt)NULL) // Use this constant to mark the end of list os blocks // The file system FileSystem fs; // The file descriptors table and the head of the free file descriptors list FileDescriptor fdt[MAX_OPEN_FILES]; // File Descriptors Table FileDesc fffd; // first free file descriptor //----------------------------------Auxiliary functions-------------------------------------------------------- BlockPt getBlock(Offset pos, File f, ...){ int na = fs.blkSize /sizeof(BlockPt); if(pos < fs.blkSize) return fs.fileTable[f].direct; pos -= fs.blkSize; if (pos < na*fs.blkSize) return fs.fileTable[f].indirect->blocks[pos/fs.blkSize]; pos -= na*fs.blkSize; if(pos blocks[pos/(na*fs.blkSize)]->blocks[pos%(na*(fs.blkSize)/fs.blkSize)]; else return NO_BLOCK; } FileDesc allocFileDesc(File f) { FileDesc fd = fffd; fffd = fdt[fd].pos; fdt[fd].f = f; fdt[fd].pos = 0; return fd; } void freeFileDesc(FileDesc fd) { fdt[fd].f = NO_FILE; fdt[fd].pos = fffd; // store the old head of the list inside the freed file descriptor (pos field) fffd = fd; // deallocated entry becomes first free file descriptor } //void freeFileDesc(FileDesc fd) //{ // fdt[fd].f = NO_FILE; // fdt[fd].pos = fffd; // store the old head of the list inside the freed file descriptor (pos field) // fffd = fd; // deallocated entry becomes first free file descriptor //} void freeBlocks(BlockPt* base, Size s){ int i; for(i = 0; i < s; i++){ free(base[i]); } BlockPt executioner = base[s]; BlockPt convicted; while(executioner->next != NO_BLOCK){ convicted = executioner; executioner = executioner->next; free(convicted); } } File findFile(char fn[]){ Size s = fs.maxFiles; int i; for(i = 0; i < s; i++){ if(strcmp(fs.fileTable[i].name, fn) == 0) return fdt[i].f; } return NO_FILE; } bool isFDTFull(){ return fffd == LIST_END; } bool isFTFull(){ return fs.fffe == LIST_END; } void startUpFDT(FileDescriptor fd[], int size){ int i; for(i = 0; i < size; i++){ fd[i].f = NO_FILE; } } void incFFFD(){ int i; for(i = 0; i < MAX_OPEN_FILES; i++){ if(fdt[i].pos == NO_FILE){ fffd = i; return; } } } File allocFileEntry(char fileName[]){ File fe = fs.fffe; fs.fffe = fs.fileTable[fe].size; strcpy(fs.fileTable[fe].name, fileName); fs.fileTable[fe].size = 0; return fe; } void freeFileEntry(int pos){ strcpy(fs.fileTable[pos].name, ""); fs.fileTable[pos].size = fs.fffe; // store the old head of the list inside the freed file entry (pos field) fs.fffe = pos; // deallocated entry becomes first free file entry } int findFileIndex(FileEntry fe[], char name[]){ int i; for (i = 0; inext; b->next = NO_BLOCK; return b; } void freeBlock(BlockPt b){ b->next = fs.ffb; // store the old head of the list inside the freed block (next field) fs.ffb = b; // deallocated entry becomes first free block } int sizeOfPointer(){ return sizeof(void*); } int pointersPerBlock(){ //tamanho bloco / tamanh apontador(16) = n. de apontadores por bloco (4) return fs.blkSize/sizeOfPointer(); } void freeBlocksFromFile(File fle){ FileEntry f = fs.fileTable[fle]; if(f.indirect != NULL){ //first takes care of direct blocks (if any) freeBlock(f.indirect); } if(f.indirect != NULL){ //then the indirects... int i; for(i=0; f.indirect->blocks[i] != NULL || i == pointersPerBlock(); i++){ freeBlock(f.indirect->blocks[i]); } freeBlock(f.indirect); //and, of course, the pointer block } if(f.doubleIndirect != NULL){ //and finally, the double indirects int i; for(i=0; f.doubleIndirect->blocks[i] != NULL || i == pointersPerBlock(); i++){ int n; for(n=0; f.indirect->blocks[i]->blocks[n] != NULL || i == pointersPerBlock(); i++){ freeBlock(f.indirect->blocks[i]->blocks[n]); } free(f.indirect->blocks[i]); } freeBlock(f.doubleIndirect); } } //Add enough memory blocks to support a growth of mem bytes to size //(this is a recursive function) int addBlocks(FileEntry f, int mem){ //mem>0 int currentIndBlock; BlockPt newBlock; if (mem == 0) return NO_ERROR; //First checks if either there is no growth if ((f.size%fs.blkSize + mem) < fs.blkSize){ //or if the growth is not enough to require f.size += mem; //the addition of blocks to the file. return NO_ERROR; } if(f.size == 0){ //Then verifies if the file size if 0 f.direct = allocBlock(); //if so, assigns a direct block. if(f.direct == NO_BLOCK){ //These are availability tests, that are return ERR_NO_SPACE_LEFT_ON_DEVICE; //performed, each time it is required } //a new block. if(mem < fs.blkSize){ // If no more block addition is required, f.size += mem; // simply updates size value and returns, return NO_ERROR; // without errors. } f.size += fs.blkSize; //If not, "allocs" the pointer block needed to use f.indirect = allocBlock(); //indirect blocks and continues recursively. // f.indirect->blocks = (BlockPt) malloc (sizeof(BlockPt)*pointersPerBlock()); addBlocks(f, mem-fs.blkSize); } if(f.size < fs.blkSize * (1 + pointersPerBlock())){ //Same treatment is given to indirect blocks currentIndBlock = ((f.size - fs.blkSize)/fs.blkSize); //except it is now require to calculate newBlock = allocBlock(); //which block in the block order we are if(newBlock == NO_BLOCK){ //currently treating. return ERR_NO_SPACE_LEFT_ON_DEVICE; } f.indirect->blocks[currentIndBlock] = newBlock; if(f.size - fs.blkSize < fs.blkSize){ //We must no forget to link the previous block to the current f.direct->next = newBlock; } else{ f.indirect->blocks[currentIndBlock-1]->next = newBlock; } if(mem < fs.blkSize){ f.size += mem; return NO_ERROR; } f.size += fs.blkSize; if(f.size >= fs.blkSize * (1 + pointersPerBlock())){ f.doubleIndirect= allocBlock(); if(f.doubleIndirect == NO_BLOCK){ return ERR_NO_SPACE_LEFT_ON_DEVICE; } } addBlocks(f, mem-fs.blkSize); } //Again, same treatment as indirect blocks, adding the extra required calculations //to find which block we are adding. else{ int currentDIndBlock = ((f.size - fs.blkSize - fs.blkSize*pointersPerBlock())/fs.blkSize); currentIndBlock = (currentDIndBlock / pointersPerBlock()); if(f.doubleIndirect->blocks[currentIndBlock] == NULL){ f.doubleIndirect->blocks[currentIndBlock] = allocBlock(); if(f.doubleIndirect->blocks[currentIndBlock] == NO_BLOCK){ return ERR_NO_SPACE_LEFT_ON_DEVICE; } } newBlock = allocBlock(); if(newBlock == NO_BLOCK){ return ERR_NO_SPACE_LEFT_ON_DEVICE; } f.doubleIndirect->blocks[currentIndBlock]->blocks[currentDIndBlock] = newBlock; if(f.size - fs.blkSize>= fs.blkSize * (1 + pointersPerBlock())){ f.indirect->blocks[pointersPerBlock()-1]->next = newBlock; } else if(currentDIndBlock == 0){ f.doubleIndirect->blocks[currentIndBlock-1]->blocks[pointersPerBlock()]->next = newBlock; } else{ f.doubleIndirect->blocks[currentIndBlock]->blocks[pointersPerBlock()-1]->next = newBlock; } addBlocks(f, mem-fs.blkSize); } return NO_ERROR; } //--------------------------------- Main functions----------------------------------- //na = blockSize/sizeOf(BlockPt) //pos < blkSize -> direct // This should create the file system, as well as setup the File Descriptors table int rdStart(int blockSize, int nBlocks, Size maxFiles) { // Initial validations if(blockSize < MIN_BLK_SIZE) return ERR_INVALID_BLK_SIZE; // Todo: If block size is not a power of 2 also return ERR_INVALID_BLK_SIZE. if(!((blockSize != 0) && !(blockSize & (blockSize - 1)))) return ERR_INVALID_BLK_SIZE; //same check implemented in malloc.c // ... if(maxFiles <= 0) return ERR_MAXFILES_NOT_POSITIVE; //*fs = (FileSystem *) malloc(sizeof(FileSystem)); DESNECESSÁRIO, fs criado no .h //e mais? // Initialize file system control information fs.maxFiles = maxFiles; fs.nFiles = 0; // Allocate file table and set it up fs.fileTable = (FileEntry *) malloc(sizeof(FileEntry)*maxFiles); // //if(fs.fileTable == NULL) return ERR_NOT_ENOUGH_MEMORY; //alocar n de blcos*tamanh de cada blcocs //base -> endereço do malloc //fffb = base //next(fffb) = base + tamanho do bloco até NO_BLOCK // //fileTable: //|size1|size2|size| LIST_END //FileEntry *fe = & fs.fileTable[fffe] //fffe = fe--> size //aumentar a memória: fe ->size = fffe; //fffe = 0; //assumir q todos os descritores são invalidos ao inicio //tamanho bloco / tamanh apontador(16) = nº de apontadores por bloco (4) //se maxblocks = 0, fffe = LIST_END fs.fileTable->size = blockSize; // ... // Setup the RamDisk blocks fs.base = malloc(blockSize*nBlocks); //BlockPt currentBlock; int i; BlockPt tmp = fs.base; for(i = 0; i<(nBlocks-1); i++){ tmp->next = fs.base + i*blockSize; } tmp->next = NO_BLOCK; fs.ffb=fs.base; fs.fffe=0; // depois para actualizar fffe += blocksize (por cada bloco) //caddr_t fs.blkSize = blockSize; startUpFDT(fdt, MAX_OPEN_FILES); return NO_ERROR; } void rdStop(void) { // Free all memory allocated by the filesystem blocks free(fs.base); // Free the file table free(fs.fileTable); } Size rdMaxFileSize(void) { return fs.blkSize * (1 + pointersPerBlock() + pointersPerBlock()*pointersPerBlock()); } FileDesc rdOpen(FileName fn, int flags ) //dado pelo Professor { FileDesc fd; // No file descriptors available -> open fails! if(isFDTFull()) return ERR_TOO_MANY_OPEN_FILES; // Next step is to check if file already exists... File f = findFile(fn); if(f == NO_FILE) { // File doesn't exist. Create one? if(flags & OF_CREATE) { // Plan ahead... if(isFTFull()) return ERR_TOO_MANY_FS_FILES; // Get a new file entry and set it up f=allocFileEntry(fn); // Get a new file descriptor and set it up fd = allocFileDesc(f); return fd; } else return ERR_FILE_NOT_FOUND; } else { // File exists... if(flags & OF_TRUNCATE) freeBlocksFromFile(f); fd=allocFileDesc(f); return fd; } } void rdClose(FileDesc fd) { freeFileDesc(fd); } int rdDelete(FileName fn) { int index = findFileIndex(fs.fileTable, fn); if(index == LIST_END){ return ERR_FILE_NOT_FOUND; } //FileEntry f = fs.fileTable[index]; freeFileEntry(index); int i; for(i = 0; i< MAX_OPEN_FILES; i++){ if(fdt[i].f == index){ freeFileDesc(i); } } return NO_ERROR; } int rdGet(FileDesc fd){ int index = fdt[fd].f; int pos = fdt[fd].pos; if(index== NO_FILE){ return ERR_FILE_NOT_FOUND; } FileEntry f = fs.fileTable[index]; if(pos > f.size){ if(pos > rdMaxFileSize()){ return END_OF_FILE; } } BlockPt auxBlck = f.direct; int z=0; int i; for(i=0; i< pos; i++){ if(i != 0 && i%fs.blkSize == 0){ auxBlck = auxBlck->next; z-=fs.blkSize; } else{ z++; } } int c = (int) auxBlck->data[z]; return c; } int rdPut(Byte c, FileDesc fd) { int index = fdt[fd].f; int pos = fdt[fd].pos; if(index== NO_FILE){ return ERR_FILE_NOT_FOUND; } FileEntry f = fs.fileTable[index]; if(pos > f.size){ if(pos > rdMaxFileSize()){ return ERR_NO_SPACE_LEFT_ON_DEVICE; } else{ int al = addBlocks (f, pos - f.size); if(al == ERR_NO_SPACE_LEFT_ON_DEVICE){ return ERR_NO_SPACE_LEFT_ON_DEVICE; } // int indexBlock = (pos/fs.blkSize); // int relativePos = pos % fs.blkSize; } } BlockPt auxBlck = f.direct; int z = 0; int i; for(i=0; i<= pos; i++){ if(i != 0 && i%fs.blkSize == 0){ auxBlck = auxBlck->next; z=0; } else{ z++; } } auxBlck->data[z]= c; return c; } Size rdRead(FileDesc fd, void *buf, Size count) { int index = fdt[fd].f; //int pos = fdt[fd].pos; if(index== NO_FILE){ return ERR_FILE_NOT_FOUND; } //FileEntry f = fs.fileTable[index]; Byte *buff = (Byte*) buf; //int buffSize = sizeof(buff)/sizeof(Byte); int read = 0; FileDescriptor fdAux; int i; for(i=0; i<=count; i++){ fdAux=fdt[fd]; fdAux.pos += i; int status = rdGet(fd); if (status == END_OF_FILE){ return read; } buff[i]=status; read++; } return read; } Size rdWrite(FileDesc fd, const void *buf, Size count) { int index = fdt[fd].f; int pos = fdt[fd].pos; if(index== NO_FILE){ return ERR_FILE_NOT_FOUND; } FileEntry f = fs.fileTable[index]; Byte *buff = (Byte*) buf; //int buffSize = sizeof(buff)/sizeof(Byte); int written = 0; if(pos > f.size){ int i; for(i=f.size; i