0

私は指定されたディレクトリとその子ディレクトリのCファイル間のすべての#include依存関係を再帰的に見つけるプログラムを作成しています。依存パスは絶対パスでなければならないので、私はrealpathを使って相対パスとシンボリックリンクを解決します。多くのファイルが存在する可能性があるので、私はプログラムをOpenMPまたはpthreadsでマルチスレッド化することに決めました。Cマルチスレッドとリアルパス

問題は、realpathが作業ディレクトリを通るパスを解決することです。すべてのスレッドが同じ作業ディレクトリを共有しているので、mutexを置く必要があります。chdirとrealpath。

realpathには、パスを引数として解決するためのディレクトリをとる代替標準関数がありますか?

+1

なぜ、各スレッドに、現在のパスの文字列を開始ディレクトリからの相対的な文字列にするのではなく、あなたはサブディレクトリに降りるたびにそれを追加することができ、出てくるレベルを削除することができます。とにかく '#include" common/util.h "'のような相対パスしか表示されません。コンパイラに与えるインクルードパス '-I'で解決する必要があります。その情報がなければ、とにかくフルパスを正しく解決しているかどうか分かりません。 – e0k

+0

あなたは正しいです、それはおそらく私が行くソリューションです。シンボリックリンクは解決しませんが、シンボリックリンクにはファイルが含まれています。私は心を持ってくれてありがとう、私もそれを修正します。 –

+0

多くの人がsymlinkヘッダーを使います。少なくとも、私が取り組んだ大きなプロジェクトのいくつかは、ヘッダーがさまざまな理由でシンボリックリンクされています(その多くはあまり良くありませんが、30年以上かかることです)。 –

答えて

2

at接尾辞(たとえばopenat()など)が指定されたディレクトリで動作するPOSIX関数がいくつかあります。しかし、POSIXにはrealpathat()の機能はありません。 opendirat()もありませんが、fdopendir()があり、オープンディレクトリのファイル記述子にはDIRストリームが作成されます。

マルチスレッドプログラムでは、chdir()を使用すると問題が発生します。

さまざまな*at()関数を使用するようにアルゴリズムを再考して、ディレクトリをまったく変更する必要がないようにする必要があります。 O_DIRECTORYopen()またはopenat()のディレクトリを開きます(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; 
} 
関連する問題