Simple File System Simulator ( Virtual File System on linux 2.6 )

Description

disk-1disk-2vfs

Source Code

Makefile

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

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

c
/* shell.h */
#ifndef _SHELL_H_
#define _SHELL_H_

#include "vfs.h"

void shell_main();

#endif

shell.c

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

c
/* 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

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

c
/* 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

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;
}