linux下简单模拟文件系统

整体思路:

文件系统基于一个大文件实现
大文件数据分为几个区域来模拟简单的文件系统
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#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)
    {
        delete []SYS_CMD;
        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
                    printf("\n");
                    delete buff;
                    return 0;
                }
            }
            if(len <= 0)
            {
                //read finish
                printf("\n");
                delete buff;
                return 0;
            }

            //遍历1个一级索引
            unsigned int addrBlockId = pInode->addr[10];
            int totalItem = blockSize/itemSize;
            if(addrBlockId > 0)
            {
                //遍历totalItem个直接索引
                for(i = 0; i < totalItem; i++)
                {
                    blockId = getItem(addrBlockId, 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
                        printf("\n");
                        delete buff;
                        return 0;
                    }
                }
            }
            else
            {
                //read finish
                printf("\n");
                delete buff;
                return 0;
            }
            if(len <= 0)
            {
                //read finish
                printf("\n");
                delete buff;
                return 0;
            }

            //遍历一个二级索引
            unsigned int addrBlockId2 = pInode->addr[11];
            if(addrBlockId2 > 0)
            {
                //遍历totalItem个一级索引
                unsigned j;
                for(j = 0; j < totalItem; j++)
                {
                    addrBlockId = getItem(addrBlockId2, j);
                    if(addrBlockId > 0)
                    {
                        //遍历totalItem个直接索引
                        for(i = 0; i < totalItem; i++)
                        {
                            blockId = getItem(addrBlockId, 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
                                printf("\n");
                                delete buff;
                                return 0;
                            }
                        }
                    }
                    else
                    {
                        //read finish
                        printf("\n");
                        delete buff;
                        return 0;
                    }
                }
            }
            else
            {
                //read finish
                printf("\n");
                delete buff;
                return 0;
            }
            return 0;
        }
        else
        {
            printf("%s is a directory\n", name);
            return -1;
        }

    }
    else
    {
        printf("no such file or directory\n");
        return -1;
    }
    return 0;
}

/**
写入文件
未完成大文件一级、二级索引时写入
finish
*/
int FileSystem::write(char *name)
{
    //printf("write file %s in  %s\n", name, curInode.name);
    unsigned int id = findChildInode(curLink, name);
    unsigned long len = 0;
    unsigned int num;
    char ch;
    if(id > 0)
    {
        //读取i节点
        PInode pInode = new Inode();
        getInode(pInode, id);
        if(pInode->isDir == 0)
        {
            if(pInode->type == 0)
            {
                printf("file %s is Read-Only file\n", name);
                return -1;
            }
            printf("write %s: use flag \"\" to end\n", name);
            //remember to delete it
            char* buff = new char[blockSize+1];
            //写入10个直接索引对应数据块
            int i;
            unsigned int blockId;
            for(i = 0; i < 10; i++)
            {
                blockId = pInode->addr[i];
                if(blockId > 0)
                {
                    num = waitForInput(buff, blockSize);
                    writeData(blockId, buff, num, 0);
                    len += num;
                    if(num < blockSize)
                    {
                        pInode->length = len;
                        time(&(pInode->time));
                        updateInode(*pInode);
                        delete buff;
                        return 0;
                    }
                    else
                    {
                        printf("You have input %ld Byte dat, continue?[Y/N]", len);
                        ch = getchar();
                        if(ch != 'Y' && ch != 'y')
                        {
                            pInode->length = len;
                            time(&(pInode->time));
                            updateInode(*pInode);
                            delete buff;
                            return 0;
                        }

                    }
                }
                else
                {
                    blockId = getAvailableBlockId();
                    if(blockId > 0)
                    {
                        superBlock.blockFree--;
                        updateSuperBlock(superBlock);
                        blockBitmap[blockId] = 1;
                        updateBlockBitmap(blockBitmap, blockId);
                        pInode->addr[i] = blockId;
                        time(&(pInode->time));
                        updateInode(*pInode);
                        num = waitForInput(buff, blockSize);
                        writeData(blockId, buff, num, 0);
                        len += num;
                        if(num < blockSize)
                        {
                            pInode->length = len;
                            time(&(pInode->time));
                            updateInode(*pInode);
                            delete buff;
                            return 0;
                        }
                        else
                        {
                            printf("You have input %ld Byte dat, continue?[Y/N]", len);
                            ch = getchar();
                            if(ch != 'Y' && ch != 'y')
                            {
                                pInode->length = len;
                                time(&(pInode->time));
                                updateInode(*pInode);
                                delete buff;
                                return 0;
                            }

                        }
                    }
                    else
                    {
                        pInode->length = len;
                        time(&(pInode->time));
                        updateInode(*pInode);
                        delete buff;
                        return 0;
                    }
                }
            }
            //写入1个一级索引
            unsigned addrBlockId = pInode->addr[10];
            int itemTotal = blockSize/itemSize;
            //写入itemTotal个直接索引对应的数据块
            if(addrBlockId > 0)
            {
                 for(i = 0; i < itemTotal; i++)
                {
                    blockId = getItem(addrBlockId, i);
                    if(blockId > 0)
                    {
                        num = waitForInput(buff, blockSize);
                        writeData(blockId, buff, num, 0);
                        len += num;
                        if(num < blockSize)
                        {
                            pInode->length = len;
                            time(&(pInode->time));
                            updateInode(*pInode);
                            delete buff;
                            return 0;
                        }
                        else
                        {
                            printf("You have input %ld Byte dat, continue?[Y/N]", len);
                            ch = getchar();
                            if(ch != 'Y' && ch != 'y')
                            {
                                pInode->length = len;
                                time(&(pInode->time));
                                updateInode(*pInode);
                                delete buff;
                                return 0;
                            }

                        }
                    }
                    else
                    {
                        blockId = getAvailableBlockId();
                        if(blockId > 0)
                        {
                            superBlock.blockFree--;
                            updateSuperBlock(superBlock);
                            blockBitmap[blockId] = 1;
                            updateBlockBitmap(blockBitmap, blockId);
                            updateItem(addrBlockId, i, blockId);
                            time(&(pInode->time));
                            updateInode(*pInode);
                            num = waitForInput(buff, blockSize);
                            writeData(blockId, buff, num, 0);
                            len += num;
                            if(num < blockSize)
                            {
                                pInode->length = len;
                                time(&(pInode->time));
                                updateInode(*pInode);
                                delete buff;
                                return 0;
                            }
                            else
                            {
                                printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                ch = getchar();
                                if(ch != 'Y' && ch != 'y')
                                {
                                    pInode->length = len;
                                    time(&(pInode->time));
                                    updateInode(*pInode);
                                    delete buff;
                                    return 0;
                                }

                            }
                        }
                        else
                        {
                            pInode->length = len;
                            time(&(pInode->time));
                            updateInode(*pInode);
                            delete buff;
                            return 0;
                        }
                    }
                }

            }
            else
            {
                addrBlockId = getAvailableBlockId();
                if(addrBlockId > 0)
                {
                    superBlock.blockFree--;
                    updateSuperBlock(superBlock);
                    blockBitmap[addrBlockId] = 1;
                    updateBlockBitmap(blockBitmap, addrBlockId);
                    pInode->addr[10] = addrBlockId;
                    time(&(pInode->time));
                    updateInode(*pInode);
                    //
                    for(i = 0; i < itemTotal; i++)
                    {
                        blockId = getItem(addrBlockId, i);
                        if(blockId > 0)
                        {
                            num = waitForInput(buff, blockSize);
                            writeData(blockId, buff, num, 0);
                            len += num;
                            if(num < blockSize)
                            {
                                pInode->length = len;
                                time(&(pInode->time));
                                updateInode(*pInode);
                                delete buff;
                                return 0;
                            }
                            else
                            {
                                printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                ch = getchar();
                                if(ch != 'Y' && ch != 'y')
                                {
                                    pInode->length = len;
                                    time(&(pInode->time));
                                    updateInode(*pInode);
                                    delete buff;
                                    return 0;
                                }

                            }
                        }
                        else
                        {
                            blockId = getAvailableBlockId();
                            if(blockId > 0)
                            {
                                superBlock.blockFree--;
                                updateSuperBlock(superBlock);
                                blockBitmap[blockId] = 1;
                                updateBlockBitmap(blockBitmap, blockId);
                                updateItem(addrBlockId, i, blockId);
                                time(&(pInode->time));
                                updateInode(*pInode);
                                num = waitForInput(buff, blockSize);
                                writeData(blockId, buff, num, 0);
                                len += num;
                                if(num < blockSize)
                                {
                                    pInode->length = len;
                                    time(&(pInode->time));
                                    updateInode(*pInode);
                                    delete buff;
                                    return 0;
                                }
                                else
                                {
                                    printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                    ch = getchar();
                                    if(ch != 'Y' && ch != 'y')
                                    {
                                        pInode->length = len;
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        delete buff;
                                        return 0;
                                    }

                                }
                            }
                            else
                            {
                                pInode->length = len;
                                time(&(pInode->time));
                                updateInode(*pInode);
                                delete buff;
                                return 0;
                            }
                        }
                    }
                }
                else
                {
                    pInode->length = len;
                    time(&(pInode->time));
                    updateInode(*pInode);
                    delete buff;
                    return 0;
                }
            }
            //写入1个二级索引
            unsigned int addrBlockId2 = pInode->addr[11];
            int j;
            if(addrBlockId2 > 0)
            {
                //遍历itemTotal个一级索引
                for(j = 0; j < itemTotal; j++)
                {
                    addrBlockId = getItem(addrBlockId2, j);

                    if(addrBlockId > 0)
                    {
                        //遍历itemTotal个直接索引
                        for(i = 0; i < itemTotal; i++)
                        {
                            blockId = getItem(addrBlockId, i);
                            if(blockId > 0)
                            {
                                num = waitForInput(buff, blockSize);
                                writeData(blockId, buff, num, 0);
                                len += num;
                                if(num < blockSize)
                                {
                                    pInode->length = len;
                                    time(&(pInode->time));
                                    updateInode(*pInode);
                                    delete buff;
                                    return 0;
                                }
                                else
                                {
                                    printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                    ch = getchar();
                                    if(ch != 'Y' && ch != 'y')
                                    {
                                        pInode->length = len;
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        delete buff;
                                        return 0;
                                    }

                                }
                            }
                            else
                            {
                                blockId = getAvailableBlockId();
                                if(blockId > 0)
                                {
                                    superBlock.blockFree--;
                                    updateSuperBlock(superBlock);
                                    blockBitmap[blockId] = 1;
                                    updateBlockBitmap(blockBitmap, blockId);
                                    updateItem(addrBlockId, i, blockId);
                                    time(&(pInode->time));
                                    updateInode(*pInode);
                                    num = waitForInput(buff, blockSize);
                                    writeData(blockId, buff, num, 0);
                                    len += num;
                                    if(num < blockSize)
                                    {
                                        pInode->length = len;
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        delete buff;
                                        return 0;
                                    }
                                    else
                                    {
                                        printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                        ch = getchar();
                                        if(ch != 'Y' && ch != 'y')
                                        {
                                            pInode->length = len;
                                            time(&(pInode->time));
                                            updateInode(*pInode);
                                            delete buff;
                                            return 0;
                                        }

                                    }
                                }
                                else
                                {
                                    pInode->length = len;
                                    time(&(pInode->time));
                                    updateInode(*pInode);
                                    delete buff;
                                    return 0;
                                }
                            }
                        }

                    }
                    else
                    {
                        addrBlockId = getAvailableBlockId();
                        if(addrBlockId > 0)
                        {
                            superBlock.blockFree--;
                            updateSuperBlock(superBlock);
                            blockBitmap[addrBlockId] = 1;
                            updateBlockBitmap(blockBitmap, addrBlockId);
                            updateItem(addrBlockId2, j, addrBlockId);
                            time(&(pInode->time));
                            updateInode(*pInode);
                            //
                            for(i = 0; i < itemTotal; i++)
                            {
                                blockId = getItem(addrBlockId, i);
                                if(blockId > 0)
                                {
                                    num = waitForInput(buff, blockSize);
                                    writeData(blockId, buff, num, 0);
                                    len += num;
                                    if(num < blockSize)
                                    {
                                        pInode->length = len;
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        delete buff;
                                        return 0;
                                    }
                                    else
                                    {
                                        printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                        ch = getchar();
                                        if(ch != 'Y' && ch != 'y')
                                        {
                                            pInode->length = len;
                                            time(&(pInode->time));
                                            updateInode(*pInode);
                                            delete buff;
                                            return 0;
                                        }

                                    }
                                }
                                else
                                {
                                    blockId = getAvailableBlockId();
                                    if(blockId > 0)
                                    {
                                        superBlock.blockFree--;
                                        updateSuperBlock(superBlock);
                                        blockBitmap[blockId] = 1;
                                        updateBlockBitmap(blockBitmap, blockId);
                                        updateItem(addrBlockId, i, blockId);
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        num = waitForInput(buff, blockSize);
                                        writeData(blockId, buff, num, 0);
                                        len += num;
                                        if(num < blockSize)
                                        {
                                            pInode->length = len;
                                            time(&(pInode->time));
                                            updateInode(*pInode);
                                            delete buff;
                                            return 0;
                                        }
                                        else
                                        {
                                            printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                            ch = getchar();
                                            if(ch != 'Y' && ch != 'y')
                                            {
                                                pInode->length = len;
                                                time(&(pInode->time));
                                                updateInode(*pInode);
                                                delete buff;
                                                return 0;
                                            }

                                        }
                                    }
                                    else
                                    {
                                        pInode->length = len;
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        delete buff;
                                        return 0;
                                    }
                                }
                            }
                        }
                        else
                        {
                            pInode->length = len;
                            time(&(pInode->time));
                            updateInode(*pInode);
                            delete buff;
                            return 0;
                        }
                    }
                }
            }
            else
            {
                addrBlockId2 = getAvailableBlockId();
                if(addrBlockId2 > 0)
                {
                    superBlock.blockFree--;
                    updateSuperBlock(superBlock);
                    blockBitmap[addrBlockId2] = 1;
                    updateBlockBitmap(blockBitmap, addrBlockId2);
                    pInode->addr[11] = addrBlockId2;
                    time(&(pInode->time));
                    updateInode(*pInode);
                    //遍历itemTotal一级索引
                    for(j = 0; j < itemTotal; j++)
                    {
                        addrBlockId = getItem(addrBlockId2, j);

                        if(addrBlockId > 0)
                        {
                            //遍历itemTotal个直接索引
                            for(i = 0; i < itemTotal; i++)
                            {
                                blockId = getItem(addrBlockId, i);
                                if(blockId > 0)
                                {
                                    num = waitForInput(buff, blockSize);
                                    writeData(blockId, buff, num, 0);
                                    len += num;
                                    if(num < blockSize)
                                    {
                                        pInode->length = len;
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        delete buff;
                                        return 0;
                                    }
                                    else
                                    {
                                        printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                        ch = getchar();
                                        if(ch != 'Y' && ch != 'y')
                                        {
                                            pInode->length = len;
                                            time(&(pInode->time));
                                            updateInode(*pInode);
                                            delete buff;
                                            return 0;
                                        }

                                    }
                                }
                                else
                                {
                                    blockId = getAvailableBlockId();
                                    if(blockId > 0)
                                    {
                                        superBlock.blockFree--;
                                        updateSuperBlock(superBlock);
                                        blockBitmap[blockId] = 1;
                                        updateBlockBitmap(blockBitmap, blockId);
                                        updateItem(addrBlockId, i, blockId);
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        num = waitForInput(buff, blockSize);
                                        writeData(blockId, buff, num, 0);
                                        len += num;
                                        if(num < blockSize)
                                        {
                                            pInode->length = len;
                                            time(&(pInode->time));
                                            updateInode(*pInode);
                                            delete buff;
                                            return 0;
                                        }
                                        else
                                        {
                                            printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                            ch = getchar();
                                            if(ch != 'Y' && ch != 'y')
                                            {
                                                pInode->length = len;
                                                time(&(pInode->time));
                                                updateInode(*pInode);
                                                delete buff;
                                                return 0;
                                            }

                                        }
                                    }
                                    else
                                    {
                                        pInode->length = len;
                                        time(&(pInode->time));
                                        updateInode(*pInode);
                                        delete buff;
                                        return 0;
                                    }
                                }
                            }

                        }
                        else
                        {
                            addrBlockId = getAvailableBlockId();
                            if(addrBlockId > 0)
                            {
                                superBlock.blockFree--;
                                updateSuperBlock(superBlock);
                                blockBitmap[addrBlockId] = 1;
                                updateBlockBitmap(blockBitmap, addrBlockId);
                                updateItem(addrBlockId2, j, addrBlockId);
                                time(&(pInode->time));
                                updateInode(*pInode);
                                //
                                for(i = 0; i < itemTotal; i++)
                                {
                                    blockId = getItem(addrBlockId, i);
                                    if(blockId > 0)
                                    {
                                        num = waitForInput(buff, blockSize);
                                        writeData(blockId, buff, num, 0);
                                        len += num;
                                        if(num < blockSize)
                                        {
                                            pInode->length = len;
                                            time(&(pInode->time));
                                            updateInode(*pInode);
                                            delete buff;
                                            return 0;
                                        }
                                        else
                                        {
                                            printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                            ch = getchar();
                                            if(ch != 'Y' && ch != 'y')
                                            {
                                                pInode->length = len;
                                                time(&(pInode->time));
                                                updateInode(*pInode);
                                                delete buff;
                                                return 0;
                                            }

                                        }
                                    }
                                    else
                                    {
                                        blockId = getAvailableBlockId();
                                        if(blockId > 0)
                                        {
                                            superBlock.blockFree--;
                                            updateSuperBlock(superBlock);
                                            blockBitmap[blockId] = 1;
                                            updateBlockBitmap(blockBitmap, blockId);
                                            updateItem(addrBlockId, i, blockId);
                                            time(&(pInode->time));
                                            updateInode(*pInode);
                                            num = waitForInput(buff, blockSize);
                                            writeData(blockId, buff, num, 0);
                                            len += num;
                                            if(num < blockSize)
                                            {
                                                pInode->length = len;
                                                time(&(pInode->time));
                                                updateInode(*pInode);
                                                delete buff;
                                                return 0;
                                            }
                                            else
                                            {
                                                printf("You have input %ld Byte dat, continue?[Y/N]", len);
                                                ch = getchar();
                                                if(ch != 'Y' && ch != 'y')
                                                {
                                                    pInode->length = len;
                                                    time(&(pInode->time));
                                                    updateInode(*pInode);
                                                    delete buff;
                                                    return 0;
                                                }

                                            }
                                        }
                                        else
                                        {
                                            pInode->length = len;
                                            time(&(pInode->time));
                                            updateInode(*pInode);
                                            delete buff;
                                            return 0;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                pInode->length = len;
                                time(&(pInode->time));
                                updateInode(*pInode);
                                delete buff;
                                return 0;
                            }
                        }
                    }
                }
                else
                {
                    pInode->length = len;
                    time(&(pInode->time));
                    updateInode(*pInode);
                    delete buff;
                    return 0;
                }
            }
            pInode->length = len;
            time(&(pInode->time));
            updateInode(*pInode);
            delete buff;
            return 0;
        }
        else
        {
            printf("%s is a directory\n", name);
            return -1;
        }
    }
    else
    {
        printf("no such file or directory\n");
        return -1;
    }
}

/**
删除文件
finish
*/
int FileSystem::del(char* name)
{
    //printf("delete 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)
        {
            if(pInode->type == 0)
            {
                printf("file %s is Read-Only file\n", name);
                return -1;
            }
            //释放文件内容数据块
            int i;
            unsigned int blockId;
            //遍历10个直接索引,释放数据块
            for(i = 0; i < 10; i++)
            {
                blockId = pInode->addr[i];
                //printf("direct addr:%d\n", blockId);
                if(blockId > 0)
                {
                    //更新superBlock
                    superBlock.blockFree++;
                    updateSuperBlock(superBlock);
                    //释放block
                    releaseBlock(blockId);
                    //更新blockBitmap
                    blockBitmap[blockId] = 0;
                    updateBlockBitmap(blockBitmap, blockId);
                }
            }
            //遍历1个一级索引
            unsigned int addrBlockId = pInode->addr[10];
            int totalItem = blockSize/itemSize;
            if(addrBlockId > 0)
            {
                //遍历totalItem个直接索引
                for(i = 0; i < totalItem; i++)
                {
                    blockId = getItem(addrBlockId, i);
                    if(blockId > 0)
                    {
                        //更新superBlock
                        superBlock.blockFree++;
                        updateSuperBlock(superBlock);
                        //释放block
                        releaseBlock(blockId);
                        //更新blockBitmap
                        blockBitmap[blockId] = 0;
                        updateBlockBitmap(blockBitmap, blockId);
                    }
                }
                //释放一级索引块
                //更新superBlock
                superBlock.blockFree++;
                updateSuperBlock(superBlock);
                //释放block
                releaseBlock(addrBlockId);
                //更新blockBitmap
                blockBitmap[addrBlockId] = 0;
                updateBlockBitmap(blockBitmap, addrBlockId);
            }
            //遍历一个二级索引
            unsigned int addrBlockId2 = pInode->addr[11];
            if(addrBlockId2 > 0)
            {
                //遍历totalItem个一级索引
                unsigned j;
                for(j = 0; j < totalItem; j++)
                {
                    addrBlockId = getItem(addrBlockId2, j);
                    if(addrBlockId > 0)
                    {
                        //遍历totalItem个直接索引
                        for(i = 0; i < totalItem; i++)
                        {
                            blockId = getItem(addrBlockId, i);
                            if(blockId > 0)
                            {
                                //更新superBlock
                                superBlock.blockFree++;
                                updateSuperBlock(superBlock);
                                //释放block
                                releaseBlock(blockId);
                                //更新blockBitmap
                                blockBitmap[blockId] = 0;
                                updateBlockBitmap(blockBitmap, blockId);
                            }
                        }
                        //释放一级索引块
                        //更新superBlock
                        superBlock.blockFree++;
                        updateSuperBlock(superBlock);
                        //释放block
                        releaseBlock(addrBlockId);
                        //更新blockBitmap
                        blockBitmap[addrBlockId] = 0;
                        updateBlockBitmap(blockBitmap, addrBlockId);
                    }
                }
                //释放二级索引块
                //更新superBlock
                superBlock.blockFree++;
                updateSuperBlock(superBlock);
                //释放block
                releaseBlock(addrBlockId2);
                //更新blockBitmap
                blockBitmap[addrBlockId2] = 0;
                updateBlockBitmap(blockBitmap, addrBlockId2);
            }

            //释放i节点
            releaseInode(pInode->id);
            //更新superBlock
            superBlock.inodeNum--;
            updateSuperBlock(superBlock);
            //更新inodeBitmap
            inodeBitmap[pInode->id] = 0;
            updateInodeBitmap(inodeBitmap, pInode->id);
            //释放目录文件项
            releaseItem(pInode->blockId, pInode->id);
            //printf("delete file %s\n", pInode->name);
        }
        //删除目录
        else
        {
            //删除子文件...
            cd(name);
            FcbLink link = curLink->next;
            while(link != NULL)
            {
                del(link->fcb.name);
                link = link->next;
            }
            cd("..");
            if(pInode->type == 0)
            {
                printf("file %s is Read-Only file\n", name);
                return -1;
            }
            //删除目录文件本身
            //释放文件内容数据块
            int i;
            unsigned int blockId;
            //遍历11个直接索引,释放数据块
            for(i = 0; i < 11; i++)
            {
                blockId = pInode->addr[i];
                if(blockId > 0)
                {
                    //更新superBlock
                    superBlock.blockFree++;
                    updateSuperBlock(superBlock);
                    //释放block
                    releaseBlock(blockId);
                    //更新blockBitmap
                    blockBitmap[blockId] = 0;
                    updateBlockBitmap(blockBitmap, blockId);
                }
            }
            //遍历1个一级索引
            unsigned int addrBlockId = pInode->addr[11];
            int totalItem = blockSize/itemSize;
            if(addrBlockId > 0)
            {
                //遍历totalItem个直接索引
                for(i = 0; i < totalItem; i++)
                {
                    blockId = getItem(addrBlockId, i);
                    if(blockId > 0)
                    {
                        //更新superBlock
                        superBlock.blockFree++;
                        updateSuperBlock(superBlock);
                        //释放block
                        releaseBlock(blockId);
                        //更新blockBitmap
                        blockBitmap[blockId] = 0;
                        updateBlockBitmap(blockBitmap, blockId);
                    }
                }
                //释放一级索引块
                //更新superBlock
                superBlock.blockFree++;
                updateSuperBlock(superBlock);
                //释放block
                releaseBlock(addrBlockId);
                //更新blockBitmap
                blockBitmap[addrBlockId] = 0;
                updateBlockBitmap(blockBitmap, addrBlockId);
            }
            //释放i节点
            releaseInode(pInode->id);
            //更新superBlock
            superBlock.inodeNum--;
            updateSuperBlock(superBlock);
            //更新inodeBitmap
            inodeBitmap[pInode->id] = 0;
            updateInodeBitmap(inodeBitmap, pInode->id);
            //释放目录文件项
            releaseItem(pInode->blockId, pInode->id);
            //printf("delete dir %s\n", pInode->name);
        }
        //更新目录i节点
        curInode.length--;
        time(&(curInode.time));
        updateInode(curInode);
        //更新curLink
        removeFcbLinkNode(curLink, *pInode);
        delete pInode;
        return 0;
    }
    else
    {
        printf("no such file or directory\n");
        return -1;
    }

}

/**
重命名文件
finish
*/
int FileSystem::mv(char* name, char* newName)
{
    //printf("rename file %s in %s to %s\n", name, curInode.name, newName);
    unsigned int id = findChildInode(curLink, name);
    if(id > 0)
    {

        Inode inode;
        getInode(&inode, id);
        if(inode.type == 0)
        {
            printf("file %s is Read-Only file\n", name);
            return -1;
        }
        strcpy(inode.name, newName);
        time(&(inode.time));
        updateInode(inode);
        //update curLink
        FcbLink link = curLink->next;
        while(link != NULL)
        {
            if(strcmp(link->fcb.name, name) == 0)
            {
                strcpy(link->fcb.name, newName);
                return 0;
            }
            link = link->next;
        }
    }
    else
    {
        printf("no such file or directory:%s\n", name);
        return -1;
    }
}

/**
复制文件
unsurpport because input and output control is difficult
*/
int FileSystem::cp(char* src, char* dst)
{
    printf("unsurpport command\n");
    return 0;
}


/**
修改文件权限:只读/可写
finish
*/
int FileSystem::chmod(char* name, unsigned char type)
{
    //printf("chmod file %s (isDir=%d) in %s to value %d\n", name, isDir, curInode.name, type);
    unsigned int id = findChildInode(curLink, name);
    if(id > 0)
    {
        Inode inode;
        getInode(&inode, id);
        //目录
        if(inode.isDir == 1)
        {
            cd(name);
            FcbLink link = curLink->next;
            while(link != NULL)
            {
                chmod(link->fcb.name, type);
                link = link->next;
            }
            cd("..");
        }

        inode.type = type;
        time(&(inode.time));
        updateInode(inode);
        return 0;
    }
    else
    {
        printf("no such file or directory:%s\n", name);
        return -1;
    }
}

/**
登录文件系统验证
finish
*/
void FileSystem::login()
{
    char username[10];
    char password[10];
    while(1)
    {
        printf("username:");
        fgets(username, sizeof(username), stdin);
        if(username[strlen(username)-1] == '\n')
            username[strlen(username)-1] = '\0';
        system("stty -echo");
        printf("password:");
        fgets(password, sizeof(password), stdin);
        if(password[strlen(password)-1] == '\n')
            password[strlen(password)-1] = '\0';
        system("stty echo");
        printf("\n");
        if(strcmp(username,user.username)==0 && strcmp(password,user.password)==0)
            break;
        else
        {
            printf("username or password is not correct,please try again.\n");
        }
    }
}

/**
退出账户
finish
*/
void FileSystem::logout()
{
    //保存数据
    updateResource();
    printf("%s has logout\n", user.username);
    //重新打开系统并进行登录验证,由于命令循环未退出,故会继续接受命令
    openFileSystem();
    login();
}

/**
退出
finish
*/
void FileSystem::exit()
{
    //保存数据并彻底退出
    printf("Bye!\n");
    stopHandle(0);
}

/**
查看文件系统信息
finish
*/
void FileSystem::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);
}

/**
清屏
finish
*/
void FileSystem::clr()
{
    system("clear");
}

/**
修改账户信息:用户名和密码
*/
int FileSystem::account()
{
    char username[10];
    char password[10];

    system("stty -echo");
    printf("old password:");
    fgets(password, 10, stdin);
    if(password[strlen(password)-1] == '\n')
        password[strlen(password)-1] = '\0';
    system("stty echo");
    printf("\n");
    if(strcmp(password,user.password)==0)
    {
        while(1)
        {
            printf("new username:");
            fgets(username, 10, stdin);
            if(username[strlen(username)-1] == '\n')
                username[strlen(username)-1] = '\0';
            system("stty -echo");
            printf("new password:");
            fgets(password, 10, stdin);
            if(password[strlen(password)-1] == '\n')
                password[strlen(password)-1] = '\0';
            system("stty echo");
            printf("\n");
            if(strlen(username) < 2 || strlen(password) < 4)
            {
                printf("your username or password is too long or too short,please try again\n");
            }
            else
            {
                break;
            }
        }
        strcpy(user.username, username);
        strcpy(user.password, password);
        setUser(user);
        printf("modify account info success.\n");
        return 0;
    }
    else
    {
        printf("password is not correct, you are not permitted to modify account info.\n");
        return -1;
    }
}

/**
运行文件系统,处理用户命令
finish
*/
void FileSystem::command()
{
    char input[128];
    do
    {
        showPath();
        fgets(input, 128, stdin);
        switch(analyse(input))
        {
            case HELP:
                help();
                break;
            case LS://执行ls或ls-l
                if(strcmp(cmd[1], "-l") == 0)
                    ls_l();
                else
                    ls();
                break;
            case CD:
                cd(cmd[1]);
                break;
            case MKDIR:
                createFile(cmd[1],1);
                break;
            case TOUCH:
                createFile(cmd[1],0);
                break;
            case CAT:
                read(cmd[1]);
                break;
            case WRITE:
                write(cmd[1]);
                break;
            case RM:
                if(strcmp(cmd[1], "-r") == 0)
                    del(cmd[2]);
                else
                    del(cmd[1]);
                break;
            case MV:
                mv(cmd[1], cmd[2]);
                break;
            case CP:
                if(strcmp(cmd[1], "-r") == 0)
                    cp(cmd[2], cmd[3]);
                else
                    cp(cmd[1], cmd[2]);
                break;
            case CHMOD:
                if(strcmp(cmd[1], "-r") == 0)
                    chmod(cmd[3], cmd[2][0]-'0');
                else
                    chmod(cmd[2], cmd[1][0]-'0');
                break;
            case LOGOUT:
                logout();
                break;
            case EXIT:
                exit();
                break;
            case SYSINFO:
                systemInfo();
                break;
            case CLEAR:
                clr();
                break;
            case ACCOUNT:
                account();
                break;
            default:
                printf("unsurpport command\n");
                break;
        }
    }while(1);
}



/**
private methods
*/

//user区域操作
/**
取出user数据
finish
*/
void FileSystem::getUser(User* pUser)
{
    if(fp == NULL || pUser == NULL)
    {
        return;
    }
    rewind(fp);
    fread(pUser, userSize, 1, fp);
}

/**
更新user数据
finish
*/
void FileSystem::setUser(User user)
{
    if(fp == NULL)
    {
        return;
    }
    rewind(fp);
    fwrite(&user, userSize, 1, fp);
}

//superBlock区域操作
/**
取出superBlock数据
finish
*/
void FileSystem::getSuperBlock(SuperBlock* pSuper)
{
    if(fp == NULL || pSuper == NULL)
    {
        return;
    }
    fseek(fp, sOffset, SEEK_SET);
    fread(pSuper, superBlockSize, 1, fp);
}

/**
更新superBlock数据
finish
*/
void FileSystem::updateSuperBlock(SuperBlock super)
{
    if(fp == NULL)
    {
        return;
    }
    fseek(fp, sOffset, SEEK_SET);
    fwrite(&super, superBlockSize, 1, fp);
}

//blockImage区域操作
/**
寻找一个空闲的数据块,0号已被分配给根目录,返回值大于0表示找到
finish
*/
unsigned int FileSystem::getAvailableBlockId()
{
    if(superBlock.blockFree <= 0)
    {
        printf("no free block\n");
        return 0;
    }

    int i;
    for(i = 0; i < blockNum; i++)
    {
        if(blockBitmap[i] == 0)
        {
            //printf("find block %d\n", i);
            releaseBlock(i);
            return i;
        }
    }
    printf("no free block\n");
    return 0;
}


/**
取出blockBitmap
finish
*/
void FileSystem::getBlockBitmap(unsigned char* bitmap)
{
    if(fp == NULL || bitmap == NULL)
    {
        return;
    }
    fseek(fp, bbOffset, SEEK_SET);
    fread(bitmap, blockBitmapSize, 1, fp);
}

/**
更新blockBitmap
finish
*/
void FileSystem::updateBlockBitmap(unsigned char* bitmap, unsigned int index)
{
    this->updateBlockBitmap(bitmap, index, 1);
    //printf("update blockBitmap index=%d, value=%d\n", index, bitmap[index]);
}

/**
更新blockBitmap
finish
*/
void FileSystem::updateBlockBitmap(unsigned char* bitmap, unsigned int start, unsigned int count)
{
    if(fp == NULL)
    {
        return;
    }
    fseek(fp, bbOffset+start, SEEK_SET);
    fwrite(bitmap+start, count, 1, fp);
}

//inodeImage区域操作
/**
寻找一个空闲的i节点块,0号已被分配给根目录,返回值大于0表示找到
finish
*/
unsigned int FileSystem::getAvailableInodeId()
{
    unsigned int i;
    for(i = 0; i < blockNum; i++)
    {
        if(inodeBitmap[i] == 0)
        {
            //printf("find inode %d\n", i);
            return i;
        }
    }
    return 0;
}

/**
取出inodeBitmap
finish
*/
void FileSystem::getInodeBitmap(unsigned char* bitmap)
{
    if(fp == NULL || bitmap == NULL)
    {
        return;
    }
    fseek(fp, ibOffset, SEEK_SET);
    fread(bitmap, inodeBitmapSize, 1, fp);
}

/**
更新inodeBitmap
finish
*/
void FileSystem::updateInodeBitmap(unsigned char* bitmap, unsigned int index)
{
    this->updateInodeBitmap(bitmap, index, 1);
}

/**
更新inodeBitmap
finish
*/
void FileSystem::updateInodeBitmap(unsigned char* bitmap, unsigned int start, unsigned int count)
{
    if(fp == NULL)
    {
        return;
    }
    fseek(fp, ibOffset+start, SEEK_SET);
    fwrite(bitmap+start, count, 1, fp);
}

//inode block区域操作
/**
取出一条inode
finish
*/
void FileSystem::getInode(PInode pInode, unsigned int id)
{
    if(fp == NULL || pInode == NULL)
    {
        return;
    }
    fseek(fp, iOffset+inodeSize*id, SEEK_SET);
    fread(pInode, inodeSize, 1, fp);
}

/**
更新一条inode
finish
*/
void FileSystem::updateInode(Inode inode)
{
    if(fp == NULL )
    {
        return;
    }
    fseek(fp, iOffset+inodeSize*inode.id, SEEK_SET);
    fwrite(&inode, inodeSize, 1, fp);
}

/**
释放一条inode
finish
*/
void FileSystem::releaseInode(unsigned int id)
{
    if(fp == NULL )
    {
        return;
    }
    fseek(fp, iOffset+inodeSize*id, SEEK_SET);
    int i;
    for(i = 0; i < inodeSize; i++)
    {
        fputc(0, fp);
    }
}

//data block区域操作
//地址或文件项
/**
寻找一个当前目录文件中可用的文件项,返回数据块地址和文件项索引,大于0表示找到
finish
*/
unsigned int FileSystem::getAvailableFileItem(Inode& inode, unsigned int* availableIndex)
{
    //遍历建立子文件或子目录节点
    int i;
    unsigned int index;
    unsigned int blockId;
    unsigned int fileItem;

    Inode fileInode;
    const int itemTotal = blockSize/itemSize;
    //遍历11个直接索引
    for(i = 0; i < 11; i++)
    {
        blockId = inode.addr[i];
        //直接索引数据块已分配,直接查找
        if(blockId > 0 || inode.id == 0)
        {
            //遍历直接索引下itemTotal个fileItem项(文件i节点索引),查找
            for(index = 0; index < itemTotal; index++)
            {
                fileItem = getItem(blockId, index);
                //printf("%d [%d] = %d\n", blockId, index, fileItem);
                //读取i子文件或子目录i节点
                if(fileItem  == 0)
                {
                    *availableIndex = index;
                    return blockId;
                }
            }
        }
        //直接索引数据块未分配,分配成功后立即返回,
        else
        {
            blockId = getAvailableBlockId();
            //分配成功
            if(blockId > 0)
            {
                //更新superBlock
                superBlock.blockFree--;
                updateSuperBlock(superBlock);
                //更新blockBitmap
                blockBitmap[blockId] = 1;
                updateBlockBitmap(blockBitmap, blockId);
                //更新i节点
                inode.addr[i] = blockId;
                updateInode(inode);
                //直接返回第0个
                *availableIndex = 0;
                return blockId;
            }
            //分配失败
            else
            {
                return 0;
            }
        }
    }
    //遍历一级索引1个
    unsigned int addrBlockId = inode.addr[11];
    //一级索引数据块已分配
    if(addrBlockId > 0)
    {
        //遍历一级索引下itemTotal个直接索引
        for(i = 0; i < itemTotal; i++)
        {
            //直接索引数据块已分配,直接查找
            if(blockId > 0)
            {
                //遍历直接索引下itemTotal个fileItem项(文件i节点索引),查找
                for(index = 0; index < itemTotal; index++)
                {
                    fileItem = getItem(blockId, index);
                    //读取i子文件或子目录i节点
                    if(fileItem  == 0)
                    {
                        *availableIndex = index;
                        return blockId;
                    }
                }
            }
            //直接索引数据块未分配,分配成功后立即返回,
            else
            {
                blockId = getAvailableBlockId();
                //分配成功
                if(blockId > 0)
                {
                    //更新superBlock
                    superBlock.blockFree--;
                    updateSuperBlock(superBlock);
                    //更新blockBitmap
                    blockBitmap[blockId] = 1;
                    updateBlockBitmap(blockBitmap, blockId);
                    //更新i节点
                    inode.addr[i] = blockId;
                    updateInode(inode);
                    //直接返回第0个
                    *availableIndex = 0;
                    return blockId;
                }
            //分配失败
            else
            {
                return 0;
            }
        }
        }
    }
    //一级索引数据块未分配
    else
    {
        addrBlockId = getAvailableBlockId();
        //一级索引数据块分配成功
        if(addrBlockId > 0)
        {
            //更新superBlock
            superBlock.blockFree--;
            updateSuperBlock(superBlock);
            //更新blockBitmap
            blockBitmap[addrBlockId] = 1;
            updateBlockBitmap(blockBitmap, addrBlockId);
            //更新i节点
            inode.addr[11] = addrBlockId;
            updateInode(inode);

            //一级索引数据块第一项直接索引分配数据块
            blockId = getAvailableBlockId();
            //分配成功
            if(blockId > 0)
            {
                //更新superBlock
                superBlock.blockFree--;
                updateSuperBlock(superBlock);
                //更新blockBitmap
                blockBitmap[blockId] = 1;
                updateBlockBitmap(blockBitmap, blockId);
                //更新一级索引第一项直接索引数据块
                updateItem(addrBlockId, 0, blockId);
                //直接返回第0个
                *availableIndex = 0;
                return blockId;
            }
        }
        //一级索引数据块分配失败
        else
        {
            return 0;
        }
    }
}

/**
取出一个地址项或文件项,针对目录的操作
finish
*/
unsigned int FileSystem::getItem(unsigned int blockId, unsigned int index)
{
    unsigned int value = 0;
    if(fp == NULL)
    {
        return value;
    }
    fseek(fp, bOffset+blockSize*blockId+itemSize*index, SEEK_SET);
    fread(&value, itemSize, 1, fp);
    return value;
}

/**
更新一个地址项或文件项
finish
*/
void FileSystem::updateItem(unsigned int blockId, unsigned int index, unsigned int value)
{
    if(fp == NULL)
    {
        return;
    }
    fseek(fp, bOffset+blockSize*blockId+itemSize*index, SEEK_SET);
    fwrite(&value, itemSize, 1, fp);
}

/**
释放一个地址项或文件项
finish
*/
void FileSystem::releaseItem(unsigned int blockId, unsigned int id)
{
    int itemTotal = blockSize/itemSize;
    int i;
    unsigned int itemId;
    fseek(fp, bOffset+blockSize*blockId, SEEK_SET);
    for(i = 0; i < itemTotal; i++)
    {
        fread(&itemId, itemSize, 1, fp);
        if(itemId == id)
        {
            //printf("release item id=%d in %d\n", id, blockId);
            fseek(fp, -itemSize, SEEK_CUR);
            itemId = 0;
            fwrite(&itemId, itemSize, 1, fp);
            return;
        }
    }
}


//文件内容
/**
取出一个数据块的全部或部分,针对文件的操作
finish
*/
int FileSystem::getData(unsigned int blockId, char* buff, unsigned int size, unsigned int offset)
{
    int len = 0;
    if(fp == NULL || buff == NULL || offset >= blockSize)
    {
        return len;
    }
    fseek(fp, bOffset+blockSize*blockId, SEEK_SET);
    if(size > blockSize-offset)
        size = blockSize-offset;
    len = fread(buff, size, 1, fp);
    return len;
}

/**
写入一个数据块的全部或部分,针对文件的操作
finish
*/
int FileSystem::writeData(unsigned int blockId, char* buff, unsigned int size, unsigned int offset)
{
    int len = 0;
    if(fp == NULL || buff == NULL || offset >= blockSize)
    {
        return len;
    }
    fseek(fp, bOffset+blockSize*blockId, SEEK_SET);
    if(size > blockSize-offset)
        size = blockSize-offset;
    len = fwrite(buff, size, 1, fp);
    return len;
}

/**
释放一个数据块
finish
*/
void FileSystem::releaseBlock(unsigned int blockId)
{
    if(fp == NULL)
    {
        return;
    }
    fseek(fp, bOffset+blockSize*blockId, SEEK_SET);
    int i;
    for (i = 0; i < blockSize; i++)
    {
        fputc(0, fp);
    }
    //printf("release block %d\n", blockId);
}


//定位操作
/**
寻找目录下的文件或子目录,返回i节点索引,大于0表示找到
finish
*/
unsigned int FileSystem::findChildInode(FcbLink curLink, char* name)
{
    if(curLink == NULL || name == NULL)
    {
        return 0;
    }
    FcbLink link = curLink->next;
    while(link != NULL)
    {
        if(strcmp(link->fcb.name, name) == 0)
        {
            return link->fcb.id;
        }
        link = link->next;
    }
    return 0;
}

//目录信息链操作
/**
构建一个FcbLinkNode
finish
*/
void FileSystem::getFcbLinkNode(FcbLink pNode, Inode inode)
{
    if(pNode == NULL)
    {
        return;
    }
    pNode->fcb.id = inode.id;
    strcpy(pNode->fcb.name, inode.name);
    pNode->fcb.isDir = inode.isDir;
    pNode->fcb.blockId = inode.blockId;
    pNode->next = NULL;
}


/**
建立目录的信息链
finish
*/
void FileSystem::getFcbLink(FcbLink& curLink, Inode inode)
{
    if(curLink != NULL)
    {
        releaseFcbLink(curLink);
    }
    //目录本身节点
    //printf("start read dir self inode\n");
    curLink = new FcbLinkNode();
    getFcbLinkNode(curLink, inode);
    //printf("end read dir self inode\n");
    if(inode.length <= 0)
        return;

    //遍历建立子文件或子目录节点
    int i;
    unsigned int index;
    unsigned int blockId;
    unsigned int fileItem;
    Inode fileInode;
    FcbLink pNode;
    FcbLink link = curLink;
    unsigned long len = inode.length;//子文件或子目录数
    const int itemTotal = blockSize/itemSize;
    //遍历11个直接索引
    for(i = 0; i < 11; i++)
    {
        blockId = inode.addr[i];
        if(blockId > 0 || curInode.id == 0)
        {
            //遍历直接索引下itemTotal个fileItem项(文件i节点索引)
            for(index = 0; index < itemTotal; index++)
            {
                fileItem = getItem(blockId, index);
                //读取i子文件或子目录i节点
                if(fileItem > 0)
                {
                    getInode(&fileInode, fileItem);
                    pNode = new FcbLinkNode();
                    getFcbLinkNode(pNode, fileInode);
                    link->next = pNode;
                    link = pNode;
                    len--;
                    //printf("read dir item inode: id=%d, name=%s, index=%d\n", fileItem, fileInode.name, index);
                    if(len <= 0)
                    {
                        return;
                    }

                }
            }
        }
    }
    //遍历一级索引1个
    unsigned int addrBlockId = inode.addr[11];
    if(addrBlockId > 0)
    {
        //遍历一级索引下itemTotal个直接索引
        for(i = 0; i < itemTotal; i++)
        {
            blockId = inode.addr[i];
            if(blockId > 0)
            {
                //遍历直接索引下itemTotal个fileItem项(文件i节点索引)
                for(index = 0; index < itemTotal; index++)
                {
                    fileItem = getItem(blockId, index);
                    //读取i子文件或子目录i节点
                    if(fileItem > 0)
                    {
                        getInode(&fileInode, fileItem);
                        pNode = new FcbLinkNode();
                        getFcbLinkNode(pNode, fileInode);
                        link->next = pNode;
                        link = pNode;
                        len--;
                        //printf("read dir item inode: id=%d, name=%s, index=%d\n", fileItem, fileInode.name, index);
                        if(len <= 0)
                            return;
                    }
                }
            }
        }
    }
}

/**
目录信息链增加一个节点,不能增加根节点
finish
*/
void FileSystem::appendFcbLinkNode(FcbLink curLink, Inode inode)
{
    if(curLink == NULL || inode.id <= 0)
    {
        return;
    }
    FcbLink link = curLink;
    while(link->next != NULL)
    {
        link = link->next;
    }
    FcbLink pNode = new FcbLinkNode();
    getFcbLinkNode(pNode, inode);
    link->next = pNode;
}

/**
目录信息链删除一个节点,不能删除根节点
finish
*/
void FileSystem::removeFcbLinkNode(FcbLink curLink, Inode inode)
{
    if(curLink == NULL || inode.id <= 0)
    {
        return;
    }
    FcbLink link = curLink->next;
    FcbLink last = curLink;
    while(link != NULL)
    {
        if(link->fcb.id == inode.id)
        {
            last->next = link->next;
            delete link;
            break;
        }
        last = link;
        link = link->next;
    }
}

/**
目录信息链删除一个节点,不能删除根节点
finish
*/
void FileSystem::removeFcbLinkNode(FcbLink curLink, char* name)
{
    if(curLink == NULL || name == NULL)
    {
        return;
    }
    FcbLink link = curLink->next;
    FcbLink last = curLink;
    while(link != NULL)
    {
        if(strcmp(link->fcb.name, name) == 0)
        {
            last->next = link->next;
            delete link;
            break;
        }
        last = link;
        link = link->next;
    }
}

/**
清空并释放目录信息链
finish
*/
void FileSystem::releaseFcbLink(FcbLink& curLink)
{
    FcbLink link = curLink;
    FcbLink tmp;
    while(link != NULL)
    {
        tmp = link->next;
        delete link;
        link = tmp;
    }
    curLink = NULL;
}

//private system methods
/**
分析命令
finish
*/
int FileSystem::analyse(char* str)
{
    int i;
    for(i = 0; i < 5; i++)
        cmd[i][0] = '\0';
    sscanf(str, "%s %s %s %s %s",cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]);

    for(i = 1; i < 17; i++)
    {
        if(strcmp(cmd[0], SYS_CMD[i]) == 0)
        {
            return i;
        }
    }
    return 0;
}

/**
停止控制输入捕获,更新并关闭文件,最后直接退出
finish
*/
void FileSystem::stopHandle(int sig)
{
    //printf("\nUpdating resource, please wait...\n");
    updateResource();
    ::exit(0);
}

/**
更新文件系统头部信息,关闭文件
finish
*/
void FileSystem::updateResource()
{
    rewind(fp);
    fwrite(&user, userSize, 1, fp);
    fwrite(&superBlock, superBlockSize, 1, fp);
    fwrite(blockBitmap, blockBitmapSize, 1, fp);
    fwrite(inodeBitmap, inodeBitmapSize, 1, fp);
    fclose(fp);
}

/**
输出当前路径作为命令提示符号
finish
*/
void FileSystem::showPath()
{
    printf("%s@localhost %s>",user.username, curPath.data());
}

//util
/**
显示文件摘要
finish
*/
void FileSystem::showFileDigest(FcbLink pNode)
{
    if(pNode == NULL)
        return;
    printf("%s",pNode->fcb.name);
    if(pNode->fcb.isDir==1)
    {
        printf("/");
    }
    printf("\n");
}

/**
显示文件详情
finish
*/
void FileSystem::showFileDetail(PInode pInode)
{
    if(pInode == NULL)
        return;
    //format output
    if(pInode->isDir == 1)
    {
        printf("%c", 'd');
    }
    else
    {
        printf("%c", '-');
    }

    printf("%c", 'r');
    if(pInode->type == 1)
    {
        printf("%c", 'w');
    }
    else
    {
        printf("%c", '-');
    }
    printf(" %10d", pInode->length);
    printf(" %.12s", 4 + ctime(&(pInode->time)));
    printf(" %s", pInode->name);
    printf("\n");
}

/**
等待数据输入
*/
unsigned int FileSystem::waitForInput(char* buff, unsigned int limit)
{
    unsigned int len = 0;
    char ch[3];
    ch[0] = 0;
    ch[1] = 0;
    while(len < limit)
    {
        ch[2] = getchar();
        if(ch[0] == '<' && ch[1] == '/' && ch[2] == '>')
        {
            len -= 2;
            buff[len] = '\0';
            return len;
        }
        else
        {
            ch[0] = ch[1];
            ch[1] = ch[2];
            buff[len] = ch[2];
            len++;
        }
    }
    buff[len] = '\0';
    return len;
}

main.cpp 文件系统调用

#include 
#include "FileSystem.h"

using namespace std;

int main(int argc, char* argv[])
{
    FileSystem file(argv[1]);
    file.init();
    cout << "Hello world!" << endl;
    return 0;
}

test.c 附:文件系统用户名和密码找回

#include 
#include 

int main(int argc, char* argv[])
{
    FILE* fp = fopen(argv[1], "rb");
    char username[10];
    char password[10];
    fread(username, sizeof(username), 1, fp);
    fread(password, sizeof(password), 1, fp);
    fclose(fp);
    printf("username:%s\npassword:%s\n", username, password);
    return 0;
}

编译方法:

生成可执行文件system

$ g++ -o system main.cpp FileSystem.cpp

运行方法:

打开或创建systemFile,并以此为基础启动文件系统

$ ./system systemFile

附:

用于忘记文件系统用户名和密码时找回

$ gcc -o test test.c
$ ./test systemFile

使用方法(类似于linux终端命令):

帮助(会提示命令操作)

> help 

系统信息

> sysinfo 

退出账户

> logout

修改账户(username,password)

> account 

清屏

> clear 

列出目录下所有文件摘要

> ls 

列出目录下所有文件详情

> ls -l 

进入子目录dir或父目录,暂不支持进入任意层次目录

> cd dir(..) 

创建目录dir

> mkdir dir 

创建文件file

> touch file 

查看文件

> cat file 

写入文件,暂时只支持标准输入,以

> write file 

删除文件file或删除目录dir及其子文件

> rm file(dir) 

暂不支持文件复制

> cp src dst 

重命名文件oldFileName为newFileName

> mv oldFileName newFileName 

修改文件file或目录dir及其子文件读写权限为只读(0)或读写(1)

> chmod 0(1) file(dir) 

退出文件系统

> exit 

你可能感兴趣的:(linux)