主要函数char* realpath(const char *path, char *resolved_path);linux
主要是想要测试下该函数自动扩展symbolic link时,最多容许symbolic link的多少层嵌套。(关键词:nested symbolic links)算法
结果:在linux 2.6.21下,最多容许20层嵌套。这个嵌套深度已经足够多了,因此,不必本身编写得到绝对路径的函数。直接使用该函数,而且对错误进行错误处理(而不是像示例代码中那样直接exit),基本上能够知足通常的编程须要了。shell
测试以下:编程
#!/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 ../ 20bash
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。好比:spa
dir1 = {link1, file1, file2, ..., filen}code
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 <limits.h> #include <stdlib.h> #include <stdio.h> #include <assert.h> #include <string.h> #include <errno.h> 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); }