主要函數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); }