bool os_link_symbolic_junctions(const std::wstring &target, const std::wstring &lname) { bool ret=false; std::wstring wtarget=target; HANDLE hJunc=INVALID_HANDLE_VALUE; char *buf=NULL; if(wtarget.find(os_file_prefix(L""))==0) wtarget.erase(0, os_file_prefix(L"").size()); if(!wtarget.empty() && wtarget[0]!='\\') wtarget=L"\\??\\"+wtarget; if(!wtarget.empty() && wtarget[target.size()-1]!='\\') wtarget+=L"\\"; if(!CreateDirectoryW(lname.c_str(), NULL) ) { goto cleanup; } hJunc=CreateFileW(lname.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); if(hJunc==INVALID_HANDLE_VALUE) goto cleanup; size_t bsize=sizeof(REPARSE_MOUNTPOINT_DATA_BUFFER) + (wtarget.size()+1) * sizeof(wchar_t)+30; buf=new char[bsize]; memset(buf, 0, bsize); REPARSE_MOUNTPOINT_DATA_BUFFER *rb=(REPARSE_MOUNTPOINT_DATA_BUFFER*)buf; rb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT; rb->ReparseTargetMaximumLength=(WORD)((wtarget.size()+1)*sizeof(wchar_t)); rb->ReparseTargetLength=rb->ReparseTargetMaximumLength-1*sizeof(wchar_t); rb->ReparseDataLength=rb->ReparseTargetLength+12; memcpy(rb->ReparseTarget, wtarget.c_str(), rb->ReparseTargetMaximumLength); DWORD bytes_ret; if(!DeviceIoControl(hJunc, FSCTL_SET_REPARSE_POINT, rb, rb->ReparseDataLength+REPARSE_MOUNTPOINT_HEADER_SIZE, NULL, 0, &bytes_ret, NULL) ) { goto cleanup; } ret=true; cleanup: if(!ret) { #ifndef OS_FUNC_NO_SERVER Server->Log("Creating junction failed. Last error="+nconvert((int)GetLastError()), LL_ERROR); #endif } delete []buf; if(hJunc!=INVALID_HANDLE_VALUE) CloseHandle(hJunc); if(!ret) { RemoveDirectoryW(lname.c_str()); } return ret; }
bool os_link_symbolic_junctions(const std::string &target, const std::string &lname, void* transaction) { std::string wtarget = target; if (wtarget.find("\\\\?\\UNC") == 0) { wtarget.erase(0, 7); wtarget = "\\" + wtarget; } else if (wtarget.find(os_file_prefix("")) == 0) { wtarget.erase(0, os_file_prefix("").size()); } if (!wtarget.empty() && wtarget[0] != '\\') wtarget = "\\??\\" + wtarget; if (!wtarget.empty() && wtarget[wtarget.size() - 1] == '\\') wtarget.erase(wtarget.size() - 1, 1); return os_link_symbolic_junctions_raw(wtarget, lname, transaction); }
void FSNTFSWIN::logFileChangesInt(const std::string& volpath, int64 min_size, char* fc_bitmap, int64& total_files, int64& total_changed_sectors) { std::vector<SFile> files = getFiles(volpath); for (size_t i = 0; i < files.size(); ++i) { if (files[i].isdir) { if (!files[i].issym) { logFileChangesInt(volpath + os_file_sep() + files[i].name, min_size, fc_bitmap, total_files, total_changed_sectors); } } else if(!files[i].issym) { HANDLE hFile = CreateFileW(Server->ConvertToWchar(os_file_prefix(volpath + os_file_sep() + files[i].name)).c_str(), GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile != INVALID_HANDLE_VALUE) { int64 sector_count = 0; int64 total_sectors = 0; STARTING_VCN_INPUT_BUFFER start_vcn = {}; std::vector<char> ret_buf; ret_buf.resize(32768); while (true) { RETRIEVAL_POINTERS_BUFFER* ret_ptrs = reinterpret_cast<RETRIEVAL_POINTERS_BUFFER*>(ret_buf.data()); DWORD bytesRet = 0; BOOL b = DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, &start_vcn, sizeof(start_vcn), ret_ptrs, static_cast<DWORD>(ret_buf.size()), &bytesRet, NULL); DWORD err = GetLastError(); if (b || err == ERROR_MORE_DATA) { LARGE_INTEGER last_vcn = ret_ptrs->StartingVcn; for (DWORD i = 0; i<ret_ptrs->ExtentCount; ++i) { if (ret_ptrs->Extents[i].Lcn.QuadPart != -1) { int64 count = ret_ptrs->Extents[i].NextVcn.QuadPart - last_vcn.QuadPart; sector_count += countSectors(ret_ptrs->Extents[i].Lcn.QuadPart, count, fc_bitmap); total_sectors += count; } last_vcn = ret_ptrs->Extents[i].NextVcn; } } if (!b) { if (err == ERROR_MORE_DATA) { start_vcn.StartingVcn = ret_ptrs->Extents[ret_ptrs->ExtentCount - 1].NextVcn; } else if (err == ERROR_HANDLE_EOF) { CloseHandle(hFile); break; } else { Server->Log("Error " + convert((int)GetLastError()) + " while accessing retrieval points", LL_WARNING); CloseHandle(hFile); break; } } else { CloseHandle(hFile); break; } } if (sector_count > 0) { ++total_files; total_changed_sectors += sector_count; } if (sector_count > 0 && sector_count*getBlocksize()>min_size) { Server->Log("Changed in " + volpath + os_file_sep() + files[i].name + ": " + convert(sector_count) + "/"+convert(total_sectors)+" sectors " + PrettyPrintBytes(sector_count*getBlocksize()) +"/"+ PrettyPrintBytes(total_sectors*getBlocksize()), LL_INFO); } } else { Server->Log("Error opening file: " + volpath + os_file_sep() + files[i].name, LL_INFO); } } } }
std::vector<SFile> getFilesWin(const std::string &path, bool *has_error, bool exact_filesize, bool with_usn, bool ignore_other_fs) { if(has_error!=NULL) { *has_error=false; } std::vector<char> usn_buffer; usn_buffer.resize(1024); std::vector<SFile> tmp; HANDLE fHandle; WIN32_FIND_DATAW wfd; std::wstring tpath=ConvertToWchar(path); if(!tpath.empty() && tpath[tpath.size()-1]=='\\' ) tpath.erase(tpath.size()-1, 1); fHandle=FindFirstFileW((tpath+L"\\*").c_str(),&wfd); if(fHandle==INVALID_HANDLE_VALUE) { if(tpath.find(L"\\\\?\\UNC")==0) { tpath.erase(0, 7); tpath=L"\\"+tpath; fHandle=FindFirstFileW((tpath+L"\\*").c_str(),&wfd); } else if(tpath.find(L"\\\\?\\")==0) { tpath.erase(0, 4); fHandle=FindFirstFileW((tpath+L"\\*").c_str(),&wfd); } if(fHandle==INVALID_HANDLE_VALUE) { if(has_error!=NULL) { *has_error=true; } return tmp; } } do { SFile f; f.name=ConvertFromWchar(wfd.cFileName); if(f.name=="." || f.name==".." ) continue; f.usn=0; f.isdir=(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)>0; LARGE_INTEGER lwt; lwt.HighPart=wfd.ftLastWriteTime.dwHighDateTime; lwt.LowPart=wfd.ftLastWriteTime.dwLowDateTime; f.last_modified=os_windows_to_unix_time(lwt.QuadPart); LARGE_INTEGER size; size.HighPart=wfd.nFileSizeHigh; size.LowPart=wfd.nFileSizeLow; f.size=size.QuadPart; lwt.HighPart=wfd.ftCreationTime.dwHighDateTime; lwt.LowPart=wfd.ftCreationTime.dwLowDateTime; f.created=os_windows_to_unix_time(lwt.QuadPart); std::string reparse_target; if (ignore_other_fs && wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && wfd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT && os_get_symlink_target(os_file_prefix(path + os_file_sep() + f.name), reparse_target) && is_volume(reparse_target) ) { continue; } else if(wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && (wfd.dwReserved0== IO_REPARSE_TAG_SYMLINK || wfd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) ) { f.issym=true; f.isspecialf=true; } else if (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && (wfd.dwReserved0 == 0x8000001b /*IO_REPARSE_TAG_APPEXECLINK*/ )) { f.isspecialf = true; } f.isencrypted = (wfd.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)>0; if( (exact_filesize && !f.isdir && !f.issym ) || with_usn ) { if(with_usn) { HANDLE hFile = CreateFileW(os_file_prefix(tpath+L"\\"+ConvertToWchar(f.name)).c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if(hFile!=INVALID_HANDLE_VALUE) { if (exact_filesize && !f.isdir && !f.issym) { BY_HANDLE_FILE_INFORMATION fileInformation; if (GetFileInformationByHandle(hFile, &fileInformation)!=0) { LARGE_INTEGER fsize; fsize.LowPart = fileInformation.nFileSizeLow; fsize.HighPart = fileInformation.nFileSizeHigh; f.size = fsize.QuadPart; f.nlinks = fileInformation.nNumberOfLinks; } } DWORD last_err=0; do { DWORD ret_bytes = 0; BOOL b = DeviceIoControl(hFile, FSCTL_READ_FILE_USN_DATA, NULL, 0, usn_buffer.data(), static_cast<DWORD>(usn_buffer.size()), &ret_bytes, NULL); if(b) { USN_RECORD* usnv2=reinterpret_cast<USN_RECORD*>(usn_buffer.data()); if(usnv2->MajorVersion==2) { f.usn = usnv2->Usn; } else if(usnv2->MajorVersion==3) { usn::USN_RECORD_V3* usnv3=reinterpret_cast<usn::USN_RECORD_V3*>(usn_buffer.data()); f.usn = usnv3->Usn; } else { Log("USN entry major version "+convert(usnv2->MajorVersion)+" of file \""+ConvertFromWchar(tpath)+"\\"+f.name+"\" not supported", LL_ERROR); } } else { last_err=GetLastError(); } if(last_err==ERROR_INSUFFICIENT_BUFFER) { usn_buffer.resize(usn_buffer.size()*2); } } while (last_err==ERROR_INSUFFICIENT_BUFFER); CloseHandle(hFile); } } else { WIN32_FILE_ATTRIBUTE_DATA fad; if( GetFileAttributesExW(os_file_prefix(tpath+L"\\"+ConvertToWchar(f.name)).c_str(), GetFileExInfoStandard, &fad) ) { size.HighPart = fad.nFileSizeHigh; size.LowPart = fad.nFileSizeLow; f.size = size.QuadPart; lwt.HighPart = fad.ftLastWriteTime.dwHighDateTime; lwt.LowPart = fad.ftLastWriteTime.dwLowDateTime; f.last_modified = os_windows_to_unix_time(lwt.QuadPart); lwt.HighPart=fad.ftCreationTime.dwHighDateTime; lwt.LowPart=fad.ftCreationTime.dwLowDateTime; f.created=os_windows_to_unix_time(lwt.QuadPart); } } } if(f.last_modified<0) f.last_modified*=-1; tmp.push_back(f); } while (FindNextFileW(fHandle,&wfd) ); if (GetLastError() != ERROR_NO_MORE_FILES) { DWORD err = GetLastError(); if (has_error != NULL) { *has_error = true; } FindClose(fHandle); std::sort(tmp.begin(), tmp.end()); SetLastError(err); return tmp; } FindClose(fHandle); std::sort(tmp.begin(), tmp.end()); return tmp; }
bool os_sync(const std::string & path) { std::string prefixedbpath = os_file_prefix(path); if (next(prefixedbpath, 0, "\\\\?\\UNC")) { HANDLE hVol = CreateFileW(ConvertToWchar(prefixedbpath).c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hVol == INVALID_HANDLE_VALUE) { return false; } BOOL b = FlushFileBuffers(hVol); CloseHandle(hVol); return b == TRUE; } std::wstring tvolume; tvolume.resize(prefixedbpath.size() + 100); DWORD cchBufferLength = static_cast<DWORD>(tvolume.size()); BOOL b = GetVolumePathNameW(ConvertToWchar(prefixedbpath).c_str(), &tvolume[0], cchBufferLength); if (!b) { return false; } std::string volume = ConvertFromWchar(tvolume.c_str()); if (volume.find("\\\\?\\") == 0 && volume.find("\\\\?\\GLOBALROOT") != 0) { volume.erase(0, 4); } if (!volume.empty() && volume[volume.size() - 1] == os_file_sep()[0]) { volume = volume.substr(0, volume.size() - 1); } HANDLE hVol = CreateFileW(ConvertToWchar("\\\\.\\"+volume).c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hVol == INVALID_HANDLE_VALUE) { return false; } b = FlushFileBuffers(hVol); CloseHandle(hVol); return b == TRUE; }
void BackupServerPrepareHash::operator()(void) { while(true) { working=false; std::string data; size_t rc=pipe->Read(&data); if(data=="exitnow") { output->Write("exitnow"); std::string t; exitpipe_hash->Read(&t); Server->destroy(exitpipe_hash); exitpipe->Write("ok"); Server->Log("server_prepare_hash Thread finished"); delete this; return; } else if(data=="exit") { output->Write("exit"); Server->destroy(exitpipe); Server->Log("server_prepare_hash Thread finished"); delete this; return; } else if(data=="flush") { continue; } if(rc>0) { working=true; CRData rd(&data); std::string temp_fn; rd.getStr(&temp_fn); int backupid; rd.getInt(&backupid); char incremental; rd.getChar(&incremental); std::string tfn; rd.getStr(&tfn); std::string hashpath; rd.getStr(&hashpath); std::string hashoutput_fn; rd.getStr(&hashoutput_fn); bool diff_file=!hashoutput_fn.empty(); std::string old_file_fn; rd.getStr(&old_file_fn); IFile *tf=Server->openFile(os_file_prefix(Server->ConvertToUnicode(temp_fn)), MODE_READ); IFile *old_file=NULL; if(diff_file) { old_file=Server->openFile(os_file_prefix(Server->ConvertToUnicode(old_file_fn)), MODE_READ); if(old_file==NULL) { ServerLogger::Log(clientid, "Error opening file \""+old_file_fn+"\" from pipe for reading. File: old_file", LL_ERROR); if(tf!=NULL) Server->destroy(tf); continue; } } if(tf==NULL) { ServerLogger::Log(clientid, "Error opening file \""+temp_fn+"\" from pipe for reading file. File: temp_fn", LL_ERROR); has_error=true; if(old_file!=NULL) { Server->destroy(old_file); } } else { ServerLogger::Log(clientid, "PT: Hashing file \""+ExtractFileName(tfn)+"\"", LL_DEBUG); std::string h; if(!diff_file) { h=hash(tf); } else { h=hash_with_patch(old_file, tf); } Server->destroy(tf); if(old_file!=NULL) { Server->destroy(old_file); } CWData data; data.addString(temp_fn); data.addInt(backupid); data.addChar(incremental); data.addString(tfn); data.addString(hashpath); data.addString(h); data.addString(hashoutput_fn); data.addString(old_file_fn); output->Write(data.getDataPtr(), data.getDataSize() ); } } } }