我正在修改教学 OS xv6(用 c 编写)以支持符号链接(AKA 快捷方式)。符号链接是 T_SYM 类型的文件,其中包含指向其目标的路径。为此,我编写了一个递归函数,它获取路径和缓冲区并用“真实”路径填充缓冲区(即,如果路径包含链接,则应将其替换为真实路径,并且链接可能发生在路径中的任何级别)。
基本上,如果我有一个路径 a/b/c/d,以及从 f 到 a/b 的链接,那么以下操作应该是等效的:
cd a/b/c/d
cd f/c/d
现在,代码已经写好了,但我试图解决的问题是路径以“/”开头的问题(意味着路径是绝对的而不是相对的)。现在,如果我使用名为 /dir1 的路径运行它,它会将其视为 dir1(相对而不是绝对)。
这是主函数,它调用递归函数。pathname 是给定的路径,buf 将包含真实路径。
int readlink(char *pathname, char *buf, size_t bufsize){
char name[DIRSIZ];
char realpathname[100];
memset(realpathname,0,100);
realpathname[0] = '/';
if(get_real_path(pathname, name, realpathname, 0, 0)){
memmove(buf, realpathname, strlen(realpathname));
return strlen(realpathname);
}
return -1;
}
这是递归部分。该函数返回一个 inode 结构(表示系统中的文件或目录)。它在 realpath 中构建真实路径。ilock 和 iunlock 被用来安全地使用 inode。
struct inode* get_real_path(char *path, char *name, char* realpath, int position){
struct inode *ip, *next;
char buf[100];
char newpath[100];
if(*path == '/')
ip = iget(ROOTDEV, ROOTINO);// ip gets the root directory
else
ip = idup(proc->cwd); // ip gets the current working directory
while((path = skipelem(path, name)) != 0){name will get the next directory in the path, path will get the rest of the directories
ilock(ip);
if(ip->type != T_DIR){//if ip is a directory
realpath[position-1] = '\0';
iunlockput(ip);
return 0;
}
if((next = dirlookup(ip, name, 0)) == 0){//next will get the inode of the next directory
realpath[position-1] = '\0';
iunlockput(ip);
return 0;
}
iunlock(ip);
ilock(next);
if (next->type == T_SYM){ //if next is a symbolic link
readi(next, buf, 0, next->size); //buf contains the path inside the symbolic link (which is a path)
buf[next->size] = 0;
iunlockput(next);
next = get_real_path(buf, name, newpath, 0);//call it recursively (might still be a symbolic link)
if(next == 0){
realpath[position-1] = '\0';
iput(ip);
return 0;
}
name = newpath;
position = 0;
}
else
iunlock(next);
memmove(realpath + position, name, strlen(name));
position += strlen(name);
realpath[position++]='/';
realpath[position] = '\0';
iput(ip);
ip = next;
}
realpath[position-1] = '\0';
return ip;
}
我尝试了很多方法来做到这一点,但没有成功。如果有人看到问题,我很乐意听到解决方案。谢谢, 埃亚尔