// 1 double direct block[12] => 256 * [0 ~ 255] if(bn < NINDIRECT * NINDIRECT){ int mid_addr_num = bn / NINDIRECT; // get mid_addr_num and c-style: divide(/) to down bn = bn % NINDIRECT; // get real bn
// Load indirect block, allocating if necessary. if((addr = ip->addrs[NDIRECT + 1]) == 0) ip->addrs[NDIRECT + 1] = addr = balloc(ip->dev); // get the addr of mid_addr_num bp = bread(ip->dev, addr); a = (uint*)bp->data; if((addr = a[mid_addr_num]) == 0){ a[mid_addr_num] = addr = balloc(ip->dev); log_write(bp); } brelse(bp);
// get the addr of real bn 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; } panic("bmap: out of range"); }
// Truncate inode (discard contents). // Caller must hold ip->lock. void itrunc(struct inode *ip) { int i, j, k; structbuf *bp; uint *a, *botton_a;
// create ip if not exist if((ip = namei(path)) == 0){ // diff char* path if((ip = create(path, T_SYMLINK, 0, 0)) == 0){ end_op(); return-1; } }
// not have to handle symbolic links to directories for this lab. if(ip_target){ if(ip_target->type == T_DIR){ end_op(); return-1; } }
// inode(ip) with lock return from create(path) // inode(ip) without lock return from namei(path) // so we need to check and maybe ilock it if(!holdingsleep(&ip->lock)){ ilock(ip); } ip->sym_link = ip_target; iupdate(ip); iunlock(ip); end_op(); return0; }
// Modify the open system call to handle the case where the path refers to a symbolic link. // If the file does not exist, open must fail. // When a process specifies O_NOFOLLOW in the flags to open, // open should open the symlink (and not follow the symbolic link). uint64 sys_open(void) { char path[MAXPATH]; int fd, omode; structfile *f; structinode *ip; int n;
if(omode & O_CREATE){ ip = namei(path); if(ip){ // if it is T_SYMLINK, we just change it type if(ip->type == T_SYMLINK){ ip->type = T_FILE; ip->major = ip->minor = 0; } else{ // if not T_SYMLINK we need free it, then create a inode // becasue it is a new path so we can sure 'ip->ref == 1' // 'ip->ref == 1'(namei()=>namex()=>idup()=>ip->ref++=>1) iput(ip); ip = create(path, T_FILE, 0, 0); if(ip == 0){ end_op(); return-1; } } } else{ ip = create(path, T_FILE, 0, 0); if(ip == 0){ end_op(); return-1; } } } else{ if((ip = namei(path)) == 0){ end_op(); return-1; } ilock(ip); if(ip->type == T_DIR && omode != O_RDONLY){ iunlockput(ip); end_op(); return-1; } }
// FOLLOW => follow symlink if(!(omode & O_NOFOLLOW)){ // we set threshold = 10, so we only check 10 times int threshold = 10; for(int i = 0; i < threshold; i++){ iunlockput(ip); ip = ip->sym_link; ilock(ip); if(ip->type != T_SYMLINK){ break; } }
// we need to ip->ref-- or free symlink when we call unlink if(ip->type == T_SYMLINK){ iput(ip); }
end_op();
return0;
bad: iunlockput(dp); end_op(); return-1; }
result
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
make[1]: Leaving directory '/home/duile/xv6-labs-2021' == Test running bigfile == $ make qemu-gdb running bigfile: OK (170.2s) (Old xv6.out.bigfile failure log removed) == Test running symlinktest == $ make qemu-gdb (0.9s) == Test symlinktest: symlinks == symlinktest: symlinks: OK == Test symlinktest: concurrent symlinks == symlinktest: concurrent symlinks: OK == Test usertests == $ make qemu-gdb usertests: OK (294.8s) == Test time == time: OK Score: 100/100