注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

独立观察员·网易

分享万岁

 
 
 

日志

 
 

[操作系统]简单文件系统(FAT)  

2013-06-19 15:21:00|  分类: 原新浪博客的 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
//简单文件系统D.cpp
#include
#include
#include
#include

#define BLOCKSIZE 1024  // 磁盘块大小
#define SIZE 1024000  // 虚拟磁盘空间大小
#define END 655  // FAT中的文件结束标志
#define FREE 0  // FAT中盘块空闲标志
#define ROOTBLOCKNUM 2  // 根目录区所占盘块数
#define MAXOPENFILE 10  // 最多同时打开文件个数
#define MAXTEXT 10000

typedef struct FCB
{
    char filename[8];  // 文件名
    char exname[3];  // 文件扩展名
    unsigned char attribute;  // 文件属性字段,值为0时表示目录文件,值为1时表示数据文件
    unsigned short time;  // 文件创建时间
    unsigned short date;  // 文件创建日期
    unsigned short first;  // 文件起始盘块号
    unsigned long length;  // 文件长度
    char free;  // 表示目录项是否为空,若值为0,表示空,值为1,表示已分配;
}fcb;

typedef struct FAT { //文件分配表; 
unsigned short id;
}fat;

//用户文件描述符和内存FCB表合在一起,称为用户打开文件表; 
typedef struct USEROPEN{
char filename[8];
char exname[3];
unsigned char attribute;
unsigned short time;
unsigned short date;
unsigned short first;  // 文件起始盘块号; 
unsigned long length; // 文件长度; 
char free; // 表示目录项是否为空,若值为0,表示空,值为1,表示已分配; 
int dirno;  // 相应打开文件的目录项在父目录文件中的盘块号; 
int diroff; // 相应打开文件的目录项在父目录文件的dirno盘块中的目录项序号; 
char dir[80]; // 相应打开文件所在的目录名,这样方便快速检查出指定文件是否已经打开;
int father;  // 父目录在打开文件表项的位置; 
int count;   // 读写指针在文件中的位置; 
char fcbstate;  // 是否修改了文件的FCB的内容,如果修改了置为1,否则为0
char topenfile;  // 表示该用户打开表项是否为空,若值为0,表示为空;否则表示已被某打开文件占据; 
}useropen;

typedef struct BLOCK0
{
    char magic[10];  // 文件系统魔数;
char information[200];  // 存储一些描述信息,如磁盘块大小、磁盘块数量、最多打开文件数等
    unsigned short root;  // 根目录文件的起始盘块号
unsigned char *startblock;  // 虚拟磁盘上数据区开始位置
}block0;

//全局变量; 
unsigned char * myvhard;  //虚拟磁盘起始地址; 
useropen openfilelist[MAXOPENFILE]; //用户打开文件表数组; 
int ptrcurdir;  //当前目录在用户打开文件表的位置; 
char currentdir[80];  // 当前目录名; 
unsigned char * startp;  // 记录虚拟磁盘上数据区开始位置; 
char * currentPath="Root:\\";   //当前路径 ;
const char * FilePath = "C:\\myfsys2"; 
FILE * fp;    //磁盘文件地址;
fcb * root;  //根目录;

//函数声明; 
void my_format();
void my_cd(char * dirname);
void my_mkdir(char * dirname);
void my_rmdir(char *dirname);
void my_ls(void);
void my_create(char *filename);
void my_rmf(char * filename);
int  my_open(char *filename);
int  my_close(int fd);
int  my_write(int fd);
int  do_write(int fd, char * text, int len, char wstyle);
int  my_read(int fd, int len);
int  do_read(int fd, int len, char * text);
void my_exitsys();
int  findblock();
int  findopenfile();
int  findopenned(char * filename); 

void startsys(){
unsigned char buf[SIZE]; //读文件缓冲区; 
myvhard = (unsigned char *)malloc(SIZE);  //申请虚拟空间;
memset(myvhard, 0, SIZE); // 初始化;

if((fp = fopen(FilePath, "r")) != NULL){ //打开磁盘文件; 
   fread(buf, SIZE, 1, fp);  //读入缓存区; 
   fclose(fp);
   if(strcmp(((block0 *)buf)->magic, "10101010")){
       printf("文件系统魔数不匹配!开始格式化...\n");
       my_format();
   }
   else{
       for(int i=0; i < SIZE; i++)
                myvhard[i] = buf[i];
   }
}
else{
   printf("%s不存在,开始创建...\n",FilePath);
   my_format();
}
root = (fcb *)(myvhard + 5 * BLOCKSIZE); //根目录首地址; 
//用户打开文件表表项0分配给根目录文件使用; 
strcpy(openfilelist[0].filename, root->filename);
strcpy(openfilelist[0].exname, root->exname);
openfilelist[0].attribute = root->attribute;
openfilelist[0].time = root->time;
openfilelist[0].date = root->date;
openfilelist[0].first = root->first;
openfilelist[0].length = root->length;
openfilelist[0].free = root->free;
openfilelist[0].dirno = 5; //第六块; 
openfilelist[0].diroff = 0;
strcpy(openfilelist[0].dir, "root\\"); //打开文件所在的目录名; 
openfilelist[0].father = 0;
openfilelist[0].count = 0;  //读写指针位置; 
openfilelist[0].fcbstate = 0;
openfilelist[0].topenfile = 1;  //置表项为非空;
 
//置其它表项为空; 
for(int i = 1; i < MAXOPENFILE; i++)
        openfilelist[i].topenfile = 0;
        
ptrcurdir = 0; //当前表项; 
strcpy(currentdir, "root\\"); //当前目录名; 
startp = ((block0 *)myvhard)->startblock;  //数据区开始位置;
printf("文件系统启动完成!\n"); 
}

void my_format()
{
int i;
fat *fat1, *fat2;
block0 *blk0;
time_t now;  //time_t为系统类型; 
struct tm * nowtime;  //在C语言中有time_t tm timeval等几种类型的时间 ;
blk0 = (block0 *)myvhard;  //引导块位于虚拟磁盘首部; 
fat1 = (fat *)(myvhard + BLOCKSIZE); //FAT1; 
fat2 = (fat *)(myvhard + 3 * BLOCKSIZE); //FAT2; 
root = (fcb *)(myvhard + 5 * BLOCKSIZE); 
//引导块赋值; 
strcpy(blk0->magic, "10101010");  //磁盘魔数赋值; 
strcpy(blk0->information, "The FileSystem Ver 1.0 \n Blocksize=1024B Whole size=1024000B Blocknum=1000 RootBlocknum=2\n");
blk0->root = 5;
blk0->startblock = (unsigned char *)root; 
for(i = 0; i < 5; i++){
        fat1->id = END;
        fat2->id = END;
        fat1++;
        fat2++;
    }
    //根目录区在第六块和第七块; 
    fat1->id = 6;
    fat2->id = 6;
    fat1++;
    fat2++;
    fat1->id = END;
    fat2->id = END;
    fat1++;  //指针顺序下移; 
    fat2++;
    //数据区磁盘块空闲; 
    for(i = 7; i < 1000; i++)
    {
        fat1->id = FREE;
        fat2->id = FREE;
        fat1++;
        fat2++;
    }
    
    now = time(NULL); //返回一个关于时间的大整数; 
    nowtime = localtime(&now);  //转换为本地时间;
//建立目录. ; 
    strcpy(root->filename, ".");
    strcpy(root->exname, "");
    root->attribute = 0x28;  //0x表示十六进制, 二进制为101000; 
    root->time = nowtime->tm_hour * 2048 + nowtime->tm_min * 32 + nowtime->tm_sec / 2;
root->date = (nowtime->tm_year - 80) * 512 + (nowtime->tm_mon + 1) * 32 + nowtime->tm_mday;
root->first = 5;
root->length = 2 * sizeof(fcb);
root->free = 1;
//建立目录.. ; 
root++;
now = time(NULL);
    nowtime = localtime(&now);
strcpy(root->filename, "..");
    strcpy(root->exname, "");
    root->attribute = 0x28;
    root->time = nowtime->tm_hour * 2048 + nowtime->tm_min * 32 + nowtime->tm_sec / 2;
root->date = (nowtime->tm_year - 80) * 512 + (nowtime->tm_mon + 1) * 32 + nowtime->tm_mday;
root->first = 5;
root->length = 2 * sizeof(fcb);
root->free = 1;  //已分配表项; 
//写回磁盘; 
    fp = fopen(FilePath, "w");
    fwrite(myvhard, SIZE, 1, fp);
    fclose(fp);
    printf("磁盘格式化成功!\n"); 
}

void my_cd(char * dirname)
{
    char * dir;
int fd;
dir = strtok(dirname, "\\");  //分解字符串为一组字符串,将'\'转为'\0'; 
if(strcmp(dir, ".") == 0)
        return;  //转到当前路径则不做处理; 
  //转到上层目录; 
    else if(strcmp(dir, "..") == 0)
    {
        if(ptrcurdir)
            ptrcurdir = my_close(ptrcurdir);  //关闭当前路径,返回值为父路径在打开表的位置; 
        return;
    }
    
    else if(strcmp(dir, "root") == 0)
    {
        while(ptrcurdir)
            ptrcurdir = my_close(ptrcurdir);  //循环关闭root下的打开文件; 
        dir = strtok(NULL, "\\");  //剩下的路径; 
    }
    while(dir)
    {
        fd = my_open(dir);  //fd为新打开的目录分配到的打开表项位置; 
        if(fd != -1)  //成功转入路径; 
            ptrcurdir = fd;   //打开表项序号; 
        else
            return;
        dir = strtok(NULL, "\\"); //剩下的路径;
    }
    printf("目录跳转完成\n");
}

void my_mkdir(char * dirname)
{
    fcb * fcbptr;  
    fat *fat1, *fat2;
    time_t now;
struct tm *nowtime;
    char text[MAXTEXT]; //存放打开表项中的内容 ; 
    short blkno;
    int rbn, fd, i;
    //文件分配表起始位置; 
    fat1 = (fat *)(myvhard + BLOCKSIZE);
    fat2 = (fat *)(myvhard + 3 * BLOCKSIZE);
    openfilelist[ptrcurdir].count = 0;  //读写指针置 0; 
    rbn = do_read(ptrcurdir, openfilelist[ptrcurdir].length, text);//读入当前目录的用户打开表内容到内存(存到 text里); 
    fcbptr = (fcb *)text; 
    for(i = 0; i < rbn / sizeof(fcb); i++) {
//检查新建目录是否重名; 
        if(strcmp(fcbptr->filename, dirname) == 0 && strcmp(fcbptr->exname, "") == 0){
            printf("Error,the dirname is already exist!\n");
            return;
        }
        fcbptr++;
    }
    fcbptr = (fcb *)text;
    for(i = 0; i < rbn / sizeof(fcb); i++)
    {
        if(fcbptr->free == 0)
            break;  //找到空闲的打开表项 ; 
        fcbptr++;
    }
    blkno = findblock();//寻找空闲盘块 ; 
    if(blkno == -1)
        return;
    (fat1 + blkno)->id = END;
    (fat2 + blkno)->id = END;

//写 FCB信息 ; 
    now = time(NULL);
    nowtime = localtime(&now);
    strcpy(fcbptr->filename, dirname);
    strcpy(fcbptr->exname, "");
    fcbptr->attribute = 0x30;
    fcbptr->time = nowtime->tm_hour * 2048 + nowtime->tm_min * 32 + nowtime->tm_sec / 2;
fcbptr->date = (nowtime->tm_year - 80) * 512 + (nowtime->tm_mon + 1) * 32 + nowtime->tm_mday;
fcbptr->first = blkno;  // 文件起始盘块号; 
fcbptr->length = 2 * sizeof(fcb);
fcbptr->free = 1;
openfilelist[ptrcurdir].count = i * sizeof(fcb);
do_write(ptrcurdir, (char *)fcbptr, sizeof(fcb), 2);

fd = my_open(dirname);  //取得该目录的用户打开表项序号; 
if(fd == -1)
        return;
        
  //在新建的目录文件所分配到的磁盘块中建立目录项"."和 ".." ; 
fcbptr = (fcb *)malloc(sizeof(fcb));
    now = time(NULL);
    nowtime = localtime(&now);
strcpy(fcbptr->filename, ".");
strcpy(fcbptr->exname, "");
fcbptr->attribute = 0x28;
fcbptr->time = nowtime->tm_hour * 2048 + nowtime->tm_min * 32 + nowtime->tm_sec / 2;
fcbptr->date = (nowtime->tm_year - 80) * 512 + (nowtime->tm_mon + 1) * 32 + nowtime->tm_mday;
fcbptr->first = blkno;
fcbptr->length = 2 * sizeof(fcb);
fcbptr->free = 1;
do_write(fd, (char *)fcbptr, sizeof(fcb), 2); 
now = time(NULL);
    nowtime = localtime(&now);
strcpy(fcbptr->filename, "..");
strcpy(fcbptr->exname, "");
fcbptr->attribute = 0x28;
fcbptr->time = nowtime->tm_hour * 2048 + nowtime->tm_min * 32 + nowtime->tm_sec / 2;
fcbptr->date = (nowtime->tm_year - 80) * 512 + (nowtime->tm_mon + 1) * 32 + nowtime->tm_mday;
fcbptr->first = blkno;
fcbptr->length = 2 * sizeof(fcb);
fcbptr->free = 1;
do_write(fd, (char *)fcbptr, sizeof(fcb), 2);
free(fcbptr);
my_close(fd);

fcbptr = (fcb *)text;
fcbptr->length = openfilelist[ptrcurdir].length;
openfilelist[ptrcurdir].count = 0;
do_write(ptrcurdir, (char *)fcbptr, sizeof(fcb), 2);
    openfilelist[ptrcurdir].fcbstate = 1;
    printf("创建目录成功!\n");
}

void my_rmdir(char *dirname)
{   //删除目录; 
    fcb *fcbptr,*fcbptr2;
    fat *fat1, *fat2, *fatptr1, *fatptr2;
char text[MAXTEXT], text2[MAXTEXT];
unsigned short blkno;
int rbn, rbn2, fd, i, j;
fat1 = (fat *)(myvhard + BLOCKSIZE);
    fat2 = (fat *)(myvhard + 3 * BLOCKSIZE);
if(strcmp(dirname, ".") == 0 || strcmp(dirname, "..") == 0)
{   //不能删除"."和".."目录; 
   printf("Error,can't remove this directory.\n");
   return;
}
openfilelist[ptrcurdir].count = 0;
rbn = do_read(ptrcurdir, openfilelist[ptrcurdir].length, text);//读取相关信息; 
fcbptr = (fcb *)text;
for(i = 0; i < rbn / sizeof(fcb); i++)
{   //寻找要删除的目录; 
   if(strcmp(fcbptr->filename, dirname) == 0 && strcmp(fcbptr->exname, "") == 0)
            break;
   fcbptr++;
}
if(i == rbn / sizeof(fcb))
{
   printf("出错,该目录不存在.\n");
        return;
}
fd = my_open(dirname);  //打开要删目录; 
rbn2 = do_read(fd, openfilelist[fd].length, text2);
fcbptr2 = (fcb *)text2;
for(j = 0; j < rbn2 / sizeof(fcb); j++)
{
   if(strcmp(fcbptr2->filename, ".") && strcmp(fcbptr2->filename, "..") && strcmp(fcbptr2->filename, ""))
   {
       my_close(fd);
       printf("出错,该目录非空!\n");
return;
   }
   fcbptr2++;
}
    blkno = openfilelist[fd].first;
    while(blkno != END)
    { //将所有占用盘块置为空闲; 
        fatptr1 = fat1 + blkno;
        fatptr2 = fat2 + blkno;
        blkno = fatptr1->id;
        fatptr1->id = FREE;
        fatptr2->id = FREE;
    }
    my_close(fd);
    
    //将相应FCB"归零"; 
    strcpy(fcbptr->filename, "");
    fcbptr->free = 0;
    openfilelist[ptrcurdir].count = i * sizeof(fcb);
    do_write(ptrcurdir, (char *)fcbptr, sizeof(fcb), 2);
    
    openfilelist[ptrcurdir].fcbstate = 1; //修改位置1; 
    printf("删除目录成功!\n");
}

void my_ls()
{   //列出当前目录下的内容; 
    fcb *fcbptr;
char text[MAXTEXT];
int rbn, i;
openfilelist[ptrcurdir].count = 0;
rbn = do_read(ptrcurdir, openfilelist[ptrcurdir].length, text); //读取当前目录所有内容; 
fcbptr = (fcb *)text;
for(i = 0; i < rbn / sizeof(fcb); i++)
    {
        if(fcbptr->free)  //如果目录项已分配(非空); 
        {
            if(fcbptr->attribute & 0x20) //是目录(文件夹);&表示按位与; 0x20的二进制数为100000 ; 
printf("%s\\\t\t
\t\t%d/%d/%d\td:d:d\n", fcbptr->filename, (fcbptr->date >> 9) + 1980, (fcbptr->date >> 5) & 0x000f, fcbptr->date & 0x001f, fcbptr->time >> 11, (fcbptr->time >> 5) & 0x003f, fcbptr->time & 0x001f * 2);
else //是文件; 
                printf("%s.%s\t\t?\t\t%d/%d/%d\td:d:d\t\n", fcbptr->filename, fcbptr->exname, (int)(fcbptr->length), (fcbptr->date >> 9) + 1980, (fcbptr->date >> 5) & 0x000f, fcbptr->date & 0x1f, fcbptr->time >> 11, (fcbptr->time >> 5) & 0x3f, fcbptr->time & 0x1f * 2);
        }
        fcbptr++;
    }
    printf("没有更多文件了.\n");
}

void my_create(char *filename)
{   //创建文件; 
    fcb *fcbptr;
    fat *fat1, *fat2;
    char *fname, *exname, text[MAXTEXT];
    short blkno;
int rbn, i;
time_t now;
struct tm *nowtime;
fat1 = (fat *)(myvhard + BLOCKSIZE);
fat2 = (fat *)(myvhard + BLOCKSIZE);
//分解文件名和扩展名; 
fname = strtok(filename, ".");
exname = strtok(NULL, ".");
if(strcmp(fname, "") == 0)
{
   printf("出错,创建文件必须有一个正确的名字!\n");
return;
}
if(!exname)
{
   printf("出错,创建文件必须有扩展名!\n");
return;
}
openfilelist[ptrcurdir].count = 0;
rbn = do_read(ptrcurdir, openfilelist[ptrcurdir].length, text);
fcbptr = (fcb *)text;
for(i = 0; i < rbn / sizeof(fcb); i++)
{
   if(strcmp(fcbptr->filename, fname) == 0 && strcmp(fcbptr->exname, exname) == 0)
   {
       printf("出错,同名文件已经存在!\n");
return;
   }
   fcbptr++;
}
    fcbptr = (fcb *)text;
for(i = 0; i < rbn / sizeof(fcb); i++)
{ //寻找空闲FCB; 
   if(fcbptr->free == 0)
            break;
        fcbptr++;
}
blkno = findblock();//寻找空闲盘块; 
if(blkno == -1)
        return;
    (fat1 + blkno)->id = END; //先占用一块; 
    (fat2 + blkno)->id = END;
//属性赋值; 
    now = time(NULL);
    nowtime = localtime(&now);
    strcpy(fcbptr->filename, fname);
    strcpy(fcbptr->exname, exname);
    fcbptr->attribute = 0x00;
    fcbptr->time = nowtime->tm_hour * 2048 + nowtime->tm_min * 32 + nowtime->tm_sec / 2;
fcbptr->date = (nowtime->tm_year - 80) * 512 + (nowtime->tm_mon + 1) * 32 + nowtime->tm_mday;
fcbptr->first = blkno;
fcbptr->length = 0;
fcbptr->free = 1;
//写入FCB到相应位置; 
openfilelist[ptrcurdir].count = i * sizeof(fcb);
do_write(ptrcurdir, (char *)fcbptr, sizeof(fcb), 2);
//修改当前目录的用户文件打开表信息; 
    fcbptr = (fcb *)text;
    fcbptr->length = openfilelist[ptrcurdir].length;
    openfilelist[ptrcurdir].count = 0;
    do_write(ptrcurdir, (char *)fcbptr, sizeof(fcb), 2);
    openfilelist[ptrcurdir].fcbstate = 1;
    printf("新文件创建成功!\n");
}

void my_rmf(char *filename)
{   //删除文件; 
    fcb *fcbptr;
    fat *fat1, *fat2, *fatptr1, *fatptr2;
    char *fname, *exname, text[MAXTEXT];
unsigned short blkno;
int rbn, i;
fat1 = (fat *)(myvhard + BLOCKSIZE);
fat2 = (fat *)(myvhard + 3 * BLOCKSIZE);
fname = strtok(filename, ".");
exname = strtok(NULL, ".");
if(strcmp(fname, "") == 0)
{
   printf("出错,要移除的文件必须有一个正确的名字.\n");
return;
}
if(!exname)
{
   printf("出错,要删除的文件必须有扩展名.\n");
return;
}
openfilelist[ptrcurdir].count = 0;
rbn = do_read(ptrcurdir, openfilelist[ptrcurdir].length, text);//读取当前目录; 
fcbptr = (fcb *)text;
for(i = 0; i < rbn / sizeof(fcb); i++)//寻找匹配的文件; 
{
   if(strcmp(fcbptr->filename, fname) == 0 && strcmp(fcbptr->exname, exname) == 0)
            break;
        fcbptr++;
}
if(i == rbn / sizeof(fcb))
{
   printf("出错,该文件不存在.\n");
   return;
}
blkno = fcbptr->first;
while(blkno != END) //循环处理该文件占用的所有磁盘块;; 
{
   fatptr1 = fat1 + blkno;
   fatptr2 = fat2 + blkno;
   blkno = fatptr1->id; //标志转到下一块; 
   fatptr1->id = FREE;
   fatptr2->id = FREE;
}
//FCB"归零"; 
strcpy(fcbptr->filename, "");
fcbptr->free = 0;
openfilelist[ptrcurdir].count = i * sizeof(fcb);
do_write(ptrcurdir, (char *)fcbptr, sizeof(fcb), 2);
openfilelist[ptrcurdir].fcbstate = 1;
printf("文件删除成功!\n");
}

int my_open(char *filename)
{   //打开当前目录下名为filename的文件; 
    fcb *fcbptr;
char *fname, exname[3], *str, text[MAXTEXT];
int rbn, fd, i;
fname = strtok(filename, "."); //分出文件名; 
str = strtok(NULL, ".");  //(strtok函数第二次调用则第一个参数写为NULL)分出扩展名;
//赋值扩展名; 
if(str)
        strcpy(exname, str);
    else
        strcpy(exname, "");
    //检查文件是否打开;    
for(i = 0; i < MAXOPENFILE; i++)
{
   if(strcmp(openfilelist[i].filename, fname) == 0 && strcmp(openfilelist[i].exname, exname) == 0 && i != ptrcurdir)
   {
       printf("出错,该文件已经打开.\n");
       return -1;
   }
}
openfilelist[ptrcurdir].count = 0;
rbn = do_read(ptrcurdir, openfilelist[ptrcurdir].length, text);
fcbptr = (fcb *)text;
//寻找文件; 
for(i = 0; i < rbn / sizeof(fcb); i++)
{
   if(strcmp(fcbptr->filename, fname) == 0 && strcmp(fcbptr->exname, exname) == 0)
            break;
        fcbptr++;
}
if(i == rbn / sizeof(fcb))
    {
        printf("出错,该文件不存在.\n");
        return -1;
    }
    fd = findopenfile();// 寻找空的用户打开表项 ; 
    if(fd == -1)
        return -1;
    strcpy(openfilelist[fd].filename, fcbptr->filename);
strcpy(openfilelist[fd].exname, fcbptr->exname);
openfilelist[fd].attribute = fcbptr->attribute;
openfilelist[fd].time = fcbptr->time;
openfilelist[fd].date = fcbptr->date;
openfilelist[fd].first = fcbptr->first;
openfilelist[fd].length = fcbptr->length;
openfilelist[fd].free = fcbptr->free;
openfilelist[fd].dirno = openfilelist[ptrcurdir].first;
openfilelist[fd].diroff = i;
//文件目录名; 
strcpy(openfilelist[fd].dir, openfilelist[ptrcurdir].dir); 
strcat(openfilelist[fd].dir, filename);
if(fcbptr->attribute & 0x20)
        strcat(openfilelist[fd].dir, "\\");
openfilelist[fd].father = ptrcurdir;
openfilelist[fd].count = 0;
openfilelist[fd].fcbstate = 0;  //未修改FCB; 
openfilelist[fd].topenfile = 1;  //打开表项状态置为已占用; 
printf("(目录/文件打开成功)\n");
return fd;  //返回文件描述符; 
}

int my_close(int fd)
{  //关闭前面由my_open()打开的文件描述符(用户打开文件表项)为fd的文件; 
    fcb *fcbptr;
int father;
if(fd < 0 || fd >= MAXOPENFILE)
{
   printf("Error,the file is not exist.\n");
   return -1;
}
if(openfilelist[fd].fcbstate)//修改过文件的FCB的内容; 
{ //将FCB内容保存到虚拟磁盘上该文件的目录项中; 
   fcbptr = (fcb *)malloc(sizeof(fcb));
   strcpy(fcbptr->filename, openfilelist[fd].filename);
   strcpy(fcbptr->exname, openfilelist[fd].exname);
        fcbptr->attribute = openfilelist[fd].attribute;
        fcbptr->time = openfilelist[fd].time;
        fcbptr->date = openfilelist[fd].date;
        fcbptr->first = openfilelist[fd].first;
        fcbptr->length = openfilelist[fd].length;
        fcbptr->free = openfilelist[fd].free;
        father = openfilelist[fd].father;
        
        //diroff为相应打开文件的目录项在父目录文件的dirno盘块中的目录项序号; 
        openfilelist[father].count = openfilelist[fd].diroff * sizeof(fcb);
        //以覆盖写方式将欲关闭的文件的FCB写入父目录文件的相应盘块中; 
        do_write(father, (char *)fcbptr, sizeof(fcb), 2);
        //回收; 
        free(fcbptr);
        openfilelist[fd].fcbstate = 0;
}
//回收打开表项; 
strcpy(openfilelist[fd].filename, "");
strcpy(openfilelist[fd].exname, "");
openfilelist[fd].topenfile = 0;
printf("(目录/文件已关闭)\n");
return father;  //返回父路径的文件描述符(打开表项序号); 
}

int my_write(int fd)
{
    fat *fat1, *fat2, *fatptr1, *fatptr2;
    int wstyle, len, ll, tmp;
    char text[MAXTEXT];
    unsigned short blkno;
    fat1 = (fat *)(myvhard + BLOCKSIZE);
    fat2 = (fat *)(myvhard + 3 * BLOCKSIZE);
    if(fd < 0 || fd >= MAXOPENFILE)
    {   //检查open()函数返回值fd的有效性; 
        printf("The file is not exist!\n");
return -1;
    }
    while(1)
    {
        printf("Please enter the number of write style:\n 1.截断写\t 2.覆盖写\t 3.追加写\n");
scanf("%d", &wstyle);
//截断写:释放文件所在的除第一块外的其它盘块(需要时再分配)并将读写指针置0; 覆盖写:直接; 追加写:读写指针放到文件末尾; 
if(wstyle > 0 && wstyle < 4)
            break; //跳出while循环; 
printf("Input Error!");
    }
    getchar();
    switch(wstyle)
    {
        case 1: //截断写; 
            blkno = openfilelist[fd].first;
            fatptr1 = fat1 + blkno;
            fatptr2 = fat2 + blkno;
            blkno = fatptr1->id; //第二块盘块号; 
            fatptr1->id = END; //第一块独立出来; 
            fatptr2->id = END;
            while(blkno != END) //如果有下一块; 
            {
                fatptr1 = fat1 + blkno;
                fatptr2 = fat2 + blkno;
                blkno = fatptr1->id;  //继续下一块; 
                fatptr1->id = FREE; //相应文件分配表项置为空闲; 
                fatptr2->id = FREE;
            }
            //读写指针和文件长度置0; 
            openfilelist[fd].count = 0; 
            openfilelist[fd].length = 0;
            break;
        case 2: //覆盖写; 
            openfilelist[fd].count = 0;
            break;
        case 3:  //追加写; 
            openfilelist[fd].count = openfilelist[fd].length; //读写指针放到末尾; 
            break;
        default:
            break;
    }
    ll = 0;  //实际写入字节数; 
    printf("please input write data(按Enter+(Ctrl+Z)+Enter结束):\n");
    while(gets(text))
    {
        len = strlen(text);
        text[len++] = '\n';
        text[len] = '\0'; //结束; 
        tmp = do_write(fd, text, len, wstyle); //返回实际写入字节数; 
        if(tmp != -1)
            ll += tmp;
        if(tmp < len)
        {
            printf("Wirte Error!");
            break;
        }
    }
    printf("写入成功!\n");
    return ll;
}

int do_write(int fd, char *text, int len, char wstyle)
{   //被my_write()函数调用,将输入内容写到相应文件中 ; wstyle:写方式 ; 
    fat *fat1, *fat2, *fatptr1, *fatptr2;
    unsigned char *buf, *blkptr;
    int blkno, blkoff;
    int i, ll;
    fat1 = (fat *)(myvhard + BLOCKSIZE);
    fat2 = (fat *)(myvhard + 3 * BLOCKSIZE);
    buf = (unsigned char *)malloc(BLOCKSIZE);
    if(buf == NULL)
    {
        printf("malloc failed!\n");
        return -1;
    }
    //将起始指针转化为逻辑块号和块内偏移; 
    blkno = openfilelist[fd].first;
    blkoff = openfilelist[fd].count;
    
    fatptr1 = fat1 + blkno;
    fatptr2 = fat2 + blkno;
    while(blkoff >= BLOCKSIZE)//块内偏移大于块的大小(一个磁盘块不能完全放下所写文件); 
    {
        blkno = fatptr1->id;  //下一块号; 
        if(blkno == END) //表明该磁盘块是单独的,没有下一块; 
        {
            blkno = findblock();//寻找空闲块; 
            if(blkno == -1)  //没有空的磁盘块; 
            {
                free(buf);
                return -1;
            }
            fatptr1->id = blkno;//写入起始块号; 
            fatptr2->id = blkno;
            fatptr1 = fat1 + blkno;
            fatptr2 = fat2 + blkno;
            fatptr1->id = END;//没有分配下一块了; 
            fatptr2->id = END;
        }
        else
        {  //存在下一块; 
            fatptr1 = fat1 + blkno;
            fatptr2 = fat2 + blkno;
        }
        blkoff = blkoff - BLOCKSIZE;  //调整块内偏移; 
    }

    ll = 0;
    while(ll < len)
    {
        blkptr = (unsigned char *)(myvhard + blkno * BLOCKSIZE);
        for(i = 0; i < BLOCKSIZE; i++)
            buf[i] = blkptr[i]; //先将块内内容全部写入缓存区; 
        for(;blkoff < BLOCKSIZE; blkoff++)
        {   //从块内偏移处开始写数据到缓存区; 
            buf[blkoff] = text[ll++];
            openfilelist[fd].count++;
            if(ll == len)
                break;
        }
        for(i = 0; i < BLOCKSIZE; i++)
            blkptr[i] = buf[i]; //将缓存区的内容全部写回; 
        if(ll < len)  //一个磁盘块写完,数据还有剩余的没写入; 
        {
            blkno = fatptr1->id; //读入下一块盘块号; 
            if(blkno == END)
            {   // 此盘块为单独的(见do_read()); 
                blkno = findblock(); //寻找; 
                if(blkno == -1)
                    break;
                fatptr1->id = blkno;
                fatptr2->id = blkno;
                fatptr1 = fat1 + blkno;
                fatptr2 = fat2 + blkno;
                fatptr1->id = END;
                fatptr2->id = END;
            }
            else
            {
                fatptr1 = fat1 + blkno;
                fatptr2 = fat2 + blkno;
            }
            blkoff = 0;  //新找到的盘块可从头开始写数据; 
        }
    }
    if(openfilelist[fd].count > openfilelist[fd].length)
        openfilelist[fd].length = openfilelist[fd].count; //修改文件长度为实际长度; 
    openfilelist[fd].fcbstate = 1;  //已分配; 
    free(buf);
   
    return ll;
}

int my_read(int fd, int len)
{   // fd为open()函数的返回值,文件的描述符 ,len为要读的字节数 ; 
    char text[MAXTEXT];
    int ll;
    if(fd < 0 || fd >= MAXOPENFILE)
    {   //检查fd的有效性 ; 
        printf("The File is not exist!\n");
        return -1;
    }
    openfilelist[fd].count = 0;
    ll = do_read(fd, len, text);  //实际读文件函数; 
    if(ll != -1)
        printf("%s", text); //成功则输出 ; 
    else
        printf("读取出错!\n");
    printf("读取成功!\n");
    return ll;
}

int do_read(int fd, int len, char *text)
{ //读出指定文件中从读写指针开始的长度为len的内容到用户空间的 text中 ,fd为open()函数的返回值,文件的描述符; 
    fat *fat1, *fatptr;
    unsigned char *buf, *blkptr;
    unsigned short blkno, blkoff;
    int i, ll;
    fat1 = (fat *)(myvhard + BLOCKSIZE);
    buf = (unsigned char *)malloc(BLOCKSIZE); //缓冲区; 
    if(buf == NULL)
    {
        printf("malloc failed!\n");
        return -1;
    }
    blkno = openfilelist[fd].first;  //文件的起始块号 ; 
    blkoff = openfilelist[fd].count;  // 块内偏移 ; 
    if(blkoff >= openfilelist[fd].length)
    {
        puts("读取超出范围!");
        free(buf);
        return -1;
    }
    fatptr = fat1 + blkno;
    while(blkoff >= BLOCKSIZE)
    { //块内偏移大于块的大小则将块号置为下一块的块号,调整偏移; 
        blkno = fatptr->id;
        blkoff = blkoff - BLOCKSIZE;
        fatptr = fat1 + blkno;
    }

    ll = 0;  
    while(ll < len)
    {
        blkptr = (unsigned char *)(myvhard + blkno * BLOCKSIZE); //将磁盘块号转化为内存地址; 
        for(i = 0; i < BLOCKSIZE; i++)
            buf[i] = blkptr[i];  //将内容读到缓冲区中; 
        for(; blkoff < BLOCKSIZE; blkoff++)
        {
            text[ll++] = buf[blkoff];  //将缓冲区中内容读到 text中 ; 
            openfilelist[fd].count++;  //读写指针跟着移动 ; 
            if(ll == len || openfilelist[fd].count == openfilelist[fd].length)
                break;  //读完退出 ; 
        }
        if(ll < len && openfilelist[fd].count != openfilelist[fd].length)
        {   //读完一个磁盘块后要读的内容还未读完 ; 
            blkno = fatptr->id;  //将存放的下一个盘块号作为新的起始盘块号 ; 
            if(blkno == END)
                break;
            blkoff = 0;
            fatptr = fat1 + blkno;  //实际地址 ; 
        }
    }
    text[ll] = '\0';  //结尾 ; 
    free(buf);
   
    return ll;  //返回实际读出的字节数; 
}

void my_exitsys()
{
    FILE *fp;
    while(ptrcurdir)
        ptrcurdir = my_close(ptrcurdir);  //关闭所有打开的目录 ; 
    fp = fopen(FilePath, "w");
    fwrite(myvhard, SIZE, 1, fp);
    fclose(fp);
    free(myvhard);
    printf("文件系统已关闭\n"); 
}

int findblock()
{  //寻找空的磁盘块 ; 
    unsigned short i;
fat *fat1, *fatptr;
fat1 = (fat *)(myvhard + BLOCKSIZE);
for(i = 7; i < SIZE / BLOCKSIZE; i++)
{
fatptr = fat1 + i;
if(fatptr->id == FREE)
return i;
}
printf("Error,Can't find free block!\n");
 
return -1;
}

int findopenfile()
{ // 寻找空的用户打开表项 ; 
    int i;
    for(i = 0; i < MAXOPENFILE; i++)
    {
        if(openfilelist[i].topenfile == 0)
            return i;
    }
    printf("Error,open too many files!\n");
   
    return -1;
}

int findopenned(char * filename){ //返回打开文件在用户文件打开表中的位置(序号); 
char *fname, *exname;
int i;
fname = strtok(filename, "."); //分出文件名; 
exname = strtok(NULL, ".");  //(strtok函数第二次调用则第一个参数写为NULL)分出扩展名;
for(i = 0; i < MAXOPENFILE; i++){
if(strcmp(openfilelist[i].filename, fname) == 0 && strcmp(openfilelist[i].exname, exname) == 0)
            break;
}
if(i == MAXOPENFILE){
        printf("出错,该文件未打开,无需关闭.\n");
        i = -1;
    }
   
    return i; 
}

int main()
{
char * inputs; //输入;
char *cmd, *para;   // 命令, 参数; 
startsys();
printf("************************************************************ \n");
printf("*               欢迎使用简单文件系统(FAT)                  * \n");
printf("* 以下是可使用的指令,您可输入序号、完整命令或括号中的简写 * \n");
printf("************************************************************ \n");
printf("* 1、 format(f)            :对磁盘格式化.                  * \n");
printf("* 2、 mkdir(md)   dirname  :创建子目录.                    * \n");
printf("* 3、 rmdir(rd)   dirname  :删除子目录.                    * \n");
printf("* 4、 ls                   :显示当前目录下文件和目录.      * \n");
printf("* 5、 cd          dirname  :跳转到指定目录.                * \n");
printf("* 6、 create(cr)  filename :在当前目录下创建一个新文件.    * \n");
printf("* 7、 write(w)             :对当前打开的文件写入信息       * \n");
printf("* 8、 read(r)              :读取当前打开的文件内容到屏幕.  * \n");
printf("* 9、 rm          filename :删除文件.                      * \n");
printf("* 10、open(o)     filename :打开文件.                      * \n");
printf("* 11、close(cl)            :关闭当前文件.                  * \n");
printf("* 12、exit(e)              :安全退出该文件系统,保存信息.   * \n");
printf("* 13、close_o(co) filename :关闭其它打开的文件.            * \n");
printf("************************************************************ \n\n");
while(1){
printf("%s",openfilelist[ptrcurdir].dir); 
gets(inputs);
if(strcmp(inputs, "")!=0){
cmd=strtok(inputs," "); 
para=strtok(NULL, " ");
if(strcmp(cmd, "format")==0||strcmp(cmd,"1")==0||strcmp(cmd,"f")==0){
my_format();
}
else if(strcmp(cmd,"mkdir")==0||strcmp(cmd,"2")==0||strcmp(cmd,"md")==0){
my_mkdir(para);
}
else if(strcmp(cmd,"rmdir")==0||strcmp(cmd,"3")==0||strcmp(cmd,"rd")==0){
my_rmdir(para);
}
else if(strcmp(cmd,"ls")==0||strcmp(cmd,"4")==0){
my_ls();
}
else if(strcmp(cmd,"cd")==0||strcmp(cmd,"5")==0){
if(para==NULL){
printf("请输入要转到的路径!\n");
//gets(para);
}
else
my_cd(para);
}
else if(strcmp(cmd,"create")==0||strcmp(cmd,"6")==0||strcmp(cmd,"cr")==0){
my_create(para);
}
  
else if(strcmp(cmd,"write")==0||strcmp(cmd,"7")==0||strcmp(cmd,"w")==0){
//int fd = my_open(para);
my_write(ptrcurdir);
}
else if(strcmp(cmd,"read")==0||strcmp(cmd,"8")==0||strcmp(cmd,"r")==0){
//int fd = my_open(para);
my_read(ptrcurdir, openfilelist[ptrcurdir].length);
}
else if(strcmp(cmd,"rm")==0||strcmp(cmd,"9")==0){
my_rmf(para);
}
else if(strcmp(cmd,"open")==0||strcmp(cmd,"10")==0||strcmp(cmd,"o")==0){
my_open(para);
printf("可进行读写操作了.\n"); 
}
else if(strcmp(cmd,"close")==0||strcmp(cmd,"11")==0||strcmp(cmd,"cl")==0){
my_close(ptrcurdir);
}
else if(strcmp(cmd,"exit")==0||strcmp(cmd,"12")==0||strcmp(cmd,"e")==0){
my_exitsys();
break;
}
else if(strcmp(cmd,"close_o")==0||strcmp(cmd,"13")==0||strcmp(cmd,"co")==0){
int fd = findopenned(para);
my_close(fd);
}
else printf("无效指令%s %s,请重新输入:\n",cmd,para);
if(inputs=="no_commond"){
printf("请输入指令.\n"); 
printf("%s",openfilelist[ptrcurdir].dir);
}
}//if 
}//while 
printf("感谢使用简单文件系统,再见。\n");
return 1;
}
//修改、注释——魏刘宏
//目录和文件的FCB分别存在哪里?(文件的FCB存在目录的开头处)

  评论这张
 
阅读(166)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018