1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2014 Pakfire development team #
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. #
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. #
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/>. #
19 #############################################################################*/
23 #include <linux/limits.h>
26 #include <sys/types.h>
29 #include <archive_entry.h>
30 #include <openssl/evp.h>
32 #include <pakfire/constants.h>
33 #include <pakfire/file.h>
34 #include <pakfire/logging.h>
35 #include <pakfire/pakfire.h>
36 #include <pakfire/private.h>
37 #include <pakfire/string.h>
38 #include <pakfire/util.h>
42 struct pakfire_file_digest
{
43 enum pakfire_digests type
;
44 unsigned char digest
[EVP_MAX_MD_SIZE
];
47 // Add a buffer to store the hex representation
52 struct pakfire
* pakfire
;
58 // The absolute path in the file system
59 char abspath
[PATH_MAX
];
62 char user
[LOGIN_NAME_MAX
];
63 char group
[LOGIN_NAME_MAX
];
74 // Creation/Modification Time
79 char hardlink
[PATH_MAX
];
80 char symlink
[PATH_MAX
];
83 struct pakfire_file_digest digests
[MAX_DIGESTS
];
85 #warning TODO capabilities, config, data
91 PAKFIRE_EXPORT
int pakfire_file_create(struct pakfire_file
** file
, struct pakfire
* pakfire
) {
92 struct pakfire_file
* f
= calloc(1, sizeof(*f
));
96 // Store reference to Pakfire
97 f
->pakfire
= pakfire_ref(pakfire
);
99 // Initialize reference counter
106 int pakfire_file_create_from_archive_entry(struct pakfire_file
** file
, struct pakfire
* pakfire
,
107 struct archive_entry
* entry
) {
108 int r
= pakfire_file_create(file
, pakfire
);
112 // Copy archive entry
113 r
= pakfire_file_copy_archive_entry(*file
, entry
);
120 pakfire_file_unref(*file
);
126 static const struct pakfire_libarchive_digest
{
127 enum pakfire_digests pakfire
;
129 } pakfire_libarchive_digests
[] = {
130 { PAKFIRE_DIGEST_SHA512
, ARCHIVE_ENTRY_DIGEST_SHA512
},
131 { PAKFIRE_DIGEST_SHA256
, ARCHIVE_ENTRY_DIGEST_SHA256
},
132 { PAKFIRE_DIGEST_NONE
, 0 },
135 int pakfire_file_copy_archive_entry(struct pakfire_file
* file
, struct archive_entry
* entry
) {
139 pakfire_file_set_abspath(file
, archive_entry_sourcepath(entry
));
142 const char* path
= archive_entry_pathname(entry
);
144 // Strip any leading dots from paths
145 if (pakfire_string_startswith(path
, "./"))
148 pakfire_file_set_path(file
, path
);
152 pakfire_file_set_hardlink(file
, archive_entry_hardlink(entry
));
153 pakfire_file_set_symlink(file
, archive_entry_symlink(entry
));
156 pakfire_file_set_size(file
, archive_entry_size(entry
));
159 pakfire_file_set_mode(file
, archive_entry_mode(entry
));
162 if (archive_entry_dev_is_set(entry
))
163 pakfire_file_set_dev(file
, archive_entry_dev(entry
));
166 pakfire_file_set_user(file
, archive_entry_uname(entry
));
169 pakfire_file_set_group(file
, archive_entry_gname(entry
));
172 pakfire_file_set_ctime(file
, archive_entry_ctime(entry
));
173 pakfire_file_set_mtime(file
, archive_entry_mtime(entry
));
176 for (const struct pakfire_libarchive_digest
* type
= pakfire_libarchive_digests
;
177 type
->pakfire
; type
++) {
178 const unsigned char* digest
= archive_entry_digest(entry
, type
->libarchive
);
180 size_t length
= pakfire_digest_length(type
->pakfire
);
182 r
= pakfire_file_set_digest(file
, type
->pakfire
, digest
, length
);
191 struct archive_entry
* pakfire_file_archive_entry(struct pakfire_file
* file
) {
192 struct archive_entry
* entry
= archive_entry_new();
194 ERROR(file
->pakfire
, "Could not allocate archive entry: %m\n");
199 archive_entry_copy_pathname(entry
, pakfire_file_get_path(file
));
202 archive_entry_copy_sourcepath(entry
, file
->abspath
);
206 archive_entry_set_hardlink(entry
, file
->hardlink
);
208 archive_entry_set_symlink(entry
, file
->symlink
);
211 archive_entry_set_size(entry
, pakfire_file_get_size(file
));
214 archive_entry_set_mode(entry
, pakfire_file_get_mode(file
));
217 archive_entry_set_uname(entry
, pakfire_file_get_user(file
));
220 archive_entry_set_gname(entry
, pakfire_file_get_group(file
));
223 archive_entry_set_ctime(entry
, pakfire_file_get_ctime(file
), 0);
224 archive_entry_set_mtime(entry
, pakfire_file_get_mtime(file
), 0);
231 static void pakfire_file_free(struct pakfire_file
* file
) {
232 struct pakfire_file_digest
* digest
= NULL
;
234 // Free any generated hexdigests
235 for (unsigned int i
= 0; i
< MAX_DIGESTS
; i
++) {
236 digest
= &file
->digests
[i
];
238 if (digest
->hexdigest
) {
239 free(digest
->hexdigest
);
240 digest
->hexdigest
= NULL
;
244 pakfire_unref(file
->pakfire
);
248 PAKFIRE_EXPORT
struct pakfire_file
* pakfire_file_ref(struct pakfire_file
* file
) {
254 PAKFIRE_EXPORT
struct pakfire_file
* pakfire_file_unref(struct pakfire_file
* file
) {
255 if (--file
->nrefs
> 0)
258 pakfire_file_free(file
);
262 PAKFIRE_EXPORT
int pakfire_file_cmp(struct pakfire_file
* file1
, struct pakfire_file
* file2
) {
263 const char* path1
= pakfire_file_get_path(file1
);
264 const char* path2
= pakfire_file_get_path(file2
);
266 return strcmp(path1
, path2
);
269 const char* pakfire_file_get_abspath(struct pakfire_file
* file
) {
270 return file
->abspath
;
273 int pakfire_file_set_abspath(struct pakfire_file
* file
, const char* path
) {
274 // Check if path is set and absolute
275 if (!path
|| *path
!= '/') {
280 return pakfire_string_set(file
->abspath
, path
);
283 PAKFIRE_EXPORT
const char* pakfire_file_get_path(struct pakfire_file
* file
) {
287 PAKFIRE_EXPORT
int pakfire_file_set_path(struct pakfire_file
* file
, const char* path
) {
288 // Check if path is set and absolute
289 if (!path
|| *path
!= '/') {
294 return pakfire_string_set(file
->path
, path
);
297 PAKFIRE_EXPORT
const char* pakfire_file_get_hardlink(struct pakfire_file
* file
) {
298 if (!*file
->hardlink
)
301 return file
->hardlink
;
304 PAKFIRE_EXPORT
void pakfire_file_set_hardlink(struct pakfire_file
* file
, const char* link
) {
306 *file
->hardlink
= '\0';
308 pakfire_string_set(file
->hardlink
, link
);
311 PAKFIRE_EXPORT
const char* pakfire_file_get_symlink(struct pakfire_file
* file
) {
315 return file
->symlink
;
318 PAKFIRE_EXPORT
void pakfire_file_set_symlink(struct pakfire_file
* file
, const char* link
) {
320 *file
->hardlink
= '\0';
322 pakfire_string_set(file
->symlink
, link
);
325 PAKFIRE_EXPORT
int pakfire_file_get_type(struct pakfire_file
* file
) {
326 return file
->mode
& S_IFMT
;
329 PAKFIRE_EXPORT ssize_t
pakfire_file_get_size(struct pakfire_file
* file
) {
333 PAKFIRE_EXPORT
void pakfire_file_set_size(struct pakfire_file
* file
, ssize_t size
) {
337 PAKFIRE_EXPORT
const char* pakfire_file_get_user(struct pakfire_file
* file
) {
341 PAKFIRE_EXPORT
void pakfire_file_set_user(struct pakfire_file
* file
, const char* user
) {
342 pakfire_string_set(file
->user
, user
);
345 PAKFIRE_EXPORT
const char* pakfire_file_get_group(struct pakfire_file
* file
) {
349 PAKFIRE_EXPORT
void pakfire_file_set_group(struct pakfire_file
* file
, const char* group
) {
350 pakfire_string_set(file
->group
, group
);
353 PAKFIRE_EXPORT mode_t
pakfire_file_get_mode(struct pakfire_file
* file
) {
357 PAKFIRE_EXPORT
void pakfire_file_set_mode(struct pakfire_file
* file
, mode_t mode
) {
361 PAKFIRE_EXPORT dev_t
pakfire_file_get_dev(struct pakfire_file
* file
) {
365 PAKFIRE_EXPORT
void pakfire_file_set_dev(struct pakfire_file
* file
, dev_t dev
) {
369 PAKFIRE_EXPORT
time_t pakfire_file_get_ctime(struct pakfire_file
* file
) {
373 PAKFIRE_EXPORT
void pakfire_file_set_ctime(struct pakfire_file
* file
, time_t time
) {
377 PAKFIRE_EXPORT
time_t pakfire_file_get_mtime(struct pakfire_file
* file
) {
381 PAKFIRE_EXPORT
void pakfire_file_set_mtime(struct pakfire_file
* file
, time_t time
) {
385 static struct pakfire_file_digest
* pakfire_file_find_digest(
386 struct pakfire_file
* file
, enum pakfire_digests type
) {
387 struct pakfire_file_digest
* digest
= NULL
;
389 for (unsigned int i
= 0; i
< MAX_DIGESTS
; i
++) {
390 digest
= &file
->digests
[i
];
392 if (digest
->type
== type
)
400 PAKFIRE_EXPORT
const unsigned char* pakfire_file_get_digest(
401 struct pakfire_file
* file
, enum pakfire_digests type
, size_t* length
) {
402 const struct pakfire_file_digest
* digest
= pakfire_file_find_digest(file
, type
);
408 *length
= digest
->length
;
410 return digest
->digest
;
413 PAKFIRE_EXPORT
const char* pakfire_file_get_hexdigest(
414 struct pakfire_file
* file
, enum pakfire_digests type
) {
415 struct pakfire_file_digest
* digest
= pakfire_file_find_digest(file
, type
);
419 // Generate the hexdigest if non exists
420 if (!digest
->hexdigest
) {
421 const size_t length
= pakfire_digest_length(digest
->type
);
425 digest
->hexdigest
= __pakfire_hexlify(digest
->digest
, length
);
428 return digest
->hexdigest
;
431 PAKFIRE_EXPORT
int pakfire_file_set_digest(struct pakfire_file
* file
,
432 enum pakfire_digests type
, const unsigned char* digest
, size_t length
) {
433 if (!digest
|| !length
) {
438 // Find any existing digests of this type
439 struct pakfire_file_digest
* d
= pakfire_file_find_digest(file
, type
);
441 // If there is no digest, we will try finding a new one
443 d
= pakfire_file_find_digest(file
, PAKFIRE_DIGEST_NONE
);
445 // If we could not find a free spot, we probably run out of space
451 // Check if the digest fits into our pre-allocated buffer space
452 if (length
> sizeof(d
->digest
)) {
457 // Store type & length
462 memcpy(d
->digest
, digest
, d
->length
);
467 PAKFIRE_EXPORT
int pakfire_file_set_hexdigest(struct pakfire_file
* file
,
468 enum pakfire_digests type
, const char* hexdigest
) {
469 const size_t digest_length
= pakfire_digest_length(type
);
470 if (!digest_length
) {
475 // Allocate a buffer for the binary representation of the digest
476 unsigned char* digest
= alloca(digest_length
);
480 // Convert from hex to binary
481 __pakfire_unhexlify(digest
, digest_length
, hexdigest
);
483 return pakfire_file_set_digest(file
, type
, digest
, digest_length
);
486 static int pakfire_file_levels(struct pakfire_file
* file
) {
492 for (char* p
= file
->path
; *p
; p
++) {
500 FILE* pakfire_file_open(struct pakfire_file
* file
) {
501 FILE* f
= fopen(file
->abspath
, "r");
503 ERROR(file
->pakfire
, "Could not open %s: %m\n", file
->abspath
);
508 int pakfire_file_remove(struct pakfire_file
* file
) {
509 if (!*file
->abspath
) {
514 DEBUG(file
->pakfire
, "Removing %s...\n", file
->path
);
516 int r
= remove(file
->abspath
);
519 // Ignore when we could not remove directories
523 // Ignore if the file didn't exist
531 ERROR(file
->pakfire
, "Could not remove %s (%s): %m\n", file
->path
, file
->abspath
);
538 This function tries to remove the file after it has been packaged.
540 It will try to delete any parent directories as well and ignore if directories
541 cannot be deleted because they might contain other files
543 int pakfire_file_cleanup(struct pakfire_file
* file
) {
546 // Try removing the file
547 int r
= pakfire_file_remove(file
);
551 // Create a working copy of abspath
552 r
= pakfire_string_set(path
, file
->abspath
);
556 // See how many levels this file has
557 int levels
= pakfire_file_levels(file
);
559 // Walk all the way up and remove all parent directories if possible
563 // Break if path is suddenly empty
569 if (errno
== ENOTEMPTY
)