如图想使用fgets获取输入的命令,结果发现无参数的命令全部报错
改用gets,又会报警告
请问该如何处理呢?
filesystem.c代码如下:
char* FILENAME = "";
char s[20];
#include"ds.h"
//设定打开文件系统名
void startsys()
{
/**
* 功能:由main()函数调用,进入并初始化我们所建立的文件系统,以供用户使用。
*/
//申请虚拟磁盘空间;
myvhard = (unsigned char*)malloc(SIZE);
FILE* file;
//使用c语言的库函数fopen()打开myfsys文件
if ((file = fopen(FILENAME, "r")) != NULL) {
fread(buffer, SIZE, 1, file);
fclose(file);
// 判断其开始的8个字节内容是否为“10101010”
if (memcmp(buffer, "10101010", 8) == 0) {
//复制到内存中的虚拟磁盘空间中
memcpy(myvhard, buffer, SIZE);
printf("文件系统成功载入\n");
} else {
printf("无效的系统, 开始创建文件系统\n");
my_format();
memcpy(buffer, myvhard, SIZE);
}
} else {
printf("文件系统不存在,现在开始创建文件系统\n");
//调用my_format()对申请到的虚拟磁盘空间进行格式化操作
my_format();
//虚拟磁盘中的内容保存到myfsys文件中
memcpy(buffer, myvhard, SIZE);
}
fcb* root;
//填写根目录文件的相关信息
root = (fcb*)(myvhard + 5 * BLOCKSIZE);
strcpy(openfilelist[0].filename, root->filename);
strcpy(openfilelist[0].exname, root->exname);
openfilelist[0].attribute = root->attribute;
openfilelist[0].time = root->time;
openfilelist[0].date = root->date;
openfilelist[0].first = root->first;
openfilelist[0].length = root->length;
openfilelist[0].free = root->free;
//表项中的dirno和diroff分别置为5
openfilelist[0].dirno = 5;
openfilelist[0].diroff = 0;
strcpy((char *)(openfilelist[0].dir), "/root/");
openfilelist[0].count = 0;
openfilelist[0].fcbstate = 0;
openfilelist[0].topenfile = 1;
//ptrcurdir指针指向该用户打开文件表项
//将当前目录设置为根目录
startp = ((block0*)myvhard)->startblock;
currfd = 0;
return;
}
void my_format()
{
/**
* 功能:对虚拟磁盘进行格式化,布局虚拟磁盘,建立根目录文件(或根目录区)
*/
//虚拟磁盘第一个块作为引导块,开始的8个字节是文件系统的魔数,记为“10101010”
block0* boot = (block0*)myvhard;
strcpy(boot->magic_number, "10101010");
strcpy(boot->information, "FAT文件系统");
boot->root = 5;
boot->startblock = myvhard + BLOCKSIZE * 5;
fat* fat1 = (fat*)(myvhard + BLOCKSIZE);
fat* fat2 = (fat*)(myvhard + BLOCKSIZE * 3);
int i;
for (i = 0; i < 6; i++) {
fat1[i].id = END;
fat2[i].id = END;
}
for (i = 6; i < 1000; i++) {
fat1[i].id = FREE;
fat2[i].id = FREE;
}
// 5th block is root
fcb* root = (fcb*)(myvhard + BLOCKSIZE * 5);
//创建两个特殊的目录项:“.”和“..”
strcpy(root->filename, ".");
strcpy(root->exname, "di");
root->attribute = 0; // dir file
time_t rawTime = time(NULL);
struct tm* time = localtime(&rawTime);
//设置root属性
root->time = time->tm_hour * 2048 + time->tm_min * 32 + time->tm_sec / 2;
root->date = (time->tm_year - 100) * 512 + (time->tm_mon + 1) * 32 + (time->tm_mday);
root->first = 5;
root->free = 1;
root->length = 2 * sizeof(fcb);
fcb* root2 = root + 1;
memcpy(root2, root, sizeof(fcb));
//创建两个特殊的目录项:“.”和“..”
strcpy(root2->filename, "..");
for (i = 2; i < (int)(BLOCKSIZE / sizeof(fcb)); i++) {
root2++;
strcpy(root2->filename, "");
root2->free = 0;
}
FILE* fp = fopen(FILENAME, "w");
fwrite(myvhard, SIZE, 1, fp);
fclose(fp);
}
void my_exitsys()
{
/**
* 依次关闭 打开文件。 写入 FILENAME 文件
*/
while (currfd) {
my_close(currfd);
}
FILE* fp = fopen(FILENAME, "w");
fwrite(myvhard, SIZE, 1, fp);
fclose(fp);
}
void my_ls()
{
/*
* 功能:显示当前目录的内容(子目录和文件信息)。
*/
// 判断是否是目录
if (openfilelist[currfd].attribute == 1) {
printf("数据文件\n");
return;
}
char buf[MAX_TEXT_SIZE];
int i;
// 读取当前目录文件信息(一个个fcb), 载入内存
openfilelist[currfd].count = 0;
//调用do_read()读出当前目录文件内容到内存;
do_read(currfd, openfilelist[currfd].length, buf);
// 遍历当前目录 fcb
//将读出的目录文件的信息按照一定的格式显示到屏幕上
fcb* fcbptr = (fcb*)buf;
printf("文件类型 文件名 创立时间 \n" );
for (i = 0; i < (int)(openfilelist[currfd].length / sizeof(fcb)); i++, fcbptr++) {
if (fcbptr->free == 1) {
if (fcbptr->attribute == 0) {
printf("<文件> %-8s\t%d/%d/%d %d:%d\%ld\n",
fcbptr->filename,
(fcbptr->date >> 9) + 2000,
(fcbptr->date >> 5) & 0x000f,
(fcbptr->date) & 0x001f,
(fcbptr->time >> 11),
(fcbptr->time >> 5) & 0x003f,
fcbptr->length);
} else {
printf("<文件> %-8s\t%d/%d/%d %d:%d\%ld\n",
fcbptr->filename,
(fcbptr->date >> 9) + 2000,
(fcbptr->date >> 5) & 0x000f,
(fcbptr->date) & 0x001f,
(fcbptr->time >> 11),
(fcbptr->time >> 5) & 0x003f,
fcbptr->length);
}
}
}
}
void my_mkdir(char* dirname)
{
/**
* 当前目录:当前打开目录项表示的目录
* 该目录:以下指创建的目录
* 父目录:指该目录的父目录
* 功能:在当前目录下创建名为dirname的子目录。
* 输入:输入dirname:新建目录的目录名。
*/
int i = 0;
char text[MAX_TEXT_SIZE];
char* fname = strtok(dirname, ".");
char* exname = strtok(NULL, ".");
if (exname != NULL) {
printf("您不能使用该功能\n");
return;
}
// 读取父目录信息
openfilelist[currfd].count = 0;
//调用do_read()读入当前目录文件内容到内存,检查当前目录下新建目录文件是否重名,若重名则返回,并显示错误信息;
int filelen = do_read(currfd, openfilelist[currfd].length, text);
fcb* fcbptr = (fcb*)text;
// 查找是否重名
for (i = 0; i < (int)(filelen / sizeof(fcb)); i++) {
if (strcmp(dirname, fcbptr[i].filename) == 0 && fcbptr->attribute == 0) {
//如果存在重名,则打印错误信息
printf("目录已存在\n");
return;
}
}
// 申请一个打开目录表项
// 如果没有空闲表项则返回-1,并显示错误信息;
int fd = get_free_openfilelist();
if (fd == -1) {
printf("没有空闲文件表\n");
return;
}
// 检查FAT是否有空闲的盘块,如有则为新建目录文件分配一个盘块
unsigned short int block_num = get_free_block();
if (block_num == END) {
printf("没有空闲磁盘块\n");
openfilelist[fd].topenfile = 0;
return;
}
// 更新 fat 表
fat* fat1 = (fat*)(myvhard + BLOCKSIZE);
fat* fat2 = (fat*)(myvhard + BLOCKSIZE * 3);
fat1[block_num].id = END;
fat2[block_num].id = END;
// 在父目录中找一个空的 fcb,分配给该目录
// 在当前目录中为新建目录文件寻找一个空闲的目录项或为其追加一个新的目录项;
for (i = 0; i < (int)(filelen / sizeof(fcb)); i++) {
if (fcbptr[i].free == 0) {
break;
}
}
//需修改当前目录文件的长度信息,并将当前目录文件的用户打开文件表项中的fcbstate置为1
openfilelist[currfd].count = i * sizeof(fcb);
openfilelist[currfd].fcbstate = 1;
// 初始化该 fcb
// 设置fcb属性
fcb* fcbtmp = (fcb*)malloc(sizeof(fcb));
fcbtmp->attribute = 0;
time_t rawtime = time(NULL);
struct tm* time = localtime(&rawtime);
fcbtmp->date = (time->tm_year - 100) * 512 + (time->tm_mon + 1) * 32 + (time->tm_mday);
fcbtmp->time = (time->tm_hour) * 2048 + (time->tm_min) * 32 + (time->tm_sec) / 2;
strcpy(fcbtmp->filename, dirname);
strcpy(fcbtmp->exname, "di");
fcbtmp->first = block_num;
fcbtmp->length = 2 * sizeof(fcb);
fcbtmp->free = 1;
//文件的属性为目录文件,以覆盖写方式调用do_write()将其填写到对应的空目录项中;
do_write(currfd, (char*)fcbtmp, sizeof(fcb), 2);
// 设置打开文件表项
openfilelist[fd].attribute = 0;
openfilelist[fd].count = 0;
openfilelist[fd].date = fcbtmp->date;
openfilelist[fd].time = fcbtmp->time;
openfilelist[fd].dirno = openfilelist[currfd].first;
openfilelist[fd].diroff = i;
strcpy(openfilelist[fd].exname, "di");
strcpy(openfilelist[fd].filename, dirname);
openfilelist[fd].fcbstate = 0;
openfilelist[fd].first = fcbtmp->first;
openfilelist[fd].free = fcbtmp->free;
openfilelist[fd].length = fcbtmp->length;
openfilelist[fd].topenfile = 1;
strcat(strcat(strcpy((char*)(openfilelist[fd].dir), (char*)(openfilelist[currfd].dir)), dirname), "/");
// 设置 . 和 .. 目录
fcbtmp->attribute = 0;
fcbtmp->date = fcbtmp->date;
fcbtmp->time = fcbtmp->time;
strcpy(fcbtmp->filename, ".");
strcpy(fcbtmp->exname, "di");
fcbtmp->first = block_num;
fcbtmp->length = 2 * sizeof(fcb);
//调用do_write()将其写到分配的磁盘块中;
do_write(fd, (char*)fcbtmp, sizeof(fcb), 2);
fcb* fcbtmp2 = (fcb*)malloc(sizeof(fcb));
memcpy(fcbtmp2, fcbtmp, sizeof(fcb));
strcpy(fcbtmp2->filename, "..");
fcbtmp2->first = openfilelist[currfd].first;
fcbtmp2->length = openfilelist[currfd].length;
fcbtmp2->date = openfilelist[currfd].date;
fcbtmp2->time = openfilelist[currfd].time;
//调用do_write()将其写到分配的磁盘块中;
do_write(fd, (char*)fcbtmp2, sizeof(fcb), 2);
// 关闭该目录的打开文件表项,close 会修改父目录中对应该目录的 fcb 信息
/**
* 这里注意,一个目录存在 2 个 fcb 信息,一个为该目录下的 . 目录文件,一个为父目录下的 fcb。
* 因此,这俩个fcb均需要修改,前一个 fcb 由各个函数自己完成,后一个 fcb 修改由 close 完成。
* 所以这里,需要打开文件表,再关闭文件表,实际上更新了后一个 fcb 信息。
*/
my_close(fd);
free(fcbtmp);
free(fcbtmp2);
// 修改父目录 fcb
fcbptr = (fcb*)text;
fcbptr->length = openfilelist[currfd].length;
openfilelist[currfd].count = 0;
do_write(currfd, (char*)fcbptr, sizeof(fcb), 2);
openfilelist[currfd].fcbstate = 1;
}
int my_create(char* filename)
{ // 输入: 新建文件的文件名
// 功能:创建名为filename的新文件。
// 非法判断
//若创建成功,返回该文件的文件描述符(文件打开表中的数组下标);否则返回-1。
if (strcmp(filename, "") == 0) {
printf("请输入文件名\n");
return -1;
}
if (openfilelist[currfd].attribute == 1) {
printf("在数据文件下不能创建文件\n");
return -1;
}
char *b="/";
char file[20];
char *filename2=file;
strcpy(filename2,filename);
if(strstr(filename, b) != NULL){
char *token = strtok(filename, b);
int i=0;
while( token != NULL ) {
i++;
token = strtok(NULL, b);
}
char *result = strtok(filename2, b);
for(int j=0;j<i-1;j++){
my_cd(result);
result = strtok(NULL, b);
}
strcpy(filename,result);
}
openfilelist[currfd].count = 0;
char buf[MAX_TEXT_SIZE];
//调用do_read()读出该父目录文件内容到内存
do_read(currfd, openfilelist[currfd].length, buf);
int i;
fcb* fcbptr = (fcb*)buf;
// 检查重名
for (i = 0; i < (int)(openfilelist[currfd].length / sizeof(fcb)); i++, fcbptr++) {
if (fcbptr->free == 0) {
continue;
}
if (strcmp(fcbptr->filename, filename) == 0 && fcbptr->attribute == 1) {
printf("文件重名错误\n");
return -1;
}
}
// 申请空 fcb;
fcbptr = (fcb*)buf;
for (i = 0; i < (int)(openfilelist[currfd].length / sizeof(fcb)); i++, fcbptr++) {
if (fcbptr->free == 0)
break;
}
// 申请磁盘块并更新 fat 表
int block_num = get_free_block();
if (block_num == -1) {
return -1;
}
fat* fat1 = (fat*)(myvhard + BLOCKSIZE);
fat* fat2 = (fat*)(myvhard + BLOCKSIZE * 3);
fat1[block_num].id = END;
memcpy(fat2, fat1, BLOCKSIZE * 2);
// 修改 fcb 信息
strcpy(fcbptr->filename, filename);
time_t rawtime = time(NULL);
struct tm* time = localtime(&rawtime);
fcbptr->date = (time->tm_year - 100) * 512 + (time->tm_mon + 1) * 32 + (time->tm_mday);
fcbptr->time = (time->tm_hour) * 2048 + (time->tm_min) * 32 + (time->tm_sec) / 2;
fcbptr->first = block_num;
fcbptr->free = 1;
fcbptr->attribute = 1;
fcbptr->length = 0;
openfilelist[currfd].count = i * sizeof(fcb);
//调用do_write()将其填写到分配的空目录项中
do_write(currfd, (char*)fcbptr, sizeof(fcb), 2);
// 修改父目录 fcb
fcbptr = (fcb*)buf;
fcbptr->length = openfilelist[currfd].length;
//长度为0
openfilelist[currfd].count = 0;
do_write(currfd, (char*)fcbptr, sizeof(fcb), 2);
openfilelist[currfd].fcbstate = 1;
}
void my_rm(char* filename)
{
// 功能:删除名为filename的文件。
char buf[MAX_TEXT_SIZE];
//打开文件,调用do_read()读出该父目录文件内容到内存
openfilelist[currfd].count = 0;
do_read(currfd, openfilelist[currfd].length, buf);
int i, flag = 0;
fcb* fcbptr = (fcb*)buf;
// 查询打开
for (i = 0; i < (int)(openfilelist[currfd].length / sizeof(fcb)); i++, fcbptr++) {
if (strcmp(fcbptr->filename, filename) == 0 && fcbptr->attribute == 1) {
flag = 1;
break;
}
}
if (flag != 1) {
printf("没有该文件\n");
return;
}
// 更新 fat 表
int block_num = fcbptr->first;
fat* fat1 = (fat*)(myvhard + BLOCKSIZE);
int nxt_num = 0;
while (1) {
nxt_num = fat1[block_num].id;
fat1[block_num].id = FREE;
if (nxt_num != END)
block_num = nxt_num;
else
break;
}
fat1 = (fat*)(myvhard + BLOCKSIZE);
fat* fat2 = (fat*)(myvhard + BLOCKSIZE * 3);
memcpy(fat2, fat1, BLOCKSIZE * 2);
// 清空 fcb
fcbptr->date = 0;
fcbptr->time = 0;
fcbptr->exname[0] = '\0';
fcbptr->filename[0] = '\0';
fcbptr->first = 0;
//free字段置为0
fcbptr->free = 0;
fcbptr->length = 0;
openfilelist[currfd].count = i * sizeof(fcb);
do_write(currfd, (char*)fcbptr, sizeof(fcb), 2);
//
int lognum = i;
if ((lognum + 1) * sizeof(fcb) == openfilelist[currfd].length) {
openfilelist[currfd].length -= sizeof(fcb);
lognum--;
fcbptr = (fcb *)buf + lognum;
while (fcbptr->free == 0) {
fcbptr--;
openfilelist[currfd].length -= sizeof(fcb);
}
}
// 修改父目录 . 目录文件的 fcb
fcbptr = (fcb*)buf;
fcbptr->length = openfilelist[currfd].length;
openfilelist[currfd].count = 0;
do_write(currfd, (char*)fcbptr, sizeof(fcb), 2);
//将该表项中的fcbstate置为1;
openfilelist[currfd].fcbstate = 1;
}
int my_open(char* filename)
{
// 功能:打开当前目录下名为filename的文件。
char buf[MAX_TEXT_SIZE];
openfilelist[currfd].count = 0;
do_read(currfd, openfilelist[currfd].length, buf);
int i, flag = 0;
fcb* fcbptr = (fcb*)buf;
// 重名检查
for (i = 0; i < (int)(openfilelist[currfd].length / sizeof(fcb)); i++, fcbptr++) {
if (strcmp(fcbptr->filename, filename) == 0 && fcbptr->attribute == 1) {
flag = 1;
break;
}
}
if (flag != 1) {
if (openfilelist[currfd].attribute == 1) {
printf("在数据文件下不能进行该操作\n");
return -1;
}
printf("没有这个文件\n");
return -1;
}
// 申请新的打开目录项并初始化该目录项
// 检查用户打开文件表中是否有空表项
int fd = get_free_openfilelist();
if (fd == -1) {
printf("my_open: 文件列表已满\n");
return -1;
}
openfilelist[fd].attribute = 1;
//读写指针置为0
openfilelist[fd].count = 0;
openfilelist[fd].date = fcbptr->date;
openfilelist[fd].time = fcbptr->time;
openfilelist[fd].length = fcbptr->length;
openfilelist[fd].first = fcbptr->first;
openfilelist[fd].free = 1;
strcpy(openfilelist[fd].filename, fcbptr->filename);
strcat(strcpy((char *)(openfilelist[fd].dir), (char*)(openfilelist[currfd].dir)), filename);
openfilelist[fd].dirno = openfilelist[currfd].first;
openfilelist[fd].diroff = i;
openfilelist[fd].topenfile = 1;
openfilelist[fd].fcbstate = 0;
// 将该文件所分配到的空白用户打开文件表表项序号(数组下标)作为文件描述符fd返回。
currfd = fd;
return 1;
}
void my_cd(char* dirname)
{
// 功能:改变当前目录到指定的名为dirname的目录。
int i = 0;
int tag = -1;
int fd;
if (openfilelist[currfd].attribute == 1) {
// 如果打开的不是一个目录
printf("您打开的是一个数据文件, 您应该用my_close退出该文件\n");
return;
}
char* buf = (char*)malloc(10000);
openfilelist[currfd].count = 0;
do_read(currfd, openfilelist[currfd].length, buf);
fcb* fcbptr = (fcb*)buf;
// 遍历当前所有fcb,查找目标fcb
for (i = 0; i < (int)(openfilelist[currfd].length / sizeof(fcb)); i++, fcbptr++) {
if (strcmp(fcbptr->filename, dirname) == 0 && fcbptr->attribute == 0) {
tag = 1;
break;
}
}
// tag不为1,当前目录无下无查询目录
if (tag != 1) {
printf("my_cd: 没有这个目录\n");
return;
} else {
// . 和 .. 检查
// ..则返回上一级目录
if (strcmp(fcbptr->filename, ".") == 0) {
return;
} else if (strcmp(fcbptr->filename, "..") == 0) {
if (currfd == 0) {
// root
return;
} else {
currfd = my_close(currfd);
return;
}
} else {
// 其他目录
fd = get_free_openfilelist();
if (fd == -1) {
return;
}
// 修改当前目录指针
openfilelist[fd].attribute = fcbptr->attribute;
openfilelist[fd].count = 0;
openfilelist[fd].date = fcbptr->date;
openfilelist[fd].time = fcbptr->time;
strcpy(openfilelist[fd].filename, fcbptr->filename);
strcpy(openfilelist[fd].exname, fcbptr->exname);
openfilelist[fd].first = fcbptr->first;
openfilelist[fd].free = fcbptr->free;
openfilelist[fd].fcbstate = 0;
openfilelist[fd].length = fcbptr->length;
strcat(strcat(strcpy((char*)(openfilelist[fd].dir), (char*)(openfilelist[currfd].dir)), dirname), "/");
openfilelist[fd].topenfile = 1;
openfilelist[fd].dirno = openfilelist[currfd].first;
openfilelist[fd].diroff = i;
currfd = fd;
}
}
}
//-------------------关闭文件----------------------------
int my_close(int fd)
{
// 功能:关闭当前目录下名为filename的文件。
//首先判断文件是否在经过改写后符合文件标准
if (fd > MAXOPENFILE || fd < 0) {
printf("my_close: 文件错误\n");
return -1;
}
//此处不需要判断和输入文件名信息“buf”,因为用户已经介于文件当中
int i;
char buf[MAX_TEXT_SIZE];
int father_fd = -1;
fcb* fcbptr;
//文件是否存在父目录
for (i = 0; i < MAXOPENFILE; i++) {
if (openfilelist[i].first == openfilelist[fd].dirno) {
father_fd = i;
break;
}
}
if (father_fd == -1) {
printf("my_close:无法退出,没有父目录\n");
return -1;
}
//判断文件系统是否在open之后被修改,如果被修改则fcbstate == 1
//此时更新fcb链表信息
//既更新到父目录上的fcb从而实现退出文件
if (openfilelist[fd].fcbstate == 1) {
do_read(father_fd, openfilelist[father_fd].length, buf);
// 更新fcb链表
fcbptr = (fcb*)(buf + sizeof(fcb) * openfilelist[fd].diroff);
strcpy(fcbptr->exname, openfilelist[fd].exname);
strcpy(fcbptr->filename, openfilelist[fd].filename);
fcbptr->first = openfilelist[fd].first;
fcbptr->free = openfilelist[fd].free;
fcbptr->length = openfilelist[fd].length;
fcbptr->time = openfilelist[fd].time;
fcbptr->date = openfilelist[fd].date;
fcbptr->attribute = openfilelist[fd].attribute;
openfilelist[father_fd].count = openfilelist[fd].diroff * sizeof(fcb);
do_write(father_fd, (char*)fcbptr, sizeof(fcb), 2);
}
// 释放打开文件表
memset(&openfilelist[fd], 0, sizeof(useropen));
currfd = father_fd;
return father_fd;
}
//读出指定文件中从读写指针开始的长度为len的内容到用户空间中。
int my_read(int fd,int len)
{
char text[len]; //定义一个字符型数组text[len],用来接收用户从文件中读出的文件内容;
int result; //定义一个整型result,用来返回实际读出的字节数
//检查fd的有效性(fd不能超出用户打开文件表所在数组的最大下标),如果无效则返回-1,并显示出错信息;
if (fd < 0 || fd >= MAXOPENFILE)
{
printf("文件不存在,无法读取!\n");
return -1;
}
openfilelist[fd].count = 0; //将用户打开文件表数组中当前读取文件的读写指针在文件中的位置置为0;
result = do_read(fd, len, text); //调用do_read()将指定文件中的len字节内容读出到text[]中;
printf("%s \n", text);
return result;
}
int my_write(int fd)
{
fat *fat1, *fat2, *fatptr1, *fatptr2;
int wstyle, len, ll, tmp;
char text[MAX_TEXT_SIZE];
unsigned short blkno;
fat1 = (fat *)(myvhard + BLOCKSIZE);
fat2 = (fat *)(myvhard + 3 * BLOCKSIZE);
if(fd < 0 || fd >= MAXOPENFILE)
{
printf("The file is not exist!\n");
return -1;
}
while(1)
{
printf("请选择输入方式:\n1.截断写\t2.覆盖写\t3.追加写\n");
scanf("%d", &wstyle);
if(wstyle > 0 && wstyle < 4)
break;
printf("Input Error!");
}
getchar();
switch(wstyle)
{
case 1://截断写把原文件所占的虚拟磁盘空间重置为1
blkno = openfilelist[fd].first;
fatptr1 = fat1 + blkno;
fatptr2 = fat2 + blkno;
blkno = fatptr1->id;
fatptr1->id = END;
fatptr2->id = END;
while(blkno != END)
{
fatptr1 = fat1 + blkno;
fatptr2 = fat2 + blkno;
blkno = fatptr1->id;
fatptr1->id = FREE;
fatptr2->id = FREE;
}
openfilelist[fd].count = 0;
openfilelist[fd].length = 0;
break;
case 2:
openfilelist[fd].count = 0;
break;
case 3:
openfilelist[fd].count = openfilelist[fd].length;
break;
default:
break;
}
ll = 0;
printf("please input data, line feed + $$ to end file\n");
for(;;)
{
fgets(text,MAX_TEXT_SIZE,stdin);
text[strlen(text) -1] = '\0';
if(!strcmp(text,"$$"))break;
text[strlen(text)]='\n';
if(do_write(fd, text, strlen(text), 2) > 0)
{
len +=strlen(text);
}
else{
return -1;
}
}
return ll;//实际写的字节数
}
int do_read(int fd, int len, char* text)
{
fat *fat1, *fatptr;
unsigned char *buf, *blockptr;
unsigned short blockno, blockoff; //文件逻辑块块号及块内偏移量off
int i;
int realtextnum; //定义一个整型realtextnum,用来接收实际读出的字节数
fat1 = (fat *)(myvhard + BLOCKSIZE); //指向从虚拟磁盘的起始再往后的1024B的地址
buf = (unsigned char *)malloc(BLOCKSIZE);
//使用malloc()申请1024B空间作为缓冲区buf BLOCKSIZE常量定义为1024
//malloc返回值指针buf ,指向已分配的内存空间。如果请求失败,则返回 NULL。
if (buf == NULL) //申请失败则返回-1,并显示出错信息;
{
printf("申请空间失败!\n");
return -1;
}
blockno = openfilelist[fd].first;
blockoff = openfilelist[fd].count;
fatptr = fat1 + blockno;
while (blockoff >= BLOCKSIZE) //blockoff为最后一块盘块剩余的容量
{
blockno = fatptr->id;
blockoff = blockoff - BLOCKSIZE;
fatptr = fat1 + blockno;
}
realtextnum = 0; //赋初值
while (realtextnum < len)
{
blockptr = (unsigned char *)(myvhard + blockno * BLOCKSIZE); //指向最后一块盘块
for (i = 0; i < BLOCKSIZE; i++) //将最后一块盘块的内容读取到buf中
buf[i] = blockptr[i];
for (; blockoff < BLOCKSIZE; blockoff++)
{
text[realtextnum++] = buf[blockoff]; //从blockoff开始的buf中的len长度的内容读入到text[]中
openfilelist[fd].count++; //读写指针往后移,增加已读字节数
if (realtextnum == len || openfilelist[fd].count == openfilelist[fd].length)
//当实际读出的字节等于len且读写指针在文件中的位置等于文件长度时循环结束
break;
}
if (realtextnum < len && openfilelist[fd].count != openfilelist[fd].length)
{
blockno = fatptr->id;
if (blockno == END) //文件结束
break;
blockoff = 0;
fatptr = fat1 + blockno;
}
}
text[realtextnum] = '\0';
free(buf); //使用free()释放申请的buf。
return realtextnum; //返回实际读出的字节数realtextnum
}
int do_write(int fd, char *text, int len, char wstyle)
{
fat *fat1, *fat2, *fatptr1, *fatptr2;
unsigned char *buf, *blkptr;
unsigned short blkno, blkoff;
int i, ll;
fat1 = (fat *)(myvhard + BLOCKSIZE);
fat2 = (fat *)(myvhard + 3 * BLOCKSIZE);
buf = (unsigned char *)malloc(BLOCKSIZE);
if(buf == NULL)
{
printf("malloc failed!\n");
return -1;
}
blkno = openfilelist[fd].first;
blkoff = openfilelist[fd].count;
fatptr1 = fat1 + blkno;
fatptr2 = fat2 + blkno;
while(blkoff >= BLOCKSIZE)
{
blkno = fatptr1->id;
if(blkno == END)
{
//blkno = findblock();
if(blkno == -1)
{
free(buf);
return -1;
}
fatptr1->id = blkno;
fatptr2->id = blkno;
fatptr1 = fat1 + blkno;
fatptr2 = fat2 + blkno;
fatptr1->id = END;
fatptr2->id = END;
}
else
{
fatptr1 = fat1 + blkno;
fatptr2 = fat2 + blkno;
}
blkoff = blkoff - BLOCKSIZE;//让blkoff定位到文件最后一个磁盘块的读写位置
}
ll = 0;//实际写的字节数
while(ll < len)//len是用户输入的字节数
{
blkptr = (unsigned char *)(myvhard + blkno * BLOCKSIZE);
for(i = 0; i < BLOCKSIZE; i++)
buf[i] = blkptr[i];
for(;blkoff < BLOCKSIZE; blkoff++)
{
buf[blkoff] = text[ll++];
openfilelist[fd].count++;
if(ll == len)
break;
}
for(i = 0; i < BLOCKSIZE; i++)
blkptr[i] = buf[i];
if(ll < len)//如果一个磁盘块写不下,则再分配一个磁盘块
{
blkno = fatptr1->id;
if(blkno == END)
{
//blkno = findblock();
if(blkno == -1)
break;
fatptr1->id = blkno;
fatptr2->id = blkno;
fatptr1 = fat1 + blkno;
fatptr2 = fat2 + blkno;
fatptr1->id = END;
fatptr2->id = END;
}
else
{
fatptr1 = fat1 + blkno;
fatptr2 = fat2 + blkno;
}
blkoff = 0;
}
}
if(openfilelist[fd].count > openfilelist[fd].length)
openfilelist[fd].length = openfilelist[fd].count;
openfilelist[fd].fcbstate = 1;
free(buf);
return ll;
}
//获取空闲文件列表
int get_free_openfilelist()
{
int i;
for (i = 0; i < MAXOPENFILE; i++) {
if (openfilelist[i].topenfile == 0) {
openfilelist[i].topenfile = 1;
return i;
}
}
return -1;
}
//获取空闲块
unsigned short int get_free_block()
{
int i;
fat* fat1 = (fat*)(myvhard + BLOCKSIZE);
for (i = 0; i < (int)(SIZE / BLOCKSIZE); i++) {
if (fat1[i].id == FREE) {
return i;
}
}
return END;
}
void my_rmdir(char* dirname)
{
// 输入:dirname:欲删除目录的目录名。
// 功能:在当前目录下删除名为dirname的子目录。
int i, tag = 0;
char buf[MAX_TEXT_SIZE];
// 排除 . 和 .. 目录
if (strcmp(dirname, ".") == 0 || strcmp(dirname, "..") == 0) {
printf("不能移除.和..特殊目录\n");
return;
}
openfilelist[currfd].count = 0;
//调用do_read()读入当前目录文件内容到内存
do_read(currfd, openfilelist[currfd].length, buf);
// 查找要删除的目录
fcb* fcbptr = (fcb*)buf;
for (i = 0; i < (int)(openfilelist[currfd].length / sizeof(fcb)); i++, fcbptr++) {
if (fcbptr->free == 0)
continue;
if (strcmp(fcbptr->filename, dirname) == 0 && fcbptr->attribute == 0) {
tag = 1;
break;
}
}
//检查当前目录下欲删除目录文件是否存在,若不存在则返回,并显示错误信息;
if (tag != 1) {
printf("没有这个目录\n");
return;
}
//检查欲删除目录文件是否为空(除了“.”和“..”外没有其他子目录和文件),可根据其目录项中记录的文件长度来判断,若不为空则返回,并显示错误信息;
if (fcbptr->length > 2 * sizeof(fcb)) {
printf("不能移除一个非空目录\n");
return;
}
// 更新 fat 表
int block_num = fcbptr->first;
fat* fat1 = (fat*)(myvhard + BLOCKSIZE);
int nxt_num = 0;
while (1) {
nxt_num = fat1[block_num].id;
fat1[block_num].id = FREE;
if (nxt_num != END) {
block_num = nxt_num;
}
else {
break;
}
}
fat1 = (fat*)(myvhard + BLOCKSIZE);
fat* fat2 = (fat*)(myvhard + BLOCKSIZE * 3);
memcpy(fat2, fat1, BLOCKSIZE * 2);
// 更新 fcb
fcbptr->date = 0;
fcbptr->time = 0;
fcbptr->exname[0] = '\0';
fcbptr->filename[0] = '\0';
fcbptr->first = 0;
fcbptr->free = 0;
fcbptr->length = 0;
openfilelist[currfd].count = i * sizeof(fcb);
do_write(currfd, (char*)fcbptr, sizeof(fcb), 2);
// 删除目录需要相应考虑可能删除 fcb,也就是修改父目录 length
// 这里需要注意:因为删除中间的 fcb,目录有效长度不变,即 length 不变
// 因此需要考虑特殊情况,即删除最后一个 fcb 时,极有可能之前的 fcb 都是空的,这是需要
// 循环删除 fcb (以下代码完成),可能需要回收 block 修改 fat 表等过程(do_write 完成)
// 回收该目录文件所占据的磁盘块,修改FAT;
int lognum = i;
if ((lognum + 1) * sizeof(fcb) == openfilelist[currfd].length) {
openfilelist[currfd].length -= sizeof(fcb);
lognum--;
fcbptr = (fcb*)buf + lognum;
//free字段置为0
while (fcbptr->free == 0) {
fcbptr--;
openfilelist[currfd].length -= sizeof(fcb);
}
}
// 更新父目录 fcb
fcbptr = (fcb*)buf;
fcbptr->length = openfilelist[currfd].length;
openfilelist[currfd].count = 0;
//调用do_write覆写
do_write(currfd, (char*)fcbptr, sizeof(fcb), 2);
//将表项中的fcbstate置为1
openfilelist[currfd].length = openfilelist[currfd].length - 1;
openfilelist[currfd].fcbstate = 1;
}
int main(void)
{
char cmd[12][15] = {
"my_format", "my_mkdir", "my_rmdir", "my_ls", "my_cd", "my_create",
"my_rm", "my_open", "my_close", "my_write", "my_read",
"my_exitsys"
};
char command[30], *sp;
int cmd_idx, i;
int fd; //从open函数中返回的文件描述符
printf("请输入要使用的文件系统名称:");
fgets(s, 10, stdin);
FILENAME = s;
printf("使用的文件系统名称为:%s",FILENAME);
//printf(FILENAME);
printf("\n");
printf("************* file system ***************\n");
startsys();
printf("文件系统提供的各项功能及命令调用格式:\n");
printf("命令名 \t 命令参数 \t 命令说明 \t 调用格式\n");
printf("my_format \t 无 \t 磁盘格式化 \t my_format\n");
printf("my_mkdir \t 目录名 \t 创建子目录 \t my_mkdir dirname\n");
printf("my_rmdir \t 目录名 \t 删除子目录 \t my_rmdir dirname\n");
printf("my_ls \t 无 \t 显示目录 \t my_ls\n");
printf("my_cd \t 目录名(路径名) \t 更改当前目录 \t my_cd dirname\n");
printf("my_create \t 文件名 \t 创建文件 \t my_create filename\n");
printf("my_rm \t 文件名 \t 删除文件 \t my_rm filename\n");
printf("my_open \t 文件名 \t 打开文件 \t my_open filename\n");
printf("my_close \t 文件描述符 \t 关闭文件 \t my_close fd\n");
printf("my_write \t 文件描述符 \t 写文件 \t my_write fd\n");
printf("my_read \t 文件的描述符、字节数 读文件 \t my_read fd size\n");
printf("my_exitsys \t 无 \t 退出文件系统 \t my_exitsys\n");
while (1) {
printf("%s> ", openfilelist[currfd].dir);
//printf(openfilelist[currfd].dir);
//printf(">");
//fgets(command, 30, stdin);
gets(command);
cmd_idx = -1;
if (strcmp(command, "") == 0) {
printf("\n");
continue;
}
sp = strtok(command, " ");
for (i = 0; i < 12; i++) {
if (strcmp(sp, cmd[i]) == 0) {
cmd_idx = i;
break;
}
}
switch (cmd_idx) {
case 0: //format
my_format();
break;
case 1: // mkdir
sp = strtok(NULL, " ");
if (sp != NULL)
my_mkdir(sp);
else
printf("mkdir error\n");
break;
case 2: // rmdir
sp = strtok(NULL, " ");
if (sp != NULL)
my_rmdir(sp);
else
printf("rmdir error\n");
break;
case 3: // ls
my_ls();
break;
case 4: // cd
sp = strtok(NULL, " ");
if (sp != NULL)
my_cd(sp);
else
printf("cd error\n");
break;
case 5: // create
sp = strtok(NULL, " ");
if (sp != NULL)
my_create(sp);
else
printf("create error\n");
break;
case 6: // rm
sp = strtok(NULL, " ");
if (sp != NULL)
my_rm(sp);
else
printf("rm error\n");
break;
case 7: // open
sp = strtok(NULL, " ");
if (sp != NULL)
{
fd=my_open(sp);
if (fd != -1)
{
printf("文件打开成功!是打开文件表中的%d号\n",fd);
}
}
else{
printf("open error\n");
}
break;
case 8: // close
if (openfilelist[currfd].attribute == 1)
my_close(currfd);
else
printf("there is not openning file\n");
break;
case 9: // write
if (openfilelist[currfd].attribute == 1)
my_write(currfd);
else
printf("please open file first, then write\n");
break;
case 10: // read
if (openfilelist[currfd].attribute == 1)
{
int len;
printf("请输入要读入内容的长度:");
scanf("%d", &len);
int result;
result = my_read(currfd,len);
printf("实际读出的字节数为%d\n",result);
}
else
printf("please open file first, then read\n");
break;
case 11: // exit
my_exitsys();
printf("**************** exit file system ****************\n");
return 0;
break;
default:
printf("wrong command: %s\n", command);
break;
}
}
return 0;
}
ds.h代码如下
#ifndef DS_H
#define DS_H
//导入头文件
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
//常量定义
#define BLOCKSIZE 1024
#define SIZE 1024000
#define END 65535
#define FREE 0
#define ROOTBLOCKNUM 2
#define MAXOPENFILE 10 // 同时打开最大文件数
#define MAX_TEXT_SIZE 10000
typedef struct FCB //仿照FAT16设置的
{
char filename[8]; //文件名
char exname[3];//文件扩展名
unsigned char attribute;//文件属性字段:为简单起见,我们只为文件设置了两种属性:值为0时表示目录文件,值为1时表示数据文件
unsigned short time;//文件创建时间
unsigned short date;//文件创建日期
unsigned short first;//文件起始盘块号
unsigned long length;//文件长度(字节数)
char free;//表示目录项是否为空,若值为0,表示空,值为1,表示已分配
}fcb;
typedef struct FAT
{
unsigned short id;
}fat;
typedef struct USEROPEN
{
char filename[8]; //文件名
char exname[3];//文件扩展名
unsigned char attribute;//文件属性:值为0时表示目录文件,值为1时表示数据文件
unsigned short time;//文件创建时间
unsigned short date;//文件创建日期
unsigned short first;//文件起始盘块号
unsigned long length;//文件长度(对数据文件是字节数,对目录文件可以是目录项个数)
char free; //表示目录项是否为空,若值为0,表示空,值为1,表示已分配
//前面内容是文件的FCB中的内容。
// 下面设置的dirno和diroff记录了相应打开文件的目录项在父目录文件中的位置,
//这样如果该文件的fcb被修改了,则要写回父目录文件时比较方便
int dirno;//相应打开文件的目录项在父目录文件中的盘块号
int diroff;// 相应打开文件的目录项在父目录文件的dirno盘块中的目录项序号
char dir[MAXOPENFILE][80];//相应打开文件所在的目录名,这样方便快速检查出指定文件是否已经打开
int count;//读写指针在文件中的位置
char fcbstate;//是否修改了文件的FCB的内容,如果修改了置为1,否则为0
char topenfile;//表示该用户打开表项是否为空,若值为0,表示为空,否则表示已被某打开文件占据
}useropen;
typedef struct BLOCK0 //引导块内容
{ //魔数 magic number 是计算机(或者说是BIOS)用来判断此设备是否包含引导程序的。
//设备一般包括软盘、硬盘、U盘等等。魔数一般在设备的第一个扇区的最后两个字节,十六进制的魔数为 0x55aa,而且一个扇区为 512 字节
//这里系统引用魔数
char magic_number[8];
//存储一些描述信息,如磁盘块大小、磁盘块数量、最多打开文件数等、
char information[200];
unsigned short root;//根目录文件的起始盘块号
unsigned char *startblock; //虚拟磁盘上数据区开始位置
}block0;
//全局变量定义
unsigned char *myvhard; //指向虚拟磁盘的起始地址
useropen openfilelist[MAXOPENFILE]; //用户打开文件表数组
useropen *ptrcurdir; //指向用户打开文件表中的当前目录所在打开文件表项的位置
char currentdir[80]; //记录当前目录的目录名(包括目录的路径)
unsigned char* startp; //记录虚拟磁盘上数据区开始位置
//以下为自定义新增
// buffer为指向存储块的指针
unsigned char buffer[SIZE];
// currfd为当前文件
int currfd;
/* 函数定义 */
void startsys();
void my_format();
void my_cd(char* dirname);
int do_read(int fd, int len, char* text);
int do_write(int fd, char* text, int len, char wstyle);
int my_read(int fd,int len);
int my_write(int fd);
void my_exitsys();
void my_cd(char* dirname);
int my_open(char* filename);
int my_close(int fd);
void my_mkdir(char* dirname);
void rmdir(char* dirname);
int my_create(char* filename);
void my_rm(char* filename);
void my_ls();
int get_free_openfilelist();
unsigned short int get_free_block();
#endif
fgets方法会把'\n'也存进去,我在windows上debug,如图所示(后面还有一些‘G’,'P'暂时不用管)
虽然用了strtok,但并没有把‘\n’去掉,所以比较fgets得到的命令总是大于字符数组存的命令,那就永远走default分支,输出command error
可以先得到字符数组存放命令的长度,然后根据这个长度,从fgets得到的命令字符串中截取出你想要的命令