// BackupActions.cpp: implementation of the CBackupActions class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "BackupActions.h" #include "resource.h" #include ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// bool CBackupActions::ArchivePrepare::Do(CActionEngine* pEngine, HWND hwndUpdates) { // Some Checks ASSERT(pEngine != NULL); if(!m_dest.valid()) throw CActionError(E_INVALIDARG, IDS_BACKUP_ERR_DEST, m_dest); // Create destination folder HRESULT hr = m_dest.create(); if(FAILED(hr)) throw CActionError(hr, IDS_BACKUP_ERR_CREATE_DEST, m_dest); // This could take a while so message Update(hwndUpdates, _T("Listing files to backup..."), NULL); // Iterate through source folders string_array::const_iterator iterSrc; for(iterSrc = m_src.begin(); iterSrc != m_src.end(); iterSrc++) { Update(hwndUpdates, NULL, (LPCTSTR)*iterSrc); // Variables Used below file_path srcPath = *iterSrc; file_path srcFile; file_path destFile; file_iterator fileIter(srcPath.files_begin(file_iterator::sub_folders)); file_iterator end; for( ; fileIter != end; fileIter++) { // Check if it has the ARCHIVE attribute set if(!(fileIter->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)) continue; if(fileIter->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; // Make File Paths srcFile = *iterSrc; // Destination is root destination + same folder structure as // original folder destFile = m_dest; if(srcFile.attributes() & FILE_ATTRIBUTE_DIRECTORY) destFile += *(srcFile.end(false) - 1); destFile += fileIter->cFileName; srcFile = srcFile.folder() + fileIter->cFileName; // Make sure extension is not in list if(m_asIgnore.find(srcFile.ext().make_lower()) == m_asIgnore.end()) { // Add the file ArchiveCopy* pCopy = new ArchiveCopy(srcFile, destFile); pEngine->Add(pCopy); } } // Error from file_iterator (listing folders) if(fileIter.state() != ERROR_SUCCESS) throw CActionError(HRESULT_FROM_WIN32(fileIter.state()), IDS_BACKUP_ERR_LIST, (file_path)*iterSrc); } return false; } HRESULT CBackupActions::BasePrepare::Initialize(const CPropertyBag& data) { m_dest = data.GetString(NS_BACKUP_REG_DEST, _T("")); data.GetStringSet(NS_BACKUP_REG_SOURCE, m_src); string_array asTemp; data.GetStringSet(NS_IGNORE_REG_EXT, asTemp); // Make them all lower for_each(asTemp.begin(), asTemp.end(), Lower); // And copy them to the set (removes doubles) copy(asTemp.begin(), asTemp.end(), inserter(m_asIgnore, m_asIgnore.begin())); // Remove any blanks from ignore m_asIgnore.erase(_T("")); if(!m_dest.valid()) return E_INVALIDARG; return S_OK; } #define FILETIME_TO_64(ft) \ ((__int64) (ft.dwLowDateTime | ((__int64)(ft.dwHighDateTime << 32)))) bool CBackupActions::DatePrepare::Do(CActionEngine* pEngine, HWND hwndUpdates) { // Some Checks ASSERT(pEngine != NULL); if(!m_dest.valid()) throw CActionError(E_INVALIDARG, IDS_BACKUP_ERR_DEST, m_dest); // Create destination folder HRESULT hr = m_dest.create(); if(FAILED(hr)) throw CActionError(hr, IDS_BACKUP_ERR_CREATE_DEST, m_dest); // This could take a while so message Update(hwndUpdates, _T("Comparing dates on backup files..."), NULL); HANDLE hFile; FILETIME ftModify; // Iterate through source folders string_array::const_iterator iterSrc; for(iterSrc = m_src.begin(); iterSrc != m_src.end(); iterSrc++) { Update(hwndUpdates, NULL, (LPCTSTR)*iterSrc); // Variables Used below file_path srcPath = *iterSrc; file_path srcFile; file_path destFile; file_iterator fileIter(srcPath.files_begin(file_iterator::sub_folders)); file_iterator end; for( ; fileIter != end; fileIter++) { if(fileIter->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; // Make File Paths srcFile = *iterSrc; // Destination is root destination + same folder structure as // original folder destFile = m_dest; if(srcFile.attributes() & FILE_ATTRIBUTE_DIRECTORY) destFile += *(srcFile.end(false) - 1); destFile += fileIter->cFileName; srcFile = srcFile.folder() + fileIter->cFileName; // Make sure extension is not in list if(m_asIgnore.find(srcFile.ext().make_lower()) != m_asIgnore.end()) continue; // Open the file hFile = CreateFile(destFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); // Check return Value if(hFile == INVALID_HANDLE_VALUE) { // If no file then Backup switch(::GetLastError()) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: break; default: throw CActionError(HRESULT_FROM_WIN32(::GetLastError()), IDS_BACKUP_ERR_FILE, m_dest); } } else { // Get the filetime ftModify.dwHighDateTime = 0; ftModify.dwLowDateTime = 0; if(!GetFileTime(hFile, NULL, NULL, &ftModify)) throw CActionError(HRESULT_FROM_WIN32(::GetLastError()), IDS_BACKUP_ERR_FILE, destFile); CloseHandle(hFile); // Are we newer? if(FILETIME_TO_64(fileIter->ftLastWriteTime) <= FILETIME_TO_64(ftModify)) continue; } // Add the file ArchiveCopy* pCopy = new ArchiveCopy(srcFile, destFile); pEngine->Add(pCopy); } // Error from file_iterator (listing folders) if(fileIter.state() != ERROR_SUCCESS) throw CActionError(HRESULT_FROM_WIN32(fileIter.state()), IDS_BACKUP_ERR_LIST, (file_path)*iterSrc); } return false; } bool CBackupActions::ArchiveCopy::Do(CActionEngine* pEngine, HWND hwndUpdates) { start: try { // Update any monitors Update(hwndUpdates, _T("Copying..."), m_src); // Create the folder this file is in HRESULT hr = m_dest.folder().create(); if(FAILED(hr)) throw CActionError(hr, IDS_BACKUP_ERR_CREATE_DEST, m_dest.folder()); // SetAttributes of the file to make sure it's not read-only // when read-only CopyFile fails (CopyFile copies attributes) ::SetFileAttributes(m_dest, FILE_ATTRIBUTE_NORMAL); // Copy. Don't worry about overwriting old files if(!CopyFile(m_src, m_dest, FALSE)) throw CActionError(HRESULT_FROM_WIN32(::GetLastError()), IDS_BACKUP_ERR_COPY, m_src); // Remove the Archive Attribute of the file SetFileAttributes(m_src, m_src.attributes() ^ FILE_ATTRIBUTE_ARCHIVE); return false; } catch(CActionError& err) { switch(err.m_hRes) { case ERROR_HANDLE_DISK_FULL: case ERROR_DISK_FULL: case ERROR_DESTINATION_ELEMENT_FULL: case STG_E_MEDIUMFULL: { string sTemp; sTemp.format(IDS_BACKUP_ERR_DISKFULL, (LPCTSTR)m_src.root()); if(IDYES == MessageBoxTimeout(hwndUpdates, sTemp, _T("Secure Shutdown"), MB_OKCANCEL | MB_ICONQUESTION, 15000, 5000)) break; } default: throw; } } goto start; } bool CBackupActions::DateCopy::Do(CActionEngine* pEngine, HWND hwndUpdates) { // Update any monitors Update(hwndUpdates, _T("Copying..."), m_src); // Create the folder this file is in HRESULT hr = m_dest.folder().create(); if(FAILED(hr)) throw CActionError(hr, IDS_BACKUP_ERR_CREATE_DEST, m_dest.folder()); // SetAttributes of the file to make sure it's not read-only // when read-only CopyFile fails (CopyFile copies attributes) ::SetFileAttributes(m_dest, FILE_ATTRIBUTE_NORMAL); // Copy. Don't worry about overwriting old files if(!CopyFile(m_src, m_dest, FALSE)) throw CActionError(HRESULT_FROM_WIN32(::GetLastError()), IDS_BACKUP_ERR_COPY, m_src); return false; // We don't try to catch disk full errors (and prompt for another disk) // because that doesn't make any sense in a date based backup }