From 37c5d873e7b9ccc9c3753c8737a886d88a4a2bb2 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Fri, 25 Aug 2023 17:39:41 +0000 Subject: [PATCH] file: Use "struct archive_entry" to store lots of metadata We used to copy metadata information from the entry format and back again which does not seem to be too clever. The overhead of the entry isn't that high that we cannot simply use them here. Signed-off-by: Michael Tremer --- src/libpakfire/file.c | 565 +++++++++++--------------- src/libpakfire/include/pakfire/file.h | 6 +- src/libpakfire/packager.c | 13 +- 3 files changed, 242 insertions(+), 342 deletions(-) diff --git a/src/libpakfire/file.c b/src/libpakfire/file.c index f308ea02c..2c985a7cf 100644 --- a/src/libpakfire/file.c +++ b/src/libpakfire/file.c @@ -62,18 +62,8 @@ struct pakfire_file { struct pakfire* pakfire; int nrefs; - // The relative path - char path[PATH_MAX]; - - // The absolute path in the file system - char abspath[PATH_MAX]; - - // File Ownership - char uname[LOGIN_NAME_MAX]; - char gname[LOGIN_NAME_MAX]; - - // Stat - struct stat st; + // Use the libarchive entry to store common attributes + struct archive_entry* entry; // Capabilities cap_t caps; @@ -81,10 +71,6 @@ struct pakfire_file { // Flags int flags; - // Link destinations - char hardlink[PATH_MAX]; - char symlink[PATH_MAX]; - // Digests struct pakfire_digests digests; @@ -206,7 +192,7 @@ static int pakfire_file_read_fcaps(struct pakfire_file* file, #ifdef ENABLE_DEBUG char* text = cap_to_text(file->caps, NULL); if (text) { - DEBUG(file->pakfire, "%s: Capabilities %s\n", file->path, text); + DEBUG(file->pakfire, "%s: Capabilities %s\n", pakfire_file_get_path(file), text); cap_free(text); } #endif @@ -284,70 +270,22 @@ ERROR: static int pakfire_file_from_archive_entry(struct pakfire_file* file, struct archive_entry* entry) { char* buffer = NULL; - const char* path = NULL; const char* attr = NULL; const void* value = NULL; size_t size = 0; int r = 0; - // Set abspath - path = archive_entry_sourcepath(entry); - if (path) { - // Make path absolute - path = pakfire_path_abspath(path); - if (!path) { - r = 1; - goto ERROR; - } - - // Set - r = pakfire_file_set_abspath(file, path); - if (r) { - ERROR(file->pakfire, "Could not set abspath: %m\n"); - goto ERROR; - } - } - - // Set path - path = archive_entry_pathname(entry); - if (path) { - r = pakfire_file_set_path(file, path); - if (r) { - ERROR(file->pakfire, "Could not set path: %m\n"); - goto ERROR; - } - } + // Remove the existing entry + if (file->entry) + archive_entry_free(file->entry); - // Set links - pakfire_file_set_hardlink(file, archive_entry_hardlink(entry)); - pakfire_file_set_symlink(file, archive_entry_symlink(entry)); - - pakfire_file_set_nlink(file, archive_entry_nlink(entry)); - pakfire_file_set_inode(file, archive_entry_ino64(entry)); - pakfire_file_set_dev(file, archive_entry_dev(entry)); - - // Set size - pakfire_file_set_size(file, archive_entry_size(entry)); - - // Set mode - pakfire_file_set_mode(file, archive_entry_mode(entry)); - - // Set dev type - if (archive_entry_dev_is_set(entry)) - pakfire_file_set_dev(file, archive_entry_dev(entry)); - - // Set uname - pakfire_file_set_uname(file, archive_entry_uname(entry)); - - // Set gname - pakfire_file_set_gname(file, archive_entry_gname(entry)); - - // Set times - pakfire_file_set_ctime(file, archive_entry_ctime(entry)); - pakfire_file_set_mtime(file, archive_entry_mtime(entry)); + // Clone the given entry + file->entry = archive_entry_clone(entry); + if (!file->entry) + return -ENOMEM; // Reset iterating over extended attributes - archive_entry_xattr_reset(entry); + archive_entry_xattr_reset(file->entry); // Read any extended attributes while (archive_entry_xattr_next(entry, &attr, &value, &size) == ARCHIVE_OK) { @@ -434,50 +372,35 @@ PAKFIRE_EXPORT int pakfire_file_create(struct pakfire_file** file, struct pakfir // Initialize reference counter f->nrefs = 1; + // Create a new archive entry + f->entry = archive_entry_new(); + if (!f->entry) + return -ENOMEM; + *file = f; return 0; } -int pakfire_file_create_from_path(struct pakfire_file** file, - struct pakfire* pakfire, const char* path) { - struct archive* reader = NULL; - struct archive_entry* entry = NULL; - int r = 1; - - // Allocate a reader - reader = pakfire_make_archive_disk_reader(pakfire, 0); - if (!reader) - goto ERROR; +int pakfire_file_read(struct pakfire_file* file, struct archive* reader, const char* path) { + int r; - // Allocate a new archive entry - entry = archive_entry_new(); - if (!entry) - goto ERROR; + // Check inputs + if (!reader || !path) + return -EINVAL; - // Set source path - archive_entry_copy_sourcepath(entry, path); + // Set abspath + r = pakfire_file_set_abspath(file, path); + if (r) + return r; - // Read all file attributes from disk - r = archive_read_disk_entry_from_file(reader, entry, -1, NULL); + // Read everything + r = archive_read_disk_entry_from_file(reader, file->entry, -1, NULL); if (r) { - ERROR(pakfire, "Could not read from %s: %m\n", path); - goto ERROR; + ERROR(file->pakfire, "Could not read %s: %s\n", path, archive_error_string(reader)); + return 1; } - // Create file - r = pakfire_file_create_from_archive_entry(file, pakfire, entry); - if (r) - goto ERROR; - -ERROR: - if (r) - ERROR(pakfire, "Could not create file from path %s: %m\n", path); - if (entry) - archive_entry_free(entry); - if (reader) - archive_read_free(reader); - - return r; + return 0; } int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire, @@ -501,50 +424,14 @@ ERROR: } struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types) { + struct archive_entry* entry = NULL; struct vfs_cap_data cap_data = {}; - const char* path = NULL; int r; - struct archive_entry* entry = archive_entry_new(); - if (!entry) { - ERROR(file->pakfire, "Could not allocate archive entry: %m\n"); + // Clone the entry + entry = archive_entry_clone(file->entry); + if (!entry) return NULL; - } - - // Set source path - archive_entry_copy_sourcepath(entry, file->abspath); - - // Set path - path = pakfire_file_get_path(file); - if (path && *path == '/') { - archive_entry_copy_pathname(entry, path + 1); - } - - // Set links - if (*file->hardlink) - archive_entry_set_hardlink(entry, file->hardlink); - if (*file->symlink) - archive_entry_set_symlink(entry, file->symlink); - - archive_entry_set_nlink(entry, pakfire_file_get_nlink(file)); - archive_entry_set_ino64(entry, pakfire_file_get_inode(file)); - archive_entry_set_dev(entry, pakfire_file_get_dev(file)); - - // Set size - archive_entry_set_size(entry, pakfire_file_get_size(file)); - - // Set mode - archive_entry_set_mode(entry, pakfire_file_get_mode(file)); - - // Set uname - archive_entry_set_uname(entry, pakfire_file_get_uname(file)); - - // Set gname - archive_entry_set_gname(entry, pakfire_file_get_gname(file)); - - // Set times - archive_entry_set_ctime(entry, pakfire_file_get_ctime(file), 0); - archive_entry_set_mtime(entry, pakfire_file_get_mtime(file), 0); // Flags if (pakfire_file_has_flag(file, PAKFIRE_FILE_CONFIG)) { @@ -562,7 +449,7 @@ struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int // Compute any required file digests r = pakfire_file_compute_digests(file, digest_types); if (r) - goto ERROR; + return NULL; // Copy digests @@ -607,7 +494,7 @@ struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int r = pakfire_file_write_fcaps(file, &cap_data); if (r) { ERROR(file->pakfire, "Could not export capabilities: %m\n"); - goto ERROR; + return NULL; } // Store capabilities in archive entry @@ -616,19 +503,14 @@ struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int } return entry; - -ERROR: - if (entry) - archive_entry_free(entry); - - return NULL; } static void pakfire_file_free(struct pakfire_file* file) { // Free capabilities if (file->caps) cap_free(file->caps); - + if (file->entry) + archive_entry_free(file->entry); pakfire_unref(file->pakfire); free(file); } @@ -717,7 +599,9 @@ static int __pakfire_file_strmode(struct pakfire_file* file, char* s, const size break; default: - if (*file->hardlink) { + const char* hardlink = pakfire_file_get_hardlink(file); + + if (hardlink) { s[0] = 'h'; break; } @@ -779,21 +663,28 @@ char* pakfire_file_dump(struct pakfire_file* file, int flags) { // Format ownership if (flags & PAKFIRE_FILE_DUMP_OWNERSHIP) { - r = asprintf(&buffer, "%s %s/%s", buffer, file->uname, file->gname); + const char* uname = pakfire_file_get_uname(file); + const char* gname = pakfire_file_get_gname(file); + + r = asprintf(&buffer, "%s %s/%s", buffer, uname, gname); if (r < 0) goto ERROR; } // Format size if (flags & PAKFIRE_FILE_DUMP_SIZE) { - r = asprintf(&buffer, "%s %8zu", buffer, file->st.st_size); + const size_t size = pakfire_file_get_size(file); + + r = asprintf(&buffer, "%s %8zu", buffer, size); if (r < 0) goto ERROR; } // Format time if (flags & PAKFIRE_FILE_DUMP_TIME) { - r = pakfire_strftime(time, "%Y-%m-%d %H:%M", file->st.st_ctime); + const time_t ctime = pakfire_file_get_ctime(file); + + r = pakfire_strftime(time, "%Y-%m-%d %H:%M", ctime); if (r) goto ERROR; @@ -803,7 +694,7 @@ char* pakfire_file_dump(struct pakfire_file* file, int flags) { } // Format path - r = asprintf(&buffer, "%s %s", buffer, file->path); + r = asprintf(&buffer, "%s %s", buffer, pakfire_file_get_path(file)); if (r < 0) goto ERROR; @@ -811,7 +702,7 @@ char* pakfire_file_dump(struct pakfire_file* file, int flags) { if (flags & PAKFIRE_FILE_DUMP_LINK_TARGETS) { switch (pakfire_file_get_type(file)) { case S_IFLNK: - r = asprintf(&buffer, "%s -> %s", buffer, file->symlink); + r = asprintf(&buffer, "%s -> %s", buffer, pakfire_file_get_symlink(file)); if (r < 0) return NULL; @@ -901,12 +792,10 @@ PAKFIRE_EXPORT int pakfire_file_cmp(struct pakfire_file* file1, struct pakfire_f } const char* pakfire_file_get_abspath(struct pakfire_file* file) { - return file->abspath; + return archive_entry_sourcepath(file->entry); } int pakfire_file_set_abspath(struct pakfire_file* file, const char* path) { - int r; - // Check if path is set and absolute if (!path || *path != '/') { errno = EINVAL; @@ -914,36 +803,18 @@ int pakfire_file_set_abspath(struct pakfire_file* file, const char* path) { } // Store the abspath - r = pakfire_string_set(file->abspath, path); - if (r) - goto ERROR; + archive_entry_copy_sourcepath(file->entry, path); - // Store path if it isn't set, yet - if (!*file->path) { - r = pakfire_file_set_path(file, path); - if (r) - goto ERROR; - } - - return r; - -ERROR: - ERROR(file->pakfire, "Could not set abspath '%s': %m\n", path); - return r; + return 0; } PAKFIRE_EXPORT const char* pakfire_file_get_path(struct pakfire_file* file) { - return file->path; + return archive_entry_pathname(file->entry); } PAKFIRE_EXPORT int pakfire_file_set_path(struct pakfire_file* file, const char* path) { - int r = 1; - - // Check if path is set - if (!path) { - errno = EINVAL; - goto ERROR; - } + char buffer[PATH_MAX]; + int r = 0; // Strip any leading dots from paths if (pakfire_string_startswith(path, "./")) @@ -952,24 +823,17 @@ PAKFIRE_EXPORT int pakfire_file_set_path(struct pakfire_file* file, const char* switch (*path) { // Just store the path if it is absolute case '/': - r = pakfire_string_set(file->path, path); - if (r) - goto ERROR; + archive_entry_set_pathname(file->entry, path); break; // Handle relative paths default: - r = pakfire_string_format(file->path, "/%s", path); + r = pakfire_string_format(buffer, "/%s", path); if (r) goto ERROR; - break; - } - // Set abspath if it isn't set, yet - if (!*file->abspath) { - r = pakfire_file_set_abspath(file, file->path); - if (r) - goto ERROR; + archive_entry_set_pathname(file->entry, buffer); + break; } return r; @@ -980,117 +844,111 @@ ERROR: } PAKFIRE_EXPORT const char* pakfire_file_get_hardlink(struct pakfire_file* file) { - if (!*file->hardlink) - return NULL; - - return file->hardlink; + return archive_entry_hardlink(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_hardlink(struct pakfire_file* file, const char* link) { - pakfire_string_set(file->hardlink, link); + archive_entry_set_hardlink(file->entry, link); } PAKFIRE_EXPORT const char* pakfire_file_get_symlink(struct pakfire_file* file) { - if (!*file->symlink) - return NULL; - - return file->symlink; + return archive_entry_symlink(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_symlink(struct pakfire_file* file, const char* link) { - pakfire_string_set(file->symlink, link); + archive_entry_set_symlink(file->entry, link); } PAKFIRE_EXPORT nlink_t pakfire_file_get_nlink(struct pakfire_file* file) { - return file->st.st_nlink; + return archive_entry_nlink(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_nlink(struct pakfire_file* file, const nlink_t nlink) { - file->st.st_nlink = nlink; + archive_entry_set_nlink(file->entry, nlink); } PAKFIRE_EXPORT ino_t pakfire_file_get_inode(struct pakfire_file* file) { - return file->st.st_ino; + return archive_entry_ino64(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_inode(struct pakfire_file* file, const ino_t ino) { - file->st.st_ino = ino; + archive_entry_set_ino64(file->entry, ino); } PAKFIRE_EXPORT dev_t pakfire_file_get_dev(struct pakfire_file* file) { - return file->st.st_dev; + return archive_entry_dev(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_dev(struct pakfire_file* file, const dev_t dev) { - file->st.st_dev = dev; + archive_entry_set_dev(file->entry, dev); } PAKFIRE_EXPORT int pakfire_file_get_type(struct pakfire_file* file) { - return file->st.st_mode & S_IFMT; + return archive_entry_filetype(file->entry); } PAKFIRE_EXPORT off_t pakfire_file_get_size(struct pakfire_file* file) { - return file->st.st_size; + return archive_entry_size(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_size(struct pakfire_file* file, off_t size) { - file->st.st_size = size; + archive_entry_set_size(file->entry, size); } PAKFIRE_EXPORT const char* pakfire_file_get_uname(struct pakfire_file* file) { - return file->uname; + return archive_entry_uname(file->entry); } PAKFIRE_EXPORT int pakfire_file_set_uname(struct pakfire_file* file, const char* uname) { - return pakfire_string_set(file->uname, uname); + archive_entry_set_uname(file->entry, uname); + + return 0; } PAKFIRE_EXPORT const char* pakfire_file_get_gname(struct pakfire_file* file) { - return file->gname; + return archive_entry_gname(file->entry); } PAKFIRE_EXPORT int pakfire_file_set_gname(struct pakfire_file* file, const char* gname) { - return pakfire_string_set(file->gname, gname); + archive_entry_set_gname(file->entry, gname); + + return 0; } PAKFIRE_EXPORT mode_t pakfire_file_get_mode(struct pakfire_file* file) { - return file->st.st_mode; + return archive_entry_mode(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_mode(struct pakfire_file* file, mode_t mode) { - file->st.st_mode = mode; + archive_entry_set_mode(file->entry, mode); } PAKFIRE_EXPORT mode_t pakfire_file_get_perms(struct pakfire_file* file) { - return file->st.st_mode & ~S_IFMT; + return archive_entry_perm(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_perms(struct pakfire_file* file, const mode_t perms) { - // Clear any previous permissions - file->st.st_mode &= S_IFMT; - - // Set new bits (with format cleared) - file->st.st_mode |= ~S_IFMT & perms; + archive_entry_set_mode(file->entry, pakfire_file_get_type(file) | perms); } static int pakfire_file_is_executable(struct pakfire_file* file) { - return file->st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH); + return pakfire_file_get_mode(file) & (S_IXUSR|S_IXGRP|S_IXOTH); } PAKFIRE_EXPORT time_t pakfire_file_get_ctime(struct pakfire_file* file) { - return file->st.st_ctime; + return archive_entry_ctime(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_ctime(struct pakfire_file* file, time_t time) { - file->st.st_ctime = time; + archive_entry_set_ctime(file->entry, time, 0); } PAKFIRE_EXPORT time_t pakfire_file_get_mtime(struct pakfire_file* file) { - return file->st.st_mtime; + return archive_entry_mtime(file->entry); } PAKFIRE_EXPORT void pakfire_file_set_mtime(struct pakfire_file* file, time_t time) { - file->st.st_mtime = time; + archive_entry_set_mtime(file->entry, time, 0); } PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest( @@ -1160,16 +1018,13 @@ PAKFIRE_EXPORT const unsigned char* pakfire_file_get_digest( PAKFIRE_EXPORT int pakfire_file_set_digest(struct pakfire_file* file, const enum pakfire_digest_types type, const unsigned char* digest, const size_t length) { - if (!digest) { - errno = EINVAL; - return 1; - } + if (!digest) + return -EINVAL; // Check buffer length if (pakfire_digest_length(type) != length) { ERROR(file->pakfire, "Digest has an incorrect length of %zu byte(s)\n", length); - errno = ENOMSG; - return 1; + return -ENOMSG; } // Store the digest @@ -1239,12 +1094,13 @@ ERROR: } static int pakfire_file_levels(struct pakfire_file* file) { - if (!*file->path) + const char* path = pakfire_file_get_path(file); + if (!path) return 0; int levels = 0; - for (char* p = file->path; *p; p++) { + for (const char* p = path; *p; p++) { if (*p == '/') levels++; } @@ -1253,9 +1109,13 @@ static int pakfire_file_levels(struct pakfire_file* file) { } FILE* pakfire_file_open(struct pakfire_file* file) { - FILE* f = fopen(file->abspath, "r+"); + const char* path = pakfire_file_get_abspath(file); + if (!path) + return NULL; + + FILE* f = fopen(path, "r+"); if (!f) - ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath); + ERROR(file->pakfire, "Could not open %s: %m\n", path); return f; } @@ -1267,12 +1127,16 @@ int pakfire_file_payload_matches(struct pakfire_file* file, void* p = NULL; int r; + const mode_t mode = pakfire_file_get_mode(file); + // Only run for regular files - if (!S_ISREG(file->st.st_mode)) + if (!S_ISREG(mode)) return 0; + const size_t size = pakfire_file_get_size(file); + // Skip empty files - if (!file->st.st_size) + if (!size) return 0; // Open the file @@ -1314,8 +1178,10 @@ static int __pakfire_file_compute_digests(struct pakfire_file* file, FILE* f = NULL; int r = 1; + const mode_t mode = pakfire_file_get_mode(file); + // Skip this for anything that isn't a regular file - if (!S_ISREG(file->st.st_mode)) + if (!S_ISREG(mode)) return 0; // Reset digests @@ -1345,17 +1211,19 @@ int pakfire_file_compute_digests(struct pakfire_file* file, const int types) { static int pakfire_file_remove(struct pakfire_file* file) { int r; - if (!*file->abspath) { - errno = EINVAL; - return 1; - } + const char* path = pakfire_file_get_path(file); + const char* abspath = pakfire_file_get_abspath(file); + + DEBUG(file->pakfire, "Removing %s...\n", path); - DEBUG(file->pakfire, "Removing %s...\n", file->path); + // We cannot delete if we don't have the absolute path + if (!abspath) + return -ENOTSUP; - switch (file->st.st_mode & S_IFMT) { + switch (pakfire_file_get_type(file)) { // Call rmdir() for directories case S_IFDIR: - r = rmdir(file->abspath); + r = rmdir(abspath); if (r) { switch (errno) { // Ignore when the directory is not empty @@ -1375,7 +1243,7 @@ static int pakfire_file_remove(struct pakfire_file* file) { // Log anything else default: - ERROR(file->pakfire, "Could not remove directory %s: %m\n", file->path); + ERROR(file->pakfire, "Could not remove directory %s: %m\n", path); break; } } @@ -1383,7 +1251,7 @@ static int pakfire_file_remove(struct pakfire_file* file) { // Call unlink() for everything else default: - r = unlink(file->abspath); + r = unlink(abspath); if (r) { switch (errno) { // Ignore if the file didn't exist @@ -1392,7 +1260,7 @@ static int pakfire_file_remove(struct pakfire_file* file) { break; default: - ERROR(file->pakfire, "Could not remove %s: %m\n", file->path); + ERROR(file->pakfire, "Could not remove %s: %m\n", path); break; } } @@ -1403,13 +1271,15 @@ static int pakfire_file_remove(struct pakfire_file* file) { } int pakfire_file_symlink_target_exists(struct pakfire_file* file) { + const mode_t mode = pakfire_file_get_mode(file); + // Fail if this got called for anything that isn't a symlink - if (!S_ISLNK(file->st.st_mode)) { - errno = EINVAL; - return -1; - } + if (!S_ISLNK(mode)) + return -EINVAL; - return pakfire_path_exists(file->abspath); + const char* path = pakfire_file_get_abspath(file); + + return pakfire_path_exists(path); } /* @@ -1417,8 +1287,10 @@ int pakfire_file_symlink_target_exists(struct pakfire_file* file) { */ int pakfire_file_detect_mimetype(struct pakfire_file* file) { + const mode_t mode = pakfire_file_get_mode(file); + // Only process regular files - if (!S_ISREG(file->st.st_mode)) + if (!S_ISREG(mode)) return 0; // Skip if MIME type is already set @@ -1430,14 +1302,17 @@ int pakfire_file_detect_mimetype(struct pakfire_file* file) { if (!magic) return 1; + const char* path = pakfire_file_get_abspath(file); + // Check the file - const char* mimetype = magic_file(magic, file->abspath); + const char* mimetype = magic_file(magic, path); if (!mimetype) { - ERROR(file->pakfire, "Could not classify %s: %s\n", file->path, magic_error(magic)); + ERROR(file->pakfire, "Could not classify %s: %s\n", + pakfire_file_get_path(file), magic_error(magic)); return 1; } - DEBUG(file->pakfire, "Classified %s as %s\n", file->path, mimetype); + DEBUG(file->pakfire, "Classified %s as %s\n", pakfire_file_get_path(file), mimetype); // Store the value return pakfire_file_set_mimetype(file, mimetype); @@ -1473,36 +1348,38 @@ static int setup_libelf(struct pakfire* pakfire) { } static int pakfire_file_classify_mode(struct pakfire_file* file) { + const mode_t mode = pakfire_file_get_mode(file); + // Check for regular files - if (S_ISREG(file->st.st_mode)) { + if (S_ISREG(mode)) { file->class |= PAKFIRE_FILE_REGULAR; // Does the file have executable permissions? - if (file->st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) + if (mode & (S_IXUSR|S_IXGRP|S_IXOTH)) file->class |= PAKFIRE_FILE_EXECUTABLE; // Check for directories - } else if (S_ISDIR(file->st.st_mode)) + } else if (S_ISDIR(mode)) file->class |= PAKFIRE_FILE_DIRECTORY; // Check for symlinks - else if (S_ISLNK(file->st.st_mode)) + else if (S_ISLNK(mode)) file->class |= PAKFIRE_FILE_SYMLINK; // Check for character devices - else if (S_ISCHR(file->st.st_mode)) + else if (S_ISCHR(mode)) file->class |= PAKFIRE_FILE_CHARACTER; // Check for block devices - else if (S_ISBLK(file->st.st_mode)) + else if (S_ISBLK(mode)) file->class |= PAKFIRE_FILE_BLOCK; // Check for FIFO pipes - else if (S_ISFIFO(file->st.st_mode)) + else if (S_ISFIFO(mode)) file->class |= PAKFIRE_FILE_FIFO; // Check for sockets - else if (S_ISSOCK(file->st.st_mode)) + else if (S_ISSOCK(mode)) file->class |= PAKFIRE_FILE_SOCKET; return 0; @@ -1580,9 +1457,9 @@ static int pakfire_file_classify_elf(struct pakfire_file* file) { return r; // Open the file - f = fopen(file->abspath, "r"); + f = pakfire_file_open(file); if (!f) { - ERROR(file->pakfire, "Could not open %s: %m\n", file->path); + ERROR(file->pakfire, "Could not open %s: %m\n", pakfire_file_get_path(file)); return 1; } @@ -1670,8 +1547,10 @@ int pakfire_file_cleanup(struct pakfire_file* file, int flags) { // Try to tidy up afterwards if (flags & PAKFIRE_FILE_CLEANUP_TIDY) { + const char* abspath = pakfire_file_get_abspath(file); + // Create a working copy of abspath - r = pakfire_string_set(path, file->abspath); + r = pakfire_string_set(path, abspath); if (r) return r; @@ -1706,7 +1585,7 @@ static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat if (type != (st->st_mode & S_IFMT)) { file->verify_status |= PAKFIRE_FILE_TYPE_CHANGED; - DEBUG(file->pakfire, "%s: File Type changed\n", file->path); + DEBUG(file->pakfire, "%s: File Type changed\n", pakfire_file_get_path(file)); } const mode_t perms = pakfire_file_get_perms(file); @@ -1715,7 +1594,7 @@ static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat if (perms != (st->st_mode & 0777)) { file->verify_status |= PAKFIRE_FILE_PERMISSIONS_CHANGED; - DEBUG(file->pakfire, "%s: Permissions changed\n", file->path); + DEBUG(file->pakfire, "%s: Permissions changed\n", pakfire_file_get_path(file)); } #if 0 @@ -1728,7 +1607,7 @@ static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat if (dev != st->st_dev) { file->verify_status |= PAKFIRE_FILE_DEV_CHANGED; - DEBUG(file->pakfire, "%s: Device Node changed\n", file->path); + DEBUG(file->pakfire, "%s: Device Node changed\n", pakfire_file_get_path(file)); } } #endif @@ -1737,15 +1616,17 @@ static int pakfire_file_verify_mode(struct pakfire_file* file, const struct stat } static int pakfire_file_verify_size(struct pakfire_file* file, const struct stat* st) { + const ssize_t size = pakfire_file_get_size(file); + // Nothing to do if size matches - if (file->st.st_size == st->st_size) + if (size == st->st_size) return 0; // Size differs file->verify_status |= PAKFIRE_FILE_SIZE_CHANGED; DEBUG(file->pakfire, "%s: Filesize differs (expected %zu, got %zu byte(s))\n", - file->path, file->st.st_size, st->st_size); + pakfire_file_get_path(file), size, st->st_size); return 0; } @@ -1760,40 +1641,46 @@ static int pakfire_file_verify_ownership(struct pakfire_file* file, const struct const gid_t gid = st->st_gid; #endif + const char* uname = pakfire_file_get_uname(file); + const char* gname = pakfire_file_get_gname(file); + // Fetch owner & group - struct passwd* owner = pakfire_getpwnam(file->pakfire, file->uname); - struct group* group = pakfire_getgrnam(file->pakfire, file->gname); + struct passwd* owner = pakfire_getpwnam(file->pakfire, uname); + struct group* group = pakfire_getgrnam(file->pakfire, gname); // Check if owner matches if (!owner || owner->pw_uid != uid) { file->verify_status |= PAKFIRE_FILE_OWNER_CHANGED; - DEBUG(file->pakfire, "%s: Owner differs\n", file->path); + DEBUG(file->pakfire, "%s: Owner differs\n", pakfire_file_get_path(file)); } // Check if group matches if (!group || group->gr_gid != gid) { file->verify_status |= PAKFIRE_FILE_GROUP_CHANGED; - DEBUG(file->pakfire, "%s: Group differs\n", file->path); + DEBUG(file->pakfire, "%s: Group differs\n", pakfire_file_get_path(file)); } return 0; } static int pakfire_file_verify_timestamps(struct pakfire_file* file, const struct stat* st) { + const time_t ctime = pakfire_file_get_ctime(file); + const time_t mtime = pakfire_file_get_mtime(file); + // Check creation time - if (file->st.st_ctime != st->st_ctime) { + if (ctime != st->st_ctime) { file->verify_status |= PAKFIRE_FILE_CTIME_CHANGED; - DEBUG(file->pakfire, "%s: Creation time changed\n", file->path); + DEBUG(file->pakfire, "%s: Creation time changed\n", pakfire_file_get_path(file)); } // Check modification time - if (file->st.st_mtime != st->st_mtime) { + if (mtime != st->st_mtime) { file->verify_status |= PAKFIRE_FILE_MTIME_CHANGED; - DEBUG(file->pakfire, "%s: Modification time changed\n", file->path); + DEBUG(file->pakfire, "%s: Modification time changed\n", pakfire_file_get_path(file)); } return 0; @@ -1819,7 +1706,7 @@ static int pakfire_file_verify_payload(struct pakfire_file* file, const struct s digest_types = pakfire_digest_has_any(&file->digests); if (!digest_types) { - ERROR(file->pakfire, "%s: No digests available\n", file->path); + ERROR(file->pakfire, "%s: No digests available\n", pakfire_file_get_path(file)); return 0; } @@ -1833,7 +1720,7 @@ static int pakfire_file_verify_payload(struct pakfire_file* file, const struct s if (r) { file->verify_status |= PAKFIRE_FILE_PAYLOAD_CHANGED; - DEBUG(file->pakfire, "%s: Digest(s) do not match\n", file->path); + DEBUG(file->pakfire, "%s: Digest(s) do not match\n", pakfire_file_get_path(file)); } ERROR: @@ -1847,10 +1734,12 @@ int pakfire_file_verify(struct pakfire_file* file, int* status) { struct stat st; int r; - DEBUG(file->pakfire, "Verifying %s...\n", file->path); + DEBUG(file->pakfire, "Verifying %s...\n", pakfire_file_get_path(file)); + + const char* abspath = pakfire_file_get_abspath(file); // stat() the file - r = lstat(file->abspath, &st); + r = lstat(abspath, &st); if (r) { // File does not exist if (errno == ENOENT) { @@ -1891,26 +1780,13 @@ int pakfire_file_verify(struct pakfire_file* file, int* status) { } PAKFIRE_EXPORT int pakfire_file_matches(struct pakfire_file* file, const char* pattern) { - int r; - // Don't match on no pattern if (!pattern) return 0; - // Check if the pattern matches - r = fnmatch(pattern, file->path, 0); - switch (r) { - // Match - case 0: - return 1; + const char* path = pakfire_file_get_path(file); - // No Match - case FNM_NOMATCH: - return 0; - - default: - return -1; - } + return pakfire_path_match(pattern, path); } /* @@ -1935,9 +1811,9 @@ static int pakfire_file_open_elf(struct pakfire_file* file, return r; // Open the file - f = fopen(file->abspath, "r"); + f = pakfire_file_open(file); if (!f) { - ERROR(file->pakfire, "Could not open %s: %m\n", file->abspath); + ERROR(file->pakfire, "Could not open %s: %m\n", pakfire_file_get_abspath(file)); return 1; } @@ -1955,7 +1831,7 @@ static int pakfire_file_open_elf(struct pakfire_file* file, break; default: - ERROR(file->pakfire, "%s is not an ELF object\n", file->path); + ERROR(file->pakfire, "%s is not an ELF object\n", pakfire_file_get_path(file)); r = 1; goto ERROR; } @@ -2086,7 +1962,7 @@ static int pakfire_file_elf_dyn_walk(struct pakfire_file* file, Elf* elf, // Find the dynamic linking information r = pakfire_file_get_elf_section(file, elf, SHT_DYNAMIC, &dynamic, &shdr, &elf_data); if (r) { - ERROR(file->pakfire, "%s does not have a dynamic section\n", file->path); + ERROR(file->pakfire, "%s does not have a dynamic section\n", pakfire_file_get_path(file)); return 1; } @@ -2114,7 +1990,7 @@ static int __pakfire_file_check_debuginfo(struct pakfire_file* file, Elf* elf, v // Not found if (r) { - DEBUG(file->pakfire, "%s has no debug sections\n", file->path); + DEBUG(file->pakfire, "%s has no debug sections\n", pakfire_file_get_path(file)); // Store the result file->issues |= PAKFIRE_FILE_MISSING_DEBUGINFO; @@ -2149,7 +2025,7 @@ static int __pakfire_file_check_ssp( // Fetch the symbol table r = pakfire_file_get_elf_section(file, elf, SHT_SYMTAB, &symtab, &shdr, &elf_data); if (r) { - ERROR(file->pakfire, "%s has no symbol table\n", file->path); + ERROR(file->pakfire, "%s has no symbol table\n", pakfire_file_get_path(file)); return 1; } @@ -2180,7 +2056,8 @@ static int __pakfire_file_check_ssp( // We do not perform the check for libraries that do not contain any functions. // Some packages use shared libraries to provide data. if (!counter) { - DEBUG(file->pakfire, "%s: File has no functions. Skipping SSP check.\n", file->path); + DEBUG(file->pakfire, "%s: File has no functions. Skipping SSP check.\n", + pakfire_file_get_path(file)); return 0; } @@ -2259,7 +2136,7 @@ static int __pakfire_file_check_execstack( case PT_GNU_STACK: DEBUG(file->pakfire, "%s: GNU_STACK flags: %c%c%c\n", - file->path, + pakfire_file_get_path(file), (phdr.p_flags & PF_R) ? 'R' : '-', (phdr.p_flags & PF_W) ? 'W' : '-', (phdr.p_flags & PF_X) ? 'X' : '-' @@ -2372,7 +2249,8 @@ static int __pakfire_file_process_runpath(struct pakfire_file* file, if (!value) return 1; - DEBUG(file->pakfire, "%s has a RUNPATH: %s\n", file->path, value); + DEBUG(file->pakfire, "%s has a RUNPATH: %s\n", + pakfire_file_get_path(file), value); // Copy the value into a buffer we can modify r = pakfire_string_set(buffer, value); @@ -2436,16 +2314,20 @@ static int pakfire_file_get_script_interpreter(struct pakfire_file* file, char** return 1; } + const mode_t mode = pakfire_file_get_mode(file); + // Only run for regular files - if (!S_ISREG(file->st.st_mode)) + if (!S_ISREG(mode)) return 0; // Only run for executable files if (!pakfire_file_is_executable(file)) return 0; + const size_t size = pakfire_file_get_size(file); + // Nothing to do if the file is empty - if (!file->st.st_size) + if (!size) return 0; // Open the file @@ -2460,7 +2342,8 @@ static int pakfire_file_get_script_interpreter(struct pakfire_file* file, char** // Handle any reading errors if (bytes_read < 0) { - ERROR(file->pakfire, "Could not read from file %s: %m\n", file->path); + ERROR(file->pakfire, "Could not read from file %s: %m\n", + pakfire_file_get_path(file)); r = 1; goto ERROR; } @@ -2472,12 +2355,13 @@ static int pakfire_file_get_script_interpreter(struct pakfire_file* file, char** } if (strncmp("#!", shebang, 2) == 0) { - DEBUG(file->pakfire, "%s is a script\n", file->path); + DEBUG(file->pakfire, "%s is a script\n", pakfire_file_get_path(file)); // Find the end of the first line (to be able to perform string operations) p = memchr(shebang, '\n', sizeof(shebang)); if (!p) { - ERROR(file->pakfire, "%s: First line seems to be too long\n", file->path); + ERROR(file->pakfire, "%s: First line seems to be too long\n", + pakfire_file_get_path(file)); errno = ENOBUFS; r = 1; goto ERROR; @@ -2527,12 +2411,13 @@ static int pakfire_file_fix_interpreter(struct pakfire_file* file, const char* i char* data = NULL; size_t length = 0; - DEBUG(file->pakfire, "%s: Fixing interpreter %s\n", file->path, interpreter); + DEBUG(file->pakfire, "%s: Fixing interpreter %s\n", + pakfire_file_get_path(file), interpreter); // Open the file f = pakfire_file_open(file); if (!f) { - ERROR(file->pakfire, "Could not open %s: %m\n", file->path); + ERROR(file->pakfire, "Could not open %s: %m\n", pakfire_file_get_path(file)); r = 1; goto ERROR; } @@ -2568,7 +2453,7 @@ static int pakfire_file_fix_interpreter(struct pakfire_file* file, const char* i if (pakfire_string_startswith(p, "#!")) { p += 2; } else { - ERROR(file->pakfire, "%s: Could not find shebang\n", file->path); + ERROR(file->pakfire, "%s: Could not find shebang\n", pakfire_file_get_path(file)); errno = EINVAL; r = 1; goto ERROR; @@ -2596,12 +2481,13 @@ static int pakfire_file_fix_interpreter(struct pakfire_file* file, const char* i // Terminate the command *p++ = '\0'; - DEBUG(file->pakfire, "%s: Found command: %s\n", file->path, command); + DEBUG(file->pakfire, "%s: Found command: %s\n", pakfire_file_get_path(file), command); // Find the absolute path to the command r = pakfire_which(file->pakfire, path, command); if (r) { - DEBUG(file->pakfire, "%s: Could not resolve command %s: %m\n", file->path, command); + DEBUG(file->pakfire, "%s: Could not resolve command %s: %m\n", + pakfire_file_get_path(file), command); goto ERROR; } @@ -2618,7 +2504,8 @@ static int pakfire_file_fix_interpreter(struct pakfire_file* file, const char* i // Write shebang r = fprintf(f, (*p) ? "#!%s %s\n" : "#!%s\n", path, p); if (r < 0) { - ERROR(file->pakfire, "%s: Could not write back first line: %m\n", file->path); + ERROR(file->pakfire, "%s: Could not write back first line: %m\n", + pakfire_file_get_path(file)); r = 1; goto ERROR; } @@ -2629,7 +2516,8 @@ static int pakfire_file_fix_interpreter(struct pakfire_file* file, const char* i // Write the rest size_t bytes_written = fwrite(rest, 1, length, f); if (bytes_written < length) { - ERROR(file->pakfire, "%s: Could not write the payload: %m\n", file->path); + ERROR(file->pakfire, "%s: Could not write the payload: %m\n", + pakfire_file_get_path(file)); r = 1; goto ERROR; } @@ -2659,7 +2547,8 @@ static int pakfire_file_check_interpreter(struct pakfire_file* file) { if (!interpreter) return 0; - DEBUG(file->pakfire, "%s: Interpreter: %s\n", file->path, interpreter); + DEBUG(file->pakfire, "%s: Interpreter: %s\n", + pakfire_file_get_path(file), interpreter); // Paths must be absolute if (*interpreter != '/') @@ -2673,7 +2562,8 @@ static int pakfire_file_check_interpreter(struct pakfire_file* file) { else if (strcmp(interpreter, "/usr/bin/env") == 0) { r = pakfire_file_fix_interpreter(file, interpreter); if (r) { - ERROR(file->pakfire, "%s: Could not fix interpreter: %m\n", file->path); + ERROR(file->pakfire, "%s: Could not fix interpreter: %m\n", + pakfire_file_get_path(file)); goto ERROR; } } @@ -2732,7 +2622,8 @@ static int __pakfire_file_check_cf_protection_x86(struct pakfire_file* file, // Check for IBT if (!(property & GNU_PROPERTY_X86_FEATURE_1_IBT)) { - DEBUG(file->pakfire, "%s: IBT property is not enabled\n", file->path); + DEBUG(file->pakfire, "%s: IBT property is not enabled\n", + pakfire_file_get_path(file)); // XXX TODO Actually modify any flags @@ -2741,7 +2632,8 @@ static int __pakfire_file_check_cf_protection_x86(struct pakfire_file* file, // Check for Shadow Stack if (!(property & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) { - DEBUG(file->pakfire, "%s: Shadow Stack is not enabled\n", file->path); + DEBUG(file->pakfire, "%s: Shadow Stack is not enabled\n", + pakfire_file_get_path(file)); // XXX TODO Actually modify any flags @@ -2762,7 +2654,8 @@ static int pakfire_file_check_cf_protection_callback(struct pakfire_file* file, // Fetch the ELF header if (!gelf_getehdr(elf, &ehdr)) { - ERROR(file->pakfire, "Could not fetch the ELF header for %s: %m\n", file->path); + ERROR(file->pakfire, "Could not fetch the ELF header for %s: %m\n", + pakfire_file_get_path(file)); return 1; } diff --git a/src/libpakfire/include/pakfire/file.h b/src/libpakfire/include/pakfire/file.h index a09622078..a175c91ff 100644 --- a/src/libpakfire/include/pakfire/file.h +++ b/src/libpakfire/include/pakfire/file.h @@ -102,6 +102,7 @@ int pakfire_file_matches(struct pakfire_file* file, const char* pattern); #ifdef PAKFIRE_PRIVATE +#include #include #include @@ -131,10 +132,11 @@ enum pakfire_file_classes { PAKFIRE_FILE_RUNTIME_LINKER = (1 << 14), }; + +int pakfire_file_read(struct pakfire_file* file, struct archive* reader, const char* path); + int pakfire_file_write_fcaps(struct pakfire_file* file, struct vfs_cap_data* cap_data); -int pakfire_file_create_from_path(struct pakfire_file** file, - struct pakfire* pakfire, const char* path); int pakfire_file_create_from_archive_entry(struct pakfire_file** file, struct pakfire* pakfire, struct archive_entry* entry); struct archive_entry* pakfire_file_archive_entry(struct pakfire_file* file, int digest_types); diff --git a/src/libpakfire/packager.c b/src/libpakfire/packager.c index 21a812b93..17b8669a2 100644 --- a/src/libpakfire/packager.c +++ b/src/libpakfire/packager.c @@ -550,7 +550,7 @@ int pakfire_packager_add_file(struct pakfire_packager* packager, struct pakfire_ const char* path = pakfire_file_get_path(file); // Files cannot have an empty path - if (!*path) { + if (!path || !*path) { ERROR(packager->pakfire, "Cannot add a file with an empty path\n"); errno = EPERM; return 1; @@ -606,10 +606,15 @@ int pakfire_packager_add_file(struct pakfire_packager* packager, struct pakfire_ int pakfire_packager_add(struct pakfire_packager* packager, const char* sourcepath, const char* path) { struct pakfire_file* file = NULL; - int r = 1; + int r; + + // Create a new file object + r = pakfire_file_create(&file, packager->pakfire); + if (r) + goto ERROR; - // Create file - r = pakfire_file_create_from_path(&file, packager->pakfire, sourcepath); + // Read the meta information + r = pakfire_file_read(file, packager->reader, sourcepath); if (r) goto ERROR; -- 2.39.5