# 今天是六一兒童節(jié)
# 下周一就要開始課設(shè)了
# 爭(zhēng)取在第一天給老師檢查吧
# 之后一個(gè)禮拜就可以好好復(fù)習(xí)算法設(shè)計(jì)的期末考試了
# 病了兩天真是難受
# 兩天沒有好好學(xué)習(xí) QWQ
Part 0 前言
整個(gè)程序是在Mac os的環(huán)境下開發(fā)的海蔽,因?yàn)橛幸恍┑讓酉到y(tǒng)調(diào)洪乍,Windows可能無(wú)法正常運(yùn)行庆亡,不過Linux應(yīng)該問題不大。
首先我是很想拿這個(gè)課設(shè)的滿分的录煤,仔細(xì)看了課設(shè)的要求鳄厌,如果要拿到滿分的話,需要有完整的文件系統(tǒng)妈踊,還要做到“命令端”和“文件系統(tǒng)端”的獨(dú)立運(yùn)行了嚎、相互通信。這個(gè)真的是比算法設(shè)計(jì)的課設(shè)工作量大多了(算法課設(shè)我就寫了百來行的代碼廊营,這個(gè)估摸著得上千了)歪泳。
講實(shí)話多進(jìn)程的東西寫的并不多,有寫露筒,但是也沒有太多的研究這個(gè)呐伞,所以這次課設(shè)對(duì)我來說難點(diǎn)就在于進(jìn)程間的通信了。也百度了一下Unix/Linux下的進(jìn)程通信的東西慎式,要實(shí)現(xiàn)的話基本就是用FIFO伶氢、消息隊(duì)列來實(shí)現(xiàn)趟径。
Part 1 架構(gòu)
架構(gòu)就如上圖吧,F(xiàn)ileSystem以讀寫的方式連接disk.dat(模擬的物理磁盤)癣防,再以IPC的方式連接各個(gè)Shell(命令端)蜗巧,當(dāng)然這里還有很多細(xì)節(jié)就先不討論了。
Part 2 文件系統(tǒng)的核心代碼
這里先上一個(gè)FileSystem的實(shí)現(xiàn)代碼(還沒Debug)蕾盯,共413行幕屹。
FileSys.h
(6.2號(hào)更新,補(bǔ)了一些注釋级遭,修復(fù)了一些“肉眼可見”的Bug望拖,因?yàn)檎麄€(gè)文件系統(tǒng)還未真正運(yùn)行過。)
#ifndef FileSys_h
#define FileSys_h
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define DISK_MEMO 10 * 1024 * 1024 // 磁盤總空間
#define DISK_SIZE 1024 // 每個(gè)磁盤塊的大小
#define DISK_NUM DISK_MEMO / DISK_SIZE // 磁盤塊的數(shù)目
#define FAT_SIZE DISK_NUM * sizeof(fatitem) // FAT表的大小
#define ROOT_DISK_NO FAT_SIZE / DISK_SIZE + 1 // 根目錄起始盤塊號(hào)
#define ROOT_DISK_SIZE sizeof(direct) // 目錄大小
#define DIR_MAXSIZE 1024 // 路徑最大長(zhǎng)度
#define MSD 5 // 目錄最大子文件數(shù)量
#define MOFN 20 // 最大打開文件
#define MAX_WRITE 1024 * 128 // 最大寫入文字長(zhǎng)度
#define FILENAME_MAXLEN 64 // 最長(zhǎng)文件名稱長(zhǎng)度
typedef struct
{
int item; // 下一個(gè)磁盤的指針
char em_disk; // 是否空閑(‘0’為空閑装畅,‘1’為非空閑)
} fatitem;
// FCB結(jié)構(gòu)體
typedef struct
{
char name[FILENAME_MAXLEN]; // 名字
char property; // 屬性(‘1’是目錄靠娱,‘0’是文件)
int size; // 文件/目錄 字節(jié)數(shù)
int firstdisk; // 文件/目錄 起始盤塊號(hào)
int next; // 子目錄起始盤塊號(hào)
int sign; // 根目錄識(shí)別符(1為根目錄標(biāo)識(shí)沧烈,0為非根目錄標(biāo)識(shí))
} FCB;
typedef struct
{
FCB directitem[MSD + 2];
} direct;
// 打開文件表 實(shí)例結(jié)構(gòu)體
struct opentableitem
{
char name[9]; // 文件名稱
int firstdisk; // 文件起始盤塊號(hào)
int size; // 文件大小
};
// 打開文件 結(jié)構(gòu)體
typedef struct
{
struct opentableitem openitem[MOFN];
int cur_size; // 當(dāng)前打開文件的數(shù)目
} opentable;
fatitem *fat; // FAT表
direct *root; // 根目錄地址
direct *cur_dir; // 當(dāng)前目錄
opentable u_opentable; // 文件打開表
int fd = -1; // 文件打開表的序號(hào)
char *bufferdir; // 記錄當(dāng)前路徑的名稱
char *fdisk; // 虛擬磁盤起始地址(內(nèi)存中)
// FAT表數(shù)據(jù)設(shè)定函數(shù)
void fatitemset(fatitem *, int, char);
// FCB數(shù)據(jù)設(shè)定函數(shù)
void FCBset(FCB *, int, int, char *, int, char, int);
// 文件初始化掠兄,生成空的模擬磁盤物理文件(當(dāng)沒有disk.dat文件時(shí)執(zhí)行)
void initfile();
// 模擬磁盤數(shù)據(jù)初始化
void format();
// 進(jìn)入物理磁盤文件
void enter();
// 退出程序,保存物理文件
void halt();
// 新建文件
int create(char *);
// 打開文件
int open(char *);
// 關(guān)閉文件
int close(char *);
// 文件寫入
int write(int, char *, int);
// 文件讀取
int read(int, char *);
// 文件刪除
int del(char *);
// 新建文件夾
int mkdir(char *);
// 刪除文件夾
int rmdir(char *);
void initfile()
{
fdisk = (char *)malloc(DISK_MEMO * sizeof(char));
format();
}
void fatitemset(fatitem *f, int i, char e)
{
f->item = I;
f->em_disk = e;
}
void FCBset(FCB *fcb, int sign, int firstdisk, char *name, int next, char property, int size)
{
fcb->sign = sign;
fcb->firstdisk = firstdisk;
strcpy(fcb->name, name);
fcb->next = next;
fcb->property = property;
fcb->size = size;
}
void format()
{
int I;
FILE *fp;
// FAT初始化
// FAT的初始地址是disk的地址往后移 1K
fat = (fatitem *)(fdisk + DISK_SIZE);
fatitemset(&fat[0], -1, '1'); // 引導(dǎo)塊初始化
// 1-ROOT全部置為1
for (i = 1; i < ROOT_DISK_NO - 1; I++)
fatitemset(&fat[i], i + 1, '1');
fatitemset(&fat[ROOT_DISK_NO], -1, '0');
for (i = ROOT_DISK_NO + 1; i < DISK_NUM - 1; I++)
fatitemset(&fat[i], -1, '0');
root = (direct *)(fdisk + DISK_SIZE + FAT_SIZE);
FCBset(&root->directitem[0], 1, ROOT_DISK_NO, ".", ROOT_DISK_NO, '1', ROOT_DISK_SIZE);
FCBset(&root->directitem[1], 1, ROOT_DISK_NO, "..", ROOT_DISK_NO, '1', ROOT_DISK_SIZE);
for (i = 2; i < MSD + 2; I++)
FCBset(&root->directitem[i], 0, -1, "", -1, '0', 0);
if ((fp = fopen("./disk.dat", "wb")) == NULL)
{
printf("Error: Can't open disk.");
return;
}
if ((fwrite(fdisk, DISK_MEMO, 1, fp)) != 1)
printf("Error: Disk write error!");
fclose(fp);
};
void enter()
{
FILE *fp;
int I;
fdisk = (char *)malloc(DISK_MEMO * sizeof(char));
if ((fp = fopen("./disk.dat", "rb")) == NULL)
{
printf("Error: Can't open disk.");
return;
}
if (!fread(fdisk, DISK_MEMO, 1, fp))
{
printf("Error: Can't open disk.");
exit(0);
}
fat = (fatitem *)(fdisk + DISK_SIZE);
root = (direct *)(fdisk + DISK_SIZE + FAT_SIZE);
fclose(fp);
for (i = 0; i < MOFN; I++)
{
strcpy(u_opentable.openitem[i].name, "");
u_opentable.openitem[i].firstdisk = -1;
u_opentable.openitem[i].size = 0;
}
u_opentable.cur_size = 0;
cur_dir = root;
// bufferdir = (char *)malloc(DIR_MAXSIZE * sizeof(char));
// strcpy(bufferdir, "Root:");
}
void halt()
{
FILE *fp;
int I;
if ((fp = fopen("./disk.dat", "wb")) == NULL)
{
printf("Error: Can't open disk.");
return;
}
if ((fwrite(fdisk, DISK_MEMO, 1, fp)) != 1)
printf("Error: Disk write error!");
fclose(fp);
free(fdisk);
free(bufferdir);
return;
}
int create(char *name)
{
int i, j;
if (strlen(name) > FILENAME_MAXLEN)
return -1;
for (j = 2; j < MSD + 2; j++)
if (!strcmp(cur_dir->directitem[j].name, name))
return -4;
for (i = 2; i < MSD + 2; I++)
if (cur_dir->directitem[i].firstdisk == -1)
break;
if (i > MSD + 2)
return -2;
if (u_opentable.cur_size >= MOFN)
return -3;
for (j = ROOT_DISK_NO + 1; j < DISK_NUM; j++)
if (fat[j].em_disk == '0')
break;
if (j >= DISK_NUM)
return -5;
fat[j].em_disk = '1';
FCBset(&cur_dir->directitem[i], 0, j, name, j, '0', 0);
fd = open(name);
return 0;
}
int open(char *name)
{
int i, j;
for (i = 2; i < MSD + 2; I++)
if (strcmp(cur_dir->directitem[i].name, name))
break;
if (i >= MSD + 2)
return -1;
if (cur_dir->directitem[i].property == '1')
return -4;
for (j = 0; j < MOFN; j++)
if (!strcmp(u_opentable.openitem[j].name, name))
break;
if (j < MOFN)
return -2;
if (u_opentable.cur_size >= MOFN)
return -3;
for (j = 0; j < MOFN; j++)
if (u_opentable.openitem[j].firstdisk == -1)
break;
u_opentable.openitem[j].firstdisk = cur_dir->directitem[i].firstdisk;
strcpy(u_opentable.openitem[j].name, name);
u_opentable.openitem[j].size = cur_dir->directitem[i].size;
u_opentable.cur_size++;
return j;
}
int close(char *name)
{
int I;
for (i = 0; i < MOFN; I++)
if (!strcmp(u_opentable.openitem[i].name, name))
break;
if (i >= MOFN)
return -1;
u_opentable.openitem[i].firstdisk = -1;
u_opentable.openitem[i].size = 0;
strcpy(u_opentable.openitem[i].name, "");
u_opentable.cur_size--;
return 0;
}
int write(int fd, char *buf, int len)
{
char *first;
int item, i, j, k;
int ilen1, ilen2, modlen, temp;
item = u_opentable.openitem[fd].firstdisk;
for (i = 2; i < MSD + 2; I++)
if (cur_dir->directitem[i].firstdisk == item)
break;
temp = I;
while (fat[item].item != -1)
item = fat[item].item;
// 找到文件的末地址
first = fdisk + item * DISK_SIZE + u_opentable.openitem[fd].size % DISK_SIZE;
if (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE > len)
{
// 最后一塊磁盤剩余的大小大于要寫入的大小
strcpy(first, buf);
u_opentable.openitem[fd].size += len;
cur_dir->directitem[temp].size += len;
}
else
{
for (i = 0; i < (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE); I++)
first[i] = buf[I];
// 剩余長(zhǎng)度
ilen1 = len - (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE);
// 需要新磁盤塊
ilen2 = (ilen1 - 1) / DISK_SIZE + 1;
// 最后一塊磁盤的長(zhǎng)度
modlen = ilen1 % DISK_SIZE;
for (j = 0; j < ilen2; j++)
{
for (i = ROOT_DISK_NO + 1; i < DISK_NUM; I++)
if (fat[i].em_disk == '0')
break;
if (i >= DISK_NUM)
return -1;
first = fdisk + i * DISK_SIZE;
if (j == ilen2 - 1)
for (k = 0; k < len - (DISK_SIZE - u_opentable.openitem[fd].size % DISK_SIZE - j * DISK_SIZE); k++)
first[k] = buf[k];
else
for (k = 0; k < DISK_SIZE; k++)
//這里的k是不是有問題锌雀?蚂夕?
first[k] = buf[k];
//這里的item是不是也有問題?腋逆?
fat[item].item = I;
fat[i].em_disk = '1';
fat[i].item = -1;
}
u_opentable.openitem[fd].size += len;
cur_dir->directitem[temp].size += len;
}
return 0;
}
int read(int fd, char *buf)
{
int len = u_opentable.openitem[fd].size;
char *first;
int i, j, item;
int ilen1, modlen;
item = u_opentable.openitem[fd].firstdisk;
ilen1 = (len - 1) / DISK_SIZE + 1;
modlen = len % DISK_SIZE;
first = fdisk + item * DISK_SIZE;
for (i = 0; i < ilen1; i++)
{
if (i == ilen1 - 1)
for (j = 0; j < len - i * DISK_SIZE; j++)
buf[i * DISK_SIZE + j] = first[j];
else
{
for (j = 0; j < len - i * DISK_SIZE; j++)
buf[i * DISK_SIZE + j] = first[j];
item = fat[item].item;
first = fdisk + item * DISK_SIZE;
}
}
return 0;
}
int del(char *name)
{
int i, cur_item, item, temp;
for (i = 2; i < MSD + 2; I++)
if (!strcmp(cur_dir->directitem[i].name, name))
break;
if (i >= MSD + 2)
return -1;
cur_item = I;
if (cur_dir->directitem[cur_item].property != '0')
return -3;
for (i = 0; i < MOFN; I++)
if (!strcmp(u_opentable.openitem[i].name, name))
return -2;
item = cur_dir->directitem[cur_item].firstdisk;
while (item != -1)
{
temp = fat[item].item;
fat[item].item = -1;
fat[item].em_disk = '0';
item = temp;
}
FCBset(&cur_dir->directitem[cur_item], 0, -1, "", -1, '0', 0);
return 0;
}
int mkdir(char *name)
{
int i, j;
direct *cur_mkdir;
if (!strcmp(name, ".") || !strcmp(name, ".."))
return -4;
if (strlen(name) > FILENAME_MAX)
return -1;
for (j = 2; j < MSD + 2; j++)
if (!strcmp(cur_dir->directitem[j].name, name))
break;
if (j < MSD + 2)
return -3;
for (j = ROOT_DISK_NO + 1; j < DISK_NUM; j++)
if (fat[j].em_disk == '0')
break;
if (j > DISK_NUM)
return -5;
fat[j].em_disk = '1';
FCBset(&cur_dir->directitem[i], 0, j, name, j, '1', ROOT_DISK_SIZE);
cur_mkdir = (direct *)(fdisk + cur_dir->directitem[i].firstdisk * DISK_SIZE);
FCBset(&cur_mkdir->directitem[0], 0, cur_dir->directitem[i].firstdisk, ".", cur_mkdir->directitem[0].firstdisk, '1', ROOT_DISK_SIZE);
FCBset(&cur_mkdir->directitem[0], cur_dir->directitem[0].sign, cur_dir->directitem[0].firstdisk, "..", cur_mkdir->directitem[1].firstdisk, '1', ROOT_DISK_SIZE);
for (i = 2; i < MSD + 2; I++)
FCBset(&cur_mkdir->directitem[i], 0, -1, "", -1, '0', 0);
return 0;
}
int rmdir(char *name)
{
int i, j, item;
direct *temp_dir;
for (i = 2; i < MSD + 2; I++)
if (!strcmp(cur_dir->directitem[i].name, name))
break;
if (i >= MSD + 2)
return -1;
if (cur_dir->directitem[i].property != '1')
return -3;
temp_dir = (direct *)(fdisk + cur_dir->directitem[i].next * DISK_SIZE);
for (j = 2; j < MSD + 2; j++)
// 文件夾不為空
if (temp_dir->directitem[j].next != -1)
break;
if (j < MSD + 2)
return -2;
item = cur_dir->directitem[i].firstdisk;
fat[item].em_disk = '0';
FCBset(&cur_dir->directitem[i], 0, -1, "", -1, '0', 0);
return 0;
}
#endif
一更(6/2上午10:08)更新一下6.1號(hào)所有的工作量
先這么寫著婿牍,等課設(shè)做完再把整篇文章的格式規(guī)范一下。
Part 3 “前后端”通信
截至目前已經(jīng)寫了1,446行代碼了惩歉,但是感覺還只是完成了一個(gè)空架(真是好大的工作量啊??)等脂。重要的是,著1,446行代碼中已經(jīng)實(shí)現(xiàn)了用IPC協(xié)議(消息列隊(duì))實(shí)現(xiàn)進(jìn)程通信撑蚌。為什么不用命名管道(FIFO)呢上遥,主要是FIFO在處理一對(duì)多要這種情況時(shí),要使用這種結(jié)構(gòu):
這樣子的話争涌,假設(shè)有N個(gè)命令端的話粉楚,我們則需要建立 2+N 條FIFO,雖然說課設(shè)并不需要考慮這種極端情況亮垫,但是強(qiáng)迫癥的我(???♂?)還是覺得這種做法不是很好模软,因?yàn)镕IFO多次創(chuàng)建、釋放容易出問題饮潦。
于是燃异,我打算用F2S(file_system to shell)、S2F(shell to file system)來實(shí)現(xiàn)命令端和文件管理端的通信(理論上其實(shí)一個(gè)消息隊(duì)列也可以實(shí)現(xiàn))继蜡。
自定義的Message結(jié)構(gòu)體
struct s2fmsg
{
long int mtype;
int serverid;
int oper;
char data[128];
};
struct f2smsg
{
long int mtype;
int oper;
int status;
char data[128];
};
命令端用S2F隊(duì)列向文件系統(tǒng)端發(fā)送請(qǐng)求特铝,文件系統(tǒng)用F2S向命令端發(fā)送請(qǐng)求結(jié)果(像極了request暑中,原諒我的淺薄理解)。乍一看鲫剿,和FIFO很像鳄逾,那它是怎么實(shí)現(xiàn)只用兩條隊(duì)列呢?這里是因?yàn)橄㈥?duì)列比FIFO多了一個(gè)關(guān)鍵性的功能灵莲,就是消息隊(duì)列傳輸?shù)南⒂幸粋€(gè) long int mtype
的屬性雕凹,而命令端在接收文件系統(tǒng)端的回傳信息的時(shí)候,可以根據(jù)這個(gè)long int mtype
來選擇接收mtype
等于特定值的消息政冻∶兜郑基于這個(gè),我們就可以給 f2smsg
的mtype
附加命令端的id明场。
(要繼續(xù)寫課設(shè)了汽摹,爭(zhēng)取明天前做好)
持續(xù)更新中……
最后一次更新于6/1上午10:36