diff options
Diffstat (limited to 'src/elfcompress.c')
-rw-r--r-- | src/elfcompress.c | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/src/elfcompress.c b/src/elfcompress.c index 78dc27a4..1d6a9672 100644 --- a/src/elfcompress.c +++ b/src/elfcompress.c @@ -1,5 +1,5 @@ /* Compress or decompress an ELF file. - Copyright (C) 2015, 2016 Red Hat, Inc. + Copyright (C) 2015, 2016, 2018 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -18,7 +18,6 @@ #include <config.h> #include <assert.h> #include <argp.h> -#include <error.h> #include <stdbool.h> #include <stdlib.h> #include <inttypes.h> @@ -34,6 +33,7 @@ #include ELFUTILS_HEADER(ebl) #include ELFUTILS_HEADER(dwelf) #include <gelf.h> +#include "system.h" #include "libeu.h" #include "printversion.h" @@ -289,6 +289,15 @@ process_file (const char *fname) return (sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0; } + /* How many sections are we going to change? */ + size_t get_sections (void) + { + size_t s = 0; + for (size_t i = 0; i < shnum / WORD_BITS + 1; i++) + s += __builtin_popcount (sections[i]); + return s; + } + int cleanup (int res) { elf_end (elf); @@ -425,6 +434,9 @@ process_file (const char *fname) names change and whether there is a symbol table that might need to be adjusted be if the section header name table is changed. + If nothing needs changing, and the input and output file are the + same, we are done. + Second a collection pass that creates the Elf sections and copies the data. This pass will compress/decompress section data when needed. And it will collect all data needed if we'll need to @@ -467,7 +479,26 @@ process_file (const char *fname) if (section_name_matches (sname)) { - if (shdr->sh_type != SHT_NOBITS + if (!force && type == T_DECOMPRESS + && (shdr->sh_flags & SHF_COMPRESSED) == 0 + && strncmp (sname, ".zdebug", strlen (".zdebug")) != 0) + { + if (verbose > 0) + printf ("[%zd] %s already decompressed\n", ndx, sname); + } + else if (!force && type == T_COMPRESS_ZLIB + && (shdr->sh_flags & SHF_COMPRESSED) != 0) + { + if (verbose > 0) + printf ("[%zd] %s already compressed\n", ndx, sname); + } + else if (!force && type == T_COMPRESS_GNU + && strncmp (sname, ".zdebug", strlen (".zdebug")) == 0) + { + if (verbose > 0) + printf ("[%zd] %s already GNU compressed\n", ndx, sname); + } + else if (shdr->sh_type != SHT_NOBITS && (shdr->sh_flags & SHF_ALLOC) == 0) { set_section (ndx); @@ -521,6 +552,14 @@ process_file (const char *fname) } } + if (foutput == NULL && get_sections () == 0) + { + if (verbose > 0) + printf ("Nothing to do.\n"); + fnew = NULL; + return cleanup (0); + } + if (adjust_names) { names = dwelf_strtab_init (true); @@ -1238,17 +1277,20 @@ process_file (const char *fname) elf_end (elfnew); elfnew = NULL; -#if HAVE_DECL_FCHMOD - /* Try to match mode and owner.group of the original file. */ - if (fchmod (fdnew, st.st_mode & 07777) != 0) - if (verbose >= 0) - error (0, errno, "Couldn't fchmod %s", fnew); -#endif #if HAVE_DECL_FCHOWN + /* Try to match mode and owner.group of the original file. + Note to set suid bits we have to make sure the owner is setup + correctly first. Otherwise fchmod will drop them silently + or fchown may clear them. */ if (fchown (fdnew, st.st_uid, st.st_gid) != 0) if (verbose >= 0) error (0, errno, "Couldn't fchown %s", fnew); #endif +#if HAVE_DECL_FCHMOD + if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0) + if (verbose >= 0) + error (0, errno, "Couldn't fchmod %s", fnew); +#endif /* Finally replace the old file with the new file. */ if (foutput == NULL) @@ -1283,7 +1325,7 @@ main (int argc, char **argv) N_("Print a message for each section being (de)compressed"), 0 }, { "force", 'f', NULL, 0, - N_("Force compression of section even if it would become larger"), + N_("Force compression of section even if it would become larger or update/rewrite the file even if no section would be (de)compressed"), 0 }, { "permissive", 'p', NULL, 0, N_("Relax a few rules to handle slightly broken ELF files"), |