bool IcePatch2::Patcher::removeFiles(const FileInfoSeq& files) { if(_remove < 1) { return true; } for(FileInfoSeq::const_reverse_iterator p = files.rbegin(); p != files.rend(); ++p) { try { remove(_dataDir + '/' + p->path); if(fputc('-', _log) == EOF || ! writeFileInfo(_log, *p)) { throw "error writing log file:\n" + IceUtilInternal::lastErrorToString(); } } catch(...) { if(_remove < 2) // We ignore errors if IcePatch2Client.Remove >= 2. { throw; } } } FileInfoSeq newLocalFiles; newLocalFiles.reserve(_localFiles.size()); set_difference(_localFiles.begin(), _localFiles.end(), files.begin(), files.end(), back_inserter(newLocalFiles), FileInfoLess()); _localFiles.swap(newLocalFiles); FileInfoSeq newRemoveFiles; set_difference(_removeFiles.begin(), _removeFiles.end(), files.begin(), files.end(), back_inserter(newRemoveFiles), FileInfoLess()); _removeFiles.swap(newRemoveFiles); return true; }
bool IcePatch2::Patcher::updateFlags(const FileInfoSeq& files) { for(FileInfoSeq::const_iterator p = files.begin(); p != files.end(); ++p) { if(p->size >= 0) // Regular file? { setFileFlags(_dataDir + '/' + p->path, *p); } } // // Remove the old files whose flags were updated from the set of // local files. // FileInfoSeq localFiles; localFiles.reserve(_localFiles.size()); set_difference(_localFiles.begin(), _localFiles.end(), files.begin(), files.end(), back_inserter(localFiles), FileInfoWithoutFlagsLess()); // NOTE: We ignore the flags. // // Add the new files to the set of local file. // _localFiles.clear(); set_union(localFiles.begin(), localFiles.end(), files.begin(), files.end(), back_inserter(_localFiles), FileInfoLess()); FileInfoSeq newUpdateFlags; set_difference(_updateFlags.begin(), _updateFlags.end(), files.begin(), files.end(), back_inserter(newUpdateFlags), FileInfoLess()); _updateFlags.swap(newUpdateFlags); return true; }
FileInfoSeq IcePatch2::FileServerI::getFileInfoSeq(Int node0, const Current& c) const { LargeFileInfoSeq largeFiles = getLargeFileInfoSeq(node0, c); FileInfoSeq files; files.resize(largeFiles.size()); transform(largeFiles.begin(), largeFiles.end(), files.begin(), toFileInfo); return files; }
FileInfoSeq PathUtil::getFileInfos(const String& base, const String& path, const String& filters, int flags) { FileInfoSeq fileinfos; _wfinddata_t finddata; long handle; int num_files = 0; size_t baselen = base.length(); Filter filter(filters); String pattern = path; if (!PathUtil::isDirectoryLetter(pattern[pattern.length() - 1])) { pattern += '/'; } pattern += '*'; handle = _wfindfirst(const_cast<wchar_t *>(u2w(pattern).c_str()), &finddata); if (handle == -1) { _findclose(handle); return fileinfos; } do { FileInfo info; if (finddata.attrib & _A_SUBDIR) { if (!wcscmp(finddata.name, L".") || !wcscmp(finddata.name, L"..")) { continue; } if (!(flags & File::List_needCVS)) { if (!wcscmp(finddata.name, L"CVS")) { continue; } } if (flags & File::List_nodirectory) { continue; } if (flags & File::List_filterDirectory) { if (!filter.In(w2u(finddata.name))) continue; } info.isDir = true; } else { if (flags & File::List_nofile) { continue; } if (!(flags & File::List_nofilterfile)) { if (!filter.In(w2u(finddata.name))) continue; } info.isDir = false; } info.fullpath = (path + "/" + w2u(finddata.name)).c_str() + baselen; info.filetype = File::Stdio; info.filesize = finddata.size; info.filetime = finddata.time_write; info.localtime = *_localtime64(&finddata.time_write); PathUtil::splitPath(info.fullpath, info.filepath, info.filename, info.fileext); info.filename = PathUtil::removeDir(info.fullpath); fileinfos.push_back(info); num_files++; } while (_wfindnext(handle, &finddata) != -1); _findclose(handle); if (flags & File::List_sort) { std::sort(fileinfos.begin(), fileinfos.end(), CmpFileInfoNameLess); } return fileinfos; }
bool IcePatch2::Patcher::updateFilesInternal(const FileInfoSeq& files, const DecompressorPtr& decompressor) { Long total = 0; Long updated = 0; for(FileInfoSeq::const_iterator p = files.begin(); p != files.end(); ++p) { if(p->size > 0) // Regular, non-empty file? { total += p->size; } } AsyncResultPtr curCB; AsyncResultPtr nxtCB; for(FileInfoSeq::const_iterator p = files.begin(); p != files.end(); ++p) { if(p->size < 0) // Directory? { createDirectoryRecursive(_dataDir + '/' + p->path); if(fputc('+', _log) == EOF || !writeFileInfo(_log, *p)) { throw "error writing log file:\n" + IceUtilInternal::lastErrorToString(); } } else // Regular file. { if(!_feedback->patchStart(p->path, p->size, updated, total)) { return false; } if(p->size == 0) { string path = simplify(_dataDir + '/' + p->path); FILE* fp = IceUtilInternal::fopen(path, "wb"); if(fp == 0) { throw "cannot open `" + path +"' for writing:\n" + IceUtilInternal::lastErrorToString(); } fclose(fp); } else { string pathBZ2 = simplify(_dataDir + '/' + p->path + ".bz2"); string dir = getDirname(pathBZ2); if(!dir.empty()) { createDirectoryRecursive(dir); } try { removeRecursive(pathBZ2); } catch(...) { } FILE* fileBZ2 = IceUtilInternal::fopen(pathBZ2, "wb"); if(fileBZ2 == 0) { throw "cannot open `" + pathBZ2 + "' for writing:\n" + IceUtilInternal::lastErrorToString(); } try { Int pos = 0; while(pos < p->size) { if(!curCB) { assert(!nxtCB); curCB = _serverNoCompress->begin_getFileCompressed(p->path, pos, _chunkSize); } else { assert(nxtCB); swap(nxtCB, curCB); } if(pos + _chunkSize < p->size) { nxtCB = _serverNoCompress->begin_getFileCompressed(p->path, pos + _chunkSize, _chunkSize); } else { FileInfoSeq::const_iterator q = p + 1; while(q != files.end() && q->size <= 0) { ++q; } if(q != files.end()) { nxtCB = _serverNoCompress->begin_getFileCompressed(q->path, 0, _chunkSize); } } ByteSeq bytes; try { bytes = _serverNoCompress->end_getFileCompressed(curCB); } catch(const FileAccessException& ex) { throw "error from IcePatch2 server for `" + p->path + "': " + ex.reason; } if(bytes.empty()) { throw "size mismatch for `" + p->path + "'"; } if(fwrite(reinterpret_cast<char*>(&bytes[0]), bytes.size(), 1, fileBZ2) != 1) { throw ": cannot write `" + pathBZ2 + "':\n" + IceUtilInternal::lastErrorToString(); } pos += static_cast<int>(bytes.size()); updated += bytes.size(); if(!_feedback->patchProgress(pos, p->size, updated, total)) { fclose(fileBZ2); return false; } } } catch(...) { fclose(fileBZ2); throw; } fclose(fileBZ2); decompressor->log(_log); decompressor->add(*p); } if(!_feedback->patchEnd()) { return false; } } } FileInfoSeq newLocalFiles; newLocalFiles.reserve(_localFiles.size()); set_union(_localFiles.begin(), _localFiles.end(), files.begin(), files.end(), back_inserter(newLocalFiles), FileInfoLess()); _localFiles.swap(newLocalFiles); FileInfoSeq newUpdateFiles; set_difference(_updateFiles.begin(), _updateFiles.end(), files.begin(), files.end(), back_inserter(newUpdateFiles), FileInfoLess()); _updateFiles.swap(newUpdateFiles); return true; }
bool IcePatch2::Patcher::prepare() { _localFiles.clear(); bool thorough = _thorough; if(!thorough) { try { loadFileInfoSeq(_dataDir, _localFiles); } catch(const string& ex) { thorough = _feedback->noFileSummary(ex); if(!thorough) { return false; } } } if(thorough) { if(!_feedback->checksumStart()) { return false; } PatcherGetFileInfoSeqCB cb(_feedback); if(!getFileInfoSeq(_dataDir, 0, &cb, _localFiles)) { return false; } if(!_feedback->checksumEnd()) { return false; } saveFileInfoSeq(_dataDir, _localFiles); } FileTree0 tree0; getFileTree0(_localFiles, tree0); if(tree0.checksum != _serverCompress->getChecksum()) { if(!_feedback->fileListStart()) { return false; } ByteSeqSeq checksumSeq = _serverCompress->getChecksumSeq(); if(checksumSeq.size() != 256) { throw string("server returned illegal value"); } AsyncResultPtr curCB; AsyncResultPtr nxtCB; for(int node0 = 0; node0 < 256; ++node0) { if(tree0.nodes[node0].checksum != checksumSeq[node0]) { if(!curCB) { assert(!nxtCB); curCB = _serverCompress->begin_getFileInfoSeq(node0); } else { assert(nxtCB); swap(nxtCB, curCB); } int node0Nxt = node0; do { ++node0Nxt; } while(node0Nxt < 256 && tree0.nodes[node0Nxt].checksum == checksumSeq[node0Nxt]); if(node0Nxt < 256) { nxtCB = _serverCompress->begin_getFileInfoSeq(node0Nxt); } FileInfoSeq files = _serverCompress->end_getFileInfoSeq(curCB); sort(files.begin(), files.end(), FileInfoLess()); files.erase(unique(files.begin(), files.end(), FileInfoEqual()), files.end()); // // Compute the set of files which were removed. // set_difference(tree0.nodes[node0].files.begin(), tree0.nodes[node0].files.end(), files.begin(), files.end(), back_inserter(_removeFiles), FileInfoWithoutFlagsLess()); // NOTE: We ignore the flags here. // // Compute the set of files which were updated (either the file contents, flags or both). // FileInfoSeq updatedFiles; updatedFiles.reserve(files.size()); set_difference(files.begin(), files.end(), tree0.nodes[node0].files.begin(), tree0.nodes[node0].files.end(), back_inserter(updatedFiles), FileInfoLess()); // // Compute the set of files whose contents was updated. // FileInfoSeq contentsUpdatedFiles; contentsUpdatedFiles.reserve(files.size()); set_difference(files.begin(), files.end(), tree0.nodes[node0].files.begin(), tree0.nodes[node0].files.end(), back_inserter(contentsUpdatedFiles), FileInfoWithoutFlagsLess()); // NOTE: We ignore the flags here. copy(contentsUpdatedFiles.begin(), contentsUpdatedFiles.end(), back_inserter(_updateFiles)); // // Compute the set of files whose flags were updated. // set_difference(updatedFiles.begin(), updatedFiles.end(), contentsUpdatedFiles.begin(), contentsUpdatedFiles.end(), back_inserter(_updateFlags), FileInfoLess()); } if(!_feedback->fileListProgress((node0 + 1) * 100 / 256)) { return false; } } if(!_feedback->fileListEnd()) { return false; } } sort(_removeFiles.begin(), _removeFiles.end(), FileInfoLess()); sort(_updateFiles.begin(), _updateFiles.end(), FileInfoLess()); sort(_updateFlags.begin(), _updateFlags.end(), FileInfoLess()); string pathLog = simplify(_dataDir + '/' + logFile); _log = IceUtilInternal::fopen(pathLog, "w"); if(!_log) { throw "cannot open `" + pathLog + "' for writing:\n" + IceUtilInternal::lastErrorToString(); } return true; }