First, the overall design, and then the combination of specific functions for detailed analysis.
First, create an approximate100Mfile as the emulated hard drive. The hard disk space is divided into three parts: the Super block area,Inodearea and disk block area. The Super block area is astructstructure, which holds theInodearea and disk block area usage. InodeDistrict is made up of1024x768aInodeblock composition. AInodeThe block corresponds to a directory file or an ordinary file, which holds the file type of the corresponding file, the file size, the number of disk blocks used, and the block number of the disk that is occupied. And then each time you read and write to the file, change the correspondingInodeand the contents of the corresponding disk blocks are available. The last is the disk block area, and the size of each disk block is1KB. Total by1024*80disk block composition, in fact, the disk block does not need a special data structure to mark, as long as the corresponding location can be found, and then read and write to the memory, and then put it back to the hard disk after operation.
Next, the directory is a directory file that contains many catalog items, each of which consists of two parts: 1. subordinate directory or file name of the file, 2. This file corresponds to i node. It is important to note that when creating a subdirectory, the contents of the directory file for that subdirectory are not empty, but contain at least two directory entries "." and ".". Where the file name is "." The directory entry represents the current directory, and the file name is ".." Represents the upper-level directory. When we need to go to the top level directory, just find ".." The catalog item corresponds to the inode "." In the root directory. and ".." The corresponding inode is the same, This also provides a condition for us to determine whether the current directory is a root directory.
Then the operation of normal files. The creation of ordinary files is actually simpler than the creation of a catalog file, because ordinary files can be empty at the beginning. So just read the corresponding inode structure and initialize it. As for the editing of the file, because I am too lazy to write an editor, so witty call the vim buff.txt file, When you want to edit the file, read the contents of the disk block of the file, and place it on the buff.txt vim buff.txt
Finally, the deletion of files. The deletion of ordinary files is relatively simple, as long as the corresponding inode Release all of its disk blocks, and finally release it itself. In fact, the so-called release, is the super block inside the disk block bitmap or inode The corresponding position of the bitmap is placed 0 It's OK, and there's nothing complicated to do. However, the removal of a directory is relatively complex, because a directory typically contains other files. So in linux system, when you want to delete a directory, It usually reminds you that the directory is not empty and does not allow you to delete it. However, in this simulation file system, for the sake of simplicity, regardless of whether the directory is empty, the contents are all deleted directly. This is actually the hardest part of the system. The method used is recursive delete, when encountered is a directory, then enter the subdirectory, if the file encountered, then delete the file, if there is no content in the current directory, the upper directory is returned. After a further deep traversal, the entire directory tree is deleted. It is important to note that the root directory and its subdirectories need to be deleted differently, the root directory not only to delete itself, but also to make a modification to its parent directory, because it contains its name and inode The catalog item is stored in the directory file of its parent directory, and its own subdirectory does not need to be modified in this step, because its parent directory is to be deleted anyway. In this way, the deletion of the file is also done, the entire system is almost complete.
The specific code is implemented as follows:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #define Number of inodenum1024//i nodes # define BLKNUM (80*1024)//number of disk blocks # define blksize1024//disk block size is 1k#define blkpernode1024// Each file contains the maximum number of disk blocks # define disk "Disk.txt" #define BUFF "buff.txt"//read/write files when the buffer file # define SUPERBEG0//Super block start address # define Inodebegsizeof (SUPERBLK)//i node area Apocalypse address # define Blockbeg (Inodebeg+inodenum*sizeof (Inode))//Data area start address # define MAXDIRNUM ( blkpernode* (Blksize/sizeof (dir))//maximum number of files per directory # define DIRPERBLK (Blksize/sizeof (dir))//Maximum directory entries per disk block # define Directory0#define file1#define commannum (sizeof (command)/sizeof (char*))//instruction number typedef struct{int INODE_MAP[INODENUM ];//i node Bitmap int blk_map[blknum];//disk block bitmap int inode_used;//number of I nodes that have been used int blk_used;//the number of disk blocks that have been used}superblk;typedef struct{ int blk_identifier[blkpernode];//occupies a disk block number int blk_num;//occupies the number of disk blocks int file_size;//file size int type;//file type}inode;typedef Struct{char name[30];//Directory Name The inode_num;//directory corresponds to the Inode}dir;dir dir_table[maxdirnum];//load the contents of the current directory file into the memory int dir_num;/ /number of entries in the corresponding numbered directoryint inode_num;//inode number for current directory inode curr_inode;//current directory inode structure superblksuper_blk;//file system Super block file*disk;/* instruction Collection */char* command[]={"FMT", "Quit", "mkdir", "RmDir", "CD", "LS", "mk", "rm", "Vim"};charpath[40]= "monster:root"; int init_fs (void );//Initialize file system int close_fs (void);//close file system int format_fs (void);//format File system int open_dir (int);//Open the corresponding inode corresponding to the directory int Close_dir (int);//the directory int show_dir (int) that holds the corresponding inode;//Displays the directory int make_file (int,char*,int);//Creates a new directory or file int del_file (int,char*,int); /delete subdirectory int enter_dir (int,char*);//Enter subdirectory int file_write (char*);//write file int file_read (char*);//Read file int adjust_dir (char*); /delete subdirectory, adjust the original directory, so that the middle no gap int check_name (int,char*);//Check rename, return 1 to indicate that the name does not exist, otherwise return the corresponding Inodeint Type_check (char*);//Determine the type of file int Free_inode (int);//release the corresponding Inodeint apply_inode ();//apply for inode, return the corresponding inode number, return 1 The inode runs out of int init_dir_inode (int,int);// Initializes the Inodeint init_file_inode (int) of the new directory,//initializes the new file's inodeint free_blk (int);//releases the corresponding disk block int get_blk (void);//Gets the disk block void Change_path (char*); int main () {char Comm[30],name[30];char *arg[]={"Vim", Buff,null};int i,quit=0,choice,sTatus;disk=fopen (Disk, "r+"); Init_fs (); while (1) {printf ("%s#", Path), scanf ("%s", comm); Choice=-1;for (i=0;i< Commannum;++i) {if (strcmp (Comm,command[i]) ==0) {choice=i;break;}} Switch (choice) {/* Format file System */case 0:FORMAT_FS () break;/* exit file system */case 1:quit=1;break;/* Create subdirectory */case 2:scanf ("%s", name) ; Make_file (inode_num,name,directory); break;/* Delete subdirectory */case 3:scanf ("%s", name), if (Type_check (name)!=directory) { printf ("rmdir:failed to remove '%s ': Not a directory\n", name); Del_file (inode_num,name,0); break;/* enters subdirectory */case 4:scanf ("%s", name), if (Type_check (name)!=directory) {printf ("CD:%s : Not a directory\n ", name); if (Enter_dir (Inode_num,name)) {Change_path (name);//change path prefix}break;/* display directory contents */case 5:show_dir (inode_num); break;/* Create File */case 6:scanf ("%s", name), Make_file (inode_num,name,file); break;/* Delete file */case 7:scanf ("%s", name); if (Type_check (name)!=file) {printf ("Rm:cannot remove '%s ': Not a file\n", name); Del_file (inode_num,name,0); break;/* Edit the file */case 8:scanf ("%s", name); if (Type_check (name)!=file) {printf ("Vim:cannot edit '%s ': Not a file\n", name); File_read (name);//writes data from file to Buffif (!fork ()) {EXECVP ("vim", Arg);} Wait (&status), File_write (name),//writes data from the buff to the file break;default:printf ("%s command not found\n", comm);} if (quit) break;} Close_fs (); fclose (Disk); return 0;} int Init_fs (void) {fseek (disk,superbeg,seek_set); Fread (&super_blk,sizeof (SUPERBLK), 1,disk);//Read Super block inode_num= 0;//the inode for the current root directory is 0if (!open_dir (inode_num)) {printf ("CANT ' T Open root directory\n"); return 0;} return 1;} int Close_fs (void) {fseek (disk,superbeg,seek_set); Fwrite (&super_blk,sizeof (SUPERBLK), 1,disk); Close_dir (inode _num); return 1;} int Format_fs (void) {/* format inode_map, retain root */memset (super_blk.inode_map,0,sizeof (Super_blk.inode_map)); Super_ blk.inode_map[0]=1;super_blk.inode_used=1;/* format Blk_map, leave the first disk block to the root directory */memset (super_blk.blk_map,0,sizeof (super_ BLK.BLK_MAP)) super_blk.blk_map[0]=1;super_blk.blk_used=1;inode_num=0;//change the current directory to the root directory/* Read the I node of the root directory */fseek (Disk, Inodebeg,seek_set); Fread (&curr_inode,sizeof (inode), 1,disk);//printf ("%d\n", Curr_inode.file_size/sizeof (dir)); curr_inode.file_size=2*sizeof (dir); curr_inode.blk_num=1;curr_ inode.blk_identifier[0]=0;//the 0th disk must be the root directory//* only. and. Catalog entry Valid */dir_num=2;strcpy (Dir_table[0].name, "."); dir_table[0].inode_num=0;strcpy (Dir_table[1].name, ".."); dir_table[1].inode_num=0;strcpy (Path, "Monster:root"); return 1;} int open_dir (int inode) {inti;int pos=0;int Left;fseek (disk,inodebeg+sizeof (inode) *inode,seek_set);/* read out the corresponding I-node */ Fread (&curr_inode,sizeof (inode), 1,disk),//printf ("%d\n", curr_inode.file_size); for (I=0;i<curr_inode.blk_ Num-1;++i) {fseek (disk,blockbeg+blksize*curr_inode.blk_identifier[i],seek_set); Fread (Dir_table+pos,sizeof (dir), Dirperblk,disk);p os+=dirperblk;} /*left is the number of directory entries in the last disk block */left=curr_inode.file_size/sizeof (Dir)-dirperblk* (curr_inode.blk_num-1), fseek (disk, Blockbeg+blksize*curr_inode.blk_identifier[i],seek_set); Fread (Dir_table+pos,sizeof (dir), left,disk);p os+=left; Dir_num=pos;return 1;} int close_dir (int inode) {int i,pos=0,left;/* data writeback disk block */for (i=0;i<curr_inode.blk_Num-1;++i) {fseek (disk,blockbeg+blksize*curr_inode.blk_identifier[i],seek_set); Fwrite (Dir_table+pos,sizeof (dir) , Dirperblk,disk);p os+=dirperblk;} left=dir_num-pos;//printf ("left:%d", left); Fseek (Disk,blockbeg+blksize*curr_inode.blk_identifier[i],seek_set); Fwrite (Dir_table+pos,sizeof (dir), Left,disk),/*inode write back to */curr_inode.file_size=dir_num*sizeof (dir), Fseek (Disk, Inodebeg+inode*sizeof (inode), Seek_set), Fwrite (&curr_inode,sizeof (Curr_inode), 1,disk); return 1;} /* Create a new Catalog entry */int make_file (int inode,char* name,int type) {int New_node;int blk_need=1;//This directory requires additional disk blocks Blk_need=2int t;if ( Dir_num>maxdirnum) {//exceeds the maximum directory entry that the catalog file can contain printf ("Mkdir:cannot Create directory '%s ':D irectory full\n", name); return 0 ;} if (Check_name (inode,name)!=-1) {//prevents renaming of printf ("Mkdir:cannnot Create file '%s ': File exist\n", name); return 0;} if (dir_num/dirperblk!= (dir_num+1)/dirperblk) {//This directory also to increase the disk block blk_need=2;} printf ("blk_used:%d\n", super_blk.blk_used); if (super_blk.blk_used+blk_need>blknum) {printf ("Mkdir:cannot Create file '%s ': BlOck used up\n ", name); return 0;} if (blk_need==2) {//This directory needs to increase disk block t=curr_inode.blk_num++;curr_inode.blk_identifier[t]=get_blk ();} /* Apply Inode*/new_node=apply_inode (), if (new_node==-1) {printf ("Mkdir:cannot Create file '%s ': Inode used up\n", name); return 0;} if (type==directory) {/* initializes the Inode*/init_dir_inode (New_node,inode) of the new Directory;} else if (type==file) {/* initializes the Inode*/init_file_inode (New_node) of the new file;} strcpy (dir_table[dir_num].name,name);d Ir_table[dir_num++].inode_num=new_node;} /* Display directory contents */int show_dir (int inode) {int i,color=32;for (i=0;i<dir_num;++i) {if (Type_check (dir_table[i].name) = = directory) {/* Directories show Green */printf ("\033[1;%dm%s\t\033[0m", Color,dir_table[i].name);} else{printf ("%s\t", Dir_table[i].name);} if (! ( (i+1)%4) printf ("\ n");//4 a line}printf ("\ n"); return 1;} /* Apply Inode*/int Apply_inode () {int i;if (super_blk.inode_used>=inodenum) {Return-1;//inode node runs out of}super_blk.inode_ Used++;for (i=0;i<inodenum;++i) {if (!super_blk.inode_map[i]) {//Find an empty I-node Super_blk.inode_map[i]=1;return i;}}} int free_inode (int inode) {Inode temp;int I;fseek (disk,inodebeg+sizeof (inode) *inode,seek_set) fread (&temp,sizeof (inode), 1,disk); for (i=0;i< Temp.blk_num;++i) {free_blk (temp.blk_identifier[i]);} Super_blk.inode_map[inode]=0;super_blk.inode_used--;return 1;} /* Enter subdirectory */int enter_dir (int inode,char* name) {int Child;child=check_name (inode,name), if (child==-1) {//The subdirectory does not exist in printf ( "CD:%s:no such file or directory\n", name); return 0;} /* Close the current directory and go to the next level directory */close_dir (inode); Inode_num=child;open_dir (child); return 1;} /* Recursive Delete folder */int del_file (int inode,char* name,int deepth) {int child,i,t;inodetemp;if (!STRCMP (Name, ".") | |! strcmp (Name, "..")) {/* does not allow deletion. and. */printf ("rmdir:failed to remove '%s ': Invalid argument\n", name); return 0;} Child=check_name (Inode,name); if (child==-1) {//subdirectory does not exist in printf ("rmdir:failed to remove '%s ': No such file or directory\n", name);} /* Reads the INODE structure of the current subdirectory */fseek (disk,inodebeg+sizeof (inode) *child,seek_set), Fread (&temp,sizeof (inode), 1,disk); Temp.type==file) {/* If the file is released, the appropriate inode can be */free_inode (child);/* If the top-level file, you need to adjust the directory */if (deepth==0) {ADJust_dir (name);} return 1;} else{/* otherwise enters subdirectory */enter_dir (inode,name);} for (i=2;i<dir_num;++i) {del_file (child,dir_table[i].name,deepth+1);} Enter_dir (Child, ".."); /return to Upper directory Free_inode (Child), if (deepth==0) {/* Delete own content in Directory */if (dir_num/dirperblk!= (dir_num-1)/dirperblk) {/* There is a disk block to release * /CURR_INODE.BLK_NUM--;T=CURR_INODE.BLK_IDENTIFIER[CURR_INODE.BLK_NUM];FREE_BLK (t);//release the corresponding disk block}adjust_dir (name) ;//Because it may be deleted at the non-end, so to move the contents of the Dir_table}/* the non-initial directory directly release Inode*/return 1;} int Adjust_dir (char* name) {int pos;for (POS=0;POS<DIR_NUM;++POS) {/* First finds the location of the deleted directory */if (strcmp, Name) ==0) break;} For (pos++;p os<dir_num;++pos) {The elements after/*pos move forward one */dir_table[pos-1]=dir_table[pos];} Dir_num--;return 1;} /* Initialize the new directory inode*/int init_dir_inode (int child,int father) {Inodetemp;dir Dot[2];intblk_pos;fseek (disk,inodebeg+ sizeof (Inode) *child,seek_set); Fread (&temp,sizeof (inode), 1,disk); blk_pos=get_blk ();//Gets the number of the new disk block temp.blk_num= 1;temp.blk_identifier[0]=blk_pos;temp.type=directory;temp.file_size=2*sizeof (Dir);/* Writes the initialized inode structure back to */fseek (DIsk,inodebeg+sizeof (inode) *child,seek_set), Fwrite (&temp,sizeof (inode), 1,disk), strcpy (Dot[0].name, "."); /point to the directory itself dot[0].inode_num=child;strcpy (Dot[1].name, ".."); Dot[1].inode_num=father;/* writes the data of the new directory into the data block */fseek (Disk,blockbeg+blksize*blk_pos,seek_set); fwrite (Dir), 2 , Disk); return 1;} /* Initializes the indoe*/int init_file_inode (int inode) {inode temp;/* of the new file to read the corresponding Inode*/fseek (disk,inodebeg+sizeof (inode) *inode, Seek_set); Fread (&temp,sizeof (Inode), 1,disk); temp.blk_num=0;temp.type=file;temp.file_size=0;/* Writes the initialized Inode back to */fseek (disk,inodebeg+sizeof (inode) *inode,seek_set), Fwrite (&temp,sizeof (inode), 1,disk); return 1;} /* Apply unused disk block */int get_blk () {int i;super_blk.blk_used++;for (i=0;i<blknum;++i) {//Find unused block if (!super_blk.blk_map[ I]) {Super_blk.blk_map[i]=1;return i;}} return-1;//no extra disk block}/* free disk block */int free_blk (int blk_pos) {super_blk.blk_used--;super_blk.blk_map[blk_pos]=0;} /* Check rename */int check_name (int inode,char* name) {int i;for (i=0;i<dir_num;++i) {/* There is a rename */if (strcmp (name,dir_table[i) . Name) ==0) {RetuRN Dir_table[i].inode_num;}} return-1;} void Change_path (char *name) {int pos;if (strcmp (Name, ".") ==0) {//Enter this directory without changing the path to return;} else if (strcmp (name, "...") ==0) {//Enter the upper directory to remove the last '/' content Pos=strlen (path) -1;for (;p os>=0;--pos) {if (path[pos]== '/') {path[pos]= '} '; break;}}} else {//otherwise add subdirectories strcat (path, "/") at the end of the path; strcat (path,name);} return;} int Type_check (char* name) {int I,inode;inode temp;for (i=0;i<dir_num;++i) {if (strcmp (name,dir_table[i].name) ==0) { Inode=dir_table[i].inode_num;fseek (disk,inodebeg+sizeof (inode) *inode,seek_set) fread (&temp,sizeof (inode), 1 , Disk); return temp.type;}} return-1;//the file or directory does not exist}/* read file function */int file_read (char* name) {int inode,i,blk_num;inodetemp; File*fp=fopen (BUFF, "w+"), Char buff[blksize];//printf ("read\n"); Inode=check_name (inode_num,name); Fseek (Disk, Inodebeg+sizeof (Inode) *inode,seek_set) fread (&temp,sizeof (temp), 1,disk); if (temp.blk_num==0) {//If the source file has no content, Exit Fclose directly (FP); return 1;} printf ("read\n"); for (i=0;i<temp.blk_num-1;++i) {blk_num=temp.blk_identifier[i];/* reads the disk blocks contained in the file */fsEEK (Disk,blockbeg+blksize*blk_num,seek_set); Fread (Buff,sizeof (char), blksize,disk);/* Write Buff*/fwrite (buff,sizeof (char), BLKSIZE,FP); free_blk (blk_num);//Release the disk block directly temp.file_size-=blksize;} /* The last block of disk may not be full */blk_num=temp.blk_identifier[i];fseek (Disk,blockbeg+blksize*blk_num,seek_set); Fread (Buff,sizeof ( char), Temp.file_size,disk), Fwrite (Buff,sizeof (char), TEMP.FILE_SIZE,FP), free_blk (blk_num);/* Modify inode Information */ Temp.file_size=0;temp.blk_num=0;/* writes the modified Inode back to */fseek (disk,inodebeg+sizeof (inode) *inode,seek_set); Fwrite (& Temp,sizeof (Inode), 1,disk); fclose (FP); return 1;} /* Write the file function */int file_write (char* name) {int inode,i;intnum,blk_num; file* Fp=fopen (BUFF, "R"); Inodetemp;charbuff[blksize];inode=check_name (inode_num,name); Fseek (disk,inodebeg+ sizeof (Inode) *inode,seek_set), Fread (&temp,sizeof (inode), 1,disk), while (Num=fread (buff,sizeof (char), blksize, FP) {printf ("num:%d\n", num), if ((Blk_num=get_blk ()) ==-1) {printf ("Error:block has been used up\n"); /* Change the corresponding state of the inode structure */temp.blk_identifier[temp.blk_num++]=blk_num;temp.file_size+=num;/* writes data back to disk block */fseek (disk,blockbeg+blksize*blk_num,seek_set); Fwrite (Buff,sizeof (char), num,Disk) ;} /* Write the modified Inode back to */fseek (disk,inodebeg+sizeof (inode) *inode,seek_set), Fwrite (&temp,sizeof (inode), 1,disk); Fclose (FP); return 1;}
Analog File system