/* * (C) 2014-2016 by Christian Hesse <mail@eworm.de> * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * compile with: * $ gcc -o ykfde-cpio ykfde-cpio.c -larchive */ #include <dirent.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <archive.h> #include <archive_entry.h> #include "../config.h" int add_dir(struct archive *archive, const char * path) { struct stat st; struct archive_entry *entry; int8_t rc; /* initialize struct stat for directories from root */ if ((rc = stat("/", &st)) < 0) { perror("stat() failed"); goto out; } if ((entry = archive_entry_new()) == NULL) { rc = EXIT_FAILURE; fprintf(stderr, "archive_entry_new() failed"); goto out; } archive_entry_set_pathname(entry, path); archive_entry_set_filetype(entry, AE_IFDIR); archive_entry_copy_stat(entry, &st); if (archive_write_header(archive, entry) != ARCHIVE_OK) { rc = EXIT_FAILURE; fprintf(stderr, "archive_write_header() failed"); goto out; } archive_entry_free(entry); rc = EXIT_SUCCESS; out: return rc; } int main(int argc, const char **argv) { char cpiotmpfile[] = CPIOTMPFILE; struct archive *archive; struct archive_entry *entry; struct stat st; char buff[64]; int len, fdfile, fdarchive; DIR * dir; struct dirent * ent; char * filename, * path; off_t pathlength = 0; int8_t rc = EXIT_FAILURE; if ((rc = fdarchive = mkstemp(cpiotmpfile)) < 0) { perror("mkstemp() failed"); goto out10; } if ((archive = archive_write_new()) == NULL) { rc = EXIT_FAILURE; fprintf(stderr, "archive_write_new() failed.\n"); goto out10; } if (archive_write_set_format_cpio_newc(archive) != ARCHIVE_OK) { rc = EXIT_FAILURE; fprintf(stderr, "archive_write_set_format_cpio_newc() failed.\n"); goto out10; } if (archive_write_open_fd(archive, fdarchive) != ARCHIVE_OK) { rc = EXIT_FAILURE; fprintf(stderr, "archive_write_open_fd() failed.\n"); goto out10; } while (1) { path = strdup(CHALLENGEDIR + 1); if (strstr(path + pathlength, "/") == NULL) break; *strstr(path + pathlength, "/") = 0; pathlength = strlen(path) + 1; if ((rc = add_dir(archive, path)) < 0) { fprintf(stderr, "add_dir() failed"); goto out10; } free(path); } if ((dir = opendir(CHALLENGEDIR)) != NULL) { while ((ent = readdir(dir)) != NULL) { filename = malloc(sizeof(CHALLENGEDIR) + strlen(ent->d_name) + 1); sprintf(filename, CHALLENGEDIR "%s", ent->d_name); if ((rc = stat(filename, &st)) < 0) { perror("stat() failed"); goto out10; } if (S_ISREG(st.st_mode)) { if ((entry = archive_entry_new()) == NULL) { rc = EXIT_FAILURE; fprintf(stderr, "archive_entry_new() failed.\n"); goto out10; } /* these do not return exit code */ archive_entry_set_pathname(entry, filename + 1); archive_entry_set_size(entry, st.st_size); archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_perm(entry, 0644); if (archive_write_header(archive, entry) != ARCHIVE_OK) { rc = EXIT_FAILURE; fprintf(stderr, "archive_write_header() failed"); goto out10; } if ((rc = fdfile = open(filename, O_RDONLY)) < 0) { perror("open() failed"); goto out10; } if ((rc = len = read(fdfile, buff, sizeof(buff))) < 0) { perror("read() failed"); goto out10; } while (len > 0) { if (( rc = archive_write_data(archive, buff, len)) < 0) { fprintf(stderr, "archive_write_data() failed"); goto out10; } if ((rc = len = read(fdfile, buff, sizeof(buff))) < 0) { perror("read() failed"); goto out10; } } if ((rc = close(fdfile)) < 0) { perror("close() failed"); goto out10; } archive_entry_free(entry); } free(filename); } if ((rc = closedir(dir)) < 0) { perror("closedir() failed"); goto out10; } } else { rc = EXIT_FAILURE; perror("opendir() failed"); goto out10; } if (archive_write_close(archive) != ARCHIVE_OK) { rc = EXIT_FAILURE; fprintf(stderr, "archive_write_close() failed"); goto out10; } if (archive_write_free(archive) != ARCHIVE_OK) { rc = EXIT_FAILURE; fprintf(stderr, "archive_write_free() failed"); goto out10; } if (access(CPIOFILE, F_OK) == 0 && (rc = unlink(CPIOFILE)) < 0) { perror("unkink() failed"); goto out10; } if ((rc = rename(cpiotmpfile, CPIOFILE)) < 0) { perror("rename() failed"); goto out10; } rc = EXIT_SUCCESS; out10: if (access(cpiotmpfile, F_OK) == 0) unlink(cpiotmpfile); return rc; } // vim: set syntax=c: