操作系统实验五

  1. 1. 运行结果
  2. 2. 请给出实验过程中遇到的问题,并解释原因和解决方案
  3. 3. 如果模拟一个inode区的前提下,请指出参考代码中creat函数需要如何修改?
  4. 4. 请设计系统打开文件表和用户打开文件表,并给出相应函数的修改方案

文件系统——散列结构文件的构造

实验目的:

  • 掌握Linux中与文件有关的系统调用命令的功能和使用,理解文件的物理组织结构。

实验内容:

  1. 设计一组关于物理结构为散列结构的文件的操作函数,包括创建、打开、关闭、读、写。
  2. 构造一个散列结构的文件,实现记录保存、查找、删除。
  3. 编写记录更新函数。

设计原理:

参考教材8.3.2

实验代码

hashfile.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#ifndef HASHFILE_H
#define HASHFILE_H


#include<unistd.h>

#include<sys/stat.h>

#define COLLISIONFACTOR 0.5



struct HashFileHeader

{

int sig; //Hash文件印鉴

int reclen; //记录长度

int total_rec_num; //总记录数

int current_rec_num; //当前记录数

};

struct CFTag

{

char collision; //冲突计数

char free; //空闲标志

};



int hashfile_creat(const char *filename,mode_t mode,int reclen,int total_rec_num);

//int hashfile_open(const char *filename,int flags);

int hashfile_open(const char *filename,int flags,mode_t mode);

int hashfile_close(int fd);

int hashfile_read(int fd,int keyoffset,int keylen,void *buf);

int hashfile_write(int fd,int keyoffset,int keylen,void *buf);

int hashfile_delrec(int fd,int keyoffset,int keylen,void *buf);

int hashfile_findrec(int fd,int keyoffset,int keylen,void *buf);

int hashfile_saverec(int fd,int keyoffset,int keylen,void *buf);

int hash(int keyoffset,int keylen,void *buf,int total_rec_num);

int checkHashFileFull(int fd);

int readHashFileHeader(int fd,struct HashFileHeader *hfh);
#endif

hashifile.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242

// hashfile.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "HashFile.h"

int hashfile_creat(const char *filename, mode_t mode, int reclen, int total_rec_num)
{
struct HashFileHeader hfh;
int fd;
int rtn;
char *buf;
int i = 0;
hfh.sig = 31415926;
hfh.reclen = reclen;
hfh.total_rec_num = total_rec_num;
hfh.current_rec_num = 0;
// fd = open(filename,mode);
fd = creat(filename, mode);
if (fd != -1)
{
rtn = write(fd, &hfh, sizeof(struct HashFileHeader));
// lseek(fd,sizeof(struct HashFileHeader),SEEK_SET);
if (rtn != -1)
{
buf = (char *)malloc((reclen + sizeof(struct CFTag)) * total_rec_num);
memset(buf, 0, (reclen + sizeof(struct CFTag)) * total_rec_num);
rtn = write(fd, buf, (reclen + sizeof(struct CFTag)) * total_rec_num);
free(buf);
}
close(fd);
return rtn;
}
else
{
close(fd);
return -1;
}
}

int hashfile_open(const char *filename, int flags, mode_t mode)
{
int fd = open(filename, flags, mode);
struct HashFileHeader hfh;
if (read(fd, &hfh, sizeof(struct HashFileHeader)) != -1)
{
lseek(fd, 0, SEEK_SET);
if (hfh.sig == 31415926)
return fd;
else
return -1;
}
else
return -1;
}
int hashfile_close(int fd)
{
return close(fd);
}
int hashfile_read(int fd, int keyoffset, int keylen, void *buf)
{
struct HashFileHeader hfh;
readHashFileHeader(fd, &hfh);
int offset = hashfile_findrec(fd, keyoffset, keylen, buf);
if (offset != -1)
{
lseek(fd, offset + sizeof(struct CFTag), SEEK_SET);
return read(fd, buf, hfh.reclen);
}
else
{
return -1;
}
}
int hashfile_write(int fd, int keyoffset, int keylen, void *buf)
{
return hashfile_saverec(fd, keyoffset, keylen, buf);
// return -1;
}
int hashfile_delrec(int fd, int keyoffset, int keylen, void *buf)
{
int offset;
offset = hashfile_findrec(fd, keyoffset, keylen, buf);
if (offset != -1)
{
struct CFTag tag;
read(fd, &tag, sizeof(struct CFTag));
tag.free = 0; // 置空闲标志
lseek(fd, offset, SEEK_SET);
write(fd, &tag, sizeof(struct CFTag));
struct HashFileHeader hfh;
readHashFileHeader(fd, &hfh);
int addr = hash(keyoffset, keylen, buf, hfh.total_rec_num);
offset = sizeof(struct HashFileHeader) + addr * (hfh.reclen + sizeof(struct CFTag));
if (lseek(fd, offset, SEEK_SET) == -1)
return -1;
read(fd, &tag, sizeof(struct CFTag));
tag.collision--; // 冲突计数减1
lseek(fd, offset, SEEK_SET);
write(fd, &tag, sizeof(struct CFTag));
hfh.current_rec_num--; // 当前记录数减1
lseek(fd, 0, SEEK_SET);
write(fd, &hfh, sizeof(struct HashFileHeader));
}
else
{
return -1;
}
}

int hashfile_findrec(int fd, int keyoffset, int keylen, void *buf)
{
struct HashFileHeader hfh;
readHashFileHeader(fd, &hfh);
int addr = hash(keyoffset, keylen, buf, hfh.total_rec_num);
int offset = sizeof(struct HashFileHeader) + addr * (hfh.reclen + sizeof(struct CFTag));
if (lseek(fd, offset, SEEK_SET) == -1)
return -1;
struct CFTag tag;
read(fd, &tag, sizeof(struct CFTag));
char count = tag.collision;
if (count == 0)
return -1; // 不存在
recfree:
if (tag.free == 0)
{
offset += hfh.reclen + sizeof(struct CFTag);
if (lseek(fd, offset, SEEK_SET) == -1)
return -1;
read(fd, &tag, sizeof(struct CFTag));
goto recfree;
}
else
{
char *p = (char *)malloc(hfh.reclen * sizeof(char));
read(fd, p, hfh.reclen);
// printf("Record is {%d , %s}\n",((struct jtRecord *)p)->key,((struct jtRecord *p)->other);
char *p1, *p2;
p1 = (char *)buf + keyoffset;
p2 = p + keyoffset;
int j = 0;
while ((*p1 == *p2) && (j < keylen))
{
p1++;
p2++;
j++;
}
if (j == keylen)
{
free(p);
p = NULL;
return (offset);
}
else
{
if (addr == hash(keyoffset, keylen, p, hfh.total_rec_num))
{
count--;
if (count == 0)
{
free(p);
p = NULL;
return -1; // 不存在
}
}
free(p);
p = NULL;
offset += hfh.reclen + sizeof(struct CFTag);
if (lseek(fd, offset, SEEK_SET) == -1)
return -1;
read(fd, &tag, sizeof(struct CFTag));
goto recfree;
}
}
}
int hashfile_saverec(int fd, int keyoffset, int keylen, void *buf)
{
if (checkHashFileFull(fd))
{
return -1;
}
struct HashFileHeader hfh;
readHashFileHeader(fd, &hfh);
int addr = hash(keyoffset, keylen, buf, hfh.total_rec_num);
int offset = sizeof(struct HashFileHeader) + addr * (hfh.reclen + sizeof(struct CFTag));
if (lseek(fd, offset, SEEK_SET) == -1)
return -1;
struct CFTag tag;
read(fd, &tag, sizeof(struct CFTag));
tag.collision++;
lseek(fd, sizeof(struct CFTag) * (-1), SEEK_CUR);
write(fd, &tag, sizeof(struct CFTag));
while (tag.free != 0) // 冲突,顺序探查
{
offset += hfh.reclen + sizeof(struct CFTag);
if (offset >= lseek(fd, 0, SEEK_END))
offset = sizeof(struct HashFileHeader); // reach at and,then rewind
if (lseek(fd, offset, SEEK_SET) == -1)
return -1;
read(fd, &tag, sizeof(struct CFTag));
}
tag.free = -1;
lseek(fd, sizeof(struct CFTag) * (-1), SEEK_CUR);
write(fd, &tag, sizeof(struct CFTag));
write(fd, buf, hfh.reclen);
hfh.current_rec_num++;
lseek(fd, 0, SEEK_SET);
return write(fd, &hfh, sizeof(struct HashFileHeader)); // 存入记录
}

int hash(int keyoffset, int keylen, void *buf, int total_rec_num)
{
int i = 0;
char *p = (char *)buf + keyoffset;
int addr = 0;
for (i = 0; i < keylen; i++)
{
addr += (int)(*p);
p++;
}
return addr % (int)(total_rec_num * COLLISIONFACTOR);
}

int checkHashFileFull(int fd)
{
struct HashFileHeader hfh;
readHashFileHeader(fd, &hfh);
if (hfh.current_rec_num < hfh.total_rec_num)
return 0;
else
return 1;
}
int readHashFileHeader(int fd, struct HashFileHeader *hfh)
{
lseek(fd, 0, SEEK_SET);
return read(fd, hfh, sizeof(struct HashFileHeader));
}

jtRecord.h

1
2
3
4
5
6
7
8
9
10
11
12
13

//jtRecord.h
#define RECORDLEN 32

struct jtRecord
{
int key;
char other[RECORDLEN-sizeof(int)];
};

#ifdef HAVE_CONFIG_H
#include<config.h>
#endif

jtRecord.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// jtRecord.c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#include "HashFile.h"
#include "jtRecord.h"
#define KEYOFFSET 0
#define KEYLEN sizeof(int)
#define FileNAME "jing.txt"

void showHashFile();

int main(int argc, char *argv[])
{
struct jtRecord rec[6] = {
{1, "jing"}, {2, "wang"}, {3, "li"}, {4, "zhang"}, {5, "qing"}, {6, "yuan"}};
int j = 0;
for (j = 0; j < 6; j++)
{
printf("<%d,%d>\t", rec[j].key, hash(KEYOFFSET, KEYLEN, &rec[j], 6));
}
int fd = hashfile_creat(FileNAME, O_RDWR | O_CREAT, RECORDLEN, 6);
int i = 0;
printf("\nOpen and Save Record...\n");
fd = hashfile_open(FileNAME, O_RDWR, 0);
for (i = 0; i < 6; i++)
{
hashfile_saverec(fd, KEYOFFSET, KEYLEN, &rec[i]);
}
hashfile_close(fd);
showHashFile();
// Demo find Rec
printf("\nFind Record...");
fd = hashfile_open(FileNAME, O_RDWR, 0);
int offset = hashfile_findrec(fd, KEYOFFSET, KEYLEN, &rec[4]);
printf("\noffset is %d\n", offset);
hashfile_close(fd);
struct jtRecord jt;
struct CFTag tag;
fd = open(FileNAME, O_RDWR);
lseek(fd, offset, SEEK_SET);
read(fd, &tag, sizeof(struct CFTag));
printf("Tag is <%d,%d>\t", tag.collision, tag.free);
read(fd, &jt, sizeof(struct jtRecord));
printf("Record is {%d,%s}\n", jt.key, jt.other);
// Demo Delete Rec
printf("\nDelete Record...");
fd = hashfile_open(FileNAME, O_RDWR, 0);
hashfile_delrec(fd, KEYOFFSET, KEYLEN, &rec[2]);
hashfile_close(fd);
showHashFile();
// Demo Read
fd = hashfile_open(FileNAME, O_RDWR, 0);
char buf[32];
memcpy(buf, &rec[1], KEYLEN);
hashfile_read(fd, KEYOFFSET, KEYLEN, buf);
printf("\nRead Record is {%d,%s}\n",
((struct jtRecord *)buf)->key, ((struct jtRecord *)buf)->other);
hashfile_close(fd);
// Demo Write
printf("\nWrite Record...");
fd = hashfile_open(FileNAME, O_RDWR, 0);
hashfile_write(fd, KEYOFFSET, KEYLEN, &rec[3]);
hashfile_close(fd);
showHashFile();
return 0;
}

void showHashFile()
{
int fd;
printf("\n");
fd = open(FileNAME, O_RDWR);
lseek(fd, sizeof(struct HashFileHeader), SEEK_SET);
struct jtRecord jt;
struct CFTag tag;
while (1)
{
if (read(fd, &tag, sizeof(struct CFTag)) <= 0)
break;
printf("Tag is <%d,%d>\t", tag.collision, tag.free);
if (read(fd, &jt, sizeof(struct jtRecord)) <= 0)
break;
printf("Record is {%d,%s}\n", jt.key, jt.other);
}
close(fd);
}

运行结果

1687684049065

HashFile.h定义了哈希文件的基本结构和操作,包括创建、打开、关闭、读、写、删除、查找和保存记录等函数。

HashFile.c实现了哈希文件的所有操作。

jtRecord.h定义了一个结构体jtRecord,用于保存数据记录,包括键(key)和其他信息(other)。

jtRecord.c包含了对哈希文件的操作代码,包括打开文件、保存记录、显示文件、查找记录、删除记录、读取和写入记录等。

以下是对每个功能的描述:

  1. 创建哈希文件:创建一个文件,文件头部保存哈希文件的元信息,如总记录数、当前记录数等。

  2. 打开哈希文件:打开一个文件,首先读取文件头部的元信息,确认其为正确的哈希文件。

  3. 关闭哈希文件:关闭一个打开的文件。

  4. 读取哈希文件:根据关键字找到哈希地址,然后读取该地址的记录。

  5. 写入哈希文件:将一条记录保存到文件中,首先计算关键字的哈希地址,然后将记录保存到该地址。

  6. 删除哈希文件记录:根据关键字找到哈希地址,然后删除该地址的记录。

  7. 查找哈希文件记录:根据关键字计算哈希地址,然后在文件中找到对应的记录。

请给出实验过程中遇到的问题,并解释原因和解决方案

下面是对所提到的修改的转写:

  1. 在HashFile.h中添加了以下内容:
1
2
3
4
5
6
#ifndef HASHFILE_H
#define HASHFILE_H

// 原有的内容

#endif
  1. 在HashFile.h中添加了以下内容:
1
#include <sys/stat.h>
  1. 在HashFile.h中,将hashfile_creat函数的参数名recnum改为total_rec_num,并将hash函数的参数名recnum改为total_rec_num,以解决参数命名不一致导致的错误。

  2. 在HashFile.c中添加了以下内容:

1
2
#include <stdlib.h>
#include <memory.h>
  1. 将HashFile.c中的tag.free=1;修改为tag.free=-1;,以改变tag结构体中的free字段的赋值。

如果模拟一个inode区的前提下,请指出参考代码中creat函数需要如何修改?

如果要模拟一个inode区,creat函数需要进行如下修改:

  1. 在创建文件之前,需要分配一个新的inode来存储文件的元数据。可以使用一个自定义的数据结构来表示inode,其中包含文件的大小、类型、权限和数据块地址等信息。

  2. 需要修改创建文件时的逻辑,将文件的元数据信息存储到新分配的inode中。可以通过在inode区中查找一个可用的inode块,或者使用链表等数据结构来管理可用的inode块。

  3. 修改创建文件时的逻辑,将文件的数据块地址存储到inode中,以便后续读取和写入文件数据时可以使用。

  4. 在创建文件时,需要更新inode区的相关信息,如标记已使用的inode块、更新inode区的空闲inode块列表等。

请设计系统打开文件表和用户打开文件表,并给出相应函数的修改方案

首先,定义打开文件表的数据结构,包括文件描述符(fd)、文件名(filename)、文件标志(flags)、打开模式(mode)等信息。可以使用一个数组来表示打开文件表,每个条目表示一个打开的文件。

1
2
3
4
5
6
7
8
9
10
11
#define MAX_OPEN_FILES 100 // 最大打开文件数

typedef struct {
int fd;
char* filename;
int flags;
int mode;
// 其他文件元数据信息
} OpenFileEntry;

OpenFileEntry openFileTable[MAX_OPEN_FILES]; // 打开文件表

然后,根据上述需求,在hashfile_open函数和hashfile_close函数中进行相应的修改。

在hashfile_open函数中的修改方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int hashfile_open(const char* filename) {
int fd = -1;

// 查找openFileTable中fd为0的条目
for (int i = 0; i < MAX_OPEN_FILES; i++) {
if (openFileTable[i].fd == 0) {
fd = i;
break;
}
}

// 如果达到了MAX,打印错误消息,并返回-1
if (fd == -1) {
printf("Reached maximum number of open files.\n");
return -1;
}

// 尝试打开文件
// 如果成功打开文件,读取HashFileHeader并检查sig值
// 其他操作

return fd; // 返回文件描述符
}

在hashfile_close函数中的修改方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int hashfile_close(int fd) {
// 首先查找openFileTable中文件描述符fd与传入fd相匹配的条目
for (int i = 0; i < MAX_OPEN_FILES; i++) {
if (openFileTable[i].fd == fd) {
// 关闭文件并重置条目信息
// 其他操作

openFileTable[i].fd = 0;
openFileTable[i].filename = NULL;
openFileTable[i].flags = 0;
openFileTable[i].mode = 0;

return 0; // 返回成功
}
}

// 如果在openFileTable中没有找到匹配的条目,返回-1
return -1;
}