Esempio n. 1
0
        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);
            }
        }
Esempio n. 2
0
        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;
        }
Esempio n. 3
0
        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);
                        }
                    }
                }
            }
        }
Esempio n. 4
0
        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");
            }
        }
Esempio n. 5
0
        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);
        }