]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/file.c
compress: Avoid prepending "(null)" to paths on extraction
[people/stevee/pakfire.git] / src / libpakfire / file.c
CommitLineData
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>
3fca5032 22#include <libgen.h>
293881bc 23#include <limits.h>
c98132d1 24#include <linux/limits.h>
221cc3ce
MT
25#include <stdlib.h>
26#include <string.h>
a09b95e0 27#include <sys/stat.h>
221cc3ce 28#include <sys/types.h>
221cc3ce
MT
29#include <time.h>
30
9a6e3e2d
MT
31#include <archive_entry.h>
32
221cc3ce 33#include <pakfire/constants.h>
c52e0148 34#include <pakfire/digest.h>
221cc3ce 35#include <pakfire/file.h>
3fca5032 36#include <pakfire/logging.h>
883b3be9 37#include <pakfire/pakfire.h>
9f953e68 38#include <pakfire/private.h>
d973a13d 39#include <pakfire/string.h>
221cc3ce
MT
40#include <pakfire/util.h>
41
c0b051bb
MT
42enum pakfire_file_verification_status {
43 PAKFIRE_FILE_NOENT = (1 << 0),
9e09e361
MT
44 PAKFIRE_FILE_TYPE_CHANGED = (1 << 1),
45 PAKFIRE_FILE_PERMISSIONS_CHANGED = (1 << 2),
46 PAKFIRE_FILE_DEV_CHANGED = (1 << 3),
47 PAKFIRE_FILE_SIZE_CHANGED = (1 << 4),
48 PAKFIRE_FILE_OWNER_CHANGED = (1 << 5),
49 PAKFIRE_FILE_GROUP_CHANGED = (1 << 6),
0eeac4a5
MT
50 PAKFIRE_FILE_CTIME_CHANGED = (1 << 7),
51 PAKFIRE_FILE_MTIME_CHANGED = (1 << 8),
76011205 52 PAKFIRE_FILE_PAYLOAD_CHANGED = (1 << 9),
c0b051bb
MT
53};
54
5803b5f6 55struct pakfire_file {
ac4c607b 56 struct pakfire* pakfire;
5e9463ec 57 int nrefs;
221cc3ce 58
e8d3b985 59 // The relative path
3b9e3970 60 char path[PATH_MAX];
e8d3b985
MT
61
62 // The absolute path in the file system
0027da6f 63 char abspath[PATH_MAX];
221cc3ce 64
e8d3b985
MT
65 // File Ownership
66 char user[LOGIN_NAME_MAX];
67 char group[LOGIN_NAME_MAX];
68
a09b95e0
MT
69 // Stat
70 struct stat st;
d03fa9a3 71
59d8c727
MT
72 // Link destinations
73 char hardlink[PATH_MAX];
74 char symlink[PATH_MAX];
75
65131b30 76 // Digests
c52e0148 77 struct pakfire_digests digests;
5e9463ec 78
c0b051bb
MT
79 // Verification Status
80 int verify_status;
81
5e9463ec
MT
82 #warning TODO capabilities, config, data
83 // capabilities
84 //int is_configfile;
85 //int is_datafile;
86};
87
eb5daf3f 88static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct archive_entry* entry) {
49a39ad9 89 const char* path = NULL;
eb5daf3f
MT
90 const char* attr = NULL;
91 const void* value = NULL;
92 size_t size = 0;
93 int r = 0;
94
95 // Set abspath
49a39ad9
MT
96 path = archive_entry_sourcepath(entry);
97 if (path) {
98 // Make path absolute
99 path = pakfire_path_abspath(path);
100 if (!path)
101 goto ERROR;
102
103 // Set
104 r = pakfire_file_set_abspath(file, path);
105 if (r) {
106 ERROR(file->pakfire, "Could not set abspath: %m\n");
107 goto ERROR;
108 }
eb5daf3f
MT
109 }
110
111 // Set path
49a39ad9 112 path = archive_entry_pathname(entry);
eb5daf3f
MT
113 if (path) {
114 // Strip any leading dots from paths
115 if (pakfire_string_startswith(path, "./"))
116 path++;
117
118 r = pakfire_file_set_path(file, path);
119 if (r) {
120 ERROR(file->pakfire, "Could not set path: %m\n");
121 goto ERROR;
122 }
123 }
124
125 // Set links
126 pakfire_file_set_hardlink(file, archive_entry_hardlink(entry));
127 pakfire_file_set_symlink(file, archive_entry_symlink(entry));
128
129 // Set size
130 pakfire_file_set_size(file, archive_entry_size(entry));
131
132 // Set mode
133 pakfire_file_set_mode(file, archive_entry_mode(entry));
134
135 // Set dev type
136 if (archive_entry_dev_is_set(entry))
137 pakfire_file_set_dev(file, archive_entry_dev(entry));
138
139 // Set user
140 pakfire_file_set_user(file, archive_entry_uname(entry));
141
142 // Set group
143 pakfire_file_set_group(file, archive_entry_gname(entry));
144
145 // Set times
146 pakfire_file_set_ctime(file, archive_entry_ctime(entry));
147 pakfire_file_set_mtime(file, archive_entry_mtime(entry));
148
149 // Read any extended attributes
150 while (archive_entry_xattr_next(entry, &attr, &value, &size) == ARCHIVE_OK) {
d98740de
MT
151 // Digest: SHA-3-512
152 if (strcmp(attr, "PAKFIRE.digests.sha3_512") == 0) {
153 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_512, value, size);
154 if (r)
155 goto ERROR;
156
157 // Digest: SHA-3-256
158 } else if (strcmp(attr, "PAKFIRE.digests.sha3_256") == 0) {
159 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA3_256, value, size);
160 if (r)
161 goto ERROR;
162
f1e6c5df 163 // Digest: BLAKE2b512
d98740de 164 } else if (strcmp(attr, "PAKFIRE.digests.blake2b512") == 0) {
f1e6c5df
MT
165 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2B512, value, size);
166 if (r)
167 goto ERROR;
168
169 // Digest: BLAKE2b512
170 } else if (strcmp(attr, "PAKFIRE.digests.blake2s256") == 0) {
171 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_BLAKE2S256, value, size);
172 if (r)
173 goto ERROR;
174
4500ed0a
MT
175 // Digest: SHA-2-512
176 } else if (strcmp(attr, "PAKFIRE.digests.sha2_512") == 0) {
177 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_512, value, size);
eb5daf3f
MT
178 if (r)
179 goto ERROR;
180
4500ed0a
MT
181 // Digest: SHA-2-256
182 } else if (strcmp(attr, "PAKFIRE.digests.sha2_256") == 0) {
183 r = pakfire_file_set_digest(file, PAKFIRE_DIGEST_SHA2_256, value, size);
eb5daf3f
MT
184 if (r)
185 goto ERROR;
186
187 } else {
188 DEBUG(file->pakfire, "Received an unknown extended attribute: %s\n", attr);
189 }
190 }
191
192ERROR:
193 return r;
194}
195
ac4c607b 196PAKFIRE_EXPORT int pakfire_file_create(struct pakfire_file** file, struct pakfire* pakfire) {
5803b5f6 197 struct pakfire_file* f = calloc(1, sizeof(*f));
5e9463ec 198 if (!f)
7403779a 199 return 1;
5e9463ec 200
e8d3b985 201 // Store reference to Pakfire
883b3be9 202 f->pakfire = pakfire_ref(pakfire);
e8d3b985
MT
203
204 // Initialize reference counter
5e9463ec
MT
205 f->nrefs = 1;
206
207 *file = f;
208 return 0;
d03fa9a3
MT
209}
210
61b0856b
MT
211int pakfire_file_create_from_path(struct pakfire_file** file,
212 struct pakfire* pakfire, const char* path) {
213 struct archive* reader = NULL;
214 struct archive_entry* entry = NULL;
215 int r = 1;
216
217 // Allocate a reader
218 reader = pakfire_make_archive_disk_reader(pakfire, 0);
219 if (!reader)
220 goto ERROR;
221
222 // Allocate a new archive entry
223 entry = archive_entry_new();
224 if (!entry)
225 goto ERROR;
226
227 // Set source path
228 archive_entry_copy_sourcepath(entry, path);
229
230 // Read all file attributes from disk
231 r = archive_read_disk_entry_from_file(reader, entry, -1, NULL);
232 if (r) {
233 ERROR(pakfire, "Could not read from %s: %m\n", path);
234 goto ERROR;
235 }
236
237 // Create file
238 r = pakfire_file_create_from_archive_entry(file, pakfire, entry);
239 if (r)
240 goto ERROR;
241
242ERROR:
243 if (r)
244 ERROR(pakfire, "Could not create file from path %s: %m\n", path);
245 if (entry)
246 archive_entry_free(entry);
247 if (reader)
248 archive_read_free(reader);
249
250 return r;
251}
252
ac4c607b 253int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire,
d0985e31
MT
254 struct archive_entry* entry) {
255 int r = pakfire_file_create(file, pakfire);
256 if (r)
257 return r;
258
259 // Copy archive entry
eb5daf3f 260 r = pakfire_file_from_archive_entry(*file, entry);
d0985e31
MT
261 if (r)
262 goto ERROR;
263
264 return 0;
265
266ERROR:
267 pakfire_file_unref(*file);
268 *file = NULL;
269
270 return r;
271}
272
49a39ad9 273struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types) {
5acd852e
MT
274 struct archive_entry* entry = archive_entry_new();
275 if (!entry) {
276 ERROR(file->pakfire, "Could not allocate archive entry: %m\n");
277 return NULL;
278 }
279
5acd852e
MT
280 // Set source path
281 archive_entry_copy_sourcepath(entry, file->abspath);
282
49a39ad9
MT
283 // Set path
284 archive_entry_copy_pathname(entry, pakfire_file_get_path(file));
285
5acd852e
MT
286 // Set links
287 if (*file->hardlink)
288 archive_entry_set_hardlink(entry, file->hardlink);
289 if (*file->symlink)
290 archive_entry_set_symlink(entry, file->symlink);
291
292 // Set size
293 archive_entry_set_size(entry, pakfire_file_get_size(file));
294
295 // Set mode
296 archive_entry_set_mode(entry, pakfire_file_get_mode(file));
297
298 // Set user
299 archive_entry_set_uname(entry, pakfire_file_get_user(file));
300
301 // Set group
302 archive_entry_set_gname(entry, pakfire_file_get_group(file));
303
304 // Set times
305 archive_entry_set_ctime(entry, pakfire_file_get_ctime(file), 0);
306 archive_entry_set_mtime(entry, pakfire_file_get_mtime(file), 0);
307
399d14c2
MT
308 // Copy digests
309
d98740de 310 // SHA-3-512
045fa504
MT
311 if ((digest_types && PAKFIRE_DIGEST_SHA3_512)
312 && pakfire_digest_set(file->digests.sha3_512))
d98740de
MT
313 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_512",
314 file->digests.sha3_512, sizeof(file->digests.sha3_512));
315
316 // SHA-3-256
045fa504
MT
317 if ((digest_types && PAKFIRE_DIGEST_SHA3_256) &&
318 pakfire_digest_set(file->digests.sha3_256))
d98740de
MT
319 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha3_256",
320 file->digests.sha3_256, sizeof(file->digests.sha3_256));
321
f1e6c5df 322 // BLAKE2b512
045fa504
MT
323 if ((digest_types && PAKFIRE_DIGEST_BLAKE2B512) &&
324 pakfire_digest_set(file->digests.blake2b512))
f1e6c5df
MT
325 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2b512",
326 file->digests.blake2b512, sizeof(file->digests.blake2b512));
327
328 // BLAKE2s256
045fa504
MT
329 if ((digest_types && PAKFIRE_DIGEST_BLAKE2S256) &&
330 pakfire_digest_set(file->digests.blake2s256))
f1e6c5df
MT
331 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.blake2s256",
332 file->digests.blake2s256, sizeof(file->digests.blake2s256));
333
4500ed0a 334 // SHA-2-512
045fa504
MT
335 if ((digest_types && PAKFIRE_DIGEST_SHA2_512) &&
336 pakfire_digest_set(file->digests.sha2_512))
4500ed0a
MT
337 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_512",
338 file->digests.sha2_512, sizeof(file->digests.sha2_512));
399d14c2 339
4500ed0a 340 // SHA-2-256
045fa504
MT
341 if ((digest_types && PAKFIRE_DIGEST_SHA2_512) &&
342 pakfire_digest_set(file->digests.sha2_256))
4500ed0a
MT
343 archive_entry_xattr_add_entry(entry, "PAKFIRE.digests.sha2_256",
344 file->digests.sha2_256, sizeof(file->digests.sha2_256));
5acd852e
MT
345
346 return entry;
347}
348
5803b5f6 349static void pakfire_file_free(struct pakfire_file* file) {
5e8dfbeb 350 pakfire_unref(file->pakfire);
f0d6233d 351 free(file);
221cc3ce
MT
352}
353
5803b5f6 354PAKFIRE_EXPORT struct pakfire_file* pakfire_file_ref(struct pakfire_file* file) {
5e9463ec 355 file->nrefs++;
221cc3ce 356
5e9463ec
MT
357 return file;
358}
221cc3ce 359
5803b5f6 360PAKFIRE_EXPORT struct pakfire_file* pakfire_file_unref(struct pakfire_file* file) {
5e9463ec
MT
361 if (--file->nrefs > 0)
362 return file;
363
364 pakfire_file_free(file);
365 return NULL;
221cc3ce
MT
366}
367
5803b5f6 368PAKFIRE_EXPORT int pakfire_file_cmp(struct pakfire_file* file1, struct pakfire_file* file2) {
32485f6c
MT
369 const char* path1 = pakfire_file_get_path(file1);
370 const char* path2 = pakfire_file_get_path(file2);
221cc3ce 371
32485f6c 372 return strcmp(path1, path2);
221cc3ce
MT
373}
374
5803b5f6 375const char* pakfire_file_get_abspath(struct pakfire_file* file) {
e4c2f7a9
MT
376 return file->abspath;
377}
378
5803b5f6 379int pakfire_file_set_abspath(struct pakfire_file* file, const char* path) {
49a39ad9
MT
380 int r;
381
d13bd5b7
MT
382 // Check if path is set and absolute
383 if (!path || *path != '/') {
384 errno = EINVAL;
385 return 1;
386 }
387
49a39ad9
MT
388 // Store the abspath
389 r = pakfire_string_set(file->abspath, path);
390 if (r)
391 goto ERROR;
392
393 // Store path if it isn't set, yet
394 if (!*file->path) {
395 r = pakfire_file_set_path(file, path);
396 if (r)
397 goto ERROR;
398 }
399
400 return r;
401
402ERROR:
403 ERROR(file->pakfire, "Could not set abspath '%s': %m\n", path);
404 return r;
3b9e3970
MT
405}
406
5803b5f6 407PAKFIRE_EXPORT const char* pakfire_file_get_path(struct pakfire_file* file) {
32485f6c 408 return file->path;
221cc3ce
MT
409}
410
5803b5f6 411PAKFIRE_EXPORT int pakfire_file_set_path(struct pakfire_file* file, const char* path) {
12a327de 412 int r = 1;
520213e9 413
d13bd5b7
MT
414 // Check if path is set and absolute
415 if (!path || *path != '/') {
416 errno = EINVAL;
12a327de 417 goto ERROR;
d13bd5b7
MT
418 }
419
520213e9
MT
420 // Store path
421 r = pakfire_string_set(file->path, path);
422 if (r)
12a327de 423 goto ERROR;
520213e9
MT
424
425 // Set abspath if it isn't set, yet
426 if (!*file->abspath) {
12a327de 427 r = pakfire_file_set_abspath(file, path);
520213e9 428 if (r)
12a327de 429 goto ERROR;
520213e9
MT
430 }
431
432 return r;
12a327de
MT
433
434ERROR:
435 ERROR(file->pakfire, "Could not set path '%s': %m\n", path);
436 return r;
221cc3ce
MT
437}
438
59d8c727
MT
439PAKFIRE_EXPORT const char* pakfire_file_get_hardlink(struct pakfire_file* file) {
440 if (!*file->hardlink)
441 return NULL;
442
443 return file->hardlink;
444}
445
446PAKFIRE_EXPORT void pakfire_file_set_hardlink(struct pakfire_file* file, const char* link) {
3c8eb581 447 pakfire_string_set(file->hardlink, link);
59d8c727
MT
448}
449
450PAKFIRE_EXPORT const char* pakfire_file_get_symlink(struct pakfire_file* file) {
451 if (!*file->symlink)
452 return NULL;
453
454 return file->symlink;
455}
456
457PAKFIRE_EXPORT void pakfire_file_set_symlink(struct pakfire_file* file, const char* link) {
3c8eb581 458 pakfire_string_set(file->symlink, link);
59d8c727
MT
459}
460
5803b5f6 461PAKFIRE_EXPORT int pakfire_file_get_type(struct pakfire_file* file) {
a09b95e0 462 return file->st.st_mode & S_IFMT;
221cc3ce
MT
463}
464
a09b95e0
MT
465PAKFIRE_EXPORT off_t pakfire_file_get_size(struct pakfire_file* file) {
466 return file->st.st_size;
221cc3ce
MT
467}
468
a09b95e0
MT
469PAKFIRE_EXPORT void pakfire_file_set_size(struct pakfire_file* file, off_t size) {
470 file->st.st_size = size;
221cc3ce
MT
471}
472
5803b5f6 473PAKFIRE_EXPORT const char* pakfire_file_get_user(struct pakfire_file* file) {
221cc3ce
MT
474 return file->user;
475}
476
f04369e6
MT
477PAKFIRE_EXPORT int pakfire_file_set_user(struct pakfire_file* file, const char* user) {
478 return pakfire_string_set(file->user, user);
221cc3ce
MT
479}
480
5803b5f6 481PAKFIRE_EXPORT const char* pakfire_file_get_group(struct pakfire_file* file) {
221cc3ce
MT
482 return file->group;
483}
484
f04369e6
MT
485PAKFIRE_EXPORT int pakfire_file_set_group(struct pakfire_file* file, const char* group) {
486 return pakfire_string_set(file->group, group);
221cc3ce
MT
487}
488
5803b5f6 489PAKFIRE_EXPORT mode_t pakfire_file_get_mode(struct pakfire_file* file) {
a09b95e0 490 return file->st.st_mode;
221cc3ce
MT
491}
492
5803b5f6 493PAKFIRE_EXPORT void pakfire_file_set_mode(struct pakfire_file* file, mode_t mode) {
a09b95e0 494 file->st.st_mode = mode;
221cc3ce
MT
495}
496
134545d5 497PAKFIRE_EXPORT mode_t pakfire_file_get_perms(struct pakfire_file* file) {
a09b95e0 498 return file->st.st_mode & ~AE_IFMT;
134545d5
MT
499}
500
501PAKFIRE_EXPORT void pakfire_file_set_perms(struct pakfire_file* file, const mode_t perms) {
502 // Clear any previous permissions
a09b95e0 503 file->st.st_mode &= S_IFMT;
134545d5
MT
504
505 // Set new bits (with format cleared)
a09b95e0 506 file->st.st_mode |= ~S_IFMT & perms;
134545d5
MT
507}
508
487d6485 509PAKFIRE_EXPORT dev_t pakfire_file_get_dev(struct pakfire_file* file) {
a09b95e0 510 return file->st.st_dev;
487d6485
MT
511}
512
513PAKFIRE_EXPORT void pakfire_file_set_dev(struct pakfire_file* file, dev_t dev) {
a09b95e0 514 file->st.st_dev = dev;
487d6485
MT
515}
516
5803b5f6 517PAKFIRE_EXPORT time_t pakfire_file_get_ctime(struct pakfire_file* file) {
a09b95e0 518 return file->st.st_ctime;
ef4e8460
MT
519}
520
5803b5f6 521PAKFIRE_EXPORT void pakfire_file_set_ctime(struct pakfire_file* file, time_t time) {
a09b95e0 522 file->st.st_ctime = time;
ef4e8460
MT
523}
524
5803b5f6 525PAKFIRE_EXPORT time_t pakfire_file_get_mtime(struct pakfire_file* file) {
a09b95e0 526 return file->st.st_mtime;
221cc3ce
MT
527}
528
5803b5f6 529PAKFIRE_EXPORT void pakfire_file_set_mtime(struct pakfire_file* file, time_t time) {
a09b95e0 530 file->st.st_mtime = time;
221cc3ce
MT
531}
532
65131b30 533PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest(
c52e0148 534 struct pakfire_file* file, const enum pakfire_digest_types type, size_t* length) {
65131b30 535
9802aaf6 536 switch (type) {
d98740de
MT
537 case PAKFIRE_DIGEST_SHA3_512:
538 if (!pakfire_digest_set(file->digests.sha3_512))
539 return NULL;
540
541 if (length)
542 *length = sizeof(file->digests.sha3_512);
543
544 return file->digests.sha3_512;
545
546 case PAKFIRE_DIGEST_SHA3_256:
547 if (!pakfire_digest_set(file->digests.sha3_256))
548 return NULL;
549
550 if (length)
551 *length = sizeof(file->digests.sha3_256);
552
553 return file->digests.sha3_256;
554
f1e6c5df
MT
555 case PAKFIRE_DIGEST_BLAKE2B512:
556 if (!pakfire_digest_set(file->digests.blake2b512))
557 return NULL;
558
559 if (length)
560 *length = sizeof(file->digests.blake2b512);
561
562 return file->digests.blake2b512;
563
564 case PAKFIRE_DIGEST_BLAKE2S256:
565 if (!pakfire_digest_set(file->digests.blake2s256))
566 return NULL;
567
568 if (length)
569 *length = sizeof(file->digests.blake2s256);
570
571 return file->digests.blake2s256;
572
4500ed0a
MT
573 case PAKFIRE_DIGEST_SHA2_512:
574 if (!pakfire_digest_set(file->digests.sha2_512))
9802aaf6 575 return NULL;
65131b30 576
9802aaf6 577 if (length)
4500ed0a 578 *length = sizeof(file->digests.sha2_512);
65131b30 579
4500ed0a 580 return file->digests.sha2_512;
9802aaf6 581
4500ed0a
MT
582 case PAKFIRE_DIGEST_SHA2_256:
583 if (!pakfire_digest_set(file->digests.sha2_256))
9802aaf6 584 return NULL;
5e8dfbeb 585
9802aaf6 586 if (length)
4500ed0a 587 *length = sizeof(file->digests.sha2_256);
5e8dfbeb 588
4500ed0a 589 return file->digests.sha2_256;
2c4b4a02
MT
590
591 case PAKFIRE_DIGEST_UNDEFINED:
592 break;
5e8dfbeb
MT
593 }
594
9802aaf6 595 return NULL;
5e8dfbeb
MT
596}
597
598PAKFIRE_EXPORT int pakfire_file_set_digest(struct pakfire_file* file,
c52e0148 599 const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
9802aaf6 600 if (!digest) {
5e8dfbeb
MT
601 errno = EINVAL;
602 return 1;
603 }
604
399d14c2
MT
605 // Check buffer length
606 if (pakfire_digest_length(type) != length) {
607 ERROR(file->pakfire, "Digest has an incorrect length of %zu byte(s)\n", length);
608 errno = ENOMSG;
609 return 1;
610 }
611
612 // Store the digest
9802aaf6 613 switch (type) {
d98740de
MT
614 case PAKFIRE_DIGEST_SHA3_512:
615 memcpy(file->digests.sha3_512, digest, sizeof(file->digests.sha3_512));
616 break;
617
618 case PAKFIRE_DIGEST_SHA3_256:
619 memcpy(file->digests.sha3_256, digest, sizeof(file->digests.sha3_256));
620 break;
621
f1e6c5df
MT
622 case PAKFIRE_DIGEST_BLAKE2B512:
623 memcpy(file->digests.blake2b512, digest, sizeof(file->digests.blake2b512));
624 break;
625
626 case PAKFIRE_DIGEST_BLAKE2S256:
627 memcpy(file->digests.blake2s256, digest, sizeof(file->digests.blake2s256));
628 break;
629
4500ed0a
MT
630 case PAKFIRE_DIGEST_SHA2_512:
631 memcpy(file->digests.sha2_512, digest, sizeof(file->digests.sha2_512));
9802aaf6 632 break;
65131b30 633
4500ed0a
MT
634 case PAKFIRE_DIGEST_SHA2_256:
635 memcpy(file->digests.sha2_256, digest, sizeof(file->digests.sha2_256));
9802aaf6 636 break;
2c4b4a02
MT
637
638 case PAKFIRE_DIGEST_UNDEFINED:
639 errno = ENOTSUP;
640 return 1;
5e8dfbeb
MT
641 }
642
5e8dfbeb 643 return 0;
221cc3ce
MT
644}
645
9802aaf6 646PAKFIRE_EXPORT char* pakfire_file_get_hexdigest(
c52e0148 647 struct pakfire_file* file, const enum pakfire_digest_types type) {
9802aaf6
MT
648 const unsigned char* digest = NULL;
649 size_t length = 0;
ffbef232 650
9802aaf6
MT
651 // Fetch the digest
652 digest = pakfire_file_get_digest(file, type, &length);
5e8dfbeb 653 if (!digest)
9802aaf6 654 return NULL;
5e8dfbeb 655
9802aaf6 656 return __pakfire_hexlify(digest, length);
221cc3ce 657}
3fca5032 658
5803b5f6 659static int pakfire_file_levels(struct pakfire_file* file) {
3fca5032
MT
660 if (!*file->path)
661 return 0;
662
663 int levels = 0;
664
665 for (char* p = file->path; *p; p++) {
666 if (*p == '/')
667 levels++;
668 }
669
670 return levels;
671}
672
d5a13ade
MT
673FILE* pakfire_file_open(struct pakfire_file* file) {
674 FILE* f = fopen(file->abspath, "r");
675 if (!f)
676 ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath);
677
678 return f;
679}
680
1e76689a
MT
681static int __pakfire_file_compute_digests(struct pakfire_file* file,
682 struct pakfire_digests* digests, const int types) {
683 FILE* f = NULL;
684 int r = 1;
685
686 // Skip this for anything that isn't a regular file
687 if (!S_ISREG(file->st.st_mode))
688 return 0;
689
690 // Reset digests
691 pakfire_digests_reset(digests, types);
692
693 // Open the file
694 f = pakfire_file_open(file);
695 if (!f)
696 goto ERROR;
697
698 // Compute digests
699 r = pakfire_digests_compute_from_file(file->pakfire, digests, types, f);
700 if (r)
701 goto ERROR;
702
703ERROR:
704 if (f)
705 fclose(f);
706
707 return r;
708}
709
710int pakfire_file_compute_digests(struct pakfire_file* file, const int types) {
6b32db11 711 return __pakfire_file_compute_digests(file, &file->digests, types);
1e76689a
MT
712}
713
ac71886a 714int pakfire_file_remove(struct pakfire_file* file) {
3fca5032
MT
715 if (!*file->abspath) {
716 errno = EINVAL;
717 return 1;
718 }
719
720 DEBUG(file->pakfire, "Removing %s...\n", file->path);
721
722 int r = remove(file->abspath);
723 if (r) {
da89e02f
MT
724 switch (errno) {
725 // Ignore when we could not remove directories
726 case ENOTEMPTY:
727 return 0;
728
729 // Ignore if the file didn't exist
730 case ENOENT:
731 return 0;
732
733 default:
734 break;
735 }
3fca5032 736
b1772bfb 737 ERROR(file->pakfire, "Could not remove %s (%s): %m\n", file->path, file->abspath);
3fca5032
MT
738 }
739
ac71886a
MT
740 return r;
741}
742
743/*
744 This function tries to remove the file after it has been packaged.
745
746 It will try to delete any parent directories as well and ignore if directories
747 cannot be deleted because they might contain other files
748*/
749int pakfire_file_cleanup(struct pakfire_file* file) {
750 char path[PATH_MAX];
751
752 // Try removing the file
753 int r = pakfire_file_remove(file);
754 if (r)
755 return r;
756
3fca5032
MT
757 // Create a working copy of abspath
758 r = pakfire_string_set(path, file->abspath);
a60955af 759 if (r)
3fca5032
MT
760 return r;
761
762 // See how many levels this file has
763 int levels = pakfire_file_levels(file);
764
765 // Walk all the way up and remove all parent directories if possible
766 while (--levels) {
767 dirname(path);
768
769 // Break if path is suddenly empty
770 if (!*path)
771 break;
772
773 r = rmdir(path);
774 if (r) {
775 if (errno == ENOTEMPTY)
776 return 0;
777
778 return r;
779 }
780 }
781
a942166c 782 return 0;
3fca5032 783}
cf9bd6f4 784
9e09e361 785static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat* st) {
a09b95e0
MT
786 const mode_t type = pakfire_file_get_type(file);
787
9e09e361 788 // Did the type change?
a09b95e0 789 if (type != (st->st_mode & S_IFMT)) {
9e09e361
MT
790 file->verify_status |= PAKFIRE_FILE_TYPE_CHANGED;
791
792 DEBUG(file->pakfire, "%s: File Type changed\n", file->path);
793 }
794
a09b95e0
MT
795 const mode_t perms = pakfire_file_get_perms(file);
796
9e09e361 797 // Check permissions
a09b95e0 798 if (perms != (st->st_mode & 0777)) {
9e09e361
MT
799 file->verify_status |= PAKFIRE_FILE_PERMISSIONS_CHANGED;
800
801 DEBUG(file->pakfire, "%s: Permissions changed\n", file->path);
802 }
803
804 // Check if device node changed
805 if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
a09b95e0
MT
806 const dev_t dev = pakfire_file_get_dev(file);
807
808 if (dev != st->st_dev) {
9e09e361
MT
809 file->verify_status |= PAKFIRE_FILE_DEV_CHANGED;
810
811 DEBUG(file->pakfire, "%s: Device Node changed\n", file->path);
812 }
813 }
814
815 return 0;
816}
817
c0b051bb
MT
818static int pakfire_file_verify_size(struct pakfire_file* file, const struct stat* st) {
819 // Nothing to do if size matches
a09b95e0 820 if (file->st.st_size == st->st_size)
c0b051bb
MT
821 return 0;
822
823 // Size differs
d2b0e219 824 file->verify_status |= PAKFIRE_FILE_SIZE_CHANGED;
c0b051bb
MT
825
826 DEBUG(file->pakfire, "%s: Filesize differs (expected %zu, got %zu byte(s))\n",
a09b95e0 827 file->path, file->st.st_size, st->st_size);
c0b051bb
MT
828
829 return 0;
830}
831
832static int pakfire_file_verify_ownership(struct pakfire_file* file, const struct stat* st) {
833 // Fetch UID/GID
834#if 0
835 const uid_t uid = pakfire_unmap_id(file->pakfire, st->st_uid);
836 const gid_t gid = pakfire_unmap_id(file->pakfire, st->st_gid);
837#else
838 const uid_t uid = st->st_uid;
839 const gid_t gid = st->st_gid;
840#endif
841
842 // Fetch owner & group
843 struct passwd* owner = pakfire_getpwnam(file->pakfire, file->user);
844 struct group* group = pakfire_getgrnam(file->pakfire, file->group);
845
846 // Check if owner matches
847 if (!owner || owner->pw_uid != uid) {
d2b0e219 848 file->verify_status |= PAKFIRE_FILE_OWNER_CHANGED;
c0b051bb
MT
849
850 DEBUG(file->pakfire, "%s: Owner differs\n", file->path);
851 }
852
853 // Check if group matches
854 if (!group || group->gr_gid != gid) {
d2b0e219 855 file->verify_status |= PAKFIRE_FILE_GROUP_CHANGED;
c0b051bb
MT
856
857 DEBUG(file->pakfire, "%s: Group differs\n", file->path);
858 }
859
860 return 0;
861}
862
0eeac4a5
MT
863static int pakfire_file_verify_timestamps(struct pakfire_file* file, const struct stat* st) {
864 // Check creation time
a09b95e0 865 if (file->st.st_ctime != st->st_ctime) {
0eeac4a5
MT
866 file->verify_status |= PAKFIRE_FILE_CTIME_CHANGED;
867
868 DEBUG(file->pakfire, "%s: Creation time changed\n", file->path);
869 }
870
871 // Check modification time
a09b95e0 872 if (file->st.st_mtime != st->st_mtime) {
0eeac4a5
MT
873 file->verify_status |= PAKFIRE_FILE_MTIME_CHANGED;
874
875 DEBUG(file->pakfire, "%s: Modification time changed\n", file->path);
876 }
877
878 return 0;
879}
880
76011205 881static int pakfire_file_verify_payload(struct pakfire_file* file, const struct stat* st) {
76011205
MT
882 int r;
883
c52e0148 884 struct pakfire_digests computed_digests;
293881bc 885 int digest_types = PAKFIRE_DIGEST_UNDEFINED;
76011205
MT
886
887 // Nothing to do for anything that isn't a regular file
888 if (!S_ISREG(st->st_mode))
889 return 0;
890
891 // Fast-path if size changed. The payload will have changed, too
892 if (file->verify_status & PAKFIRE_FILE_SIZE_CHANGED) {
893 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
894 return 0;
895 }
896
897 // Check if this file has any digests at all
6b32db11 898 digest_types = pakfire_digest_has_any(&file->digests);
76011205 899
293881bc
MT
900 if (!digest_types) {
901 ERROR(file->pakfire, "%s: No digests available\n", file->path);
902 return 0;
76011205
MT
903 }
904
293881bc 905 // Compute digests
1e76689a 906 r = __pakfire_file_compute_digests(file, &computed_digests, digest_types);
293881bc 907 if (r)
76011205 908 goto ERROR;
76011205 909
293881bc
MT
910 // Compare digests
911 r = pakfire_digests_compare(file->pakfire, &file->digests, &computed_digests, digest_types);
76011205
MT
912 if (r) {
913 file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED;
914
293881bc 915 DEBUG(file->pakfire, "%s: Digest(s) do not match\n", file->path);
76011205
MT
916 }
917
76011205 918ERROR:
76011205
MT
919 return r;
920}
921
cf9bd6f4
MT
922/*
923 Verify the file - i.e. does the metadata match what is on disk?
924*/
c0b051bb
MT
925int pakfire_file_verify(struct pakfire_file* file, int* status) {
926 struct stat st;
927 int r;
928
cf9bd6f4
MT
929 DEBUG(file->pakfire, "Verifying %s...\n", file->path);
930
c0b051bb
MT
931 // stat() the file
932 r = lstat(file->abspath, &st);
933 if (r) {
934 // File does not exist
935 if (errno == ENOENT) {
936 file->verify_status |= PAKFIRE_FILE_NOENT;
937 return 1;
938 }
939
940 // Raise any other errors from stat()
941 return r;
942 }
943
9e09e361
MT
944 // Verify mode
945 r = pakfire_file_verify_mode(file, &st);
946 if (r)
947 return r;
948
c0b051bb
MT
949 // Verify size
950 r = pakfire_file_verify_size(file, &st);
951 if (r)
952 return r;
953
954 // Verify ownership
955 r = pakfire_file_verify_ownership(file, &st);
956 if (r)
957 return r;
958
0eeac4a5
MT
959 // Verify timestamps
960 r = pakfire_file_verify_timestamps(file, &st);
961 if (r)
962 return r;
963
76011205
MT
964 // Verify payload
965 r = pakfire_file_verify_payload(file, &st);
966 if (r)
967 return r;
968
cf9bd6f4
MT
969 return 0;
970}