整体思路:
文件系统基于一个大文件实现
大文件数据分为几个区域来模拟简单的文件系统
1.User:username and password
2.SuperBlock:blockSize,blockNum,inodeNum,blockFree
3.blockBitmap:the use state of block area
4.inodeBitmap:the use state of inode area
5.Inode area:inode * inodeMax(blockNum)
6.Block area:block * blockNum
系统评估:
系统的实现只是很基础的,许多实现细节还有优化的空间,还有一些功能可继续扩展。
待优化:
文件读写具体实现写法;
文件写入的方式;
可扩展:
cd命令任意性;
文件移动;
文件复制;
多用户;
图形化支持;
已实现:
基于标准输入输出流读写;
大文件存储,最多支持二级索引,文件大小上限为64M;
子目录和父目录跳转;
文件重命名;
文件,目录删除;
文件,目录读写权限控制;
code:
FileSystem.h 文件系统定义
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#include <malloc.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#define BLOCK_SIZE 1024
#define BLOCK_NUM 102400
#define SYSTEM_NAME "FileSystem.tzh"
#define SUDO 0
#define HELP 1
#define LS 2
#define CD 3
#define MKDIR 4
#define TOUCH 5
#define CAT 6
#define WRITE 7
#define RM 8
#define MV 9
#define CP 10
#define CHMOD 11
#define LOGOUT 12
#define EXIT 13
#define SYSINFO 14
#define CLEAR 15
#define ACCOUNT 16
using namespace std;
/**
文件系统块结构
*/
typedef struct{
unsigned short blockSize;//2B,文件块大小
unsigned int blockNum;//4B,文件块数量
unsigned int inodeNum;//4B,i节点数量,即文件数量
unsigned int blockFree;//4B,空闲块数量
}SuperBlock;
/**
文件i节点结构
100B
*/
typedef struct{
unsigned int id; //4B,i节点索引
char name[30]; //30B,文件名,最大长度29
unsigned char isDir; //1B,文件类型 0-file 1-dir
unsigned int parent; //4B,父目录i节点索引
unsigned int length; //4B,文件长度,unsigned int最大2^32-1(4GB-1B),目录文件则为子文件项数量
unsigned char type; //1B,文件权限,0-read-only,1-read-write
time_t time; //8B,文件最后修改时间,从1970年1月1日00时00分00秒至今所经过的秒数
unsigned int addr[12];//12*4B,文件内容索引,文件前10项为直接索引,目录前11项为直接索引
unsigned int blockId; //文件项所在的目录数据块的id,便于删除时定位
}Inode,*PInode;
/**
文件部分信息节点,用于简要显示文件信息
文件名 文件/目录 文件长度 文件权限 修改时间
*/
typedef struct {
unsigned int id; //4B
char name[30]; //30B
unsigned char isDir; //1B
unsigned int blockId; //4B,在目录数据块中的位置0-255
}Fcb,*PFcb;
typedef struct FCB_LINK_NODE{
Fcb fcb;
struct FCB_LINK_NODE* next;
}FcbLinkNode, *FcbLink;
/**
文件系统用户结构
*/
typedef struct{
char username[10];//用户名,最大长度9
char password[10];//密码,最大长度9
}User;
class FileSystem
{
public:
FileSystem(char* name);
virtual ~FileSystem();
int init();
//system init
void createFileSystem();
void openFileSystem();
//command
void help();
void ls();
void ls_l();
int cd(char* name);
//file operation
int createFile(char* name, unsigned char isDir);
int read(char* name);
int write(char* name);
int del(char* name);
int mv(char* name, char* newName);
int cp(char* src, char* dst);
int chmod(char* name, unsigned char type);
//system
void login();
void logout();
void exit();
void systemInfo();
void clr();
int account();
void command(void);
protected:
private:
const int blockSize;//文件块大小
const int blockNum; //文件块数量
unsigned char* blockBitmap;//文件块使用图
unsigned char* inodeBitmap;//i节点使用图
//大小
unsigned short userSize;
unsigned short superBlockSize;
unsigned short blockBitmapSize;
unsigned short inodeBitmapSize;
unsigned short inodeSize;
unsigned short fcbSize;
unsigned short itemSize;
//偏移
unsigned long sOffset; //superBlock偏移
unsigned long bbOffset; //blockBitmap偏移
unsigned long ibOffset; //inodeBitmap偏移
unsigned long iOffset; //i节点区偏移
unsigned long bOffset; //数据区偏移
unsigned char isAlive; //系统是否在运行
char name[30];//文件系统名
FILE* fp;//文件系统文件指针
SuperBlock superBlock;//文件系统块信息
string curPath;//当前目录字符串
Inode curInode;//当前目录i节点
FcbLink curLink;//当前目录子文件链指针
User user;//用户
char cmd[5][20];//命令行输入
char* SYS_CMD[17];//系统支持的命令
//user区域操作
void getUser(User* pUser);
void setUser(User user);
//superBlock区域操作
void getSuperBlock(SuperBlock* pSuper);
void updateSuperBlock(SuperBlock super);
//blockBitmap区域操作
unsigned int getAvailableBlockId();
void getBlockBitmap(unsigned char* bitmap);
void updateBlockBitmap(unsigned char* bitmap, unsigned int index);
void updateBlockBitmap(unsigned char* bitmap, unsigned int start, unsigned int count);
//inodeBitmap区域操作
unsigned int getAvailableInodeId();
void getInodeBitmap(unsigned char* bitmap);
void updateInodeBitmap(unsigned char* bitmap, unsigned int index);
void updateInodeBitmap(unsigned char* bitmap, unsigned int start, unsigned int count);
//inode block区域操作
void getInode(PInode pInode, unsigned int id);
void updateInode(Inode inode);
void releaseInode(unsigned int id);
//data block区域操作
//地址或文件项
unsigned int getAvailableFileItem(Inode& inode, unsigned int* availableIndex);
unsigned int getItem(unsigned int blockId, unsigned int index);
void updateItem(unsigned int blockId, unsigned int index, unsigned int value);
void releaseItem(unsigned int blockId, unsigned int id);
//文件内容
int getData(unsigned int blockId, char* buff, unsigned int size, unsigned int offset);
int writeData(unsigned int blockId, char* buff, unsigned int size, unsigned int offset);
void releaseBlock(unsigned int blockId);
//定位操作
unsigned int findChildInode(FcbLink curLink, char* name);
//目录信息链操作
void getFcbLinkNode(FcbLink pNode, Inode inode);
void getFcbLink(FcbLink& curLink, Inode inode);
void appendFcbLinkNode(FcbLink curLink, Inode inode);
void removeFcbLinkNode(FcbLink curLink, Inode inode);
void removeFcbLinkNode(FcbLink curLink, char* name);
void releaseFcbLink(FcbLink& curLink);
//system command
int analyse(char* str);
void stopHandle(int sig);
void updateResource();
void showPath();
//util
void showFileDigest(FcbLink pNode);
void showFileDetail(PInode pInode);
unsigned int waitForInput(char* buff, unsigned int limit);
};
#endif // FILESYSTEM_H
FileSystem.cpp 文件系统实现
#include "FileSystem.h"
/**
初始化常量,文件系统名和命令集合
finish
*/
FileSystem::FileSystem(char* name)
:blockSize(BLOCK_SIZE),
blockNum(BLOCK_NUM),
blockBitmap(new unsigned char[BLOCK_NUM+1]),
inodeBitmap(new unsigned char[BLOCK_NUM+1]),
isAlive(0),
fp(NULL),
curLink(NULL)
{
userSize = sizeof(User);
superBlockSize = sizeof(SuperBlock);
blockBitmapSize = blockNum;
inodeBitmapSize = blockNum;
inodeSize = sizeof(Inode);
fcbSize = sizeof(Fcb);
itemSize = sizeof(unsigned int);
sOffset = userSize;
bbOffset = sOffset+sizeof(SuperBlock);
ibOffset = bbOffset+blockBitmapSize;
iOffset = ibOffset+inodeBitmapSize;
bOffset = iOffset+sizeof(Inode)*blockNum;
if(name == NULL || strcmp(name, "") == 0)
strcpy(this->name, SYSTEM_NAME);
else
strcpy(this->name, name);
SYS_CMD[0] = new char[5];
strcpy(SYS_CMD[0], "sudo");
SYS_CMD[1] = new char[5];
strcpy(SYS_CMD[1], "help");
SYS_CMD[2] = new char[3];
strcpy(SYS_CMD[2], "ls");
SYS_CMD[3] = new char[3];
strcpy(SYS_CMD[3], "cd");
SYS_CMD[4] = new char[6];
strcpy(SYS_CMD[4], "mkdir");
SYS_CMD[5] = new char[6];
strcpy(SYS_CMD[5], "touch");
SYS_CMD[6] = new char[4];
strcpy(SYS_CMD[6], "cat");
SYS_CMD[7] = new char[6];
strcpy(SYS_CMD[7], "write");
SYS_CMD[8] = new char[3];
strcpy(SYS_CMD[8], "rm");
SYS_CMD[9] = new char[3];
strcpy(SYS_CMD[9], "mv");
SYS_CMD[10] = new char[3];
strcpy(SYS_CMD[10], "cp");
SYS_CMD[11] = new char[6];
strcpy(SYS_CMD[11], "chmod");
SYS_CMD[12] = new char[7];
strcpy(SYS_CMD[12], "logout");
SYS_CMD[13] = new char[5];
strcpy(SYS_CMD[13], "exit");
SYS_CMD[14] = new char[8];
strcpy(SYS_CMD[14], "sysinfo");
SYS_CMD[15] = new char[6];
strcpy(SYS_CMD[15], "clear");
SYS_CMD[16] = new char[8];
strcpy(SYS_CMD[16], "account");
}
/**
释放动态分配的控件
finish
*/
FileSystem::~FileSystem()
{
if(blockBitmap != NULL)
{
delete blockBitmap;
blockBitmap = NULL;
}
if(inodeBitmap != NULL)
{
delete inodeBitmap;
inodeBitmap = NULL;
}
if(SYS_CMD[0] != NULL)
{
for (int i = 0; i < 17; i++)
delete SYS_CMD[i];
SYS_CMD[0] = NULL;
}
if(curLink != NULL)
{
releaseFcbLink(curLink);
}
}
/**
系统初始化,启动系统时调用
finish
*/
int FileSystem::init()
{
if(isAlive)
return -1;
//signal(SIGINT,stopHandle);
openFileSystem();
login();
command();
return 0;
}
/**
创建文件系统
finish
*/
void FileSystem::createFileSystem()
{
printf("create file system...\n");
if ((fp = fopen(name,"wb+"))==NULL)
{
printf("open file %s error...\n",name);
::exit(-1);
}
//init user
printf("username:");
fgets(user.username, sizeof(user.username), stdin);
if(user.username[strlen(user.username)-1] == '\n')
user.username[strlen(user.username)-1] = '\0';
system("stty -echo");
printf("password:");
fgets(user.password, sizeof(user.password), stdin);
if(user.password[strlen(user.password)-1] == '\n')
user.password[strlen(user.password)-1] = '\0';
system("stty echo");
printf("\n");
printf("username:%s\npassword:%s\n", user.username, user.password);
setUser(user);
//init superBlock
superBlock.blockSize = blockSize;
superBlock.blockNum = blockNum;
//分配一个给root
superBlock.inodeNum = 1;
superBlock.blockFree = blockNum-1;
updateSuperBlock(superBlock);
//init two bitmaps
unsigned long i;
//分配一个给root
blockBitmap[0] = 1;
inodeBitmap[0] = 1;
for(i = 1; i < blockNum; i++)
{
blockBitmap[i] = 0;
inodeBitmap[i] = 0;
}
updateBlockBitmap(blockBitmap, 0, blockBitmapSize);
updateInodeBitmap(inodeBitmap, 0, inodeBitmapSize);
//init inode and block
long len = 0;
len += (inodeSize+ blockSize) * blockNum;
for (i = 0; i < len; i++)
{
fputc(0, fp);
}
//init root dir
//set root inode info
curInode.id = 0;
strcpy(curInode.name, "/");
curInode.isDir = 1;
curInode.parent = inodeSize;
curInode.length = 0;
curInode.type = 0;
time(&(curInode.time));
for(i = 0; i < 12; i++)
curInode.addr[i] = 0;
curInode.blockId = 0;
//write root inode
updateInode(curInode);
fflush(fp);
//get curLink info
getFcbLink(curLink, curInode);
//get current path
curPath = "/";
printf("create file system %s finish.\n", this->name);
}
/**
打开文件系统,若不存在,则创建
finish
*/
void FileSystem::openFileSystem()
{
if((fp = fopen(this->name,"rb"))==NULL)
{
createFileSystem();
}
else
{
printf("open file system...\n");
if ((fp=fopen(this->name,"rb+"))==NULL)
{
printf("open file %s error...\n", name);
::exit(1);
}
rewind(fp);
//read header
getUser(&user);
getSuperBlock(&superBlock);
getBlockBitmap(blockBitmap);
getInodeBitmap(inodeBitmap);
//get current inode
getInode(&curInode, 0);
//get curLink info
getFcbLink(curLink, curInode);
//get current path
curPath = "/";
printf("open file system %s success\n", this->name);
}
}
/**
显示帮助信息
finish
*/
void FileSystem::help()
{
printf("command: \n\
help --- show help menu \n\
sysinfo --- show system base information \n\
logout --- exit user \n\
account --- modify username and password \n\
clear --- clear the screen \n\
ls --- list the digest of the directory's children \n\
ls -l --- list the detail of the directory's children \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\
rm --- delete a directory or a file \n\
cp --- cp a directory file to another directory or file (not finish)\n\
mv --- rename a file or directory \n\
chmod --- change the authorizatino of a directory or a file \n\
exit --- exit this system\n");
}
/**
列出目录下所有文件(目录)名
finish
*/
void FileSystem::ls()
{
//printf("ls %s\n", curInode.name);
FcbLink link = curLink->next;
while(link != NULL)
{
showFileDigest(link);
link = link->next;
}
}
/**
列出目录下所有文件(目录)的详细信息
finish
*/
void FileSystem::ls_l()
{
//printf("ls -l %s\n", curInode.name);
FcbLink link = curLink->next;
PInode pInode = new Inode();
while(link != NULL)
{
pInode->id = link->fcb.id;
getInode(pInode, pInode->id);
showFileDetail(pInode);
link = link->next;
}
}
/**
进入目录,暂时只支持进入子目录和返回父目录
finish
*/
int FileSystem::cd(char* name)
{
//printf("cd from %s to child %s\n", curInode.name, name);
unsigned int id;
//回到父目录
if(strcmp(name, "..") == 0)
{
id = curInode.parent;
if(curInode.id > 0)
{
getInode(&curInode, id);
getFcbLink(curLink, curInode);
int pos = curPath.rfind('/', curPath.length()-2);
curPath.erase(pos+1, curPath.length()-1-pos);
}
return 0;
}
id = findChildInode(curLink, name);
if(id > 0)
{
getInode(&curInode, id);
getFcbLink(curLink, curInode);
curPath.append(name);
curPath.append(1, '/');
return 0;
}
else
{
printf("no such file or directory:%s\n", name);
return -1;
}
}
/**
创建文件或目录
flag:0-file,1-dir
finish
*/
int FileSystem::createFile(char * name, unsigned char isDir)
{
if(name == NULL || strcmp(name, "") == 0 || findChildInode(curLink, name) > 0)
{
printf("invalid file name:the name is empty,or the file has existed\n");
return -1;
}
//printf("create file %s (isDir=%d) in %s\n", name, isDir, curInode.name);
unsigned int index;
unsigned int dirBlockId = getAvailableFileItem(curInode, &index);
//找到一个可用文件项
if(dirBlockId > 0 || curInode.id == 0)
{
unsigned int blockId = getAvailableBlockId();
//找到一个空闲数据块
if(blockId > 0)
{
//更新superBlock
superBlock.blockFree--;
superBlock.inodeNum++;
//更新blockBitmap
blockBitmap[blockId] = 1;
updateBlockBitmap(blockBitmap, blockId);
unsigned int id = getAvailableInodeId();
//创建i节点
PInode pInode = new Inode();
pInode->id = id;
strcpy(pInode->name, name);
pInode->isDir = isDir;
pInode->parent = curInode.id;
pInode->length = 0;
pInode->type = 1;
time(&(pInode->time));
int i;
pInode->addr[0] = blockId;
for(i = 1; i < 12; i++)
pInode->addr[i] = 0;
pInode->blockId = dirBlockId;
//写入i节点
updateInode(*pInode);
//更新inodeBitmap
inodeBitmap[id] = 1;
updateInodeBitmap(inodeBitmap, id);
//将文件id(i节点索引)写入目录文件
//printf("%d register in dir %d [%d]\n", id, dirBlockId, index);
updateItem(dirBlockId, index, id);
//printf("%d [%d] = %d\n", dirBlockId, index, id);
//更新目录i节点
curInode.length++;
time(&(curInode.time));
updateInode(curInode);
//更新curLink
appendFcbLinkNode(curLink, *pInode);
delete pInode;
//printf("create file %s success:id=%d\n", pInode->name, pInode->id);
return 0;
}
else
{
printf("storage space is not enough, %d\n", blockId);
return -1;
}
}
else
{
printf("the directory can't append file item, %d\n", dirBlockId);
return -1;
}
}
/**
读取文件
finish
*/
int FileSystem::read(char *name)
{
//printf("read file %s in %s\n", name, curInode.name);
unsigned int id = findChildInode(curLink, name);
if(id > 0)
{
//读取i节点
PInode pInode = new Inode();
getInode(pInode, id);
if(pInode->isDir == 0)
{
unsigned long len = pInode->length;
//remember to delete it
char* buff = new char[blockSize+1];
int i;
unsigned int blockId;
//遍历10个直接索引,读取数据块
for(i = 0; i < 10; i++)
{
blockId = pInode->addr[i];
if(blockId > 0)
{
if(len > blockSize)
{
len -= getData(blockId, buff, blockSize, 0);
printf("%s", buff);
}
else
{
len -= getData(blockId, buff, len, 0);
printf("%s\n", buff);
//read finish
delete buff;
return 0;
}
}
else
{
//read finish