终于还是来到了最后一次上机。
可能是作为第一届拥有OS官方课下答案的试验品,同学们对OS整体架构的把握情况貌似远不如前。毕竟花的时间可能确确实实地少了。
我自己则更是深刻感受到与学长们的差距。直到上机,也还在疯狂地寻找结构体成员的名字是什么,找结构体在哪里宏定义,找各种各样的lookup,walk与get究竟要怎么用。
在上机前,我还在抱有幻想。我自以为对各种方法的基本功能不太陌生。给我一个方法名,我知道大概记得它能得到什么,它会改变什么。
但我并没有意识到我根本不会用。当我真的要填写参数的时候,这里要填谁?这个参数来源于谁?那个结构体成员变量名到底是谁?
exam
这次的exam我个人认为是不难的。尽管总共用了1个小时,中途de了很久bug,但是上完机和别人交流后发现花费1个小时貌似并不是特别长。
题面
见:
1
|
https://demiurge-zby.github.io/p/%E5%8C%97%E8%88%AAos-lab5-%E4%B8%8A%E6%9C%BA/lab5_exam.pdf
|
其实题目本身并不是很简单,但是给的提示太全面了。本来我看到深搜的时候有点慌,但是具体实现都已经给出来了。
基本上所有人在这里卡住,都只是把path与name拼接时出错。不过这也是这道题在给予如此多的提示之下最大的难点了。
不过,这个难点并不是很易于察觉。
注意到题干上明确指出了给出的path以’/‘结尾。
但是样例上在输出时却又发现结尾并不含’/’。
这意味着我们至少要做出一点改动:
要么保证所有的path都以’/‘结尾,但保存时要把最后一个’/‘变为’\0’
如果保证path以’/‘结尾,在拼接时应当直接拼接name再加上’/’
要么就保证所有的path都不以’/‘结尾,保存时直接用path
这样的话,我们就需要在拼接时,先在path后追加’/’,再拼接name
但是刚开始的path是保证以’/‘结尾的,因此,在path后追加’/‘时,要先判断现在的结尾是不是’/’
这时有同学要说了:哎呀这也太复杂了吧,这怎么想得到呢?
为了让大家顺利通过,助教现场添加了一条又一条新的HINT,并疯狂地参与答疑。
最后的结果应当是不错的。
代码
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
|
int traverse_file(const char *path, struct File *file, const char *name, struct Find_res *res) {
u_int nblock;
nblock = file->f_size / BLOCK_SIZE;
// debugf("now path is %s\n", path);
// 1. 检查路径长度是否符合要求,如不符合,直接返回
if (strlen(path) == 0 || strlen(path) > MAXPATHLEN/* path 的长度为零或不小于最大路径长度*/) {
/*返回*/
return;
}
// 2. 比较当前文件名是否等于 name,如果相等则更改 res
if (strcmp(name, file->f_name) == 0/*file 的名字等于 name*/) {
// debugf("path is %s, name is %s\n", path, file->f_name);
/*增加 res->count*/res->count++;
/*添加 res 的路径*/strcpy(res->file_path[res->count - 1], path);
}
if (file->f_type == FTYPE_DIR) {
for (int i = 0; i < nblock; i++) {
void *blk;
try(file_get_block(file, i ,&blk));
struct File *files = (struct File *)blk;
for (struct File *f = files; f < files + FILE2BLK; ++f) {
char curpath[MAXPATHLEN + MAXNAMELEN + 3];
// 3. 把 path 和 name 拼接起来得到下一层文件路径,注意结尾的 '\0'
// 提示:我们没有实现 strcat 工具函数,你可以用 strcpy 实现拼接
strcpy(curpath, path);
if (curpath[strlen(curpath) - 1] != '/') {
strcpy(curpath + strlen(curpath), "/\0");
}
strcpy(curpath + strlen(curpath), f->f_name);
strcpy(curpath + strlen(curpath), "\0"); // 其实可以不需要
// 4. 递归调用 traverse_file 函数
traverse_file(curpath, f, name, res);
}
}
}
return 0;
}
int find_files(const char *path, const char *name, struct Find_res *res) {
struct File *file;
int r;
// 用 walk_path 来找到 path 对应的文件夹
// Lab5-Exam: Your code here. (1/2)
if ((r = walk_path(path, 0, &file, 0)) < 0) {
return r;
} // debugf("I have found\n");
// 在 path 对应的文件夹下面遍历,找到所有名字为 name 的文件,你可以调用下面的参考函数 traverse_file
// Lab5-Exam: Your code here. (2/2)
traverse_file(path, file, name, res);
return 0;
}
|
jby学长出的很有意思的综合性很强的加密文件extra。
其实流程给的也很详细了,奈何自己的熟练程度还是太差。
题面
见:
1
|
https://demiurge-zby.github.io/p/%E5%8C%97%E8%88%AAos-lab5-%E4%B8%8A%E6%9C%BA/lab5_extra.pdf
|
错误的代码
下面是我跟着流程,装模作样写出来的其中一个函数。其中很多用法自己也不确定,*(blk->data) != FS_MAGIC
好像还编译错误了。(我还特意看了block的data是字节的指针呢。 哦,笔者刚刚意识到FS_MAGIC是字)
仅仅这么点看起来很公式,很平凡的代码,还充满了提示,我却足足用了半个多小时的时间。此时还有8个有流程的函数没有完成,还有serve_map与serve_close没有修改。
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
|
void serve_key_set(u_int envid, struct Fsreq_key_set *rq) {
// 判断当前状态是否已加载密钥,如果已加载密钥, IPC 返回 -E_BAD_KEY
if (encrypt_key_set != 0) {
ipc_send(envid, -E_BAD_KEY, 0, 0);
return;
}
// 利用 open_lookup 找到对应的 Open 结构体,判断文件大小是否至少有两个磁盘块大小
// 利用 file_get_block 读取文件的第一个磁盘块,判断第一个字是否为 FS_MAGIC
// 如果密钥文件不合法, IPC 返回 -E_INVALID_KEY_FILE
struct Open *o;
if ((r = open_lookup(envid, rq->req_fileid, &pOpen)) < 0) {
ipc_send(envid, r, 0, 0);
return;
}
if (o->o_file->f_size < 2 * BLOCKSIZE) {
ipc_send(envid, -E_INVALID_KEY_FILE, 0, 0);
return;
}
struct Block *blk;
if ((r = file_get_block(o->o_file, 0, &blk)) < 0) {
ipc_send(envid, r, 0, 0);
return;
}
if (*(blk->data) != FS_MAGIC) {
ipc_send(envid, -E_INVALID_KEY_FILE, 0, 0);
return;
}
// 利用 file_get_block 读取文件的第二个磁盘块,将密钥复制到 encrypt_key 中
if ((r = file_get_block(pOpen->o_file, 1, &blk)) < 0) {
ipc_send(envid, r, 0, 0);
return;
}
strcpy(encrypt_key, blk->data);
// 将当前状态标记为已加载密钥
encrypt_key_set = 1;
// IPC 返回 0
ipc_send(envid, 0, 0, 0);
}
|
后记
OS上机结束了,回头看来,真是一无是处。曾经还在为lab0-extra懊悔不已,现在已经连连溃败。
OOhw13因为重构代码,漏了一句很重要的话,却没被中测测出来,导致强测完全失败,比hw7的分数还要低得多。
乒乓球也因为平时没有经常与老师交流,考试时错误频出,等待下周再次测试。
没几天就要去考OS理论期末了。准确来说,就是端午节假期后的第一个上午。本学期最高学分的课程就要结束了。
祝好运。