archive_extractor.c (3816B)
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 struct archive *a; 95 struct archive_entry *entry; 96 const char *fname; 97 const char *s; 98 char *format; 99 100 format = NULL; 101 a = archive_read_new (); 102 #if ARCHIVE_VERSION_NUMBER >= 3000000 103 archive_read_support_filter_all (a); 104 #else 105 archive_read_support_compression_all (a); 106 #endif 107 archive_read_support_format_all (a); 108 if (archive_read_open2 (a, ec, NULL, &read_cb, &skip_cb, NULL)!= ARCHIVE_OK) 109 return; 110 111 while (ARCHIVE_OK == archive_read_next_header (a, &entry)) 112 { 113 if ( (NULL == format) && 114 (NULL != (fname = archive_format_name (a))) ) 115 format = strdup (fname); 116 s = archive_entry_pathname (entry); 117 if (0 != ec->proc (ec->cls, 118 "tar", 119 EXTRACTOR_METATYPE_FILENAME, 120 EXTRACTOR_METAFORMAT_UTF8, 121 "text/plain", 122 s, strlen (s) + 1)) 123 break; 124 } 125 #if ARCHIVE_VERSION_NUMBER >= 3000000 126 archive_read_free (a); 127 #else 128 archive_read_finish (a); 129 #endif 130 if (NULL != format) 131 { 132 if (0 != ec->proc (ec->cls, 133 "tar", 134 EXTRACTOR_METATYPE_FORMAT, 135 EXTRACTOR_METAFORMAT_UTF8, 136 "text/plain", format, strlen (format) + 1)) 137 { 138 free (format); 139 return; 140 } 141 free (format); 142 } 143 } 144 145 146 /* end of tar_extractor.c */