Nathanaël

纳塔纳埃尔,切莫再想去尝试旧日的清水

0%

lab-9-fs

lab-fs

Large files

修改fs.h中关于直接块间接块的定义,前11块为直接快,第12块为一级间接块,第13块为二级间接块。

1
2
3
4
#define NDIRECT 11
#define NINDIRECT (BSIZE / sizeof(uint))
#define NDUBINDIRECT (BSIZE / sizeof(uint)) * (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT + NDUBINDIRECT)

当要访问的bn(block number)大于NDIRECT + NINDIRECT时,访问二级间接块,仿照一级间接块的查询方式即可,注意需要查询两级地址。

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
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;

if(bn < NDIRECT){
if((addr = ip->addrs[bn]) == 0)
ip->addrs[bn] = addr = balloc(ip->dev);
return addr;
}
bn -= NDIRECT;

if(bn < NINDIRECT) {
// Load indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT]) == 0)
ip->addrs[NDIRECT] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if((addr = a[bn]) == 0){
a[bn] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
bn -= NINDIRECT;
if (bn < NDUBINDIRECT)
{
if((addr = ip->addrs[NDIRECT + 1]) == 0) {
ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev);
}
uint indirect_index = bn / (NINDIRECT);
uint offset = bn % NINDIRECT;
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if((addr = a[indirect_index]) == 0) {
a[indirect_index] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);

bp = bread(ip->dev,addr);
a = (uint*)bp->data;
if((addr = a[offset]) == 0) {
a[offset] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}

确保itrunc释放文件的所有块,包括二级间接块。

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
void
itrunc(struct inode *ip)
{
int i, j;
struct buf *bp;
struct buf *indirect_bp;
uint *a;
uint *b;
int indirect_index,offset;
for(i = 0; i < NDIRECT; i++){
if(ip->addrs[i]){
bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0;
}
}

if(ip->addrs[NDIRECT]){
bp = bread(ip->dev, ip->addrs[NDIRECT]);
a = (uint*)bp->data;
for(j = 0; j < NINDIRECT; j++){
if(a[j])
bfree(ip->dev, a[j]);
}
brelse(bp);
bfree(ip->dev, ip->addrs[NDIRECT]);
ip->addrs[NDIRECT] = 0;
}

if(ip->addrs[NDIRECT + 1]) {
bp = bread(ip->dev, ip->addrs[NDIRECT + 1]);
a = (uint*)bp->data;
for(indirect_index = 0; indirect_index < NINDIRECT; indirect_index++) {
if(a[indirect_index]) {
indirect_bp = bread(ip->dev,a[indirect_index]);
b = (uint*)indirect_bp->data;
for(offset = 0; offset < NINDIRECT; offset++) {
if(b[offset]) {
bfree(ip->dev,b[offset]);
}
}
brelse(indirect_bp);
bfree(ip->dev,a[indirect_index]);
}
}
brelse(bp);
}
ip->size = 0;
iupdate(ip);
}

stat.h内定义 T_SYMLINK 类型。

1
#define T_SYMLINK 4   //soft link

fcntl.h定于新标志O_NOFOLLOW

1
#define O_NOFOLLOW 0x1000

仿照其他文件系统调用,实现sys_symlink。在新创建的inode的数据块中保存目标路径target字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
uint64
sys_symlink(void)
{
char taget[MAXPATH], path[MAXPATH];
struct inode *ip;
begin_op();
if(argstr(0, taget, MAXPATH) < 0 || argstr(1, path, MAXPATH) < 0)
return -1;
if ((ip = create(path, T_SYMLINK, 0, 0)) == 0) {
end_op();
return -1;
}
if(writei(ip,0,(uint64)taget,0,MAXPATH) < MAXPATH) {
end_op();
return -1;
}
iunlockput(ip);
end_op();
return 0;
}

修改sys_open。当打开文件类型为T_SYMLINK时,首先判断是否指定标志O_NOFOLLOW,如果制定了,则按照打开其他类型文件一样处理。否则需要不断递归查询真实文件路径。

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
uint64
sys_open(void)
{
...
if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
iunlockput(ip);
end_op();
return -1;
}

if(ip->type == T_SYMLINK) {
if(!(omode & O_NOFOLLOW)) {
int cnt = 0;
char target[MAXPATH];
while(ip->type == T_SYMLINK) {
if(cnt >= 10) {
iunlockput(ip);
end_op();
return -1;
}
cnt++;
readi(ip,0,(uint64)target,0,MAXPATH);
iunlockput(ip);
if((ip = namei(target)) == 0) {
end_op();
return -1;
}
ilock(ip);
}
}
}
...
}