-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathlibarchive_extract.cpp
131 lines (114 loc) · 4.4 KB
/
libarchive_extract.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "libarchive_extract.h"
#include <archive.h>
#include <archive_entry.h>
#include <iostream>
#include <filesystem>
#include "Logger.h"
// from: https://github.com/libarchive/libarchive/wiki/Examples#user-content-A_Complete_Extractor
using namespace std::filesystem;
namespace Utils
{
int copy_data(struct archive* ar, struct archive* aw);
const bool SECURE_EXTRACTION = true;
const size_t BYTES_PER_KB = 1024UL;
const size_t READ_OPEN_BLOCK_SIZE = BYTES_PER_KB * 10UL;
bool extract(const char* filename, const char* destDir)
{
struct archive* a;
struct archive* ext;
struct archive_entry* entry;
int flags;
int r;
/* Select which attributes we want to restore. */
flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
if (SECURE_EXTRACTION)
{
flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS;
flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT;
//flags |= ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS;
}
a = archive_read_new();
archive_read_support_format_all(a);
archive_read_support_filter_all(a);
//archive_read_support_format_tar(a);
//archive_read_support_filter_gzip(a);
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, flags);
archive_write_disk_set_standard_lookup(ext);
r = archive_read_open_filename(a, filename, READ_OPEN_BLOCK_SIZE);
if (r != ARCHIVE_OK)
{
auto errNo = archive_errno(a);
fprintf(stderr, "%s (%d)\n", archive_error_string(a), errNo);
return false;
}
for (;;) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF)
break;
if (r < ARCHIVE_OK)
fprintf(stderr, "%s\n", archive_error_string(a));
if (r < ARCHIVE_WARN)
{
return false;
}
// prepend destPath to beginning of entry to extract it in the destination path
std::string entryPathname = archive_entry_pathname(entry);
std::filesystem::path entryDestinationPathname(destDir);
entryDestinationPathname /= entryPathname;
//auto relativeEntryDestinationPathname = relative(entryDestinationPathname, current_path());
logdebug("Extracting, destination dir: [" + std::string(destDir) + "]");
logdebug("Extracting, entry path name: [" + entryPathname + "]");
logdebug("Extracting, destination path name: [" + entryDestinationPathname.string() + "]");
//loginfo("Extracting, relative destination path name: [" + relativeEntryDestinationPathname.string() + "]");
archive_entry_set_pathname(entry, entryDestinationPathname.string().c_str());
r = archive_write_header(ext, entry);
if (r < ARCHIVE_OK)
fprintf(stderr, "archive_write_header failed: %s\n", archive_error_string(ext));
else if (archive_entry_size(entry) > 0) {
r = copy_data(a, ext);
if (r < ARCHIVE_OK)
fprintf(stderr, "%s\n", archive_error_string(ext));
if (r < ARCHIVE_WARN)
{
return false;
}
}
r = archive_write_finish_entry(ext);
if (r < ARCHIVE_OK)
fprintf(stderr, "%s\n", archive_error_string(ext));
if (r < ARCHIVE_WARN)
{
return false;
}
}
archive_read_close(a);
archive_read_free(a);
archive_write_close(ext);
archive_write_free(ext);
return true;
}
int copy_data(struct archive* ar, struct archive* aw)
{
int r;
const void* buff;
size_t size;
la_int64_t offset;
la_ssize_t written;
for (;;) {
r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF)
return (ARCHIVE_OK);
if (r < ARCHIVE_OK)
return (r);
written = archive_write_data_block(aw, buff, size, offset);
if (written < ARCHIVE_OK) {
fprintf(stderr, "%s\n", archive_error_string(aw));
return (r);
}
}
}
}