本周进行操作系统课程设计,在很多的题目中选了个unix文件系统模拟,主要就是操作结构与文件。
为了方便,文件系统结构如下:
Super block -- Block bitmap -- Inode bitmap -- Inode table -- Block zone
其中:
Super block: 存储基本信息
Block bitmap:块分配情况
Inode bitmap:索引节点分配情况
Inode table: Indoe 节点存放区
Block zone:存放数据区
效果如下:
总的说来,做的还是挺简单的,只是实现了基本的功能.而块的分配没有怎么完成,linux系统中一般是通过多级索引的方式为inode分配块.
刚开始我的想法是:inode的块(512B)只写510B,留下2B用于记录下一块的块号,我觉得应该可行,但觉得繁,就没有写下去.所以就没有多余的
块分配操作.知识INode对应一个Block....,太懒了.还有一个缺点,文件指针移动太频繁了,而且都是绝对定位移动(好算,呵呵)
代码如下:
/*核心思想:一切皆是文件
如果是目录:Block中存储的是目录下文件和目录的fcb
如果是文件:Block中存储的是文件的内容
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <signal.h>
#define BLOCKSIZE 512
#define BLOCKNUM 512
#define INODENUM 30
#define FILENAME "file.dat"
typedef struct{
unsigned short blockSize;
unsigned short blockNum;
unsigned short inodeNum;
unsigned short blockFree;
unsigned short inodeFree;
}SuperBlock;
typedef struct{
unsigned short inum;
char fileName[10];
unsigned short isDir; // 0-file 1-dir
unsigned short iparent;
unsigned short length; //if file->filesize if dir->filenum
unsigned short blockNum;
}Inode,*PtrInode;
//Fcb用于存储文件与 目录信息,主要用途:将一个目录下的所有文件(包括目录)写入到该目录对应的Block中
typedef struct {
unsigned short inum;
char fileName[10];
unsigned short isDir;
}Fcb,*PtrFcb;
typedef struct{
char userName[10];
char passWord[10];
}User;
char blockBitmap[BLOCKNUM];
char inodeBitmap[INODENUM];
SuperBlock superBlock;
User curUser=(User){"root","root"};
unsigned short currentDir; //current inodenum
FILE *fp;
const unsigned short superBlockSize=sizeof(superBlock);
const unsigned short blockBitmapSize=sizeof(blockBitmap);
const unsigned short inodeBitmapSize=sizeof(inodeBitmap);
const unsigned short inodeSize=sizeof(Inode);
const unsigned short fcbSize=sizeof(Fcb);
char *argv[5];
int argc;
void createFileSystem()
/*创建*/
{
long len;
PtrInode fileInode;
if ((fp=fopen(FILENAME,"wb+"))==NULL)
{
printf("open file %s error...\n",FILENAME);
exit(1);
}
//init bitmap
for(len=0;len<BLOCKNUM;len++)
blockBitmap[len]=0;
for(len=0;len<INODENUM;len++)
inodeBitmap[len]=0;
//memset
for (len=0;len<(superBlockSize+blockBitmapSize+inodeBitmapSize+inodeSize*INODENUM+BLOCKSIZE*BLOCKNUM);len++)
{
fputc(0,fp);
}
rewind(fp);
//init superBlock
superBlock.blockNum=BLOCKNUM;
superBlock.blockSize=BLOCKSIZE;
superBlock.inodeNum=INODENUM;
superBlock.blockFree=BLOCKNUM-1;
superBlock.inodeFree=INODENUM-1;
fwrite(&superBlock,superBlockSize,1,fp);
//create root
fileInode=(PtrInode)malloc(inodeSize);
fileInode->inum=0;
strcpy(fileInode->fileName,"/");
fileInode->isDir=1;
fileInode->iparent=0;
fileInode->length=0;
fileInode->blockNum=0;
//write / info to file
inodeBitmap[0]=1;
blockBitmap[0]=1;
fseek(fp,superBlockSize,SEEK_SET);
fwrite(blockBitmap,blockBitmapSize,1,fp);
fseek(fp,superBlockSize+blockBitmapSize,SEEK_SET);
fwrite(inodeBitmap,inodeBitmapSize,1,fp);
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize,SEEK_SET);
fwrite(fileInode,inodeSize,1,fp);
fflush(fp);
//point to currentDir
currentDir=0;
}
void openFileSystem()
/*如果FILENAME可读,则代表之前已有信息,并读取相应数据 如果不可读,则创建文件系统 */
{
if((fp=fopen(FILENAME,"rb"))==NULL)
{
createFileSystem();
}
else
{
if ((fp=fopen(FILENAME,"rb+"))==NULL)
{
printf("open file %s error...\n",FILENAME);
exit(1);
}
rewind(fp);
//read superBlock from file
fread(&superBlock,superBlockSize,1,fp);
//read bitmap from file
fread(blockBitmap,blockBitmapSize,1,fp);
fread(inodeBitmap,inodeBitmapSize,1,fp);
//init current dir
currentDir=0;
}
}
void createFile(char *name,int flag) //flag=0 ->create file =1 ->directory
{
int i,nowBlockNum,nowInodeNUm;
PtrInode fileInode=(PtrInode)malloc(inodeSize);
PtrInode parentInode=(PtrInode)malloc(inodeSize);
PtrFcb fcb=(PtrFcb)malloc(fcbSize);
//the available blockNumber
for(i=0;i<BLOCKNUM;i++)
{
if(blockBitmap[i]==0)
{
nowBlockNum=i;
break;
}
}
//the available inodeNumber
for(i=0;i<INODENUM;i++)
{
if(inodeBitmap[i]==0)
{
nowInodeNUm=i;
break;
}
}
//init fileINode struct
fileInode->blockNum=nowBlockNum;
strcpy(fileInode->fileName,name);
fileInode->inum=nowInodeNUm;
fileInode->iparent=currentDir;
if(flag==0)
{
fileInode->isDir=0;
}
else
{
fileInode->isDir=1;
}
fileInode->length=0;
//write fileInfo to file
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+inodeSize*nowInodeNUm,SEEK_SET);
fwrite(fileInode,inodeSize,1,fp);
//update superBlock and bitmap
superBlock.blockFree-=1;
superBlock.inodeFree-=1;
blockBitmap[nowBlockNum]=1;
inodeBitmap[nowInodeNUm]=1;
//init fcb info
strcpy(fcb->fileName,fileInode->fileName);
fcb->inum=fileInode->inum;
fcb->isDir=fileInode->isDir;
//update to file ...
//update parent dir block info
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
fread(parentInode,inodeSize,1,fp);
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+parentInode->blockNum*BLOCKSIZE+parentInode->length*fcbSize,SEEK_SET);
fwrite(fcb,fcbSize,1,fp);
//update parent dir inode info
parentInode->length+=1;
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
fwrite(parentInode,inodeSize,1,fp);
// free resource
free(fileInode);
free(parentInode);
free(fcb);
}
void list()
{
int i;
PtrFcb fcb=(PtrFcb)malloc(fcbSize);
PtrInode parentInode=(PtrInode)malloc(inodeSize);
//read parent inode info from file
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
fread(parentInode,inodeSize,1,fp);
//point to parent dir block
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+inodeSize*INODENUM+parentInode->blockNum*BLOCKSIZE,SEEK_SET);
//list info
for(i=0;i<parentInode->length;i++)
{
fread(fcb,fcbSize,1,fp);
printf("Filename: %-10s",fcb->fileName);
printf("Inode number: %-2d ",fcb->inum);
if(fcb->isDir==1)
{
printf("Directory\n");
}
else
{
printf("Regular file\n");
}
}
//free resource
free(fcb);
free(parentInode);
}
int findInodeNum(char *name,int flag) //flag=0 ->find file flag=1 -> find dir
{
int i,fileInodeNum;
PtrInode parentInode=(PtrInode)malloc(inodeSize);
PtrFcb fcb=(PtrFcb)malloc(fcbSize);
//read current inode info from file
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
fread(parentInode,inodeSize,1,fp);
//read the fcb in the current dir block
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+inodeSize*INODENUM+parentInode->blockNum*BLOCKSIZE,SEEK_SET);
for(i=0;i<parentInode->length;i++)
{
fread(fcb,fcbSize,1,fp);
if(flag==0)
{
if((fcb->isDir==0)&&(strcmp(name,fcb->fileName)==0))
{
fileInodeNum=fcb->inum;
break;
}
}
else
{
if((fcb->isDir==1)&&(strcmp(name,fcb->fileName)==0))
{
fileInodeNum=fcb->inum;
break;
}
}
}
if(i==parentInode->length)
fileInodeNum=-1;
free(fcb);
free(parentInode);
return fileInodeNum;
}
void cd(char *name)
{
int fileInodeNum;
PtrInode fileInode=(PtrInode)malloc(inodeSize);
if(strcmp(name,"..")!=0)
{
fileInodeNum=findInodeNum(name,1);
if(fileInodeNum==-1)
printf("This is no %s directory...\n",name);
else
{
currentDir=fileInodeNum;
}
}
else
{
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
fread(fileInode,inodeSize,1,fp);
currentDir=fileInode->iparent;
}
free(fileInode);
}
void cdParent()
{
PtrInode fileInode=(PtrInode)malloc(inodeSize);
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
fread(fileInode,inodeSize,1,fp);
currentDir=fileInode->iparent;
free(fileInode);
}
void write(char *name)
{
int fileInodeNum,i=0;
char c;
PtrInode fileInode=(PtrInode)malloc(inodeSize);
if((fileInodeNum=findInodeNum(name,1))!=-1)
{
printf("This is a directory,not a file...\n");
return;
}
fileInodeNum=findInodeNum(name,0);
if(fileInodeNum==-1)
printf("This is no %s file...\n",name);
else
{
//get inode->blocknum
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInodeNum*inodeSize,SEEK_SET);
fread(fileInode,inodeSize,1,fp);
//point to the block site
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+fileInode->blockNum*BLOCKSIZE,SEEK_SET);
printf("please input file content(stop by #):\n");
while((c=getchar())!='#')
{
fputc(c,fp);
i++;
}
//update inode->length
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInodeNum*inodeSize,SEEK_SET);
fread(fileInode,inodeSize,1,fp);
fileInode->length=i-1;
fseek(fp,-inodeSize,SEEK_CUR);
fwrite(fileInode,inodeSize,1,fp);
}
free(fileInode);
}
void read(char *name)
{
int fileInodeNum;
char c;
PtrInode fileInode=(PtrInode)malloc(inodeSize);
if((fileInodeNum=findInodeNum(name,1))!=-1)
{
printf("This is a directory,not a file...\n");
return;
}
fileInodeNum=findInodeNum(name,0);
if(fileInodeNum==-1)
printf("This is no %s file...\n",name);
else
{
//get inode->blocknum
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInodeNum*inodeSize,SEEK_SET);
fread(fileInode,inodeSize,1,fp);
//point to the block site
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+fileInode->blockNum*BLOCKSIZE,SEEK_SET);
//read content
if(fileInode->length!=0)
{
while((c=fgetc(fp))!=EOF)
{
putchar(c);
}
printf("\n");
}
}
free(fileInode);
}
void delete(char *name)
/*delete 一个文件,需要修改SuperBlock,Blockbitmap,Inodebitmap,并更新父节点长度,删除父节点Block中存储的该文件fcb*/
{
int fileInodeNum,i;
PtrInode fileInode=(PtrInode)malloc(inodeSize);
PtrInode parentInode=(PtrInode)malloc(inodeSize);
Fcb fcb[20];
if(((fileInodeNum=findInodeNum(name,0))==-1)&&((fileInodeNum=findInodeNum(name,1))==-1))
{
printf("This is no %s...\n",name);
}
else
{
if((fileInodeNum=findInodeNum(name,0))==-1)
{
fileInodeNum=findInodeNum(name,1);
}
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInodeNum*inodeSize,SEEK_SET);
fread(fileInode,inodeSize,1,fp);
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInode->iparent*inodeSize,SEEK_SET);
fread(parentInode,inodeSize,1,fp);
//update parent info
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+parentInode->blockNum*BLOCKSIZE,SEEK_SET);
for(i=0;i<parentInode->length;i++)
{
fread(&fcb[i],fcbSize,1,fp);
//fcb[i]=tmp;
}
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+parentInode->blockNum*BLOCKSIZE,SEEK_SET);
for(i=0;i<BLOCKSIZE;i++)
fputc(0,fp);
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+parentInode->blockNum*BLOCKSIZE,SEEK_SET);
for(i=0;i<parentInode->length;i++)
{
if((strcmp(fcb[i].fileName,name))!=0)
{
fwrite(&fcb[i],fcbSize,1,fp);
}
}
parentInode->length-=1;
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInode->iparent*inodeSize,SEEK_SET);
fwrite(parentInode,inodeSize,1,fp);
//update bitmap
inodeBitmap[fileInodeNum]=0;
blockBitmap[fileInode->blockNum]=0;
//update superblock
superBlock.blockFree+=1;
superBlock.inodeFree+=1;
}
free(fileInode);
free(parentInode);
}
void updateResource()
{
rewind(fp);
fwrite(&superBlock,superBlockSize,1,fp);
fwrite(blockBitmap,blockBitmapSize,1,fp);
fwrite(inodeBitmap,inodeBitmapSize,1,fp);
fclose(fp);
}
void pathSet()
{
PtrInode curInode=(PtrInode)malloc(inodeSize);
fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
fread(curInode,inodeSize,1,fp);
printf("%s@localhost:%s#",curUser.userName,curInode->fileName);
free(curInode);
}
void systemInfo()
{
printf("Sum of block number:%d\n",superBlock.blockNum);
printf("Each block size:%d\n",superBlock.blockSize);
printf("Free of block number:%d\n",superBlock.blockFree);
printf("Sum of inode number:%d\n",superBlock.inodeNum);
printf("Free of inode number:%d\n",superBlock.inodeFree);
}
void help()
{
printf("command: \n\
help --- show help menu \n\
sysinfo --- show system base information \n\
cls --- clear the screen \n\
cd --- change directory \n\
mkdir --- make directory \n\
touch --- create a new file \n\
cat --- read a file \n\
write --- write something to a file \n\
logout --- exit user \n\
rm --- delete a directory or a file \n\
exit --- exit this system\n");
}
int analyse(char *str)
{
int i;
char temp[20];
char *ptr_char;
char *syscmd[]={"help","ls","cd","mkdir","touch","cat","write","rm","logout","exit","sysinfo","cls"};
argc = 0;
for(i = 0, ptr_char = str; *ptr_char != '\0'; ptr_char++)
{
if(*ptr_char != ' ')
{
while(*ptr_char != ' ' && (*ptr_char != '\0'))
temp[i++] = *ptr_char++;
argv[argc] = (char *)malloc(i+1);
strncpy(argv[argc], temp, i);
argv[argc][i] = '\0';
argc++;
i = 0;
if(*ptr_char == '\0')
break;
}
}
if(argc != 0)
{
for(i = 0; (i < 12) && strcmp(argv[0], syscmd[i]); i++);
return i;
}
else
return 12;
return 0;
}
void login()
{
char userName[10];
char passWord[10];
while(1)
{
printf("login:");
gets(userName);
system("stty -echo");
printf("passwd:");
gets(passWord);
system("stty echo");
printf("\n");
if(strcmp(userName,curUser.userName)==0&&strcmp(passWord,curUser.passWord)==0)
break;
}
}
void stopHandle(int sig)
{
printf("\nPlease wait...,update resource\n");
updateResource();
exit(0);
}
void command(void)
{
char cmd[20];
do
{
pathSet();
gets(cmd);
switch(analyse(cmd))
{
case 0:
help();
break;
case 1:
list();
break;
case 2:
cd(argv[1]);
break;
case 3:
createFile(argv[1],1);
break;
case 4:
createFile(argv[1],0);
break;
case 5:
read(argv[1]);
break;
case 6:
write(argv[1]);
break;
case 7:
delete(argv[1]);
break;
case 8:
updateResource();
login();
openFileSystem();
command();
break;
case 9:
updateResource();
exit(0);
break;
case 10:
systemInfo();
break;
case 11:
system("clear");
break;
default:
break;
}
}while(1);
}
int main(int argc,char **argv){
signal(SIGINT,stopHandle);
login();
openFileSystem();
command();
return 0;
}