Makefile
simple_file_system : main.o vfs.o shell.o disk.o gcc -o simple_file_system main.o vfs.o shell.o disk.o main.o : main.c gcc -c main.c vfs.o : vfs.h vfs.c gcc -c vfs.c shell.o : shell.h shell.c gcc -c shell.c disk.o : disk.h disk.c gcc -c disk.c
main.c
/* main.c */ #include "shell.h" int main(void) { printf("\n"); printf("\t-+- SFS with mini shell -+-\n"); printf("\n"); printf("\t Command List:$ help\n"); printf("\n"); shell_main(); return 0; }
shell.h
/* shell.h */ #ifndef _SHELL_H_ #define _SHELL_H_ #include "vfs.h" void shell_main(); #endif
shell.c
/* shell.c */ #include "shell.h" char buf[4][MAX_CHAR]; char buf_line[MAX_CHAR * 4]; char user_name[MAX_CHAR] = "user"; char str[2][3] = {".", ".."}; int buf_size[4]; void shell_print_mode(int mode) { if(mode / 4) { putc('r', stdout); } else { putc('-', stdout); } if((mode % 4) / 2) { putc('w', stdout); } else { putc('-', stdout); } if((mode % 4) % 2) { putc('x', stdout); } else { putc('-', stdout); } return; } void shell_print_name(char name[]) { int i; for(i = 0; i < MAX_CHAR; ++i) { if(name[i] == '|') { break; } putc(name[i], stdout); } return; } void shell_print_path(struct dentry *d) { int i; if(d == d->parent) { putc('/', stdout); return; } shell_print_path(d->parent); shell_print_name(d->name); putc('/', stdout); return; } void shell_print_time(struct tm c) { printf("%04d-%02d-%02d %02d:%02d:%02d ", c.tm_year + 1900, c.tm_mon, c.tm_mday, c.tm_hour, c.tm_min, c.tm_sec); return; } void shell_command_ls(FILE *disk, struct dentry *d) { int i,x; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_read(d->d_mode)) { printf("Permission dennied\n"); return; } if(!vfs_mode_excute(d->d_mode)) { printf("Permission dennied\n"); return; } } vfs_dentry_open(disk, d); // printf("ls\n"); x = 0; for(i = 0; i < MAX_D_INODE; ++i) { if(d->d_inode[i] != NULL) { shell_print_name(d->d_inode[i]->name); putc(' ', stdout); x = 1; } } if(x != 0) { putc('\n', stdout); } // printf("inode:%d, dentry:%d\n", d->num_inode, d->num_dentry); return; } void shell_command_ll(FILE *disk, struct dentry *d) { int i; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_read(d->d_mode)) { printf("Permission dennied\n"); return; } if(!vfs_mode_excute(d->d_mode)) { printf("Permission dennied\n"); return; } } vfs_dentry_open(disk, d); //printf("%s\n", d->name); printf("AUTH SIZE CREATED ACCESSED NAME \n"); for(i = -2; i < MAX_D_INODE; ++i) { if(i < 0) { shell_print_mode(d->d_dentry[i + 2]->d_mode); printf(" "); shell_print_time(d->d_dentry[i + 2]->d_ctime); shell_print_time(d->d_dentry[i + 2]->d_atime); printf("%s/\n", str[i + 2]); } else { if(d->d_inode[i] != NULL) { shell_print_mode(d->d_inode[i]->i_mode); printf(" %7d ", d->d_inode[i]->size); shell_print_time(d->d_inode[i]->i_ctime); shell_print_time(d->d_inode[i]->i_atime); shell_print_name(d->d_inode[i]->name); if(d->d_inode[i]->i_type == INODE_DIRECTORY) { putc('/', stdout); } putc('\n', stdout); } } } return; } void shell_command_rmdir(FILE *disk, struct dentry *d, char name[]) { int i; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_excute(d->d_mode)) { printf("Permission dennied\n"); return; } } i = vfs_inode_remove(disk, d, name, INODE_DIRECTORY); if(i < 0) { if(i == -1) { printf("rmdir: \'"); shell_print_name(name); printf("\' cannot remove directory: 파일이 없습니다\n"); } if(i == -2) { printf("rmdir: \'"); shell_print_name(name); printf("\' cannot remove directory: 디렉토리가 아닙니다\n"); } if(i == -3) { printf("rmdir: \'"); shell_print_name(name); printf("\' cannot remove directory: 디렉토리가 비어있지 않습니다\n"); } if(i == -8) { printf("Permission dennied\n"); } } return; } void shell_command_rmfile(FILE *disk, struct dentry *d, char name[]) { int i; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_excute(d->d_mode)) { printf("Permission dennied\n"); return; } } i = vfs_inode_remove(disk, d, name, INODE_FILE); if(i < 0) { if(i == -1) { printf("rmfile: \'"); shell_print_name(name); printf("\' cannot remove file: 파일이 없습니다\n"); } if(i == -4) { printf("rmfile: \'"); shell_print_name(name); printf("\' cannot remove file: 파일이 아닙니다\n"); } if(i == -8) { printf("Permission dennied\n"); } } return; } void shell_command_mkdir(FILE *disk, struct dentry *d, char name[]) { int i; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_excute(d->d_mode)) { printf("Permission dennied\n"); return; } } if(vfs_compare_name(".|", name) == 0 || vfs_compare_name("..|", name) == 0) { i = -2; } else { vfs_dentry_open(disk, d); i = vfs_inode_make(disk, d, name, 0, INODE_DIRECTORY); } if(i < 0) { if(i == -1) { printf("mkdir: \'"); shell_print_name(name); printf("\' cannot make directory: 파일이 있습니다\n"); } if(i == -2) { printf("mkdir: \'"); shell_print_name(name); printf("\' cannot make directory: 사용할 수 없는 이름입니다\n"); } if(i == -8) { printf("Permission dennied\n"); } return; } return; } void shell_command_mkfile(FILE *disk, struct dentry *d, char name[], int size) { int i; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_excute(d->d_mode)) { printf("Permission dennied\n"); return; } } if(vfs_compare_name(".|", name) == 0 || vfs_compare_name("..|", name) == 0) { i = -2; } else { vfs_dentry_open(disk, d); i = vfs_inode_make(disk, d, name, size, INODE_FILE); } if(i < 0) { if(i == -1) { printf("mkfile: \'"); shell_print_name(name); printf("\' cannot make file: 파일이 있습니다\n"); } if(i == -2) { printf("mkfile: \'"); shell_print_name(name); printf("\' cannot make file: 사용할 수 없는 이름입니다\n"); } if(i == -8) { printf("Permission dennied\n"); } } return; } void* shell_command_cd(FILE *disk, struct dentry *d, char name[]) { struct dentry *child; int i; // init child = NULL; if(vfs_compare_name(".|", name) == 0) { child = d; } else if(vfs_compare_name("..|", name) == 0) { child = d->parent; } else { vfs_dentry_open(disk, d); for(i = 0; i < MAX_D_CHILD; ++i) { if(d->d_dentry[i] != NULL) { if(vfs_compare_name(d->d_dentry[i]->name, name) == 0) { break; } } } if(i == MAX_D_CHILD) { printf("cd: "); shell_print_name(name); printf(": 디렉토리가 없습니다.\n"); return child; } child = d->d_dentry[i]; } // directory mode check if(child->sb->s_mode == USER_MODE) { if(!vfs_mode_excute(child->d_mode)) { printf("Permission dennied\n"); } } // vfs_dentry_open(disk, child); return child; } void shell_command_mv(FILE *disk, struct dentry *d, char name[], char new_name[]) { int i, j; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_write(d->d_mode)) { printf("Permission dennied\n"); return; } // if(!vfs_mode_excute(d->d_mode)) { // printf("Permission dennied\n"); // return; // } } // if name == new_name if(vfs_compare_name(name, new_name) == 0) { return; } // search by name for(i = 0; i < MAX_D_INODE; ++i) { if(d->d_inode[i] != NULL) { if(vfs_compare_name(d->d_inode[i]->name, new_name) == 0) { break; } } } if(i != MAX_D_INODE) { printf("mv: "); shell_print_name(name); printf(": 이미 존재하는 파일명입니다\n"); return; } // search by new_name for(i = 0; i < MAX_D_INODE; ++i) { if(d->d_inode[i] != NULL) { if(vfs_compare_name(d->d_inode[i]->name, name) == 0) { vfs_inode_rename(disk, d->d_inode[i], new_name); break; } } } if(i == MAX_D_INODE) { printf("mv: "); shell_print_name(name); printf(": 파일이 없습니다\n"); return; } // if it is directory if(d->d_inode[i]->i_type == INODE_DIRECTORY) { for(j = 0; j < MAX_D_CHILD; ++i) { if(d->d_dentry[j] != NULL) { if(vfs_compare_name(d->d_dentry[j]->name, name) == 0) { vfs_dentry_rename(d->d_dentry[j], d->d_inode[i]); break; } } } } return; } void shell_command_chmod(FILE *disk, struct dentry *d, char mode_str[], char name[]) { int i, j, mode; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_write(d->d_mode)) { printf("Permission dennied\n"); return; } // if(!vfs_mode_excute(d->d_mode)) { // printf("Permission dennied\n"); // return; // } } // decoding option mode = 0; if(mode_str[0] == 'r') { mode += 4; } else if(mode_str[0] != '-') { mode = -8; } if(mode_str[1] == 'w') { mode += 2; } else if(mode_str[1] != '-') { mode = -8; } if(mode_str[2] == 'x') { mode += 1; } else if(mode_str[2] != '-') { mode = -8; } if(mode < 0) { printf("chmod: 옵션이 잘못되었습니다\n"); return; } // search by name for(i = 0; i < MAX_D_INODE; ++i) { if(d->d_inode[i] != NULL) { if(vfs_compare_name(d->d_inode[i]->name, name) == 0) { vfs_inode_chmod(disk, d->d_inode[i], mode); break; } } } if(i == MAX_D_INODE) { printf("chmod: "); shell_print_name(name); printf(": 파일이 없습니다\n"); return; } // printf("chmod\n"); // if it is directory if(d->d_inode[i]->i_type == INODE_DIRECTORY) { for(j = 0; j < MAX_D_CHILD; ++j) { if(d->d_dentry[j] != NULL) { if(vfs_compare_name(d->d_dentry[j]->name, name) == 0) { // printf("chmod\n"); vfs_dentry_chmod(d->d_dentry[j], d->d_inode[i]); // printf("chmod\n"); break; } } } } // printf("chmod\n"); return; } void shell_command_df(FILE *disk, struct dentry *d) { printf("disk.img: %ld / %ld (%ld%%)\n", d->sb->s_blocksize, d->sb->s_maxbytes, (unsigned long)((d->sb->s_blocksize * 100) / d->sb->s_maxbytes)); return; } char *indirect_type[] = {"", "single", "double", "triple"}; void shell_print_indirect_block(FILE *disk, int block_addr, int depth) { int k, addr; if(block_addr == 0) { return; } if(depth == 0) { if(block_addr != 0) { printf(" %08x", block_addr); } return; } printf("\n [%s:%08x]", indirect_type[depth], block_addr); for(k = 0; k < DISK_BLOCK_SIZE / 8; ++k) { fseek(disk, block_addr + k*8, SEEK_SET); addr = disk_read_int(disk); if(addr != 0) { shell_print_indirect_block(disk, addr, depth - 1); } } return; } void shell_command_blocks(FILE *disk, struct dentry *d, char name[]) { struct inode *in; int i; // search by name for(i = 0; i < MAX_D_INODE; ++i) { if(d->d_inode[i] != NULL) { if(vfs_compare_name(d->d_inode[i]->name, name) == 0) { break; } } } if(i == MAX_D_INODE) { printf("blocks: "); shell_print_name(name); printf(": 파일이 없습니다\n"); return; } // mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_read(d->d_inode[i]->i_mode)) { printf("Permission dennied\n"); return; } } // print in = d->d_inode[i]; if(in->direct_block[0] == NULL) { printf("0 block"); } else { printf("direct blocks:\n"); for(i = 0; i < 12; ++i) { if(in->direct_block[i] != NULL) { printf(" %08x", (int)in->direct_block[i]); } } if(in->single_block != NULL) { printf("\nsingle indirect blocks:"); shell_print_indirect_block(disk, (int)in->single_block, 1); } if(in->double_block != NULL) { printf("\ndouble indirect blocks:"); shell_print_indirect_block(disk, (int)in->double_block, 2); } if(in->triple_block != NULL) { printf("\ntriple indirect blocks:"); shell_print_indirect_block(disk, (int)in->triple_block, 3); } } printf("\n"); return; } // shell command const int num_command = 14; const int num_command_without_permission = 5; char *command[] = {"help", "sudo", "su", "cd", "df", "ls", "ll", "rmdir", "rmfile", "mkdir", "mkfile", "mv", "chmod", "blocks"}; char *command_help[] = {"", "\t-Command", "", "\t-Directory", "", "", "", "\t-Directory", "\t-File", "\t-Directory", "\t-File\t-Size", "\t-File1\t-File2", "\t-(rwx)\t-File", ""}; void shell_command_help() { int i; for(i = 0; i < num_command; ++i) { printf("%s\t%s\n", command[i], command_help[i]); } return; } void* shell_command(FILE *disk, struct dentry *current, char buf[][MAX_CHAR], int buf_size[]) { struct dentry *child; int i; // init child = NULL; // mod buf if(buf_size[0] > 64) { buf_size[0] = 63; } buf[0][buf_size[0]] = '\0'; if(buf_size[1] > 64) { buf_size[1] = 63; } buf[1][buf_size[1]] = '|'; if(buf_size[2] > 64) { buf_size[2] = 63; } buf[2][buf_size[2]] = '|'; // check command list for(i = 0; i < num_command; ++i) { if(strcmp(buf[0], command[i]) == 0) { break; } } if(i == num_command) { i = -1; } if(i >= num_command_without_permission) { // directory mode check if(current->sb->s_mode == USER_MODE) { if(!vfs_mode_excute(current->d_mode)) { printf("Permission dennied\n"); return child; } } } // excute command switch(i) { case 0: shell_command_help(); break; case 1: current->sb->s_mode = ROOT_MODE; shell_command(disk, current, buf+1, buf_size+1); current->sb->s_mode = USER_MODE; break; case 2: current->sb->s_mode = ROOT_MODE; break; case 3: child = shell_command_cd(disk, current, buf[1]); break; case 4: shell_command_df(disk, current); break; case 5: shell_command_ls(disk, current); break; case 6: shell_command_ll(disk, current); break; case 7: shell_command_rmdir(disk, current, buf[1]); break; case 8: shell_command_rmfile(disk, current, buf[1]); break; case 9: shell_command_mkdir(disk, current, buf[1]); break; case 10: if(buf_size[2] > 8) { buf_size[2] = 8; } buf[2][buf_size[2]] = '\0'; // printf("%d\n", atoi(buf[2])); shell_command_mkfile(disk, current, buf[1], atoi(buf[2])); break; case 11: shell_command_mv(disk, current, buf[1], buf[2]); break; case 12: shell_command_chmod(disk, current, buf[1], buf[2]); break; case 13: shell_command_blocks(disk, current, buf[1]); break; default: printf("%s: command not found\n", buf[0]); break; }; //printf("shell_command\n"); return child; } void shell_main() { FILE *disk; struct super_block *sb; struct dentry *root; struct dentry *current; struct dentry *child; int num_buf, i, j, k; // mount disk disk = disk_init("disk.img"); sb = vfs_sb_init(disk); root = sb->s_root; current = root; while(1) { if(sb->s_mode == USER_MODE) { printf("%s:", user_name); } else { printf("%s:", "root"); } shell_print_path(current); putc('$', stdout); putc(' ', stdout); //scanf("%s\n", buf_line); fgets(buf_line, MAX_CHAR * 4, stdin); i = 0; for(j = 0; j < MAX_CHAR * 4; ++j) { if(buf_line[j] == ' ') { continue; } for(k = 0; k < MAX_CHAR; ++k) { if(buf_line[j] == '\n' || buf_line[j] == '\0') { ++i; break; } else if(buf_line[j] == ' ') { ++i; break; } buf[i][k] = buf_line[j]; ++j; } // printf("%d %d\n", k, i); if(k > 0) { buf_size[i - 1] = k; } if(i >= 4) { break; } if(buf_line[j] == '\n') { for(k = i; k < 4; ++k) { buf_size[k] = 0; } break; } } //num_buf = i + 1; //printf("num_buf: %d\n", num_buf); if(strncmp(buf[0], "exit", 4) == 0) { if(sb->s_mode == USER_MODE) { break; } else { sb->s_mode = USER_MODE; } } else if(buf[0][0] != '\n' && buf[0][0] != '\0') { //printf("sss\n"); child = shell_command(disk, current, buf, buf_size); if(child != NULL) { current = child; } } else { } memset(buf_line, '\0', MAX_CHAR * 4); memset(buf[0], '\0', MAX_CHAR); memset(buf[1], '\0', MAX_CHAR); memset(buf[2], '\0', MAX_CHAR); } //fseek(disk, 0, SEEK_END); // unmount disk fclose(disk); }
vfs.h
/* vfs.h */ #ifndef _FS_H_ #define _FS_H_ #include "disk.h" #define MAX_D_CHILD (DISK_BLOCK_SIZE / BYTE) * DIRECTORY_ENTRY_BLOCK_NUM #define MAX_D_INODE (DISK_BLOCK_SIZE / BYTE) * DIRECTORY_ENTRY_BLOCK_NUM #define DENTRY_CLOSE 0 #define DENTRY_OPEN 1 #define USER_MODE 0 #define ROOT_MODE 1 // VFS Structure struct dentry { int d_type; int d_mode; char name[MAX_CHAR]; struct super_block *sb; struct dentry *parent; int num_dentry; struct dentry *d_dentry[MAX_D_CHILD]; int num_inode; struct inode *d_inode[MAX_D_INODE]; struct tm d_ctime; struct tm d_atime; }; struct super_block { int s_mode; struct dentry *s_root; struct inode *s_root_inode; unsigned long s_blocksize; unsigned long s_maxbytes; }; struct inode { int i_type; int i_mode; int id; char name[MAX_CHAR]; struct tm i_ctime; struct tm i_atime; int size; void* direct_block[12]; void* single_block; void* double_block; void* triple_block; }; // VFS PROC struct tm vfs_set_time(); int vfs_mode_read(int mode); int vfs_mode_write(int mode); int vfs_mode_excute(int mode); int vfs_compare_name(char name1[], char name2[]); void vfs_inode_chmod(FILE *disk, struct inode *i, int mode); void vfs_inode_rename(FILE *disk, struct inode *i, char name[]); void* vfs_inode_read(FILE *disk, int addr); int vfs_inode_remove(FILE *disk, struct dentry *d, char name[], int flag); int vfs_inode_make(FILE *disk, struct dentry *d, char name[], int size, int flag); void vfs_dentry_chmod(struct dentry *d, struct inode *i); void vfs_dentry_rename(struct dentry *d, struct inode *i); void* vfs_dentry_make(struct dentry *p, struct inode *i); void vfs_dentry_open(FILE *disk, struct dentry *d); void vfs_sb_refresh(FILE *disk, struct super_block *sb); void* vfs_sb_init(FILE *disk); #endif
vfs.c
/* vfs.c */ #include "vfs.h" // VFS PROC struct tm vfs_set_time() { time_t timer; struct tm *c; timer = time(NULL); c = localtime(&timer); //free(c); return *c; } int vfs_mode_read(int mode) { return (mode / 4); } int vfs_mode_write(int mode) { return ((mode % 4) / 2); } int vfs_mode_excute(int mode) { return (((mode % 4) % 2)); } int vfs_compare_name(char name1[], char name2[]) { int i; for(i = 0; i < MAX_CHAR; ++i) { if(name1[i] == '|' && name2[i] == '|') { break; } if(name1[i] != name2[i]) { return -1; } } return 0; } void vfs_inode_chmod(FILE *disk, struct inode *i, int mode) { char buf[MAX_CHAR]; i->i_mode = mode; i->i_atime = vfs_set_time(); // printf("inode_chmod\n"); fseek(disk, i->id, SEEK_SET); disk_read_int(disk); disk = disk_write_int(disk,i->i_mode); // printf("inode_chmod\n"); disk_read_name(disk, buf); // printf("inode_chmod\n"); disk_read_time(disk); disk = disk_write_time(disk, i->i_atime); // printf("inode_chmod\n"); return; } void vfs_inode_rename(FILE *disk, struct inode *i, char name[]) { strncpy(i->name, name, MAX_CHAR); i->i_atime = vfs_set_time(); fseek(disk, i->id, SEEK_SET); disk_read_int(disk); disk_read_int(disk); disk = disk_write_name(disk, i->name); disk_read_time(disk); disk = disk_write_time(disk, i->i_atime); return; } void* vfs_inode_read(FILE *disk, int addr) { struct inode *i; int disk_addr, k; if(addr == 0) { return NULL; } i = (struct inode*)malloc(sizeof(struct inode)); // disk_addr = addr / BYTE; disk_addr = addr; fseek(disk, disk_addr, SEEK_SET); i->i_type = disk_read_int(disk); i->i_mode = disk_read_int(disk); // i->id = (disk_addr - INODE_TABLE_ADDR) / INODE_SIZE; i->id = disk_addr; disk_read_name(disk, i->name); i->i_ctime = disk_read_time(disk); i->i_atime = disk_read_time(disk); i->size = disk_read_int(disk); for(k = 0; k < 12; ++k) { i->direct_block[k] = (void*)disk_read_int(disk); } i->single_block = (void*)disk_read_int(disk); i->double_block = (void*)disk_read_int(disk); i->triple_block = (void*)disk_read_int(disk); return i; } int vfs_inode_remove(FILE *disk, struct dentry *d, char name[], int flag) { struct dentry *p, *i_dentry; struct inode *i, *d_inode; int i_addr, block_addr, remain_size, j, k, l; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_write(d->d_mode)) { //printf("inode_remove\n"); return -8; } } // search inode with same name i = NULL; for(k = 0; k < MAX_D_INODE; ++k) { if(d->d_inode[k] != NULL) { //if(strncmp(d->d_inode[k]->name, name, MAX_CHAR) == 0) { if(vfs_compare_name(d->d_inode[k]->name, name) == 0) { i = d->d_inode[k]; break; } //printf("%s\n", d->d_inode[k]->name); } } if(i == NULL) { return -1; } // inode mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_write(i->i_mode)) { return -8; } } // search dentry with same name i_dentry = NULL; for(k = 0; k < MAX_D_CHILD; ++k) { if(d->d_dentry[k] != NULL) { //if(strncmp(d->d_dentry[k]->name, name, MAX_CHAR) == 0) { if(vfs_compare_name(d->d_dentry[k]->name, name) == 0) { i_dentry = d->d_dentry[k]; break; } } } if(flag == INODE_DIRECTORY) { if(i_dentry == NULL) { return -2; } vfs_dentry_open(disk, i_dentry); if(i_dentry->num_inode != 0) { return -3; } } else { if(i_dentry != NULL) { return -4; } } // search directory inode p = d->parent; // if(p != NULL) { // not root directory if(p != d) { // not root directory for(k = 0; k < MAX_D_INODE; ++k) { if(vfs_compare_name(d->name, p->d_inode[k]->name) == 0) { d_inode = p->d_inode[k]; break; } } } else { // root directory d_inode = d->sb->s_root_inode; } // remove inode block addr for(k = 0; k < DIRECTORY_ENTRY_BLOCK_NUM; ++k) { // fseek(disk, (int)d_inode->direct_block[k] / BYTE, SEEK_SET); fseek(disk, (int)d_inode->direct_block[k], SEEK_SET); for(l = 0; l < DISK_BLOCK_SIZE / BYTE; ++l) { i_addr = disk_read_int(disk); if(i_addr == i->id) { fseek(disk, -BYTE, SEEK_CUR); disk = disk_write_int(disk, 0); break; } } if(l != DISK_BLOCK_SIZE / BYTE) { break; } } // remove inode pointer --d->num_inode; for(k = 0; k < MAX_D_INODE; ++k) { if(d->d_inode[k] == i) { d->d_inode[k] = NULL; break; } } // remove dentry pointer if(flag == INODE_DIRECTORY) { --d->num_dentry; for(k = 0; k < MAX_D_CHILD; ++k) { if(d->d_dentry[k] == i_dentry) { d->d_dentry[k] = NULL; break; } } } // free inode's data blocks d->sb->s_blocksize -= i->size; // direct blocks for(k = 0; k < 12; ++k) { block_addr = (int)i->direct_block[k]; if(block_addr != 0) { //d->sb->s_blocksize -= DISK_BLOCK_SIZE; disk_free_block(disk, (int)i->direct_block[k]); } } // indirect blocks disk_free_indirect_block(disk, (int)i->single_block, 1); disk_free_indirect_block(disk, (int)i->double_block, 2); disk_free_indirect_block(disk, (int)i->triple_block, 3); //free data block end // free inode block disk_free_inode(disk, i->id); // super_block refresh vfs_sb_refresh(disk, p->sb); // debug: inode table address // printf("%08x \n", i->id); // free pointers free(i); if(flag == INODE_DIRECTORY) { free(i_dentry); } return 0; } int vfs_inode_make(FILE *disk, struct dentry *d, char name[], int size, int flag) { struct dentry *p; struct inode *i, *d_inode; int i_addr, remain_size, real_size, block_num, j, k, l; // directory mode check if(d->sb->s_mode == USER_MODE) { if(!vfs_mode_write(d->d_mode)) { return -8; } } // check inode with same name for(k = 0; k < MAX_D_INODE; ++k) { if(d->d_inode[k] != NULL) { //if(strncmp(d->d_inode[k]->name, name, MAX_CHAR) == 0) { if(vfs_compare_name(d->d_inode[k]->name, name) == 0) { return -1; } } } // search directory inode p = d->parent; if(p != d) { // not root directory for(k = 0; k < MAX_D_INODE; ++k) { if(vfs_compare_name(d->name, p->d_inode[k]->name) == 0) { d_inode = p->d_inode[k]; break; } } } else { // root directory d_inode = d->sb->s_root_inode; } // make new inode i = (struct inode*)malloc(sizeof(struct inode)); // inode block alloc i->id = disk_alloc_inode(disk); if(i->id == 0) { free(i); return -5; } i->i_type = flag; if(flag == INODE_FILE) { i->i_mode = 6; } else { i->i_mode = 7; } //i->id = (disk_addr - INODE_TABLE_ADDR) / INODE_SIZE; strncpy(i->name, name, MAX_CHAR); // printf("%s\n", i->name); i->i_ctime = vfs_set_time(); i->i_atime = i->i_ctime; // disk block alloc if(i->i_type == INODE_DIRECTORY) { i->size = DISK_BLOCK_SIZE * DIRECTORY_ENTRY_BLOCK_NUM; for(k = 0; k < DIRECTORY_ENTRY_BLOCK_NUM; ++k) { i->direct_block[k] = (void*)disk_alloc_block(disk); d->sb->s_blocksize += DISK_BLOCK_SIZE; } for(k = DIRECTORY_ENTRY_BLOCK_NUM; k < 12; ++k) { i->direct_block[k] = NULL; } i->single_block = NULL; i->double_block = NULL; i->triple_block = NULL; } else { i->size = size; remain_size = i->size; k = remain_size % DISK_BLOCK_SIZE; remain_size = remain_size / DISK_BLOCK_SIZE; if(k != 0) { remain_size += 1; } // direct block /* for(k = 0; k < 12; ++k) { i->direct_block[k] = (void*)disk_alloc_block(disk); //d->sb->s_blocksize += DISK_BLOCK_SIZE; // fseek(disk, ((int)i->direct_block[k]) / BYTE , SEEK_SET); if(remain_size == 0 || (remain_size > 0 && i->direct_block[k] == NULL)) { } else { fseek(disk, (int)i->direct_block[k], SEEK_SET); for(l = 0; l < 1024; ++l) { if(remain_size == 0) { break; } --remain_size; disk = disk_write_char(disk, '1'); } } if(remain_size == 0) { break; } } */ for(k = 0; k < 12; ++k) { if(remain_size > 0) { i->direct_block[k] = (void*)disk_alloc_block(disk); } else { i->direct_block[k] = NULL; } if(i->direct_block[k] != NULL) { --remain_size; } } // indirect single block /* i->single_block = NULL; i->double_block = NULL; i->triple_block = NULL; */ //printf("%d\n", remain_size); i->single_block = (void*)disk_alloc_indirect_block(disk, &remain_size, 1); //printf("%d\n", remain_size); // indirect double block i->double_block = (void*)disk_alloc_indirect_block(disk, &remain_size, 2); //printf("%d\n", remain_size); // indirect triple block i->triple_block = (void*)disk_alloc_indirect_block(disk, &remain_size, 3); //printf("%d\n", remain_size); if(remain_size > 0) { real_size = size / DISK_BLOCK_SIZE; if(size % DISK_BLOCK_SIZE != 0) { real_size += 1; } i->size = (real_size - remain_size) * DISK_BLOCK_SIZE; } } // write new inode // fseek(disk, i->id / BYTE, SEEK_SET); fseek(disk, i->id, SEEK_SET); disk = disk_write_int(disk, i->i_type); disk = disk_write_int(disk, i->i_mode); disk = disk_write_name(disk, i->name); disk = disk_write_time(disk, i->i_ctime); disk = disk_write_time(disk, i->i_atime); disk = disk_write_int(disk, i->size); for(k = 0; k < 12; ++k) { disk = disk_write_int(disk, (int)i->direct_block[k]); } disk = disk_write_int(disk, (int)i->single_block); disk = disk_write_int(disk, (int)i->double_block); disk = disk_write_int(disk, (int)i->triple_block); // write inode block addr to d_inode for(k = 0; k < DIRECTORY_ENTRY_BLOCK_NUM; ++k) { // fseek(disk, (int)d_inode->direct_block[k] / BYTE, SEEK_SET); fseek(disk, (int)d_inode->direct_block[k], SEEK_SET); for(l = 0; l < DISK_BLOCK_SIZE / BYTE; ++l) { i_addr = disk_read_int(disk); if(i_addr == 0) { fseek(disk, -BYTE, SEEK_CUR); disk = disk_write_int(disk, i->id); break; } } if(l != DISK_BLOCK_SIZE / BYTE) { break; } } // add inode pointer to d for(k = 0; k < MAX_D_INODE; ++k) { if(d->d_inode[k] == NULL) { break; } } d->d_inode[k] = i; ++d->num_inode; //debug: p->d_dentry // for(k = 0; k < MAX_D_CHILD; ++k) { // if(p->d_dentry[k] != NULL) { // printf("%s\n", p->d_dentry[k]->name); // } // } // for(k = 0; k < MAX_D_INODE; ++k) { // if(p->d_inode[k] != NULL) { // printf("%s\n", p->d_inode[k]->name); // } // } // if i_type is DIRECTORY // make new dentry if(i->i_type == INODE_DIRECTORY) { for(k = 0; k < MAX_D_CHILD; ++k) { if(d->d_dentry[k] == NULL) { break; } } d->d_dentry[k] = vfs_dentry_make(d, i); ++d->num_dentry; } //endif d->sb->s_blocksize += i->size; // super_block refresh vfs_sb_refresh(disk, d->sb); // debug: inode table address // printf("%08x\n", i->id); //return i; return 0; } void vfs_dentry_chmod(struct dentry *d, struct inode *i) { d->d_mode = i->i_mode; d->d_atime = i->i_atime; return; } void vfs_dentry_rename(struct dentry *d, struct inode *i) { strncpy(d->name, i->name, MAX_CHAR); d->d_atime = i->i_atime; return; } void* vfs_dentry_make(struct dentry *p, struct inode *i) { struct dentry *d; int k; if(i == NULL) { return NULL; } if(i->i_type != INODE_DIRECTORY) { // printf("ssss\n"); return NULL; } d = (struct dentry*)malloc(sizeof(struct dentry)); d->d_type = DENTRY_CLOSE; d->d_mode = i->i_mode; strncpy(d->name, i->name, MAX_CHAR); if(p != NULL) { d->sb = p->sb; } else { d->sb = 0; } d->parent = p; d->num_dentry = 0; for(k = 0; k < MAX_D_CHILD; ++k) { d->d_dentry[k] = NULL; } d->num_inode = 0; for(k = 0; k < MAX_D_INODE; ++k) { d->d_inode[k] = NULL; } d->d_ctime = i->i_ctime; d->d_atime = i->i_atime; return d; } void vfs_dentry_open(FILE *disk, struct dentry *d) { struct dentry *p; struct inode *in; int i, j, k, l, block_num; int inode_addr; // printf("d_open %d\n", d->d_mode); if(d->d_type == DENTRY_OPEN) { return; } // printf("dentry_open\n"); p = d->parent; d->d_type = DENTRY_OPEN; // for(i = 0; i < p->num_inode; ++i) { for(i = 0; i < MAX_D_INODE; ++i) { if(p->d_inode != NULL) { in = p->d_inode[i]; if(vfs_compare_name(d->name, in->name) == 0) { break; } } } // printf("d_open\n"); // block_num = (in->size / DISK_BLOCK_SIZE) + 1; block_num = in->size / DISK_BLOCK_SIZE; for(i = 0; i < block_num; ++i) { for(j = 0; j < DISK_BLOCK_SIZE / BYTE; ++j) { // fseek(disk, ((int)in->direct_block[i] / BYTE) + (j * 8), SEEK_SET); fseek(disk, (int)in->direct_block[i] + (j * 8), SEEK_SET); inode_addr = disk_read_int(disk); if(inode_addr != 0) { ++d->num_inode; } d->d_inode[(DISK_BLOCK_SIZE / BYTE)*i + j] = vfs_inode_read(disk, inode_addr); } } d->d_dentry[0] = d; d->d_dentry[1] = p; j = 2; for(i = 0; i < MAX_D_INODE; ++i) { d->d_dentry[j] = vfs_dentry_make(d, d->d_inode[i]); if(d->d_dentry[j] != NULL) { ++j; } } d->num_dentry = j; // printf("d_open\n"); return; } void vfs_sb_refresh(FILE *disk, struct super_block *sb) { int i, k; fseek(disk, 0, SEEK_SET); k = disk_read_int(disk); disk = disk_write_long(disk, sb->s_blocksize); return; } void* vfs_sb_init(FILE *disk) { struct super_block *sb; struct dentry *d; struct inode *in; int root_inode_addr; int inode_id; int inode_addr; int block_num, i, j; sb = (struct super_block*)malloc(sizeof(struct super_block)); sb->s_mode = USER_MODE; root_inode_addr = disk_read_int(disk); // inode_id = ((root_inode_addr / BYTE) - INODE_TABLE_ADDR) / INODE_SIZE; inode_id = (root_inode_addr - INODE_TABLE_ADDR) / INODE_SIZE; sb->s_blocksize = disk_read_long(disk); sb->s_maxbytes = disk_read_long(disk); in = vfs_inode_read(disk, root_inode_addr); sb->s_root = vfs_dentry_make(NULL, in); d = sb->s_root; d->sb = sb; d->parent = d; d->d_type = DENTRY_OPEN; d->d_mode = in->i_mode; block_num = (in->size / DISK_BLOCK_SIZE); // if(in->size % DISK_BLOCK_SIZE != 0) { // ++block_num; // } for(i = 0; i < block_num; ++i) { for(j = 0; j < DISK_BLOCK_SIZE / BYTE; ++j) { // fseek(disk, ((int)in->direct_block[i] / BYTE) + (j * 8), SEEK_SET); fseek(disk, (int)in->direct_block[i] + (j * 8), SEEK_SET); inode_addr = disk_read_int(disk); if(inode_addr != 0) { ++d->num_inode; } d->d_inode[(DISK_BLOCK_SIZE / BYTE)*i + j] = vfs_inode_read(disk, inode_addr); } } d->d_dentry[0] = d; d->d_dentry[1] = d; j = 2; for(i = 0; i < MAX_D_INODE; ++i) { d->d_dentry[j] = vfs_dentry_make(d, d->d_inode[i]); if(d->d_dentry[j] != NULL) { ++j; } } d->num_dentry = j; sb->s_root_inode = in; return sb; }
disk.h
/* disk.h */ #ifndef _DISK_H_ #define _DISK_H_ #define BYTE 8 #define MAX_CHAR 64 #define INDEX_NUM 2 #define INODE_NUM 256 #define INODE_SIZE 512 #define INODE_FILE 0 #define INODE_DIRECTORY 1 #define DIRECTORY_ENTRY_BLOCK_NUM 1 #define DATA_BLOCK_NUM 893 #define DISK_BLOCK_NUM 1024 #define DISK_BLOCK_SIZE 1024 #define SUPER_BLOCK_ADDR 0 #define DISK_BLOCK_INDEX_ADDR 1024 #define INODE_INDEX_ADDR 2048 #define INODE_TABLE_ADDR 3072 #define DATA_BLOCK_ADDR (INODE_TABLE_ADDR + INODE_SIZE * INODE_NUM) #include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> char disk_read_char(FILE *f); int disk_read_int(FILE *f); unsigned long disk_read_long(FILE *f); char* disk_read_name(FILE *f, char buf[]); struct tm disk_read_time(FILE *f); FILE* disk_write_char(FILE *f, char value); FILE* disk_write_int(FILE *f, int value); FILE* disk_write_long(FILE *f, unsigned long value); FILE* disk_write_name(FILE *f, char name[]); FILE* disk_write_time(FILE *f, struct tm c); int disk_alloc_inode(FILE *f); void disk_free_inode(FILE *f, int inode_addr); int disk_alloc_block(FILE *f); int disk_alloc_indirect_block(FILE *f, int *block_num, int depth); void disk_free_block(FILE *f, int block_addr); void disk_free_indirect_block(FILE *f, int block_addr, int depth); FILE* disk_init(char disk_name[]); #endif
disk.c
/* disk.c */ #include "disk.h" char buf_char[1]; char buf_int[8]; char buf_long[16]; char buf_name[MAX_CHAR]; char padding_64[MAX_CHAR] = "0000000000000000000000000000000000000000000000000000000000000000"; char disk_read_char(FILE *f) { fread(buf_char, 1, 1, f); return buf_char[0]; } int disk_read_int(FILE *f) { int i, t; fread(buf_int, 1, 8, f); t = 0; for(i = 0; i < 8; ++i) { if(buf_int[i] < 'a') { t = (t * 16) + buf_int[i] - '0'; } else { t = (t * 16) + buf_int[i] - 'a' + 10; } } return t; } unsigned long disk_read_long(FILE *f) { int i; unsigned long t; fread(buf_long, 1, 16, f); t = 0; for(i = 0; i < 16; ++i) { if(buf_long[i] < 'a') { t = (t * 16) + buf_long[i] - '0'; } else { t = (t * 16) + buf_long[i] - 'a' + 10; } } return t; } char* disk_read_name(FILE *f, char buf[]) { int i; fread(buf_name, 1, MAX_CHAR, f); for(i = 0; i < MAX_CHAR; ++i) { buf[i] = buf_name[i]; if(buf_name[i] == '|') { ++i; break; } } for(;i < MAX_CHAR; ++i) { buf[i] = '\0'; } return buf; } struct tm disk_read_time(FILE *f) { struct tm c; c.tm_sec = disk_read_int(f); c.tm_min = disk_read_int(f); c.tm_hour = disk_read_int(f); c.tm_mday = disk_read_int(f); c.tm_mon = disk_read_int(f); c.tm_year = disk_read_int(f); c.tm_wday = disk_read_int(f); c.tm_yday = disk_read_int(f); c.tm_isdst = disk_read_int(f); return c; } FILE* disk_write_char(FILE *f, char value) { buf_char[0] = value; fwrite(buf_char, 1, 1 ,f); return f; } FILE* disk_write_int(FILE *f, int value) { int i, t; for(i = 7; i >= 0; --i) { t = value % 16; if(t < 10) { buf_int[i] = '0' + t; } else { buf_int[i] = 'a' + (t - 10); } value = value / 16; } fwrite(buf_int, 1, 8, f); return f; } FILE* disk_write_long(FILE *f, unsigned long value) { int i; unsigned long t; for(i = 15; i >= 0; --i) { t = value % 16; if(t < 10) { buf_long[i] = '0' + t; } else { buf_long[i] = 'a' + (t - 10); } value = value / 16; } fwrite(buf_long, 1, 16, f); return f; } FILE* disk_write_name(FILE *f, char name[]) { int i; for(i = MAX_CHAR - 1; i >= 0; --i) { buf_name[i] = name[i]; } fwrite(buf_name, 1, MAX_CHAR, f); return f; } FILE* disk_write_time(FILE *f, struct tm c) { f = disk_write_int(f, c.tm_sec); f = disk_write_int(f, c.tm_min); f = disk_write_int(f, c.tm_hour); f = disk_write_int(f, c.tm_mday); f = disk_write_int(f, c.tm_mon); f = disk_write_int(f, c.tm_year); f = disk_write_int(f, c.tm_wday); f = disk_write_int(f, c.tm_yday); f = disk_write_int(f, c.tm_isdst); return f; } int disk_alloc_inode(FILE *f) { int i, inode_addr; char c; fseek(f, INODE_INDEX_ADDR, SEEK_SET); for(i = 0; i < INODE_NUM; ++i) { c = disk_read_char(f); if(c == '0') { break; } } if(i == INODE_NUM) { return 0; } fseek(f, -1, SEEK_CUR); f = disk_write_char(f, '1'); // inode_addr = (INODE_TABLE_ADDR + (INODE_SIZE * i)) * BYTE; inode_addr = INODE_TABLE_ADDR + (INODE_SIZE * i); return inode_addr; } void disk_free_inode(FILE *f, int inode_addr) { int i, index, addr; if(inode_addr == 0) { return; } // addr = inode_addr / BYTE; addr = inode_addr; index = (addr - INODE_TABLE_ADDR) / INODE_SIZE; fseek(f, addr, SEEK_SET); for(i = 0; i < INODE_SIZE / 64; ++i) { f = disk_write_name(f, padding_64); } fseek(f, INODE_INDEX_ADDR + index, SEEK_SET); f = disk_write_char(f, '0'); return; } int disk_alloc_block(FILE *f) { int i, block_addr; char c; fseek(f, DISK_BLOCK_INDEX_ADDR, SEEK_SET); for(i = 0; i < DISK_BLOCK_NUM; ++i) { c = disk_read_char(f); if(c == '0') { break; } } if(i == DISK_BLOCK_NUM) { return 0; } fseek(f, -1, SEEK_CUR); f = disk_write_char(f, '1'); // block_addr = DISK_BLOCK_SIZE * i * BYTE; block_addr = DISK_BLOCK_SIZE * i; return block_addr; } int disk_alloc_indirect_block(FILE *f, int *block_num, int depth) { int i, block_addr, parent_addr, addr, k; char c; if(*block_num == 0) { return 0; } if(depth == 0) { return disk_alloc_block(f); } parent_addr = disk_alloc_block(f); if(parent_addr == 0) { return parent_addr; } for(i = 0; i < DISK_BLOCK_SIZE / 8; ++i) { addr = (int)disk_alloc_indirect_block(f, block_num, depth - 1); if(addr == 0) { return parent_addr; } else { if(depth == 1) { --(*block_num); } fseek(f, parent_addr + i*8, SEEK_SET); f = disk_write_int(f, addr); if(block_num == 0) { return parent_addr; } } } // } return parent_addr; } void disk_free_block(FILE *f, int block_addr) { int i, index, addr; if(block_addr == 0) { return; } // addr = block_addr / BYTE; addr = block_addr; index = addr / DISK_BLOCK_SIZE; fseek(f, addr, SEEK_SET); for(i = 0; i < DISK_BLOCK_SIZE / 64; ++i) { f = disk_write_name(f, padding_64); } fseek(f, DISK_BLOCK_INDEX_ADDR + index, SEEK_SET); f = disk_write_char(f, '0'); return; } void disk_free_indirect_block(FILE *f, int block_addr, int depth) { int i, index, addr, child_addr; if(block_addr == 0) { return; } if(depth == 0) { disk_free_block(f, block_addr); return; } // addr = block_addr / BYTE; addr = block_addr; index = addr / DISK_BLOCK_SIZE; for(i = 0; i < DISK_BLOCK_SIZE / 8; ++i) { fseek(f, addr + i*8, SEEK_SET); child_addr = disk_read_int(f); disk_free_indirect_block(f, child_addr, depth - 1); } disk_free_block(f, addr); return; } FILE* disk_init(char disk_name[]) { time_t timer; struct tm c, *t; FILE *f; int i, j; f = fopen(disk_name, "r"); if(!f) { f = fopen(disk_name, "w"); // c_time timer = time(NULL); t = localtime(&timer); c = *t; //free(t); // super_block (1KB) //f = disk_write_name(f, "2009147093|");// disk_name,64byte f = disk_write_int(f, INODE_TABLE_ADDR); // root_inode,8byte f = disk_write_long(f, DISK_BLOCK_SIZE * 132);// block_size,16byte f = disk_write_long(f, DISK_BLOCK_SIZE * DISK_BLOCK_NUM);// maxbytes,16byte f = disk_write_int(f, 0); // padding,8byte f = disk_write_long(f, 0); // padding,16byte for(i = 0; i < 15; ++i) { f = disk_write_name(f, padding_64); } // padding,1024-64 // disk block index block (1KB) for(i = 0; i < 131; ++i) { f = disk_write_char(f, '1'); } for(i = 131; i < 132; ++i) { f = disk_write_char(f, '1'); // root inode } for(i = 132; i < 1024; ++i) { // 0~DISK_BLOCK_NUM-1 f = disk_write_char(f, '0'); //f = disk_write_name(f, padding_64); } // init by 0 // inode index block (1KB) f = disk_write_char(f, '1'); for(i = 1; i < 1024; ++i) { // INODE_NUM f = disk_write_char(f, '0'); //f = disk_write_name(f, padding_64); } // init by 0 // inode table (inode = 512byte > 8+64+72+72+8+8*15 = 344) // root inode f = disk_write_int(f, INODE_DIRECTORY); // i_type,8byte f = disk_write_int(f, 7); // i_mode,8byte f = disk_write_name(f, "|"); // i_name,64byte f = disk_write_time(f, c); // i_ctime,72byte f = disk_write_time(f, c); // i_atime,72byte f = disk_write_int(f, DISK_BLOCK_SIZE); // i_size,8byte for(i = 0; i < 1; ++i) { // f = disk_write_int(f, (DATA_BLOCK_ADDR + DISK_BLOCK_SIZE*i) * BYTE); f = disk_write_int(f, DATA_BLOCK_ADDR + DISK_BLOCK_SIZE*i); } for(i = 1; i < 15; ++i) { // block,8*15byte f = disk_write_int(f, 0); // direct X 12 } // indirect X 3 f = disk_write_name(f, padding_64); // padding,64byte f = disk_write_name(f, padding_64); // padding,64byte for(i = 0; i < 4; ++i) { // padding f = disk_write_int(f, 0); } // 8byte X 4 // root inode end for(j = 1; j < INODE_NUM; ++j) { for(i = 0; i < 8; ++i) { f = disk_write_name(f, padding_64); } } // 128KB (INODE_NUM/2 byte) // inode table end // remain 1024 - 131 KB = 893KB // disk blocks for(j = 0; j < 893; ++j) { for(i = 0; i < 16; ++i) { f = disk_write_name(f, padding_64); } // disk block = 1KB } // 893KB } fclose(f); f = fopen(disk_name, "r+"); return f; }
No comments:
Post a Comment