mechanicker icon

abspath implementation without filesystem calls

mechanicker | PRO | 01/15/23 01:52:05 PM UTC | 0 ⭐ | 1317 👁️ | Never ⏰ | []
C |

1.6 KB

|

Source Code

|

0 👍

/

0 👎

// Regex pattern to detect if path is relative by
// matching for valid '.' or '..' path components
static const regex_t dot_regex;
static const char *dot_pattern = "(^\\.{1,2}/|/\\.{1,2}/|/\\.{1,2}$)";
 
// Initializer function automatically invoked when shared library is loaded
__attribute__((constructor)) static void library_initialize(void)
{
    int err;
    if ((err = regcomp((regex_t *)&dot_regex, dot_pattern,
               REG_EXTENDED | REG_NOSUB))) {
        fprintf(stderr, "error err=%d compiling regex=%s\n", err,
            dot_pattern);
        abort();
    }
}
 
static int make_abspath(const char *src, char *buff, size_t size)
{
    // Check if we even have relative path to resolve by
    // looking for '.' before the last directory component
    const char *rpos = strrchr(src, '/');
    if (!rpos || rpos == src || regexec(&dot_regex, src, 0, NULL, 0)) {
        GITCEPTOR_TRACE("not a relative path=%s\n", src);
        strncpy(buff, src, size);
        return 0;
    }
 
    char *last = NULL;
    char path[PATH_MAX];
    buff[0] = '\0';
    strncpy(path, src, sizeof(path));
 
    for (char *word = strtok_r(path, "/", &last); word;
         word = strtok_r(NULL, "/", &last)) {
        // Skip referring to current directory or repeat slash
        if (!*word || !strcmp(word, ".")) {
            continue;
        }
 
        // Traverse up to parent directory by popping the current leaf
        if (!strcmp(word, "..")) {
            char *right_slash = strrchr(buff, '/');
            if (right_slash) {
                right_slash[0] = '\0';
            }
            continue;
        }
 
        // Append valid directory component to absolute path
        strncat(buff, "/", size);
        strncat(buff, word, size);
    }
 
    return '\0' == *buff ? -1 : 0;
}

Comments