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