Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Backup Utility implementing Backup Rotation Scheme (Open Source Windows Forms Application in C#)

4.96/5 (12 votes)
14 Jun 2019CPOL6 min read 41.8K   2K  
CopyTree is a Backup Utility implementing Backup Rotation Scheme. It is an open source Windows Forms Application written in C#. The utility was designed to perform backup of critical folders to multiple backup folders.

Copy Tree Icon

Introduction

CopyTree is a Backup Utility implementing Backup Rotation Scheme. It is an open source Windows Forms Application written in C#. The utility was designed to perform a backup of critical folders to multiple backup folders. The result of running the utility is that each backup folder is an exact copy of the source folder at a given time. Each time the utility is run, the oldest backup folder is updated with the current source folder. In other words, the utility rotates between the backup folders. The backup update process ensures that the backup directory structure is the same as the source directory. New files are copied from source to backup. Files that were deleted will be deleted from the backup. Files that were modified are copied over the old version. Files that were not modified are ignored. Except for the first time, the result is a very efficient backup process.

After the utility is installed, you select the critical folders on your hard disks for backup. We will call them the source folders. Next, you create several backup folders on an external hard drive or drives. My choice is three backup folders. Each time the utility is run, it will backup the source folders to the oldest of these backup folders. The result is that at any time, you have three generations of copies of your source folders. For example, if you run the utility once a day at the end of the day, on the next day you have a copy from yesterday, from the day before yesterday and from three days ago.

The copy process compares the source folder structure to the backup folder structure. If a file or sub-folder exists in the source and does not exist in the backup, the utility copies it from source to backup. If a file or sub-folder exists in the backup and does not exist in the source, the utility deletes it from the backup. If a file exists in both source and backup, the utility compares the LastWriteTimeUtc of the source and the backup. If they are equal, the utility assumes that the file was not modified since last backup and no copy takes place. If the last write times are different, the utility copies the source file and overrides the old backup.

The file copy process preserves the file CreationTimeUtc, LastWriteTimeUtc and LastAccessTimeUtc. Further, the file attribute flags: ReadOnly, Hidden, System, Archive and Normal will be preserved. If a file is read only and there is a need to delete it or to override it, the read only flag will be removed. Source files that are in use by other applications on your computer cannot be copied. The exception will be trapped by try-catch pair and an error message will be displayed and logged. The backup process will continue.

Backup Schema

The backup schema consists of two lists. The backup list and the source list. Each list is made of records with two fields each.

  • Backup Root Folders
    • Last backup date and time
    • Backup root folder name
  • Backup Subfolder Name and Source Folders Paths
    • Backup subfolder name
    • Source folder path

Below, you will find an example of backup roots folder list. The list consists of three generations backup rotation on external hard disk drive G:.

  • 2018/01/01 17:12:20 G:\Backup1
  • 2018/01/02 17:35:43 G:\Backup2
  • 2018/01/03 18:01:05 G:\Backup3

Let us assume that you want to backup your development projects that are stored in folder C:\MyDevelopment. And you want to backup your private documents folder, C:\MyDocuments. The Backup subfolder name and source folder paths will be:

  • MyDevelopment C:\MyDevelopment
  • MyDocuments C:\MyDocuments

If Backup1 is selected as the current backup, CopyTree tree will copy C:\MyDevelopment to G:\Backup1\MyDevelopment folder. And C:\MyDocuments to G:\Backup1\MyDocuments.

Copy Tree Main Screen

CopyTree main screen

Copy Tree Edit Schema

CopyTree edit schema screen

Demo Program

Create a folder CopyTree (or any other name) on your hard disk. Copy CopyTree.exe to this folder. Start the program. Click on the Edit Schema button.

The Edit Backup Schema window form will be displayed. Add one or more backup roots folders. My suggestion is three. Keep the suggested last backup time as the current time.

Add one or more source folder paths with their corresponding backup subfolders.

Click Save.

If the required backup root directory structure is not in place, CopyTree will ask your permission to create it.

Press Go to perform a backup.

Backup progress will be displayed in the information text labels at the top of the screen.

The error log in the center of the screen will display errors. Normally, there will be no errors. The most common reason for a system exception is attempting to copy a file while the file is in use.

After backup is complete, you can press the View Log button or the View Errors button to see all activities.

Program Source Code

The Backup class is the heart of the utility. The backup class runs the actual backup process in a background thread using the BackgroundWorker class.

The CopyTree class shows how to create the Backup class, how to initiate a backup, how to log the results, and how to be informed when the process is done.

Create backup class and attach two event handlers.

C#
// create backup class
Backup Backup = new Backup();
Backup.WriteToLogFile += WriteToLogFile;
Backup.BackupCompletedEvent += OnBackupCompleted;

Define write to log file event handler.

C#
/// <summary>
/// Write to log file
/// </summary>
/// <param name="Control">Log or Error</param>
/// <param name="LogText">Message</param>
private void WriteToLogFile
    (
    LogControl Control,  // LogControl is either Log or Error
    string LogText       // text
    )
        {
        // write to loe and error files
        }

Define backup is completed event handler.

C#
/// <summary>
/// Backup process is completed
/// </summary>
private void OnBackupCompleted
        (
        bool BackupDone	// true=normal completion, false=user pressed cancel
        )
    {
    // perform completed event tasks
    }

Initiate backup.

C#
// set the selected index of the backup folder list
Schema.RootIndex = SelectedIndex;

// initiate backup
Backup.BackupFolders(Schema);

The main method of the Backup class is PerformFolderBackup. It is a recursive method that traverses the source and backup folders tree.

C#
/// <summary>
/// recursive folder backup
/// </summary>
/// <param name="SourceFolderName">Source folder name</param>
/// <param name="BackupFolderName">Backup folder name</param>
private void PerformFolderBackup
    (
    DirectoryInfo SourceFolderInfo,
    DirectoryInfo BackupFolderInfo
    )
{
// cancel backup
if(BackupWorker.CancellationPending) throw new CanceBackupException();

// backup folder full name shortcut
string BackupFolderFullName = BackupFolderInfo.FullName;

// get source child files
FileInfo[] SourceFiles = SourceFolderInfo.GetFiles();

// get backup child files
FileInfo[] BackupFiles = BackupFolderInfo.GetFiles();

// source has files
if(SourceFiles.Length != 0)
    {
    // backup has files
    if(BackupFiles.Length != 0)
        {
        // backup has files
        EqualizeFiles(SourceFiles, BackupFiles, BackupFolderFullName);
        }

    // backup has no files
    else
        {
        // copy all source files to backup folder
        CopyFiles(SourceFiles, BackupFolderFullName);
        }
    }

// source has no files but backup has files
else if(BackupFiles.Length != 0)
    {
    // delete all files of backup folder
    DeleteFiles(BackupFiles);
    }
	
// get source child folders
DirectoryInfo[] SourceFolders = SourceFolderInfo.GetDirectories();

// get backup child folders
DirectoryInfo[] BackupFolders = BackupFolderInfo.GetDirectories();

// source has folders
if(SourceFolders.Length != 0)
    {
    // backup has folders
    if(BackupFolders.Length != 0)
        {
        // backup has folders
        EqualizeFolders(SourceFolders, BackupFolders, BackupFolderFullName);
        }

    // backup has no folders
    else
        {
        // copy all source child folders to backup folder
        CreateFolders(SourceFolders, BackupFolderFullName);
        }
    }

// source has no folders but backup has folders
else if(BackupFolders.Length != 0)
    {
    // delete all files of backup folder
    DeleteFolders(BackupFolders);
    }
	
// done
return;
}

Open Source Software Published by the Author

History

  • 2017/08/01: Version 1.0 Original version
  • 2017/08/09: Version 1.1 Change DateTime.TryParse out parameter to work with earlier C# compilers
  • 2017/08/01: Version 1.2 Fix for Go button enable status on first use of the program
  • 2019/06/14: Version 1.3 Fix for unauthorized exception

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)