forked from RPCS3/rpcs3
-
Notifications
You must be signed in to change notification settings - Fork 3
/
TAR.cpp
134 lines (114 loc) · 2.99 KB
/
TAR.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
132
133
134
#include "stdafx.h"
#include "TAR.h"
#include <cmath>
#include <cstdlib>
LOG_CHANNEL(tar_log, "TAR");
tar_object::tar_object(const fs::file& file, size_t offset)
: m_file(file)
, initial_offset(static_cast<int>(offset))
{
m_file.seek(initial_offset);
largest_offset = initial_offset;
}
TARHeader tar_object::read_header(u64 offset)
{
m_file.seek(offset);
TARHeader header;
m_file.read(header);
return header;
}
int octalToDecimal(int octalNumber)
{
int decimalNumber = 0, i = 0, rem;
while (octalNumber != 0)
{
rem = octalNumber % 10;
octalNumber /= 10;
decimalNumber += rem * (1 << (i * 3));
++i;
}
return decimalNumber;
}
std::vector<std::string> tar_object::get_filenames()
{
std::vector<std::string> vec;
get_file("");
for (auto it = m_map.cbegin(); it != m_map.cend(); ++it)
{
vec.push_back(it->first);
}
return vec;
}
fs::file tar_object::get_file(std::string path)
{
if (!m_file) return fs::file();
auto it = m_map.find(path);
if (it != m_map.end())
{
TARHeader header = read_header(it->second);
int size = octalToDecimal(atoi(header.size));
std::vector<u8> buf(size);
m_file.read(buf, size);
int offset = ((m_file.pos() - initial_offset + 512 - 1) & ~(512 - 1)) + initial_offset; // Always keep the offset aligned to 512 bytes + the initial offset.
m_file.seek(offset);
return fs::make_stream(std::move(buf));
}
else //continue scanning from last file entered
{
while (m_file.pos() < m_file.size())
{
TARHeader header = read_header(largest_offset);
if (std::string(header.magic).find("ustar") != umax)
m_map[header.name] = largest_offset;
int size = octalToDecimal(atoi(header.size));
if (path == header.name) { //path is equal, read file and advance offset to start of next block
std::vector<u8> buf(size);
m_file.read(buf, size);
int offset = ((m_file.pos() - initial_offset + 512 - 1) & ~(512 - 1)) + initial_offset;
m_file.seek(offset);
largest_offset = offset;
return fs::make_stream(std::move(buf));
}
else { // just advance offset to next block
m_file.seek(size, fs::seek_mode::seek_cur);
int offset = ((m_file.pos() - initial_offset + 512 - 1) & ~(512 - 1)) + initial_offset;
m_file.seek(offset);
largest_offset = offset;
}
}
return fs::file();
}
}
bool tar_object::extract(std::string path, std::string ignore)
{
if (!m_file) return false;
get_file(""); //Make sure we have scanned all files
for (auto iter : m_map)
{
TARHeader header = read_header(iter.second);
if (!header.name[0]) continue;
std::string result = path + header.name;
if (result.compare(path.size(), ignore.size(), ignore) == 0)
{
result.erase(path.size(), ignore.size());
}
switch (header.filetype)
{
case '0':
{
fs::file file(result, fs::rewrite);
file.write(get_file(header.name).to_vector<u8>());
break;
}
case '5':
{
fs::create_dir(result);
break;
}
default:
tar_log.error("TAR Loader: unknown file type: 0x%x", header.filetype);
return false;
}
}
return true;
}