Ejemplo n.º 1
0
/**
 * Create a backup of the specified package. A backup is only created if the specified
 * package meets specific criteria, as outlined in the comments for ShouldBackupPackage().
 *
 * @param	InPackage	Package which should be backed up
 *
 * @see		FAutoPackageBackup::ShouldBackupPackage()
 *
 * @return	true if the package was successfully backed up; false if it was not
 */
bool FAutoPackageBackup::BackupPackage( const UPackage& InPackage )
{
	bool bPackageBackedUp = false;
	FString OriginalFileName;
	
	// Check if the package is valid for being backed up
	if ( ShouldBackupPackage( InPackage, OriginalFileName ) )
	{
		GWarn->StatusUpdate( -1, -1, NSLOCTEXT("UnrealEd", "PackageBackup_Warning", "Backing up asset...") );

		// Construct the backup file name by appending a timestamp in between the base file name and extension
		FString DestinationFileName = GetBackupDirectory() / FPaths::GetBaseFilename(OriginalFileName);

		DestinationFileName += TEXT("_");
		DestinationFileName += FDateTime::Now().ToString(TEXT("%Y-%m-%d-%H-%M-%S"));
		DestinationFileName += FPaths::GetExtension( OriginalFileName, true );

		// Copy the file to the backup file name
		IFileManager::Get().Copy( *DestinationFileName, *OriginalFileName );

		bPackageBackedUp = true;
	}
	
	return bPackageBackedUp;
}
Ejemplo n.º 2
0
/** \fn DBUtil::DoBackup(QString&)
 *  \brief Creates a backup of the database.
 *
 *   This fallback function is used only if the database backup script cannot
 *   be found.
 */
bool DBUtil::DoBackup(QString &filename)
{
    DatabaseParams dbParams = gCoreContext->GetDatabaseParams();
    QString     dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
    QString backupDirectory = GetBackupDirectory();

    QString command;
    QString compressCommand("");
    QString extension = ".sql";
    if (QFile::exists("/bin/gzip"))
        compressCommand = "/bin/gzip";
    else if (QFile::exists("/usr/bin/gzip"))
        compressCommand = "/usr/bin/gzip";
    else
        LOG(VB_GENERAL, LOG_CRIT, "Neither /bin/gzip nor /usr/bin/gzip exist. "
                                  "The database backup will be uncompressed.");

    QString backupFilename = CreateBackupFilename(
        dbParams.dbName + "-" + dbSchemaVer, extension);
    QString backupPathname = backupDirectory + "/" + backupFilename;

    QString privateinfo = QString(
        "[client]\npassword=%1\n[mysqldump]\npassword=%2\n")
        .arg(dbParams.dbPassword).arg(dbParams.dbPassword);
    QString tempExtraConfFile = QString::null;
    if (!CreateTemporaryDBConf(privateinfo, tempExtraConfFile))
        return false;

    QString portArg = "";
    if (dbParams.dbPort > 0)
        portArg = QString(" --port='%1'").arg(dbParams.dbPort);
    command = QString("mysqldump --defaults-extra-file='%1' --host='%2'%3"
                      " --user='******' --add-drop-table --add-locks"
                      " --allow-keywords --complete-insert"
                      " --extended-insert --lock-tables --no-create-db --quick"
                      " '%5' > '%6' 2>/dev/null")
                      .arg(tempExtraConfFile).arg(dbParams.dbHostName)
                      .arg(portArg).arg(dbParams.dbUserName)
                      .arg(dbParams.dbName).arg(backupPathname);

    LOG(VB_FILE, LOG_INFO, QString("Backing up database with command: '%1'")
            .arg(command));
    LOG(VB_GENERAL, LOG_CRIT, QString("Backing up database to file: '%1'")
            .arg(backupPathname));

    uint status = myth_system(command, kMSDontBlockInputDevs|kMSAnonLog);

    QByteArray tmpfile = tempExtraConfFile.toLocal8Bit();
    unlink(tmpfile.constData());

    if (status != GENERIC_EXIT_OK)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
            QString("Error backing up database: '%1' (%2)")
                .arg(command).arg(status));
        filename = "__FAILED__";
        return false;
    }

    if (compressCommand != "")
    {
        LOG(VB_GENERAL, LOG_CRIT, "Compressing database backup file.");
        compressCommand += " " + backupPathname;
        status = myth_system(compressCommand, kMSDontBlockInputDevs);

        if (status != GENERIC_EXIT_OK)
        {
            LOG(VB_GENERAL, LOG_CRIT,
                   "Compression failed, backup file will remain uncompressed.");
        }
        else
        {
            backupPathname += ".gz";

            LOG(VB_GENERAL, LOG_CRIT, QString("Database Backup filename: '%1'")
                    .arg(backupPathname));
        }
    }

    LOG(VB_GENERAL, LOG_CRIT, "Database Backup complete.");

    filename = backupPathname;
    return true;
}
Ejemplo n.º 3
0
/** \fn DBUtil::DoBackup(const QString&, QString&)
 *  \brief Creates a backup of the database by executing the backupScript.
 *
 *   This function executes the specified backup script to create a database
 *   backup.  This is the preferred approach for creating the backup.
 */
bool DBUtil::DoBackup(const QString &backupScript, QString &filename,
                      bool disableRotation)
{
    DatabaseParams dbParams = gCoreContext->GetDatabaseParams();
    QString     dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
    QString backupDirectory = GetBackupDirectory();
    QString  backupFilename = CreateBackupFilename(dbParams.dbName + "-" +
                                                   dbSchemaVer, ".sql");
    QString      scriptArgs = gCoreContext->GetSetting("BackupDBScriptArgs");
    QString rotate = "";
    if (disableRotation)
    {
        if (!(scriptArgs.contains("rotate", Qt::CaseInsensitive)))
            rotate = "rotate=-1";
    }


    QString privateinfo =
        QString("DBHostName=%1\nDBPort=%2\n"
                "DBUserName=%3\nDBPassword=%4\n"
                "DBName=%5\nDBSchemaVer=%6\n"
                "DBBackupDirectory=%7\nDBBackupFilename=%8\n%9\n")
        .arg(dbParams.dbHostName).arg(dbParams.dbPort)
        .arg(dbParams.dbUserName).arg(dbParams.dbPassword)
        .arg(dbParams.dbName).arg(dbSchemaVer)
        .arg(backupDirectory).arg(backupFilename).arg(rotate);
    QString tempDatabaseConfFile = QString::null;
    bool hastemp = CreateTemporaryDBConf(privateinfo, tempDatabaseConfFile);
    if (!hastemp)
        LOG(VB_GENERAL, LOG_ERR, LOC + "Attempting backup, anyway.");

    LOG(VB_GENERAL, LOG_ERR, QString("Backing up database with script: '%1'")
            .arg(backupScript));

    QString command = backupScript + " " + scriptArgs + " " +
                      tempDatabaseConfFile;
    uint status = myth_system(command, kMSDontBlockInputDevs|kMSAnonLog);

    if (hastemp)
    {
        QByteArray tmpfile = tempDatabaseConfFile.toLocal8Bit();
        unlink(tmpfile.constData());
    }

    if (status != GENERIC_EXIT_OK)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
            QString("Error backing up database: %1 (%2)")
                .arg(command).arg(status));
        filename = "__FAILED__";
        return false;
    }

    LOG(VB_GENERAL, LOG_CRIT, "Database Backup complete.");

    QDir dir(backupDirectory, backupFilename + "*");
    uint numfiles = dir.count();
    if (numfiles < 1)
    {
        // If no file begins with the suggested filename, don't show the backup
        // filename in the GUI message -- the script probably used some other
        // filename
        filename = "";
        LOG(VB_FILE, LOG_ERR, LOC +
            QString("No files beginning with the suggested database backup "
                    "filename '%1' were found in '%2'.")
                .arg(backupFilename).arg(backupDirectory));
    }
    else
    {
        filename = dir.path() + "/" + dir[0];;
        if (numfiles > 1)
        {
            LOG(VB_FILE, LOG_ERR, LOC +
                QString("Multiple files beginning with the suggested database "
                        "backup filename '%1' were found in '%2'. "
                        "Assuming the first is the backup.")
                    .arg(backupFilename).arg(backupDirectory));
        }
    }

    if (!filename.isEmpty())
    {
        LOG(VB_GENERAL, LOG_CRIT, QString("Backed up database to file: '%1'")
                .arg(filename));
    }

    return true;
}
Ejemplo n.º 4
0
/**
 * Helper function designed to determine if the provided package should be backed up or not.
 * The function checks for many conditions, such as if the package is too large to backup,
 * if the package has a particular attribute that should prevent it from being backed up (such
 * as being marked for PIE-use), if cooking is in progress, etc.
 *
 * @param	InPackage		Package which should be checked to see if its valid for backing-up
 * @param	OutFileName		File name of the package on disk if the function determines the package
 *							already existed
 *
 * @return	true if the package is valid for backing-up; false otherwise
 */
bool FAutoPackageBackup::ShouldBackupPackage( const UPackage& InPackage, FString& OutFilename )
{
	// Check various conditions to see if the package is a valid candidate for backing up
	bool bShouldBackup =
		GIsEditor																			// Backing up packages only makes sense in the editor
		&& !IsRunningCommandlet()															// Don't backup saves resulting from commandlets
		&& IsPackageBackupEnabled()															// Ensure that the package backup is enabled in the first place
		&& (InPackage.HasAnyPackageFlags(PKG_PlayInEditor) == false)						// Don't back up PIE packages
		&& (InPackage.HasAnyPackageFlags(PKG_ContainsScript) == false);						// Don't back up script packages

	if( bShouldBackup )
	{
		GWarn->StatusUpdate( -1, -1, NSLOCTEXT("UnrealEd", "PackageBackup_ValidityWarning", "Determining asset backup validity...") );

		bShouldBackup =	FPackageName::DoesPackageExist( InPackage.GetName(), NULL, &OutFilename );	// Make sure the file already exists (no sense in backing up a new package)
	}
	
	// If the package passed the initial backup checks, proceed to check more specific conditions
	// that might disqualify the package from being backed up
	const int32 FileSizeOfBackup = IFileManager::Get().FileSize( *OutFilename );
	if ( bShouldBackup )
	{
		// Ensure that the size the backup would require is less than that of the maximum allowed
		// space for backups
		bShouldBackup = FileSizeOfBackup <= GetMaxAllowedBackupSpace();
	}

	// If all of the prior checks have passed, now see if the package has been backed up
	// too recently to be considered for an additional backup
	if ( bShouldBackup )
	{
		// Ensure that the autosave/backup directory exists
		const FString& BackupSaveDir = GetBackupDirectory();
		IFileManager::Get().MakeDirectory( *BackupSaveDir, 1 );

		// Find all of the files in the backup directory
		TArray<FString> FilesInBackupDir;
		IFileManager::Get().FindFilesRecursive(FilesInBackupDir, *BackupSaveDir, TEXT("*.*"), true, false);

		// Extract the base file name and extension from the passed-in package file name
		FString ExistingBaseFileName = FPaths::GetBaseFilename(OutFilename);
		FString ExistingFileNameExtension = FPaths::GetExtension(OutFilename);

		bool bFoundExistingBackup = false;
		int32 DirectorySize = 0;
		FDateTime LastBackupTimeStamp = FDateTime::MinValue();

		TArray<FBackupFileInfo> BackupFileInfoArray;
		
		// Check every file in the backup directory for matches against the passed-in package
		// (Additionally keep statistics on all backup files for potential maintenance)
		for ( TArray<FString>::TConstIterator FileIter( FilesInBackupDir ); FileIter; ++FileIter )
		{
			const FString CurBackupFileName = FString( *FileIter );
			
			// Create a new backup file info struct for keeping information about each backup file
			const int32 FileInfoIndex = BackupFileInfoArray.AddZeroed();
			FBackupFileInfo& CurBackupFileInfo = BackupFileInfoArray[ FileInfoIndex ];
			
			// Record the backup file's name, size, and timestamp
			CurBackupFileInfo.FileName = CurBackupFileName;
			CurBackupFileInfo.FileSize = IFileManager::Get().FileSize( *CurBackupFileName );
			
			// If we failed to get a timestamp or a valid size, something has happened to the file and it shouldn't be considered
			CurBackupFileInfo.FileTimeStamp = IFileManager::Get().GetTimeStamp(*CurBackupFileName);
			if (CurBackupFileInfo.FileTimeStamp == FDateTime::MinValue() || CurBackupFileInfo.FileSize == -1)
			{
				BackupFileInfoArray.RemoveAt( BackupFileInfoArray.Num() - 1 );
				continue;
			}

			// Calculate total directory size by adding the size of this backup file
			DirectorySize += CurBackupFileInfo.FileSize;

			FString CurBackupBaseFileName =  FPaths::GetBaseFilename(CurBackupFileName);
			FString CurBackupFileNameExtension = FPaths::GetExtension(CurBackupFileName);

			// The base file name of the backup file is going to include an underscore followed by a timestamp, so they must be removed for comparison's sake
			CurBackupBaseFileName = CurBackupBaseFileName.Left( CurBackupBaseFileName.Find( TEXT("_"), ESearchCase::CaseSensitive, ESearchDir::FromEnd ) );
					
			// If the base file names and extensions match, we've found a backup
			if ( CurBackupBaseFileName == ExistingBaseFileName &&  CurBackupFileNameExtension == ExistingFileNameExtension )
			{
				bFoundExistingBackup = true;

				// Keep track of the most recent matching time stamp so we can check if the passed-in package
				// has been backed up too recently
				if ( CurBackupFileInfo.FileTimeStamp > LastBackupTimeStamp )
				{
					LastBackupTimeStamp = CurBackupFileInfo.FileTimeStamp;
				}
			}
		}

		// If there was an existing backup, check to see if it was created too recently to allow another backup
		if ( bFoundExistingBackup )
		{
			// Check the difference in timestamp seconds against the backup interval; if not enough time has elapsed since
			// the last backup, we don't want to make another one
			if ((FDateTime::UtcNow() - LastBackupTimeStamp).GetTotalSeconds() < GetBackupInterval())
			{
				bShouldBackup = false;
			}
		}

		// If every other check against the package has succeeded for backup purposes, ensure there is enough directory space
		// available in the backup directory, as adding the new backup might use more space than the user allowed for backups.
		// If the backup file size + the current directory size exceeds the max allowed space, deleted old backups until there
		// is sufficient space. If enough space can't be freed for whatever reason, then no back-up will be created.
		if ( bShouldBackup && ( FileSizeOfBackup + DirectorySize > GetMaxAllowedBackupSpace() ) )
		{
			bShouldBackup = PerformBackupSpaceMaintenance( BackupFileInfoArray, DirectorySize, FileSizeOfBackup );
		}
	}
	
	return bShouldBackup;
}