Line data Source code
1 : /**
2 : * @file ft_archive.c
3 : * @brief Archive handling functions for extracting files from archives.
4 : * @ingroup Archive
5 : */
6 : /*
7 : * Copyright (C) 2007 François Pesce : francois.pesce (at) gmail (dot) com
8 : *
9 : * Licensed under the Apache License, Version 2.0 (the "License");
10 : * you may not use this file except in compliance with the License.
11 : * You may obtain a copy of the License at
12 : *
13 : * http://www.apache.org/licenses/LICENSE-2.0
14 : *
15 : * Unless required by applicable law or agreed to in writing, software
16 : * distributed under the License is distributed on an "AS IS" BASIS,
17 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 : * See the License for the specific language governing permissions and
19 : * limitations under the License.
20 : */
21 :
22 : #include "ft_archive.h"
23 :
24 : #include <sys/stat.h>
25 : #include <unistd.h>
26 :
27 : #include <apr_file_io.h>
28 : #include <apr_strings.h>
29 :
30 : #include "config.h"
31 : #include "debug.h"
32 :
33 : #include <archive.h>
34 : #include <archive_entry.h>
35 :
36 : /**
37 : * @brief The block size for archive operations.
38 : *
39 : * This constant defines the block size (in bytes) used for reading from
40 : * and writing to archives.
41 : */
42 : static const size_t ARCHIVE_BLOCK_SIZE = 10240;
43 :
44 0 : static int copy_data(struct archive *archive_read, struct archive *archive_write)
45 : {
46 0 : const void *buff = NULL;
47 0 : off_t offset = 0;
48 0 : size_t size = 0;
49 :
50 0 : for (;;) {
51 0 : int result_value = archive_read_data_block(archive_read, &buff, &size, &offset);
52 0 : if (result_value == ARCHIVE_EOF) {
53 0 : return ARCHIVE_OK;
54 : }
55 0 : if (result_value != ARCHIVE_OK) {
56 0 : DEBUG_ERR("error calling archive_read_data_block(): %s", archive_error_string(archive_read));
57 0 : return result_value;
58 : }
59 0 : result_value = (int) archive_write_data_block(archive_write, buff, size, offset);
60 0 : if (result_value != ARCHIVE_OK) {
61 0 : DEBUG_ERR("error calling archive_write_data_block(): %s", archive_error_string(archive_write));
62 0 : return result_value;
63 : }
64 : }
65 : }
66 :
67 0 : char *ft_archive_untar_file(ft_file_t *file, apr_pool_t *pool)
68 : {
69 0 : struct archive *archive_handle = NULL;
70 0 : struct archive *ext = NULL;
71 0 : struct archive_entry *entry = NULL;
72 0 : char *tmpfile = NULL;
73 0 : int result_value = 0;
74 :
75 0 : archive_handle = archive_read_new();
76 0 : if (NULL == archive_handle) {
77 0 : DEBUG_ERR("error calling archive_read_new()");
78 0 : return NULL;
79 : }
80 0 : result_value = archive_read_support_filter_all(archive_handle);
81 0 : if (0 != result_value) {
82 0 : DEBUG_ERR("error calling archive_read_support_filter_all(): %s", archive_error_string(archive_handle));
83 0 : return NULL;
84 : }
85 0 : result_value = archive_read_support_format_all(archive_handle);
86 0 : if (0 != result_value) {
87 0 : DEBUG_ERR("error calling archive_read_support_format_all(): %s", archive_error_string(archive_handle));
88 0 : return NULL;
89 : }
90 0 : result_value = archive_read_open_filename(archive_handle, file->path, ARCHIVE_BLOCK_SIZE);
91 0 : if (0 != result_value) {
92 0 : DEBUG_ERR("error calling archive_read_open_filename(%s): %s", file->path, archive_error_string(archive_handle));
93 0 : return NULL;
94 : }
95 :
96 0 : ext = archive_write_disk_new();
97 0 : if (NULL == ext) {
98 0 : DEBUG_ERR("error calling archive_write_disk_new()");
99 0 : return NULL;
100 : }
101 :
102 : for (;;) {
103 0 : result_value = archive_read_next_header(archive_handle, &entry);
104 0 : if (result_value == ARCHIVE_EOF) {
105 0 : DEBUG_ERR("subpath [%s] not found in archive [%s]", file->subpath, file->path);
106 0 : return NULL;
107 : }
108 0 : if (result_value != ARCHIVE_OK) {
109 0 : DEBUG_ERR("error in archive (%s): %s", file->path, archive_error_string(archive_handle));
110 0 : return NULL;
111 : }
112 :
113 0 : if (!strcmp(file->subpath, archive_entry_pathname(entry))) {
114 0 : mode_t current_mode = umask(S_IRWXG | S_IRWXO);
115 :
116 : /*
117 : * All I want is only a temporary filename, but gcc outputs me an
118 : * ugly warning if I use tempnam...
119 : * tmpfile = tempnam("/tmp/", "ftwin");
120 : */
121 0 : tmpfile = apr_pstrdup(pool, "/tmp/ftwinXXXXXX");
122 0 : result_value = mkstemp(tmpfile);
123 0 : if (result_value < 0) {
124 0 : DEBUG_ERR("error creating tmpfile %s", tmpfile);
125 0 : return NULL;
126 : }
127 0 : umask(current_mode);
128 0 : close(result_value);
129 :
130 0 : archive_entry_copy_pathname(entry, tmpfile);
131 :
132 0 : result_value = archive_write_header(ext, entry);
133 0 : if (result_value == ARCHIVE_OK) {
134 0 : result_value = copy_data(archive_handle, ext);
135 0 : if (result_value != ARCHIVE_OK) {
136 0 : DEBUG_ERR("error while copying data from archive (%s)", file->path);
137 0 : (void) apr_file_remove(tmpfile, pool);
138 0 : return NULL;
139 : }
140 : }
141 : else {
142 0 : DEBUG_ERR("error in archive (%s): %s", file->path, archive_error_string(archive_handle));
143 0 : (void) apr_file_remove(tmpfile, pool);
144 0 : return NULL;
145 : }
146 :
147 0 : break;
148 : }
149 : }
150 :
151 0 : archive_write_free(ext);
152 0 : archive_read_free(archive_handle);
153 :
154 0 : return tmpfile;
155 : }
|