diff --git a/a.out b/a.out deleted file mode 100755 index f376a85..0000000 Binary files a/a.out and /dev/null differ diff --git a/ext2_cp.c b/ext2_cp.c index 9bbec5c..14e9df1 100644 --- a/ext2_cp.c +++ b/ext2_cp.c @@ -11,17 +11,14 @@ #include "utilities.h" unsigned char *disk; -struct ext2_inode *inodeTable; int main(int argc, char **argv) { - int src_fd; + FILE *src_fd; char parentDirPath[EXT2_NAME_LEN]; char fileName[EXT2_NAME_LEN]; - int fileSize; int parentInodeNum, childInodeNum; - struct ext2_inode parentInode, childInode; - struct ext2_dir_entry_2 *dir_entry = NULL; - int total_rec_len; + struct ext2_inode *inodeTable; + struct ext2_inode *parentInode, *childInode; if(argc!=4) { fprintf(stderr, "Usage: ext2_cp \n"); @@ -46,51 +43,60 @@ int main(int argc, char **argv) { // get the parent directory inode strcpy(parentDirPath, argv[3]); if (parentDirPath[0]!='/') { - fprintf(stderr, "No such file or directory\n"); + fprintf(stderr, "Must be absolute path\n"); return ENOENT; + } else if (parentDirPath[1]=='\0'){ + fprintf(stderr, "Destination cannot be root directory\n"); + return EEXIST; } else { getParentDirPath(parentDirPath); } - parentInodeNum = getInodeFromPath(getParentDirPath); + parentInodeNum = getInodeFromPath(parentDirPath); if (parentInodeNum == 0) { fprintf(stderr, "No such file or directory\n"); return ENOENT; } - parentInode = inodeTable[parentInodeNum-1]; + parentInode = &inodeTable[parentInodeNum-1]; // check file exist getFileNameFromPath(fileName, argv[3]); - childInodeNum = searchFileInDir(&parentInode, fileName); - if (parentInodeNum != 0) { + childInodeNum = searchFileInDir(parentInode, fileName); + if (childInodeNum != 0) { fprintf(stderr, "File or directory already exist\n"); return EEXIST; } // create file and cp - childInodeNum = initInode('f'); - unsigned int *singleIndirect; + childInodeNum = initInode(EXT2_S_IFREG); + childInode = &inodeTable[childInodeNum-1]; + unsigned int *singleIndirect = NULL; int nextBlockNum, byteRead; + int fileSize = 0; int i = 0; - while (feof(src_fd)) { - nextBlockNum = allocateBlock(); + while (!feof(src_fd)) { + nextBlockNum = allocateNewBlock(); if (i<12) { - inodeTable[childInodeNum].i_block[i] = nextBlockNum; + childInode->i_block[i] = nextBlockNum; } else if (i==12) { - inodeTable[childInodeNum].i_block[i] = nextBlockNum; - singleIndirect = getBlock(nextBlockNum); - nextBlockNum = allocateBlock(); + childInode->i_block[i] = nextBlockNum; + singleIndirect = initSingleIndirect(nextBlockNum); + i++; + continue; } else { singleIndirect[i-13] = nextBlockNum; } - byteRead = fread(getBlock(nextBlockNum), 1024, 1, src_fd); + byteRead = fread(getBlock(nextBlockNum), 1, 1024, src_fd); fileSize += byteRead; i++; } - // uptate inode filed - inodeTable[childInodeNum].i_size = fileSize; - inodeTable[childInodeNum].i_blocks = (fileSize+511)/512; - + fclose(src_fd); + // update inode fields + childInode->i_size = fileSize; + if (singleIndirect == NULL) + childInode->i_blocks = ((fileSize+1023)/1024)*2; + else + childInode->i_blocks = ((fileSize+1023)/1024+1)*2; // add dir_entry fot this file into parent dir - allocateNewDirent(&parentInode, childInodeNum, 'f', fileName); + initNewDirent(parentInode, childInodeNum, EXT2_FT_REG_FILE, fileName); } \ No newline at end of file diff --git a/ext2_ln.c b/ext2_ln.c index c6eefa1..9f44734 100644 --- a/ext2_ln.c +++ b/ext2_ln.c @@ -5,10 +5,134 @@ #include #include #include +#include +#include #include "ext2.h" +#include "utilities.h" unsigned char *disk; +struct ext2_inode *inodeTable; int main(int argc, char **argv) { + + char pathTo[EXT2_NAME_LEN]; + char pathFrom[EXT2_NAME_LEN]; + char pathToCopy[EXT2_NAME_LEN]; + char pathFromCopy[EXT2_NAME_LEN]; + char parentOfPathFrom[EXT2_NAME_LEN]; + char linkName[EXT2_NAME_LEN]; + + int flagged = FALSE; + int inodeNum, parentInodeNum, childInodeNum; + + struct ext2_inode *targetInode, *parentInode, *childInode; + + if(argc!=4 && argc!=5) { + fprintf(stderr, "Usage: ext2_ln \n"); + exit(1); + } + + // read disk and get inode table + int fd = open(argv[1], O_RDWR); + disk = mmap(NULL, 128 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(disk == MAP_FAILED) { + perror("mmap"); + exit(1); + } + inodeTable = getInodeTable(); + + // read other arguments + if(argc == 4) { + strcpy(pathTo, argv[2]); + strcpy(pathFrom, argv[3]); + } else { + if (strcmp(argv[2], "-s") != 0) { + fprintf(stderr, "Invalid Flag\n"); + exit(1); + } + flagged = TRUE; + strcpy(pathTo, argv[3]); + strcpy(pathFrom, argv[4]); + } + + // get the inode from pathTo + strcpy(pathToCopy, pathTo); + if (pathToCopy[0]!='/') { + perror("Invalid path argument"); + fprintf(stderr, "No such file or directory\n"); + return ENOENT; + } else { + inodeNum = getInodeFromPath(pathToCopy); + } + + if (inodeNum == 0) { + fprintf(stderr, "No such file or directory\n"); + return ENOENT; + } + targetInode = &inodeTable[inodeNum-1]; + if (targetInode->i_mode & EXT2_S_IFDIR){ + fprintf(stderr, "No link to a directory\n"); + return EISDIR; + } + + // get the upper level inode from pathFrom + strcpy(pathFromCopy, pathFrom); + strcpy(parentOfPathFrom, pathFrom); + + if (parentOfPathFrom[0]!='/') { + perror("Invalid parentDirPath"); + fprintf(stderr, "No such file or directory\n"); + return ENOENT; + } else if (parentOfPathFrom[1]=='\0'){ + fprintf(stderr, "No link from a directory\n"); + return EISDIR; + } else { + getParentDirPath(parentOfPathFrom); + } + + parentInodeNum = getInodeFromPath(parentOfPathFrom); + if (parentInodeNum == 0) { + perror("parentDirPath not exist"); + fprintf(stderr, "No such file or directory\n"); + return ENOENT; + } + parentInode = &inodeTable[parentInodeNum-1]; + + // check whether the link has already existed + getFileNameFromPath(linkName, pathFromCopy); + childInodeNum = searchFileInDir(parentInode, linkName); + if (childInodeNum != 0) { + fprintf(stderr, "File or directory already exist\n"); + return EEXIST; + } + + if (!flagged){ + + // implementation for the hard link + initNewDirent(parentInode, inodeNum, EXT2_FT_REG_FILE, linkName); + // increment the link count of the target inode + targetInode->i_links_count++; + + }else{ + + // implementation for the symbolic link + childInodeNum = initInode(EXT2_S_IFLNK); + childInode = &inodeTable[childInodeNum-1]; + childInode->i_size = strlen(pathFromCopy); + childInode->i_blocks = 0; + + initNewDirent(parentInode, childInodeNum, EXT2_FT_SYMLINK, linkName); + + if (childInode->i_size <= 60){ + strncpy((char *)childInode->i_block, pathTo, 60); + }else{ + // append path to the inode block + int block_num = allocateNewBlock(); + strcpy((char *)getBlock(block_num), pathTo); + childInode->i_block[0] = block_num; + } + + } + return 0; -} \ No newline at end of file +} diff --git a/ext2_ls.c b/ext2_ls.c index 1cbfbe1..6209486 100644 --- a/ext2_ls.c +++ b/ext2_ls.c @@ -17,11 +17,8 @@ int main(int argc, char **argv) { char path[EXT2_NAME_LEN]; char pathCopy[EXT2_NAME_LEN]; char fileName[EXT2_NAME_LEN]; - int flagged = FALSE; + int flagged = 0; struct ext2_inode inode; - struct ext2_dir_entry_2 *dir_entry = NULL; - int total_rec_len; - unsigned char *singleIndirect; if(argc!=3 && argc!=4) { fprintf(stderr, "Usage: ext2_ls \n"); @@ -45,7 +42,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Invalid Flag\n"); exit(1); } - flagged = TRUE; + flagged = 1; strcpy(path, argv[3]); } @@ -57,22 +54,32 @@ int main(int argc, char **argv) { return ENOENT; } inode = inodeTable[inodeNum-1]; - + // print all file nemes in directory data block if (inode.i_mode & EXT2_S_IFDIR) { + struct ext2_dir_entry_2 *dir_entry = NULL; + unsigned int *singleIndirect = NULL; + int total_rec_len = 0; // print file names in direct blocks - for (int i=0; i<12; i++) { - if (inode.i_block[i] == 0){ + for (int i=0; i<13+EXT2_BLOCK_SIZE/4; i++) { + + if (i<12) { + if (inode.i_block[i] == 0) continue; + dir_entry = (struct ext2_dir_entry_2 *)getBlock(inode.i_block[i]); + } else if (i==12) { + if (inode.i_block[i] == 0) break; + singleIndirect = (unsigned int *)getBlock(inode.i_block[12]); continue; } else { - dir_entry = (struct ext2_dir_entry_2 *)getBlock(inode.i_block[i]); + if (singleIndirect[i-13] == 0) continue; + dir_entry = (struct ext2_dir_entry_2 *)getBlock(singleIndirect[i-13]); } - + // for each dir entry in the block total_rec_len = 0; while (total_rec_len < EXT2_BLOCK_SIZE) { - if (dir_entry->name[0]!='.' || flagged) { + if ((dir_entry->name[0]!='.' || flagged) && (dir_entry->name_len!=0)) { printf("%s\n", dir_entry->name); } total_rec_len = total_rec_len + dir_entry->rec_len; @@ -80,27 +87,6 @@ int main(int argc, char **argv) { } } - // print file in single indirect blocks - if (inode.i_block[12] != 0) { - singleIndirect = getBlock(inode.i_block[12]); - for(int i = 0; iname[0]!='.' || flagged) { - printf("%s\n", dir_entry->name); - } - total_rec_len = total_rec_len + dir_entry->rec_len; - dir_entry = (void *) dir_entry + dir_entry->rec_len; - } - } - } - // print file name } else if (inode.i_mode&EXT2_S_IFREG || inode.i_mode&EXT2_S_IFLNK) { getFileNameFromPath(fileName, path); diff --git a/ext2_mkdir.c b/ext2_mkdir.c index 7cbac38..adce85b 100644 --- a/ext2_mkdir.c +++ b/ext2_mkdir.c @@ -5,13 +5,85 @@ #include #include #include -#include #include "ext2.h" +#include +#include #include "utilities.h" unsigned char *disk; int main(int argc, char **argv) { - + char path[EXT2_NAME_LEN]; + char pathCopy[EXT2_NAME_LEN]; + char dirName[EXT2_NAME_LEN]; + struct ext2_inode *parent_inode, *inode_table, *target_inode; + + if(argc!=3) { + fprintf(stderr, "Usage: ./ext2_mkdir \n"); + exit(1); + } + int fd = open(argv[1], O_RDWR); + + // read disk and get inode table + disk = mmap(NULL, 128 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(disk == MAP_FAILED) { + perror("mmap"); + exit(1); + } + + strcpy(path, argv[2]); + strcpy(pathCopy, argv[2]); + // if input is root, return EEXIST + if (strcmp(pathCopy, "/") == 0) { + fprintf(stderr, "Specified directory already exists\n"); + return EEXIST; + } + // get the parent directory of the specified directory + getParentDirPath(pathCopy); + int parent_inode_num = getInodeFromPath(pathCopy); + // if any component on the path of parent directory does not exist, + // return ENOENT + if (parent_inode_num == 0) { + fprintf(stderr, "One of the components on the path does not exist\n"); + return ENOENT; + } + + // get the parent directory inode + inode_table = getInodeTable(); + parent_inode = &inode_table[parent_inode_num-1]; + // get the directory name from input + strcpy(pathCopy, path); + getFileNameFromPath(dirName, pathCopy); + int target_inode_num = searchFileInDir(parent_inode, dirName); + // if specified dir already exists, return EEXIST + if (target_inode_num != 0) { + fprintf(stderr, "Specified directory already exists\n"); + return EEXIST; + } + + // initialize an inode for the specified directory + target_inode_num = initInode(EXT2_S_IFDIR); + target_inode = &inode_table[target_inode_num-1]; + //create an directory entry for the specified directory + initNewDirent(parent_inode, target_inode_num, EXT2_FT_DIR, dirName); + + // allocate a new block for the specified directory + int newBlockNum = allocateNewBlock(); + target_inode->i_block[0] = newBlockNum; + struct ext2_dir_entry_2 *firstDirent = (struct ext2_dir_entry_2 *)getBlock(newBlockNum); + // initialize the data block information for the target directory + firstDirent->file_type = EXT2_FT_DIR; + firstDirent->inode = target_inode_num; + // create an entry for . + strcpy(firstDirent->name, "."); + firstDirent->name_len = 1; + firstDirent->rec_len = EXT2_BLOCK_SIZE; + // create an entry for .. + initNewDirent(target_inode, parent_inode_num, EXT2_FT_DIR, ".."); + + // update the revelent information + getGroupDesc()->bg_used_dirs_count++; + parent_inode->i_links_count++; + target_inode->i_links_count = 2; return 0; -} \ No newline at end of file +} diff --git a/ext2_rm.c b/ext2_rm.c index c6eefa1..a916024 100644 --- a/ext2_rm.c +++ b/ext2_rm.c @@ -5,10 +5,73 @@ #include #include #include +#include +#include #include "ext2.h" +#include "utilities.h" unsigned char *disk; int main(int argc, char **argv) { - return 0; + char parentDirPath[EXT2_NAME_LEN]; + char fileName[EXT2_NAME_LEN]; + int parentInodeNum, childInodeNum; + struct ext2_inode *inodeTable; + struct ext2_inode *parentInode, *childInode; + + if(argc!=3) { + fprintf(stderr, "Usage: ext2_rm \n"); + exit(1); + } + + // read disk and get inode table + int fd = open(argv[1], O_RDWR); + disk = mmap(NULL, 128 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(disk == MAP_FAILED) { + perror("mmap"); + exit(1); + } + inodeTable = getInodeTable(); + + // get the parent directory inode + strcpy(parentDirPath, argv[2]); + // if it's not a absolute path + if (parentDirPath[0]!='/') { + fprintf(stderr, "Must be an absolute path\n"); + return ENOENT; + // if it's a root directory + } else if (parentDirPath[1]=='\0'){ + fprintf(stderr, "Cannot remove root directory\n"); + return ENOENT; + // general case + } else { + getParentDirPath(parentDirPath); + } + parentInodeNum = getInodeFromPath(parentDirPath); + if (parentInodeNum == 0) { + fprintf(stderr, "No such file or directory\n"); + return ENOENT; + } + parentInode = &inodeTable[parentInodeNum-1]; + + // check file exist + getFileNameFromPath(fileName, argv[2]); + if (strcmp(fileName, ".") == 0 || strcmp(fileName, "..") == 0){ + fprintf(stderr, "Cannot remove . or ..\n"); + return ENOENT; + } + childInodeNum = searchFileInDir(parentInode, fileName); + if (childInodeNum == 0) { + fprintf(stderr, "No such file or directory\n"); + return ENOENT; + } + childInode = &inodeTable[childInodeNum-1]; + + // if the file is a directory + if (childInode->i_mode & EXT2_S_IFDIR) { + fprintf(stderr, "Cannot remove a directory\n"); + return ENOENT; + } + + rm(parentInode, fileName); } \ No newline at end of file diff --git a/ext2_rm_bonus.c b/ext2_rm_bonus.c index c6eefa1..8c4954b 100644 --- a/ext2_rm_bonus.c +++ b/ext2_rm_bonus.c @@ -5,10 +5,84 @@ #include #include #include +#include +#include #include "ext2.h" +#include "utilities.h" unsigned char *disk; int main(int argc, char **argv) { - return 0; + char parentDirPath[EXT2_NAME_LEN]; + char parentDirPathCopy[EXT2_NAME_LEN]; + char fileName[EXT2_NAME_LEN]; + int parentInodeNum, childInodeNum; + struct ext2_inode *inodeTable; + struct ext2_inode *parentInode, *childInode; + int flagged = 0; + + if(argc!=3 && argc!=4) { + fprintf(stderr, "Usage: ext2_rm \n"); + exit(1); + } + + // read disk and get inode table + int fd = open(argv[1], O_RDWR); + disk = mmap(NULL, 128 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(disk == MAP_FAILED) { + perror("mmap"); + exit(1); + } + inodeTable = getInodeTable(); + + // read other arguments + if(argc == 3) { + strcpy(parentDirPath, argv[2]); + } else { + if (strcmp(argv[2], "-r")!=0) { + fprintf(stderr, "Invalid Flag\n"); + exit(1); + } + flagged = 1; + strcpy(parentDirPath, argv[3]); + } + strcpy(parentDirPathCopy, parentDirPath); + + // get the parent directory inode + if (parentDirPath[0]!='/') { + fprintf(stderr, "Must be an absolute path\n"); + return ENOENT; + } else if (parentDirPath[1]=='\0'){ + fprintf(stderr, "Cannot remove root directory\n"); + return ENOENT; + } else { + getParentDirPath(parentDirPath); + } + parentInodeNum = getInodeFromPath(parentDirPath); + if (parentInodeNum == 0) { + fprintf(stderr, "No such file or directory\n"); + return ENOENT; + } + parentInode = &inodeTable[parentInodeNum-1]; + + // check file exist + getFileNameFromPath(fileName, parentDirPathCopy); + if (strcmp(fileName, ".") == 0 || strcmp(fileName, "..") == 0){ + fprintf(stderr, "Cannot remove . or ..\n"); + return ENOENT; + } + childInodeNum = searchFileInDir(parentInode, fileName); + if (childInodeNum == 0) { + fprintf(stderr, "No such file or directory\n"); + return ENOENT; + } + childInode = &inodeTable[childInodeNum-1]; + + // if the file is a directory + if ((childInode->i_mode & EXT2_S_IFDIR) && !flagged){ + fprintf(stderr, "Cannot remove a directory without -r flag\n"); + return ENOENT; + } + + rm(parentInode, fileName); } \ No newline at end of file diff --git a/readimage.c b/readimage.c index 0251ac3..3f3af72 100644 --- a/readimage.c +++ b/readimage.c @@ -40,8 +40,8 @@ int main(int argc, char **argv) { // task1, print bitmap int i,j; - char unsigned *block_bitmap = getBlockBitmap(); - char unsigned *inode_bitmap = getInodeBitmap(); + char unsigned *block_bitmap = getBitmap(BLOCK_BITMAP); + char unsigned *inode_bitmap = getBitmap(INODE_BITMAP); printf("Block bitmap:"); for (i=0; is_blocks_count/8; i++) { printf(" "); @@ -86,7 +86,8 @@ int main(int argc, char **argv) { // task3, print directory enties char type='\0'; - struct ext2_dir_entry_2 *dir_entries; + struct ext2_dir_entry_2 *dir_entry; + int total_rec_len; printf("Directory Blocks:\n"); for(i = 0; i < sb->s_inodes_count; i++) { @@ -97,23 +98,32 @@ int main(int argc, char **argv) { if (!(inodeTable[i].i_mode & EXT2_S_IFDIR)) continue; - printf("\tDIR BLOCK NUM: %d (for inode %d)\n", inodeTable[i].i_block[0], i+1); - dir_entries = (struct ext2_dir_entry_2 *)getBlock(inodeTable[i].i_block[0]); - // while not hit the end og the block - while ((int)dir_entries < (int)(disk+(inodeTable[i].i_block[0]+1)*EXT2_BLOCK_SIZE)) { - if (dir_entries->file_type == EXT2_FT_UNKNOWN) - type = 'u'; - else if (dir_entries->file_type == EXT2_FT_REG_FILE) - type = 'f'; - else if (dir_entries->file_type == EXT2_FT_DIR) - type = 'd'; - else if (dir_entries->file_type == EXT2_FT_SYMLINK) - type = 'l'; - printf("Inode: %d rec_len: %d name_len: %d type= %c name=%s\n", dir_entries->inode, dir_entries->rec_len, dir_entries->name_len, type, dir_entries->name); - dir_entries = (void *) dir_entries + dir_entries->rec_len; - } + for (int j=0; j<12; j++) { + if (inodeTable[i].i_block[j] == 0) continue; + printf("\tDIR BLOCK NUM: %d (for inode %d)\n", inodeTable[i].i_block[j], i+1); + dir_entry = (struct ext2_dir_entry_2 *)getBlock(inodeTable[i].i_block[j]); + + // while not hit the end of the block + total_rec_len = 0; + while (total_rec_len < EXT2_BLOCK_SIZE) { + if (dir_entry->file_type == EXT2_FT_UNKNOWN) + type = 'u'; + else if (dir_entry->file_type == EXT2_FT_REG_FILE) + type = 'f'; + else if (dir_entry->file_type == EXT2_FT_DIR) + type = 'd'; + else if (dir_entry->file_type == EXT2_FT_SYMLINK) + type = 'l'; + if (dir_entry->name_len != 0) + printf("Inode: %d rec_len: %d name_len: %d type= %c name=%s\n", dir_entry->inode, dir_entry->rec_len, dir_entry->name_len, type, dir_entry->name); + total_rec_len = total_rec_len + dir_entry->rec_len; + dir_entry = (void *) dir_entry + dir_entry->rec_len; + } + } } } + + return 0; } diff --git a/test.sh b/test.sh deleted file mode 100755 index e42194f..0000000 --- a/test.sh +++ /dev/null @@ -1,42 +0,0 @@ -#./readimage twolevel.img - -# ls -echo "-----test root: <<<./ext2_ls twolevel.img />>>-----" -./ext2_ls twolevel.img / - -echo "-----test root with flag: <<<./ext2_ls twolevel.img -a />>>-----" -./ext2_ls twolevel.img -a / - -echo "-----test afile: <<<./ext2_ls twolevel.img /afile>>>-----" -./ext2_ls twolevel.img /afile - -echo "-----test afile, <<>>-----" -./ext2_ls twolevel.img -a /afile - -echo "-----test afile, this should fail: <<<./ext2_ls twolevel.img -a /afile/>>>-----" -./ext2_ls twolevel.img -a /afile/ - -echo "-----test level1: <<<./ext2_ls twolevel.img /level1>>>-----" -./ext2_ls twolevel.img /level1 - -echo "-----test level 1 end with '/': <<<./ext2_ls twolevel.img -a /level1/>>>-----" -./ext2_ls twolevel.img -a /level1/ - -echo "-----test level2: <<<./ext2_ls twolevel.img -a /level1/level2>>>-----" -./ext2_ls twolevel.img -a /level1/level2 - -echo "-----test bfile: <<<./ext2_ls twolevel.img -a /level1/level2/bfile>>>-----" -./ext2_ls twolevel.img -a /level1/level2/bfile - -echo "-----test bfile, this should fail: <<<./ext2_ls twolevel.img -a /level1/level2/bfile/>>>-----" -./ext2_ls twolevel.img -a /level1/level2/bfile/ - -echo "-----test non-exist path, this should fail: <<<./ext2_ls twolevel.img -a /level1/level2/cfile>>>-----" -./ext2_ls twolevel.img -a /level1/level2/cfile - -echo "-----test no input image file, this should fail: <<<./ext2_ls twolevel.img>>>-----" -./ext2_ls twolevel.img - -# note: the bfilee.s file in the disk contain an 16 character! below testcase should actually fail -echo "-----test print a file name, this should work but fail: <<<./ext2_ls onedirectory.img /level1/bfilee.s>>>-----" -./ext2_ls onedirectory.img /level1/bfilee.s diff --git a/utilities.c b/utilities.c index e2c5523..0faaa60 100644 --- a/utilities.c +++ b/utilities.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "ext2.h" #include "utilities.h" @@ -19,22 +20,31 @@ struct ext2_group_desc *getGroupDesc() { } // bitmaps, bit -char unsigned *getBlockBitmap() { +char unsigned *getBitmap(int bitmapNum) { struct ext2_group_desc *gd = getGroupDesc(); - return (char unsigned *)(disk+gd->bg_block_bitmap*EXT2_BLOCK_SIZE); -} - -char unsigned *getInodeBitmap() { - struct ext2_group_desc *gd = getGroupDesc(); - return (char unsigned *)(disk+gd->bg_inode_bitmap*EXT2_BLOCK_SIZE); + if (bitmapNum == INODE_BITMAP) + return (char unsigned *)(disk+gd->bg_inode_bitmap*EXT2_BLOCK_SIZE); + else if (bitmapNum == BLOCK_BITMAP) + return (char unsigned *)(disk+gd->bg_block_bitmap*EXT2_BLOCK_SIZE); + return NULL; } -int getBit(char unsigned * bitmap, int index) { +int getBit(char unsigned *bitmap, int index) { return (bitmap[index/8]>>index%8)&1; } -int getFirstEmptyBitIndex(char unsigned * bitmap, int maxLength) { - int index = 0; +int getFirstEmptyBitIndex(int bitmapNum) { + int index, maxLength; + unsigned char *bitmap; + if (bitmapNum == INODE_BITMAP) { + index = EXT2_GOOD_OLD_FIRST_INO; + maxLength = getSuperblock()->s_inodes_count; + bitmap = getBitmap(INODE_BITMAP); + } else { + index = 0; + maxLength = getSuperblock()->s_blocks_count; + bitmap = getBitmap(BLOCK_BITMAP); + } while (index < maxLength) { if (getBit(bitmap, index) == 0) { return index; @@ -52,7 +62,6 @@ void changeBitmap(char unsigned *bitmap, int idx, char mode) { turn_on = turn_on << idx%8; turn_off = ~(turn_off << idx%8); - if (mode == 'a'){ // turning on the bit bitmap[idx/8] = bitmap[idx/8] | turn_on; @@ -68,15 +77,23 @@ struct ext2_inode *getInodeTable() { return (struct ext2_inode *)(disk+gd->bg_inode_table*EXT2_BLOCK_SIZE); } +struct ext2_inode *getInode(int inodeNum) { + struct ext2_inode *inodeTable = getInodeTable(); + return &inodeTable[inodeNum-1]; +} -int initInode(char mode) { +/** + * return new intialized inode number + */ +int initInode(unsigned short mode) { // find the first free inode - int index = getFirstEmptyBitIndex(getInodeBitmap(), getSuperblock()->s_inodes_count); + int index = getFirstEmptyBitIndex(INODE_BITMAP); - // change its bitmap - char unsigned *bitmap = getInodeBitmap(); + // change its bitmap and update field in gd + char unsigned *bitmap = getBitmap(INODE_BITMAP); changeBitmap(bitmap, index, 'a'); + getGroupDesc()->bg_free_inodes_count--; // initialize inode attribute struct ext2_inode *inode_table = getInodeTable(); @@ -87,142 +104,127 @@ int initInode(char mode) { for(int i=0; i<15; i++) { inode_table[index].i_block[i] = 0; } - return index; + + // set creation time for this inode + inode_table[index].i_ctime = time(NULL); + return index+1; } -void deleteInode(int index) { +void deleteInode(int inodeNum) { - char unsigned *inode_bitmap = getInodeBitmap(); - char unsigned *block_bitmap = getBlockBitmap(); - - // change inode bitmap - changeBitmap(inode_bitmap, index, 'd'); + char unsigned *inode_bitmap = getBitmap(INODE_BITMAP); + char unsigned *block_bitmap = getBitmap(BLOCK_BITMAP); + // delete inode + changeBitmap(inode_bitmap, inodeNum-1, 'd'); + getGroupDesc()->bg_free_inodes_count++; struct ext2_inode *inode_table = getInodeTable(); - struct ext2_inode target = inode_table[index]; - - // delete the block bitmap + struct ext2_inode *target = &inode_table[inodeNum-1]; + target->i_dtime = time(NULL); + + // delete block int i; - int block_num; for(i = 0; i<12;i++) { - block_num = target.i_block[i]; - changeBitmap(block_bitmap, block_num, 'd'); + if (target->i_block[i] != 0) { + changeBitmap(block_bitmap, target->i_block[i]-1, 'd'); + getGroupDesc()->bg_free_blocks_count++; + } } + // delete single indirect - int bp = target.i_block[12]; + int bp = target->i_block[12]; if (bp != 0) { - unsigned char *single = getBlock(bp); - i=0; - while(single[i] != 0) { - changeBitmap(block_bitmap, single[i], 'd'); - i++; - } + // delete blocks in single + unsigned int *single = (unsigned int*)getBlock(bp); + for (int i=0; ibg_free_blocks_count++; + } + } + // delte single itself + changeBitmap(block_bitmap, target->i_block[12]-1, 'd'); + getGroupDesc()->bg_free_blocks_count++; } } // block char unsigned *getBlock(int blockNum) { + // block index start at 1, so block Number == block Index + // since "block[0]" is allocated for superblock return (char unsigned*)(disk+blockNum*EXT2_BLOCK_SIZE); } +/** + * return new allocated block number + */ int allocateNewBlock() { - int index = getFirstEmptyBitIndex(getBlockBitmap(), getSuperblock()->s_blocks_count); - changeBitmap(getBlockBitmap(), index, 'a'); - return index; + int index = getFirstEmptyBitIndex(BLOCK_BITMAP); + changeBitmap(getBitmap(BLOCK_BITMAP), index, 'a'); + getGroupDesc()->bg_free_blocks_count--; + return index+1; } // dir_entry -int searchFileInDir(struct ext2_inode *inode, char *fileName) { - /* - * return inode number of file if the file is found, o/w return 0 - */ - struct ext2_dir_entry_2 * dir_entry; - int total_rec_len; - unsigned int *singleIndirect; - - // first argument must be directory type - assert(inode->i_mode & EXT2_S_IFDIR); - - // search in direct block - for (int i=0; i<12; i++) { - if (inode->i_block[i] == 0) { - continue; - } else { - dir_entry = (struct ext2_dir_entry_2 *)getBlock(inode->i_block[i]); - } - - // for each dir entry in the block - total_rec_len = 0; - while (total_rec_len < EXT2_BLOCK_SIZE) { - if(strcmp(dir_entry->name, fileName)==0) { - return dir_entry->inode; - } - total_rec_len = total_rec_len + dir_entry->rec_len; - dir_entry = (void *) dir_entry + dir_entry->rec_len; - } - } - // search in single indirect block - if (inode->i_block[12] != 0) { - // for each block number in single indirect block - singleIndirect = getBlock(inode->i_block[12]); - for(int i = 0; iname, fileName)==0) { - return dir_entry->inode; - } - total_rec_len = total_rec_len + dir_entry->rec_len; - dir_entry = (void *) dir_entry + dir_entry->rec_len; - } - } +int searchFileInDir(struct ext2_inode *parentInode, char *childFileName) { + /** + * return inode num if childFile is found, o/w 0 + */ + struct ext2_dir_entry_2 *cur_dir_entry = NULL; + struct ext2_dir_entry_2 *pre_dir_entry = getPreDirent(parentInode, childFileName); + if (strcmp(childFileName, ".") == 0) { + return ((struct ext2_dir_entry_2 *)getBlock(parentInode->i_block[0]))->inode; } + else if (pre_dir_entry != NULL) { + cur_dir_entry = (void *)pre_dir_entry + pre_dir_entry->rec_len; + return cur_dir_entry->inode; + } return 0; } int calculateActuralSize(struct ext2_dir_entry_2 *dirent) { - return sizeof(struct ext2_dir_entry_2) + ((dirent->name_len+4)/4)*4; + return ((sizeof(struct ext2_dir_entry_2)+(dirent->name_len+4))/4)*4; } -struct ext2_dir_entry_2 *initDirent(struct ext2_inode *parent_inode, int size) { - int total_rec_len; - int residue_len, actural_len; - struct ext2_dir_entry_2 *dir_entry; - struct ext2_dir_entry_2 *new_dir_entry; - unsigned int *singleIndirect; - - // search in direct block +struct ext2_dir_entry_2 *allocateNewDirent(struct ext2_inode *parent_inode, int size) { + struct ext2_dir_entry_2 *new_dir_entry = NULL; + // search in all used direct block for(int i = 0; i<12;i++) { - if (parent_inode->i_block[i] == 0) - continue; - new_dir_entry = initDirentDDB(parent_inode->i_block[i], size); - if (new_dir_entry!=NULL) - return new_dir_entry; - } - // search in single indirect block - if (parent_inode->i_block[12] != 0); - { - // for each block number in single indirect block - singleIndirect = getBlock(parent_inode->i_block[12]); - for(int i = 0; ii_block[i] != 0) { + new_dir_entry = allocateDirentHelper(parent_inode->i_block[i], size); if (new_dir_entry!=NULL) return new_dir_entry; } } + + // if we cannot find a space, try to allocate a new block + int newBlockNum = 0; + for(int i = 0; i<12;i++) { + if (parent_inode->i_block[i] != 0) continue; + newBlockNum = allocateNewBlock(); + parent_inode->i_block[i] = newBlockNum; + + // increse parentdir size + parent_inode->i_blocks+=(EXT2_BLOCK_SIZE+511)/512; + parent_inode->i_size+=EXT2_BLOCK_SIZE; + + // insert dummy head + new_dir_entry = (struct ext2_dir_entry_2 *)getBlock(newBlockNum); + new_dir_entry->file_type = EXT2_FT_UNKNOWN; + new_dir_entry->inode = 0; + new_dir_entry->name_len = 0; + new_dir_entry->rec_len = ((sizeof(struct ext2_dir_entry_2)+3)/4)*4; + + // return new setted dir_entry + new_dir_entry = (void *)new_dir_entry + new_dir_entry->rec_len; + new_dir_entry->rec_len=EXT2_BLOCK_SIZE-((sizeof(struct ext2_dir_entry_2)+3)/4)*4; + return new_dir_entry; + } return NULL; } -struct ext2_dir_entry_2 *initDirentDDB(int blockNum, int size) { +struct ext2_dir_entry_2 *allocateDirentHelper(int blockNum, int size) { /* * Helper function for initDirent */ @@ -247,25 +249,33 @@ struct ext2_dir_entry_2 *initDirentDDB(int blockNum, int size) { return NULL; } -struct ext2_dir_entry_2 *allocateNewDirent(struct ext2_inode *parentInode, int childInodeNum, char type, char *fileName) { +struct ext2_dir_entry_2 *initNewDirent(struct ext2_inode *parentInode, int childInodeNum, int type, char *fileName) { int name_len, size; struct ext2_dir_entry_2 *newDirent; // calculate actual size required for new dir_entry - int name_len = strlen(fileName); - int size = sizeof(struct ext2_dir_entry_2) + ((name_len+4)/4)*4; + name_len = strlen(fileName); + size = sizeof(struct ext2_dir_entry_2) + ((name_len+4)/4)*4; // allocate new dir_entry in parent directory - newDirent = initDirent(parentInode, size); + newDirent = allocateNewDirent(parentInode, size); // initialize new dir_entry newDirent->inode = childInodeNum; newDirent->file_type = type; - newDirent->name_len = strlen; + newDirent->name_len = (unsigned char) name_len; strcpy(newDirent->name, fileName); return newDirent; } +unsigned int *initSingleIndirect(int blockNum) { + unsigned int *singleIndirect = (unsigned int *)getBlock(blockNum); + for (int i=0; i<(EXT2_BLOCK_SIZE/4); i++) { + singleIndirect[i] = 0; + } + return singleIndirect; +} + // path handling int getInodeFromPath(char *path) { /* @@ -273,7 +283,7 @@ int getInodeFromPath(char *path) { */ struct ext2_inode *inodeTable = getInodeTable(); int inode_num = EXT2_ROOT_INO; - struct ext2_inode cur_inode = inodeTable[inode_num-1]; + struct ext2_inode *cur_inode = &inodeTable[inode_num-1]; char *next_file; int endWithDir = path[strlen(path)-1] == '/'; // is path endwith '/' ? @@ -286,16 +296,16 @@ int getInodeFromPath(char *path) { next_file = strtok(path, "/"); while(next_file != NULL) { // cannot have a non-directory type file in the middle of path - if (!(cur_inode.i_mode & EXT2_S_IFDIR)) { + if (!(cur_inode->i_mode & EXT2_S_IFDIR)) { // Invalid path; non-dir type file inside path return 0; } // get next inode from current directory - inode_num = searchFileInDir(&cur_inode, next_file); + inode_num = searchFileInDir(cur_inode, next_file); // update inode to next file with next_file if (inode_num != 0) { - cur_inode = inodeTable[inode_num-1]; + cur_inode = &inodeTable[inode_num-1]; } else { // invalid path: file name not found return 0; @@ -304,11 +314,10 @@ int getInodeFromPath(char *path) { next_file = strtok(NULL, "/"); } - if (!(cur_inode.i_mode & EXT2_S_IFDIR) && endWithDir) { + if (!(cur_inode->i_mode & EXT2_S_IFDIR) && endWithDir) { // invalid path: path endwith '/' but have a non-dir type file at the end return 0; } - return inode_num; } @@ -327,9 +336,105 @@ void getParentDirPath(char *path) { /* * modify input path */ + assert (strcmp(path, "/")!=0); + int len = strlen(path); if (path[len-1]=='/') path[len-1] = '\0'; char *target = strrchr(path, '/'); *(target+1) = '\0'; +} + +struct ext2_dir_entry_2 *getPreDirent(struct ext2_inode *parentInode, char *childFileName) { + struct ext2_dir_entry_2 * pre_dir_entry; + struct ext2_dir_entry_2 * cur_dir_entry; + int total_rec_len; + + // search in direct block + for (int i=0; i<12; i++) { + if (parentInode->i_block[i] == 0) { + continue; + } else { + pre_dir_entry = (struct ext2_dir_entry_2 *)getBlock(parentInode->i_block[i]); + total_rec_len = pre_dir_entry->rec_len; + cur_dir_entry = (void *) pre_dir_entry + pre_dir_entry->rec_len; + } + + // for each dir entry in the block + while (total_rec_len < EXT2_BLOCK_SIZE) { + if(strcmp(cur_dir_entry->name, childFileName)==0) { + return pre_dir_entry; + } + total_rec_len = total_rec_len + cur_dir_entry->rec_len; + pre_dir_entry = cur_dir_entry; + cur_dir_entry = (void *) cur_dir_entry + cur_dir_entry->rec_len; + } + } + return NULL; +} + +void rm(struct ext2_inode *parentInode, char *childFileName) { + struct ext2_dir_entry_2 *pre_dir_entry = NULL; + struct ext2_dir_entry_2 *cur_dir_entry = NULL; + struct ext2_dir_entry_2 *child_dir_entry = NULL; + struct ext2_inode *childInode = NULL; + int total_rec_len; + + // delete childFile from parentDir and get childInode + pre_dir_entry = getPreDirent(parentInode, childFileName); + cur_dir_entry = (void *)pre_dir_entry + pre_dir_entry->rec_len; + childInode = getInode(cur_dir_entry->inode); + + // base case1, if childInode is Symbolic link + if (cur_dir_entry->file_type == EXT2_FT_SYMLINK) + { + if (childInode->i_size > 60) { + changeBitmap(getBitmap(BLOCK_BITMAP), childInode->i_block[0]-1, 'd'); + getGroupDesc()->bg_free_blocks_count++; + } + changeBitmap(getBitmap(INODE_BITMAP), cur_dir_entry->inode-1, 'd'); + getGroupDesc()->bg_free_inodes_count++; + } + // base case2, if childInode is a file + else if (cur_dir_entry->file_type == EXT2_FT_REG_FILE) + { + // if link count == 0 remove inode + if (childInode->i_links_count == 1) { + deleteInode(cur_dir_entry->inode); + } else { + childInode->i_links_count--; + } + } + // recursive case, if childInode is a dir + else if (cur_dir_entry->file_type == EXT2_FT_DIR) + { + // reduce link count for self and parent (. and ..) + childInode->i_links_count--; + parentInode->i_links_count--; + + // for each file name (other than . and ..) in child dir, call recursion + for (int i=0; i<12; i++) { + if (childInode->i_block[i] == 0) + continue; + child_dir_entry = (struct ext2_dir_entry_2 *)getBlock(childInode->i_block[i]); + total_rec_len = 0; + // for each dir entry in the block + while (total_rec_len < EXT2_BLOCK_SIZE) { + if (child_dir_entry->name_len != 0 && + strcmp(child_dir_entry->name, ".")!=0 && + strcmp(child_dir_entry->name, "..")!=0) { + rm(childInode, child_dir_entry->name); + } + total_rec_len = total_rec_len + child_dir_entry->rec_len; + child_dir_entry = (void *) child_dir_entry + child_dir_entry->rec_len; + } + } + + // if child link count == 0 remove inode + if (childInode->i_links_count == 1) { + deleteInode(cur_dir_entry->inode); + getGroupDesc()->bg_used_dirs_count--; + } + } + pre_dir_entry->rec_len += cur_dir_entry->rec_len; } \ No newline at end of file diff --git a/utilities.h b/utilities.h index 72ae72b..e9384cf 100644 --- a/utilities.h +++ b/utilities.h @@ -9,8 +9,11 @@ #include #include "ext2.h" -#define TRUE 1; -#define FALSE 0; +#define TRUE 1 +#define FALSE 0 + +#define INODE_BITMAP 1 +#define BLOCK_BITMAP 0 extern char unsigned *disk; @@ -20,22 +23,22 @@ struct ext2_super_block *getSuperblock(void); struct ext2_group_desc *getGroupDesc(void); // bitmap -char unsigned *getBlockBitmap(void); - -char unsigned *getInodeBitmap(void); +char unsigned *getBitmap(int bitmapNum); int getBit(char unsigned * bitmap, int index); -int getFirstEmptyBitIndex(char unsigned * bitmap, int maxLength); +int getFirstEmptyBitIndex(int bitmap); void changeBitmap(char unsigned *bitmap, int idx, char mode); // inode struct ext2_inode *getInodeTable(void); -int initInode(char mode); +struct ext2_inode *getInode(int inodeNum); + +int initInode(unsigned short mode); -void deleteInode(int index); +void deleteInode(int inodeNum); // block char unsigned *getBlock(int blockNum); @@ -43,15 +46,19 @@ char unsigned *getBlock(int blockNum); int allocateNewBlock(void); // dir_entry +struct ext2_dir_entry_2 *getPreDirent(struct ext2_inode *parentInode, char *childFileName); + int searchFileInDir(struct ext2_inode *inode, char *fileName); int calculateActuralSize(struct ext2_dir_entry_2 *dirent); -struct ext2_dir_entry_2 *initDirent(struct ext2_inode *parent_inode, int size); +struct ext2_dir_entry_2 *allocateNewDirent(struct ext2_inode *parent_inode, int size); + +struct ext2_dir_entry_2 *allocateDirentHelper(int blockNum, int size); -struct ext2_dir_entry_2 *initDirentDDB(int blockNum, int size); +struct ext2_dir_entry_2 *initNewDirent(struct ext2_inode *parentInode, int childInodeNum, int type, char *fileName); -struct ext2_dir_entry_2 *allocateNewDirent(struct ext2_inode *parentInode, int childInodeNum, char type, char *fileName); +unsigned int *initSingleIndirect(int blockNum); // path handling int getInodeFromPath(char *path); @@ -59,3 +66,5 @@ int getInodeFromPath(char *path); void getFileNameFromPath(char *fileName, char *path); void getParentDirPath(char *path); + +void rm(struct ext2_inode *parentInode, char *childFileName);