tCheck for collision before unpacking - pm - barely a pack manager
 (HTM) git clone git://z3bra.org/pm
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit e6ba7b3f0f832855bd1ea7323644fcf0c9d39258
 (DIR) parent e7c528b75ba86304b270abc8181868ed3f5efd32
 (HTM) Author: z3bra <willyatmailoodotorg>
       Date:   Tue, 12 Jan 2016 10:27:00 +0100
       
       Check for collision before unpacking
       
       Diffstat:
         M pm.c                                |      50 ++++++++++++++++++++++++++-----
       
       1 file changed, 43 insertions(+), 7 deletions(-)
       ---
 (DIR) diff --git a/pm.c b/pm.c
       t@@ -51,6 +51,7 @@ char *base_name(char *path);
        struct pack *pack_load(char *path);
        void pack_free(struct pack *p);
        
       +int inspect_collision(char *rootfs, struct pack *p);
        int inspect_system(int fd, char *datadir);
        int inspect_files(int fd, char *datadir, char *packname);
        int inspect(char *datadir, char *packname);
       t@@ -134,6 +135,41 @@ base_name(char *path)
        
        
        /*
       + * Check for collisions between the filesystem and the tarball
       + */
       +int
       +inspect_collision(char *rootfs, struct pack *p)
       +{
       +        int r = 0;
       +        struct stat st;
       +        struct archive *a;
       +        struct archive_entry *e;
       +
       +        a = archive_read_new();
       +        archive_read_support_filter_bzip2(a);
       +        archive_read_support_format_tar(a);
       +
       +        r = archive_read_open_filename(a, p->path, 0);
       +        if (r != ARCHIVE_OK)
       +                return -1;
       +
       +        chdir(rootfs);
       +        while (archive_read_next_header(a, &e) == ARCHIVE_OK) {
       +                if (stat(archive_entry_pathname(e), &st) == 0 && !S_ISDIR(st.st_mode)) {
       +                        fprintf(stderr, "%s: File exists\n", archive_entry_pathname(e));
       +                        r = -1;
       +                        break;
       +                }
       +                archive_read_data_skip(a);
       +        }
       +
       +        archive_read_free(a);
       +
       +        return r;
       +}
       +
       +
       +/*
         * Write files installed by a pack to a file descriptor
         */
        int
       t@@ -273,19 +309,16 @@ write_entry(struct archive *a, struct archive *w)
        }
        
        
       +/*
       + * Extract a tarball to the given directory
       + */
        int
        unpack(struct archive *a, char *meta, int mask)
        {
                int r, fd;
       -        struct stat st;
                struct archive *w;
                struct archive_entry *e;
        
       -        if (stat(meta, &st) == 0 && (mask & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
       -                fprintf(stderr, "%s: File exists\n", meta);
       -                return -1;
       -        }
       -
                if ((fd = open(meta, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
                        perror(meta);
                        return -1;
       t@@ -337,8 +370,11 @@ install(char *rootfs, char *datadir, struct pack *p, int overwrite)
                int mask = ARCHIVE_EXTRACT_PERM
                          |ARCHIVE_EXTRACT_SECURE_NODOTDOT;
        
       -        if (overwrite == 0)
       +        if (overwrite == 0) {
       +                if (inspect_collision(rootfs, p) != 0)
       +                        return -1;
                        mask |= ARCHIVE_EXTRACT_NO_OVERWRITE;
       +        }
        
                /*
                 * ensure we can chdir to the rootfs and write metadata