Develop and Download Open Source Software

Browse Subversion Repository

Contents of /hamigaki/trunk/libs/archivers/example/unlha.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1782 - (show annotations) (download) (as text)
Sun Jun 10 06:01:53 2018 UTC (5 years, 9 months ago) by hamigaki
File MIME type: text/x-c++src
File size: 4044 byte(s)
fix for Zip Slip
1 // unlha.cpp: a simple LZH decompressing program
2
3 // Copyright Takeshi Mouri 2006-2018.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7
8 // See http://hamigaki.sourceforge.jp/libs/archivers for library home page.
9
10
11 // Security warning:
12 // This program never check the validity of paths in the archive.
13 // See http://www.forest.impress.co.jp/article/2004/07/30/arcsecurity.html .
14 // (The above link is Japanese site)
15
16
17 #include <hamigaki/archivers/lzh_file.hpp>
18 #include <hamigaki/filesystem/operations.hpp>
19 #include <boost/filesystem/convenience.hpp>
20 #include <boost/iostreams/copy.hpp>
21 #include <clocale>
22 #include <exception>
23 #include <iostream>
24
25 namespace ar = hamigaki::archivers;
26 namespace fs_ex = hamigaki::filesystem;
27 namespace io_ex = hamigaki::iostreams;
28 namespace fs = boost::filesystem;
29 namespace io = boost::iostreams;
30
31 template<class Path>
32 inline bool has_parent_path(const Path& ph)
33 {
34 #if BOOST_VERSION < 103600
35 return ph.has_branch_path();
36 #else
37 return ph.has_parent_path();
38 #endif
39 }
40
41 template<class Path>
42 bool is_valid_path(const Path& ph)
43 {
44 #if !defined(HAMIGAKI_ALLOW_DIRECTORY_TRAVERSAL)
45 if (ph.has_root_name() || ph.has_root_directory())
46 return false;
47 for (typename Path::iterator it = ph.begin(); it != ph.end(); ++it)
48 {
49 if (*it == "..")
50 return false;
51 }
52 #endif
53 return true;
54 }
55
56 inline fs_ex::timestamp make_timestamp(boost::uint64_t ft)
57 {
58 return fs_ex::timestamp::from_windows_file_time(ft);
59 }
60
61 int main(int argc, char* argv[])
62 {
63 try
64 {
65 if (argc != 2)
66 {
67 std::cerr << "Usage: unlha (archive)" << std::endl;
68 return 1;
69 }
70
71 std::setlocale(LC_ALL, "");
72
73 ar::lzh_file_source lzh(argv[1]);
74
75 while (lzh.next_entry())
76 {
77 const ar::lha::header& head = lzh.header();
78
79 std::cout << head.path.string() << '\n';
80 if (!is_valid_path(head.path))
81 {
82 std::cerr << "Warning: invalid path" << '\n';
83 continue;
84 }
85
86 if (!head.link_path.empty())
87 {
88 if (::has_parent_path(head.path))
89 fs::create_directories(head.path.branch_path());
90
91 fs_ex::create_symlink(head.link_path, head.path);
92 }
93 else if (head.is_directory())
94 fs::create_directories(head.path);
95 else
96 {
97 if (::has_parent_path(head.path))
98 fs::create_directories(head.path.branch_path());
99
100 io::copy(
101 lzh,
102 io_ex::file_sink(
103 head.path.file_string(), std::ios_base::binary)
104 );
105 }
106
107 // Note:
108 // The POSIX chown() clears S_ISUID/S_ISGID bits.
109 // So, we must call change_symlink_owner()
110 // before calling change_permissions().
111 fs_ex::error_code ec;
112 if (head.owner)
113 {
114 fs_ex::change_symlink_owner(
115 head.path, head.owner->uid, head.owner->gid, ec);
116 }
117
118 fs_ex::change_attributes(head.path, head.attributes, ec);
119
120 if (head.permissions)
121 fs_ex::change_permissions(head.path, *(head.permissions), ec);
122
123 if (head.timestamp)
124 {
125 const ar::lha::windows::timestamp ts(head.timestamp.get());
126
127 fs_ex::last_write_time(
128 head.path, make_timestamp(ts.last_write_time));
129 fs_ex::last_access_time(
130 head.path, make_timestamp(ts.last_access_time));
131 fs_ex::creation_time(
132 head.path, make_timestamp(ts.creation_time));
133 }
134 }
135
136 return 0;
137 }
138 catch (const std::exception& e)
139 {
140 std::cerr << "Error: " << e.what() << std::endl;
141 }
142 return 1;
143 }

Properties

Name Value
svn:eol-style native

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26