archive_extractor.c (3894B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2012 Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file plugins/archive_extractor.c 22 * @brief plugin to support archives (such as TAR) 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "extractor.h" 27 #include <archive.h> 28 #include <archive_entry.h> 29 30 /** 31 * Callback for libarchive for 'reading'. 32 * 33 * @param a archive handle 34 * @param client_data our 'struct EXTRACTOR_ExtractContext' 35 * @param buff where to store data with pointer to data 36 * @return number of bytes read 37 */ 38 static ssize_t 39 read_cb (struct archive *a, 40 void *client_data, 41 const void **buff) 42 { 43 struct EXTRACTOR_ExtractContext *ec = client_data; 44 ssize_t ret; 45 46 *buff = NULL; 47 if (-1 == (ret = ec->read (ec->cls, (void **) buff, 16 * 1024))) 48 return ARCHIVE_FATAL; 49 return ret; 50 } 51 52 53 /** 54 * Older versions of libarchive do not define __LA_INT64_T. 55 */ 56 #if ARCHIVE_VERSION_NUMBER < 2000000 57 #define __LA_INT64_T size_t 58 #else 59 #ifndef __LA_INT64_T 60 #define __LA_INT64_T int64_t 61 #endif 62 #endif 63 64 65 /** 66 * Callback for libarchive for 'skipping'. 67 * 68 * @param a archive handle 69 * @param client_data our 'struct EXTRACTOR_ExtractContext' 70 * @param request number of bytes to skip 71 * @return number of bytes skipped 72 */ 73 static __LA_INT64_T 74 skip_cb (struct archive *a, 75 void *client_data, 76 __LA_INT64_T request) 77 { 78 struct EXTRACTOR_ExtractContext *ec = client_data; 79 80 if (-1 == ec->seek (ec->cls, request, SEEK_CUR)) 81 return 0; 82 return request; 83 } 84 85 86 /** 87 * Main entry method for the ARCHIVE extraction plugin. 88 * 89 * @param ec extraction context provided to the plugin 90 */ 91 void 92 EXTRACTOR_archive_extract_method (struct EXTRACTOR_ExtractContext *ec); 93 94 void 95 EXTRACTOR_archive_extract_method (struct EXTRACTOR_ExtractContext *ec) 96 { 97 struct archive *a; 98 struct archive_entry *entry; 99 const char *fname; 100 const char *s; 101 char *format; 102 103 format = NULL; 104 a = archive_read_new (); 105 #if ARCHIVE_VERSION_NUMBER >= 3000000 106 archive_read_support_filter_all (a); 107 #else 108 archive_read_support_compression_all (a); 109 #endif 110 archive_read_support_format_all (a); 111 if (archive_read_open2 (a, ec, NULL, &read_cb, &skip_cb, NULL)!= ARCHIVE_OK) 112 return; 113 114 while (ARCHIVE_OK == archive_read_next_header (a, &entry)) 115 { 116 if ( (NULL == format) && 117 (NULL != (fname = archive_format_name (a))) ) 118 format = strdup (fname); 119 s = archive_entry_pathname (entry); 120 if (0 != ec->proc (ec->cls, 121 "tar", 122 EXTRACTOR_METATYPE_FILENAME, 123 EXTRACTOR_METAFORMAT_UTF8, 124 "text/plain", 125 s, strlen (s) + 1)) 126 break; 127 } 128 #if ARCHIVE_VERSION_NUMBER >= 3000000 129 archive_read_free (a); 130 #else 131 archive_read_finish (a); 132 #endif 133 if (NULL != format) 134 { 135 if (0 != ec->proc (ec->cls, 136 "tar", 137 EXTRACTOR_METATYPE_FORMAT, 138 EXTRACTOR_METAFORMAT_UTF8, 139 "text/plain", format, strlen (format) + 1)) 140 { 141 free (format); 142 return; 143 } 144 free (format); 145 } 146 } 147 148 149 /* end of tar_extractor.c */