aboutsummaryrefslogtreecommitdiff
path: root/src/find.c
blob: 348a8f75de5f9a2036c4bf3b73ffbfdf908c1706 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
 * @file find.c
 */
#include "spm.h"

/**
 * glob callback function
 * @param epath path to file that generated the error condition
 * @param eerrno the error condition
 * @return the error condition
 */
int errglob(const char *epath, int eerrno) {
    fprintf(stderr, "glob matching error: %s (%d)", epath, eerrno);
    return eerrno;
}

/**
 * Scan a directory for a file by name, or by wildcard
 *
 * @param root directory path to scan
 * @param filename file to find (wildcards accepted)
 * @return success=path to file, failure=NULL
 */
char *find_file(const char *root, const char *filename) {
    glob_t results;
    int glob_flags = 0;
    int match = 0;
    char path[PATH_MAX];
    memset(path, '\0', PATH_MAX);

    // GUARD
    if (!root || !filename || strstr(filename, "..") || strstr(filename, "./")) {
        return NULL;
    }

    if (realpath(root, path) == NULL) {
        perror("Cannot determine realpath()");
        fprintf(SYSERROR);
        return NULL;
    }

    strcat(path, "/");
    strcat(path, filename);

    // Save a little time if the file exists
    if (access(path, F_OK) != -1) {
        return strdup(path);
    }

    // Inject wildcard
    strcat(path, "*");
    // Search for the file
    match = glob(path, glob_flags, errglob, &results);

    if (match != 0) {
        // report critical errors except GLOB_NOMATCH
        if (match == GLOB_NOSPACE || match == GLOB_ABORTED) {
            fprintf(SYSERROR);
        }
        globfree(&results);
        return NULL;
    }

    // Replace path string with wanted path string
    strcpy(path, results.gl_pathv[0]);

    globfree(&results);
    return strdup(path);
}

/**
 * Scan the package directory for a package by name
 * @param filename file to find
 * @return success=path to file, failure=NULL
 */
char *find_package(const char *filename) {
    char *repo = join((char *[]) {SPM_GLOBAL.package_dir, SPM_GLOBAL.repo_target, NULL}, DIRSEPS);
    char *match = find_file(repo, filename);
    free(repo);
    return match;
}

/**
 * Determine whether `pattern` is present within a file
 * @param filename
 * @param pattern
 * @return 0=found, 1=not found, -1=OS error
 */
int find_in_file(const char *filename, const char *pattern) {
    int result = 1;  // default "not found"

    FILE *fp = fopen(filename, "rb");
    if (!fp) {
        return -1;
    }

    long int file_len = get_file_size(filename);
    if (file_len == -1) {
        fclose(fp);
        return -1;
    }
    char *buffer = (char *)calloc((size_t) file_len, sizeof(char));
    if (!buffer) {
        fclose(fp);
        return -1;
    }
    size_t pattern_len = strlen(pattern);

    fread(buffer, (size_t) file_len, sizeof(char), fp);
    fclose(fp);

    for (size_t i = 0; i < (size_t) file_len; i++) {
        if (memcmp(&buffer[i], pattern, pattern_len) == 0) {
            result = 0;  // found
            break;
        }
    }
    free(buffer);
    return result;
}

/**
 * Get the full path of a shell command
 * @param program
 * @return success=absolute path to program, failure=NULL
 */
char *find_executable(const char *program) {
    int found = 0;
    char *result = NULL;
    char *env_path = NULL;
    env_path = getenv("PATH");
    if (!env_path) {
        return NULL;
    }
    char **search_paths = split(env_path, ":");

    char buf[PATH_MAX];
    for (int i = 0; search_paths[i] != NULL; i++) {
        sprintf(buf, "%s%c%s", search_paths[i], DIRSEP, program);
        if (access(buf, F_OK | X_OK) == 0) {
            found = 1;
            break;
        }
        memset(buf, '\0', sizeof(buf));
    }
    if (found) {
        result = strdup(buf);
    }
    split_free(search_paths);
    return result;
}