2016-12-17 19 views
0

나는 지정된 디렉토리와 그 하위 디렉토리에있는 C 파일 사이의 모든 #include 의존성을 재귀 적으로 찾는 프로그램을 만들고있다. 종속 경로는 절대적이어야하므로 realpath을 사용하여 상대 경로와 심볼 링크를 해결하십시오. OpenMP 나 pthreads로 프로그램을 멀티 스레드하기로 결정한 파일이 많을 수 있습니다.C 멀티 스레딩과 realpath

문제는 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_DIRECTORY과 함께 open() 또는 openat() 디렉토리를 열면 *at()의 디렉토리 파일 설명자를 사용하여 파일에 적절하게 액세스 할 수 있습니다 (O_DIRECTORY은 100 % 필요하지 않으며 macOS에서도 지원되지 않음). 전화.

+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; 
}