实验四 文件系统 实验报告

实验四 文件系统 实验报告
实验四 文件系统 实验报告

文件系统实验报告

一、实验目的

了解操作系统中文件系统的原理以及实现方法。

二、实验方法

通过FAT12文件系统的解读,了解文件系统的原理和实现。

三、实验任务

通过对FAT12文件系统的了解,编写程序,读取并列出一个虚拟软盘中文件信息(文件名、属性、修改时间等),以及读取其中的文件内容

四、实验要点

FAT12文件系统的了解,Linux系统下文件读写相关系统调用。

五、实验过程

1. FAT12 文件系统分析

簇是操作系统分配文件空间的基本单位,簇由若干个扇区组成。在FAT12文件系统中,簇号的有效位是12位,所以这种文件系统就被称为FAT12。FAT12

其中,引导区中储存着一些基本的信息。例如,0x0000000B和0x0000000C 两个字节保存着每个扇区的大小,0x0000000D保存着每个簇占用多少个扇区。

FAT区中储存着簇号。在0x00000200开始的三个字节,分别储存设备类型标记(0xF0为软盘);第二个第三个字节均为0xFF,是FAT标识符。在FAT12

文件系统中,每个簇占用12位,即1.5个字节。簇号与地址的对应关系如下

表:

然后对读出的两个字节进行位运算处理,得到下一簇的簇序号。

注意,这里同样需要对高低位进行处理,即使用位计算的方式提取相应的簇号信息。

根据上述的原理,可以得出一个函数,以一个簇号为参数,返回值为文件下一个簇号。代码如下:

int getNextClutserId(FILE *fp, short clusterId)

{

unsigned short tmp, low = 0, high = 0;;

int address = (clusterId * 3 / 2) + 0x0000200;

fseek(fp, address, SEEK_SET);

fread((void *)(&tmp), 1, sizeof(unsigned short), fp);

low = ((tmp & 0xFFF0) >> 4);

high = tmp & 0x0FFF;

return (clusterId % 2 == 0 ? high : low);

}

其中,fp 是用于读取文件系统的文件流,clusterID是当前簇号,返回值是下一个簇号。

函数体的第二句代码,计算出当前簇号对应的地址,用于文件指针的定位。第三句代码是根据第二句计算得到的地址对文件指针进行定位,定位到当前簇号所对应的信息处。第四句代码是从文件指针的位置为起始位置读入两个字节的内容(fread会自动对高低字节位进行处理)。并把这两个字节的信息储存到tmp变量之中。例如,读取002簇号的下一个簇号,根据公式,计算得到的address是0x00000203,读取到0x00000203和0x00000204两个字节的内容。我们需要的是0x00000203整个字节的内容和0x00000204的高四位,所以需要跟0xFFF0进行位与运算,并向右移四位,得到下一个簇号。

同样地,读取003簇号的下一个簇号,根据公式,计算得到的address是0x00000204,读取到0x00000204和0x00000205两个字节的内容,我们需要的是0x00000205整个字节的内容和0x00000204第四位的内容,所以需要跟0x0FFF进行位与运算,得到下一个簇号。所以代码中需要对簇号的奇偶性进行判断,跟根据奇偶性的不同返回不同的值。

在根目录中,保存着根目录下面的文件或文件夹的信息。每个文件或者文件夹的信息使用32个字节保存。这些内容的含义如下表:

文件的大小不能超过232字节,也就是4G;文件名和扩展名采用了固定长度,分别为8和3,太长的文件名在FAT中是不允许的。

其中,文件名的第一个字节还有其他的意义,例如,当文件名的第一个字节为0x00时,表示这一项没有文件;为0xE5时,则表示这个文件已经被删除,在编码时应该忽略这个文件。

文件的属性采用一个字节,也就是8个位来表示文件的6种属性,最高两

得出相应的属性值,根据上表,可以得出一个函数,参数是表示文件属性的那个字节,返回值是一个以字符方式显示文件属性的一个字符串

char *formatAttribute(char attribute)

{

char *result = (char *)malloc(sizeof(char)* 7);

result[0] = ((attribute & 0x01) == 0x01) ? 'r' : '-';

result[1] = ((attribute & 0x02) == 0x02) ? 'h' : '-';

result[2] = ((attribute & 0x04) == 0x04) ? 's' : '-';

result[3] = ((attribute & 0x08) == 0x08) ? 'l' : '-';

result[4] = ((attribute & 0x10) == 0x10) ? 'd' : '-';

result[5] = ((attribute & 0x20) == 0x20) ? 'f' : '-';

result[6] = '\0';

return result;

}

因为文件属性有6种,需要6个字符分别存放六种属性,第7位则用于储存字符串的结束标记’\0’,确保输出的时候不会产生乱码。

这个函数代码是通过位与运算对文件的各个属性进行判断,并在相应的字符位用字符或者’-’填充,最后把字符串返回。

时间和日期都采用的是压缩储存,储存时间两个字节的各位含义如下:

注:日期和时间都需要对高低字节进行交换然后再读取。实验中使用fread 方法会自动进行交换。

根据上面的原理,可以得出这样的一个函数,这个函数以表示日期和时间的两个原始值作为参数输入,返回的是一个格式形如”xxxx-xx-xx xx:xx:xx”的字符串,这个函数的代码如下:

char *formatDatetime(short date, short time)

{

int year, month, day, hour, minute, second;

char *result = (char *)malloc(sizeof(char)* 20);

year = 1980 + ((date & 0xE000) >> 9);

month = ((date & 0x01E0) >> 5);

day = (date & 0x001F);

hour = ((time & 0xF800) >> 11);

minute = ((time & 0x07E0) >> 5);

second = ((time & 0x001F) << 1);

sprintf(result, "%d-%d%d-%d%d %d%d:%d%d:%d%d",

year, month / 10, month % 10, day / 10, day % 10,

hour / 10, hour % 10, minute / 10, minute % 10,

second / 10, second % 10);

return result;

}

函数的第一句,第二句是为函数运行过程中需要临时储存的数据分配储存空间,随后就是根据上述的原理,进行位与运算和移位操作,得到各项的时间

属性。最后通过sprintf函数对各个属性按照固定的格式输出到字符串之中并返回。

首簇号,指的是这个文件储存在磁盘的第一个簇的簇号,也就是文件存放的具体地址。同样地,需要对簇号的两个字节进行高低位交换。

最后一个是文件大小,需要对四个字节进行高低字节交换,得到文件大小。

在实验中,会通过read函数每次读入32个字节,即读取FAT表中的每一项,在输出文件信息时予以分析。

另外,每个目录中都包含两个虚拟目录,文件名分别为’.’和’..’,分别表示当前目录和上一级目录。在目录的处理时需要对其进行判断,避免在进行子目录迭代显示时进入死循环。综上所述,可以得出从文件段中读出文件信息的源码。下面的是一些在读取过程中所使用的一些数据结构:

struct file_info {

char filename[8];

char extname[3];

char attributes;

char reserved[10];

short time;

short date;

short pos;

int size;

};

上面是表示文件信息原始信息的结构体,每个成员变量对应一个属性。

struct file_info_node {

int id;

struct file_info *info;

struct file_info_node *next;

};

这个文件信息链表的结点,相应地,在实验中定义了file_list_new_info方法,将文件信息添加到链表之中。

同时,为了避免递归调用,在实验中,通过一个队列的方式实现列出所有子目录文件的功能。

在下面代码中,content_char是一个指向储存上述文件结构的指针,content->size是file_content中表示文件大小的一个整型变量,用于计算文件夹中最大文件数量,newInfo是一个file_info结构体的指针,用于储存读取到的文件信息原始值。

先把一个文件信息的原始信息从文件内容中提取出来,为此,可以实现内存复制的函数,代码如下:

int copyTo(void *desc, void *src, int size)

{

int counter = 0, i;

for (i = 0; i < size; i++, counter++)

*(char *)(((char *)desc) + i) = *(char *)(((char *)src) + i);

return counter;

}

通过这个函数把文件信息的原始信息复制到newInfo之中。

上述的文件夹结构不仅仅适用于根目录,所有的目录的遵循这种格式,所以这里可以得出一个初步的结论:文件夹是一种特殊的文件。

if (newInfo->filename[0] != (char)0xE5 && newInfo->filename[0] != (char)0x00) { file_list_new_info(newInfo, &newId, &newInfoNode);

if ((newInfo->attributes & 0x10) == 0x10)

{

if (newInfo->filename[0] == '.') continue;

char *buffer = (char *)malloc(sizeof(char)* 9);

int j;

for (j = 0; j < 8 && newInfo->filename[j] != (char)0x20; j++)

{

buffer[j] = newInfo->filename[j];

}

buffer[j] = '\0';

queue_new_task(buffer, 0, 0, newInfo->pos);

}

这是放在一个for循环中的代码,先通过文件名判断这个文件是否存在,如果存在,则把文件信息添加到程序的文件信息链表之中。再则判断是否是目录,如果是目录,则把这个目录添加到队列之中。

2.文件储存方式

FAT文件系统对空间的分配和管理是以簇为基本单位的。所以,一个逻辑上连续的文件可能会被分散地储存在磁盘的各个位置。操作系统输出文件时,遵循下面的步骤:

1. 会先通过文件夹信息找到文件首簇号。

2. 根据文件的首簇号,定位到FAT区相应位置;读出下一个簇的簇号。

3. 如果下一个簇的簇号不是结束标记(0xFFF),则会根据读出的下一个簇

号定位,读出簇里面的内容。如果读出的是结束标记,则表示文件已经读

取完成。

假如一个文件被分散储存在0x012,0x022,0x302三个簇里。从目录的信息中读出首簇号0x012,读出0x012簇里的内容;然后再通过0x012这个簇号在FAT区中找到下一个簇号0x022,读出0x022的内容;再通过0x022这个簇号找到下一个簇号0x302,读出0x302中的内容;再通过0x302读出下一个簇号的内容,此时,读出的簇号为0xFFF,即表示这个文件已经结束。

本实验中,读取文件的具体实现方法如下:

1. 通过一个链表,将这个文件的所有簇号储存起来。

2. 遍历储存簇号的链表,逐个逐个簇读取出来并储存到内存之中,返回之。

下面是读取文件的实现所需要的一些数据结构:

struct int_linked_list {

int data;

struct int_linked_list *next;

};

struct file_content {

struct int_linked_list *curList;

void *content;

int size;

char *filename;

};

其中,int_linked_list是一个储存整型的链表,file_content是一个用于保存读出文件内容和文件信息的结构体。

遍历链表的过程中,通过一个while循环实现,把读取到簇号添加到链表之中。具体实现代码如下,tail为保存簇号链表的末尾结点指针,fp是用于读

取文件的文件指针,curConnt是一个用于统计文件簇数的变量,便于后续步骤

分配内存空间使用,下文同:

while ((clusterId = getNextClutserId(fp, clusterId)) != 0x00000FFF)

{

curCount++;

tail->next = (struct int_linked_list *)malloc(sizeof(struct int_linked_list));

tail->next->data = clusterId;

tail->next->next = NULL;

tail = tail->next;

}

把簇号读取完毕以后,开始对文件内容进行读取,下面是文件内容读取的具体实现代码,下面代码中的content是一个指向用于存放文件内容的内存空

间的指针变量:

content->size = curCount * 512;

content->content = malloc(content->size);

struct int_linked_list *ptr = head;

int i = 0, address = 0xFFFFFFF;

for (ptr = head; ptr != NULL; ptr = ptr->next, i++)

{

address = 0x00003E00 + (512 * ptr->data);

fseek(fp, address, SEEK_SET);

fread((void *)(((char *)(content->content)) + (512 * i)), 512, 1, fp);

}

在for循环的第一句代码之中,通过簇号对簇所在的地址进行计算,把地址值储存到address变量之中;第二句代码则是通过上一步计算得到的address

变量对文件指针进行定位,第三句是通过fread方法把文件内容读入到内存之

中。

六、实验结论

1. FAT12文件系统中,把磁盘划分成引导区、FAT区、FAT备份区、根目录

区和文件数据区。

2. 除了根目录以外,文件系统把每个文件夹都当成是一个特殊的文件进

行处理。

3. FAT12文件系统通过簇进行空间的管理和分配。

七、完整实验代码

/*

* 操作系统课程实验

* FAT12 文件系统实验代码

*

* 虽然这个程序在Windows 和Linux 环境下都能运行。

* 不过,在Windows 环境下运行的话,显示文件内容的时候,内容的末尾会有几个奇怪的字符。

* Linux 环境下完全没问题

* 暂时推测是Windows 控制台的原因,Windows 控制台会把一些非字符的ASCII 显示为奇怪的字符,

* 例如,0x0A 会显示成一个笑脸,Linux 的控制台下不会对这些非字符的ASCII 进行处理

*

* 我是今天早上才发现这个问题的阿(╯‵□′)╯︵┻━┻

*

* 注意:编译前,需要把IMAGE_FILE 那个宏定义改成公邮上面的那个IMG 文件;

* Linux 下打开这个源码文件注释会变成乱码

*

*/

// 这个定义只是为了程序能在VS2013 下面正常编译而已

#ifdef _WIN32

#define _CRT_SECURE_NO_WARNINGS

#endif

#include

#include

#include

#ifdef _WIN32

#include

#endif

#define OK 0x00000000

#define MESSAGE_FILE_NOT_FOUND 0xE0000404

#define ERROR_MALLOC_FAILED 0xF0000001

#define ERROR_IO_ERROR 0xF0000002

// ↓这里改路径↓

#define IMAGE_FILE "/home/user/DOS622.IMG"

// ↑这里改路径↑

/******************** 这里是结构体的定义**************************/

// 这里是文件信息

struct file_info {

char filename[8];

char extname[3];

char attributes;

char reserved[10];

short time;

short date;

short pos;

int size;

};

struct file_info_node {

int id;

struct file_info *info;

struct file_info_node *next;

};

// 这里是储存文件夹信息

struct folder_info {

char *filename;

int fileBeginIndex, fileEndIndex;

struct file_info_node *beginFile, *endFile;

struct folder_info *next;

};

// 这里是一个队列,用于迭代方式遍历文件系统的一个中间变量

struct queue_info {

char *filename;

int offset, size, cluster;

struct queue_info *next;

};

// 一个整数链表结构

struct int_linked_list {

int data;

struct int_linked_list *next;

};

// 这里是一个文件结构,表示内容,可以读取文件的其中一段,也可以通过簇的方式完整读入整个文件

struct file_content {

struct int_linked_list *curList;

void *content;

int size;

char *filename;

};

/******************** 这里是全局变量的定义**************************/ struct file_info_node *file_list_head, *file_list_tail;

struct folder_info *folder_info_head, *folder_info_tail;

struct queue_info *queue_head, *queue_tail;

char decToHex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

/******************** 这里是函数的定义**************************/

int file_list_init();

int file_list_new_info(struct file_info *info, int *id, struct file_info_node **newInfoNode);

int folder_info_init();

int folder_info_new_info(struct folder_info *info);

int queue_init();

int queue_new_task(char *filename, int offset, int size, int cluster);

struct queue_info *queue_get_task();

int process_task(struct queue_info* info);

struct file_content* readContentFromFixedSection(FILE *fp, int offset, int size);

struct file_content* readContentFromCluster(FILE *fp, short clusterId, int isFolder, int *size); struct file_content* find_file_by_id(FILE *fp, int id, int *errCode);

int process_file_content(struct file_content* content, struct queue_info *info);

int getNextClutserId(FILE *fp, short clusterId);

int copyTo(void *desc, void *src, int size);

void print_all_list();

void print_file_content(struct file_content *content);

char *formatIndex(int i);

char *formatClustNo(int i);

char *formatFileName(char *filename, char *ext);

char *formatAttribute(char attribute);

char *formatDatetime(short date, short time);

char *formatSize(int size, int rightAlign);

/******************** 主函数**************************/

int main(int argc, char **args)

{

struct queue_info *task = NULL;

int choose, status;

FILE *fp = fopen(IMAGE_FILE, "r");

struct file_content *content;

char tmp;

if (fp == NULL)

{

return 1;

}

getNextClutserId(fopen(IMAGE_FILE, "r"), 2);

queue_init();

queue_new_task("Root", 0x00002600, 6144, 0);

while ((task = queue_get_task()) != NULL)

{

process_task(task);

}

print_all_list();

fflush(stdin);

printf("\nThe Number of File you want to view (enter -1 to exit): ");

scanf("%d", &choose);

content = find_file_by_id(fp, choose, &status);

if (status == MESSAGE_FILE_NOT_FOUND)

{

printf("Invaild Number, please input again!\n");

return 0;

}

else

{

if (content != NULL)

{

print_file_content(content);

}

}

return 0;

}

int process_task(struct queue_info* info)

{

FILE *fp;

struct file_content* content = NULL;

int size = 0;

fp = fopen(IMAGE_FILE, "r");

if (fp == NULL)

{

return ERROR_IO_ERROR;

}

// 判断是否对根目录进行读取

if (info->offset == 0x00002600)

{

content = readContentFromFixedSection(fp, info->offset, info->size);

}

else

{

content = readContentFromCluster(fp, info->cluster, 1, &size);

info->size = size;

}

process_file_content(content, info);

fclose(fp);

return OK;

}

int process_file_content(struct file_content* content, struct queue_info *info)

{

struct folder_info *node = (struct folder_info *)malloc(sizeof(struct folder_info));

struct file_info *newInfo = NULL;

struct file_info_node *newInfoNode = NULL;

char *content_char = (char *)content->content;

int newId = -1, fileCount = 0;

if (node == NULL)

{

return ERROR_MALLOC_FAILED;

}

node->filename = info->filename;

// 根据大小计算目录中的文件数量

int maxFile = content->size / 32, i;

for (i = 0; i < maxFile; i++)

{

newInfo = (struct file_info *)malloc(sizeof(struct file_info));

if (newInfo == NULL)

{

printf("malloc failed!\n");

return ERROR_MALLOC_FAILED;

}

copyTo((void *)newInfo, (void *)(content_char + (32 * i)), 32);

if (newInfo->filename[0] != (char)0xE5 && newInfo->filename[0] != (char)0x00) { file_list_new_info(newInfo, &newId, &newInfoNode);

if ((newInfo->attributes & 0x10) == 0x10)

{

if (newInfo->filename[0] == '.')

{

continue;

}

char *buffer = (char *)malloc(sizeof(char)* 9);

int j;

for (j = 0; j < 8 && newInfo->filename[j] != (char)0x20; j++)

{

buffer[j] = newInfo->filename[j];

}

buffer[j] = '\0';

queue_new_task(buffer, 0, 0, newInfo->pos);

}

if (0 == fileCount)

{

node->fileBeginIndex = newId;

node->beginFile = newInfoNode;

}

fileCount++;

}

}

node->fileEndIndex = file_list_tail->id;

node->endFile = file_list_tail;

folder_info_new_info(node);

return OK;

}

int copyTo(void *desc, void *src, int size)

{

int counter = 0, i;

for (i = 0; i < size; i++, counter++)

{

*(char *)(((char *)desc) + i) = *(char *)(((char *)src) + i);

}

return counter;

}

int file_list_init()

{

file_list_head = NULL;

file_list_tail = NULL;

return OK;

}

int file_list_new_info(struct file_info *info, int *id, struct file_info_node **newInfoNode)

{

struct file_info_node *newNode = (struct file_info_node*)malloc(sizeof(struct file_info_node));

if (newNode == NULL)

{

return ERROR_MALLOC_FAILED;

}

newNode->info = info;

newNode->next = NULL;

if (file_list_head == NULL)

{

newNode->id = 1;

file_list_head = newNode;

file_list_tail = newNode;

}

else

{

newNode->id = file_list_tail->id + 1;

file_list_tail->next = newNode;

file_list_tail = newNode;

}

*newInfoNode = newNode;

*id = newNode->id;

return OK;

}

int folder_info_init()

{

folder_info_head = folder_info_tail = NULL;

return OK;

}

int folder_info_new_info(struct folder_info *info) {

if (info == NULL)

{

return OK;

}

if (folder_info_head == NULL)

{

info->next = NULL;

folder_info_head = info;

folder_info_tail = info;

}

else

{

info->next = NULL;

folder_info_tail->next = info;

folder_info_tail = info;

}

return OK;

}

int queue_init()

{

queue_head = queue_tail = NULL;

return OK;

}

int queue_new_task(char *filename, int offset, int size, int cluster)

{

struct queue_info *newNode = (struct queue_info *)malloc(sizeof(struct queue_info));

if (newNode == NULL)

{

return ERROR_MALLOC_FAILED;

}

newNode->filename = filename;

newNode->offset = offset;

newNode->size = size;

newNode->cluster = cluster;

newNode->next = NULL;

if (queue_head == NULL)

{

queue_head = queue_tail = newNode;

}

else

{

queue_tail->next = newNode;

queue_tail = newNode;

}

return OK;

}

struct queue_info *queue_get_task()

{

struct queue_info *retValue = queue_head;

if (queue_head == NULL)

{

return NULL;

}

if (queue_head == queue_tail)

{

queue_tail = NULL;

}

queue_head = queue_head->next;

retValue->next = NULL;

return retValue;

}

struct file_content* readContentFromFixedSection(FILE *fp, int offset, int size)

{

if (fp == NULL)

{

return NULL;

}

struct file_content *retValue = (struct file_content *)malloc(sizeof(struct file_content));

if (retValue == NULL)

{

return NULL;

}

retValue->curList = NULL;

retValue->size = size;

retValue->content = malloc(size);

if (retValue->content == NULL)

{

free(retValue);

return NULL;

}

fseek(fp, offset, SEEK_SET);

fread(retValue->content, size, 1, fp);

return retValue;

}

struct file_content* readContentFromCluster(FILE *fp, short clusterId, int isFolder, int *size) {

int curCount = 1;

struct file_content *content = (struct file_content *)malloc(sizeof(struct file_content));

if (content == NULL)

{

return NULL;

}

// 第一步:迭代寻找所有簇号

content->curList = (struct int_linked_list *)malloc(sizeof(struct int_linked_list)); if (content->curList == NULL)

{

return NULL;

}

struct int_linked_list *head = content->curList, *tail = head;

head->data = clusterId;

head->next = NULL;

while ((clusterId = getNextClutserId(fp, clusterId)) != 0x00000FFF)

{

curCount++;

tail->next = (struct int_linked_list *)malloc(sizeof(struct int_linked_list));

tail->next->data = clusterId;

tail->next->next = NULL;

tail = tail->next;

}

// 第二步:开始根据簇号读取

content->size = curCount * 512;

content->content = malloc(content->size);

struct int_linked_list *ptr = head;

int i = 0, address = 0xFFFFFFF;

for (ptr = head; ptr != NULL; ptr = ptr->next, i++)

{

address = 0x00003E00 + (512 * ptr->data);

fseek(fp, address, SEEK_SET);

fread((void *)(((char *)(content->content)) + (512 * i)), 512, 1, fp);

}

if (size != NULL)

{

*size = content->size;

}

return content;

}

struct file_content* find_file_by_id(FILE *fp, int id, int *errCode)

{

if (id < 1)

{

*errCode = MESSAGE_FILE_NOT_FOUND;

return NULL;

}

// 先遍历目录寻找这个文件

struct folder_info *ptr = folder_info_head;

struct file_info_node *node = NULL, *tmp = NULL;

struct file_content *content = NULL;

while (ptr != NULL)

{

if (ptr->fileBeginIndex <= id && id <= ptr->fileEndIndex)

{

for (tmp = ptr->beginFile; tmp->id != id && id <= ptr->fileEndIndex; tmp = tmp->next);

if (tmp->id == id)

{

node = tmp;

break;

}

}

else

{

ptr = ptr->next;

}

}

*errCode = (node == NULL ? MESSAGE_FILE_NOT_FOUND : OK);

if (node != NULL)

{

content = readContentFromCluster(fp, node->info->pos, 0, NULL);

content->size = node->info->size;

content->filename = formatFileName(node->info->filename, node->info->extname);

}

return (node == NULL ? NULL : content);

}

int getNextClutserId(FILE *fp, short clusterId)

{

if (clusterId == 0x000000A0)

{

printf("");

}

unsigned short tmp;

int address = (clusterId * 3 / 2) + 0x0000200;

unsigned short low = 0, high = 0;

fseek(fp, address, SEEK_SET);

fread((void *)(&tmp), 1, sizeof(unsigned short), fp);

low = ((tmp & 0xFFF0) >> 4);

high = tmp & 0x0FFF;

return (clusterId % 2 == 0 ? high : low);

}

void print_all_list() {

struct folder_info *ptr = folder_info_head;

struct file_info_node *node;

int index;

#ifdef _WIN32

system("cls");

#else

printf("\033[2J");

#endif

for (; ptr != NULL; ptr = ptr->next)

{

int count = 0, totalSize = 0;

printf("--------------------------------------------------------------------------\n");

printf(" Folder : %s\n", ptr->filename);

printf("--------------------------------------------------------------------------\n");

printf(" Num | File Name | Type | CLUSTNO | File Change Time | Size \n");

printf("--------------------------------------------------------------------------\n");

index = ptr->fileBeginIndex;

node = ptr->beginFile;

while (node != NULL && node->id <= ptr->fileEndIndex)

{

// 只是实现不同平台下的变色操作

#ifdef _WIN32

HANDLE hOut;

hOut = GetStdHandle(STD_OUTPUT_HANDLE);

SetConsoleTextAttribute(hOut,

((node->info->attributes & 0x10) == 0x10) ?

FOREGROUND_GREEN : (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED));

#else

printf(((node->info->attributes & 0x10) == 0x10) ? "\033[32m" : "\033[0m");

#endif

printf(" %s | %s | %s | %s | %s | %s\n",

formatIndex(node->id), formatFileName(node->info->filename, node->info->extname),

formatAttribute(node->info->attributes), formatClustNo(node->info->pos),

formatDatetime(node->info->date, node->info->time),

((node->info->attributes & 0x10) == 0x10) ? "

" : formatSize(node->info->size, 1));

totalSize += node->info->size;

count++;

node = node->next;

}

printf("--------------------------------------------------------------------------\n");

printf(" %d Files, %s\n", count, formatSize(totalSize, 0));

}

}

void print_file_content(struct file_content *content)

{

if (content == NULL)

{

return;

}

printf("--------------------------------------------------------------------------\n");

printf(" File Content : %s\n", content->filename);

printf("--------------------------------------------------------------------------\n");

文件系统实验报告

嵌入式系统实验报告(二) --嵌入式文件系统的构建 138352019陈霖坤一实验目的 了解嵌入式操作系统中文件系统的类型和作用 了解JFFS2文件系统的优点及其在嵌入式系统中的作用 掌握利用Busybox软件制作嵌入式文件系统的方法 掌握嵌入式linux文件系统的挂载过程 二实验内容与要求 编译BusyBox,以BusyBox为基础,构建一个适合的文件系统; 制作ramdisk文件系统映像,用你的文件系统启动到正常工作状态; 研究NFS作为根文件系统的启动过程。 三Busybox介绍 BusyBox最初是由Bruce Perens在1996年为Debian GNU/Linux安装盘编写的,其原始构想是希望在一张软盘上能放入一个开机系统,以作为急救盘和安装盘。后来它变成了嵌入式Linux设备和系统和Linux发布版安装程序的实质标准,因为每个Linux可执行文件需要数Kb的空间,而集成两百多个程序的BusyBox可以节省大量空间。Busybox集成了包括mini-vi编辑器、/sbin/init、文件操作、目录操作、系统配置等应用程序。 Busybox支持多种体系结构,可以选择静态或动态链接,以满足不同需要。 四linux文件系统 文件系统是对一个存储设备上的数据和元数据进行组织的机制,linux文件系统接口设计为分层的体系结构,从而将用户接口层、文件系统实现层和操作存储设备的驱动程序分隔开。 在文件系统方面,linux可以算得上操作系统中的“瑞士军刀”。Linux支持许多种文件系统,从日志型文件系统到集群文件系统和加密文件系统,而且对于使用标准的和比较奇特的文件系统以及开发文件系统来说,linux是极好的平台,这得益于linux内核中的虚拟文件系统(VFS,也称虚拟文件系统交换器)。 文件结构 Windows的文件结构是多个并列的树状结构,不同的磁盘分区各对应一个树。Linux的文件结构是单个的树,最上层是根目录,其它目录都从根目录生成。不同的linux发行版集

操作系统实验报告--实验一--进程管理

实验一进程管理 一、目的 进程调度是处理机管理的核心内容。本实验要求编写和调试一个简单的进程调度程序。通过本实验加深理解有关进程控制块、进程队列的概念,并体会和了解进程调度算法的具体实施办法。 二、实验内容及要求 1、设计进程控制块PCB的结构(PCB结构通常包括以下信息:进程名(进程ID)、进程优先数、轮转时间片、进程所占用的CPU时间、进程的状态、当前队列指针等。可根据实验的不同,PCB结构的内容可以作适当的增删)。为了便于处理,程序中的某进程运行时间以时间片为单位计算。各进程的轮转时间数以及进程需运行的时间片数的初始值均由用户给定。 2、系统资源(r1…r w),共有w类,每类数目为r1…r w。随机产生n进程P i(id,s(j,k),t),0<=i<=n,0<=j<=m,0<=k<=dt为总运行时间,在运行过程中,会随机申请新的资源。 3、每个进程可有三个状态(即就绪状态W、运行状态R、等待或阻塞状态B),并假设初始状态为就绪状态。建立进程就绪队列。 4、编制进程调度算法:时间片轮转调度算法 本程序用该算法对n个进程进行调度,进程每执行一次,CPU时间片数加1,进程还需要的时间片数减1。在调度算法中,采用固定时间片(即:每执行一次进程,该进程的执行时间片数为已执行了1个单位),这时,CPU时间片数加1,进程还需要的时间片数减1,并排列到就绪队列的尾上。 三、实验环境 操作系统环境:Windows系统。 编程语言:C#。 四、实验思路和设计 1、程序流程图

2、主要程序代码 //PCB结构体 struct pcb { public int id; //进程ID public int ra; //所需资源A的数量 public int rb; //所需资源B的数量 public int rc; //所需资源C的数量 public int ntime; //所需的时间片个数 public int rtime; //已经运行的时间片个数 public char state; //进程状态,W(等待)、R(运行)、B(阻塞) //public int next; } ArrayList hready = new ArrayList(); ArrayList hblock = new ArrayList(); Random random = new Random(); //ArrayList p = new ArrayList(); int m, n, r, a,a1, b,b1, c,c1, h = 0, i = 1, time1Inteval;//m为要模拟的进程个数,n为初始化进程个数 //r为可随机产生的进程数(r=m-n) //a,b,c分别为A,B,C三类资源的总量 //i为进城计数,i=1…n //h为运行的时间片次数,time1Inteval为时间片大小(毫秒) //对进程进行初始化,建立就绪数组、阻塞数组。 public void input()//对进程进行初始化,建立就绪队列、阻塞队列 { m = int.Parse(textBox4.Text); n = int.Parse(textBox5.Text); a = int.Parse(textBox6.Text); b = int.Parse(textBox7.Text); c = int.Parse(textBox8.Text); a1 = a; b1 = b; c1 = c; r = m - n; time1Inteval = int.Parse(textBox9.Text); timer1.Interval = time1Inteval; for (i = 1; i <= n; i++) { pcb jincheng = new pcb(); jincheng.id = i; jincheng.ra = (random.Next(a) + 1); jincheng.rb = (random.Next(b) + 1); jincheng.rc = (random.Next(c) + 1); jincheng.ntime = (random.Next(1, 5)); jincheng.rtime = 0;

山东大学操作系统实验报告4进程同步实验

山东大学操作系统实验报告4进程同步实验

计算机科学与技术学院实验报告 实验题目:实验四、进程同步实验学号: 日期:20120409 班级:计基地12 姓名: 实验目的: 加深对并发协作进程同步与互斥概念的理解,观察和体验并发进程同步与互斥 操作的效果,分析与研究经典进程同步与互斥问题的实际解决方案。了解 Linux 系统中 IPC 进程同步工具的用法,练习并发协作进程的同步与互斥操作的编程与调试技术。 实验内容: 抽烟者问题。假设一个系统中有三个抽烟者进程,每个抽烟者不断地卷烟并抽烟。抽烟者卷起并抽掉一颗烟需要有三种材料:烟草、纸和胶水。一个抽烟者有烟草,一个有纸,另一个有胶水。系统中还有两个供应者进程,它们无限地供应所有三种材料,但每次仅轮流提供三种材料中的两种。得到缺失的两种材料的抽烟者在卷起并抽掉一颗烟后会发信号通知供应者,让它继续提供另外的两种材料。这一过程重复进行。请用以上介绍的 IPC 同步机制编程,实现该问题要求的功能。 硬件环境: 处理器:Intel? Core?i3-2350M CPU @ 2.30GHz ×4 图形:Intel? Sandybridge Mobile x86/MMX/SSE2 内存:4G 操作系统:32位 磁盘:20.1 GB 软件环境: ubuntu13.04 实验步骤: (1)新建定义了producer和consumer共用的IPC函数原型和变量的ipc.h文件。

(2)新建ipc.c文件,编写producer和consumer 共用的IPC的具体相应函数。 (3)新建Producer文件,首先定义producer 的一些行为,利用系统调用,建立共享内存区域,设定其长度并获取共享内存的首地址。然后设定生产者互斥与同步的信号灯,并为他们设置相应的初值。当有生产者进程在运行而其他生产者请求时,相应的信号灯就会阻止他,当共享内存区域已满时,信号等也会提示生产者不能再往共享内存中放入内容。 (4)新建Consumer文件,定义consumer的一些行为,利用系统调用来创建共享内存区域,并设定他的长度并获取共享内存的首地址。然后设定消费者互斥与同步的信号灯,并为他们设置相应的初值。当有消费进程在运行而其他消费者请求时,相应的信号灯就会阻止它,当共享内存区域已空时,信号等也会提示生产者不能再从共享内存中取出相应的内容。 运行的消费者应该与相应的生产者对应起来,只有这样运行结果才会正确。

操作系统实验报告

操作系统实验报告 ' 学号: 姓名: 指导老师: 完成日期: ~

目录 实验一 (1) 实验二 (2) 实验三 (7) 实验四 (10) 实验五 (15) 实验六 (18) 实验七 (22) \

实验一 UNIX/LINUX入门 一、实验目的 了解 UNIX/LINUX 运行环境,熟悉UNIX/LINUX 的常用基本命令,熟悉和掌握UNIX/LINUX 下c 语言程序的编写、编译、调试和运行方法。 二、实验内容 熟悉 UNIX/LINUX 的常用基本命令如ls、who、pwd、ps 等。 练习 UNIX/LINUX的文本行编辑器vi 的使用方法 熟悉 UNIX/LINUX 下c 语言编译器cc/gcc 的使用方法。用vi 编写一个简单的显示“Hello,World!”c 语言程序,用gcc 编译并观察编译后的结果,然后运行它。 三、实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四、实验程序 #include <> #include <> int main() { printf ("Hello World!\n"); return 0; } 五、实验感想 通过第一次室验,我了解 UNIX/LINUX 运行环境,熟悉了UNIX/LINUX 的常用基本命令,熟悉和掌握了UNIX/LINUX 下c 语言程序的编写、编译、调试和运行方法。

实验二进程管理 一、实验目的 加深对进程概念的理解,明确进程与程序的区别;进一步认识并发执行的实质。 二、实验内容 (1)进程创建 编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示“a“;子进程分别显示字符”b“和字符“c”。试观察记录屏幕上的显示结果,并分析原因。 (2)进程控制 修改已编写的程序,将每一个进程输出一个字符改为每一个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。 (3)进程的管道通信 编写程序实现进程的管道通信。使用系统调用pipe()建立一个管道,二个子进程P1 和P2 分别向管道各写一句话: Child 1 is sending a message! Child 2 is sending a message! 父进程从管道中读出二个来自子进程的信息并显示(要求先接收P1,再接收P2)。 三、实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四、实验设计 1、功能设计 (1)进程创建 使用fork()创建两个子进程,父进程等待两个子进程执行完再运行。 (2)进程控制 使用fork()创建两个子进程,父进程等待两个子进程分别输出一句话再运行。 (3)进程的管道通信 先创建子进程1,向管道写入一句话,子进程1结束后创建子进程2,向管道写入一句话,最后父进程从管道中读出。 2、数据结构 子进程和管道。 3、程序框图

Linux文件系统实验报告

黄冈师学院 提高型实验报告 实验课题文件系统的设计与实现(实验类型:□综合性 设计性□应用性) 实验课程操作系统原理 实验时间2015-2016 第二学期 学生何正发 专业班级软件工程1401 学号07

成绩: 一、实验目的和要求 1、熟悉操作系统设计的过程,巩固操作系统的基本知识,加深对操作原理、功能及各种不同的存储管理方法理解与应用; 2、学会运用各种语言、软件开发新软件的基本方法; 3、增强实际应用能力和动手操作能力。 二、实验条件 Win7 /Windows 8.1/Linux等操作系统,装有java、C、C++、C#等语言工具的环境。 三、实验原理分析 可以选择最佳适应算法,按照从小到大的次序组成空闲区自由链,当用户作业或进程申请一个空闲区时,存储管理 程序从表头开始查找,当找到第一个満足要求的空闲区时,停止查找。如果该空闲区大于请求表中的请求长 度,将减去请求长度后的剩余空闲区部分留在可用表中。回收时,从作链中删去要回收的作业块,同时在空 闲链中插入该作业大小的空闲区,并按顺序排列 四、实验方案或步骤 1、应用环境、需求分析 本模拟系统主要针对文件的管理和操作名主要有:创建用户、文件、文件夹,读文件,写文件,执行文件,关闭文件,删除用户、文件夹、文件的功能。 创建用户、文件、文件夹:在对系统发出操作命令之前必须先登录用户,然而登录之前必须创建该用户。在创建完后,可通过登录用户来创建文件和文件夹。在创建文件时可设置文件的属性和输入文件的容。 读文件:读取任何已创建的只读或读写文件的容;如果所要读的文件不是可读文件时,系统会显示该文件不可读;如果所读文件不存在,系统会显示文件不存在。 写文件用户可写或重写读写文件中的容,并保存文件中的重写容,以供下次读取;当所要写的文件不是可写的文件时,系统会显示该文件不可写;当所要写的文件并不存在时,系统会显示该文件不存在。

嵌入式操作系统实验报告

中南大学信息科学与工程学院实验报告 姓名:安磊 班级:计科0901 学号: 0909090310

指导老师:宋虹

目录 课程设计内容 ----------------------------------- 3 uC/OS操作系统简介 ------------------------------------ 3 uC/OS操作系统的组成 ------------------------------ 3 uC/OS操作系统功能作用 ---------------------------- 4 uC/OS文件系统的建立 ---------------------------- 6 文件系统设计的原则 ------------------------------6 文件系统的层次结构和功能模块 ---------------------6 文件系统的详细设计 -------------------------------- 8 文件系统核心代码 --------------------------------- 9 课程设计感想 ------------------------------------- 11 附录-------------------------------------------------- 12

课程设计内容 在uC/OS操作系统中增加一个简单的文件系统。 要求如下: (1)熟悉并分析uc/os操作系统 (2)设计并实现一个简单的文件系统 (3)可以是存放在内存的虚拟文件系统,也可以是存放在磁盘的实际文件系统 (4)编写测试代码,测试对文件的相关操作:建立,读写等 课程设计目的 操作系统课程主要讲述的内容是多道操作系统的原理与技术,与其它计算机原理、编译原理、汇编语言、计算机网络、程序设计等专业课程关系十分密切。 本课程设计的目的综合应用学生所学知识,建立系统和完整的计算机系统概念,理解和巩固操作系统基本理论、原理和方法,掌握操作系统开发的基本技能。 I.uC/OS操作系统简介 μC/OS-II是一种可移植的,可植入ROM的,可裁剪的,抢占式的,实时多任务操作系统内核。它被广泛应用于微处理器、微控制器和数字信号处理器。 μC/OS 和μC/OS-II 是专门为计算机的嵌入式应用设计的,绝大部分代码是用C语言编写的。CPU 硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU 上。用户只要有标准的ANSI 的C交叉编译器,有汇编器、连接器等软件工具,就可以将μC/OS-II嵌入到开发的产品中。μC/OS-II 具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点,最小内核可编译至2KB 。μC/OS-II 已经移植到了几乎所有知名的CPU 上。 严格地说uC/OS-II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。没有提供输入输出管理,文件系统,网络等额外的服务。但由于uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全 可以由用户自己根据需要分别实现。 uC/OS-II目标是实现一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最基本的系统服务,如信号量,邮箱,消息队列,内存管理,中断管理等。 uC/OS操作系统的组成 μC/OS-II可以大致分成核心、任务处理、时间处理、任务同步与通信,CPU的移植等5个部分。如下图:

FAT文件系统操作系统课程设计实验报告

操作系统课程设计之三 设计任务:模拟OS文件系统 在任一OS(Window或者Dos;也可以是在Linux下,但要求能将结果演示给老 师看)下,建立一个大文件,把它假象成一张盘,在其中实现一个简单的模拟OS 字 ,第 ⑤、每个目录实际能放下文件或子目录30项。 ⑸、文件系统空间分配: ①、第0个盘块(1k)存放磁盘信息(可以设定为格式说明“FAT32”、盘块大小,盘块数等 内容) ②、第1个盘块起,至125盘块,共125个盘块(125k)存放FAT内容 ③、第126、127(2个)盘块,存放位示图

④、从第128盘块至10000盘块,皆为数据(区)盘块,其逻辑编号从0开始,至 9872号数据盘块,即第0数据盘块为128号盘块,第1数据盘块为129号盘块,… ⑤、第0数据盘块(即128号盘块),存放根目录(同样只用一个盘块作根目录), 由于第0、1目录项为“.”(本目录), “..”(父目录),因此根目录下同样只能存放30个文件或目录,并且从第2个目录项开始。 ⑥、文件或子目录数据,放在第1数据盘块及以后的数据盘块中,由用户按需要使 用。 内容 ⑺、删除文件 #DelFile 文件名.扩展名,在文件所在的目录项中,将第一个字节变为0xE5,并同时修改FAT内容和位示图内容;如果文件不存在,给出出错信息 ⑻、文件拷贝 #CopyFile 老文件,新文件,为新文件创建一个目录项,并将老文件内容复制到新文件中,并同时修改FAT内容和位示图内容 ⑼、显示位示图内容

#ShowBitMP,将位示图内容(已有信息部分),显示在屏幕上(按十六进制)⑽、显示FAT内容 #ShowFAT,将FAT内容(已有信息部分),显示在屏幕上(按十六进制) 4、程序的总体流程为: ⑴、输出提示符#,等待接受命令,分析键入的命令; ⑵、对合法的命令,执行相应的处理程序,否则输出错误信息,继续等待新命令 关于对FAT表和MAP表的用法 1.当要用到数据块是,查询MAP表(因为只做比较查询即可),查询到的未用位置 置1,然后在FAT表上进行相应记录,在本程序做出的规定是,当文件夹FAT 表做-1,若是文件则按照FAT做对应的顺序记录,最后一块同样是-1结束,2.回收的时候,是按照FAT表的首项,做顺序置0,然后MAP也在相应位置置0

实时操作系统报告

实时操作系统课程实验报告 专业:通信1001 学号:3100601025 姓名:陈治州 完成时间:2013年6月11日

实验简易电饭煲的模拟 一.实验目的: 掌握在基于嵌入式实时操作系统μC/OS-II的应用中,基于多任务的模式的编程方法。锻炼综合应用多任务机制,任务间的通信机制,内存管理等的能力。 二.实验要求: 1.按“S”开机,系统进入待机状态,时间区域显示当前北京时间,默认模式“煮饭”; 2.按“C”选择模式,即在“煮饭”、“煮粥”和“煮面”模式中循环选择; 3.按“B”开始执行模式命令,“开始”状态选中,时间区域开始倒计时,倒计时完成后进入“保温”状态,同时该状态显示选中,时间区域显示保温时间; 4.按“Q”取消当前工作状态,系统进入待机状态,时间区域显示北京时间,模式为当前模式; 5.按“X”退出系统,时间区域不显示。 6.煮饭时长为30,煮粥时长为50,煮面时长为40. 三.实验设计: 1.设计思路: 以老师所给的五个程序为基础,看懂每个实验之后,对borlandc的操作有了大概的认识,重点以第五个实验Task_EX为框架,利用其中界面显示与按键扫描以及做出相应的响应,对应实现此次实验所需要的功能。 本次实验分为界面显示、按键查询与响应、切换功能、时钟显示与倒计时模块,综合在一起实验所需功能。 2.模块划分图: (1)界面显示: Main() Taskstart() Taskstartdispinit() 在TaskStartDispInit()函数中,使用PC_DispStr()函数画出界面。

(2)按键查询与响应: Main() Taskstart() 在TaskStart()函数中,用if (PC_GetKey(&key) == TRUE)判断是否有按键输入。然后根据key 的值,判断输入的按键是哪一个;在响应中用switch语句来执行对应按键的响应。 (3)切换功能: l计数“C”按 键的次数 M=l%3 Switch(m) M=0,1,2对应于煮饭,煮粥,煮面,然后使用PC_DispStr()函数在选择的选项前画上“@”指示,同时,在其余两项钱画上“”以“擦出”之前画下的“@”,注意l自增。 四.主要代码: #include "stdio.h" #include "includes.h" #include "time.h" #include "dos.h" #include "sys/types.h" #include "stdlib.h" #define TASK_STK_SIZE 512 #define N_TASKS 2 OS_STK TaskStk[N_TASKS][TASK_STK_SIZE]; OS_STK TaskStartStk[TASK_STK_SIZE]; INT8U TaskData[N_TASKS];

操作系统实验报告4

《操作系统》实验报告 实验序号: 4 实验项目名称:进程控制

Printf(“child Complete”); CloseHandle(pi.hProcess); CloseHandle(pi hThread); ﹜ 修改后: #include #include int main(VOID) { STARTUPINFO si; PROCESS_INFORMA TION pi; ZeroMemory(&si,sizeof(si)); si.cb=sizeof(si); ZeroMemory(&pi,sizeof(pi)); if(!CreateProcess(NULL, "c:\\WINDOWS\\system32\\mspaint.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si,&pi)) { fprintf(stderr,"Creat Process Failed"); return -1; } WaitForSingleObject(pi.hProcess,INFINITE); printf("child Complete"); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } 在“命令提示符”窗口运行CL命令产生可执行程序4-1.exe:C:\ >CL 4-1.cpp

实验任务:写出程序的运行结果。 4.正在运行的进程 (2)、编程二下面给出了一个使用进程和操作系统版本信息应用程序(文件名为4-5.cpp)。它利用进程信息查询的API函数GetProcessVersion()与GetVersionEx()的共同作用。确定运行进程的操作系统版本号。阅读该程序并完成实验任务。 #include #include

操作系统实验报告

操作系统实验报告 集团企业公司编码:(LL3698-KKI1269-TM2483-LUI12689-ITT289-

实验二进程调度1.目的和要求 通过这次实验,理解进程调度的过程,进一步掌握进程状态的转变、进程调度的策略,进一步体会多道程序并发执行的特点,并分析具体的调度算法的特点,掌握对系统性能的评价方法。 2.实验内容 阅读教材《计算机操作系统》第二章和第三章,掌握进程管理及调度相关概念和原理。 编写程序模拟实现进程的轮转法调度过程,模拟程序只对PCB进行相应的调度模拟操作,不需要实际程序。假设初始状态为:有n个进程处于就绪状态,有m个进程处于阻塞状态。采用轮转法进程调度算法进行调度(调度过程中,假设处于执行状态的进程不会阻塞),且每过t个时间片系统释放资源,唤醒处于阻塞队列队首的进程。 程序要求如下: 1)输出系统中进程的调度次序; 2)计算CPU利用率。 3.实验环境 Windows操作系统、VC++6.0 C语言 4设计思想: (1)程序中进程可用PCB表示,其类型描述如下:

structPCB_type { intpid;//进程名 intstate;//进程状态 2——表示“执行”状态 1——表示“就绪”状态 0——表示“阻塞”状态 intcpu_time;//运行需要的CPU时间(需运行的时间片个数) } 用PCB来模拟进程; (2)设置两个队列,将处于“就绪”状态的进程PCB挂在队列ready中;将处于“阻塞”状态的进程PCB挂在队列blocked中。队列类型描述如下: structQueueNode{ structPCB_typePCB; StructQueueNode*next; } 并设全程量: structQueueNode*ready_head=NULL,//ready队列队首指针 *ready_tail=NULL,//ready队列队尾指 针

文件系统实验报告

实验二文件系统实验报告

一.实验简介 本实验要求在假设的I/O 系统之上开发一个简单的文件系统,这样做既能让实验者对文件系统有整体了解,又避免了涉及过多细节。用户通过create, open, read 等命令与文件系统交互。文件系统把磁盘视为顺序编号的逻辑块序列,逻辑块的编号为0 至L-1。I/O 系统利用内存中的数组模拟磁盘。 实际物理磁盘的结构是多维的:有柱面、磁道、扇区等概念。I/O 系统的任务是隐藏磁盘的结构细节,把磁盘以逻辑块的面目呈现给文件系统。逻辑块顺序编号,编号取值范围为0 至L .. 1,其中L 表示磁盘的存储块总数。实验中,我们可以利用字符数组ldisk[L][B] 构建磁盘模型,其中 B 表示每个存储块的长度。I/O 系统从文件系统接收命令,根据命令指定的逻辑块号把磁盘块的内容读入命令指定的内存区域,或者把命令指定的内存区域内容写入磁盘块。 我设计的文件系统拥有三个用户。 二.具体说明 1.文件系统的组织:磁盘的前k 个块是保留区,其中包含如下信息:位图和文件描述符。位图用来描述磁盘块的分配情况。位图中的每一位对应一个逻辑块。创建或者删除文件,以及文件的长度发生变化时,文件系统都需要进行位图操作。前k 个块的剩余部分包含一组文件描述符。每个文件描述符包含如下信息: ?文件长度,单位字节 ?文件分配到的磁盘块号数组。该数组的长度是一个系统参数。在实验中我们可以把它设置为一个比较小的数,例如3。 2.目录:我们的文件系统中仅设置一个目录,该目录包含文件系统中的所有文件。除了不需要显示地创建和删除之外,目录在很多方面和普通文件相像。目录对应0 号文件描述符。初始状态下,目录中没有文件,所有,目录对应的描述符中记录的长度应为0,而且也没有分配磁盘块。每创建一个文件,目录文件的长度便增加一分。目录文件的内容由一系列的目录项组成,其中每个目录项由如下内容组成: ?文件名 ?文件描述符序号 3.对文件的操作: 文件系统需提供如下函数;create, destroy, open, read, write。 ?create(filename): 根据指定的文件名创建新文件。 ?destroy(filename): 删除指定文件。 ?open(filename): 打开文件。该函数返回的索引号可用于后续的read, write, lseek, 或close 操作。 ?close(index): 关闭制定文件。 ?read(index, mem_area, count): 从指定文件顺序读入count 个字节mem_area 指定的内存位

操作系统实验报告

操作系统教程 实 验 指 导 书 姓名: 学号: 班级:软124班 指导老师:郭玉华 2014年12月10日

实验一WINDOWS进程初识 1、实验目的 (1)学会使用VC编写基本的Win32 Consol Application(控制台应用程序)。 (2)掌握WINDOWS API的使用方法。 (3)编写测试程序,理解用户态运行和核心态运行。 2、实验内容和步骤 (1)编写基本的Win32 Consol Application 步骤1:登录进入Windows,启动VC++ 6.0。 步骤2:在“FILE”菜单中单击“NEW”子菜单,在“projects”选项卡中选择“Win32 Consol Application”,然后在“Project name”处输入工程名,在“Location”处输入工程目录。创建一个新的控制台应用程序工程。 步骤3:在“FILE”菜单中单击“NEW”子菜单,在“Files”选项卡中选择“C++ Source File”, 然后在“File”处输入C/C++源程序的文件名。 步骤4:将清单1-1所示的程序清单复制到新创建的C/C++源程序中。编译成可执行文件。 步骤5:在“开始”菜单中单击“程序”-“附件”-“命令提示符”命令,进入Windows“命令提示符”窗口,然后进入工程目录中的debug子目录,执行编译好的可执行程序: E:\课程\os课\os实验\程序\os11\debug>hello.exe 运行结果 (如果运行不成功,则可能的原因是什么?) : 有可能是因为DOS下路径的问题 (2)计算进程在核心态运行和用户态运行的时间 步骤1:按照(1)中的步骤创建一个新的“Win32 Consol Application”工程,然后将清单1-2中的程序拷贝过来,编译成可执行文件。 步骤2:在创建一个新的“Win32 Consol Application”工程,程序的参考程序如清单1-3所示,编译成可执行文件并执行。 步骤3:在“命令提示符”窗口中运行步骤1中生成的可执行文件,测试步骤2中可执行文件在核心态运行和用户态运行的时间。 E:\课程\os课\os实验\程序\os12\debug>time TEST.exe 步骤4:运行结果 (如果运行不成功,则可能的原因是什么?) : 因为程序是个死循环程序 步骤5:分别屏蔽While循环中的两个for循环,或调整两个for循环的次数,写出运行结果。 屏蔽i循环: 屏蔽j循环: _______________________________________________________________________________调整循环变量i的循环次数:

实验四 文件系统实验报告

实验四文件系统实验 一 . 目的要求 1、用高级语言编写和调试一个简单的文件系统,模拟文件管理的工作过程。从而对各种文件操作命令的实质内容和执行过程有比较深入的了解。 2、要求设计一个 n个用户的文件系统,每次用户可保存m个文件,用户在一次运行中只能打开一个文件,对文件必须设置保护措施,且至少有Create、delete、open、close、read、write等命令。 二 . 例题: 1、设计一个10个用户的文件系统,每次用户可保存10个文件,一次运行用户可以打开5个文件。 2、程序采用二级文件目录(即设置主目录[MFD])和用户文件目录(UED)。另外,为打开文件设置了运行文件目录(AFD)。 3、为了便于实现,对文件的读写作了简化,在执行读写命令时,只需改读写指针,并不进行实际的读写操作。 4、算法与框图: ①因系统小,文件目录的检索使用了简单的线性搜索。 ②文件保护简单使用了三位保护码:允许读写执行、对应位为 1,对应位为0,则表示不允许读写、执行。 ③程序中使用的主要设计结构如下: 主文件目录和用户文件目录( MFD、UFD) 打开文件目录( AFD)(即运行文件目录)

文件系统算法的流程图如下: 三 . 实验题: 1、增加 2~3个文件操作命令,并加以实现。(如移动读写指针,改变文件属性,更换文件名,改变文件保护级别)。 #include #include #include #include #define MAXSIZE 100 #define ADDSIZE 50 #define PT elem+l-> length #define N 4 typedef struct term{/*班级和学期的结构体*/ char class1[10]; char term1[10]; }term; typedef struct student{/*学生成绩信息的结构体*/ term st;/*班级和学期结构体放于此结构体中*/ char num[10]; char name[12]; float course[4]; float total; float average; int bit; }lnode,*stu; typedef struct{ lnode *elem;/*指向上个结构体的指针*/ int size;/*最大能放lnode结构体成员的个数*/ int length;/*当前长度*/ }sqack,*sq; sqack *l; void init(void)/*动态分配存储空间*/ { l-> elem=(stu)malloc(MAXSIZE*sizeof(lnode)); l-> length =0; l-> size=MAXSIZE; } void input(void)/*输入学生的信息*/ { lnode *newbase,*p; char cla[10],ter[10],ch; int n,i; if(l-> length> =l-> size){ newbase=(stu)realloc(l-> elem,(l-> size +ADDSIZE)*sizeof(lnode));/*追加存储空间*/ l-> elem =newbase; l-> size +=ADDSIZE; } p=l-> elem; do { printf( "输入班级和学期(学期用这种格式,如2005年上学期2005 1,2005年下学期2005 2;先输入班级,回车后再输入学期)\n "); gets(cla); gets(ter); printf( "要输入多少个名单?"); scanf( "%d ",&n); printf( "输入学生的成绩\n学号\t姓名\t科目1\t科目2\t科目3\t科目4\n "); for(i=0;i num ,p-> name,p-> course[0],p-> course[1],p-> course[2],p-> course[3]); strcpy(p-> st.class1,cla); strcpy(p-> st.term1,ter); ++l-> length ; } printf( "要继续吗?(y/n) ");

嵌入式实时操作系统实验报告

嵌入式实时操作系统实验报告 任务间通信机制的建立 系别计算机与电子系 专业班级***** 学生姓名****** 指导教师 ****** 提交日期 2012 年 4 月 1 日

一、实验目的 掌握在基于嵌入式实时操作系统μC/OS-II的应用中,任务使用信号量的一般原理。掌握在基于优先级的可抢占嵌入式实时操作系统的应用中,出现优先级反转现象的原理及解决优先级反转的策略——优先级继承的原理。 二、实验内容 1.建立并熟悉Borland C 编译及调试环境。 2.使用课本配套光盘中第五章的例程运行(例5-4,例5-5,例5-6),观察运行结果,掌握信号量的基本原理及使用方法,理解出现优先级反转现象的根本原因并提出解决方案。 3.试编写一个应用程序,采用计数器型信号量(初值为2),有3个用户任务需要此信号量,它们轮流使用此信号量,在同一时刻只有两个任务能使用信号量,当其中一个任务获得信号量时向屏幕打印“TASK N get the signal”。观察程序运行结果并记录。 4. 试编写一个应用程序实现例5-7的内容,即用优先级继承的方法解决优先级反转的问题,观察程序运行结果并记录。 5.在例5-8基础上修改程序增加一个任务HerTask,它和YouTask一样从邮箱Str_Box里取消息并打印出来,打印信息中增加任务标识,即由哪个任务打印的;MyTask发送消息改为当Times为5的倍数时才发送,HerTask接收消息采用无等待方式,如果邮箱为空,则输出“The mailbox is empty”, 观察程序运行结果并记录。 三、实验原理 1. 信号量 μC/OS-II中的信号量由两部分组成:一个是信号量的计数值,它是一个16位的无符号整数(0 到65,535之间);另一个是由等待该信号量的任务组成的等待任务表。用户要在OS_CFG.H中将OS_SEM_EN开关量常数置成1,这样μC/OS-II 才能支持信号量。

《 Windows7 操作系统》实验报告

实验(一) Windows 7基本操作 一、实验目的 1.掌握文件和文件夹基本操作。 2.掌握“资源管理器”和“计算机”基本操作。 二、实验要求 1.请将操作结果用Alt+Print Screen组合键截图粘贴在题目之后。 2.实验完成后,请将实验报告保存并提交。 三、实验内容 1.文件或文件夹的管理(提示:此题自行操作一遍即可,无需抓图)★期末机试必考题★ (1) 在D:盘根目录上创建一个名为“上机实验”的文件夹,在“上机实验”文件夹中创建1个名为“操作系统上机实验”的空白文件夹和2个分别名为“2.xlsx”和“3.pptx”的空白文件,在“操作系统上机实验”文件夹中创建一个名为“1.docx”的空白文件。 (2) 将“1.docx”改名为“介绍信.docx”;将“上机实验”改名为“作业”。 (3) 在“作业”文件夹中分别尝试选择一个文件、同时选择两个文件、一次同时选择所有文件和文件夹。 (4) 将“介绍信.docx”复制到C:盘根目录。 (5) 将D:盘根目录中的“作业”文件夹移动到C:盘根目录。 (6) 将“作业”文件夹中的“2.xlsx”文件删除放入“回收站”。 (7) 还原被删除的“2.xlsx”文件到原位置。 2.搜索文件或文件夹,要求如下: 查找C盘上所有以大写字母“A”开头,文件大小在10KB以上的文本文件。(提示:搜索时,可以使用“?”和“*”。“?”表示任意一个字符,“*”表示任意多个字符。)

3. 在桌面上为C:盘根目录下的“作业”文件夹创建一个桌面快捷方式。★期末机试必考题★ 3.“计算机”或“资源管理器”的使用 (1) 在“资源管理器”窗口,设置以详细信息方式显示C:\WINDOWS中所有文件和文件夹,使所有图标按类型排列显示,并不显示文件扩展名。(提示:三步操作全部做完后,将窗口中显示的最终设置结果抓一张图片即可) (2) 将C:盘根目录中“介绍信.docx”的文件属性设置为“只读”和“隐藏”,并设置在窗口中显示“隐藏属性”的文件或文件夹。(提示:请将“文件夹”对话框中选项设置效果与C:盘根目录中该文件图标呈现的半透明显示效果截取在一整张桌面图片中即可) 4.回收站的设置 设置删除文件后,不将其移入回收站中,而是直接彻底删除功能。

操作系统实验报告

《操作系统原理》实验报告 实验项目名称:模拟使用银行家算法判断系统的状态 一、实验目的 银行家算法是操作系统中避免死锁的算法,本实验通过对银行家算法的模拟,加强对操作系统中死锁的认识,以及如何寻找到一个安全序列解除死锁。 二、实验环境 1、硬件:笔记本。 2、软件:Windows 7 , Eclipse。 三、实验内容 1.把输入资源初始化,形成资源分配表; 2.设计银行家算法,输入一个进程的资源请求,按银行家算法步骤进行检查; 3.设计安全性算法,检查某时刻系统是否安全; 4.设计显示函数,显示资源分配表,安全分配序列。 四、数据处理与实验结果 1.资源分配表由进程数组,Max,Allocation,Need,Available 5个数组组成; 实验采用数据为下表: 2.系统总体结构,即菜单选项,如下图

实验的流程图。如下图 3.实验过程及结果如下图所示

1.首先输入进程数和资源类型及各进程的最大需求量 2.输入各进程的占有量及目前系统的可用资源数量 3.初始化后,系统资源的需求和分配表 4.判断线程是否安全

5.对线程进行死锁判断 五、实验过程分析 在实验过程中,遇到了不少问题,比如算法无法回滚操作,程序一旦执行,必须直接运行到单个任务结束为止,即使产生了错误,也必须等到该项任务结束才可以去选择别的操作。但总之,实验还是完满的完成了。 六、实验总结 通过实验使我对以前所学过的基础知识加以巩固,也对操作系统中抽象理论知识加以理解,例如使用Java语言来实现银行家算法,在这个过程中更进一步了解了银行家算法,通过清晰字符界面能进行操作。不过不足之处就是界面略显简洁,对于一个没有操作过计算机的人来说,用起来可能还是有些难懂。所以,以后会对界面以及功能进行完善,做到人人都可以看懂的算法。

操作系统实验报告

实验报告 实验课程名称:操作系统 实验地点:南主楼七楼机房 2018—2019学年(一)学期 2018年 9月至 2019 年 1 月 专业: 班级: 学号: 姓名: 指导老师:刘一男

实验一 实验项目:分时系统模拟 实验学时:2实验日期: 2018-10-25 成绩: 实验目的利用程序设计语言模拟分时系统中多个进程按时间片轮转调度算法进行进程调度的过程; 假设有五个进程A,B,C,D,E,它们的到达时间及要求服务的时间分别为:进程名 A B C D E 到达时间0 1 2 3 4 服务时间 4 3 4 2 4 时间片大小为1,利用程序模拟A,B,C,D,E五个进程按时间片轮转的调度及执行过程并计算各进程的周转时间及带权周转时间。 执行过程并计算各进程的周转时间及带权周转时间。 轮转调度:BDACE

(1)修改时间片大小为2,利用程序模拟A,B,C,D,E五个进程按时间片轮转的调度及执行过程并计算各进程的周转时间及带权周转时间。 轮转调度:ADBCE (2)修改时间片大小为4,利用程序模拟A,B,C,D,E五个进程按时间片轮转的调度及执行过程并计算各进程的周转时间及带权周转时间.

顺序:ABCDE 1、思考 时间片的大小对调度算法产生什么影响?对计算机的性能产生什么影响?答:通过对时间片轮转调度算法中进程最后一次执行时间片分配的优化,提出了一种改进的时间片轮转调度算法,该算法具有更好的实时性,同时减少了任务调度次数和进程切换次数,降低了系统开销,提升了CPU的运行效率,使操作系统的性能得到了一定的提高。 A B C D E 时间片为1 周转时间12 9 14 8 13 3 3 3.5 4 3.25 带权周转 时间 时间片为2 周转时间8 12 13 7 13 2 4 3.25 3.5 3.25 带权周转 时间 时间片为4 周转时间 4 6 9 10 13 1 2 2.25 5 3.25 带权周转 时间

相关文档
最新文档