/* This file is part of "reprepro" * Copyright (C) 2006,2007 Bernhard R. Link * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include "error.h" #include "uncompression.h" #include "ar.h" #include "filelist.h" #include "debfile.h" #ifndef HAVE_LIBARCHIVE #error Why did this file got compiled? #endif #if ARCHIVE_VERSION_NUMBER < 3000000 #define archive_read_free archive_read_finish #endif static retvalue read_data_tar(/*@out@*/char **list, /*@out@*/size_t *size, const char *debfile, struct ar_archive *ar, struct archive *tar) { struct archive_entry *entry; struct filelistcompressor c; retvalue r; int a, e; r = filelistcompressor_setup(&c); if (RET_WAS_ERROR(r)) return r; archive_read_support_format_tar(tar); archive_read_support_format_gnutar(tar); a = archive_read_open(tar, ar, ar_archivemember_open, ar_archivemember_read, ar_archivemember_close); if (a != ARCHIVE_OK) { filelistcompressor_cancel(&c); e = archive_errno(tar); if (e == -EINVAL) /* special code to say there is none */ fprintf(stderr, "open data.tar within '%s' failed: %s\n", debfile, archive_error_string(tar)); else fprintf(stderr, "open data.tar within '%s' failed: %d:%d:%s\n", debfile, a, e, archive_error_string(tar)); return RET_ERROR; } while ((a=archive_read_next_header(tar, &entry)) == ARCHIVE_OK) { const char *name = archive_entry_pathname(entry); mode_t mode; if (name[0] == '.') name++; if (name[0] == '/') name++; if (name[0] == '\0') continue; mode = archive_entry_mode(entry); if (!S_ISDIR(mode)) { r = filelistcompressor_add(&c, name, strlen(name)); if (RET_WAS_ERROR(r)) { filelistcompressor_cancel(&c); return r; } } if (interrupted()) { filelistcompressor_cancel(&c); return RET_ERROR_INTERRUPTED; } a = archive_read_data_skip(tar); if (a != ARCHIVE_OK) { e = archive_errno(tar); if (e == -EINVAL) { r = RET_ERROR; fprintf(stderr, "Error skipping %s within data.tar from %s: %s\n", archive_entry_pathname(entry), debfile, archive_error_string(tar)); } else { fprintf(stderr, "Error %d skipping %s within data.tar from %s: %s\n", e, archive_entry_pathname(entry), debfile, archive_error_string(tar)); if (e != 0) r = RET_ERRNO(e); else r = RET_ERROR; } filelistcompressor_cancel(&c); return r; } } if (a != ARCHIVE_EOF) { e = archive_errno(tar); if (e == -EINVAL) { r = RET_ERROR; fprintf(stderr, "Error reading data.tar from %s: %s\n", debfile, archive_error_string(tar)); } else { fprintf(stderr, "Error %d reading data.tar from %s: %s\n", e, debfile, archive_error_string(tar)); if (e != 0) r = RET_ERRNO(e); else r = RET_ERROR; } filelistcompressor_cancel(&c); return r; } return filelistcompressor_finish(&c, list, size); } retvalue getfilelist(/*@out@*/char **filelist, size_t *size, const char *debfile) { struct ar_archive *ar; retvalue r; bool hadcandidate; bool uncompressedretry = false; retrylabel: hadcandidate = false; r = ar_open(&ar, debfile); if (RET_WAS_ERROR(r)) return r; assert (r != RET_NOTHING); do { char *filename; enum compression c; r = ar_nextmember(ar, &filename); if (RET_IS_OK(r)) { if (strncmp(filename, "data.tar", 8) != 0) { free(filename); continue; } hadcandidate = true; for (c = 0 ; c < c_COUNT ; c++) { if (strcmp(filename + 8, uncompression_suffix[c]) == 0) break; } if (c >= c_COUNT) { free(filename); continue; } if (uncompressedretry) c = c_none; ar_archivemember_setcompression(ar, c); if (uncompression_supported(c)) { struct archive *tar; int a; tar = archive_read_new(); r = read_data_tar(filelist, size, debfile, ar, tar); a = archive_read_close(tar); if (a != ARCHIVE_OK && !RET_WAS_ERROR(r)) { int e = archive_errno(tar); if (e == -EINVAL) fprintf(stderr, "reading data.tar within '%s' failed: %s\n", debfile, archive_error_string( tar)); else fprintf(stderr, "reading data.tar within '%s' failed: %d:%d:%s\n", debfile, a, e, archive_error_string( tar)); r = RET_ERROR; } a = archive_read_free(tar); if (a != ARCHIVE_OK && !RET_WAS_ERROR(r)) { r = RET_ERROR; } if (r != RET_NOTHING) { ar_close(ar); free(filename); if ((r == RET_ERROR) && (!uncompressedretry)) { uncompressedretry = true; fprintf(stderr,"retrying uncompressed\n"); goto retrylabel; } else { return r; } } } free(filename); } } while (RET_IS_OK(r)); ar_close(ar); if (hadcandidate) fprintf(stderr, "Could not find a suitable data.tar file within '%s'!\n", debfile); else fprintf(stderr, "Could not find a data.tar file within '%s'!\n", debfile); return RET_ERROR_MISSING; }