Develop and Download Open Source Software

Browse Subversion Repository

Contents of /hamigaki/trunk/libs/archivers/doc/tutorial.xml

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: application/xml
File size: 8189 byte(s)
fix for Zip Slip
1 <?xml version="1.0" encoding="utf-8"?>
2 <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
3 "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
4 <!--
5 Hamigaki.Archivers Library Document Source
6
7 Copyright Takeshi Mouri 2006-2018.
8 Distributed under the Boost Software License, Version 1.0.
9 (See accompanying file LICENSE_1_0.txt or copy at
10 http://www.boost.org/LICENSE_1_0.txt)
11
12 See http://hamigaki.sourceforge.jp/libs/archivers for library home page.
13 -->
14 <section id="archivers.tutorial">
15 <title>チュートリアル</title>
16 <using-namespace name="hamigaki::archivers"/>
17
18 <section id="archivers.tutorial.tar">
19 <title>tarファイルの作成</title>
20 <using-class name="hamigaki::archivers::basic_tar_file_sink"/>
21
22 <para>次のプログラムはファイル<filename>foo.txt</filename><filename>bar.txt</filename>を含むtarファイル<filename>test.tar</filename>を作成する。</para>
23
24 <programlisting><![CDATA[#include <hamigaki/archivers/tar_file.hpp>
25 #include <boost/filesystem/fstream.hpp>
26 #include <boost/filesystem/operations.hpp>
27 #include <boost/iostreams/copy.hpp>
28
29 namespace ar = hamigaki::archivers;
30 namespace fs = boost::filesystem;
31 namespace io = boost::iostreams;
32
33 void append_file(ar::tar_file_sink& tar, const fs::path& ph)
34 {
35 ar::tar::header head;
36 head.path = ph;
37 head.file_size = fs::file_size(ph);
38 tar.create_entry(head);
39
40 fs::ifstream file(ph, std::ios_base::binary);
41 io::copy(file, tar);
42 }
43
44 int main()
45 {
46 ar::tar_file_sink tar("test.tar");
47
48 append_file(tar, "foo.txt");
49 append_file(tar, "bar.txt");
50
51 tar.close_archive();
52 }
53 ]]></programlisting>
54
55 <para>tarファイルを作成するには、クラス<classname>tar_file_sink</classname>を用いる。コンストラクタの引数は、作成するtarファイルのパス名である。</para>
56
57 <para>アーカイブに追加する個々のファイルは(アーカイブ)エントリと呼ばれ、それぞれ個別のヘッダ情報を持つ。エントリを追加するには、適切な値を設定した構造体<classname alt="tar::basic_header">tar::header</classname>を引数にして、メンバ関数<methodname>create_entry</methodname>()を呼び出す。</para>
58
59 <para><classname alt="tar::basic_header">tar::header</classname>のメンバ変数の内、<code>path</code>(ファイルのパス名)と<code>file_size</code>(ファイルサイズ)は必須項目である。それ以外のメンバに関しては<link linkend="hamigaki.archivers.tar.header">ドキュメント</link>を参照せよ。</para>
60
61 <para><methodname>create_entry</methodname>()を呼び出すと、アーカイブは<conceptname>Sink</conceptname>として書き込み可能となる。</para>
62
63 <para>書き込みが完了したら、メンバ関数<methodname>close_archive</methodname>()でアーカイブを閉じる。アーカイブのフォーマットによっては、<methodname>close_archive</methodname>()の呼び出しを忘れると、フッタ情報のない不正なアーカイブができてしまうので注意すること。</para>
64
65 </section>
66
67 <section id="archivers.tutorial.untar">
68 <title>tarファイルの展開</title>
69 <using-class name="hamigaki::archivers::basic_tar_file_source"/>
70
71 <para>今度は、先ほど作成した<filename>test.tar</filename>をカレントディレクトリに展開するプログラムを作成する。</para>
72
73 <programlisting><![CDATA[#include <hamigaki/archivers/tar_file.hpp>
74 #include <boost/filesystem/fstream.hpp>
75 #include <boost/iostreams/copy.hpp>
76
77 namespace ar = hamigaki::archivers;
78 namespace fs = boost::filesystem;
79 namespace io = boost::iostreams;
80
81 bool is_valid_path(const fs::path& ph)
82 {
83 if (ph.has_root_name() || ph.has_root_directory())
84 return false;
85 for (typename Path::iterator it = ph.begin(); it != ph.end(); ++it)
86 {
87 if (*it == "..")
88 return false;
89 }
90 return true;
91 }
92
93 void extract_file(ar::tar_file_source& tar)
94 {
95 const ar::tar::header& head = tar.header();
96 if (!is_valid_path(head.path))
97 {
98 std::cerr << "Warning: skip invalid path: " << head.path.string() << std::endl;
99 }
100
101 fs::ofstream file(head.path, std::ios_base::binary);
102 io::copy(tar, file);
103 }
104
105 int main()
106 {
107 ar::tar_file_source tar("test.tar");
108
109 while (tar.next_entry())
110 extract_file(tar);
111 }
112 ]]></programlisting>
113
114 <para>tarファイルを読み込むには、クラス<classname>tar_file_source</classname>を用いる。コンストラクタの引数は、tarファイルのパス名である。</para>
115
116 <para>tarファイルのオープンに成功したら、メンバ関数<methodname>next_entry</methodname>()を呼び出し、次のエントリを確認する。この関数は未読のエントリがある場合<code>true</code>を返す。全てのエントリを読み終わり、これ以上のエントリが見つからない場合は<code>false</code>が返され、ループは終了する。</para>
117
118 <para><methodname>next_entry</methodname>()の呼び出しに成功したら、アーカイブは<conceptname>Source</conceptname>として読み出し可能である。また、メンバ関数<methodname>header</methodname>()を呼び出すことで、ヘッダ情報を取得することもできる。ここでは、ヘッダから取得したパス名と同名のファイルを作成し、エントリから読み出した内容を書き出している。特に意図していない限り、絶対パスやカレントディレクトリより上への相対パスを含むアーカイブは悪意のあるものである。ファイルシステムへ出力する前には必ずパス名を検証する必要がある。</para>
119 </section>
120
121 <section id="archivers.tutorial.zip">
122 <title>ZIPファイルの作成</title>
123 <using-class name="hamigaki::archivers::basic_zip_file_sink"/>
124
125 <para><xref linkend="archivers.tutorial.tar"/>のプログラムをZIPフォーマット用に書き換えると、次のようになる。</para>
126
127 <programlisting><![CDATA[#include <hamigaki/archivers/zip_file.hpp>
128 #include <boost/filesystem/fstream.hpp>
129 #include <boost/filesystem/operations.hpp>
130 #include <boost/iostreams/copy.hpp>
131
132 namespace ar = hamigaki::archivers;
133 namespace fs = boost::filesystem;
134 namespace io = boost::iostreams;
135
136 void append_file(ar::zip_file_sink& zip, const fs::path& ph)
137 {
138 ar::zip::header head;
139 head.path = ph;
140 head.file_size = fs::file_size(ph);
141 zip.create_entry(head);
142
143 fs::ifstream file(ph, std::ios_base::binary);
144 try
145 {
146 io::copy(file, zip);
147 }
148 catch (const ar::give_up_compression&)
149 {
150 file.clear();
151 file.seekg(0, std::ios_base::beg);
152 zip.rewind_entry();
153 io::copy(file, zip);
154 }
155 }
156
157 int main()
158 {
159 ar::zip_file_sink zip("test.zip");
160
161 append_file(zip, "foo.txt");
162 append_file(zip, "bar.txt");
163
164 zip.close_archive();
165 }
166 ]]></programlisting>
167
168 <para>ZIPファイルを作成するには、クラス<classname>zip_file_sink</classname>を用いる。コンストラクタの引数は、やはり、作成するzipファイルのパス名である。</para>
169
170 <para>ZIPフォーマットはtarフォーマットのようなアーカイバの機能に加え、ファイルを圧縮する機能を持っている。圧縮率はファイルの内容によって変化し、場合によっては元のサイズより大きくなってしまうこともある。Hamigaki.Archiversでは例外<classname>give_up_compression</classname>を送出することで、この状況を報告する。</para>
171
172 <para><classname>give_up_compression</classname>が送出されたら、これを捕捉し、非圧縮で出力をやり直す必要がある。メンバ関数<methodname>rewind_entry</methodname>()はこのためのものであり、ファイルの書き込み位置をエントリの先頭に戻し、圧縮メソッドを非圧縮に設定する。<methodname>rewind_entry</methodname>()の呼び出しに成功したら、再度出力を試みることになる。</para>
173 </section>
174 </section>

Properties

Name Value
svn:eol-style native

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