ftwin 0.8.10
ft_archive.c
Go to the documentation of this file.
1
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
42static const size_t ARCHIVE_BLOCK_SIZE = 10240;
43
44static int copy_data(struct archive *archive_read, struct archive *archive_write)
45{
46 const void *buff = NULL;
47 off_t offset = 0;
48 size_t size = 0;
49
50 for (;;) {
51 int result_value = archive_read_data_block(archive_read, &buff, &size, &offset);
52 if (result_value == ARCHIVE_EOF) {
53 return ARCHIVE_OK;
54 }
55 if (result_value != ARCHIVE_OK) {
56 DEBUG_ERR("error calling archive_read_data_block(): %s", archive_error_string(archive_read));
57 return result_value;
58 }
59 result_value = (int) archive_write_data_block(archive_write, buff, size, offset);
60 if (result_value != ARCHIVE_OK) {
61 DEBUG_ERR("error calling archive_write_data_block(): %s", archive_error_string(archive_write));
62 return result_value;
63 }
64 }
65}
66
67char *ft_archive_untar_file(ft_file_t *file, apr_pool_t *pool)
68{
69 struct archive *archive_handle = NULL;
70 struct archive *ext = NULL;
71 struct archive_entry *entry = NULL;
72 char *tmpfile = NULL;
73 int result_value = 0;
74
75 archive_handle = archive_read_new();
76 if (NULL == archive_handle) {
77 DEBUG_ERR("error calling archive_read_new()");
78 return NULL;
79 }
80 result_value = archive_read_support_filter_all(archive_handle);
81 if (0 != result_value) {
82 DEBUG_ERR("error calling archive_read_support_filter_all(): %s", archive_error_string(archive_handle));
83 return NULL;
84 }
85 result_value = archive_read_support_format_all(archive_handle);
86 if (0 != result_value) {
87 DEBUG_ERR("error calling archive_read_support_format_all(): %s", archive_error_string(archive_handle));
88 return NULL;
89 }
90 result_value = archive_read_open_filename(archive_handle, file->path, ARCHIVE_BLOCK_SIZE);
91 if (0 != result_value) {
92 DEBUG_ERR("error calling archive_read_open_filename(%s): %s", file->path, archive_error_string(archive_handle));
93 return NULL;
94 }
95
96 ext = archive_write_disk_new();
97 if (NULL == ext) {
98 DEBUG_ERR("error calling archive_write_disk_new()");
99 return NULL;
100 }
101
102 for (;;) {
103 result_value = archive_read_next_header(archive_handle, &entry);
104 if (result_value == ARCHIVE_EOF) {
105 DEBUG_ERR("subpath [%s] not found in archive [%s]", file->subpath, file->path);
106 return NULL;
107 }
108 if (result_value != ARCHIVE_OK) {
109 DEBUG_ERR("error in archive (%s): %s", file->path, archive_error_string(archive_handle));
110 return NULL;
111 }
112
113 if (!strcmp(file->subpath, archive_entry_pathname(entry))) {
114 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 tmpfile = apr_pstrdup(pool, "/tmp/ftwinXXXXXX");
122 result_value = mkstemp(tmpfile);
123 if (result_value < 0) {
124 DEBUG_ERR("error creating tmpfile %s", tmpfile);
125 return NULL;
126 }
127 umask(current_mode);
128 close(result_value);
129
130 archive_entry_copy_pathname(entry, tmpfile);
131
132 result_value = archive_write_header(ext, entry);
133 if (result_value == ARCHIVE_OK) {
134 result_value = copy_data(archive_handle, ext);
135 if (result_value != ARCHIVE_OK) {
136 DEBUG_ERR("error while copying data from archive (%s)", file->path);
137 (void) apr_file_remove(tmpfile, pool);
138 return NULL;
139 }
140 }
141 else {
142 DEBUG_ERR("error in archive (%s): %s", file->path, archive_error_string(archive_handle));
143 (void) apr_file_remove(tmpfile, pool);
144 return NULL;
145 }
146
147 break;
148 }
149 }
150
151 archive_write_free(ext);
152 archive_read_free(archive_handle);
153
154 return tmpfile;
155}
UTIL debug output macros.
#define DEBUG_ERR(str, arg...)
Display error message at the level error.
Definition debug.h:31
static const size_t ARCHIVE_BLOCK_SIZE
The block size for archive operations.
Definition ft_archive.c:42