/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011-2014 Martin Raiber * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **************************************************************************/ #include #include "ServerDownloadThread.h" #include "../Interface/Server.h" #include "server_log.h" #include "ClientMain.h" #include "../stringtools.h" #include "../common/data.h" #include "file_metadata.h" #include "server_settings.h" #include "server_cleanup.h" #include "FileBackup.h" namespace { const unsigned int shadow_copy_timeout=30*60*1000; const size_t max_queue_size = 500; const size_t queue_items_full = 1; const size_t queue_items_chunked = 4; } ServerDownloadThread::ServerDownloadThread( FileClient& fc, FileClientChunked* fc_chunked, const std::wstring& backuppath, const std::wstring& backuppath_hashes, const std::wstring& last_backuppath, const std::wstring& last_backuppath_complete, bool hashed_transfer, bool save_incomplete_file, int clientid, const std::wstring& clientname, bool use_tmpfiles, const std::wstring& tmpfile_path, const std::string& server_token, bool use_reflink, int backupid, bool r_incremental, IPipe* hashpipe_prepare, ClientMain* client_main, int filesrv_protocol_version) : fc(fc), fc_chunked(fc_chunked), backuppath(backuppath), backuppath_hashes(backuppath_hashes), last_backuppath(last_backuppath), last_backuppath_complete(last_backuppath_complete), hashed_transfer(hashed_transfer), save_incomplete_file(save_incomplete_file), clientid(clientid), clientname(clientname), use_tmpfiles(use_tmpfiles), tmpfile_path(tmpfile_path), server_token(server_token), use_reflink(use_reflink), backupid(backupid), r_incremental(r_incremental), hashpipe_prepare(hashpipe_prepare), max_ok_id(0), is_offline(false), client_main(client_main), filesrv_protocol_version(filesrv_protocol_version), skipping(false), queue_size(0), all_downloads_ok(true) { mutex = Server->createMutex(); cond = Server->createCondition(); } ServerDownloadThread::~ServerDownloadThread() { Server->destroy(mutex); Server->destroy(cond); } void ServerDownloadThread::operator()( void ) { if(fc_chunked!=NULL && filesrv_protocol_version>2) { fc_chunked->setQueueCallback(this); } while(true) { SQueueItem curr; { IScopedLock lock(mutex); while(dl_queue.empty()) { cond->wait(&lock); } curr = dl_queue.front(); dl_queue.pop_front(); if(curr.action == EQueueAction_Fileclient) { if(curr.fileclient == EFileClient_Full) { queue_size-=queue_items_full; } else if(curr.fileclient== EFileClient_Chunked) { queue_size-=queue_items_chunked; } } } if(curr.action==EQueueAction_Quit) { break; } else if(curr.action==EQueueAction_Skip) { skipping = true; continue; } if(is_offline || skipping) { download_nok_ids.push_back(curr.id); { IScopedLock lock(mutex); all_downloads_ok=false; } if(curr.patch_dl_files.prepared) { delete curr.patch_dl_files.orig_file; ScopedDeleteFile del_1(curr.patch_dl_files.patchfile); ScopedDeleteFile del_2(curr.patch_dl_files.hashoutput); if(curr.patch_dl_files.delete_chunkhashes) { ScopedDeleteFile del_3(curr.patch_dl_files.chunkhashes); } else { delete curr.patch_dl_files.chunkhashes; } } continue; } if(curr.action==EQueueAction_StartShadowcopy) { start_shadowcopy(Server->ConvertToUTF8(curr.fn)); continue; } else if(curr.action==EQueueAction_StopShadowcopy) { stop_shadowcopy(Server->ConvertToUTF8(curr.fn)); continue; } bool ret = true; if((curr.fileclient == EFileClient_Full || curr.fileclient == EFileClient_Chunked) && curr.predicted_filesize == 0 ) { ret = touch_file(curr); } else if(curr.fileclient == EFileClient_Full) { ret = load_file(curr); } else if(curr.fileclient== EFileClient_Chunked) { ret = load_file_patch(curr); } if(!ret) { IScopedLock lock(mutex); is_offline=true; } } std::sort(download_nok_ids.begin(), download_nok_ids.end()); std::sort(download_partial_ids.begin(), download_partial_ids.end()); } void ServerDownloadThread::addToQueueFull(size_t id, const std::wstring &fn, const std::wstring &short_fn, const std::wstring &curr_path, const std::wstring &os_path, _i64 predicted_filesize, const FileMetadata& metadata, const FileMetadata& parent_metadata, bool is_script, bool at_front ) { SQueueItem ni; ni.id = id; ni.fn = fn; ni.short_fn = short_fn; ni.curr_path = curr_path; ni.os_path = os_path; ni.fileclient = EFileClient_Full; ni.patch_dl_files.prepared=false; ni.patch_dl_files.prepare_error=false; ni.action = EQueueAction_Fileclient; ni.predicted_filesize = predicted_filesize; ni.metadata = metadata; ni.parent_metadata = parent_metadata; ni.is_script = is_script; IScopedLock lock(mutex); if(!at_front) { dl_queue.push_back(ni); } else { dl_queue.push_front(ni); } cond->notify_one(); queue_size+=queue_items_full; if(!at_front) { sleepQueue(lock); } } void ServerDownloadThread::addToQueueChunked(size_t id, const std::wstring &fn, const std::wstring &short_fn, const std::wstring &curr_path, const std::wstring &os_path, _i64 predicted_filesize, const FileMetadata& metadata, const FileMetadata& parent_metadata, bool is_script) { SQueueItem ni; ni.id = id; ni.fn = fn; ni.short_fn = short_fn; ni.curr_path = curr_path; ni.os_path = os_path; ni.fileclient = EFileClient_Chunked; ni.patch_dl_files.prepared=false; ni.patch_dl_files.prepare_error=false; ni.action = EQueueAction_Fileclient; ni.predicted_filesize= predicted_filesize; ni.metadata = metadata; ni.parent_metadata = parent_metadata; ni.is_script = is_script; IScopedLock lock(mutex); dl_queue.push_back(ni); cond->notify_one(); queue_size+=queue_items_chunked; sleepQueue(lock); } void ServerDownloadThread::addToQueueStartShadowcopy(const std::wstring& fn) { SQueueItem ni; ni.action = EQueueAction_StartShadowcopy; ni.fn=fn; ni.id=std::string::npos; ni.patch_dl_files.prepared=false; ni.patch_dl_files.prepare_error=false; IScopedLock lock(mutex); dl_queue.push_back(ni); cond->notify_one(); sleepQueue(lock); } void ServerDownloadThread::addToQueueStopShadowcopy(const std::wstring& fn) { SQueueItem ni; ni.action = EQueueAction_StopShadowcopy; ni.fn=fn; ni.id=std::string::npos; ni.patch_dl_files.prepared=false; ni.patch_dl_files.prepare_error=false; IScopedLock lock(mutex); dl_queue.push_back(ni); cond->notify_one(); sleepQueue(lock); } bool ServerDownloadThread::load_file(SQueueItem todl) { ServerLogger::Log(clientid, L"Loading file \""+todl.fn+L"\"", LL_DEBUG); IFile *fd=ClientMain::getTemporaryFileRetry(use_tmpfiles, tmpfile_path, clientid); if(fd==NULL) { ServerLogger::Log(clientid, L"Error creating temporary file 'fd' in load_file", LL_ERROR); return false; } std::wstring cfn=getDLPath(todl); _u32 rc=fc.GetFile(Server->ConvertToUTF8(cfn), fd, hashed_transfer); int hash_retries=5; while(rc==ERR_HASH && hash_retries>0) { fd->Seek(0); rc=fc.GetFile(Server->ConvertToUTF8(cfn), fd, hashed_transfer); --hash_retries; } bool ret = true; bool hash_file = false; if(rc!=ERR_SUCCESS) { ServerLogger::Log(clientid, L"Error getting complete file \""+cfn+L"\" from "+clientname+L". Errorcode: "+widen(fc.getErrorString(rc))+L" ("+convert(rc)+L")", LL_ERROR); { IScopedLock lock(mutex); all_downloads_ok=false; } if( (rc==ERR_TIMEOUT || rc==ERR_ERROR) && save_incomplete_file && fd->Size()>0 ) { ServerLogger::Log(clientid, L"Saving incomplete file.", LL_INFO); hash_file = true; if(todl.id>max_ok_id) { max_ok_id=todl.id; } download_partial_ids.push_back(todl.id); } else { download_nok_ids.push_back(todl.id); ClientMain::destroyTemporaryFile(fd); } if(rc==ERR_TIMEOUT || rc==ERR_ERROR || rc==ERR_BASE_DIR_LOST) { ret=false; } } else { if(todl.id>max_ok_id) { max_ok_id=todl.id; } hash_file=true; } if(hash_file) { std::wstring os_curr_path=FileBackup::convertToOSPathFromFileClient(todl.os_path+L"/"+todl.short_fn); std::wstring os_curr_hash_path=FileBackup::convertToOSPathFromFileClient(todl.os_path+L"/"+escape_metadata_fn(todl.short_fn)); std::wstring dstpath=backuppath+os_curr_path; std::wstring hashpath =backuppath_hashes+os_curr_hash_path; std::wstring filepath_old; if( use_reflink && (!last_backuppath.empty() || !last_backuppath_complete.empty() ) ) { std::wstring cfn_short=todl.os_path+L"/"+todl.short_fn; if(cfn_short[0]=='/') cfn_short.erase(0,1); filepath_old=last_backuppath+os_file_sep()+FileBackup::convertToOSPathFromFileClient(cfn_short); IFile *file_old=Server->openFile(os_file_prefix(filepath_old), MODE_READ); if(file_old==NULL) { if(!last_backuppath_complete.empty()) { filepath_old=last_backuppath_complete+os_file_sep()+FileBackup::convertToOSPathFromFileClient(cfn_short); file_old=Server->openFile(os_file_prefix(filepath_old), MODE_READ); } if(file_old==NULL) { ServerLogger::Log(clientid, L"No old file for \""+todl.fn+L"\"", LL_DEBUG); filepath_old.clear(); } } Server->destroy(file_old); } hashFile(dstpath, hashpath, fd, NULL, Server->ConvertToUTF8(filepath_old), fd->Size(), todl.metadata, todl.parent_metadata); } return ret; } bool ServerDownloadThread::load_file_patch(SQueueItem todl) { std::wstring cfn=todl.curr_path+L"/"+todl.fn; if(cfn[0]=='/') cfn.erase(0,1); if(todl.is_script) { cfn = L"SCRIPT|" + cfn + L"|" + convert(Server->getRandomNumber()); } bool full_dl=false; SPatchDownloadFiles dlfiles = todl.patch_dl_files; if(!dlfiles.prepared && !dlfiles.prepare_error) { dlfiles = preparePatchDownloadFiles(todl, full_dl); if(dlfiles.orig_file==NULL && full_dl) { addToQueueFull(todl.id, todl.fn, todl.short_fn, todl.curr_path, todl.os_path, todl.predicted_filesize, todl.metadata, todl.parent_metadata, true); return true; } } if(dlfiles.prepare_error) { return false; } ServerLogger::Log(clientid, L"Loading file patch for \""+todl.fn+L"\"", LL_DEBUG); ScopedDeleteFile pfd_destroy(dlfiles.patchfile); ScopedDeleteFile hash_tmp_destroy(dlfiles.hashoutput); ScopedDeleteFile hashfile_old_destroy(NULL); ObjectScope file_old_destroy(dlfiles.orig_file); ObjectScope hashfile_old_delete(dlfiles.chunkhashes); if(dlfiles.delete_chunkhashes) { hashfile_old_destroy.reset(dlfiles.chunkhashes); hashfile_old_delete.release(); } if(!server_token.empty() && !todl.is_script) { cfn=widen(server_token)+L"|"+cfn; } _u32 rc=fc_chunked->GetFilePatch(Server->ConvertToUTF8(cfn), dlfiles.orig_file, dlfiles.patchfile, dlfiles.chunkhashes, dlfiles.hashoutput, todl.predicted_filesize); int64 download_filesize = todl.predicted_filesize; int hash_retries=5; while(rc==ERR_HASH && hash_retries>0) { dlfiles.orig_file->Seek(0); dlfiles.patchfile=ClientMain::getTemporaryFileRetry(use_tmpfiles, tmpfile_path, clientid); if(dlfiles.patchfile==NULL) { ServerLogger::Log(clientid, L"Error creating temporary file 'pfd' in load_file_patch", LL_ERROR); return false; } pfd_destroy.reset(dlfiles.patchfile); dlfiles.hashoutput=ClientMain::getTemporaryFileRetry(use_tmpfiles, tmpfile_path, clientid); if(dlfiles.hashoutput==NULL) { ServerLogger::Log(clientid, L"Error creating temporary file 'hash_tmp' in load_file_patch -2", LL_ERROR); return false; } hash_tmp_destroy.reset(dlfiles.hashoutput); dlfiles.chunkhashes->Seek(0); download_filesize = todl.predicted_filesize; rc=fc_chunked->GetFilePatch(Server->ConvertToUTF8(cfn), dlfiles.orig_file, dlfiles.patchfile, dlfiles.chunkhashes, dlfiles.hashoutput, download_filesize); --hash_retries; } if(download_filesize<0) { Server->Log("download_filesize is smaller than zero", LL_DEBUG); download_filesize=todl.predicted_filesize; } bool hash_file; if(rc!=ERR_SUCCESS) { ServerLogger::Log(clientid, L"Error getting file patch for \""+cfn+L"\" from "+clientname+L". Errorcode: "+widen(FileClient::getErrorString(rc))+L" ("+convert(rc)+L")", LL_ERROR); if(rc==ERR_ERRORCODES) { ServerLogger::Log(clientid, "Remote Error: "+fc_chunked->getErrorcodeString(), LL_ERROR); } { IScopedLock lock(mutex); all_downloads_ok=false; } if( (rc==ERR_TIMEOUT || rc==ERR_CONN_LOST || rc==ERR_SOCKET_ERROR) && dlfiles.patchfile->Size()>0 && save_incomplete_file) { ServerLogger::Log(clientid, L"Saving incomplete file.", LL_INFO); hash_file=true; if(todl.id>max_ok_id) { max_ok_id=todl.id; } download_partial_ids.push_back(todl.id); } else { hash_file=false; download_nok_ids.push_back(todl.id); } } else { if(todl.id>max_ok_id) { max_ok_id=todl.id; } hash_file=true; } if(hash_file) { std::wstring os_curr_path=FileBackup::convertToOSPathFromFileClient(todl.os_path+L"/"+todl.short_fn); std::wstring dstpath=backuppath+os_curr_path; pfd_destroy.release(); hash_tmp_destroy.release(); hashFile(dstpath, dlfiles.hashpath, dlfiles.patchfile, dlfiles.hashoutput, Server->ConvertToUTF8(dlfiles.filepath_old), download_filesize, todl.metadata, todl.parent_metadata); } if(rc==ERR_TIMEOUT || rc==ERR_ERROR || rc==ERR_SOCKET_ERROR || rc==ERR_INT_ERROR || rc==ERR_BASE_DIR_LOST || rc==ERR_CONN_LOST ) return false; else return true; } void ServerDownloadThread::hashFile(std::wstring dstpath, std::wstring hashpath, IFile *fd, IFile *hashoutput, std::string old_file, int64 t_filesize, const FileMetadata& metadata, const FileMetadata& parent_metadata) { int l_backup_id=backupid; CWData data; data.addString(Server->ConvertToUTF8(fd->getFilenameW())); data.addInt(l_backup_id); data.addInt(r_incremental==true?1:0); data.addString(Server->ConvertToUTF8(dstpath)); data.addString(Server->ConvertToUTF8(hashpath)); if(hashoutput!=NULL) { data.addString(Server->ConvertToUTF8(hashoutput->getFilenameW())); } else { data.addString(""); } data.addString(old_file); data.addInt64(t_filesize); metadata.serialize(data); parent_metadata.serialize(data); ServerLogger::Log(clientid, "GT: Loaded file \""+ExtractFileName(Server->ConvertToUTF8(dstpath))+"\"", LL_DEBUG); Server->destroy(fd); if(hashoutput!=NULL) { Server->destroy(hashoutput); } hashpipe_prepare->Write(data.getDataPtr(), data.getDataSize() ); } bool ServerDownloadThread::isOffline() { IScopedLock lock(mutex); return is_offline; } void ServerDownloadThread::queueStop(bool immediately) { SQueueItem ni; ni.action = EQueueAction_Quit; IScopedLock lock(mutex); if(immediately) { dl_queue.push_front(ni); } else { dl_queue.push_back(ni); } cond->notify_one(); } bool ServerDownloadThread::isDownloadOk( size_t id ) { return !std::binary_search(download_nok_ids.begin(), download_nok_ids.end(), id); } bool ServerDownloadThread::isDownloadPartial( size_t id ) { return !download_partial_ids.empty() && std::binary_search(download_partial_ids.begin(), download_partial_ids.end(), id); } size_t ServerDownloadThread::getMaxOkId() { return max_ok_id; } std::string ServerDownloadThread::getQueuedFileFull(bool& metadata) { IScopedLock lock(mutex); for(std::deque::iterator it=dl_queue.begin(); it!=dl_queue.end();++it) { if(it->action==EQueueAction_Fileclient && !it->queued && it->fileclient==EFileClient_Full && it->predicted_filesize>0) { it->queued=true; metadata=false; return Server->ConvertToUTF8(getDLPath(*it)); } } return std::string(); } std::wstring ServerDownloadThread::getDLPath( SQueueItem todl ) { std::wstring cfn=todl.curr_path+L"/"+todl.fn; if(cfn[0]=='/') cfn.erase(0,1); if(todl.is_script) { cfn = L"SCRIPT|" + cfn + L"|" + convert(Server->getRandomNumber()); } else if(!server_token.empty()) { cfn=widen(server_token)+L"|"+cfn; } return cfn; } void ServerDownloadThread::resetQueueFull() { IScopedLock lock(mutex); for(std::deque::iterator it=dl_queue.begin(); it!=dl_queue.end();++it) { if(it->action==EQueueAction_Fileclient && it->fileclient==EFileClient_Full) { it->queued=false; } } } bool ServerDownloadThread::getQueuedFileChunked( std::string& remotefn, IFile*& orig_file, IFile*& patchfile, IFile*& chunkhashes, IFile*& hashoutput, _i64& predicted_filesize ) { IScopedLock lock(mutex); for(std::deque::iterator it=dl_queue.begin(); it!=dl_queue.end();++it) { if(it->action==EQueueAction_Fileclient && !it->queued && it->fileclient==EFileClient_Chunked && it->predicted_filesize>0) { if(it->patch_dl_files.prepare_error) { continue; } remotefn = Server->ConvertToUTF8(getDLPath(*it)); if(!it->patch_dl_files.prepared) { bool full_dl; it->patch_dl_files = preparePatchDownloadFiles(*it, full_dl); if(it->patch_dl_files.orig_file==NULL && full_dl) { it->fileclient=EFileClient_Full; queue_size-=queue_items_chunked-queue_items_full; continue; } } if(it->patch_dl_files.prepared) { it->queued=true; orig_file = it->patch_dl_files.orig_file; patchfile = it->patch_dl_files.patchfile; chunkhashes = it->patch_dl_files.chunkhashes; hashoutput = it->patch_dl_files.hashoutput; predicted_filesize = it->predicted_filesize; return true; } } } return false; } void ServerDownloadThread::resetQueueChunked() { IScopedLock lock(mutex); for(std::deque::iterator it=dl_queue.begin(); it!=dl_queue.end();++it) { if(it->action==EQueueAction_Fileclient && it->fileclient==EFileClient_Chunked) { it->queued=false; } } } SPatchDownloadFiles ServerDownloadThread::preparePatchDownloadFiles( SQueueItem todl, bool& full_dl ) { SPatchDownloadFiles dlfiles = {}; dlfiles.prepare_error=true; full_dl=false; std::wstring cfn=todl.curr_path+L"/"+todl.fn; if(cfn[0]=='/') cfn.erase(0,1); std::wstring cfn_short=todl.os_path+L"/"+todl.short_fn; if(cfn_short[0]=='/') cfn_short.erase(0,1); std::wstring dstpath=backuppath+os_file_sep()+FileBackup::convertToOSPathFromFileClient(cfn_short); std::wstring hashpath=backuppath_hashes+os_file_sep()+FileBackup::convertToOSPathFromFileClient(cfn_short); std::wstring hashpath_old=last_backuppath+os_file_sep()+L".hashes"+os_file_sep()+FileBackup::convertToOSPathFromFileClient(cfn_short); std::wstring filepath_old=last_backuppath+os_file_sep()+FileBackup::convertToOSPathFromFileClient(cfn_short); std::auto_ptr file_old(Server->openFile(os_file_prefix(filepath_old), MODE_READ)); if(file_old.get()==NULL) { if(!last_backuppath_complete.empty()) { filepath_old=last_backuppath_complete+os_file_sep()+FileBackup::convertToOSPathFromFileClient(cfn_short); file_old.reset(Server->openFile(os_file_prefix(filepath_old), MODE_READ)); } if(file_old.get()==NULL) { ServerLogger::Log(clientid, L"No old file for \""+todl.fn+L"\"", LL_DEBUG); full_dl=true; return dlfiles; } hashpath_old=last_backuppath_complete+os_file_sep()+L".hashes"+os_file_sep()+FileBackup::convertToOSPathFromFileClient(cfn_short); } IFile *pfd=ClientMain::getTemporaryFileRetry(use_tmpfiles, tmpfile_path, clientid); if(pfd==NULL) { ServerLogger::Log(clientid, L"Error creating temporary file 'pfd' in load_file_patch", LL_ERROR); return dlfiles; } ScopedDeleteFile pfd_delete(pfd); IFile *hash_tmp=ClientMain::getTemporaryFileRetry(use_tmpfiles, tmpfile_path, clientid); if(hash_tmp==NULL) { ServerLogger::Log(clientid, L"Error creating temporary file 'hash_tmp' in load_file_patch", LL_ERROR); return dlfiles; } ScopedDeleteFile hash_tmp_delete(pfd); if(!server_token.empty()) { cfn=widen(server_token)+L"|"+cfn; } std::auto_ptr hashfile_old(Server->openFile(os_file_prefix(hashpath_old), MODE_READ)); dlfiles.delete_chunkhashes=false; if( (hashfile_old.get()==NULL || hashfile_old->Size()==0 || is_metadata_only(hashfile_old.get()) ) && file_old.get()!=NULL ) { ServerLogger::Log(clientid, L"Hashes for file \""+filepath_old+L"\" not available. Calulating hashes...", LL_DEBUG); hashfile_old.reset(ClientMain::getTemporaryFileRetry(use_tmpfiles, tmpfile_path, clientid)); if(hashfile_old.get()==NULL) { ServerLogger::Log(clientid, L"Error creating temporary file 'hashfile_old' in load_file_patch", LL_ERROR); return dlfiles; } dlfiles.delete_chunkhashes=true; BackupServerPrepareHash::build_chunk_hashs(file_old.get(), hashfile_old.get(), NULL, false, NULL, false); hashfile_old->Seek(0); } dlfiles.orig_file=file_old.release(); dlfiles.patchfile=pfd; pfd_delete.release(); dlfiles.chunkhashes=hashfile_old.release(); dlfiles.hashoutput=hash_tmp; hash_tmp_delete.release(); dlfiles.hashpath = hashpath; dlfiles.filepath_old = filepath_old; dlfiles.prepared=true; dlfiles.prepare_error=false; return dlfiles; } void ServerDownloadThread::start_shadowcopy(const std::string &path) { client_main->sendClientMessage("START SC \""+path+"\"#token="+server_token, "DONE", L"Activating shadow copy on \""+clientname+L"\" for path \""+Server->ConvertToUnicode(path)+L"\" failed", shadow_copy_timeout); } void ServerDownloadThread::stop_shadowcopy(const std::string &path) { client_main->sendClientMessage("STOP SC \""+path+"\"#token="+server_token, "DONE", L"Removing shadow copy on \""+clientname+L"\" for path \""+Server->ConvertToUnicode(path)+L"\" failed", shadow_copy_timeout); } void ServerDownloadThread::sleepQueue(IScopedLock& lock) { while(queue_size>max_queue_size) { lock.relock(NULL); Server->wait(1000); lock.relock(mutex); } } void ServerDownloadThread::queueSkip() { SQueueItem ni; ni.action = EQueueAction_Skip; IScopedLock lock(mutex); dl_queue.push_front(ni); cond->notify_one(); } void ServerDownloadThread::unqueueFileFull( const std::string& fn ) { IScopedLock lock(mutex); for(std::deque::iterator it=dl_queue.begin(); it!=dl_queue.end();++it) { if(it->action==EQueueAction_Fileclient && it->queued && it->fileclient==EFileClient_Full && Server->ConvertToUTF8(getDLPath(*it)) == fn) { it->queued=false; return; } } } void ServerDownloadThread::unqueueFileChunked( const std::string& remotefn ) { IScopedLock lock(mutex); for(std::deque::iterator it=dl_queue.begin(); it!=dl_queue.end();++it) { if(it->action==EQueueAction_Fileclient && it->queued && it->fileclient==EFileClient_Chunked && Server->ConvertToUTF8(getDLPath(*it)) == remotefn ) { it->queued=false; return; } } } bool ServerDownloadThread::touch_file( SQueueItem todl ) { std::wstring cfn_short=todl.os_path+L"/"+todl.short_fn; if(cfn_short[0]=='/') cfn_short.erase(0,1); std::wstring os_curr_path=FileBackup::convertToOSPathFromFileClient(cfn_short); std::wstring dstpath=backuppath+os_file_sep()+os_curr_path; std::wstring hashpath=backuppath_hashes+os_file_sep()+os_curr_path; ServerLogger::Log(clientid, L"GT: Touching file \""+dstpath+L"\"", LL_DEBUG); IFile* f = Server->openFile(os_file_prefix(dstpath), MODE_WRITE); if(f!=NULL) { if(todl.id>max_ok_id) { max_ok_id=todl.id; } Server->destroy(f); if(!write_file_metadata(hashpath, client_main, todl.metadata)) { ServerLogger::Log(clientid, L"GT: Error writing file metadata to \""+hashpath+L"\"", LL_ERROR); return false; } return true; } else { { IScopedLock lock(mutex); all_downloads_ok=false; } download_nok_ids.push_back(todl.id); ServerLogger::Log(clientid, L"GT: Error creating file \""+dstpath+L"\"", LL_ERROR); return false; } } bool ServerDownloadThread::isAllDownloadsOk() { IScopedLock lock(mutex); return all_downloads_ok; }