操做系统 - 课程设计

操做系统 课程设计

Linux内核编译及添加系统调用

先安装ccache能够大幅节省屡次内核编译时间linux

  • 进入内核目录
  • 分配系统调用号,修改系统调用表
vim ./arch/x86/entry/syscalls/syscall_64.tbl

尾部添加 ([549]为最后一个系统调用号+1)
549     64      mysetnice               sys_mysetnice
  • 申明系统调用服务例程原型
vim ./include/linux/syscalls.h

asmlinkage long sys_mysetnice(pid_t pid,int flag,int nicevalue); //,void __user* prio,void __user* nice);
  • 实现系统调用服务例程
vim ./kernel/sys.c

SYSCALL_DEFINE3(mysetnice, pid_t, pid, int, flag, int, nicevalue)
{
    struct pid * kpid;
    struct task_struct * task;
    int nicebef;
    kpid = find_get_pid(pid);/* 返回pid */
    task = pid_task(kpid, PIDTYPE_PID);/* 返回task_struct */
    nicebef = task_nice(task);/* 返回进程当前nice值 */
    if(flag == 1)
    {
        set_user_nice(task, nicevalue);/* 修改进程nice值 */
        printk("修改前nice值:%d\t修改后nice值:%d\n", nicebef, nicevalue);
        return 0;
    }
    else if(flag == 0)
    {
        printk("该进程的nice值为%d\n", nicebef);
        return 0;
    }
    return EFAULT;
}
  • 从新编译内核
make oldconfig
make
make modules
make modules_install
make install
grub2-mkconfig -o /boot/grub2/grub.cfg  //centos
update-grub2  //ubuntu
reboot
  • 编写用户态程序测试新系统调用 [define的常量修改]
#include <linux/unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>
#define __NR_mysetnice 549

int main(int argc, char *argv[])
{
     pid_t tid;
     int nicevalue = atoi(argv[1]);
     tid = getpid();
     syscall(__NR_mysetnice,tid,0,0);
     syscall(__NR_mysetnice,tid,1,nicevalue);
     syscall(__NR_mysetnice,tid,0,0);

     //syscall(__NR_mysetnice,tid,flag,nicevalue);
     return 0;
}
  • 查看输出内容
dmesg

Linux内核模块编程

Makefile的KDIR须要修改成内核目录 Makefile 和 OS-2-x.c在同一文件夹内便可 执行make编译web

1

  • Makefile
obj-m:=OS-2-1.o
OS21-objs:=OS-2-1.o
KDIR:=/home/kannaduki/linux/linux-4.15.15
PWD:= $(shell pwd)
default:
	make -C $(KDIR) M=$(PWD) modules
clean:
	make -C $(KDIR) M=$(PWD) clean
  • OS-2-1.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
// 内核版本为3.X 则为<linux/sched.h>
#include<linux/sched/signal.h>
static int hello_init(void)
{
    struct task_struct *p= &init_task;
	printk(KERN_ALERT"\n\n\n----------------------");
	printk(KERN_ALERT"------全部进程程序名 pid 进程状态 父进程------");
    for_each_process(p) {
        if(p->mm == NULL)
		    printk(KERN_ALERT"程序名: %s Pid: %d 进程状态: %ld 父进程pid: %d\n",p->comm,p->pid, p->state,p->real_parent->pid);
        }
	    printk(KERN_ALERT"----------------------\n\n\n");
        return 0;
}
static void hello_exit(void)
{
        printk(KERN_ALERT "______Exit______ !\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

2

  • Makefile
obj-m:=OS-2-2.o
OS22-objs:=OS-2-2.o
KDIR:=/home/kannaduki/linux/linux-4.15.15
PWD:= $(shell pwd)
default:
	make -C $(KDIR) M=$(PWD) modules
clean:
	make -C $(KDIR) M=$(PWD) clean
  • family.c
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/pid.h>
// 内核版本为3.X 则为<linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/moduleparam.h>

static pid_t pid=0;
module_param(pid,int,0644);

static int family_init(void)
{
	struct task_struct *p;
	struct list_head *pp;
	struct task_struct *pl;
        if(pid == 0) {
                printk("输入错误\n");
		return 0;
        }
	p = pid_task(find_vpid(pid), PIDTYPE_PID);
	if(!p) {
		printk("\n\n\n------进程不存在----\n\n\n");
		return 0;
	}
	printk("\n\n\n\n\n\n\n\n\n");
	printk("-----进程号------\n");
	printk("%d\n",pid);
	printk("-----父进程------\n");
	if(p->parent==NULL)
	{
		printk("父进程不存在\n");
	}
        else
	{
		printk("pid: %d 程序名:%s 进程状态: %ld\n",p->parent->pid,p->parent->comm,p->parent->state);
	}
	printk("------兄弟进程-------\n");
	list_for_each(pp,&p->parent->children)
	{
		pl=list_entry(pp,struct task_struct,sibling);
		printk("pid: %d 程序名: %s 进程状态: %ld\n",pl->pid,pl->comm,pl->state);
	}
	printk("---------子进程--------\n");
	if(&p->children==NULL) printk("子进程不存在");
	list_for_each(pp,&p->children)
	{
		pl=list_entry(pp,struct task_struct,sibling);
		printk("pid: %d 程序名: %s 进程状态: %ld\n",pl->pid,pl->comm,pl->state);
	}
	printk("-----------------------\n\n\n\n\n\n");
        return 0;
}
static void family_exit(void)
{
        printk(KERN_ALERT "\n--------Exit---------\n");
}

module_init(family_init);
module_exit(family_exit);
MODULE_LICENSE("GPL");

Linux 进程管理

1. 模拟的shell

  • cmd一、cm二、cmd3.c
#include<stdio.h>
void  main() {
	printf("cmd1运行完毕\n");
}

gcc cmd1.c -o cmd1 (cmd2 cmd3 同理)shell

  • shell.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
void  main() {
	int pid;
	int i;
	char *cmd = (char*)malloc(sizeof(20));
	while(1) {
		printf("输入指令\n");
		scanf("%s",cmd);
                if(strcmp(cmd,"exit")==0)       return;
		pid=vfork();
		if (pid) {
			waitpid(pid,NULL,0);
		}else{
			if(strcmp(cmd,"cmd1")==0 || strcmp(cmd,"cmd2")==0 || strcmp(cmd,"cmd3")==0){
				execl(cmd,cmd,NULL);
			}else{
				printf("Command not found\n");
				_exit(0);
			}
		}
	}
}

gcc shell.c编程

2. 管道通讯、Posix信号量

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <semaphore.h>
#include <string.h>

int main()
{
	int filedes[2];
	pid_t child1;
	pid_t child2;
	pid_t child3;
	char b_read[100]={0};
	int num;
	sem_t sem;
	sem_init(&sem,1,1);
	//int pipe(int filedes[2])
	if(pipe(filedes)<0)
		exit(-1);
	else {
		//close(filedes[0]);
		//close(filedes[1]);
	}
	
	//filedes[0]读 filedes[1]写
	pid_t p1 = fork();
	if(p1==0) {
		sem_wait(&sem);
		close(filedes[0]);
                open(filedes[1]);
                write(filedes[1],"1111",4);
                printf("child1 写入 写入值为1111\n\n");
                close(filedes[1]);
                sem_post(&sem);
                exit(0);
	}
	pid_t p2 = fork();
	if(p2==0) {
		sem_wait(&sem);
                close(filedes[0]);
                open(filedes[1]);
                write(filedes[1],"2222",4);
                printf("child2 写入 写入值为2222\n\n");
                close(filedes[1]);
                sem_post(&sem);
                exit(0);
	}
	pid_t p3 = fork();
	if(p3==0) {
		sem_wait(&sem);
		close(filedes[0]);
		open(filedes[1]);
		write(filedes[1],"3333",4);
                printf("child3 写入 写入值为3333\n\n");
		close(filedes[1]);
		sem_post(&sem);
		exit(0);
	}
	int s1,s2,s3,n;
	//open(filedes[0]);
	close(filedes[1]);
	//waitpid(p1,&s1,0);
	//waitpid(p2,&s2,0);
	//waitpid(p3,&s3,0);
	usleep(400);
	printf("请输入读取数\n");
	scanf("%d",&n);
	printf("读取%d\n\n",n);
	num = read(filedes[0],b_read,n);
	printf("返回值%d,读取值%s\n\n",num,b_read);
	close(filedes[0]);
	return 0;
}

gcc OS-3-2.c -o OS-3-2 -pthreadubuntu

3. 消息队列、无名信号量

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

//	gcc OS-3-3.c -o OS-3-3 -pthread
//	./OS-3-3
//	第三个题和第四个题跑多了好像ftok的key_t会混起来 接收不到信息 改一下或者重启一下就好了

sem_t sem;
int sval;

void sender() {
	sem_wait(&sem);
	key_t key;
	int msqid,msnd;
	char msgp[100] = {0};
	key = ftok(".",1);
	msqid = msgget(key,IPC_CREAT);
	while(1) {
		printf("请输入消息\n");
		scanf("%s",msgp);
		if(strcmp(msgp,"exit")==0){
			strcpy(msgp,"end");
			msnd = msgsnd(msqid,msgp,strlen(msgp),MSG_NOERROR);
			printf("--------------------------------\n");
			printf("发送%d个字符(end),应答信息以下\n",strlen(msgp));
			break;
		}else{
			msnd = msgsnd(msqid,msgp,strlen(msgp),MSG_NOERROR);
			printf("发送%d个字符,输入exit应答\n",strlen(msgp));
		}
	}
	//msnd = msgsnd(msqid,msgp,strlen(msgp),MSG_NOERROR);
	//printf("sender key_t: %d IPC:%d \n",key,msqid);
	sem_post(&sem);
	usleep(100);
	sem_wait(&sem);
	msgrcv(msqid,msgp,100,0,0);
	printf("sender 接收 %s\n",msgp);
	sem_post(&sem);
} 
void receiver() {
	usleep(100);
	sem_wait(&sem);
	//printf("receiver start\n");
	key_t key;
	int msqid;
	int count;
	ssize_t mrcv;
	struct msqid_ds *buf;
	char msgp[100]={0};
	key = ftok(".",1);
	msqid = msgget(key,IPC_CREAT);
	count = 0;
	while(msgrcv(msqid,msgp,100,0,IPC_NOWAIT)!= -1) {
		count++;
		printf("第%d条信息 %s\n",count,msgp);
	}
	strcpy(msgp,"over");
	msgsnd(msqid,msgp,strlen(msgp),MSG_NOERROR);
	printf("receiver 发送 over\n");
	sem_post(&sem);
	usleep(100);
	if(msgctl(msqid,IPC_RMID,buf) == 0)
		printf("消息队列删除成功\n");
	printf("-----------------------------\n");
}

int main(void) 
{ 
        pthread_t tid1, tid2;    
        sem_init(&sem, 0, 1);
        pthread_create(&tid1,NULL,sender,NULL);
        pthread_create(&tid2,NULL,receiver, NULL);  
        pthread_join(tid1,NULL); 
        pthread_join(tid2,NULL);  
        sem_destroy(&sem);
        return 0;  
}

4.共享内存、有名信号量

  • sender.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <fcntl.h>

struct shm_msg {
	pid_t pid;
	char msg[100];
};

int main() {
	sem_t *sem;
	int shmid;
	char msg[100];
	struct shm_msg *shmaddr;
	sem = sem_open("mysem",O_CREAT,0644,1);
	shmid = shmget(ftok(".",1),1024,IPC_CREAT);
	shmaddr = shmat(shmid,0,0);
	shmaddr->pid = -1;
	printf("请输入字符串\n");
	scanf("%s",msg);
	sem_wait(sem);
	shmaddr->pid = 1;
	strcpy(shmaddr->msg,msg);
	printf("sender 发送 %s\n",shmaddr->msg);
	sem_post(sem);
	while(1) {
		if(shmaddr->pid == 0){
			sem_wait(sem);
			printf("sender 接收 %s",shmaddr->msg);
			break;
		}
	}
	sem_post(sem);
	sem_close(sem);
	sem_unlink("mysem");
    return 0;
}
  • receiver.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <fcntl.h>

struct shm_msg {
	pid_t pid;
	char msg[100];
};

int main() 
{
	sem_t *sem;
	int shmid;
	char msg[100];
	struct shm_msg *shmaddr;
	sem = sem_open("mysem",O_CREAT,0644,1);
	shmid = shmget(ftok(".",1),1024,IPC_CREAT);
	shmaddr = shmat(shmid,0,0);
	while(1) {
		if(shmaddr->pid == 1){
			sem_wait(sem);
			printf("receiver 接收 %s\n",shmaddr->msg);
			strcpy(shmaddr->msg,"over");
			printf("receiver 发送 %s \n",shmaddr->msg);
			shmaddr->pid = 0;
			break;
		}
	}
	sem_post(sem);
	sem_close(sem);
      return 0; 
}

打开两个终端 一个执行sender 一个执行receiver sender发送信息后receiver会接收vim

文件系统

结构

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>

#define BLOCKSIZE 1024
#define SIZE 1024000
#define END 65535
#define FREE 0
#define MAXOPENFILE 10
#define CUVER 0
#define APPEND 1

#pragma warning(disable:4996)

typedef struct BLOCK0 {
    char infomation[50];  //你想要提示的第一句话
    unsigned short blocksize;   //设成1024,单位B
    unsigned short totalsize;   //设成1000,单位KB
    unsigned short fat_num; // fat表的数量,设成2
    unsigned short root;// 根目录文件的起始盘块号
    unsigned char *startblock;
    /*tsz:对free的管理须要完善*/
    unsigned free_block;    //剩余未使用的块数
}block0;

typedef struct FCB {
    char filename[8];   //文件名
    char exname[3]; //扩展名
    unsigned char attribute;    //属性,0目录;1文件
    unsigned short time;
    unsigned short data;
    unsigned short first;
    unsigned long length;
    char free;  //0为空,1相反
    char reserved[7];   //预留,同时也为了内存对齐
}fcb;


// /* 这个数据结构为长文件准备,以倒序顺序放在长文件FCB的前面*/
//typedef struct EXTEND_NAME{
//    unsigned char endflag; /*若end是1则为最后一个EXTEND_NAME,不然为0*/
//    char extname1[10];   /*扩展名的存储位置1*/
//    unsigned char attribute;    /*属性,长文件的扩展名的属性为4*/
//    char extname2[20];   /*扩展名的存储位置2*/
//}ext_name;

typedef struct FAT {
    unsigned short id;
}fat;

typedef struct USEROPEN {
    char filename[8];
    char exname[4];
    unsigned char attribute;
    unsigned short time;
    unsigned short data;
    unsigned short first;
    unsigned long length;
    char free;
    fcb *ptrfcb;	//指向加载的fcb
    int count; //读写指针的位置
    short fcbstate;// 是否修改了文件的FCB的内容,1:修改;0:未修改
    short topenfile;// 户打开表项是否为空,0:空;1:已分配
}useropen;

unsigned char *myvhard; //虚拟磁盘开始位置的指针
useropen openfilelist[MAXOPENFILE];
char currentdir[100];
unsigned char* startp;  //磁盘数据区开始位置的指针
useropen *ptrcurdir;// 指向用户打开文件表中的当前目录所在打开文件表项的位置
fat *fat1;
fat *fat2;

函数

void info() {
    block0 *p = (block0*)myvhard;
    printf("*\t%s\n", p->infomation);
    printf("*\t块大小为:%dB,总大小为:%dKB\n", p->blocksize, p->totalsize);
    printf("*\tfat表数量为:%d\n", p->fat_num);
    printf("*\t数据区的开始块数为:%d\n", p->root);
    printf("*\t剩余未分配块数为:%d\n", p->free_block);
}

void help() {
    printf("*\t命令名称\t参数\t\t解释\n");
    printf("*\tinfo\t\t无\t\t获取文件系统总体信息\n");
    printf("*\thelp\t\t无\t\t获取全部命令的说明\n");
    printf("*\tcd\t\tdirname\t\t改变当前目录到指定的名为 dirname 的目录\n");
    printf("*\topen\t\tfilename\t打开当前目录下名为 filename 的文件\n");
    printf("*\tformat\t\t无\t\t对虚拟磁盘进行格式化,布局虚拟磁盘,创建根目录文件(或根目录区)\n");
    printf("*\tmkdir\t\tdirname\t\t在当前目录下建立名为 dirname 的子目录\n");
    printf("*\trmdir\t\tdirname\t\t在当前目录下删除名为 dirname 的子目录\n");
    printf("*\tls\t\t无\t\t显示当前目录的内容(子目录和文件信息)\n");
    printf("*\tcreate\t\tfilename\t建立名为 filename 的新文件\n");
    printf("*\tclose\t\tfd\t\t关闭前面由 my_open 打开的文件描述符为 fd 的文件\n");
    printf("*\twrite\t\tfd\t\t将接下来输入的文本保存到前面由 my_open 打开的文件描述符为 fd 的文件\n");
    printf("*\tread\t\tfd\t\t将前面由 my_open 打开的文件描述符为 fd 的文件中读取 1024 个字节的文本\n");
    printf("*\trm\t\tfilename\t删除名为 filename 的文件\n");
    printf("*\texit\t\t无\t\t退出文件系统\n");
    printf("*\tshow\t\t无\t\t显示全部已打开文件的fd值\n");
}

void fcbcpy(int i, fcb *fileFcb) {
    strcpy(openfilelist[i].filename, fileFcb->filename);
    strcpy(openfilelist[i].exname, fileFcb->exname);
    openfilelist[i].attribute = fileFcb->attribute;
    openfilelist[i].time = fileFcb->time;
    openfilelist[i].data = fileFcb->data;
    openfilelist[i].first = fileFcb->first;
    openfilelist[i].length = fileFcb->length;
    openfilelist[i].free = fileFcb->free;
    openfilelist[i].ptrfcb = fileFcb;
    openfilelist[i].fcbstate = 0;
    openfilelist[i].topenfile = 1;
    openfilelist[i].count = 0;
}

void init_fat1() {
    fat *p = (fat*)(myvhard + BLOCKSIZE);
    fat *p1, *p2;
    p1 = p2 = p;
    int i;
    for (i = 0; i<2 * BLOCKSIZE / sizeof(fat); ++i, ++p1)(p1->id) = FREE;
    for (i = 0; i<7; ++i, ++p2)p2->id = END;
    p[5].id = 6;
    fat1 = (fat*)(myvhard + BLOCKSIZE);
    fat2 = (fat*)(myvhard + 3 * BLOCKSIZE);
}

void init_b0() {
    block0 *p_b0 = (block0*)myvhard;
    strcpy(p_b0->infomation, "File System made by 陈王杰 汤胜中 徐时越 包治宽");
    p_b0->blocksize = BLOCKSIZE;
    p_b0->totalsize = SIZE / 1024;
    p_b0->fat_num = 2;
    p_b0->root = 5;
    p_b0->startblock = myvhard + 5 * BLOCKSIZE;
    p_b0->free_block = (SIZE / BLOCKSIZE) - 6;
}

void bak_fat1() {
    memcpy(myvhard + 3 * BLOCKSIZE, myvhard + BLOCKSIZE, 2 * BLOCKSIZE);
}

void get_time(int *data_time) {
    time_t now;
    time(&now);
    struct tm *nowtime;
    nowtime = localtime(&now);
    data_time[1] = nowtime->tm_hour * 2048 + nowtime->tm_min * 32 + nowtime->tm_sec / 2;  /*前面的两个乘是为了移位*/
    data_time[0] = (nowtime->tm_year - 80) * 512 + (nowtime->tm_mon + 1) * 32 + nowtime->tm_mday;
}

void check_enough_block(int block_index,int blocknum_need) {
    fat temp=fat1[block_index];
    int i,j;
    for (i = 0; i < blocknum_need; ++i) {
        if (temp.id == END)break;
        if(i!=blocknum_need-1){
            int need_new = blocknum_need - i - 1;
            for (j = 0; j < need_new; ++j)temp.id = dirst_block();
            temp = fat1[temp.id];
            temp.id = END;
        }
    }
}

void clean_openfilelist(int index) {
    strcpy(openfilelist[index].filename, "\0");
    strcpy(openfilelist[index].exname, "\0");
    openfilelist[index].attribute = 0;
    openfilelist[index].time = 0;
    openfilelist[index].data = 0;
    openfilelist[index].first = 0;
    openfilelist[index].length = 0;
    openfilelist[index].fcbstate = 0;
    openfilelist[index].ptrfcb = NULL;
    openfilelist[index].free = 0;
    openfilelist[index].topenfile = 0;
    openfilelist[index].count = 0;
}

int is_rootdir(fcb *fileFcb) {
    if (fileFcb->first == 5)return 1;
    else return 0;
}

int getblocknum_fromfilelen(int len) {
    if (len == 0)return 1;
    else return len % BLOCKSIZE == 0 ? (len / BLOCKSIZE) : (len / BLOCKSIZE + 1);
}

fcb* exist_file(fcb *fileFcb,char* filename) {
    int length = fileFcb->length;
    int flag = 0;
    int i;
    for (i = 0; i < length / sizeof(fcb); i++, ++fileFcb) {
        if (!strcmp(fileFcb->filename, filename)) {
            flag = 1;
            break;
        }
        if (fileFcb->free == 0)
            i--;
    }
    if (flag == 0)return NULL;
    else return fileFcb;
}

/*建立新文件夹时,传入为为新文件夹分配的块号便可快速完成新文件目录下的.和..的建立*/
/*root参数通常传0就好*/
void fast_dir(int dirst_block, int root) {
    char* block_start = (char*)myvhard + dirst_block * BLOCKSIZE;
    fcb* p = (fcb*)block_start;
    int i;
    for (i = 0; i<BLOCKSIZE / sizeof(fcb); ++i, ++p)p->free = 0;
    fcb *cur = (fcb*)block_start;
    fcb *father = (cur + 1);
    int data_time[2];
    get_time(data_time);
    strcpy(cur->filename, ".");
    strcpy(father->filename, "..");
    strcpy(cur->exname, "di");
    strcpy(father->exname, "di");
    cur->attribute = father->attribute = 0;
    cur->time = father->time = data_time[1];
    cur->data = father->data = data_time[0];
    cur->first = dirst_block;
    cur->length = 2 * sizeof(fcb);
    if (root) {
        father->first = cur->first;
        father->length = cur->length;
    }
    else {
        i = get_curnum();
        father->first = openfilelist[i].first;
        father->length = openfilelist[i].length;
    }
    cur->free = father->free = 1;
    fat1[dirst_block].id = END;
    fat2[dirst_block].id = END;
}

void fast_dirfcb(fcb *fileFcb, char *dirname,int dirst_block) {
    strcpy(fileFcb->filename, dirname);
    strcpy(fileFcb->exname, "di");
    fileFcb->attribute = 0;
    int time[2];
    get_time(time);
    fileFcb->time = time[1];
    fileFcb->data = time[0];
    fileFcb->first = dirst_block;
    fileFcb->free = 1;
    fileFcb->length = 2 * sizeof(fcb);
}
/* fat的前5个给了block0,fat1,fat2*/
void my_format() {
    init_b0();
    init_fat1();
    bak_fat1();
    fast_dir(5, 1);
}

void startsys() {
    myvhard = (unsigned char*)malloc(SIZE);
    memset(myvhard, 0, SIZE);
    FILE * fp;
    if ((fp = fopen("./my_fs", "r")) != NULL) {
        fread(myvhard, SIZE, 1, fp);
        fclose(fp);
    }
    else {
        printf("*\tfile not found!new file created!\n");
        my_format();
    }
    fcbcpy(0, (fcb*)(myvhard + 5 * BLOCKSIZE));
    ptrcurdir = &openfilelist[0];

    /*初始化后面的全部opoenfilelist项*/
    int i;
    for (i = 1; i < MAXOPENFILE; i++) {
        clean_openfilelist(i);
    }

    /*设置一些全局变量*/
    strcpy(currentdir, "/");
    startp = ((block0 *)myvhard)->startblock;
    fat1 = (fat*)(myvhard + BLOCKSIZE);
    fat2 = (fat*)(myvhard + 3 * BLOCKSIZE);
}

int get_curnum() {
    return(ptrcurdir - openfilelist);
}

int dirst_block() {
    int i, freeBlock;
    fat *fat1 = (fat *)(myvhard + BLOCKSIZE);
    fat *fat2 = (fat *)(myvhard + BLOCKSIZE * 3);
    int flag = 0;
    for (i = 0; i < BLOCKSIZE * 2 / sizeof(fat); i++) {
        if (fat1->id == FREE) {
            flag = 1;
            freeBlock = i;
            return i;
        }
        fat1++;
        fat2++;
    }
    if (flag == 0) {
        printf("FAT满了!");
        return -1;
    }
}

int get_block_num(int start_block) {
    int i = 1;
    fat *fat1 = (fat*)(myvhard + BLOCKSIZE);
    fat *fat_t = fat1 + start_block;
    if (fat_t->id == FREE)return 0;
    else {
        while (fat_t->id != END) {
            ++i;
            fat_t = fat1 + fat_t->id;
        }
    }
    return i;
}

void fast_file(fcb*fileFcb, char *filename, int dirstblock) {
    strcpy(fileFcb->filename, filename);
    strcpy(fileFcb->exname, "txt");
    fileFcb->attribute = 1;
    int time[2];
    get_time(time);
    fileFcb->time = time[1];
    fileFcb->data = time[0];
    fileFcb->first = dirstblock;
    fileFcb->free = 1;
    fileFcb->length = 0;
    fat *fat1 = (fat*)(myvhard + BLOCKSIZE);
    fat *fat2 = (fat*)(myvhard + 3*BLOCKSIZE);
    fat1[dirstblock].id = END;
    fat2[dirstblock].id = END;
}

void update_dir(char *filename) {
    if (strcmp(filename, ".") && strcmp(filename, "..")) {
        if (!strcmp(currentdir, "/"))strcat(currentdir, filename);
        else {
            strcat(currentdir, "/");
            strcat(currentdir, filename);
        }
    }
}

void update_dir_father() {
    int last = findlast();
    currentdir[last] = '\0';
}

int findlast() {
    int i, j;
    i = j = 0;
    while (currentdir[i] != '\0') {
        if (currentdir[i] == '/')j = i;
        ++i;
    }
    if (j == 0)++j;
    return j;
}

void my_ls() {
    printf("filename\texname\t\ttime\t\tdata\t\tsize\n");
    /*找到当前目录再openfilelist中得位置*/
    int i = get_curnum();
    // 读取当前目录文件的内容到内存
    char *buf = (char *)malloc(1024);
    do_read(i, 1024, buf);
    fcb *fileFcb = (fcb *)buf;
    int num = fileFcb->length / sizeof(fcb);
    for (i = 0; i < num; i++, fileFcb++) {   /*只有fileFCB是真的文件(目录),i才会增长*/
        if (fileFcb->free == 1) {
            char exname[4];
		int j;
            for (j = 0; j<3; ++j)exname[j] = fileFcb->exname[j];
            exname[3] = '\0';
            printf("%s\t\t%s\t\t%02d:%02d:%02d\t%02d,%02d,%02d\t%d\n", fileFcb->filename, exname, fileFcb->time / 2048, (fileFcb->time % 2048) / 32, (fileFcb->time % 32) * 2, fileFcb->data / 512 + 1980, fileFcb->data % 512 / 32,
                   fileFcb->data % 32, fileFcb->length);
        }
        else i--;
    }
    free(buf);
}

void my_mkdir(char *dirname) {
    int i = get_curnum();
    int curOpenNum = i;
    char *buf = (char *)malloc(1024);
    do_read(i, 1024, buf);
    fcb *fileFcb = (fcb *)buf;
    int fcb_num = fileFcb->length / sizeof(fcb);
    for (i = 0; i < fcb_num; ++i, ++fileFcb) {
        if (!strcmp(fileFcb->filename, dirname)) {
            printf("目录重名\n");
            free(buf);
            return;
        }
        if (fileFcb->free == 0)
            i--;
    }
    for (i = 0; i < MAXOPENFILE; ++i) {
        if (openfilelist[i].topenfile == 0) {
            break;
        }
    }
    if (i == MAXOPENFILE) {
        printf("无剩余openuserlist项!\n");
        free(buf);
        return;
    }
    int freeBlock = dirst_block();
    if (freeBlock==-1) {
        printf("FAT已满!\n");
        free(buf);
        return;
    }
    //为新目录分配fcb
    fileFcb = (fcb *)buf;
    int isroot = is_rootdir(fileFcb);
    for (i = 0; i < fcb_num; i++, fileFcb++) {
        if (!strcmp(fileFcb->filename, ".")) {
            fileFcb->length += sizeof(fcb);
        }
        //when root is current directory
        if(isroot&& !strcmp(fileFcb->filename, ".."))fileFcb->length += sizeof(fcb);
        if (fileFcb->free == 0)break;
    }
    //update openfilelist
    openfilelist[curOpenNum].length += sizeof(fcb);
    fast_dirfcb(fileFcb, dirname, freeBlock);
    fast_dir(freeBlock, 0);
    do_write(curOpenNum, buf, 1024, 0);
    free(buf);
}

void my_rm(char *filename) {
    // 读取当前目录文件的内容到内存
    char *buf = (char *)malloc(1024);;
    int i=get_curnum();
    int fd = i;
    do_read(i, 1024, buf);
    // 检查要删除的目录是否存在
    fcb *fileFcb = (fcb *)buf;
    fileFcb = exist_file(fileFcb, filename);
    if (!fileFcb) {
        printf("%s文件(目录)不存在!\n", filename);
        return;
    }
   if(fileFcb->attribute==0){
	printf("不能删除目录\n");
	free(buf);
	return;
    } else {
	int j;
	for(j=0;j<MAXOPENFILE;++j) {
		if(openfilelist[j].topenfile==1 && !strcmp(openfilelist[j].filename,fileFcb->filename)) {
			printf("文件正在被使用");
			free(buf);
			return;		
		}
	}
     }
    // 回收磁盘块
    int index = fileFcb->first;
    int indexT;
    do {
        indexT = fat1[index].id;
        fat1[index].id = FREE;
        fat2[index].id = FREE;
        index = indexT;
    } while (index != END);
    // 清空目录项
    fileFcb->filename[0] = '\0';
    fileFcb->free = 0;
    fileFcb = (fcb *)buf;
    // 修改目录的长度
    fileFcb->length -= sizeof(fcb);
    do_write(fd, buf, 1024, 0);
    ptrcurdir->length -= sizeof(fcb);
    free(buf);
}

void my_close(int fd) {
    if (fd >= MAXOPENFILE)
    {
        printf("fd不是有效数字\n");
        return;
    }
    else if (openfilelist[fd].topenfile == 0) {
        printf("文件未打开!\n");
        return;
    }
    //else if (openfilelist[fd].fcbstate == 1) {
    //	//暂时只须要改length
    //	update_fcb(fd);
    //}
    clean_openfilelist(fd);
}

void my_rmdir(char *dirname) {
    int i = 0;
    char *buf = (char *)malloc(1024);
    i = get_curnum();
    int fd = i;
    do_read(i, 1024, buf);

    // 检查要删除的目录是否存在
    fcb *fileFcb = (fcb *)buf;
    fileFcb = exist_file(fileFcb, dirname);
    if (!fileFcb) {
        printf("%s文件(目录)不存在!\n", dirname);
        return;
    }
    // 检查要删除的目录文件是否为空
    fcb *temp = (fcb *)(myvhard + BLOCKSIZE * fileFcb->first);
    if (temp->length > 2 * sizeof(fcb)) {
        printf("目录不为空,不可删除!\n");
        return;
    }
    int flag = 0;
    // 检查该目录是否已经打开
    for (i = 0; i < MAXOPENFILE; i++) {
        if (strcmp(openfilelist[i].filename, dirname) == 0) {
            flag = 1;
            break;
        }
    }
    if (flag == 1) {//f 把打开的目录关闭
        my_close(i);
    }

    // 回收磁盘块
    int index = fileFcb->first;
    int indexT;
    //length = fileFcb->length;
    do {
        indexT = fat1[index].id;
        fat1[index].id = FREE;
        fat2[index].id = FREE;
        index = indexT;
    } while (index != END);

    // 清空目录项,将其free设置为0便可,而后是将上层目录的长度进行更新,同时对于openlist中也要更新,由于其指向并不相同.
    fileFcb->filename[0] = '\0';
    fileFcb->free = 0;
    fileFcb = (fcb *)buf;
    fileFcb->length -=sizeof(fcb);
    ptrcurdir->length -= sizeof(fcb);
    do_write(fd, buf, 1024, 0);
    free(buf);
}

void my_create(char *filename) {
    int i = get_curnum();
    int curOpenNum = i;
    int block_num = get_block_num(openfilelist[i].first);
    int fcb_num = openfilelist[i].length / sizeof(fcb);
    char *buf = (char *)malloc(block_num * 1024);
    /* 把全部块的数据都读到buf里面去*/
    do_read(i, block_num * 1024, buf);
    fcb *fileFcb = (fcb *)buf;
    for (i = 0; i < fcb_num; i++, ++fileFcb) {
        if (!strcmp(fileFcb->filename, filename)) {
            printf("文件重名!");
            free(buf);
            return;
            break;
        }
        if (fileFcb->free == 0)
            i--;
    }
    int freeBlock = dirst_block();
    if (freeBlock == -1) {
        free(buf);
        return;
    }
    // 在当前目录中分配FCB给新的目录fcb
    fileFcb = (fcb *)buf;
    for (i = 0; i < fcb_num; ++i, ++fileFcb) {
        if (!strcmp(fileFcb->filename, ".")) {
            fileFcb->length += sizeof(fcb);
            /* check if it is root directory*/
            if (fileFcb->first == 5)(fileFcb + 1)->length = fileFcb->length;
        }
        if (fileFcb->free == 0)
            break;
    }
    fast_file(fileFcb, filename, freeBlock);
    ptrcurdir->length += sizeof(fcb);
    do_write(curOpenNum, buf, 1024, 0);
    free(buf);
}

void my_cd(char *dirname) {
    // 打开该目录文件
    int fd = my_open(dirname);
    switch (fd) {
        case -1:break;
        case -2:break;
        case -3:update_dir_father(); break;
        default:update_dir(dirname); break;
    }

}

int my_open(char *filename) {
    int i = get_curnum();
    fcb *p = (fcb*)(myvhard + (openfilelist[i].first)*BLOCKSIZE);
    int block_num = get_block_num(openfilelist[i].first);
    int fcb_num = openfilelist[i].length / sizeof(fcb);
    char *buf = (char *)malloc(block_num * 1024);
    /* 把全部块的数据都读到buf里面去*/
    do_read(i, block_num * 1024, buf);
    fcb *fileFcb = (fcb *)buf;
    int flag = 0;
    //找到此fcb,同时检查文件存不存在
    for (i = 0; i < fcb_num; i++, fileFcb++) {
        if (!strcmp(fileFcb->filename, filename)) {
            flag = 1;
            break;
        }
    }
    if (flag == 0) {
        printf("文件不存在!\n");
        return -2;
    }
    //获得真正的pcb指针
    p+=(fileFcb - (fcb*)buf);
    // 检查文件是否已打开
    for (i = 0; i < MAXOPENFILE; i++) {
        if (openfilelist[i].topenfile == 1 && openfilelist[i].first == fileFcb->first) {	//用first来判断是否同一个文件,注意不能用filename
            if (!strcmp(fileFcb->filename, "..") && (ptrcurdir->first != 5)) {	//若是是打开上个目录而且不是在根目录
                // 找到当前文件夹并关闭
                int j = 0;
                for (j = 0; j<MAXOPENFILE; j++)
                    if (openfilelist[j].free == 1 && (&openfilelist[j]) == ptrcurdir)
                        my_close(j);
                // 打开上级目录
                for (j = 0; j<MAXOPENFILE; j++)
                    if (openfilelist[j].free = 1 && openfilelist[j].first == fileFcb->first)
                        ptrcurdir = &openfilelist[j];
                free(buf);
                printf("打开上级目录!\n");
                return -3;
            }
            free(buf);
            printf("文件已打开!\n");
            return -1;
        }
    }
    // 检查opefilelist是否有空余
    int fd;
    flag = 0;
    for (i = 0; i < MAXOPENFILE; i++) {
        if (openfilelist[i].topenfile == 0) {
            fd = i;
            flag = 1;
            break;
        }
    }
    if (flag == 0) {
        printf("文件打开太多!\n");
        free(buf);
        return -1;
    }
    // 填写打开分配的openfilelist
    fcbcpy(i, p);
    if(fileFcb->attribute==0)ptrcurdir = &openfilelist[i];
    if(fileFcb->attribute==1)printf("打开文件的fd是%d\n", fd);
    free(buf);
    return fd;
}

void my_write(int fd) {
    if (openfilelist[fd].attribute == 0) {
        printf("can't write directory!\n");
        return;
    }
    int writeStyle;
    char *text = (char *)malloc(BLOCKSIZE);
    int index = -1;
    char c_temp;
    unsigned short block_index=openfilelist[fd].first;
    if (fd >= MAXOPENFILE || fd < 0) {
        printf("fd超出范围\n");
        return;
    }
    printf("请选择写入方式(0.覆盖写 1.追加写 2.覆盖写一行 3.追加写一行)\n");
    scanf("%d", &writeStyle);
    getchar();
    printf("请输入内容:\n");
    while ((c_temp = getchar()) != '\n')text[(++index)] = c_temp;
    if (writeStyle == 2 || writeStyle == 3) {
        text[(++index)] = '\n';
        writeStyle -= 2;
    }
    int len = (index + 1);
    int writed_len = do_write(fd, text, len, writeStyle); //返回实际写入字节数;
    if (writed_len != -1 && writed_len == len) {
        printf("写入成功,共写入 %d 个字节\n", writed_len);
        //update openfilelist
        if (writeStyle == 0) {
            openfilelist[fd].count=openfilelist[fd].length = len;
            openfilelist[fd].ptrfcb->length = len;
        }
        else {
            openfilelist[fd].count += len;
            openfilelist[fd].length = openfilelist[fd].count;
            openfilelist[fd].ptrfcb->length = openfilelist[fd].count;
        }
        openfilelist[fd].fcbstate = 1;
    }
    else printf("something wrong in writing!\n");
    free(text);
}
void my_read(int fd, int len) {
    int i;
    int j = 0;
    for (i = 0; i < MAXOPENFILE; i++) {
        if (fd == 0)break;
        if (openfilelist[i].topenfile == 1)fd--;
    }
    fd = i;
    char *text = (char *)malloc(BLOCKSIZE);
    if (fd>MAXOPENFILE || fd<0)printf("超过操做边界\n");
    else {
        printf("读出字节数:%d\n",do_read(fd,len,text));
        text[len]='\0';
        printf("%s\n", text);
    }
    free(text);
}


int  do_read(int fd, int len, char *text) {
    int block_index = openfilelist[fd].first;
    /*读写指针*/
    unsigned char *p = block_index * BLOCKSIZE + myvhard;
    int block_num =len%BLOCKSIZE==0?(len/BLOCKSIZE):(len / BLOCKSIZE + 1);
    int i, j, k = 0;
    //可能占据了多个盘块
    for (i = 0; i < block_num; i++) {
        for (j = 0; j < BLOCKSIZE && k < len; j++, k++, p++)text[k] = *p;
        p = myvhard + BLOCKSIZE * (fat1[block_index].id);
        block_index = fat1[block_index].id;
    }
    return k;
}

int do_write(int fd, char *text, int len, int wstyle) {
    if (wstyle != 0&& wstyle != 1)return -1;
    int index = openfilelist[fd].first;
    unsigned char *p = index * BLOCKSIZE + myvhard;
    int block_num = getblocknum_fromfilelen(len);
    int i, j, k = 0;
    if (wstyle == 0) {
        for (i = 0; i < block_num; ++i) {
            for (j = 0; j < BLOCKSIZE && k < len; ++j, ++k,++p)*p = text[k];
            p = myvhard + BLOCKSIZE * (fat1[index].id);
            index = fat1[index].id;
        }
    }
    else {
	  int i;
        int file_len = openfilelist[fd].length;
        for (i = 0; i < file_len; ++i)++p;
        int new_file_len = file_len + len;
        int old_block = getblocknum_fromfilelen(file_len);
        int new_block = getblocknum_fromfilelen(new_file_len);
        check_enough_block(openfilelist[fd].first,new_block);
        for (i = old_block; i <= new_block; ++i) {
            for (j = (file_len-1)%BLOCKSIZE; j < BLOCKSIZE && k < len; ++j, ++k,++p)*p = text[k];
            p = myvhard + BLOCKSIZE * (fat1[index].id);
            index = fat1[index].id;
        }
    }
    return k;
}

void showOpenFile() {
    int i;
    for (i = 0; i < MAXOPENFILE; i++) {
        if (openfilelist[i].topenfile == 1)
            printf("%d %s\n", i, openfilelist[i].filename);
    }
}

void my_exitsys() {
    //for (int i = 0; i < MAXOPENFILE; ++i) {
    //	if (openfilelist[i].topenfile == 1 && openfilelist[i].attribute == 1 && openfilelist[i].fcbstate == 1)
    //		update_fcb(i);
    //}
    FILE *fp;
    fp = fopen("./my_fs", "w");
    fwrite(myvhard, SIZE, 1, fp);
    free(myvhard);
    fclose(fp);
    exit(0);
}

void switcher(char *cmd) {
    int fd;
    char command[20];
    if (!strcmp(cmd, "help")) {
        help();
    }
    else if (!strcmp(cmd, "info")) {
        info();
    }
    else if (!strcmp(cmd, "mkdir")) {
        scanf("%s", command);
	if (strlen(command)>=8) printf("目录名过长\n");
      else  my_mkdir(command);
    }
    else if (!strcmp(cmd, "rmdir")) {
        scanf("%s", command);
        my_rmdir(command);
    }
    else if (!strcmp(cmd, "ls")) {
        my_ls();
    }
    else if (!strcmp(cmd, "cd")) {
        scanf("%s", command);
        my_cd(command);
    }
    else if (!strcmp(cmd, "create")) {
        scanf("%s", command);
        if (strlen(command)>=8) printf("文件名过长\n");
        else my_create(command);
    }
    else if (!strcmp(cmd, "write")) {
        scanf("%d", &fd);
        my_write(fd);
    }
    else if (!strcmp(cmd,"rm")) {
        scanf("%s",command);
        my_rm(command);
    }
    else if (!strcmp(cmd, "read")) {
        scanf("%d", &fd);
        my_read(fd, openfilelist[fd].length);
    }
    else if (!strcmp(cmd, "ls")) {
        scanf("%s", command);
        my_rm(command);
    }
    else if (!strcmp(cmd, "open")) {
        scanf("%s", command);
        my_open(command);
    }
    else if (!strcmp(cmd, "close")) {
        scanf("%d", &fd);
        my_close(fd);
    }
    else if (!strcmp(cmd, "exit")) {
        my_exitsys();
        return;
    }
    else if (!strcmp(cmd, "show")) {
        showOpenFile();
    }
    else {
        char c;
        while (1) {
            c = getchar();
            if (c == '\n') break;
        }
        printf("无效指令,请从新输入:\n");
    }
}

int main(int argc, const char * argv[]) {
    printf("*\t输入help以获取帮助!\n");
    startsys();
    char cmd[10];
    while (1) {
        printf("%s:$", currentdir);
        scanf("%s", cmd);
        switcher(cmd);
    }
    return 0;
}