]>
Commit | Line | Data |
---|---|---|
221cc3ce MT |
1 | /*############################################################################# |
2 | # # | |
3 | # Pakfire - The IPFire package management system # | |
4 | # Copyright (C) 2014 Pakfire development team # | |
5 | # # | |
6 | # This program is free software: you can redistribute it and/or modify # | |
7 | # it under the terms of the GNU General Public License as published by # | |
8 | # the Free Software Foundation, either version 3 of the License, or # | |
9 | # (at your option) any later version. # | |
10 | # # | |
11 | # This program is distributed in the hope that it will be useful, # | |
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
14 | # GNU General Public License for more details. # | |
15 | # # | |
16 | # You should have received a copy of the GNU General Public License # | |
17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
18 | # # | |
19 | #############################################################################*/ | |
20 | ||
5e9463ec | 21 | #include <errno.h> |
c064d9ec | 22 | #include <fnmatch.h> |
3fca5032 | 23 | #include <libgen.h> |
293881bc | 24 | #include <limits.h> |
c98132d1 | 25 | #include <linux/limits.h> |
221cc3ce MT |
26 | #include <stdlib.h> |
27 | #include <string.h> | |
a09b95e0 | 28 | #include <sys/stat.h> |
221cc3ce | 29 | #include <sys/types.h> |
221cc3ce MT |
30 | #include <time.h> |
31 | ||
9a6e3e2d MT |
32 | #include <archive_entry.h> |
33 | ||
221cc3ce | 34 | #include <pakfire/constants.h> |
c52e0148 | 35 | #include <pakfire/digest.h> |
221cc3ce | 36 | #include <pakfire/file.h> |
3fca5032 | 37 | #include <pakfire/logging.h> |
883b3be9 | 38 | #include <pakfire/pakfire.h> |
9f953e68 | 39 | #include <pakfire/private.h> |
d973a13d | 40 | #include <pakfire/string.h> |
221cc3ce MT |
41 | #include <pakfire/util.h> |
42 | ||
c0b051bb MT |
43 | enum pakfire_file_verification_status { |
44 | PAKFIRE_FILE_NOENT = (1 << 0), | |
9e09e361 MT |
45 | PAKFIRE_FILE_TYPE_CHANGED = (1 << 1), |
46 | PAKFIRE_FILE_PERMISSIONS_CHANGED = (1 << 2), | |
47 | PAKFIRE_FILE_DEV_CHANGED = (1 << 3), | |
48 | PAKFIRE_FILE_SIZE_CHANGED = (1 << 4), | |
49 | PAKFIRE_FILE_OWNER_CHANGED = (1 << 5), | |
50 | PAKFIRE_FILE_GROUP_CHANGED = (1 << 6), | |
0eeac4a5 MT |
51 | PAKFIRE_FILE_CTIME_CHANGED = (1 << 7), |
52 | PAKFIRE_FILE_MTIME_CHANGED = (1 << 8), | |
76011205 | 53 | PAKFIRE_FILE_PAYLOAD_CHANGED = (1 << 9), |
c0b051bb MT |
54 | }; |
55 | ||
5803b5f6 | 56 | struct pakfire_file { |
ac4c607b | 57 | struct pakfire* pakfire; |
5e9463ec | 58 | int nrefs; |
221cc3ce | 59 | |
e8d3b985 | 60 | // The relative path |
3b9e3970 | 61 | char path[PATH_MAX]; |
e8d3b985 MT |
62 | |
63 | // The absolute path in the file system | |
0027da6f | 64 | char abspath[PATH_MAX]; |
221cc3ce | 65 | |
e8d3b985 | 66 | // File Ownership |
302e3253 MT |
67 | char uname[LOGIN_NAME_MAX]; |
68 | char gname[LOGIN_NAME_MAX]; | |
e8d3b985 | 69 | |
a09b95e0 MT |
70 | // Stat |
71 | struct stat st; | |
d03fa9a3 | 72 | |
59d8c727 MT |
73 | // Link destinations |
74 | char hardlink[PATH_MAX]; | |
75 | char symlink[PATH_MAX]; | |
76 | ||
65131b30 | 77 | // Digests |
c52e0148 | 78 | struct pakfire_digests digests; |
5e9463ec | 79 | |
71f6f465 MT |
80 | // Class |
81 | int class; | |
82 | ||
c0b051bb MT |
83 | // Verification Status |
84 | int verify_status; | |
85 | ||
5e9463ec MT |
86 | #warning TODO capabilities, config, data |
87 | // capabilities | |
88 | //int is_configfile; | |
89 | //int is_datafile; | |
90 | }; | |
91 | ||
eb5daf3f | 92 | static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct archive_entry* entry) { |
49a39ad9 | 93 | const char* path = NULL; |
eb5daf3f MT |
94 | const char* attr = NULL; |
95 | const void* value = NULL; | |
96 | size_t size = 0; | |
97 | int r = 0; | |
98 | ||
99 | // Set abspath | |
49a39ad9 MT |
100 | path = archive_entry_sourcepath(entry); |
101 | if (path) { | |
102 | // Make path absolute | |
103 | path = pakfire_path_abspath(path); | |
004f0160 MT |
104 | if (!path) { |
105 | r = 1; | |
49a39ad9 | 106 | goto ERROR; |
004f0160 | 107 | } |
49a39ad9 MT |
108 | |
109 | // Set | |
110 | r = pakfire_file_set_abspath(file, path); | |
111 | if (r) { | |
112 | ERROR(file->pakfire, "Could not set abspath: %m\n"); | |
113 | goto ERROR; | |
114 | } | |
eb5daf3f MT |
115 | } |
116 | ||
117 | // Set path | |
49a39ad9 | 118 | path = archive_entry_pathname(entry); |
eb5daf3f | 119 | if (path) { |
eb5daf3f MT |
120 | r = pakfire_file_set_path(file, path); |
121 | if (r) { | |
122 | ERROR(file->pakfire, "Could not set path: %m\n"); | |
123 | goto ERROR; | |
124 | } | |
125 | } | |
126 | ||
127 | // Set links | |
128 | pakfire_file_set_hardlink(file, archive_entry_hardlink(entry)); | |
129 | pakfire_file_set_symlink(file, archive_entry_symlink(entry)); | |
130 | ||
f8733b31 MT |
131 | pakfire_file_set_nlink(file, archive_entry_nlink(entry)); |
132 | pakfire_file_set_inode(file, archive_entry_ino64(entry)); | |
133 | pakfire_file_set_dev(file, archive_entry_dev(entry)); | |
134 | ||
eb5daf3f MT |
135 | // Set size |
136 | pakfire_file_set_size(file, archive_entry_size(entry)); | |
137 | ||
138 | // Set mode | |
139 | pakfire_file_set_mode(file, archive_entry_mode(entry)); | |
140 | ||
141 | // Set dev type | |
142 | if (archive_entry_dev_is_set(entry)) | |
143 | pakfire_file_set_dev(file, archive_entry_dev(entry)); | |
144 | ||
302e3253 MT |
145 | // Set uname |
146 | pakfire_file_set_uname(file, archive_entry_uname(entry)); | |
eb5daf3f | 147 | |
302e3253 MT |
148 | // Set gname |
149 | pakfire_file_set_gname(file, archive_entry_gname(entry)); | |
eb5daf3f MT |
150 | |
151 | // Set times | |
152 | pakfire_file_set_ctime(file, archive_entry_ctime(entry)); | |
153 | pakfire_file_set_mtime(file, archive_entry_mtime(entry)); | |
154 | ||
155 | // Read any extended attributes | |
156 | while (archive_entry_xattr_next(entry, &attr, &value, &size) == ARCHIVE_OK) { | |
d98740de MT |
157 | // Digest: SHA-3-512 |
158 | if (strcmp(attr, "PAKFIRE.digests.sha3_512") == 0) { | |
159 | r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_512, value, size); | |
160 | if (r) | |
161 | goto ERROR; | |
162 | ||
163 | // Digest: SHA-3-256 | |
164 | } else if (strcmp(attr, "PAKFIRE.digests.sha3_256") == 0) { | |
165 | r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_256, value, size); | |
166 | if (r) | |
167 | goto ERROR; | |
168 | ||
f1e6c5df | 169 | // Digest: BLAKE2b512 |
d98740de | 170 | } else if (strcmp(attr, "PAKFIRE.digests.blake2b512") == 0) { |
f1e6c5df MT |
171 | r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2B512, value, size); |
172 | if (r) | |
173 | goto ERROR; | |
174 | ||
175 | // Digest: BLAKE2b512 | |
176 | } else if (strcmp(attr, "PAKFIRE.digests.blake2s256") == 0) { | |
177 | r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2S256, value, size); | |
178 | if (r) | |
179 | goto ERROR; | |
180 | ||
4500ed0a MT |
181 | // Digest: SHA-2-512 |
182 | } else if (strcmp(attr, "PAKFIRE.digests.sha2_512") == 0) { | |
183 | r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_512, value, size); | |
eb5daf3f MT |
184 | if (r) |
185 | goto ERROR; | |
186 | ||
4500ed0a MT |
187 | // Digest: SHA-2-256 |
188 | } else if (strcmp(attr, "PAKFIRE.digests.sha2_256") == 0) { | |
189 | r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_256, value, size); | |
eb5daf3f MT |
190 | if (r) |
191 | goto ERROR; | |
192 | ||
193 | } else { | |
194 | DEBUG(file->pakfire, "Received an unknown extended attribute: %s\n", attr); | |
195 | } | |
196 | } | |
197 | ||
198 | ERROR: | |
199 | return r; | |
200 | } | |
201 | ||
ac4c607b | 202 | PAKFIRE_EXPORT int pakfire_file_create(struct pakfire_file** file, struct pakfire* pakfire) { |
5803b5f6 | 203 | struct pakfire_file* f = calloc(1, sizeof(*f)); |
5e9463ec | 204 | if (!f) |
7403779a | 205 | return 1; |
5e9463ec | 206 | |
e8d3b985 | 207 | // Store reference to Pakfire |
883b3be9 | 208 | f->pakfire = pakfire_ref(pakfire); |
e8d3b985 MT |
209 | |
210 | // Initialize reference counter | |
5e9463ec MT |
211 | f->nrefs = 1; |
212 | ||
213 | *file = f; | |
214 | return 0; | |
d03fa9a3 MT |
215 | } |
216 | ||
61b0856b MT |
217 | int pakfire_file_create_from_path(struct pakfire_file** file, |
218 | struct pakfire* pakfire, const char* path) { | |
219 | struct archive* reader = NULL; | |
220 | struct archive_entry* entry = NULL; | |
221 | int r = 1; | |
222 | ||
223 | // Allocate a reader | |
224 | reader = pakfire_make_archive_disk_reader(pakfire, 0); | |
225 | if (!reader) | |
226 | goto ERROR; | |
227 | ||
228 | // Allocate a new archive entry | |
229 | entry = archive_entry_new(); | |
230 | if (!entry) | |
231 | goto ERROR; | |
232 | ||
233 | // Set source path | |
234 | archive_entry_copy_sourcepath(entry, path); | |
235 | ||
236 | // Read all file attributes from disk | |
237 | r = archive_read_disk_entry_from_file(reader, entry, -1, NULL); | |
238 | if (r) { | |
239 | ERROR(pakfire, "Could not read from %s: %m\n", path); | |
240 | goto ERROR; | |
241 | } | |
242 | ||
243 | // Create file | |
244 | r = pakfire_file_create_from_archive_entry(file, pakfire, entry); | |
245 | if (r) | |
246 | goto ERROR; | |
247 | ||
248 | ERROR: | |
249 | if (r) | |
250 | ERROR(pakfire, "Could not create file from path %s: %m\n", path); | |
251 | if (entry) | |
252 | archive_entry_free(entry); | |
253 | if (reader) | |
254 | archive_read_free(reader); | |
255 | ||
256 | return r; | |
257 | } | |
258 | ||
ac4c607b | 259 | int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire, |
d0985e31 MT |
260 | struct archive_entry* entry) { |
261 | int r = pakfire_file_create(file, pakfire); | |
262 | if (r) | |
263 | return r; | |
264 | ||
265 | // Copy archive entry | |
eb5daf3f | 266 | r = pakfire_file_from_archive_entry(*file, entry); |
d0985e31 MT |
267 | if (r) |
268 | goto ERROR; | |
269 | ||
270 | return 0; | |
271 | ||
272 | ERROR: | |
273 | pakfire_file_unref(*file); | |
274 | *file = NULL; | |
275 | ||
276 | return r; | |
277 | } | |
278 | ||
49a39ad9 | 279 | struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types) { |
d7b476ef | 280 | const char* path = NULL; |
d4b2ef2d | 281 | int r; |
d7b476ef | 282 | |
5acd852e MT |
283 | struct archive_entry* entry = archive_entry_new(); |
284 | if (!entry) { | |
285 | ERROR(file->pakfire, "Could not allocate archive entry: %m\n"); | |
286 | return NULL; | |
287 | } | |
288 | ||
5acd852e MT |
289 | // Set source path |
290 | archive_entry_copy_sourcepath(entry, file->abspath); | |
291 | ||
49a39ad9 | 292 | // Set path |
d7b476ef MT |
293 | path = pakfire_file_get_path(file); |
294 | if (path && *path == '/') { | |
295 | archive_entry_copy_pathname(entry, path + 1); | |
296 | } | |
49a39ad9 | 297 | |
5acd852e MT |
298 | // Set links |
299 | if (*file->hardlink) | |
300 | archive_entry_set_hardlink(entry, file->hardlink); | |
301 | if (*file->symlink) | |
302 | archive_entry_set_symlink(entry, file->symlink); | |
303 | ||
f8733b31 MT |
304 | archive_entry_set_nlink(entry, pakfire_file_get_nlink(file)); |
305 | archive_entry_set_ino64(entry, pakfire_file_get_inode(file)); | |
306 | archive_entry_set_dev(entry, pakfire_file_get_dev(file)); | |
307 | ||
5acd852e MT |
308 | // Set size |
309 | archive_entry_set_size(entry, pakfire_file_get_size(file)); | |
310 | ||
311 | // Set mode | |
312 | archive_entry_set_mode(entry, pakfire_file_get_mode(file)); | |
313 | ||
302e3253 MT |
314 | // Set uname |
315 | archive_entry_set_uname(entry, pakfire_file_get_uname(file)); | |
5acd852e | 316 | |
302e3253 MT |
317 | // Set gname |
318 | archive_entry_set_gname(entry, pakfire_file_get_gname(file)); | |
5acd852e MT |
319 | |
320 | // Set times | |
321 | archive_entry_set_ctime(entry, pakfire_file_get_ctime(file), 0); | |
322 | archive_entry_set_mtime(entry, pakfire_file_get_mtime(file), 0); | |
323 | ||
d4b2ef2d MT |
324 | // Compute any required file digests |
325 | r = pakfire_file_compute_digests(file, digest_types); | |
326 | if (r) | |
327 | goto ERROR; | |
328 | ||
399d14c2 MT |
329 | // Copy digests |
330 | ||
d98740de | 331 | // SHA-3-512 |
045fa504 MT |
332 | if ((digest_types && PAKFIRE_DIGEST_SHA3_512) |
333 | && pakfire_digest_set(file->digests.sha3_512)) | |
d98740de MT |
334 | archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_512", |
335 | file->digests.sha3_512, sizeof(file->digests.sha3_512)); | |
336 | ||
337 | // SHA-3-256 | |
045fa504 MT |
338 | if ((digest_types && PAKFIRE_DIGEST_SHA3_256) && |
339 | pakfire_digest_set(file->digests.sha3_256)) | |
d98740de MT |
340 | archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_256", |
341 | file->digests.sha3_256, sizeof(file->digests.sha3_256)); | |
342 | ||
f1e6c5df | 343 | // BLAKE2b512 |
045fa504 MT |
344 | if ((digest_types && PAKFIRE_DIGEST_BLAKE2B512) && |
345 | pakfire_digest_set(file->digests.blake2b512)) | |
f1e6c5df MT |
346 | archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2b512", |
347 | file->digests.blake2b512, sizeof(file->digests.blake2b512)); | |
348 | ||
349 | // BLAKE2s256 | |
045fa504 MT |
350 | if ((digest_types && PAKFIRE_DIGEST_BLAKE2S256) && |
351 | pakfire_digest_set(file->digests.blake2s256)) | |
f1e6c5df MT |
352 | archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2s256", |
353 | file->digests.blake2s256, sizeof(file->digests.blake2s256)); | |
354 | ||
4500ed0a | 355 | // SHA-2-512 |
045fa504 MT |
356 | if ((digest_types && PAKFIRE_DIGEST_SHA2_512) && |
357 | pakfire_digest_set(file->digests.sha2_512)) | |
4500ed0a MT |
358 | archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_512", |
359 | file->digests.sha2_512, sizeof(file->digests.sha2_512)); | |
399d14c2 | 360 | |
4500ed0a | 361 | // SHA-2-256 |
045fa504 MT |
362 | if ((digest_types && PAKFIRE_DIGEST_SHA2_512) && |
363 | pakfire_digest_set(file->digests.sha2_256)) | |
4500ed0a MT |
364 | archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_256", |
365 | file->digests.sha2_256, sizeof(file->digests.sha2_256)); | |
5acd852e MT |
366 | |
367 | return entry; | |
d4b2ef2d MT |
368 | |
369 | ERROR: | |
370 | if (entry) | |
371 | archive_entry_free(entry); | |
372 | ||
373 | return NULL; | |
5acd852e MT |
374 | } |
375 | ||
5803b5f6 | 376 | static void pakfire_file_free(struct pakfire_file* file) { |
5e8dfbeb | 377 | pakfire_unref(file->pakfire); |
f0d6233d | 378 | free(file); |
221cc3ce MT |
379 | } |
380 | ||
5803b5f6 | 381 | PAKFIRE_EXPORT struct pakfire_file* pakfire_file_ref(struct pakfire_file* file) { |
5e9463ec | 382 | file->nrefs++; |
221cc3ce | 383 | |
5e9463ec MT |
384 | return file; |
385 | } | |
221cc3ce | 386 | |
5803b5f6 | 387 | PAKFIRE_EXPORT struct pakfire_file* pakfire_file_unref(struct pakfire_file* file) { |
5e9463ec MT |
388 | if (--file->nrefs > 0) |
389 | return file; | |
390 | ||
391 | pakfire_file_free(file); | |
392 | return NULL; | |
221cc3ce MT |
393 | } |
394 | ||
5852b822 MT |
395 | #define pakfire_file_strmode(file, buffer) \ |
396 | __pakfire_file_strmode(file, buffer, sizeof(buffer)) | |
397 | ||
398 | static int __pakfire_file_strmode(struct pakfire_file* file, char* s, const size_t length) { | |
399 | int r; | |
400 | ||
401 | static const mode_t permbits[] = { | |
402 | 0400, | |
403 | 0200, | |
404 | 0100, | |
405 | 0040, | |
406 | 0020, | |
407 | 0010, | |
408 | 0004, | |
409 | 0002, | |
410 | 0001 | |
411 | }; | |
412 | ||
413 | const mode_t mode = pakfire_file_get_mode(file); | |
414 | const mode_t type = pakfire_file_get_type(file); | |
415 | ||
416 | // Set some default string | |
417 | r = __pakfire_string_set(s, length, "?rwxrwxrwx "); | |
418 | if (r) | |
419 | return r; | |
420 | ||
421 | switch (type) { | |
422 | case S_IFREG: | |
423 | s[0] = '-'; | |
424 | break; | |
425 | ||
426 | case S_IFBLK: | |
427 | s[0] = 'b'; | |
428 | break; | |
429 | ||
430 | case S_IFCHR: | |
431 | s[0] = 'c'; | |
432 | break; | |
433 | ||
434 | case S_IFDIR: | |
435 | s[0] = 'd'; | |
436 | break; | |
437 | ||
438 | case S_IFLNK: | |
439 | s[0] = 'l'; | |
440 | break; | |
441 | ||
442 | case S_IFSOCK: | |
443 | s[0] = 's'; | |
444 | break; | |
445 | ||
446 | case S_IFIFO: | |
447 | s[0] = 'p'; | |
448 | break; | |
449 | ||
450 | default: | |
451 | if (*file->hardlink) { | |
452 | s[0] = 'h'; | |
453 | break; | |
454 | } | |
455 | } | |
456 | ||
457 | for (unsigned int i = 0; i < 9; i++) { | |
458 | if (mode & permbits[i]) | |
459 | continue; | |
460 | ||
461 | s[i+1] = '-'; | |
462 | } | |
463 | ||
464 | if (mode & S_ISUID) { | |
465 | if (mode & 0100) | |
466 | s[3] = 's'; | |
467 | else | |
468 | s[3] = 'S'; | |
469 | } | |
470 | ||
471 | if (mode & S_ISGID) { | |
472 | if (mode & 0010) | |
473 | s[6] = 's'; | |
474 | else | |
475 | s[6] = 'S'; | |
476 | } | |
477 | ||
478 | if (mode & S_ISVTX) { | |
479 | if (mode & 0001) | |
480 | s[9] = 't'; | |
481 | else | |
482 | s[9] = 'T'; | |
483 | } | |
484 | ||
485 | #if 0 | |
486 | if (file->caps) | |
487 | s[10] = '+'; | |
488 | #endif | |
489 | ||
490 | return 0; | |
491 | } | |
492 | ||
493 | char* pakfire_file_dump(struct pakfire_file* file) { | |
494 | char* buffer = NULL; | |
495 | int r; | |
496 | ||
497 | char mode[12]; | |
498 | char time[32]; | |
499 | ||
500 | // Format mode | |
501 | r = pakfire_file_strmode(file, mode); | |
502 | if (r) | |
503 | return NULL; | |
504 | ||
505 | // Format time | |
506 | r = pakfire_strftime(time, "%Y-%m-%d %H:%M", file->st.st_ctime); | |
507 | if (r) | |
508 | return NULL; | |
509 | ||
510 | // Put everything together | |
511 | r = asprintf(&buffer, "%s %s/%s %8zu %s %s", | |
302e3253 | 512 | mode, file->uname, file->gname, file->st.st_size, time, file->path); |
5852b822 MT |
513 | if (r < 0) |
514 | return NULL; | |
515 | ||
516 | return buffer; | |
517 | } | |
518 | ||
5803b5f6 | 519 | PAKFIRE_EXPORT int pakfire_file_cmp(struct pakfire_file* file1, struct pakfire_file* file2) { |
32485f6c MT |
520 | const char* path1 = pakfire_file_get_path(file1); |
521 | const char* path2 = pakfire_file_get_path(file2); | |
221cc3ce | 522 | |
32485f6c | 523 | return strcmp(path1, path2); |
221cc3ce MT |
524 | } |
525 | ||
5803b5f6 | 526 | const char* pakfire_file_get_abspath(struct pakfire_file* file) { |
e4c2f7a9 MT |
527 | return file->abspath; |
528 | } | |
529 | ||
5803b5f6 | 530 | int pakfire_file_set_abspath(struct pakfire_file* file, const char* path) { |
49a39ad9 MT |
531 | int r; |
532 | ||
d13bd5b7 MT |
533 | // Check if path is set and absolute |
534 | if (!path || *path != '/') { | |
535 | errno = EINVAL; | |
536 | return 1; | |
537 | } | |
538 | ||
49a39ad9 MT |
539 | // Store the abspath |
540 | r = pakfire_string_set(file->abspath, path); | |
541 | if (r) | |
542 | goto ERROR; | |
543 | ||
544 | // Store path if it isn't set, yet | |
545 | if (!*file->path) { | |
546 | r = pakfire_file_set_path(file, path); | |
547 | if (r) | |
548 | goto ERROR; | |
549 | } | |
550 | ||
551 | return r; | |
552 | ||
553 | ERROR: | |
554 | ERROR(file->pakfire, "Could not set abspath '%s': %m\n", path); | |
555 | return r; | |
3b9e3970 MT |
556 | } |
557 | ||
5803b5f6 | 558 | PAKFIRE_EXPORT const char* pakfire_file_get_path(struct pakfire_file* file) { |
32485f6c | 559 | return file->path; |
221cc3ce MT |
560 | } |
561 | ||
5803b5f6 | 562 | PAKFIRE_EXPORT int pakfire_file_set_path(struct pakfire_file* file, const char* path) { |
12a327de | 563 | int r = 1; |
520213e9 | 564 | |
2cc8b5f4 MT |
565 | // Check if path is set |
566 | if (!path) { | |
d13bd5b7 | 567 | errno = EINVAL; |
12a327de | 568 | goto ERROR; |
d13bd5b7 MT |
569 | } |
570 | ||
2cc8b5f4 MT |
571 | // Strip any leading dots from paths |
572 | if (pakfire_string_startswith(path, "./")) | |
573 | path++; | |
574 | ||
575 | switch (*path) { | |
576 | // Just store the path if it is absolute | |
577 | case '/': | |
578 | r = pakfire_string_set(file->path, path); | |
579 | if (r) | |
580 | goto ERROR; | |
581 | break; | |
582 | ||
583 | // Handle relative paths | |
584 | default: | |
585 | r = pakfire_string_format(file->path, "/%s", path); | |
586 | if (r) | |
587 | goto ERROR; | |
588 | break; | |
589 | } | |
520213e9 MT |
590 | |
591 | // Set abspath if it isn't set, yet | |
592 | if (!*file->abspath) { | |
2cc8b5f4 | 593 | r = pakfire_file_set_abspath(file, file->path); |
520213e9 | 594 | if (r) |
12a327de | 595 | goto ERROR; |
520213e9 MT |
596 | } |
597 | ||
598 | return r; | |
12a327de MT |
599 | |
600 | ERROR: | |
601 | ERROR(file->pakfire, "Could not set path '%s': %m\n", path); | |
602 | return r; | |
221cc3ce MT |
603 | } |
604 | ||
59d8c727 MT |
605 | PAKFIRE_EXPORT const char* pakfire_file_get_hardlink(struct pakfire_file* file) { |
606 | if (!*file->hardlink) | |
607 | return NULL; | |
608 | ||
609 | return file->hardlink; | |
610 | } | |
611 | ||
612 | PAKFIRE_EXPORT void pakfire_file_set_hardlink(struct pakfire_file* file, const char* link) { | |
3c8eb581 | 613 | pakfire_string_set(file->hardlink, link); |
59d8c727 MT |
614 | } |
615 | ||
616 | PAKFIRE_EXPORT const char* pakfire_file_get_symlink(struct pakfire_file* file) { | |
617 | if (!*file->symlink) | |
618 | return NULL; | |
619 | ||
620 | return file->symlink; | |
621 | } | |
622 | ||
623 | PAKFIRE_EXPORT void pakfire_file_set_symlink(struct pakfire_file* file, const char* link) { | |
3c8eb581 | 624 | pakfire_string_set(file->symlink, link); |
59d8c727 MT |
625 | } |
626 | ||
f8733b31 MT |
627 | PAKFIRE_EXPORT nlink_t pakfire_file_get_nlink(struct pakfire_file* file) { |
628 | return file->st.st_nlink; | |
629 | } | |
630 | ||
631 | PAKFIRE_EXPORT void pakfire_file_set_nlink(struct pakfire_file* file, const nlink_t nlink) { | |
632 | file->st.st_nlink = nlink; | |
633 | } | |
634 | ||
635 | PAKFIRE_EXPORT ino_t pakfire_file_get_inode(struct pakfire_file* file) { | |
636 | return file->st.st_ino; | |
637 | } | |
638 | ||
639 | PAKFIRE_EXPORT void pakfire_file_set_inode(struct pakfire_file* file, const ino_t ino) { | |
640 | file->st.st_ino = ino; | |
641 | } | |
642 | ||
643 | PAKFIRE_EXPORT dev_t pakfire_file_get_dev(struct pakfire_file* file) { | |
644 | return file->st.st_dev; | |
645 | } | |
646 | ||
647 | PAKFIRE_EXPORT void pakfire_file_set_dev(struct pakfire_file* file, const dev_t dev) { | |
648 | file->st.st_dev = dev; | |
649 | } | |
650 | ||
5803b5f6 | 651 | PAKFIRE_EXPORT int pakfire_file_get_type(struct pakfire_file* file) { |
a09b95e0 | 652 | return file->st.st_mode & S_IFMT; |
221cc3ce MT |
653 | } |
654 | ||
a09b95e0 MT |
655 | PAKFIRE_EXPORT off_t pakfire_file_get_size(struct pakfire_file* file) { |
656 | return file->st.st_size; | |
221cc3ce MT |
657 | } |
658 | ||
a09b95e0 MT |
659 | PAKFIRE_EXPORT void pakfire_file_set_size(struct pakfire_file* file, off_t size) { |
660 | file->st.st_size = size; | |
221cc3ce MT |
661 | } |
662 | ||
302e3253 MT |
663 | PAKFIRE_EXPORT const char* pakfire_file_get_uname(struct pakfire_file* file) { |
664 | return file->uname; | |
221cc3ce MT |
665 | } |
666 | ||
302e3253 MT |
667 | PAKFIRE_EXPORT int pakfire_file_set_uname(struct pakfire_file* file, const char* uname) { |
668 | return pakfire_string_set(file->uname, uname); | |
221cc3ce MT |
669 | } |
670 | ||
302e3253 MT |
671 | PAKFIRE_EXPORT const char* pakfire_file_get_gname(struct pakfire_file* file) { |
672 | return file->gname; | |
221cc3ce MT |
673 | } |
674 | ||
302e3253 MT |
675 | PAKFIRE_EXPORT int pakfire_file_set_gname(struct pakfire_file* file, const char* gname) { |
676 | return pakfire_string_set(file->gname, gname); | |
221cc3ce MT |
677 | } |
678 | ||
5803b5f6 | 679 | PAKFIRE_EXPORT mode_t pakfire_file_get_mode(struct pakfire_file* file) { |
a09b95e0 | 680 | return file->st.st_mode; |
221cc3ce MT |
681 | } |
682 | ||
5803b5f6 | 683 | PAKFIRE_EXPORT void pakfire_file_set_mode(struct pakfire_file* file, mode_t mode) { |
a09b95e0 | 684 | file->st.st_mode = mode; |
221cc3ce MT |
685 | } |
686 | ||
134545d5 | 687 | PAKFIRE_EXPORT mode_t pakfire_file_get_perms(struct pakfire_file* file) { |
a09b95e0 | 688 | return file->st.st_mode & ~AE_IFMT; |
134545d5 MT |
689 | } |
690 | ||
691 | PAKFIRE_EXPORT void pakfire_file_set_perms(struct pakfire_file* file, const mode_t perms) { | |
692 | // Clear any previous permissions | |
a09b95e0 | 693 | file->st.st_mode &= S_IFMT; |
134545d5 MT |
694 | |
695 | // Set new bits (with format cleared) | |
a09b95e0 | 696 | file->st.st_mode |= ~S_IFMT & perms; |
134545d5 MT |
697 | } |
698 | ||
5803b5f6 | 699 | PAKFIRE_EXPORT time_t pakfire_file_get_ctime(struct pakfire_file* file) { |
a09b95e0 | 700 | return file->st.st_ctime; |
ef4e8460 MT |
701 | } |
702 | ||
5803b5f6 | 703 | PAKFIRE_EXPORT void pakfire_file_set_ctime(struct pakfire_file* file, time_t time) { |
a09b95e0 | 704 | file->st.st_ctime = time; |
ef4e8460 MT |
705 | } |
706 | ||
5803b5f6 | 707 | PAKFIRE_EXPORT time_t pakfire_file_get_mtime(struct pakfire_file* file) { |
a09b95e0 | 708 | return file->st.st_mtime; |
221cc3ce MT |
709 | } |
710 | ||
5803b5f6 | 711 | PAKFIRE_EXPORT void pakfire_file_set_mtime(struct pakfire_file* file, time_t time) { |
a09b95e0 | 712 | file->st.st_mtime = time; |
221cc3ce MT |
713 | } |
714 | ||
65131b30 | 715 | PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest( |
c52e0148 | 716 | struct pakfire_file* file, const enum pakfire_digest_types type, size_t* length) { |
65131b30 | 717 | |
9802aaf6 | 718 | switch (type) { |
d98740de MT |
719 | case PAKFIRE_DIGEST_SHA3_512: |
720 | if (!pakfire_digest_set(file->digests.sha3_512)) | |
721 | return NULL; | |
722 | ||
723 | if (length) | |
724 | *length = sizeof(file->digests.sha3_512); | |
725 | ||
726 | return file->digests.sha3_512; | |
727 | ||
728 | case PAKFIRE_DIGEST_SHA3_256: | |
729 | if (!pakfire_digest_set(file->digests.sha3_256)) | |
730 | return NULL; | |
731 | ||
732 | if (length) | |
733 | *length = sizeof(file->digests.sha3_256); | |
734 | ||
735 | return file->digests.sha3_256; | |
736 | ||
f1e6c5df MT |
737 | case PAKFIRE_DIGEST_BLAKE2B512: |
738 | if (!pakfire_digest_set(file->digests.blake2b512)) | |
739 | return NULL; | |
740 | ||
741 | if (length) | |
742 | *length = sizeof(file->digests.blake2b512); | |
743 | ||
744 | return file->digests.blake2b512; | |
745 | ||
746 | case PAKFIRE_DIGEST_BLAKE2S256: | |
747 | if (!pakfire_digest_set(file->digests.blake2s256)) | |
748 | return NULL; | |
749 | ||
750 | if (length) | |
751 | *length = sizeof(file->digests.blake2s256); | |
752 | ||
753 | return file->digests.blake2s256; | |
754 | ||
4500ed0a MT |
755 | case PAKFIRE_DIGEST_SHA2_512: |
756 | if (!pakfire_digest_set(file->digests.sha2_512)) | |
9802aaf6 | 757 | return NULL; |
65131b30 | 758 | |
9802aaf6 | 759 | if (length) |
4500ed0a | 760 | *length = sizeof(file->digests.sha2_512); |
65131b30 | 761 | |
4500ed0a | 762 | return file->digests.sha2_512; |
9802aaf6 | 763 | |
4500ed0a MT |
764 | case PAKFIRE_DIGEST_SHA2_256: |
765 | if (!pakfire_digest_set(file->digests.sha2_256)) | |
9802aaf6 | 766 | return NULL; |
5e8dfbeb | 767 | |
9802aaf6 | 768 | if (length) |
4500ed0a | 769 | *length = sizeof(file->digests.sha2_256); |
5e8dfbeb | 770 | |
4500ed0a | 771 | return file->digests.sha2_256; |
2c4b4a02 MT |
772 | |
773 | case PAKFIRE_DIGEST_UNDEFINED: | |
774 | break; | |
5e8dfbeb MT |
775 | } |
776 | ||
9802aaf6 | 777 | return NULL; |
5e8dfbeb MT |
778 | } |
779 | ||
780 | PAKFIRE_EXPORT int pakfire_file_set_digest(struct pakfire_file* file, | |
c52e0148 | 781 | const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) { |
9802aaf6 | 782 | if (!digest) { |
5e8dfbeb MT |
783 | errno = EINVAL; |
784 | return 1; | |
785 | } | |
786 | ||
399d14c2 MT |
787 | // Check buffer length |
788 | if (pakfire_digest_length(type) != length) { | |
789 | ERROR(file->pakfire, "Digest has an incorrect length of %zu byte(s)\n", length); | |
790 | errno = ENOMSG; | |
791 | return 1; | |
792 | } | |
793 | ||
794 | // Store the digest | |
9802aaf6 | 795 | switch (type) { |
d98740de MT |
796 | case PAKFIRE_DIGEST_SHA3_512: |
797 | memcpy(file->digests.sha3_512, digest, sizeof(file->digests.sha3_512)); | |
798 | break; | |
799 | ||
800 | case PAKFIRE_DIGEST_SHA3_256: | |
801 | memcpy(file->digests.sha3_256, digest, sizeof(file->digests.sha3_256)); | |
802 | break; | |
803 | ||
f1e6c5df MT |
804 | case PAKFIRE_DIGEST_BLAKE2B512: |
805 | memcpy(file->digests.blake2b512, digest, sizeof(file->digests.blake2b512)); | |
806 | break; | |
807 | ||
808 | case PAKFIRE_DIGEST_BLAKE2S256: | |
809 | memcpy(file->digests.blake2s256, digest, sizeof(file->digests.blake2s256)); | |
810 | break; | |
811 | ||
4500ed0a MT |
812 | case PAKFIRE_DIGEST_SHA2_512: |
813 | memcpy(file->digests.sha2_512, digest, sizeof(file->digests.sha2_512)); | |
9802aaf6 | 814 | break; |
65131b30 | 815 | |
4500ed0a MT |
816 | case PAKFIRE_DIGEST_SHA2_256: |
817 | memcpy(file->digests.sha2_256, digest, sizeof(file->digests.sha2_256)); | |
9802aaf6 | 818 | break; |
2c4b4a02 MT |
819 | |
820 | case PAKFIRE_DIGEST_UNDEFINED: | |
821 | errno = ENOTSUP; | |
822 | return 1; | |
5e8dfbeb MT |
823 | } |
824 | ||
5e8dfbeb | 825 | return 0; |
221cc3ce MT |
826 | } |
827 | ||
5803b5f6 | 828 | static int pakfire_file_levels(struct pakfire_file* file) { |
3fca5032 MT |
829 | if (!*file->path) |
830 | return 0; | |
831 | ||
832 | int levels = 0; | |
833 | ||
834 | for (char* p = file->path; *p; p++) { | |
835 | if (*p == '/') | |
836 | levels++; | |
837 | } | |
838 | ||
839 | return levels; | |
840 | } | |
841 | ||
d5a13ade MT |
842 | FILE* pakfire_file_open(struct pakfire_file* file) { |
843 | FILE* f = fopen(file->abspath, "r"); | |
844 | if (!f) | |
845 | ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath); | |
846 | ||
847 | return f; | |
848 | } | |
849 | ||
1e76689a MT |
850 | static int __pakfire_file_compute_digests(struct pakfire_file* file, |
851 | struct pakfire_digests* digests, const int types) { | |
852 | FILE* f = NULL; | |
853 | int r = 1; | |
854 | ||
855 | // Skip this for anything that isn't a regular file | |
856 | if (!S_ISREG(file->st.st_mode)) | |
857 | return 0; | |
858 | ||
859 | // Reset digests | |
860 | pakfire_digests_reset(digests, types); | |
861 | ||
862 | // Open the file | |
863 | f = pakfire_file_open(file); | |
864 | if (!f) | |
865 | goto ERROR; | |
866 | ||
867 | // Compute digests | |
868 | r = pakfire_digests_compute_from_file(file->pakfire, digests, types, f); | |
869 | if (r) | |
870 | goto ERROR; | |
871 | ||
872 | ERROR: | |
873 | if (f) | |
874 | fclose(f); | |
875 | ||
876 | return r; | |
877 | } | |
878 | ||
879 | int pakfire_file_compute_digests(struct pakfire_file* file, const int types) { | |
6b32db11 | 880 | return __pakfire_file_compute_digests(file, &file->digests, types); |
1e76689a MT |
881 | } |
882 | ||
ac71886a | 883 | int pakfire_file_remove(struct pakfire_file* file) { |
3fca5032 MT |
884 | if (!*file->abspath) { |
885 | errno = EINVAL; | |
886 | return 1; | |
887 | } | |
888 | ||
889 | DEBUG(file->pakfire, "Removing %s...\n", file->path); | |
890 | ||
891 | int r = remove(file->abspath); | |
892 | if (r) { | |
da89e02f MT |
893 | switch (errno) { |
894 | // Ignore when we could not remove directories | |
895 | case ENOTEMPTY: | |
896 | return 0; | |
897 | ||
898 | // Ignore if the file didn't exist | |
899 | case ENOENT: | |
900 | return 0; | |
901 | ||
902 | default: | |
903 | break; | |
904 | } | |
3fca5032 | 905 | |
b1772bfb | 906 | ERROR(file->pakfire, "Could not remove %s (%s): %m\n", file->path, file->abspath); |
3fca5032 MT |
907 | } |
908 | ||
ac71886a MT |
909 | return r; |
910 | } | |
911 | ||
71f6f465 MT |
912 | /* |
913 | Classification | |
914 | */ | |
915 | ||
916 | static int pakfire_file_classify_mode(struct pakfire_file* file) { | |
917 | // Check for regular files | |
918 | if (S_ISREG(file->st.st_mode)) | |
919 | file->class |= PAKFIRE_FILE_REGULAR; | |
920 | ||
921 | // Check for directories | |
922 | else if (S_ISDIR(file->st.st_mode)) | |
923 | file->class |= PAKFIRE_FILE_DIRECTORY; | |
924 | ||
925 | // Check for symlinks | |
926 | else if (S_ISLNK(file->st.st_mode)) | |
927 | file->class |= PAKFIRE_FILE_SYMLINK; | |
928 | ||
929 | // Check for character devices | |
930 | else if (S_ISCHR(file->st.st_mode)) | |
931 | file->class |= PAKFIRE_FILE_CHARACTER; | |
932 | ||
933 | // Check for block devices | |
934 | else if (S_ISBLK(file->st.st_mode)) | |
935 | file->class |= PAKFIRE_FILE_BLOCK; | |
936 | ||
937 | // Check for FIFO pipes | |
938 | else if (S_ISFIFO(file->st.st_mode)) | |
939 | file->class |= PAKFIRE_FILE_FIFO; | |
940 | ||
941 | // Check for sockets | |
942 | else if (S_ISSOCK(file->st.st_mode)) | |
943 | file->class |= PAKFIRE_FILE_SOCKET; | |
944 | ||
945 | return 0; | |
946 | } | |
947 | ||
948 | static const struct extension { | |
949 | const char* extension; | |
950 | int class; | |
951 | } extensions[] = { | |
d0831491 MT |
952 | { "*.a", PAKFIRE_FILE_STATIC_LIBRARY }, |
953 | { "*.la", PAKFIRE_FILE_LIBTOOL_ARCHIVE }, | |
71f6f465 MT |
954 | { "*.pm", PAKFIRE_FILE_PERL }, |
955 | { "*.pc", PAKFIRE_FILE_PKGCONFIG }, | |
956 | { NULL , 0 }, | |
957 | }; | |
958 | ||
959 | static int pakfire_file_classify_extension(struct pakfire_file* file) { | |
960 | for (const struct extension* e = extensions; e->extension; e++) { | |
961 | if (pakfire_file_matches(file, e->extension)) { | |
962 | file->class |= e->class; | |
963 | break; | |
964 | } | |
965 | } | |
966 | ||
967 | return 0; | |
968 | } | |
969 | ||
970 | static const struct mimetype { | |
971 | const char* mimetype; | |
972 | int class; | |
973 | } mimetypes[] = { | |
974 | { "application/x-sharedlibary", PAKFIRE_FILE_EXECUTABLE }, | |
975 | { "text/x-perl", PAKFIRE_FILE_PERL }, | |
976 | { NULL, 0 }, | |
977 | }; | |
978 | ||
979 | static int pakfire_file_classify_magic(struct pakfire_file* file) { | |
980 | // Don't run this if the file has already been classified | |
981 | if (file->class & ~PAKFIRE_FILE_REGULAR) | |
982 | return 0; | |
983 | ||
984 | // Fetch the magic cookie | |
985 | magic_t magic = pakfire_get_magic(file->pakfire); | |
986 | if (!magic) | |
987 | return 1; | |
988 | ||
989 | // Check the file | |
990 | const char* mimetype = magic_file(magic, file->abspath); | |
991 | if (!mimetype) { | |
992 | ERROR(file->pakfire, "Could not classify %s: %s\n", file->path, magic_error(magic)); | |
993 | return 1; | |
994 | } | |
995 | ||
996 | DEBUG(file->pakfire, "Classified %s as %s\n", file->path, mimetype); | |
997 | ||
998 | for (const struct mimetype* m = mimetypes; m->mimetype; m++) { | |
999 | if (strcmp(m->mimetype, mimetype) == 0) { | |
1000 | file->class |= m->class; | |
1001 | break; | |
1002 | } | |
1003 | } | |
1004 | ||
1005 | return 0; | |
1006 | } | |
1007 | ||
1008 | int pakfire_file_classify(struct pakfire_file* file) { | |
1009 | int r; | |
1010 | ||
1011 | if (!file->class) { | |
1012 | // First, check the mode so that we won't run magic on directories, symlinks, ... | |
1013 | r = pakfire_file_classify_mode(file); | |
1014 | if (r) | |
1015 | goto ERROR; | |
1016 | ||
1017 | // Only run this for regular files | |
1018 | if (file->class & PAKFIRE_FILE_REGULAR) { | |
1019 | // Then check for the extension | |
1020 | r = pakfire_file_classify_extension(file); | |
1021 | if (r) | |
1022 | goto ERROR; | |
1023 | ||
1024 | // After that, we will use libmagic... | |
1025 | r = pakfire_file_classify_magic(file); | |
1026 | if (r) | |
1027 | goto ERROR; | |
1028 | } | |
1029 | } | |
1030 | ||
1031 | return file->class; | |
1032 | ||
1033 | ERROR: | |
1034 | // Reset the class | |
1035 | file->class = PAKFIRE_FILE_UNKNOWN; | |
1036 | ||
1037 | return r; | |
1038 | } | |
1039 | ||
1040 | int pakfire_file_matches_class(struct pakfire_file* file, const int class) { | |
1041 | return pakfire_file_classify(file) & class; | |
1042 | } | |
1043 | ||
ac71886a MT |
1044 | /* |
1045 | This function tries to remove the file after it has been packaged. | |
1046 | ||
1047 | It will try to delete any parent directories as well and ignore if directories | |
1048 | cannot be deleted because they might contain other files | |
1049 | */ | |
1050 | int pakfire_file_cleanup(struct pakfire_file* file) { | |
1051 | char path[PATH_MAX]; | |
1052 | ||
1053 | // Try removing the file | |
1054 | int r = pakfire_file_remove(file); | |
1055 | if (r) | |
1056 | return r; | |
1057 | ||
3fca5032 MT |
1058 | // Create a working copy of abspath |
1059 | r = pakfire_string_set(path, file->abspath); | |
a60955af | 1060 | if (r) |
3fca5032 MT |
1061 | return r; |
1062 | ||
1063 | // See how many levels this file has | |
1064 | int levels = pakfire_file_levels(file); | |
1065 | ||
1066 | // Walk all the way up and remove all parent directories if possible | |
1067 | while (--levels) { | |
1068 | dirname(path); | |
1069 | ||
1070 | // Break if path is suddenly empty | |
1071 | if (!*path) | |
1072 | break; | |
1073 | ||
a8783709 MT |
1074 | DEBUG(file->pakfire, "Trying to remove parent directory %s\n", path); |
1075 | ||
3fca5032 | 1076 | r = rmdir(path); |
3fca5032 | 1077 | |
a8783709 MT |
1078 | // Break on any error |
1079 | if (r) | |
1080 | break; | |
3fca5032 MT |
1081 | } |
1082 | ||
a942166c | 1083 | return 0; |
3fca5032 | 1084 | } |
cf9bd6f4 | 1085 | |
9e09e361 | 1086 | static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat* st) { |
a09b95e0 MT |
1087 | const mode_t type = pakfire_file_get_type(file); |
1088 | ||
9e09e361 | 1089 | // Did the type change? |
a09b95e0 | 1090 | if (type != (st->st_mode & S_IFMT)) { |
9e09e361 MT |
1091 | file->verify_status |= PAKFIRE_FILE_TYPE_CHANGED; |
1092 | ||
1093 | DEBUG(file->pakfire, "%s: File Type changed\n", file->path); | |
1094 | } | |
1095 | ||
a09b95e0 MT |
1096 | const mode_t perms = pakfire_file_get_perms(file); |
1097 | ||
9e09e361 | 1098 | // Check permissions |
a09b95e0 | 1099 | if (perms != (st->st_mode & 0777)) { |
9e09e361 MT |
1100 | file->verify_status |= PAKFIRE_FILE_PERMISSIONS_CHANGED; |
1101 | ||
1102 | DEBUG(file->pakfire, "%s: Permissions changed\n", file->path); | |
1103 | } | |
1104 | ||
f8733b31 MT |
1105 | #if 0 |
1106 | // XXX This does not check what it is supposed to check | |
1107 | ||
9e09e361 MT |
1108 | // Check if device node changed |
1109 | if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { | |
a09b95e0 MT |
1110 | const dev_t dev = pakfire_file_get_dev(file); |
1111 | ||
1112 | if (dev != st->st_dev) { | |
9e09e361 MT |
1113 | file->verify_status |= PAKFIRE_FILE_DEV_CHANGED; |
1114 | ||
1115 | DEBUG(file->pakfire, "%s: Device Node changed\n", file->path); | |
1116 | } | |
1117 | } | |
f8733b31 | 1118 | #endif |
9e09e361 MT |
1119 | |
1120 | return 0; | |
1121 | } | |
1122 | ||
c0b051bb MT |
1123 | static int pakfire_file_verify_size(struct pakfire_file* file, const struct stat* st) { |
1124 | // Nothing to do if size matches | |
a09b95e0 | 1125 | if (file->st.st_size == st->st_size) |
c0b051bb MT |
1126 | return 0; |
1127 | ||
1128 | // Size differs | |
d2b0e219 | 1129 | file->verify_status |= PAKFIRE_FILE_SIZE_CHANGED; |
c0b051bb MT |
1130 | |
1131 | DEBUG(file->pakfire, "%s: Filesize differs (expected %zu, got %zu byte(s))\n", | |
a09b95e0 | 1132 | file->path, file->st.st_size, st->st_size); |
c0b051bb MT |
1133 | |
1134 | return 0; | |
1135 | } | |
1136 | ||
1137 | static int pakfire_file_verify_ownership(struct pakfire_file* file, const struct stat* st) { | |
1138 | // Fetch UID/GID | |
1139 | #if 0 | |
1140 | const uid_t uid = pakfire_unmap_id(file->pakfire, st->st_uid); | |
1141 | const gid_t gid = pakfire_unmap_id(file->pakfire, st->st_gid); | |
1142 | #else | |
1143 | const uid_t uid = st->st_uid; | |
1144 | const gid_t gid = st->st_gid; | |
1145 | #endif | |
1146 | ||
1147 | // Fetch owner & group | |
302e3253 MT |
1148 | struct passwd* owner = pakfire_getpwnam(file->pakfire, file->uname); |
1149 | struct group* group = pakfire_getgrnam(file->pakfire, file->gname); | |
c0b051bb MT |
1150 | |
1151 | // Check if owner matches | |
1152 | if (!owner || owner->pw_uid != uid) { | |
d2b0e219 | 1153 | file->verify_status |= PAKFIRE_FILE_OWNER_CHANGED; |
c0b051bb MT |
1154 | |
1155 | DEBUG(file->pakfire, "%s: Owner differs\n", file->path); | |
1156 | } | |
1157 | ||
1158 | // Check if group matches | |
1159 | if (!group || group->gr_gid != gid) { | |
d2b0e219 | 1160 | file->verify_status |= PAKFIRE_FILE_GROUP_CHANGED; |
c0b051bb MT |
1161 | |
1162 | DEBUG(file->pakfire, "%s: Group differs\n", file->path); | |
1163 | } | |
1164 | ||
1165 | return 0; | |
1166 | } | |
1167 | ||
0eeac4a5 MT |
1168 | static int pakfire_file_verify_timestamps(struct pakfire_file* file, const struct stat* st) { |
1169 | // Check creation time | |
a09b95e0 | 1170 | if (file->st.st_ctime != st->st_ctime) { |
0eeac4a5 MT |
1171 | file->verify_status |= PAKFIRE_FILE_CTIME_CHANGED; |
1172 | ||
1173 | DEBUG(file->pakfire, "%s: Creation time changed\n", file->path); | |
1174 | } | |
1175 | ||
1176 | // Check modification time | |
a09b95e0 | 1177 | if (file->st.st_mtime != st->st_mtime) { |
0eeac4a5 MT |
1178 | file->verify_status |= PAKFIRE_FILE_MTIME_CHANGED; |
1179 | ||
1180 | DEBUG(file->pakfire, "%s: Modification time changed\n", file->path); | |
1181 | } | |
1182 | ||
1183 | return 0; | |
1184 | } | |
1185 | ||
76011205 | 1186 | static int pakfire_file_verify_payload(struct pakfire_file* file, const struct stat* st) { |
76011205 MT |
1187 | int r; |
1188 | ||
c52e0148 | 1189 | struct pakfire_digests computed_digests; |
293881bc | 1190 | int digest_types = PAKFIRE_DIGEST_UNDEFINED; |
76011205 MT |
1191 | |
1192 | // Nothing to do for anything that isn't a regular file | |
1193 | if (!S_ISREG(st->st_mode)) | |
1194 | return 0; | |
1195 | ||
1196 | // Fast-path if size changed. The payload will have changed, too | |
1197 | if (file->verify_status & PAKFIRE_FILE_SIZE_CHANGED) { | |
1198 | file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED; | |
1199 | return 0; | |
1200 | } | |
1201 | ||
1202 | // Check if this file has any digests at all | |
6b32db11 | 1203 | digest_types = pakfire_digest_has_any(&file->digests); |
76011205 | 1204 | |
293881bc MT |
1205 | if (!digest_types) { |
1206 | ERROR(file->pakfire, "%s: No digests available\n", file->path); | |
1207 | return 0; | |
76011205 MT |
1208 | } |
1209 | ||
293881bc | 1210 | // Compute digests |
1e76689a | 1211 | r = __pakfire_file_compute_digests(file, &computed_digests, digest_types); |
293881bc | 1212 | if (r) |
76011205 | 1213 | goto ERROR; |
76011205 | 1214 | |
293881bc MT |
1215 | // Compare digests |
1216 | r = pakfire_digests_compare(file->pakfire, &file->digests, &computed_digests, digest_types); | |
76011205 MT |
1217 | if (r) { |
1218 | file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED; | |
1219 | ||
293881bc | 1220 | DEBUG(file->pakfire, "%s: Digest(s) do not match\n", file->path); |
76011205 MT |
1221 | } |
1222 | ||
76011205 | 1223 | ERROR: |
76011205 MT |
1224 | return r; |
1225 | } | |
1226 | ||
cf9bd6f4 MT |
1227 | /* |
1228 | Verify the file - i.e. does the metadata match what is on disk? | |
1229 | */ | |
c0b051bb MT |
1230 | int pakfire_file_verify(struct pakfire_file* file, int* status) { |
1231 | struct stat st; | |
1232 | int r; | |
1233 | ||
cf9bd6f4 MT |
1234 | DEBUG(file->pakfire, "Verifying %s...\n", file->path); |
1235 | ||
c0b051bb MT |
1236 | // stat() the file |
1237 | r = lstat(file->abspath, &st); | |
1238 | if (r) { | |
1239 | // File does not exist | |
1240 | if (errno == ENOENT) { | |
1241 | file->verify_status |= PAKFIRE_FILE_NOENT; | |
1242 | return 1; | |
1243 | } | |
1244 | ||
1245 | // Raise any other errors from stat() | |
1246 | return r; | |
1247 | } | |
1248 | ||
9e09e361 MT |
1249 | // Verify mode |
1250 | r = pakfire_file_verify_mode(file, &st); | |
1251 | if (r) | |
1252 | return r; | |
1253 | ||
c0b051bb MT |
1254 | // Verify size |
1255 | r = pakfire_file_verify_size(file, &st); | |
1256 | if (r) | |
1257 | return r; | |
1258 | ||
1259 | // Verify ownership | |
1260 | r = pakfire_file_verify_ownership(file, &st); | |
1261 | if (r) | |
1262 | return r; | |
1263 | ||
0eeac4a5 MT |
1264 | // Verify timestamps |
1265 | r = pakfire_file_verify_timestamps(file, &st); | |
1266 | if (r) | |
1267 | return r; | |
1268 | ||
76011205 MT |
1269 | // Verify payload |
1270 | r = pakfire_file_verify_payload(file, &st); | |
1271 | if (r) | |
1272 | return r; | |
1273 | ||
cf9bd6f4 MT |
1274 | return 0; |
1275 | } | |
c064d9ec MT |
1276 | |
1277 | PAKFIRE_EXPORT int pakfire_file_matches(struct pakfire_file* file, const char* pattern) { | |
1278 | int r; | |
1279 | ||
1280 | // Don't match on no pattern | |
1281 | if (!pattern) | |
1282 | return 0; | |
1283 | ||
1284 | // Check if the pattern matches | |
1285 | r = fnmatch(pattern, file->path, 0); | |
1286 | switch (r) { | |
1287 | // Match | |
1288 | case 0: | |
1289 | return 1; | |
1290 | ||
1291 | // No Match | |
1292 | case FNM_NOMATCH: | |
1293 | return 0; | |
1294 | ||
1295 | default: | |
1296 | return -1; | |
1297 | } | |
1298 | } |