主要函数char* realpath(const char *path, char *resolved_path);
主要是想要测试下该函数自动扩展symbolic link时,最多允许symbolic link的多少层嵌套。(关键词:nested symbolic links)
结果:在linux 2.6.21下,最多允许20层嵌套。这个嵌套深度已经足够多了,所以,没必要自己编写获得绝对路径的函数。直接使用该函数,并且对错误进行错误处理(而不是像示例代码中那样直接exit),基本上可以满足一般的编程需要了。
测试如下:
#!/bin/bash
## generate_link file depth
print_usage()
{
echo -e "\033[40;31;1m Usage: generate_link.sh file depth \033[0m"
}
## check para num
if [ $# -ne 2 ]; then
print_usage
exit 1
fi
file=${1}
depth=${2}
ln -s ${file} link1
for ((count=1;count<=${depth};count++)); do
ln -s link${count} link$((count+1))
done
./generate_link.sh ../ 20
ls
common.h getrealpath.c link11 link14 link17 link2 link3 link6 link9 test
generate_link.sh link1 link12 link15 link18 link20 link4 link7 Makefile test.c
generate_link.sh~ link10 link13 link16 link19 link21 link5 link8 Makefile~ test.c~
chenqi@chenqi-laptop ~/MyPro/CFiles/detect_recursive_dir $./test link20
/home/chenqi/MyPro/CFiles
chenqi@chenqi-laptop ~/MyPro/CFiles/detect_recursive_dir $ ./test link21
Getting realpath of [link21] failed: Too many levels of symbolic links
另外,之所以想到要测试下嵌套层数,是因为我想要写个探测某目录是否包含递归循环引用。这个程序本身不难,就是遍历目录,对三种情况分别处理(directory, symbolic link, other)。因为递归循环引用只能由symbolic link,或者directory引起,所以,每次处理directory时,要记录其绝对路径,维护一份stack,进行入栈,出栈操作,并且在入栈时进行绝对路径的对比;处理symbolic link时,如果其扩展后绝对路径不是dir,肯定不会引起循环引用问题,如果是dir,则处理该dir。比如:
dir1 = {link1, file1, file2, ..., filen}
dir2 = {link2, file1, file2, ..., filen}
link1 -> dir2; link2 -> dir1
于是遍历dir1时,有如下计算顺序:
处理dir1,dir1是一个目录,所以入栈,今后,如果再有元素入栈,而该元素的路径是dir1或者dir1的父路径,则出现递归循环引用。
处理link1,link1是一个symbolic link,获得其绝对路径dir2.
处理dir2,dir2是一个目录,所以入栈。dir2不是dir1,也不是dir1的父路径。
处理link2,link2是一个sym link,获得其绝对路径dir1.
处理dir1,目录,入栈。dir1是栈中元素dir1,所以出现递归循环引用。记录,输出。
处理dir2中的file2.....
dir2处理完成,dir2出栈。
处理dir1中的file2等
总体来说,处理目录之初进栈,并且判断,处理完目录出栈;处理sym link时,如果其绝对路径是dir,则处理该dir。
所以,如上所述,该算法中有两个关键的subroutine,一个是获得绝对路径。一个是判断某目录是否是另外一个目录或者其父目录。
如上测试,realpath能解析20层的symbolic link嵌套,绝对满足要求。
代码如下:
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
assert(argc == 2);
const char *filepath = argv[1];
char *real_path = realpath(filepath, NULL);
if (real_path == NULL) /* failed */
{
fprintf(stderr, "Getting realpath of [%s] failed: %s \n",
filepath, strerror(errno));
exit(EXIT_FAILURE);
}
else /* succeed */
{
printf("%s\n", real_path);
free(real_path);
}
exit(EXIT_SUCCESS);
}