2012-02-27 31 views
3

我正在編寫一個程序來模仿find的一些行爲,該行爲遍歷目錄樹並調用lstat來確定它們的類型。真正的find將忽略用戶在該目錄中沒有R或X訪問權限的文件。我似乎無法複製這種行爲;我的代碼將繼續並調用lstat,並獲得非法查找錯誤(這正是我試圖阻止的),即使執行此操作的代碼位於檢查access()的塊內部。Linux,C:access()沒有捕獲權限問題,或者其他什麼

我首先想到的是,也許是第二access()呼籲應該對路徑,而不是路徑/文件名,但似乎並沒有工作,要麼(而不是它多餘的呢?)

任何指導意見將不勝感激。

我的代碼(我切割出錯誤捕獲和其他的東西爲簡潔起見):

void open_dir(char *dir, char *pattern, char type) 
    { 
     DIR *d; 
     struct dirent *de; 

     if (access(dir, (R_OK | X_OK)) == 0) 
     { 
      d = opendir(dir); 

      while((de = readdir(d))) 
       examine_de(de, dir, pattern, type); 

      closedir(d); 
     } 
    } 

    void examine_de(struct dirent *de, char *dir, char *pattern, char type) 
    { 
     char fn[ _POSIX_PATH_MAX ]; 
     strcpy(fn, dir); 
     strcat(fn, "/"); 
     strcat(fn, de->d_name); 

     if (access(fn, (R_OK | X_OK)) == 0) 
     { 
      struct stat buf; 
      lstat(fn, &buf); 
      //check pattern matches, etc., printf fn if appropriate 
      if ((S_ISDIR(buf.st_mode)) && 
       (strcmp(de->d_name, ".") != 0) && 
       (strcmp(de->d_name, "..") != 0)) 
       open_dir(fn, pattern, type); 
     } 
     return; 
    } 

回答

4

lstat()應該從未返回ESPIPE(非法謀取)。你確定它不是另一個系統調用返回,或者在成功lstat()之後的值不變嗎? (換句話說,這個錯誤實際上可能在你的錯誤檢查代碼中,你已經忽略了)。

這就是說,存在這樣使用access()反正是沒有意義的 - 它只是引入了競爭條件(由於文件的權限可以在access()呼叫和opendir()/lstat()通話之間切換),並且不會獲得任何東西。只需選中的opendir()lstat()返回值來代替:

void open_dir(char *dir, char *pattern, char type) 
{ 
    DIR *d; 
    struct dirent *de; 

    if (d = opendir(dir)) 
    { 
     while((de = readdir(d))) 
      examine_de(de, dir, pattern, type); 

     closedir(d); 
    } 
} 

void examine_de(struct dirent *de, char *dir, char *pattern, char type) 
{ 
    char fn[ _POSIX_PATH_MAX ]; 
    struct stat buf; 

    strcpy(fn, dir); 
    strcat(fn, "/"); 
    strcat(fn, de->d_name); 

    if (lstat(fn, &buf) == 0) 
    { 
     //check pattern matches, etc., printf fn if appropriate 
     if ((S_ISDIR(buf.st_mode)) && 
      (strcmp(de->d_name, ".") != 0) && 
      (strcmp(de->d_name, "..") != 0)) 
      open_dir(fn, pattern, type); 
    } 
    return; 
} 

這通常是正確的模式 - 而不是檢查,看是否操作可能會工作,然後嘗試操作,而不是無條件地試操作,然後檢查原因它失敗了。

+0

+1用於指出造成'access'無用的種族。 – 2012-02-27 02:36:33

+0

你可能認爲這是一個非正式的評論,但是我發現在每個perror之後設置'errno = 0'有所不同,特別是在'readdir'錯誤檢查的情況下,因爲'readdir'返回NULL目錄*和*的末尾出現錯誤,所以我的代碼在繼續之前檢查是否有'errno == 0'。但我肯定也會考慮到你有關「訪問」的警告 - 謝謝! – 2012-02-27 02:54:35

+1

@SabrinaStar:你應該在* readdir()調用之前立即設置'errno = 0;'這裏重要的一點是調用不成功的調用會設置'errno',但成功的調用不會改變'errno'。 – caf 2012-02-27 03:20:33