📄 file_list.cc
字号:
if (chunkSize == 0) throw internal_error("FileList::initialize() chunk_size() == 0."); m_chunkSize = chunkSize; m_torrentSize = torrentSize; m_rootDir = "."; m_bitfield.set_size_bits((size_bytes() + chunk_size() - 1) / chunk_size()); File* newFile = new File(); newFile->set_offset(0); newFile->set_size_bytes(torrentSize); newFile->set_range(m_chunkSize); base_type::push_back(newFile);}struct file_list_cstr_less { bool operator () (const char* c1, const char* c2) const { return std::strcmp(c1, c2) < 0; }};voidFileList::open() { typedef std::set<const char*, file_list_cstr_less> path_set; if (m_rootDir.empty()) throw internal_error("FileList::open() m_rootDir.empty()."); m_indirectLinks.push_back(m_rootDir); Path lastPath; path_set pathSet; iterator itr = begin(); try { if (::mkdir(m_rootDir.c_str(), 0777) != 0 && errno != EEXIST) throw storage_error("Could not create directory '" + m_rootDir + "': " + strerror(errno)); while (itr != end()) { File* entry = *itr++; if (entry->is_open()) throw internal_error("FileList::open(...) found an already opened file."); // manager->file_manager()->insert(entry); // Update the path during open so that any changes to root dir // and file paths are properly handled. if (entry->path()->back().empty()) entry->set_frozen_path(std::string()); else entry->set_frozen_path(m_rootDir + entry->path()->as_string()); if (!pathSet.insert(entry->frozen_path().c_str()).second) throw storage_error("Found a duplicate filename."); if (entry->size_bytes() > m_maxFileSize) throw storage_error("Found a file exceeding max file size."); if (entry->path()->empty()) throw storage_error("Found an empty filename."); if (!open_file(&*entry, lastPath)) throw storage_error("Could not open file \"" + m_rootDir + entry->path()->as_string() + "\": " + rak::error_number::current().c_str()); lastPath = *entry->path(); } } catch (storage_error& e) { for (iterator cleanupItr = begin(); cleanupItr != itr; ++cleanupItr) manager->file_manager()->close(*cleanupItr); throw e; } m_isOpen = true;}voidFileList::close() { if (!is_open()) return; for (iterator itr = begin(), last = end(); itr != last; ++itr) { manager->file_manager()->close(*itr); // Keep the progress so the user can see it even though he closes // the torrent.// (*itr)->set_completed(0); } m_isOpen = false; m_indirectLinks.clear();}boolFileList::resize_all() { bool success = true; for (iterator itr = begin(); itr != end(); itr++) if (!(*itr)->frozen_path().empty() && !(*itr)->resize_file()) success = false; return success;}voidFileList::make_directory(Path::const_iterator pathBegin, Path::const_iterator pathEnd, Path::const_iterator startItr) { std::string path = m_rootDir; while (pathBegin != pathEnd) { path += "/" + *pathBegin; if (pathBegin++ != startItr) continue; startItr++; rak::file_stat fileStat; if (fileStat.update_link(path) && fileStat.is_link() && std::find(m_indirectLinks.begin(), m_indirectLinks.end(), path) == m_indirectLinks.end()) m_indirectLinks.push_back(path); if (pathBegin == pathEnd) break; if (::mkdir(path.c_str(), 0777) != 0 && errno != EEXIST) throw storage_error("Could not create directory '" + path + "': " + strerror(errno)); }}boolFileList::open_file(File* node, const Path& lastPath) { const Path* path = node->path(); Path::const_iterator lastItr = lastPath.begin(); Path::const_iterator firstMismatch = path->begin(); // Couldn't find a suitable stl algo, need to write my own. while (firstMismatch != path->end() && lastItr != lastPath.end() && *firstMismatch == *lastItr) { lastItr++; firstMismatch++; } rak::error_number::clear_global(); make_directory(path->begin(), path->end(), firstMismatch); // Some torrents indicate an empty directory by having a path with // an empty last element. This entry must be zero length. if (path->back().empty()) return node->size_bytes() == 0; rak::file_stat fileStat; if (fileStat.update(node->frozen_path()) && !fileStat.is_regular() && !fileStat.is_link()) { // Might also bork on other kinds of file types, but there's no // suitable errno for all cases. rak::error_number::set_global(rak::error_number::e_isdir); return false; } return node->prepare(MemoryChunk::prot_read | MemoryChunk::prot_write, SocketFile::o_create) || node->prepare(MemoryChunk::prot_read, SocketFile::o_create);}MemoryChunkFileList::create_chunk_part(FileList::iterator itr, uint64_t offset, uint32_t length, int prot) { offset -= (*itr)->offset(); length = std::min<uint64_t>(length, (*itr)->size_bytes() - offset); if (offset < 0) throw internal_error("FileList::chunk_part(...) caught a negative offset"); // Check that offset != length of file. if (!(*itr)->prepare(prot)) return MemoryChunk(); return SocketFile((*itr)->file_descriptor()).create_chunk(offset, length, prot, MemoryChunk::map_shared);}Chunk*FileList::create_chunk(uint64_t offset, uint32_t length, int prot) { if (offset + length > m_torrentSize) throw internal_error("Tried to access chunk out of range in FileList"); std::auto_ptr<Chunk> chunk(new Chunk); for (iterator itr = std::find_if(begin(), end(), std::bind2nd(std::mem_fun(&File::is_valid_position), offset)); length != 0; ++itr) { if (itr == end()) throw internal_error("FileList could not find a valid file for chunk"); if ((*itr)->size_bytes() == 0) continue; MemoryChunk mc = create_chunk_part(itr, offset, length, prot); if (!mc.is_valid()) return NULL; if (mc.size() == 0) throw internal_error("FileList::create_chunk(...) mc.size() == 0."); if (mc.size() > length) throw internal_error("FileList::create_chunk(...) mc.size() > length."); chunk->push_back(ChunkPart::MAPPED_MMAP, mc); offset += mc.size(); length -= mc.size(); } if (chunk->empty()) return NULL; return chunk.release();}Chunk*FileList::create_chunk_index(uint32_t index, int prot) { return create_chunk((uint64_t)index * chunk_size(), chunk_index_size(index), prot);}voidFileList::mark_completed(uint32_t index) { if (m_bitfield.get(index)) throw internal_error("FileList::mark_completed(...) received a chunk that has already been finished."); if (m_bitfield.size_set() >= m_bitfield.size_bits()) throw internal_error("FileList::mark_completed(...) m_bitfield.size_set() >= m_bitfield.size_bits()."); if (index >= size_chunks() || completed_chunks() >= size_chunks()) throw internal_error("FileList::mark_completed(...) received an invalid index."); m_bitfield.set(index); DEBUGP_DOWNLOAD("complete download %d\n",index); inc_completed(begin(), index);}FileList::iteratorFileList::inc_completed(iterator firstItr, uint32_t index) { firstItr = std::find_if(firstItr, end(), rak::less(index, std::mem_fun(&File::range_second))); iterator lastItr = std::find_if(firstItr, end(), rak::less(index + 1, std::mem_fun(&File::range_second))); if (firstItr == end()) throw internal_error("FileList::inc_completed() first == m_entryList->end()."); std::for_each(firstItr, lastItr == end() ? end() : (lastItr + 1), std::mem_fun(&File::inc_completed)); return lastItr;}voidFileList::update_completed() { if (!m_bitfield.is_tail_cleared()) throw internal_error("Content::update_done() called but m_bitfield's tail isn't cleared."); if (m_bitfield.is_all_set()) { for (iterator itr = begin(), last = end(); itr != last; ++itr) (*itr)->set_completed((*itr)->size_chunks()); } else { // Clear any old progress data from the entries as we don't clear // this on close, etc. for (iterator itr = begin(), last = end(); itr != last; ++itr) (*itr)->set_completed(0); if (m_bitfield.is_all_unset()) return; iterator entryItr = begin(); for (Bitfield::size_type index = 0; index < m_bitfield.size_bits(); ++index) if (m_bitfield.get(index)) entryItr = inc_completed(entryItr, index); }}voidFileList::set_match_depth(File* left, File* right) { uint32_t level = 0; Path::const_iterator itrLeft = left->path()->begin(); Path::const_iterator itrRight = right->path()->begin(); while (itrLeft != left->path()->end() && itrRight != right->path()->end() && *itrLeft == *itrRight) { itrLeft++; itrRight++; level++; } left->set_match_depth_next(level); right->set_match_depth_prev(level);}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -