2012-06-21 20:14:09 yueguanghaidao 阅读数 6570

本周进行操作系统课程设计,在很多的题目中选了个unix文件系统模拟,主要就是操作结构与文件。

为了方便,文件系统结构如下:

Super block   --  Block bitmap  -- Inode bitmap  -- Inode table -- Block zone

其中:

Super block: 存储基本信息

Block bitmap:块分配情况

Inode bitmap:索引节点分配情况

Inode table: Indoe 节点存放区

Block zone:存放数据区

效果如下:


总的说来,做的还是挺简单的,只是实现了基本的功能.而块的分配没有怎么完成,linux系统中一般是通过多级索引的方式为inode分配块.

刚开始我的想法是:inode的块(512B)只写510B,留下2B用于记录下一块的块号,我觉得应该可行,但觉得繁,就没有写下去.所以就没有多余的

块分配操作.知识INode对应一个Block....,太懒了.还有一个缺点,文件指针移动太频繁了,而且都是绝对定位移动(好算,呵呵)

代码如下:

/*核心思想:一切皆是文件
如果是目录:Block中存储的是目录下文件和目录的fcb
如果是文件:Block中存储的是文件的内容
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <signal.h>

#define BLOCKSIZE 512
#define BLOCKNUM  512
#define INODENUM  30
#define FILENAME "file.dat"

typedef struct{
	unsigned short blockSize;
	unsigned short blockNum;
	unsigned short inodeNum;
	unsigned short blockFree;
	unsigned short inodeFree;
}SuperBlock;

typedef struct{
	unsigned short inum;
	char fileName[10];
	unsigned short isDir;  // 0-file 1-dir
	unsigned short iparent;
	unsigned short length;    //if file->filesize  if dir->filenum
	unsigned short blockNum;
}Inode,*PtrInode;

//Fcb用于存储文件与 目录信息,主要用途:将一个目录下的所有文件(包括目录)写入到该目录对应的Block中
typedef struct {
    unsigned short inum;
    char fileName[10];
    unsigned short isDir;
}Fcb,*PtrFcb;


typedef struct{
	char userName[10];
	char passWord[10];
}User;


char blockBitmap[BLOCKNUM];
char inodeBitmap[INODENUM];

SuperBlock superBlock;
User curUser=(User){"root","root"};

unsigned short currentDir; //current inodenum
FILE *fp;
const unsigned short superBlockSize=sizeof(superBlock);
const unsigned short blockBitmapSize=sizeof(blockBitmap);
const unsigned short inodeBitmapSize=sizeof(inodeBitmap);
const unsigned short inodeSize=sizeof(Inode);
const unsigned short fcbSize=sizeof(Fcb);
char		*argv[5];
int argc;


void createFileSystem()
/*创建*/
{
	long len;
	PtrInode fileInode;
	if ((fp=fopen(FILENAME,"wb+"))==NULL)
	{
		printf("open file %s error...\n",FILENAME);
		exit(1);
	}

    //init bitmap
	for(len=0;len<BLOCKNUM;len++)
        blockBitmap[len]=0;

    for(len=0;len<INODENUM;len++)
        inodeBitmap[len]=0;

     //memset

	for (len=0;len<(superBlockSize+blockBitmapSize+inodeBitmapSize+inodeSize*INODENUM+BLOCKSIZE*BLOCKNUM);len++)
	{
		fputc(0,fp);
	}
	rewind(fp);

	//init superBlock
	superBlock.blockNum=BLOCKNUM;
	superBlock.blockSize=BLOCKSIZE;
	superBlock.inodeNum=INODENUM;
	superBlock.blockFree=BLOCKNUM-1;
	superBlock.inodeFree=INODENUM-1;

	fwrite(&superBlock,superBlockSize,1,fp);

	//create root
	fileInode=(PtrInode)malloc(inodeSize);
	fileInode->inum=0;
	strcpy(fileInode->fileName,"/");
	fileInode->isDir=1;
	fileInode->iparent=0;
	fileInode->length=0;
	fileInode->blockNum=0;

	//write / info to file
	inodeBitmap[0]=1;
	blockBitmap[0]=1;
	fseek(fp,superBlockSize,SEEK_SET);
	fwrite(blockBitmap,blockBitmapSize,1,fp);
	fseek(fp,superBlockSize+blockBitmapSize,SEEK_SET);
	fwrite(inodeBitmap,inodeBitmapSize,1,fp);
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize,SEEK_SET);
	fwrite(fileInode,inodeSize,1,fp);
	fflush(fp);

	//point to currentDir
	currentDir=0;

}

void openFileSystem()
/*如果FILENAME可读,则代表之前已有信息,并读取相应数据    如果不可读,则创建文件系统 */
{

	if((fp=fopen(FILENAME,"rb"))==NULL)
	{
		createFileSystem();
	}
	else
	{
	    if ((fp=fopen(FILENAME,"rb+"))==NULL)
        {
            printf("open file %s error...\n",FILENAME);
            exit(1);
        }
	    rewind(fp);
        //read superBlock from file
        fread(&superBlock,superBlockSize,1,fp);

        //read bitmap from file
        fread(blockBitmap,blockBitmapSize,1,fp);
        fread(inodeBitmap,inodeBitmapSize,1,fp);

        //init current dir
        currentDir=0;

	}

}


void createFile(char *name,int flag) //flag=0 ->create file   =1 ->directory
{
	int i,nowBlockNum,nowInodeNUm;
	PtrInode fileInode=(PtrInode)malloc(inodeSize);
	PtrInode parentInode=(PtrInode)malloc(inodeSize);
	PtrFcb fcb=(PtrFcb)malloc(fcbSize);

	//the available blockNumber
	for(i=0;i<BLOCKNUM;i++)
	{
		if(blockBitmap[i]==0)
		{
			nowBlockNum=i;
			break;
		}

	}

	//the available inodeNumber
	for(i=0;i<INODENUM;i++)
		{
			if(inodeBitmap[i]==0)
			{
				nowInodeNUm=i;
				break;
			}

		}

	//init fileINode struct
	fileInode->blockNum=nowBlockNum;
	strcpy(fileInode->fileName,name);
	fileInode->inum=nowInodeNUm;
	fileInode->iparent=currentDir;
	if(flag==0)
	{
		fileInode->isDir=0;
	}
	else
	{
		fileInode->isDir=1;
	}
	fileInode->length=0;

	//write fileInfo to file
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+inodeSize*nowInodeNUm,SEEK_SET);
	fwrite(fileInode,inodeSize,1,fp);

	//update superBlock and bitmap
	superBlock.blockFree-=1;
	superBlock.inodeFree-=1;
	blockBitmap[nowBlockNum]=1;
	inodeBitmap[nowInodeNUm]=1;

	//init fcb info
	strcpy(fcb->fileName,fileInode->fileName);
	fcb->inum=fileInode->inum;
	fcb->isDir=fileInode->isDir;

	//update to file ...

	//update parent dir block info
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
	fread(parentInode,inodeSize,1,fp);
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+parentInode->blockNum*BLOCKSIZE+parentInode->length*fcbSize,SEEK_SET);
	fwrite(fcb,fcbSize,1,fp);

	//update parent dir inode info
	parentInode->length+=1;
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
	fwrite(parentInode,inodeSize,1,fp);

	// free resource
	free(fileInode);
	free(parentInode);
	free(fcb);
}



void list()
{
	int i;
	PtrFcb fcb=(PtrFcb)malloc(fcbSize);
	PtrInode parentInode=(PtrInode)malloc(inodeSize);

	//read parent inode info from file
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
	fread(parentInode,inodeSize,1,fp);

	//point to parent dir block
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+inodeSize*INODENUM+parentInode->blockNum*BLOCKSIZE,SEEK_SET);

	//list info
	for(i=0;i<parentInode->length;i++)
	{
		fread(fcb,fcbSize,1,fp);
		printf("Filename: %-10s",fcb->fileName);
		printf("Inode number: %-2d    ",fcb->inum);
		if(fcb->isDir==1)
		{
		printf("Directory\n");
		}
		else
		{
			printf("Regular file\n");
		}
	}

	//free resource
	free(fcb);
	free(parentInode);
}


int findInodeNum(char *name,int flag)  //flag=0 ->find file flag=1 -> find dir
{
	int i,fileInodeNum;
	PtrInode parentInode=(PtrInode)malloc(inodeSize);
	PtrFcb fcb=(PtrFcb)malloc(fcbSize);

	//read current inode info from file
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
	fread(parentInode,inodeSize,1,fp);

	//read the fcb in the current dir block
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+inodeSize*INODENUM+parentInode->blockNum*BLOCKSIZE,SEEK_SET);

	for(i=0;i<parentInode->length;i++)
	{
		fread(fcb,fcbSize,1,fp);
		if(flag==0)
		{
			if((fcb->isDir==0)&&(strcmp(name,fcb->fileName)==0))
					{
						fileInodeNum=fcb->inum;
						break;
					}

		}
		else
		{
			if((fcb->isDir==1)&&(strcmp(name,fcb->fileName)==0))
					{
						fileInodeNum=fcb->inum;
						break;
					}

		}
	}

	if(i==parentInode->length)
			fileInodeNum=-1;

	free(fcb);
	free(parentInode);
	return fileInodeNum;
}

void cd(char *name)
{
	int fileInodeNum;
	PtrInode fileInode=(PtrInode)malloc(inodeSize);
	if(strcmp(name,"..")!=0)
	{
		fileInodeNum=findInodeNum(name,1);
		if(fileInodeNum==-1)
			printf("This is no %s directory...\n",name);
		else
		{
			currentDir=fileInodeNum;
		}
	}
	else
	{
		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
		fread(fileInode,inodeSize,1,fp);
		currentDir=fileInode->iparent;

	}
	free(fileInode);
}

void cdParent()
{
	PtrInode fileInode=(PtrInode)malloc(inodeSize);
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
	fread(fileInode,inodeSize,1,fp);
	currentDir=fileInode->iparent;

	free(fileInode);
}

void write(char *name)
{
	int fileInodeNum,i=0;
	char c;
	PtrInode fileInode=(PtrInode)malloc(inodeSize);
	if((fileInodeNum=findInodeNum(name,1))!=-1)
	{
		printf("This is a directory,not a file...\n");
		return;
	}

	fileInodeNum=findInodeNum(name,0);
	if(fileInodeNum==-1)
		printf("This is no %s file...\n",name);
	else
	{
		//get inode->blocknum
		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInodeNum*inodeSize,SEEK_SET);
		fread(fileInode,inodeSize,1,fp);
		//point to the block site
		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+fileInode->blockNum*BLOCKSIZE,SEEK_SET);
		printf("please input file content(stop by #):\n");
		while((c=getchar())!='#')
		{
			fputc(c,fp);
			i++;
		}

		//update inode->length
		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInodeNum*inodeSize,SEEK_SET);
		fread(fileInode,inodeSize,1,fp);
		fileInode->length=i-1;
		fseek(fp,-inodeSize,SEEK_CUR);
		fwrite(fileInode,inodeSize,1,fp);
	}

	free(fileInode);

}

void read(char *name)
{
	int fileInodeNum;
	char c;
	PtrInode fileInode=(PtrInode)malloc(inodeSize);
	if((fileInodeNum=findInodeNum(name,1))!=-1)
	{
			printf("This is a directory,not a file...\n");
			return;
	}
	fileInodeNum=findInodeNum(name,0);
	if(fileInodeNum==-1)
		printf("This is no %s file...\n",name);
	else
	{
		//get inode->blocknum
		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInodeNum*inodeSize,SEEK_SET);
		fread(fileInode,inodeSize,1,fp);
		//point to the block site
		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+fileInode->blockNum*BLOCKSIZE,SEEK_SET);

		//read content
		if(fileInode->length!=0)
		{
			while((c=fgetc(fp))!=EOF)
			{
				putchar(c);
			}
			printf("\n");
		}

	}

	free(fileInode);
}


void delete(char *name) 
/*delete 一个文件,需要修改SuperBlock,Blockbitmap,Inodebitmap,并更新父节点长度,删除父节点Block中存储的该文件fcb*/ 
{
	int fileInodeNum,i;
	PtrInode fileInode=(PtrInode)malloc(inodeSize);
	PtrInode parentInode=(PtrInode)malloc(inodeSize);
	Fcb fcb[20];
	if(((fileInodeNum=findInodeNum(name,0))==-1)&&((fileInodeNum=findInodeNum(name,1))==-1))
	{
		printf("This is no %s...\n",name);
	}
	else
	{
		if((fileInodeNum=findInodeNum(name,0))==-1)
		{
			fileInodeNum=findInodeNum(name,1);
		}

		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInodeNum*inodeSize,SEEK_SET);
		fread(fileInode,inodeSize,1,fp);

		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInode->iparent*inodeSize,SEEK_SET);
		fread(parentInode,inodeSize,1,fp);


		//update parent info
		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+parentInode->blockNum*BLOCKSIZE,SEEK_SET);
		for(i=0;i<parentInode->length;i++)
		{
			fread(&fcb[i],fcbSize,1,fp);
				//fcb[i]=tmp;
		}

		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+parentInode->blockNum*BLOCKSIZE,SEEK_SET);
		for(i=0;i<BLOCKSIZE;i++)
				fputc(0,fp);

		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+INODENUM*inodeSize+parentInode->blockNum*BLOCKSIZE,SEEK_SET);
		for(i=0;i<parentInode->length;i++)
		{
			if((strcmp(fcb[i].fileName,name))!=0)
			{
					fwrite(&fcb[i],fcbSize,1,fp);
			}
		}

		parentInode->length-=1;
		fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+fileInode->iparent*inodeSize,SEEK_SET);
		fwrite(parentInode,inodeSize,1,fp);
		//update bitmap
		inodeBitmap[fileInodeNum]=0;
		blockBitmap[fileInode->blockNum]=0;

		//update superblock
		superBlock.blockFree+=1;
		superBlock.inodeFree+=1;
	}

	free(fileInode);
	free(parentInode);

}

void updateResource()
{
	rewind(fp);
	fwrite(&superBlock,superBlockSize,1,fp);
	fwrite(blockBitmap,blockBitmapSize,1,fp);
	fwrite(inodeBitmap,inodeBitmapSize,1,fp);
	fclose(fp);
}

void pathSet()
{
	PtrInode curInode=(PtrInode)malloc(inodeSize);
	fseek(fp,superBlockSize+blockBitmapSize+inodeBitmapSize+currentDir*inodeSize,SEEK_SET);
	fread(curInode,inodeSize,1,fp);
	printf("%s@localhost:%s#",curUser.userName,curInode->fileName);
	free(curInode);
}

void 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);
	printf("Free of inode number:%d\n",superBlock.inodeFree);
}

void help()
{
	printf("command: \n\
	help   ---  show help menu \n\
	sysinfo  --- show system base information \n\
	cls  ---  clear the screen \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\
	logout ---  exit user \n\
	rm     ---  delete a directory or a file \n\
	exit   ---  exit this system\n");
}

int analyse(char *str)
{
	int  i;
	char temp[20];
	char *ptr_char;
	char *syscmd[]={"help","ls","cd","mkdir","touch","cat","write","rm","logout","exit","sysinfo","cls"};
	argc = 0;
	for(i = 0, ptr_char = str; *ptr_char != '\0'; ptr_char++)
	{
		if(*ptr_char != ' ')
		{
			while(*ptr_char != ' ' && (*ptr_char != '\0'))
				temp[i++] = *ptr_char++;
			argv[argc] = (char *)malloc(i+1);
			strncpy(argv[argc], temp, i);
			argv[argc][i] = '\0';
			argc++;
			i = 0;
			if(*ptr_char == '\0')
				break;
		}
	}
	if(argc != 0)
	{
		for(i = 0; (i < 12) && strcmp(argv[0], syscmd[i]); i++);
			return i;
	}
	else
		return 12;
	return 0;
}

void login()
{
	char userName[10];
	char passWord[10];
	while(1)
	{
		printf("login:");
		gets(userName);
        system("stty -echo");
		printf("passwd:");
		gets(passWord);
		system("stty echo");
		printf("\n");
		if(strcmp(userName,curUser.userName)==0&&strcmp(passWord,curUser.passWord)==0)
			break;
	}
}

void stopHandle(int sig)
{
    printf("\nPlease wait...,update resource\n");
    updateResource();
    exit(0);
}

void command(void)
{
	char cmd[20];
	do
	{
		pathSet();
		gets(cmd);
		switch(analyse(cmd))
		{
			case 0:
				help();
				break;
			case 1:
				list();
				break;
			case 2:
				cd(argv[1]);
				break;
			case 3:
				createFile(argv[1],1);
				break;
			case 4:
				createFile(argv[1],0);
				break;
			case 5:
				read(argv[1]);
				break;
			case 6:
				write(argv[1]);
				break;
			case 7:
				delete(argv[1]);
				break;
			case 8:
				updateResource();
				login();
				openFileSystem();
                command();
				break;
			case 9:
				updateResource();
				exit(0);
				break;
			case 10:
				systemInfo();
				break;
            case 11:
                system("clear");
				break;
			default:
				break;
		}
	}while(1);
}

int main(int argc,char **argv){
    signal(SIGINT,stopHandle);
	login();
	openFileSystem();
	command();
	return 0;
}



          



2019-06-14 16:31:37 qq_38474647 阅读数 36

一、实验介绍

本次实验的内容是完成一个 UNIX文件系统的子集的模拟实现。

实验要求:

完成文件卷结构设计

I节点结构设计

目录结构

用户及组结构

文件树结构

实现功能如下命令:

6607861-4df08be9f6c3eba6

参考文档和完整的文档和源码下载地址:

https://www.write-bug.com/article/2384.html

2015-05-16 21:56:48 LINXURY 阅读数 4269


项目背景

完成一个 UNIX文件系统的子集的模拟实现。
1. 完成文件卷结构设计
2. I节点结构设计
3. 目录结构
4. 用户及组结构
5. 文件树结构
6. 实现功能如下命令:

Ls 显示文件目录
Chmod 改变文件权限
Chown 改变文件拥有者
Chgrp 改变文件所属组
Pwd 显示当前目录
Cd 改变当前目录
Mkdir 创建子目录
Rmdir 删除子目录
Umask 文件创建屏蔽码
Mv 改变文件名
Cp 文件拷贝
Rm 文件删除
Ln 建立文件联接
Cat 连接显示文件内容
Passwd 修改用户口令


开发环境

操作系统 :windows 7 64位
开发工具 :visual studio 2010
程序类型 :win32 控制台应用程序


分析

文件系统特特性

文件数据除了文件的实际内容外,通常还包含很多额外的属性,例如Linux操作系统的文件权限(RWX)与晚间属性(所有者、族群、时间参数等)。文件系统通常会将这两部分数据分别存放在不同的块,权限与属性放置到Inode中,至于时间数据则放置到Data Block中。另外,还有一个超级块 Superblock 会记录整个文件系统的整体信息,包括inode和block的总量、使用量、剩余量。

  • super block:记录此文件系统的整体信息,包括inode/block 的总量,使用情况、剩余量。以及文件系统的格式相关信息等;
  • inode:记录文件的属性,一个文件占用一个inode,同时记录此文件的数据所在的block的号码;
  • block:实际记录文件的内容,若文件太大的时候,会占用多个block

盘块的管理

位示图法

位示图是利用二级制的以为来表示磁盘的中有个盘块的使用情况。当其值为“0”时,表示对应的盘块空闲;为“1”的时,表示已经分配。

成组链接法

在UNIX系统中,将空闲块分成若干组,每100个空闲块为一组,每组的第一空闲块登记了下一组空闲块的物理盘块号和空闲块总数。如果一个组的第二个空闲块号等于0,则有特殊的含义,意味着该组是最后一组,即无下一个空闲块。

分配空闲块的时候,从前往后分配,先从第一组开始分配,第一组空闲的100块分完了,才进入第二组。

释放空闲块的时候正好相反,从后往前分配,先将释放的空闲块放到第一组,第一组满了,在第一组前再开辟一组,之前的第一组变成第二组。


设计

系统流程

系统流程图

程序开始执行后,程序会先将资源文件读取,并以一文件指针保存在全局变量virtualDisk中。
读取文件成功以后,通过文件指针访问超级块所在盘块,读取内容保存在全局变量super中。
加载超级块以后,程序通过iget操作获取到root节点,保存在全局变量root中。
接下来,进入登录界面,用户输入密码和口令,程序根据用户的输入,读取用户文件,判断是否登录成功,成功以后进入程序的主界面。


文件卷设计

这里写图片描述

本程序的模拟磁盘的大小是8MB,每个盘块的大小设定为1KB,共8192个盘块。其中0号盘块在本程序中没有使用,但保留了下来。1号盘块保存超级块的信息。2-911盘块保存的是finode节点的信息。从912盘块开始,都是存储文件内容的盘块,使用成组链接法来管理,每组的盘块数是20。关于结点等数据结构会在下面部分详细介绍。


数据结构设计

超级快数据结构

1#块为超级块(superblock)。磁盘的回收和索引结点的分配与回收,将涉及到超级块。超级块是专门用于记录文件系统中盘块和磁盘索引节点使用情况的一个盘块,其中含有以下各个字段:

  1. size :文件系统的盘块数。
  2. freeBlock:空闲盘块号栈,即用于记录当前可用的空闲盘块编号的栈。
  3. nextFreeBlock:当前空闲盘快号数,即在空闲盘块号栈中保存的空闲盘块号的数目。他也可以被视为空闲盘块号栈的指针。
  4. freeInode:空闲磁盘i结点编号栈,即记录了当前可用的素偶皮空闲结点编号的栈。
  5. nextFreeInode:空闲磁盘i结点数目,指在磁盘i结点栈中保存的空闲i结点编号的数目,也可以视为当前空闲i结点栈顶的指针。
  6. freeBlockNum:空闲盘块数,用于记录整个文件系统中未被分配的盘块个数。
  7. freeInodeNum:空闲i结点个数,用于记录整个文件系统中未被分配的节点个数。
  8. lastLogin:上次登录时间
struct supblock
{
    unsigned int size;                  //the size of the disk
    unsigned int freeBlock[BLOCKNUM];   //the stack of the free block
    unsigned int    nextFreeBlock;      //the pointer of the next free block in the stack
    unsigned int freeBlockNum;          //the totally number of the free block in the disk
    unsigned int freeInode[INODENUM];   //the stack of the free node
    unsigned int freeInodeNum;          //the totally number of the free inode in the disk
    unsigned int nextFreeInode;         //the next free inode in the stack
    unsigned int lastLogin;
};

结点数据结构

关于索引结点,本程序的主要由两种结构的定义,分别是内存索引结点和磁盘索引结点。
磁盘索引结点:
1. mode :文件类型及属性
2. fileSize :文件大小
3. fileLink :文件连接数
4. owner :所属用户名
5. group :所属用户组
6. modifyTime :修改时间
7. createTime :创建时间
8. addr :盘块地址数组

truct finode
{
    int             mode;
    long        int fileSize;
    int             fileLink;
    char            owner[MAXNAME];
    char            group[GROUPNAME];
    long        int modifyTime;
    long        int createTime;
    int             addr[6];
    char            black[45];              //留空,以备内容扩充时不会影响结构大小
};

内存索引结点:
内存索引结点是保存在内存中索引结点的数据结构,当文件第一次被打开时,文件的索引结点从模拟磁盘上读出,并保存在内存中,方便下一次文件的打开。
1. finode:磁盘索引结点结构,保存从磁盘读出的索引结点信息
2. parent:父级内存索引结点指针
3. inodeID:索引结点号

struct inode
{
    struct                      finode finode;
    struct                      inode *parent;
    unsigned short int          inodeID;                //the node id
    int                         userCount;                  //the number of process using the inode
};

文件目录项:

文件目录项由文件名和文件索引结点号组成。
1. directName:文件名或目录名
2. inodeID:文件索引结点号

struct direct
{
    char                    directName[DIRECTNAME];
    unsigned short int      inodeID;
};

目录数据结构

目录结构:
1. dirNum:目录数目
2. direct:目录项数组

struct dir
{
    int     dirNum;
    struct  direct direct[DIRNUM];
};

对于目录类,它的内容都是以dir结构保存在磁盘中的,并以dir结构读取。


代码实现

主函数

主函数中,最最核心的函数就是dispatch函数,它解析用户输入的指令,并解析出参数,调用用户需要的函数。其流程图如下:
这里写图片描述


核心函数

一下函数为整一个文件系统最最核心的功能,所有的操作都是建立在一下函数的基础上进行的:
1. 盘块读函数
int bread(void * _Buf,unsigned short int bno,long int offset,int size,int count=1)
该函数将指定的盘块号内容的读取到对应的数据结构中。

  1. 盘块写函数
    int bwrite(void * _Buf,unsigned short int bno,long int offset,int size,int count=1)

  2. 结点分配函数
    struct inode* ialloc()
    该函数的作用是为从超级块的空闲结点栈中取出一个新的结点,并 出示化该结点。其流程图如图所示。
    这里写图片描述

  3. 盘块分配函数
    int balloc()
    该函数的主要功能是从超级快的空闲盘块栈中取出一个空闲盘块号,若栈只剩一个空闲盘块,那么采用成组链接法,读取下一组的空闲盘块栈。函数流程图如图所示。
    这里写图片描述

  4. 盘块回收函数
    int bfree(int bno)
    该函数的主要功能是回收空闲盘块,若超级块中的空闲盘块栈未满,则回收盘块号入栈,若空闲盘块栈满,则将栈内容写到新回收的盘块上,清空栈,并将新的盘块号入栈。流程图如图。
    这里写图片描述

代码实现

点我点我

2007-06-10 14:12:00 qiaozhiwei 阅读数 3390

前几天,见到了这个题目,时间较紧,大概的做了一下,没有实现文件内容COPY,代码及文档见附件,上传的目的为抛砖引玉,如果有人做了更好的修改,请给我一份,谢谢!

一、题目: 模拟UNIX文件系统的设计及实现 
即:多用户、多目录的文件系统的设计------对模拟文件系统的管理
二、目的
通过OS子系统的设计、增强OS设计的技巧,达到提高解决实际OS的设计能力的提高。
三、内容
多用户的多级目录的文件系统设计。
四、要求
1. 多用户 :usr1,usr2,usr3,……,usr8 (1-8个用户)
2. 多级目录:可有多级子目录;
3. 具有login (用户登录)
4. 系统初始化(建文件卷、提供登录模块)
5. 文件的创建: create
6. 文件的打开:open
7. 文件的读:read
8. 文件的写:write
9. 文件关闭:close
10. 删除文件:delete
11. 创建目录(建立子目录):mkdir
12. 改变当前目录:cd
13. 列出文件目录:dir
14. 退出:logout 15. 文件内容拷贝
五、课程设计说明书的要求
1. 设计思想说明
2. 文件系统结构的说明
3. 数据结构的说明
4. 各模块的算法流程图
5. 程序清单:注意加注释(包含关键字、方法、变量等),在每个模块前加注释;
6. 使用说明书(即用户手册)(内容包含如何登录、退出、读、写、等操作说明)
7. 体会,建议 
 晕。。。上传不了附件。源码下载

2017-03-11 14:40:50 theonlytao 阅读数 370

点击打开链接获取源代码

一、实验介绍

本实验要求完成一个 UNIX文件系统的子集的模拟实现。实验的提示与要求:

(1)   文件卷结构设计

盘块管理采用成组链接法。

0#块可省略

I节点栈及空间为20项

块大小为512字节

卷盘块数大于100

I节点盘块数大于10块

(2)   I节点结构设计

文件大小

文件联接计数

文件地址

文件拥有者

文件所属组

文件权限及类别

文件最后修改时间

其中文件地址为六项:四个直接块号,一个一次间址,一个两次间址

(3)   目录结构

用16字节表示,其中14字节为文件名,2字节为I节点号

(4)   用户及组结构

用户信息中包括用户名、口令,所属组,用户打开文件表

(文件树结构应与用户相对应:有每个用户的HOME目录)

组信息中可只包含组名

(5)   文件树结构

除(4)要求外,适当考虑UNIX本身文件树结构

(6)   实现功能

ls                显示文件目录

chmod        改变文件权限

chown              改变文件拥有者

chgrp               改变文件所属组

pwd            显示当前目录

cd               改变当前目录

mkdir               创建子目录

rmdir                删除子目录

mv              改变文件名

cp               文件拷贝

rm              文件删除

ln              建立文件联接

cat              连接显示文件内容

passwd       修改用户口令

 

二、实验环境

操作系统    :windows7 64位

开发工具    :vc6.0

三、实验设计

3.1 系统流程


图3.1.1系统流程图

注释:命令执行完毕后将返回输入命令界面

文字说明:

      系统开始后进行初始化操作,首先判断模拟磁盘文件是否存在,不存在则初始化一个模拟磁盘,存在则读入超级块、用户、组,初始化当前目录。

      接着用户登录,登录成功后进入系统主界面,输入各项命令即可进行各项操作。

3.2 文件结构


图3.2.1文件卷结构

文字说明:

      模拟磁盘大小为200KB,每一个盘块大小为512字节,一共400个盘块,其中0号盘块预留,1号盘块为超级块,2~41号盘块为INode节点,42号~399号盘块为Block。

3.3 实现命令操作

本系统主要实现了以下命令:

ls               显示目录文件

chmod      改变文件权限

chown       改变文件拥有者

chgrp        改变文件所属组

pwd          显示当前目录

cd             改变当前目录

mkdir        创建子目录

rmdir         删除子目录

mv            改变文件名;

cp             文件拷贝

rm             文件删除

ln              建立文件联接

cat            连接显示文件内容

passwd      修改用户口令

touch        创建文件

>>            文本内容追加

注释:测试系统时为了校验特地加了sp命令:输出超级块内容

三、数据结构

3.1 超级块

SuperBlock结构体:

structsuperBlock  //超级块

{

      unsigned int size;  //磁盘大小

      unsigned int freeINodeNum; //空闲INode数

      unsigned int freeINode[INODE_NUM];   //空闲INode栈

      unsigned int nextFreeINode; //栈中下一个INode

      unsigned int freeBlockNum;  //空闲盘块数

      unsigned int freeBlock[BLOCK_GROUP_SIZE];     //空闲盘块栈

      unsigned int nextFreeBlock;  //栈中下一个盘块

};

文字说明:

      空闲INode栈和空闲盘块栈在形式上虽然表现为数组模式,但是通过nextFreeINode和nextFreeBlock的指向实现栈的弹出和弹入。当nextFreeBlock指向0且用户又申请盘块存储数据时,将通过读freeBlock[0]指向的盘块读入下一组盘块刷新freeBlock和nextFreeBlock。

3.2 磁盘iNode

dINode结构体:

structdINode //磁盘iNode

{

      unsigned int fileSize;  //文件大小

      unsigned int linkNum;     //文件的链接数

      unsigned int addr[6];  //文件地址:四个直接块号,一个一级间址,一个二级间址

      unsigned short ownerId;  //文件拥有者Id

      unsigned short groupId;  //文件所属组Id

      unsigned int mod;      //文件权限和类型

      long int createTime;   //文件创建时间

      long int modifyTime;  //文件最后修改时间

      long int readTime;           //文件最后访问时间

};

文字说明:

      fileSize不仅提供了计算文件地址的依据,也是控制数据读写的关键参数。

      linkNum为实现ln命令提供了方便,链接方和被链接方共享一个iNode,链接数也相应增加,进行删除命令删除一个链接文件时,只需使链接数减1并删除在父亲节点留下的目录信息即可,除非链接数为1时才真正删除该文件。

      ownerId为权限管理提供了依据。

      mod决定了文件的权限和类型:

dir=8,r=4,w=2,x=1

文件Mode

若要rwx属性则4+2+1=7

若要rw-属性则4+2=6

若要r-x属性则4+1=5

若要r--属性则4=4

若要-wx属性则2+1=3

若要-w-属性则2=2

若要--x属性则1=1

文件夹Mode

若要rw-属性则8+4+2=14

若要r--属性则8+4=12

若要-w-属性则8+2=10

3.3 内存iNode

iNode结构体:

structiNode    //内存iNode

{

      dINode dINode;

      iNode *parent;      //所属的目录i节点

      unsigned int nodeId;  //i节点Id

      unsigned int users;     //引用计数

};

文字说明:

      parent指针为cd ../操作提供了返回的路径。

3.4 目录

direct结构体:

structdirect    //目录项结构

{

      char name[MAX_NAME_SIZE];     //文件或目录的名字

      unsigned short iNodeId;  //文件或目录的i节点号

};

 

dir结构体:

structdir   //目录结构

{

      unsigned short dirNum;   //目录项数

      direct direct[MAX_DIRECT_NUM];     //目录项数组

      char padding[DIR_PADDING_SIZE];   //目录结构填充字符组

};

文字说明:填充字符为了使dir结构占512个字节方便读写。

3.5 用户

owner结构体:

structowner   //用户

{

      unsigned short ownerId;  //用户Id

      unsigned short groupId;  //组Id

      char ownerName[MAX_NAME_SIZE];      //用户名

      char ownerPassword[MAX_NAME_SIZE];//用户密码

};

 

owners结构体:

structowners  //用户组

{

      unsigned short ownerNum;   //用户项数

      owner os[MAX_OWNER_NUM];   //用户项组

};

3.6 用户组

group结构体:

structgroup    //组

{

      unsigned short groupId;  //用户组Id

      char groupName[MAX_NAME_SIZE];//组名

};

 

groups结构体:

structgroups  //组集合

{

      unsigned short groupNum;   //组数

      group gs[MAX_GROUP_NUM];

};

 

五、模块详解

5.1 文件操作

1.chgrp

1)     命令格式:

chgrp[组] [文件名]

2)     命令功能:

改变文件所属组

3)     命令参数:

[组]:用户组ID

[文件名]:文件名称

2.chown

1)     命令格式:

chown [用户][文件名]

2)     命令功能:

改变文件拥有者。

3)     命令参数:

[用户名]:用户ID

[文件名]:文件名称

3.chmod

1)     命令格式:

chmod [mod] [文件名]

2)     命令功能:

改变文件所属的权限和类型。

3)     命令参数:

[mod] 文件权限码

dir=8,r=4,w=2,x=1

文件mode

若要rwx属性则4+2+1=7

若要rw-属性则4+2=6

若要r-x属性则4+1=5

若要r--属性则4=4

若要-wx属性则2+1=3

若要-w-属性则2=2

若要--x属性则1=1

文件夹mode

若要rw-属性则8+4+2=14

若要r--属性则8+4=12

若要-w-属性则8+2=10

[文件名] 文件名称

4.cat

1)     命令格式:

cat [文件名]

2)     命令功能:

连接显示文件内容

5.cp

1)     命令格式:

cp [源] [目的]

2)     命令功能:

复制源文件到目的文件,若目的文件不存在则创建一个,若存在则目的文件被覆盖。

3)     命令参数:

[源]:源文件

[目的]:目的文件

6.touch

1)     命令格式:

touch [文件名]

2)     命令功能:

创建一个新的不存在文件

7.>> 

1)     命令格式:

>> [文件名]

2)     命令功能:

向已存在文件追加内容。(输入ctrl+q,回车结束输入)

8.mv

1)     命令格式:

mv [文件] [新文件名]

2)命令功能:

      更改文件的文件名。

9.rm

2)     命令格式:

rm [文件]

2)命令功能:

      文件删除。

10.ln

3)     命令格式:

mv [源] [目的]

2)命令功能:

      将源文件链接到目的文件。

 

 

5.2目录操作

1.     ls

1)     命令格式:

ls

2)     命令功能:

打印出当前目录清单。

2.     pwd

1)     命令格式:

pwd

2)     命令功能:

查看当前目录路径。

3.     cd

1)     命令格式:

cd [目录名]

2)     命令功能:

改变当前目录。

4.     mkdir

1)     命令格式:

mkdir [目录名]

2)     命令功能:

在当前目录下创建子目录。

5.     rmdir

1)命令格式:

rmdir [目录名]

2)命令功能:

删除指定目录和该目录下所有内容。

6.     ln

1)命令格式:

ln   [源] [目的]

2)命令功能:

      将源目录链接到目标目录。

 

5.3核心函数

核心函数表

函数名

描述

void initGlobal(FILE* f);

初始化全局变量、超级块、用户、用户组和成组链接信息(均写入磁盘),仅当模拟磁盘文件不存在时调用

void initSystem();

初始化文件系统:读入超级块、用户、用户组、当前目录

bool readINode(iNode* r);

读取磁盘INode信息,成功返回true,失败返回false

bool writeINode(iNode* w);

写入磁盘INode信息,成功返回true,失败返回false

bool writeSuperBlock();

写入超级块信息,成功返回true,失败返回false

bool writeDir(unsigned int blockId,dir* d);

写入目录结构,成功返回true,失败返回false

bool readDir(unsigned int blockId,dir* d);

读取目录结构,成功返回true,失败返回false

bool readNextBG();

读取下一组盘块组信息,,成功返回true,失败返回false

int mkdir(iNode* parent,char name[MAX_NAME_SIZE]);

创建目录,返回状态码

int getFreeBlock();

获取空闲盘块,成功返回空闲盘块号,失败返回状态码

int getFreeINode();

获取空闲INode节点,成功返回空闲INode节点,失败返回状态码

int login();

登录,返回状态码

void commandDispatcher();

命令分派器

void displayCommands();

显示所有命令

string pwd();

返回当前路径字符串

string trim(string s);

去除字符串两侧空格

int readCurDir();

读取当前目录,返回状态码

string ls();

返回当前目录清单字符串

bool checkFileName(char name[MAX_NAME_SIZE]);

检查当前目录下是否存在该名字,存在返回true,不存在返回false

int cd(char name[MAX_NAME_SIZE]);

改变当前目录,返回状态码

int superMkdir(iNode* parent,char name[MAX_NAME_SIZE],unsigned short ownerId,unsigned short groupId);

创建用户目录,返回状态码

int chmod(char name[MAX_NAME_SIZE],unsigned int mod);

改变文件权限,返回状态码

int chown(char name[MAX_NAME_SIZE],unsigned short ownerId);

改变文件拥有者,返回状态码

int chgrp(char name[MAX_NAME_SIZE],unsigned short groupId);

改变文件所属组,返回状态码

int passwd();

更改当前用户密码,返回状态码

bool writeOS();

写入用户组信息,成功返回true,失败返回false

int mv(char oldName[MAX_NAME_SIZE],char newName[MAX_NAME_SIZE]);

修改文件名,返回状态码

int touch(iNode* parent,char name[MAX_NAME_SIZE]);

创建新文件,返回状态码

int writeText(iNode* temp,string text);

写入文件内容,返回状态码

int textAppend(char name[MAX_NAME_SIZE]);

文件内容追加操作,返回状态码

int cat(char name[MAX_NAME_SIZE]);

显示文件内容,返回状态码

int readText(iNode *temp);

读取文件内容,返回状态码

int rm(char name[MAX_NAME_SIZE]);

删除文件,返回状态码

int returnFreeBlock(unsigned int blockId);

回收空闲盘块,返回状态码

int returnFreeINode(unsigned int iNodeId);

回收空闲INode节点,返回状态码

int ln(char source[MAX_NAME_SIZE],char des[MAX_NAME_SIZE]);

链接源文件至目标文件,返回状态码

void rmIter(unsigned short iNodeId);

迭代删除目录下所有内容(即级联删除)

int rmdir(char name[MAX_NAME_SIZE]);

删除目录操作,返回状态码

int cp(char source[MAX_NAME_SIZE],char des[MAX_NAME_SIZE]);

复制源文件至目标文件,返回状态码

string getText(iNode* temp);

获取文件内容字符串

 


显示

阅读数 244

没有更多推荐了,返回首页