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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
#include "spm.h"
extern const char *METADATA_FILES[];
static int verify_filelist(size_t lineno, char **a) {
if (lineno == 0) {
if (strncmp((*a), SPM_PACKAGE_HEADER_FILELIST, strlen(SPM_PACKAGE_HEADER_FILELIST)) != 0) {
fprintf(stderr, "invalid or missing header: line %zu: %s (expected: '%s')\n",
lineno, (*a), SPM_PACKAGE_HEADER_FILELIST);
return 1;
}
}
return -1;
}
#pragma GCC diagnostic ignored "-Wunused-parameter"
static int verify_depends(size_t lineno, char **a) {
return -1;
}
static int verify_descriptor(size_t lineno, char **a) {
if (lineno == 0) {
if (strncmp((*a), SPM_PACKAGE_HEADER_DESCRIPTOR, strlen(SPM_PACKAGE_HEADER_DESCRIPTOR)) != 0) {
fprintf(stderr, "invalid or missing header: line %zu: %s (expected: '%s')\n",
lineno, (*a), SPM_PACKAGE_HEADER_DESCRIPTOR);
return 1;
}
}
return -1;
}
static int verify_prefix(size_t lineno, char **a) {
size_t parity = lineno % 2;
if (parity == 0 && *(*a) == '#') {
return 0;
}
else {
return 1;
}
}
#pragma GCC diagnostic ignored "-Wunused-parameter"
static int verify_no_op(size_t lineno, char **a) {
return -1;
}
#pragma GCC diagnostic ignored "-Wunused-parameter"
static int reader_metadata(size_t lineno, char **line) {
(*line) = strip((*line));
if (isempty((*line))) {
return 1; // indicate "continue"
}
return 0; // indicate "ok"
}
/**
* Detect the type of metadata based on file name and execute the appropriate function against each line
* in the file. Verification can be disabled by passing a non-zero value as the second argument.
* @param filename
* @param no_verify SPM_METADATA_VERIFY or SPM_METADATA_NO_VERIFY
* @return array of strings (line endings removed)
*/
char **spm_metadata_read(const char *_filename, int no_verify) {
char *filename = strdup(_filename);
char **data = NULL;
char **result = NULL;
size_t start = 0;
ReaderFn *func_verify;
// Guard
if (file_is_metadata(filename) == 0) {
free(filename);
return NULL;
}
// Setup function pointer and data starting offsets (if any)
if (strcmp(basename(filename), SPM_META_FILELIST) == 0) {
func_verify = verify_filelist;
start = 1;
} else if (strcmp(basename(filename), SPM_META_DESCRIPTOR) == 0) {
func_verify = verify_descriptor;
start = 1;
} else if (strcmp(basename(filename), SPM_META_DEPENDS) == 0) {
func_verify = verify_depends;
} else if (strcmp(basename(filename), SPM_META_PREFIX_BIN) == 0) {
func_verify = verify_prefix;
} else if (strcmp(basename(filename), SPM_META_PREFIX_TEXT) == 0) {
func_verify = verify_prefix;
} else {
func_verify = verify_no_op;
}
// Get file contents
data = file_readlines(filename, 0, 0, reader_metadata);
// Strip newlines and whitespace
for (size_t i = 0; data[i] != NULL; i++) {
data[i] = strip(data[i]);
}
// Perform verification
if (no_verify == 0) {
for (size_t i = 0; data[i] != NULL; i++) {
int status = func_verify(i, &data[i]);
if (status > 0) {
fprintf(stderr, "%s: file verification failed\n", filename);
free(filename);
return NULL;
} else if (status < 0) {
// NOT AN ERROR
// a negative value indicates the verification function has processed enough information
// so we can gracefully
break;
}
}
}
// If there was a header, duplicate the array from the start of the data
// Otherwise return the array
if (start > 0) {
result = strdup_array(&data[start]);
for (size_t i = 0; data[i] != NULL; i++) {
free(data[i]);
}
free(data);
} else {
result = data;
}
free(filename);
return result;
}
/**
* SPM packages contain metadata files that are not useful post-install and would amount to a lot of clutter.
* This function removes these data files from a directory tree
* @param _path
* @return success=0, error=-1
*/
int spm_metadata_remove(const char *_path) {
if (exists(_path) != 0) {
perror(_path);
fprintf(SYSERROR);
return -1;
}
for (int i = 0; METADATA_FILES[i] != NULL; i++) {
char path[PATH_MAX];
sprintf(path, "%s%c%s", _path, DIRSEP, METADATA_FILES[i]);
if (exists(path) != 0) {
continue;
}
if (unlink(path) < 0) {
perror(path);
fprintf(SYSERROR);
return -1;
}
}
return 0;
}
ConfigItem **spm_descriptor_read(const char *filename) {
ConfigItem **result = config_read(filename);
return result;
}
|