#include "FileMetadataPipe.h" #include "../common/data.h" #include #include "../Interface/Server.h" #include "../stringtools.h" #include "../urbackupcommon/os_functions.h" const size_t metadata_id_size = 4+4+8+4; FileMetadataPipe::FileMetadataPipe( IPipe* pipe, const std::wstring& cmd ) : PipeFileBase(cmd), pipe(pipe), hFile(INVALID_HANDLE_VALUE), metadata_state(MetadataState_Wait), errpipe(Server->createMemoryPipe()) { metadata_buffer.resize(4096); init(); } bool FileMetadataPipe::getExitCode( int& exit_code ) { exit_code = 0; return true; } bool FileMetadataPipe::readStdoutIntoBuffer( char* buf, size_t buf_avail, size_t& read_bytes ) { if(buf_avail==0) { read_bytes = 0; return true; } if(metadata_state==MetadataState_FnSize) { read_bytes = (std::min)(buf_avail, sizeof(unsigned int) - fn_off); unsigned int fn_size = little_endian(static_cast(public_fn.size())); memcpy(buf, &fn_size + fn_off, read_bytes); fn_off+=read_bytes; if(fn_off==sizeof(unsigned int)) { fn_off=0; metadata_state = MetadataState_Fn; } return true; } else if(metadata_state==MetadataState_Fn) { read_bytes = (std::min)(buf_avail, public_fn.size()- fn_off); memcpy(buf, public_fn.data(), read_bytes); fn_off+=read_bytes; if(fn_off==public_fn.size()) { metadata_buffer_size = 0; metadata_buffer_off = 0; metadata_state = MetadataState_Os; } return true; } else if(metadata_state == MetadataState_Os) { if(!transmitCurrMetadata(buf, buf_avail, read_bytes)) { metadata_state = MetadataState_Wait; } return true; } while(true) { std::string msg; size_t r = pipe->Read(&msg, 100000); if(r==0) { if(pipe->hasError()) { read_bytes = 0; return false; } else { *buf = ID_METADATA_NOP; read_bytes = 1; return true; } } else { CRData msg_data(&msg); if(msg_data.getStr(&public_fn) && msg_data.getStr(&local_fn)) { if(public_fn.empty() && local_fn.empty()) { read_bytes = 0; return false; } if(public_fn=="==&'") { int abc=5; } if(isDirectory(os_file_prefix(Server->ConvertToUnicode(local_fn)))) { public_fn = "d" + public_fn; } else { public_fn = "f" + public_fn; } metadata_state = MetadataState_FnSize; *buf = ID_METADATA_V1; read_bytes = 1; fn_off = 0; return true; } else { assert(false); return false; } } } } bool FileMetadataPipe::readStderrIntoBuffer( char* buf, size_t buf_avail, size_t& read_bytes ) { while(true) { if(stderr_buf.size()>0) { read_bytes = (std::min)(buf_avail, stderr_buf.size()); memcpy(buf, stderr_buf.data(), read_bytes); stderr_buf.erase(0, read_bytes); return true; } if(errpipe->Read(&stderr_buf)==0) { if(pipe->hasError()) { return false; } } } } bool FileMetadataPipe::transmitCurrMetadata( char* buf, size_t buf_avail, size_t& read_bytes ) { if(metadata_buffer_size-metadata_buffer_off>0) { read_bytes = (std::min)(metadata_buffer_size-metadata_buffer_off, buf_avail); memcpy(buf, metadata_buffer.data()+metadata_buffer_off, read_bytes); metadata_buffer_off+=read_bytes; return true; } if(hFile == INVALID_HANDLE_VALUE) { hFile = CreateFileW(Server->ConvertToUnicode(local_fn).c_str(), GENERIC_READ|ACCESS_SYSTEM_SECURITY|READ_CONTROL, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN, NULL); if(hFile==INVALID_HANDLE_VALUE) { errpipe->Write("Error opening file \""+local_fn+"\" to read metadata. Last error: "+nconvert((int)GetLastError())+"\n"); return false; } backup_read_state = 0; backup_read_context=NULL; } if(backup_read_state==0) { DWORD total_read = 0; DWORD read; BOOL b = BackupRead(hFile, reinterpret_cast(metadata_buffer.data()+1), metadata_id_size, &read, FALSE, TRUE, &backup_read_context); if(b==FALSE) { errpipe->Write("Error getting metadata of file \""+local_fn+"\". Last error: "+nconvert((int)GetLastError())+"\n"); *buf = 0; read_bytes = 1; return false; } if(read==0) { BackupRead(hFile, NULL, 0, NULL, TRUE, TRUE, &backup_read_context); backup_read_context=NULL; CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; *buf=0; read_bytes = 1; return false; } if(readWrite("Error getting metadata stream structure.\n"); *buf=0; read_bytes = 1; return false; } total_read += read; metadata_buffer[0]=1; WIN32_STREAM_ID* curr_stream = reinterpret_cast(metadata_buffer.data()+1); if(curr_stream->dwStreamNameSize>0) { b = BackupRead(hFile, reinterpret_cast(metadata_buffer.data()+1) + read, curr_stream->dwStreamNameSize, &read, FALSE, TRUE, &backup_read_context); if(b==FALSE) { errpipe->Write("Error getting metadata of file \""+local_fn+"\" (2). Last error: "+nconvert((int)GetLastError())+"\n"); *buf=0; read_bytes = 1; return false; } if(readdwStreamNameSize) { errpipe->Write("Error getting metadata stream structure (name).\n"); *buf=0; read_bytes = 1; return false; } total_read += read; } if(curr_stream->dwStreamId==BACKUP_DATA) { //skip LARGE_INTEGER seeked; DWORD high_seeked; b = BackupSeek(hFile, curr_stream->Size.LowPart, curr_stream->Size.HighPart, &seeked.LowPart, &high_seeked, &backup_read_context); seeked.HighPart = high_seeked; if(b==FALSE) { errpipe->Write("Error skipping data stream of file \""+local_fn+"\" (1). Last error: "+nconvert((int)GetLastError())+"\n"); *buf=0; read_bytes = 1; return false; } if(seeked.QuadPart!=curr_stream->Size.QuadPart) { errpipe->Write("Error skipping data stream of file \""+local_fn+"\" (2). Last error: "+nconvert((int)GetLastError())+"\n"); *buf=0; read_bytes = 1; return false; } return transmitCurrMetadata(buf, buf_avail, read_bytes); } backup_read_state = 1; curr_stream_size = curr_stream->Size; metadata_buffer_size = total_read + 1; metadata_buffer_off = 0; curr_pos = 0; return transmitCurrMetadata(buf, buf_avail, read_bytes); } else if(backup_read_state==1) { DWORD toread = static_cast((std::min)(curr_stream_size.QuadPart-curr_pos, static_cast(buf_avail))); DWORD read; BOOL b = BackupRead(hFile, reinterpret_cast(buf), toread, &read, FALSE, TRUE, &backup_read_context); if(b==FALSE) { errpipe->Write("Error reading metadata stream of file \""+local_fn+"\". Last error: "+nconvert((int)GetLastError())+"\n"); memset(buf, 0, toread); } read_bytes = read; curr_pos+=read; if(curr_pos==curr_stream_size.QuadPart) { backup_read_state = 0; } return true; } return false; }