void Double_Indirect_Set_Helper(struct Block_Device *dev, GOSFSsuperblock *super, int *array, int index, int blockNum) { int *arr = Safe_Calloc(PAGE_SIZE); int *empty = Safe_Calloc(PAGE_SIZE); int newBlock = 0; if (array[index/INT_ARR_SIZE] == 0) { newBlock = Find_First_Free_Bit(&super->bitmap, super->size); Set_Bit(&super->bitmap, newBlock); array[index/INT_ARR_SIZE] = newBlock; GOSFS_Block_Write(dev, newBlock, empty); } GOSFS_Block_Read(dev, array[index/INT_ARR_SIZE], arr); arr[index % INT_ARR_SIZE] = blockNum; GOSFS_Block_Write(dev, blockNum, empty); GOSFS_Block_Write(dev, array[index/INT_ARR_SIZE], arr); Free(empty); Free(arr); }
int main() { void *bitset = Create_Bit_Set(100); assert(Find_First_Free_Bit(bitset,100) == 0); Set_Bit(bitset, 0); assert(Find_First_Free_Bit(bitset,100) == 1); Set_Bit(bitset, 1); assert(Find_First_Free_Bit(bitset,100) == 2); Set_Bit(bitset, 3); assert(Find_First_Free_Bit(bitset,100) == 2); Set_Bit(bitset, 4); Set_Bit(bitset, 5); Set_Bit(bitset, 6); Set_Bit(bitset, 7); assert(Find_First_Free_Bit(bitset,100) == 2); Set_Bit(bitset, 2); assert(Find_First_Free_Bit(bitset,100) == 8); Clear_Bit(bitset, 2); assert(Find_First_Free_Bit(bitset,100) == 2); }
int Double_Indirect_Helper(struct Block_Device *dev, GOSFSsuperblock *super, int *array, int index) { int blockNum = 0; int tempBlock = 0; int *arr = Safe_Calloc(PAGE_SIZE); int *empty = Safe_Calloc(PAGE_SIZE); if (array[index/INT_ARR_SIZE] == 0) { blockNum = 0; /* Allocate block for double indirect */ tempBlock = Find_First_Free_Bit(&super->bitmap, super->size); Set_Bit(&super->bitmap, tempBlock); array[index/INT_ARR_SIZE] = tempBlock; GOSFS_Block_Write(dev, array[index/INT_ARR_SIZE], empty); } else { GOSFS_Block_Read(dev, array[index/INT_ARR_SIZE], arr); blockNum = arr[index % INT_ARR_SIZE]; } Free(empty); Free(arr); return blockNum; }
/* * Create a directory named by given path. */ int GOSFS_Create_Directory(struct Mount_Point *mountPoint, const char *path) { int rc = 0; int blockNum = 0; // The GOSFS block the fileNode(file or dir) exists in int newBlock = 0; int index = 0; char name[MAX_NAME_SIZE] = {}; bool found = 0; GOSFSfileNode *currNode = 0; GOSFSsuperblock *super = (GOSFSsuperblock *)mountPoint->fsData; GOSFSptr *gosfsEntry = Safe_Calloc(sizeof(GOSFSptr)); GOSFSdirectory *currDir = Safe_Calloc(PAGE_SIZE); /* Grab the root directory from the disk */ GOSFS_Block_Read(mountPoint->dev, super->rootDir, currDir); blockNum = super->rootDir; /* Create all of the directories in the path if they don't exist */ while (*path != 0) { memset(name, '\0', MAX_NAME_SIZE); memset(gosfsEntry, '\0', sizeof(GOSFSptr)); newBlock = 0; currNode = 0; Get_Next_Name_In_Path(&path, name); found = GOSFS_Lookup(currDir, name, blockNum, gosfsEntry); /* If last element in path exists then fail */ if (found == true && *path == 0) { rc = EEXIST; goto fail; } /* If anything in path is a file then fail */ if (found == true && gosfsEntry->node.isDirectory == 0) { rc = ENOTDIR; goto fail; } /* If entry is a directory, then go into it */ if (found == true && gosfsEntry->node.isDirectory == 1) { blockNum = gosfsEntry->node.blocks[0]; GOSFS_Block_Read(mountPoint->dev, blockNum, currDir); continue; } /* If entry does not exist, then make it */ if (found == false) { /* Find the next open spot in the directory */ for (index = 0; index < MAX_FILES_PER_DIR; index++) { currNode = &currDir->files[index]; if (currNode->isUsed == 0) { /* Allocate new GOSFS block for new dir */ newBlock = Find_First_Free_Bit(&super->bitmap, super->size); Set_Bit(&super->bitmap, newBlock); /* Set up new dir */ memcpy(currNode->name, name, MAX_NAME_SIZE); currNode->size = MAX_FILES_PER_DIR; currNode->isUsed = 1; currNode->isDirectory = 1; currNode->blocks[0] = newBlock; /* Write changes to the curr dir back to disk */ GOSFS_Block_Write(mountPoint->dev, blockNum, currDir); memset(currDir, '\0', PAGE_SIZE); // new curr dir empty GOSFS_Block_Write(mountPoint->dev, newBlock, currDir); blockNum = newBlock; break; } /* If no more room in curr dir */ if ((index + 1) == MAX_FILES_PER_DIR) { rc = ENOMEM; goto fail; } } } } /* Write super block back to disk */ GOSFS_Block_Write(mountPoint->dev, 0, super); fail: done: Free(currDir); Free(gosfsEntry); return rc; }
/* * Gets the next block num we need to write to. Also handles setting blocks * array in the node to the new block num */ int Get_Blocknum_To_Write(struct File *file) { int blockNum = 0; int tempBlock = 0; int index = ((int)file->filePos) / PAGE_SIZE; int *array = Safe_Calloc(PAGE_SIZE); void *empty = Safe_Calloc(PAGE_SIZE); GOSFSptr *entry = (GOSFSptr *)file->fsData; GOSFSfileNode *node = &entry->node; GOSFSsuperblock *super = (GOSFSsuperblock *)file->mountPoint->fsData; struct Block_Device *dev = file->mountPoint->dev; /* Return the block num we need to write to, or 0 if it doesn't exist */ if (index < SINGLE_BLOCK) { blockNum = node->blocks[index]; } else if (index > SINGLE_MIN_INDEX && index < SINGLE_MAX_INDEX) { if (node->blocks[SINGLE_BLOCK] == 0) { blockNum = 0; /* Allocate new block for single indirect */ tempBlock = Find_First_Free_Bit(&super->bitmap, super->size); Set_Bit(&super->bitmap, tempBlock); node->blocks[SINGLE_BLOCK] = tempBlock; GOSFS_Block_Write(dev, tempBlock, empty); } else { GOSFS_Block_Read(dev, node->blocks[SINGLE_BLOCK], array); blockNum = array[index - SINGLE_BLOCK]; } } else { if (node->blocks[DBL_BLOCK] == 0) { blockNum = 0; /* Allocate new block for double indirect */ tempBlock = Find_First_Free_Bit(&super->bitmap, super->size); Set_Bit(&super->bitmap, tempBlock); node->blocks[DBL_BLOCK] = tempBlock; GOSFS_Block_Write(dev, tempBlock, empty); } else { GOSFS_Block_Read(dev, node->blocks[DBL_BLOCK], array); blockNum = Double_Indirect_Helper(dev, super, array, index - SINGLE_MAX_INDEX); GOSFS_Block_Write(dev, node->blocks[DBL_BLOCK], array); // In case array changed } } /* If it does not exist than we need to allocate a new block */ if (blockNum == 0) { blockNum = Find_First_Free_Bit(&super->bitmap, super->size); Set_Bit(&super->bitmap, blockNum); // Set the super bit map if (index < SINGLE_BLOCK) { node->blocks[index] = blockNum; GOSFS_Block_Write(dev, node->blocks[index], empty); } else if (index > SINGLE_MIN_INDEX && index < SINGLE_MAX_INDEX) { GOSFS_Block_Read(dev, node->blocks[SINGLE_BLOCK], array); array[index - SINGLE_BLOCK] = blockNum; GOSFS_Block_Write(dev, blockNum, empty); // Write empty array back GOSFS_Block_Write(dev, node->blocks[SINGLE_BLOCK], array); // Write change back } else { GOSFS_Block_Read(dev, node->blocks[DBL_BLOCK], array); Double_Indirect_Set_Helper(dev, super, array, index - SINGLE_MAX_INDEX, blockNum); GOSFS_Block_Write(dev, node->blocks[DBL_BLOCK], array); } } Free(empty); Free(array); return blockNum; }
/* * Create a directory named by given path. */ int GOSFS_Create_Directory(struct Mount_Point *mountPoint, const char *path) { GOSFSinstance *instance = (GOSFSinstance *) mountPoint->fsData; GOSFSfileNode *filePtr = 0; GOSFSdirectory *dir, *newDir; char *file = path, *nextSlash; int rc, offset, i; uint_t parentBlock; /* Malloc data for file node and directory */ newDir = Malloc(sizeof(GOSFSdirectory)); dir = Malloc(sizeof(GOSFSdirectory)); if (dir == 0 || newDir == 0) goto memfail; /* Point to the root directory and read in contents... */ parentBlock = instance->superblock->rootDirPointer; readGOSFSBlock(instance->dev, parentBlock, dir, sizeof(GOSFSdirectory)); /* Iterate until there are no remaining slashes */ while ((nextSlash = strchr(file + 1, '/'))) { /* Ignores leading '/' character */ file += 1; offset = nextSlash - file; filePtr = lookupFileInDirectory(dir, file, offset); if (!filePtr) { /* Need to create a directory */ /* Make sure name is not too long */ if (offset >= sizeof(dir->files[0].name)) goto fail; /* First find a free spot in the directory */ for (i = 0; i < MAX_FILES_PER_DIR; i++) { if (!dir->files[i].isUsed) { offset = i; break; } } if (offset == -1) /* No free space in directory */ goto fail; /* Now set up the file node at that point */ filePtr = &dir->files[i]; memset(filePtr, '\0', sizeof(GOSFSfileNode)); filePtr->isUsed = true; filePtr->isDirectory = true; memcpy(filePtr->name, file, offset); /* Allocate an empty block for this directory */ rc = Find_First_Free_Bit(instance->superblock->freeBlocks, instance->superblock->size); if (rc < 0) goto fail; Set_Bit(instance->superblock->freeBlocks, rc); /* Clear out this new directory */ memset(newDir, '\0', sizeof(GOSFSdirectory)); filePtr->blocks[0] = rc; rc = writeGOSFSBlock(instance->dev, rc, newDir, sizeof(GOSFSdirectory)); if (rc < 0) goto fail; /* Now write out the updated parent directory to disk */ rc = writeGOSFSBlock(instance->dev, parentBlock, dir, sizeof(GOSFSdirectory)); if (rc < 0) goto fail; } if (!filePtr->isDirectory) goto fail; /* Read in the directory this file node represents */ parentBlock = filePtr->blocks[0]; rc = readGOSFSBlock(instance->dev, parentBlock, dir, sizeof(GOSFSdirectory)); if (rc < 0) goto fail; file = nextSlash; } file += 1; /* Make sure this doesn't exist */ filePtr = lookupFileInDirectory(dir, file, strlen(file)); if (filePtr) goto fail; /* Create the final directory */ /* Make sure name is not too long */ if (strlen(file) >= sizeof(dir->files[0].name)) goto fail; /* First find a free spot in the directory */ for (i = 0; i < MAX_FILES_PER_DIR; i++) { if (!dir->files[i].isUsed) { offset = i; break; } } if (offset == -1) /* No free space in directory */ goto fail; /* Now set up the file node at that point */ filePtr = &dir->files[i]; memset(filePtr, '\0', sizeof(GOSFSfileNode)); filePtr->isUsed = true; filePtr->isDirectory = true; memcpy(filePtr->name, file, strlen(file)); /* Allocate an empty block for this directory */ rc = Find_First_Free_Bit(instance->superblock->freeBlocks, instance->superblock->size); if (rc < 0) goto fail; Set_Bit(instance->superblock->freeBlocks, rc); /* Clear out this new directory */ memset(newDir, '\0', sizeof(GOSFSdirectory)); filePtr->blocks[0] = rc; rc = writeGOSFSBlock(instance->dev, rc, newDir, sizeof(GOSFSdirectory)); if (rc < 0) goto fail; /* Now write out the updated directory to disk */ rc = writeGOSFSBlock(instance->dev, parentBlock, dir, sizeof(GOSFSdirectory)); if (rc < 0) goto fail; /* Write out the updated superblock */ rc = writeGOSFSBlock(instance->dev, GOSFS_SUPERBLOCK, instance->superblock, sizeof(GOSFSsuperblock)); if (rc < 0) goto fail; Free(dir); return 0; memfail: rc = ENOMEM; goto fail; fail: if (dir) Free(dir); return rc; }
/* Grows a file by one block (from the end position) and, if necessary, * allocates indirect or double indirect blocks to contain this * new block. */ static int growFile(struct File *file) { GOSFSinstance *instance = (GOSFSinstance *) file->mountPoint->fsData; GOSFSsuperblock *superblock = instance->superblock; GOSFSptr *filePtr = (GOSFSptr *) file->fsData; GOSFSfileNode *node = &filePtr->node; GOSFSdirectory *dir; ulong_t nextBlock = file->endPos / GOSFS_BLOCK_SIZE; char *buf; int *indirect = 0, *doubleIndirect = 0; int rc, newBlock; buf = Malloc(GOSFS_BLOCK_SIZE); indirect = Malloc(GOSFS_BLOCK_SIZE); doubleIndirect = Malloc(GOSFS_BLOCK_SIZE); dir = Malloc(sizeof(GOSFSdirectory)); if (!buf || !indirect || !doubleIndirect || !dir) goto memfail; if (nextBlock < INDIRECT_BLOCK_START) { /* This is a simple direct block */ rc = Find_First_Free_Bit(superblock->freeBlocks, superblock->size); if (rc < 0) goto fail; node->blocks[nextBlock] = rc; newBlock = rc; } else if (nextBlock < DOUBLE_INDIRECT_BLOCK_START) { /* Check for indirect block existence */ if (node->blocks[INDIRECT_BLOCK] == 0) { /* Need to create indirect block */ rc = Find_First_Free_Bit(superblock->freeBlocks, superblock->size); if (rc < 0) goto fail; /* Update (cached) file node */ node->blocks[INDIRECT_BLOCK] = rc; newBlock = rc; /* Write out zero-filled block */ memset(buf, '\0', GOSFS_BLOCK_SIZE); rc = writeGOSFSBlock(instance->dev, newBlock, buf, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; /* Claim bit */ Set_Bit(superblock->freeBlocks, newBlock); /* "Read" indirect block by copying it to array */ memcpy(indirect, buf, GOSFS_BLOCK_SIZE); } else { /* Read in indirect block */ rc = readGOSFSBlock(instance->dev, node->blocks[INDIRECT_BLOCK], indirect, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; } rc = Find_First_Free_Bit(superblock->freeBlocks, superblock->size); if (rc < 0) goto fail; /* Update block array */ indirect[nextBlock - INDIRECT_BLOCK_START] = rc; newBlock = rc; /* Write out updated block array to disk */ rc = writeGOSFSBlock(instance->dev, node->blocks[INDIRECT_BLOCK], indirect, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; } else if (nextBlock < MAX_BLOCK) { /* Check for indirect block existence */ if (node->blocks[DOUBLE_INDIRECT_BLOCK] == 0) { /* Need to create indirect block */ rc = Find_First_Free_Bit(superblock->freeBlocks, superblock->size); if (rc < 0) goto fail; /* Update (cached) file node */ node->blocks[DOUBLE_INDIRECT_BLOCK] = rc; newBlock = rc; /* Write out zero-filled block */ memset(buf, '\0', GOSFS_BLOCK_SIZE); rc = writeGOSFSBlock(instance->dev, newBlock, buf, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; /* Claim bit */ Set_Bit(superblock->freeBlocks, newBlock); /* "Read" indirect block by copying it to array */ memcpy(indirect, buf, GOSFS_BLOCK_SIZE); } else { /* Read in indirect block */ rc = readGOSFSBlock(instance->dev, node->blocks[DOUBLE_INDIRECT_BLOCK], indirect, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; } /* Check for double indirect block existence */ if (indirect[(nextBlock - DOUBLE_INDIRECT_BLOCK_START) / (GOSFS_BLOCK_SIZE / sizeof(int))] == 0) { /* Need to create second indirect block */ rc = Find_First_Free_Bit(superblock->freeBlocks, superblock->size); if (rc < 0) goto fail; /* Update indirect block */ indirect[(nextBlock - DOUBLE_INDIRECT_BLOCK_START) / (GOSFS_BLOCK_SIZE / sizeof(int))] = rc; newBlock = rc; Set_Bit(superblock->freeBlocks, newBlock); /* Write out zero-filled block */ memset(buf, '\0', GOSFS_BLOCK_SIZE); rc = writeGOSFSBlock(instance->dev, newBlock, buf, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; /* Write out updated indirect block */ rc = writeGOSFSBlock(instance->dev, node->blocks[DOUBLE_INDIRECT_BLOCK], indirect, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; /* "Read" double indirect block by copying array */ memcpy(doubleIndirect, buf, GOSFS_BLOCK_SIZE); } else { /* Read in double indirect block */ rc = indirect[(nextBlock - DOUBLE_INDIRECT_BLOCK_START) / (GOSFS_BLOCK_SIZE / sizeof(int))]; rc = readGOSFSBlock(instance->dev, rc, doubleIndirect, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; } /* Now finally we can allocate a block for the double indirect layer */ rc = Find_First_Free_Bit(superblock->freeBlocks, superblock->size); if (rc < 0) goto fail; doubleIndirect[(nextBlock - DOUBLE_INDIRECT_BLOCK_START) % (GOSFS_BLOCK_SIZE / sizeof(int))] = rc; newBlock = rc; /* Write out updated double indirect block */ rc = indirect[(nextBlock - DOUBLE_INDIRECT_BLOCK_START) / (GOSFS_BLOCK_SIZE / sizeof(int))]; rc = writeGOSFSBlock(instance->dev, rc, doubleIndirect, GOSFS_BLOCK_SIZE); if (rc < 0) goto fail; } else { /* This would be triple indirect and above */ rc = EINVALID; goto fail; } /* Now update file node on disk */ rc = readGOSFSBlock(instance->dev, filePtr->blockNum, dir, sizeof(GOSFSdirectory)); if (rc < 0) goto fail; memcpy(&dir->files[filePtr->offset], node, sizeof(GOSFSfileNode)); rc = writeGOSFSBlock(instance->dev, filePtr->blockNum, dir, sizeof(GOSFSdirectory)); Set_Bit(superblock->freeBlocks, newBlock); /* Now update superblock */ rc = writeGOSFSBlock(instance->dev, GOSFS_SUPERBLOCK, superblock, sizeof(GOSFSsuperblock)); if (rc < 0) goto fail; Free(buf); Free(indirect); Free(doubleIndirect); Free(dir); return newBlock; memfail: rc = ENOMEM; goto fail; fail: if (buf) Free(buf); if (indirect) Free(indirect); if (doubleIndirect) Free(doubleIndirect); if (dir) Free(dir); return rc; }