///<summary>This is the function that the worker thread uses to perform the backup.</summary> private void InstanceMethodBackup() { curVal = 0; Invoke(new PassProgressDelegate(PassProgressToDialog), new object [] { curVal, Lan.g(this, "Preparing to copy database"), //this happens very fast and probably won't be noticed. 100, "" }); //max of 100 keeps dlg from closing string dbName = MiscData.GetCurrentDatabase(); ulong driveFreeSpace = 0; double dbSize = GetFileSizes(textBackupFromPath.Text + dbName) / 1024; //Attempt to get the free disk space on the drive or share of the destination folder. //If the free space cannot be determined the backup will be attempted anyway (old behavior). if (ODFileUtils.GetDiskFreeSpace(textBackupToPath.Text, out driveFreeSpace)) { if ((ulong)dbSize * 1024 * 1024 >= driveFreeSpace) //dbSize is in megabytes, cast to ulong to compare. It will never be negative so this is safe. { Invoke(new ErrorMessageDelegate(SetErrorMessage), new object[] { Lan.g(this, "Not enough free disk space available on the destination drive to backup the database.") }); //We now want to automatically close FormProgress. This is done by clearing out the variables. Invoke(new PassProgressDelegate(PassProgressToDialog), new object[] { 0, "", 0, "" }); return; } } try{ string dbtopath = ODFileUtils.CombinePaths(textBackupToPath.Text, dbName); if (Directory.Exists(dbtopath)) // D:\opendental { int loopCount = 1; while (Directory.Exists(dbtopath + "backup_" + loopCount)) { loopCount++; } Directory.Move(dbtopath, dbtopath + "backup_" + loopCount); } string fromPath = ODFileUtils.CombinePaths(textBackupFromPath.Text, dbName); string toPath = textBackupToPath.Text; DirectoryInfo dirInfo = new DirectoryInfo(fromPath); //does not check to see if dir exists Directory.CreateDirectory(ODFileUtils.CombinePaths(toPath, dirInfo.Name)); FileInfo[] files = dirInfo.GetFiles(); curVal = 0; //curVal gets increased for (int i = 0; i < files.Length; i++) { string fromFile = files[i].FullName; string toFile = ODFileUtils.CombinePaths(new string[] { toPath, dirInfo.Name, files[i].Name }); if (File.Exists(toFile)) { if (files[i].LastWriteTime != File.GetLastWriteTime(toFile)) //if modification dates don't match { FileAttributes fa = File.GetAttributes(toFile); bool isReadOnly = ((fa & FileAttributes.ReadOnly) == FileAttributes.ReadOnly); if (isReadOnly) { //If the destination file exists and is marked as read only, then we must mark it as a //normal read/write file before it may be overwritten. File.SetAttributes(toFile, FileAttributes.Normal); //Remove read only from the destination file. } File.Copy(fromFile, toFile, true); } } else //file doesn't exist, so just copy { File.Copy(fromFile, toFile); } curVal += (double)files[i].Length / (double)1024 / (double)1024; if (curVal < dbSize) //this avoids setting progress bar to max, which would close the dialog. { Invoke(new PassProgressDelegate(PassProgressToDialog), new object [] { curVal, Lan.g(this, "Database: ?currentVal MB of ?maxVal MB copied"), dbSize, "" }); } } } catch { //for instance, if abort. //If the user aborted, FormP will return DialogResult.Cancel which will not cause this error text to be displayed to the user. See butBackup_Click for more info. Invoke(new ErrorMessageDelegate(SetErrorMessage), new object[] { Lan.g(this, "Backup failed.") }); //We now want to automatically close FormProgress. This is done by clearing out the variables. Invoke(new PassProgressDelegate(PassProgressToDialog), new object[] { 0, "", 0, "" }); return; } //A to Z folder------------------------------------------------------------------------------------ try { if (ShouldUseAtoZFolder()) { string atozFull = ODFileUtils.RemoveTrailingSeparators(ImageStore.GetPreferredAtoZpath()); string atozDir = atozFull.Substring(atozFull.LastIndexOf(Path.DirectorySeparatorChar) + 1); //OpenDentalData Invoke(new PassProgressDelegate(PassProgressToDialog), new object[] { 0, Lan.g(this, "Calculating size of files in A to Z folder."), 100, "" });//max of 100 keeps dlg from closing long atozSize = GetFileSizes(ODFileUtils.CombinePaths(atozFull, ""), ODFileUtils.CombinePaths(new string[] { textBackupToPath.Text, atozDir, "" })) / 1024; driveFreeSpace = 0; //Attempt to get the free disk space on the drive or share of the destination folder. //If the free space cannot be determined the backup will be attempted anyway (old behavior). if (ODFileUtils.GetDiskFreeSpace(textBackupToPath.Text, out driveFreeSpace)) { if ((ulong)(atozSize * 1024 * 1024) >= driveFreeSpace) //atozSize is in megabytes, cast to ulong in order to compare. It will never be negative so it's safe. //Not enough free space to perform the backup. { throw new ApplicationException(Lan.g(this, "Backing up A to Z images folder failed. Not enough free disk space available on the destination drive.") + "\r\n" + Lan.g(this, "AtoZ folder size:") + " " + atozSize * 1024 * 1024 + "B\r\n" + Lan.g(this, "Destination available space:") + " " + driveFreeSpace + "B"); } } if (!Directory.Exists(ODFileUtils.CombinePaths(textBackupToPath.Text, atozDir))) // D:\OpenDentalData { Directory.CreateDirectory(ODFileUtils.CombinePaths(textBackupToPath.Text, atozDir)); // D:\OpenDentalData } curVal = 0; CopyDirectoryIncremental(ODFileUtils.CombinePaths(atozFull, ""), // C:\OpenDentalData\ ODFileUtils.CombinePaths(new string[] { textBackupToPath.Text, atozDir, "" }), // D:\OpenDentalData\ atozSize); } } catch (ApplicationException ex) { Invoke(new ErrorMessageDelegate(SetErrorMessage), new object[] { ex.Message }); } catch { Invoke(new ErrorMessageDelegate(SetErrorMessage), new object[] { Lan.g(this, "Backing up A to Z images folder failed. User might not have enough permissions or a file might be in use.") }); } //force dialog to close even if no files copied or calculation was slightly off. Invoke(new PassProgressDelegate(PassProgressToDialog), new object[] { 0, "", 0, "" }); }