2016-12-17 114 views
0

我正在創建一個遞歸查找指定目錄及其子目錄中的C文件之間的所有#include依賴關係的程序。相關路徑應該是絕對的,所以我使用實際路徑來解析相對路徑和符號鏈接。由於可以有很多文件,因此我決定使用OpenMP或pthread構建多線程程序。C多線程和實時路徑

問題是realpath解析了通過工作目錄的路徑。所有線程共享相同的工作目錄,所以我需要在chdir和realpath上設置互斥鎖。

是否有任何實時路徑的替代標準函數,它也需要目錄來解析作爲參數的路徑?

+1

爲什麼不只是讓每個線程都保持一個相對於您的起始目錄的當前路徑字符串?每當你進入一個子目錄時,你都可以追加它,並在你出來時刪除一個關卡。無論如何,你通常只會看到相對路徑,比如'#include「common/util.h」'。它們必須通過給編譯器的包含路徑「-I」來解決。沒有這些信息,我不知道你是如何正確解決完整路徑的。 – e0k

+0

你說得對,那可能是我將要解決的問題。它不能解決符號鏈接,但真正的符號鏈接包含文件..?感謝你帶來 - 我想,我會解決這個問題。 –

+0

很多人的符號鏈接標題。或者,至少,我工作過的一些更大的項目有各種不同的原因(其中許多不是很好,但這是30多年發生的事情)符號鏈接。 –

回答

2

有許多POSIX函數,後綴at(例如openat())與指定的目錄一起使用。然而,POSIX中並沒有這樣的功能。也沒有opendirat(),但有fdopendir()它爲打開的目錄文件描述符創建一個DIR流。

在多線程程序中,任何對chdir()的使用都是充滿的。

您應該重新考慮使用各種*at()函數的算法,以避免需要更改目錄。您可以打開讀取目錄(open()openat()O_DIRECTORY,也許 - 雖然O_DIRECTORY不是100%必需的,也不支持在macOS上),以便您可以使用*at()中的目錄文件描述符適當地訪問文件調用。

+0

這會解決我的問題嗎? –

+0

我相信是這樣,但我還沒有代碼顯示如此。 –

0

我在解決方案上工作了一下。這絕不是最佳的,但至少它似乎工作。我創建了函數abspathat它將相對路徑變成絕對路徑。然後我使用內置的readlinkat來修復符號鏈接。該解決方案處理將諸如「../code.c」「./code.c」「code.c」的路徑轉換爲「/dir/code.c」。然而,它目前不能修復諸如../dir/../code.c的路徑,但爲什麼有人會創建這樣的路徑。它也不檢查文件是否真的存在。隨意改善或做任何你喜歡的代碼。

#include <string.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <dirent.h> 
#include <stdio.h> 
/*****************************************************************************/ 
char *abspathat(char *dirpath, int dirlen, char *path); 
/*****************************************************************************/ 
static const int MAX_FILEPATH = 4096; 
/*****************************************************************************/ 
char *realpathat(int dirfd, char *dirpath, int dirlen, char *path) { 
    char *abs = abspathat(dirpath, dirlen, path); 
    char *buf = malloc(sizeof(char)*MAX_FILEPATH); 
    ssize_t size = readlinkat(dirfd, abs, buf, MAX_FILEPATH); 
    char *realpath; 
    if(size != -1) { 
     realpath = malloc(sizeof(size+1)); 
     memcpy(realpath, buf, size); 
     realpath[size] = '\0'; 
     free(abs); 
    } else { 
     realpath = abs; 
    } 
    free(buf); 
    return realpath; 
} 
/*---------------------------------------------------------------------------*/ 
char *abspathat(char *dirpath, int dirlen, char *path) { 
    /* If absolute */ 
    if(path[0] == '/') { 
     return path; 
    } 
    int i; 
    char *right; 
    int d = 0; 
    int rlen = strlen(path); 
    int llen = 0; 
    if(path[0] == '.') { 
     if(path[1] == '.' && path[2] == '/') { 
      for(i = 3, d = 1; path[i] == '.' 
        && path[i+1] == '.' 
        && path[i+2] == '/' 
        && i < rlen; i+=3) { 
       d++; 
      } 
      right = &path[i]; 
      rlen -= i; 
     } else if(path[1] == '/') { 
      right = &path[2]; 
      rlen -= 2; 
     } 
    } else { 
     right = &path[0]; 
    } 
    for(i = dirlen - 1 - (dirpath[dirlen-1] == '/'); d && i; i--) { 
     if(dirpath[i] == '/') { 
      d--; 
     } 
    } 
    llen = i+1; 
    char *cpy = malloc(sizeof(char)*(llen + rlen + 2)); 
    memcpy(cpy, dirpath, llen); 
    cpy[llen] = '/'; 
    memcpy(cpy+llen+1, right, rlen); 
    cpy[llen+rlen+1] = '\0'; 
    return cpy; 
} 
/*---------------------------------------------------------------------------*/ 
int main(int argc, char *argv[]) { 
    if(argc == 3) { 
     char *dirpath = argv[1]; 
     DIR *d = opendir(dirpath); 
     char *path = argv[2]; 
     char *resolved = realpathat(dirfd(d), dirpath, strlen(dirpath), path); 
     printf("%s\n", resolved); 
    } else { 
     printf("realpathat [directory] [filepath]\n"); 
    } 
    return 0; 
}