~ubuntu-branches/ubuntu/maverick/libtorrent-rasterbar/maverick

« back to all changes in this revision

Viewing changes to src/create_torrent.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christophe Sauthier
  • Date: 2010-08-10 12:59:37 UTC
  • mfrom: (1.3.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20100810125937-jbcmmf17y8yo9hgz
Tags: 0.15.0-0ubuntu1
* New upstream version.
* debian/patches/100_fix_html_docs.patch: refreshed.
* debian/control: bump up standards-version to 3.9.1 (no changes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
#include "libtorrent/create_torrent.hpp"
34
34
#include "libtorrent/file_pool.hpp"
35
35
#include "libtorrent/storage.hpp"
 
36
#include "libtorrent/escape_string.hpp"
36
37
 
37
 
#include <boost/date_time/posix_time/posix_time.hpp>
38
 
#include <boost/date_time/gregorian/gregorian.hpp>
 
38
#include <boost/date_time/posix_time/posix_time_types.hpp>
 
39
#include <boost/date_time/gregorian/greg_date.hpp>
39
40
#include <boost/bind.hpp>
 
41
#include <boost/next_prior.hpp>
 
42
 
 
43
#include <sys/types.h>
 
44
#include <sys/stat.h>
 
45
 
 
46
#define MAX_SYMLINK_PATH 200
40
47
 
41
48
namespace gr = boost::gregorian;
42
49
 
43
50
namespace libtorrent
44
51
{
45
 
        create_torrent::create_torrent(file_storage& fs, int size)
 
52
        // defined in torrent_info.cpp
 
53
        int merkle_num_leafs(int);
 
54
        int merkle_num_nodes(int);
 
55
        int merkle_get_parent(int);
 
56
        int merkle_get_sibling(int);
 
57
 
 
58
        namespace detail
 
59
        {
 
60
                int TORRENT_EXPORT get_file_attributes(boost::filesystem::path const& p)
 
61
                {
 
62
#ifdef TORRENT_WINDOWS
 
63
 
 
64
#if TORRENT_USE_WPATH
 
65
                        std::wstring path = convert_to_wstring(p.external_file_string());
 
66
                        DWORD attr = GetFileAttributesW(path.c_str());
 
67
#else
 
68
                        std::string path = convert_to_native(p.external_file_string());
 
69
                        DWORD attr = GetFileAttributesA(path.c_str());
 
70
#endif
 
71
                        if (attr & FILE_ATTRIBUTE_HIDDEN) return file_storage::attribute_hidden;
 
72
                        return 0;
 
73
#else
 
74
                        struct stat s;
 
75
                        if (lstat(convert_to_native(p.external_file_string()).c_str(), &s) < 0) return 0;
 
76
                        int file_attr = 0;
 
77
                        if (s.st_mode & S_IXUSR) 
 
78
                                file_attr += file_storage::attribute_executable;
 
79
                        if(S_ISLNK(s.st_mode))
 
80
                                file_attr += file_storage::attribute_symlink;
 
81
                        return file_attr;
 
82
#endif
 
83
                }
 
84
        
 
85
#if TORRENT_USE_WPATH
 
86
                int TORRENT_EXPORT get_file_attributes(boost::filesystem::wpath const& p)
 
87
                {
 
88
#ifdef TORRENT_WINDOWS
 
89
                        std::wstring const& path = p.external_file_string();
 
90
                        DWORD attr = GetFileAttributesW(path.c_str());
 
91
                        if (attr & FILE_ATTRIBUTE_HIDDEN) return file_storage::attribute_hidden;
 
92
                        return 0;
 
93
#else
 
94
                        std::string native;
 
95
                        wchar_utf8(p.string(), native);
 
96
                        native = convert_to_native(native);
 
97
 
 
98
                        struct stat s;
 
99
                        if (lstat(native.c_str(), &s) < 0) return 0;
 
100
                        int file_attr = 0;
 
101
                        if (s.st_mode & S_IXUSR) 
 
102
                                file_attr += file_storage::attribute_executable;
 
103
                        if (S_ISLNK(s.st_mode))
 
104
                                file_attr += file_storage::attribute_symlink;
 
105
                        return file_attr;
 
106
#endif
 
107
                }
 
108
#endif // TORRENT_USE_WPATH
 
109
 
 
110
                std::time_t get_file_mtime(char const* path)
 
111
                {
 
112
#ifdef TORRENT_WINDOWS
 
113
                        struct _stat s;
 
114
                        if (::_stat(path, &s) < 0) return 0;
 
115
#else
 
116
                        struct stat s;
 
117
                        if (lstat(path, &s) < 0) return 0;
 
118
#endif
 
119
                        return s.st_mtime;
 
120
                }
 
121
 
 
122
                std::time_t TORRENT_EXPORT get_file_mtime(boost::filesystem::path const& p)
 
123
                {
 
124
#if defined TORRENT_WINDOWS && TORRENT_USE_WPATH
 
125
                        std::wstring path = convert_to_wstring(p.external_file_string());
 
126
                        struct _stat s;
 
127
                        if (::_wstat(path.c_str(), &s) < 0) return 0;
 
128
                        return s.st_mtime;
 
129
#else
 
130
                        std::string path = convert_to_native(p.external_file_string());
 
131
                        return get_file_mtime(p.string().c_str());
 
132
#endif
 
133
                }
 
134
 
 
135
#if TORRENT_USE_WPATH
 
136
                std::time_t TORRENT_EXPORT get_file_mtime(boost::filesystem::wpath const& p)
 
137
                {
 
138
#ifdef TORRENT_WINDOWS
 
139
                        struct _stat s;
 
140
                        if (::_wstat(p.string().c_str(), &s) < 0) return 0;
 
141
                        return s.st_mtime;
 
142
#else
 
143
                        std::string utf8;
 
144
                        wchar_utf8(p.string(), utf8);
 
145
                        utf8 = convert_to_native(utf8);
 
146
                        return get_file_mtime(utf8.c_str());
 
147
#endif
 
148
                }
 
149
#endif // TORRENT_USE_WPATH
 
150
 
 
151
#ifndef TORRENT_WINDOWS
 
152
                boost::filesystem::path get_symlink_path_impl(char const* path)
 
153
                {
 
154
                        char buf[MAX_SYMLINK_PATH];
 
155
                        int char_read = readlink(path,buf,MAX_SYMLINK_PATH);
 
156
                        if (char_read < 0) return "";
 
157
                        if (char_read < MAX_SYMLINK_PATH) buf[char_read] = 0;
 
158
                        else buf[0] = 0;
 
159
                        return buf;
 
160
                }
 
161
#endif
 
162
 
 
163
                boost::filesystem::path TORRENT_EXPORT get_symlink_path(boost::filesystem::path const& p)
 
164
                {
 
165
#if defined TORRENT_WINDOWS
 
166
                        return "";
 
167
#else
 
168
                        std::string path = convert_to_native(p.external_file_string());
 
169
                        return get_symlink_path_impl(p.string().c_str());
 
170
#endif
 
171
                }
 
172
 
 
173
#if TORRENT_USE_WPATH
 
174
                boost::filesystem::path TORRENT_EXPORT get_symlink_path(boost::filesystem::wpath const& p)
 
175
                {
 
176
#ifdef TORRENT_WINDOWS
 
177
                        return "";
 
178
#else
 
179
                        std::string utf8;
 
180
                        wchar_utf8(p.string(), utf8);
 
181
                        utf8 = convert_to_native(utf8);
 
182
                        return get_symlink_path_impl(utf8.c_str());
 
183
#endif
 
184
                }
 
185
#endif // TORRENT_USE_WPATH
 
186
 
 
187
        }
 
188
 
 
189
        create_torrent::create_torrent(file_storage& fs, int piece_size, int pad_file_limit, int flags)
46
190
                : m_files(fs)
47
191
                , m_creation_date(pt::second_clock::universal_time())
48
192
                , m_multifile(fs.num_files() > 1)
49
193
                , m_private(false)
 
194
                , m_merkle_torrent(flags & merkle)
 
195
                , m_include_mtime(flags & modification_time)
 
196
                , m_include_symlinks(flags & symlinks)
50
197
        {
51
198
                TORRENT_ASSERT(fs.num_files() > 0);
52
199
 
59
206
                if (!m_multifile && m_files.at(0).path.has_parent_path()) m_multifile = true;
60
207
#endif
61
208
 
 
209
                // a piece_size of 0 means automatic
 
210
                if (piece_size == 0 && !m_merkle_torrent)
 
211
                {
 
212
                        const int target_size = 40 * 1024;
 
213
                        piece_size = fs.total_size() / (target_size / 20);
 
214
        
 
215
                        int i = 16*1024;
 
216
                        for (; i < 2*1024*1024; i *= 2)
 
217
                        {
 
218
                                if (piece_size > i) continue;
 
219
                                break;
 
220
                        }
 
221
                        piece_size = i;
 
222
                }
 
223
                else if (piece_size == 0 && m_merkle_torrent)
 
224
                {
 
225
                        piece_size = 64*1024;
 
226
                }
 
227
 
62
228
                // make sure the size is an even power of 2
63
229
#ifndef NDEBUG
64
230
                for (int i = 0; i < 32; ++i)
65
231
                {
66
 
                        if (size & (1 << i))
 
232
                        if (piece_size & (1 << i))
67
233
                        {
68
 
                                TORRENT_ASSERT((size & ~(1 << i)) == 0);
 
234
                                TORRENT_ASSERT((piece_size & ~(1 << i)) == 0);
69
235
                                break;
70
236
                        }
71
237
                }
72
238
#endif
73
 
                m_files.set_piece_length(size);
 
239
                m_files.set_piece_length(piece_size);
 
240
                if (flags & optimize)
 
241
                        m_files.optimize(pad_file_limit);
74
242
                m_files.set_num_pieces(static_cast<int>(
75
243
                        (m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
76
244
                m_piece_hash.resize(m_files.num_pieces());
77
245
        }
78
246
 
79
 
        create_torrent::create_torrent(file_storage& fs)
80
 
                : m_files(fs)
 
247
        create_torrent::create_torrent(torrent_info const& ti)
 
248
                : m_files(const_cast<file_storage&>(ti.files()))
81
249
                , m_creation_date(pt::second_clock::universal_time())
82
 
                , m_multifile(fs.num_files() > 1)
83
 
                , m_private(false)
 
250
                , m_multifile(ti.num_files() > 1)
 
251
                , m_private(ti.priv())
 
252
                , m_merkle_torrent(ti.is_merkle_torrent())
 
253
                , m_include_mtime(false)
 
254
                , m_include_symlinks(false)
84
255
        {
85
 
                TORRENT_ASSERT(fs.num_files() > 0);
86
 
 
87
 
                // return instead of crash in release mode
88
 
                if (fs.num_files() == 0) return;
89
 
 
90
 
#if BOOST_VERSION < 103600
91
 
                if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
92
 
#else
93
 
                if (!m_multifile && m_files.at(0).path.has_parent_path()) m_multifile = true;
94
 
#endif
95
 
 
96
 
                const int target_size = 40 * 1024;
97
 
                int size = fs.total_size() / (target_size / 20);
98
 
        
99
 
                for (int i = 4*1024*1024; i > 16*1024; i /= 2)
100
 
                {
101
 
                        if (size < i) continue;
102
 
                        size = i;
103
 
                        break;
104
 
                }
105
 
 
106
 
                m_files.set_piece_length(size);
107
 
                m_files.set_num_pieces(static_cast<int>(
108
 
                        (m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
 
256
                TORRENT_ASSERT(ti.is_valid());
 
257
                if (ti.creation_date()) m_creation_date = *ti.creation_date();
 
258
 
 
259
                if (!ti.creator().empty()) set_creator(ti.creator().c_str());
 
260
                if (!ti.comment().empty()) set_comment(ti.comment().c_str());
 
261
 
 
262
                torrent_info::nodes_t const& nodes = ti.nodes();
 
263
                for (torrent_info::nodes_t::const_iterator i = nodes.begin()
 
264
                        , end(nodes.end()); i != end; ++i)
 
265
                        add_node(*i);
 
266
 
 
267
                std::vector<libtorrent::announce_entry> const& trackers = ti.trackers();
 
268
                for (std::vector<libtorrent::announce_entry>::const_iterator i = trackers.begin()
 
269
                        , end(trackers.end()); i != end; ++i)
 
270
                        add_tracker(i->url, i->tier);
 
271
 
 
272
                std::vector<std::string> const& web_seeds = ti.url_seeds();
 
273
                for (std::vector<std::string>::const_iterator i = web_seeds.begin()
 
274
                        , end(web_seeds.end()); i != end; ++i)
 
275
                        add_url_seed(*i);
 
276
 
109
277
                m_piece_hash.resize(m_files.num_pieces());
 
278
                for (int i = 0; i < num_pieces(); ++i) set_hash(i, ti.hash_for_piece(i));
 
279
 
 
280
                m_info_dict = bdecode(&ti.metadata()[0], &ti.metadata()[0] + ti.metadata_size());
 
281
                m_info_hash = ti.info_hash();
110
282
        }
111
283
 
112
284
        entry create_torrent::generate() const
113
285
        {
114
286
                TORRENT_ASSERT(m_files.piece_length() > 0);
115
287
 
 
288
                entry dict;
 
289
 
116
290
                if (m_files.num_files() == 0)
117
 
                {
118
 
                        // TODO: throw something here
119
 
                        // throw
120
 
                        return entry();
121
 
                }
122
 
 
123
 
                entry dict;
 
291
                        return dict;
124
292
 
125
293
                if (!m_urls.empty()) dict["announce"] = m_urls.front().first;
126
294
                
185
353
                }
186
354
 
187
355
                entry& info = dict["info"];
 
356
                if (m_info_dict.type() == entry::dictionary_t)
 
357
                {
 
358
                        info = m_info_dict;
 
359
                        return dict;
 
360
                }
 
361
 
188
362
                info["name"] = m_files.name();
189
363
 
190
364
                if (m_private) info["private"] = 1;
191
365
 
192
366
                if (!m_multifile)
193
367
                {
 
368
                        if (m_include_mtime) info["mtime"] = m_files.at(0).mtime;
194
369
                        info["length"] = m_files.at(0).size;
 
370
                        if (m_files.at(0).pad_file || m_files.at(0).hidden_attribute || m_files.at(0).executable_attribute || m_files.at(0).symlink_attribute)
 
371
                        {
 
372
                                std::string& attr = info["attr"].string();
 
373
                                if (m_files.at(0).pad_file) attr += 'p';
 
374
                                if (m_files.at(0).hidden_attribute) attr += 'h';
 
375
                                if (m_files.at(0).executable_attribute) attr += 'x';
 
376
                                if (m_include_symlinks && m_files.at(0).symlink_attribute) attr += 'l';
 
377
                        }
 
378
                        if (m_include_symlinks && m_files.at(0).symlink_attribute)
 
379
                        {
 
380
                                entry& sympath_e = info["symlink path"];
 
381
                                
 
382
                                for (fs::path::iterator j = (m_files.at(0).symlink_path.begin());
 
383
                                        j != m_files.at(0).symlink_path.end(); ++j)
 
384
                                {
 
385
                                        sympath_e.list().push_back(entry(*j));
 
386
                                }
 
387
                        }
195
388
                }
196
389
                else
197
390
                {
204
397
                                {
205
398
                                        files.list().push_back(entry());
206
399
                                        entry& file_e = files.list().back();
 
400
                                        if (m_include_mtime) file_e["mtime"] = i->mtime; 
207
401
                                        file_e["length"] = i->size;
208
402
                                        entry& path_e = file_e["path"];
209
403
 
219
413
                                        {
220
414
                                                path_e.list().push_back(entry(*j));
221
415
                                        }
 
416
                                        if (i->pad_file || i->hidden_attribute || i->executable_attribute || i->symlink_attribute)
 
417
                                        {
 
418
                                                std::string& attr = file_e["attr"].string();
 
419
                                                if (i->pad_file) attr += 'p';
 
420
                                                if (i->hidden_attribute) attr += 'h';
 
421
                                                if (i->executable_attribute) attr += 'x';
 
422
                                                if (m_include_symlinks && i->symlink_attribute) attr += 'l';
 
423
                                        }
 
424
                                        if (m_include_symlinks && i->symlink_attribute)
 
425
                                        {
 
426
                                                entry& sympath_e = file_e["symlink path"];
 
427
 
 
428
                                                for (fs::path::iterator j = (i->symlink_path.begin());
 
429
                                                        j != i->symlink_path.end(); ++j)
 
430
                                                {
 
431
                                                        sympath_e.list().push_back(entry(*j));
 
432
                                                }
 
433
                                        }
222
434
                                }
223
435
                        }
224
436
                }
225
437
 
226
438
                info["piece length"] = m_files.piece_length();
227
 
                entry& pieces = info["pieces"];
228
 
 
229
 
                std::string& p = pieces.string();
230
 
 
231
 
                for (std::vector<sha1_hash>::const_iterator i = m_piece_hash.begin();
232
 
                        i != m_piece_hash.end(); ++i)
233
 
                {
234
 
                        p.append((char*)i->begin(), (char*)i->end());
 
439
                if (m_merkle_torrent)
 
440
                {
 
441
                        std::vector<sha1_hash> merkle_tree;
 
442
                        
 
443
                        int num_leafs = merkle_num_leafs(m_files.num_pieces());
 
444
                        int num_nodes = merkle_num_nodes(num_leafs);
 
445
                        int first_leaf = num_nodes - num_leafs;
 
446
                        merkle_tree.resize(num_nodes);
 
447
                        int num_pieces = m_piece_hash.size();
 
448
                        for (int i = 0; i < num_pieces; ++i)
 
449
                                merkle_tree[first_leaf + i] = m_piece_hash[i];
 
450
                        sha1_hash filler(0);
 
451
                        for (int i = num_pieces; i < num_leafs; ++i)
 
452
                                merkle_tree[first_leaf + i] = filler;
 
453
 
 
454
                        // now that we have initialized all leaves, build
 
455
                        // each level bottom-up
 
456
                        int level_start = first_leaf;
 
457
                        int level_size = num_leafs;
 
458
                        while (level_start > 0)
 
459
                        {
 
460
                                int parent = merkle_get_parent(level_start);
 
461
                                for (int i = level_start; i < level_start + level_size; i += 2, ++parent)
 
462
                                {
 
463
                                        hasher h;
 
464
                                        h.update((char const*)&merkle_tree[i][0], 20);
 
465
                                        h.update((char const*)&merkle_tree[i+1][0], 20);
 
466
                                        merkle_tree[parent] = h.final();
 
467
                                }
 
468
                                level_start = merkle_get_parent(level_start);
 
469
                                level_size /= 2;
 
470
                        }
 
471
                        TORRENT_ASSERT(level_size == 1);
 
472
                        std::string& p = info["root hash"].string();
 
473
                        p.assign((char const*)&merkle_tree[0][0], 20);
 
474
                }
 
475
                else
 
476
                {
 
477
                        std::string& p = info["pieces"].string();
 
478
 
 
479
                        for (std::vector<sha1_hash>::const_iterator i = m_piece_hash.begin();
 
480
                                i != m_piece_hash.end(); ++i)
 
481
                        {
 
482
                                p.append((char*)i->begin(), sha1_hash::size);
 
483
                        }
235
484
                }
236
485
 
237
486
                std::vector<char> buf;