public virtual long SizeOverhead(long filesize) { using (Utility.TempFile t1 = new XervBackup.Library.Utility.TempFile()) using (Utility.TempFile t2 = new XervBackup.Library.Utility.TempFile()) { using (System.IO.Stream s1 = System.IO.File.Create(t1)) { long bytesleft = filesize; byte[] buf = new byte[1024]; Random rnd = new Random(); while (bytesleft > 0) { rnd.NextBytes(buf); s1.Write(buf, 0, (int)Math.Min(buf.Length, bytesleft)); bytesleft -= buf.Length; } } Encrypt(t1, t2); return Math.Max(0, new System.IO.FileInfo(t2).Length - filesize); } }
static bool Run(List<string> args, Dictionary<string, string> options, bool first) { string allowedChars = ValidFilenameChars; if (options.ContainsKey("extended-chars")) allowedChars += options["extended-chars"]; else allowedChars += ExtendedChars; bool autoCreateFolders = Library.Utility.Utility.ParseBoolOption(options, "auto-create-folder"); Library.Interface.IBackend backend = Library.DynamicLoader.BackendLoader.GetBackend(args[0], options); if (backend == null) { Console.WriteLine("Unsupported backend"); Console.WriteLine(); Console.WriteLine("Supported backends: " + string.Join(",", XervBackup.Library.DynamicLoader.BackendLoader.Keys)); return false; } string disabledModulesValue; string enabledModulesValue; options.TryGetValue("enable-module", out enabledModulesValue); options.TryGetValue("disable-module", out disabledModulesValue); string[] enabledModules = enabledModulesValue == null ? new string[0] : enabledModulesValue.Trim().ToLower().Split(','); string[] disabledModules = disabledModulesValue == null ? new string[0] : disabledModulesValue.Trim().ToLower().Split(','); List<Library.Interface.IGenericModule> loadedModules = new List<IGenericModule>(); foreach (Library.Interface.IGenericModule m in Library.DynamicLoader.GenericLoader.Modules) if (Array.IndexOf<string>(disabledModules, m.Key.ToLower()) < 0 && (m.LoadAsDefault || Array.IndexOf<string>(enabledModules, m.Key.ToLower()) >= 0)) { m.Configure(options); loadedModules.Add(m); } try { List<Library.Interface.IFileEntry> curlist = null; try { curlist = backend.List(); } catch (FolderMissingException fex) { if (autoCreateFolders) { try { if (backend is IBackend_v2) ((IBackend_v2)backend).CreateFolder(); curlist = backend.List(); } catch (Exception ex) { Console.WriteLine("Autocreate folder failed with message: " + ex.Message); } } if (curlist == null) throw fex; } foreach (Library.Interface.IFileEntry fe in curlist) if (!fe.IsFolder) { if (Library.Utility.Utility.ParseBoolOption(options, "auto-clean") && first) if (Library.Utility.Utility.ParseBoolOption(options, "force")) { Console.WriteLine("Auto clean, removing file: {0}", fe.Name); backend.Delete(fe.Name); continue; } else Console.WriteLine("Specify the --force flag to actually delete files"); Console.WriteLine("*** Remote folder is not empty, aborting"); return false; } int number_of_files = 10; int min_file_size = 1024; int max_file_size = 1024 * 1024 * 50; int min_filename_size = 5; int max_filename_size = 80; bool disableStreaming = Library.Utility.Utility.ParseBoolOption(options, "disable-streaming-transfers"); bool skipOverwriteTest = Library.Utility.Utility.ParseBoolOption(options, "skip-overwrite-test"); if (options.ContainsKey("number-of-files")) number_of_files = int.Parse(options["number-of-files"]); if (options.ContainsKey("min-file-size")) min_file_size = (int)XervBackup.Library.Utility.Sizeparser.ParseSize(options["min-file-size"], "mb"); if (options.ContainsKey("max-file-size")) max_file_size = (int)XervBackup.Library.Utility.Sizeparser.ParseSize(options["max-file-size"]); if (options.ContainsKey("min-filename-length")) min_filename_size = int.Parse(options["min-filename-length"]); if (options.ContainsKey("max-filename-length")) max_filename_size = int.Parse(options["max-filename-length"]); Random rnd = new Random(); System.Security.Cryptography.SHA256 sha = System.Security.Cryptography.SHA256.Create(); //Create random files using (Library.Utility.TempFolder tf = new XervBackup.Library.Utility.TempFolder()) { List<TempFile> files = new List<TempFile>(); for (int i = 0; i < number_of_files; i++) { StringBuilder filename = new StringBuilder(); int filenamelen = rnd.Next(min_filename_size, max_filename_size); for (int j = 0; j < filenamelen; j++) filename.Append(allowedChars[rnd.Next(0, allowedChars.Length)]); string localfilename = CreateRandomFile(tf, i, min_file_size, max_file_size, rnd); //Calculate local hash and length using (System.IO.FileStream fs = new System.IO.FileStream(localfilename, System.IO.FileMode.Open, System.IO.FileAccess.Read)) files.Add(new TempFile(filename.ToString(), localfilename, sha.ComputeHash(fs), fs.Length)); } byte[] dummyFileHash = null; if (!skipOverwriteTest) { Console.WriteLine("Uploading wrong files ..."); using (Library.Utility.TempFile dummy = new Library.Utility.TempFile(CreateRandomFile(tf, files.Count, 1024, 2048, rnd))) { using (System.IO.FileStream fs = new System.IO.FileStream(dummy, System.IO.FileMode.Open, System.IO.FileAccess.Read)) dummyFileHash = sha.ComputeHash(fs); //Upload a dummy file for entry 0 and the last one, they will be replaced by the real files afterwards //We upload entry 0 twice just to try to freak any internal cache list Uploadfile(dummy, 0, files[0].remotefilename, backend, disableStreaming); Uploadfile(dummy, 0, files[0].remotefilename, backend, disableStreaming); Uploadfile(dummy, files.Count - 1, files[files.Count - 1].remotefilename, backend, disableStreaming); } } Console.WriteLine("Uploading files ..."); for (int i = 0; i < files.Count; i++) Uploadfile(files[i].localfilename, i, files[i].remotefilename, backend, disableStreaming); Console.WriteLine("Verifying file list ..."); curlist = backend.List(); foreach (Library.Interface.IFileEntry fe in curlist) if (!fe.IsFolder) { bool found = false; foreach (TempFile tx in files) if (tx.remotefilename == fe.Name) { if (tx.found) Console.WriteLine("*** File with name {0} was found more than once", tx.remotefilename); found = true; tx.found = true; if (fe.Size > 0 && tx.length != fe.Size) Console.WriteLine("*** File with name {0} has size {1} but the size was reported as {2}", tx.remotefilename, tx.length, fe.Size); break; } if (!found) Console.WriteLine("*** File with name {0} was found on server but not uploaded!", fe.Name); } foreach (TempFile tx in files) if (!tx.found) Console.WriteLine("*** File with name {0} was uploaded but not found afterwards", tx.remotefilename); Console.WriteLine("Downloading files"); for (int i = 0; i < files.Count; i++) { using (XervBackup.Library.Utility.TempFile cf = new XervBackup.Library.Utility.TempFile()) { Exception e = null; Console.Write("Downloading file {0} ... ", i); try { if (backend is Library.Interface.IStreamingBackend && !disableStreaming) { using (System.IO.FileStream fs = new System.IO.FileStream(cf, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None)) using (NonSeekableStream nss = new NonSeekableStream(fs)) (backend as Library.Interface.IStreamingBackend).Get(files[i].remotefilename, nss); } else backend.Get(files[i].remotefilename, cf); e = null; } catch (Exception ex) { e = ex; } if (e != null) Console.WriteLine("failed\n*** Error: {0}", e.ToString()); else Console.WriteLine("done"); Console.Write("Checking hash ... "); using (System.IO.FileStream fs = new System.IO.FileStream(cf, System.IO.FileMode.Open, System.IO.FileAccess.Read)) if (Convert.ToBase64String(sha.ComputeHash(fs)) != Convert.ToBase64String(files[i].hash)) { if (dummyFileHash != null && Convert.ToBase64String(sha.ComputeHash(fs)) == Convert.ToBase64String(dummyFileHash)) Console.WriteLine("failed\n*** Downloaded file was the dummy file"); else Console.WriteLine("failed\n*** Downloaded file was corrupt"); } else Console.WriteLine("done"); } } Console.WriteLine("Deleting files..."); foreach (TempFile tx in files) try { backend.Delete(tx.remotefilename); } catch (Exception ex) { Console.WriteLine("*** Failed to delete file {0}, message: {1}", tx.remotefilename, ex.ToString()); } curlist = backend.List(); foreach (Library.Interface.IFileEntry fe in curlist) if (!fe.IsFolder) { Console.WriteLine("*** Remote folder contains {0} after cleanup", fe.Name); } } } finally { foreach (Library.Interface.IGenericModule m in loadedModules) if (m is IDisposable) ((IDisposable)m).Dispose(); } return true; }
private void Put(BackupEntryBase remote, string filename, bool forcesync) { if (!remote.IsEncrypted && !m_options.NoEncryption && remote as VerificationEntry == null) { if (m_encryption == null) m_encryption = DynamicLoader.EncryptionLoader.GetModule(m_options.EncryptionModule, m_options.Passphrase, m_options.RawOptions); using (Utility.TempFile raw = new XervBackup.Library.Utility.TempFile(filename)) using (Utility.TempFile enc = new XervBackup.Library.Utility.TempFile()) { m_encryption.Encrypt(raw, enc); filename = enc; enc.Protected = true; raw.Protected = false; } remote.IsEncrypted = true; } remote.RemoteHash = Utility.Utility.CalculateHash(filename); remote.Filename = GenerateFilename(remote); remote.Filesize = new System.IO.FileInfo(filename).Length; if (!m_async) PutInternal(remote, filename); else { if (forcesync) { int count; lock (m_queuelock) count = m_pendingOperations.Count; while (count > 0) { m_asyncItemProcessed.WaitOne(1000 * 5, false); lock (m_queuelock) count = m_pendingOperations.Count; } PutInternal(remote, filename); } else { bool waitForCompletion; //There are 3 files in a volume (signature, content and manifest) + a verification file int uploads_in_set = m_options.CreateVerificationFile ? 4 : 3; lock (m_queuelock) { if (m_workerException != null) throw m_workerException; m_pendingOperations.Enqueue(new KeyValuePair<BackupEntryBase, string>(remote, filename)); m_asyncItemReady.Set(); waitForCompletion = m_options.AsynchronousUploadLimit > 0 && m_pendingOperations.Count > (m_options.AsynchronousUploadLimit * uploads_in_set); } while (waitForCompletion) { m_asyncItemProcessed.WaitOne(1000 * 5, false); lock (m_queuelock) { if (m_workerException != null) throw m_workerException; waitForCompletion = m_options.AsynchronousUploadLimit > 0 && m_pendingOperations.Count > (m_options.AsynchronousUploadLimit * uploads_in_set); } } } } }
public static void CompileResxFiles(string folder, List<string> excludeFolders, string @namespace, string assemblyname, string versionAssembly, string keyfile, string culture, string productname) { string resgenexe; string alexe; if (XervBackup.Library.Utility.Utility.IsClientLinux) { resgenexe = ExecuteAndRead("which", "resgen"); alexe = ExecuteAndRead("which", "al"); } else //Windows { //Order of these paths is also the search order string[] known_sdk_paths = { Environment.ExpandEnvironmentVariables("%WINDIR%\\Microsoft.Net\\Framework\\v4.0\\"), Environment.ExpandEnvironmentVariables("%WINDIR%\\Microsoft.Net\\Framework\\v4.0.30319\\"), Environment.ExpandEnvironmentVariables("%WINDIR%\\Microsoft.Net\\Framework\\v3.5\\"), Environment.ExpandEnvironmentVariables("%WINDIR%\\Microsoft.Net\\Framework\\v3.0\\"), Environment.ExpandEnvironmentVariables("%WINDIR%\\Microsoft.Net\\Framework\\v2.0.50727\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES%\\Microsoft SDKs\\Windows\\v8.0A\\bin\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES%\\Microsoft SDKs\\Windows\\v7.1\\Bin\\NETFX 4.0 Tools\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES%\\Microsoft SDKs\\Windows\\v7.0A\\bin\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES%\\Microsoft SDKs\\Windows\\v6.0A\\bin\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES%\\Microsoft.NET\\SDK\\v2.0\\bin\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES(X86)%\\Microsoft SDKs\\Windows\\v8.0A\\bin\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES(X86)%\\Microsoft SDKs\\Windows\\v7.1\\Bin\\NETFX 4.0 Tools\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES(X86)%\\Microsoft SDKs\\Windows\\v7.0A\\bin\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES(X86)%\\Microsoft SDKs\\Windows\\v6.0A\\bin\\"), Environment.ExpandEnvironmentVariables("%PROGRAMFILES(X86)%\\Microsoft.NET\\SDK\\v2.0\\bin\\"), }; resgenexe = "resgen.exe"; alexe = "al.exe"; foreach(var p in known_sdk_paths) if (System.IO.File.Exists(System.IO.Path.Combine(p, resgenexe))) { resgenexe = System.IO.Path.Combine(p, resgenexe); break; } foreach (var p in known_sdk_paths) if (System.IO.File.Exists(System.IO.Path.Combine(p, alexe))) { alexe = System.IO.Path.Combine(p, alexe); break; } } if (!System.IO.File.Exists(resgenexe)) { Console.WriteLine("Unable to locate file: {0}", resgenexe); Console.WriteLine("This can be fixed by installing a microsoft platform SDK, or visual studio (express is fine)"); return; } if (!System.IO.File.Exists(alexe)) { Console.WriteLine("Unable to locate file: {0}", alexe); Console.WriteLine("This can be fixed by installing the .Net framework version 2.0"); return; } if (!string.IsNullOrEmpty(keyfile) && XervBackup.Library.Utility.Utility.IsClientLinux) keyfile = keyfile.Replace("\\", System.IO.Path.DirectorySeparatorChar.ToString()); List<string> resources = new List<string>(); folder = XervBackup.Library.Utility.Utility.AppendDirSeparator(folder); foreach (string s in XervBackup.Library.Utility.Utility.EnumerateFiles(folder)) { if (s.ToLower().EndsWith("." + culture.ToLower() + ".resx")) { if (excludeFolders.Any(xf => s.ToLower().StartsWith(XervBackup.Library.Utility.Utility.AppendDirSeparator(xf).ToLower()))) continue; string resname = System.IO.Path.ChangeExtension(s, ".resources"); if (!System.IO.File.Exists(resname) || System.IO.File.GetLastWriteTime(resname) < System.IO.File.GetLastWriteTime(s)) { Console.WriteLine("Compiling: " + s); System.Diagnostics.ProcessStartInfo pi = new System.Diagnostics.ProcessStartInfo(resgenexe, "\"" + s + "\""); pi.CreateNoWindow = true; pi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; pi.RedirectStandardOutput = true; pi.RedirectStandardError = true; pi.UseShellExecute = false; pi.WorkingDirectory = System.IO.Path.GetDirectoryName(s); System.Diagnostics.Process pr = System.Diagnostics.Process.Start(pi); pr.WaitForExit(); if (pr.ExitCode != 0) { Console.WriteLine("Error"); Console.WriteLine(pr.StandardOutput.ReadToEnd()); Console.WriteLine(pr.StandardError.ReadToEnd()); throw new Exception("Resgen failure: " + s); } } else Console.WriteLine("Not modified: " + s); resources.Add(resname); } } if (resources.Count == 0) return; if (!System.IO.File.Exists(versionAssembly) && XervBackup.Library.Utility.Utility.IsClientLinux) versionAssembly = versionAssembly.Replace("\\", System.IO.Path.DirectorySeparatorChar.ToString()); if (!System.IO.File.Exists(versionAssembly)) { Console.WriteLine("Unable to locate file: {0}", versionAssembly); Console.WriteLine("This can be fixed by compiling the application or modifying the file configuration.xml"); return; } using (XervBackup.Library.Utility.TempFile tf = new XervBackup.Library.Utility.TempFile()) { using (System.IO.StreamWriter sw = new System.IO.StreamWriter(tf)) { System.Reflection.Assembly asm = System.Reflection.Assembly.ReflectionOnlyLoadFrom(versionAssembly); sw.WriteLine("/t:lib"); sw.WriteLine("/out:\"" + assemblyname + "\""); sw.WriteLine("/product:\"" + productname + "\""); sw.WriteLine("/title:\"" + productname + "\""); sw.WriteLine("/version:" + asm.GetName().Version.ToString()); if (!string.IsNullOrEmpty(keyfile)) sw.WriteLine("/keyfile:\"" + keyfile + "\""); sw.WriteLine("/culture:" + culture); foreach (string s in resources) { string resname = s.Substring(folder.Length); resname = resname.Replace("\\", "."); resname = resname.Replace(" ", "_"); resname = @namespace + "." + resname; sw.WriteLine("/embed:\"" + s + "\"," + resname); } } Console.WriteLine("Linking ..."); System.Diagnostics.ProcessStartInfo pi = new System.Diagnostics.ProcessStartInfo(alexe, "@\"" + tf + "\""); pi.CreateNoWindow = true; pi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; System.Diagnostics.Process pr = System.Diagnostics.Process.Start(pi); pr.WaitForExit(); if (pr.ExitCode != 0) throw new Exception("Linker failure"); } }
private void GetInternal(BackupEntryBase remote, Manifestfile manifest, string filename, Manifestfile.HashEntry hash) { int retries = m_options.NumberOfRetries; Exception lastEx = null; m_statusmessage = string.Format(Strings.BackendWrapper.StatusMessageDownloading, remote.Filename); do { try { if (manifest != null && !string.IsNullOrEmpty(m_options.SignatureCachePath) && hash != null && remote is SignatureEntry) { string cachefilename = FindCacheEntry(remote as SignatureEntry); if (cachefilename != null && System.IO.File.Exists(cachefilename)) { if ((hash.Size < 0 || new System.IO.FileInfo(cachefilename).Length == hash.Size) && Utility.Utility.CalculateHash(cachefilename) == hash.Hash) { if (manifest.Version > 2 && !string.IsNullOrEmpty(remote.EncryptionMode)) { try { using (Library.Interface.IEncryption enc = DynamicLoader.EncryptionLoader.GetModule(remote.EncryptionMode, m_options.Passphrase, m_options.RawOptions)) enc.Decrypt(cachefilename, filename); return; } catch (Exception ex) { m_statistics.LogWarning(string.Format(Strings.BackendWrapper.CachedSignatureDecryptWarning, cachefilename, ex.Message), null); try { System.IO.File.Delete(cachefilename); } catch { } } } else { //TODO: Don't copy, but just return it as write protected System.IO.File.Copy(cachefilename, filename, true); return; } } else { m_statistics.LogWarning(string.Format(Strings.BackendWrapper.CachedSignatureHashMismatchWarning, cachefilename), null); try { System.IO.File.Delete(cachefilename); } catch { } } } } Utility.TempFile tempfile = null; try { if (!string.IsNullOrEmpty(remote.EncryptionMode)) tempfile = new XervBackup.Library.Utility.TempFile(); else tempfile = new XervBackup.Library.Utility.TempFile(filename); ResetBackend(); m_statistics.AddNumberOfRemoteCalls(1); if (m_backend is XervBackup.Library.Interface.IStreamingBackend && !m_options.DisableStreamingTransfers) { using (System.IO.FileStream fs = System.IO.File.Open(tempfile, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None)) using (Utility.ProgressReportingStream pgs = new XervBackup.Library.Utility.ProgressReportingStream(fs, remote.Fileentry.Size)) using (Utility.ThrottledStream ts = new XervBackup.Library.Utility.ThrottledStream(pgs, m_options.MaxUploadPrSecond, m_options.MaxDownloadPrSecond)) { pgs.Progress += new XervBackup.Library.Utility.ProgressReportingStream.ProgressDelegate(pgs_Progress); ts.Callback += new XervBackup.Library.Utility.ThrottledStream.ThrottledStreamCallback(ThrottledStream_Callback); ((XervBackup.Library.Interface.IStreamingBackend)m_backend).Get(remote.Filename, ts); } } else { if (!m_async && ProgressEvent != null) ProgressEvent(50, m_statusmessage); m_backend.Get(remote.Filename, tempfile); if (!m_async && ProgressEvent != null) ProgressEvent(100, m_statusmessage); } //This is required so we are sure that the file was downloaded completely and not partially, // as any exception here will cause a retry, but using a partial file may cause random errors if (remote.Fileentry.Size > 0 && remote.Fileentry.Size != new System.IO.FileInfo(tempfile).Length) throw new Exception(string.Format(Strings.BackendWrapper.DownloadedFileSizeError, remote.Filename, remote.Fileentry.Size, new System.IO.FileInfo(tempfile).Length)); remote.RemoteHash = Utility.Utility.CalculateHash(tempfile); //Manifest version 3 has hashes WITH encryption if (manifest != null && manifest.Version > 2) { if (hash != null && remote.RemoteHash != hash.Hash) throw new HashMismathcException(string.Format(Strings.BackendWrapper.HashMismatchError, remote.Filename, hash.Hash, Utility.Utility.CalculateHash(tempfile))); if (!string.IsNullOrEmpty(m_options.SignatureCachePath) && remote is SignatureEntry) { string cachefilename = System.IO.Path.Combine(m_options.SignatureCachePath, m_cachefilenamestrategy.GenerateFilename(remote)); try { System.IO.File.Copy(tempfile, cachefilename, true); } catch (Exception ex) { m_statistics.LogWarning(string.Format(Strings.BackendWrapper.SaveCacheFileError, cachefilename), ex); } } } if (!string.IsNullOrEmpty(remote.EncryptionMode)) { try { using (Library.Interface.IEncryption enc = DynamicLoader.EncryptionLoader.GetModule(remote.EncryptionMode, m_options.Passphrase, m_options.RawOptions)) enc.Decrypt(tempfile, filename); } catch (Exception ex) { //If we fail here, make sure that we throw a crypto exception if (ex is System.Security.Cryptography.CryptographicException) throw; else throw new System.Security.Cryptography.CryptographicException(ex.Message, ex); } tempfile.Dispose(); //Remove the encrypted file //Wrap the new file as a temp file tempfile = new XervBackup.Library.Utility.TempFile(filename); } //Manifest version 1+2 has hashes WITHOUT encryption if (manifest != null && manifest.Version <= 2) { if (hash != null && Utility.Utility.CalculateHash(tempfile) != hash.Hash) throw new HashMismathcException(string.Format(Strings.BackendWrapper.HashMismatchError, remote.Filename, hash.Hash, Utility.Utility.CalculateHash(tempfile))); if (!string.IsNullOrEmpty(m_options.SignatureCachePath) && remote is SignatureEntry) { string cachefilename = System.IO.Path.Combine(m_options.SignatureCachePath, m_cachefilenamestrategy.GenerateFilename(remote)); try { System.IO.File.Copy(tempfile, cachefilename, true); } catch (Exception ex) { m_statistics.LogWarning(string.Format(Strings.BackendWrapper.SaveCacheFileError, cachefilename), ex); } } } lastEx = null; tempfile.Protected = true; //Don't delete it if (m_backendInterfaceLogger != null) { if (remote is ManifestEntry) m_backendInterfaceLogger.RegisterGet(remote.Fileentry, true, System.IO.File.ReadAllText(tempfile)); else m_backendInterfaceLogger.RegisterGet(remote.Fileentry, true, null); } } finally { try { if (tempfile != null) tempfile.Dispose(); } catch { } } } catch (System.Threading.ThreadAbortException tex) { if (m_backendInterfaceLogger != null) m_backendInterfaceLogger.RegisterGet(remote.Fileentry, false, tex.ToString()); throw; } catch (Exception ex) { lastEx = ex; m_statistics.LogRetryAttempt(ex.Message, ex); if (m_backendInterfaceLogger != null) m_backendInterfaceLogger.RegisterGet(remote.Fileentry, false, ex.ToString()); DisposeBackend(); retries--; if (retries > 0 && m_options.RetryDelay.Ticks > 0) System.Threading.Thread.Sleep(m_options.RetryDelay); } } while (lastEx != null && retries > 0); if (lastEx != null) if (lastEx is HashMismathcException) throw lastEx; else if (lastEx is System.Security.Cryptography.CryptographicException) throw lastEx; else throw new Exception(string.Format(Strings.BackendWrapper.FileDownloadError2, filename, lastEx.Message), lastEx); m_statistics.AddBytesDownloaded(new System.IO.FileInfo(filename).Length); }