private async Task <Library.Utility.TempFile> DoGet(FileEntryItem item) { Library.Utility.TempFile tmpfile = null; await m_stats.SendEventAsync(BackendActionType.Get, BackendEventType.Started, item.RemoteFilename, item.Size); try { var begin = DateTime.Now; tmpfile = new Library.Utility.TempFile(); if (m_backend is Library.Interface.IStreamingBackend && !m_options.DisableStreamingTransfers) { using (var fs = System.IO.File.OpenWrite(tmpfile)) using (var ts = new ThrottledStream(fs, m_options.MaxUploadPrSecond, m_options.MaxDownloadPrSecond)) using (var pgs = new Library.Utility.ProgressReportingStream(ts, item.Size, pg => HandleProgress(ts, pg))) ((Library.Interface.IStreamingBackend)m_backend).Get(item.RemoteFilename, pgs); } else { m_backend.Get(item.RemoteFilename, tmpfile); } var duration = DateTime.Now - begin; var filehash = FileEntryItem.CalculateFileHash(tmpfile); Logging.Log.WriteProfilingMessage(LOGTAG, "DownloadSpeed", "Downloaded {0} in {1}, {2}/s", Library.Utility.Utility.FormatSizeString(item.Size), duration, Library.Utility.Utility.FormatSizeString((long)(item.Size / duration.TotalSeconds))); await m_database.LogRemoteOperationAsync("get", item.RemoteFilename, JsonConvert.SerializeObject(new { Size = new System.IO.FileInfo(tmpfile).Length, Hash = filehash })); await m_stats.SendEventAsync(BackendActionType.Get, BackendEventType.Completed, item.RemoteFilename, new System.IO.FileInfo(tmpfile).Length); if (!m_options.SkipFileHashChecks) { var nl = new System.IO.FileInfo(tmpfile).Length; if (item.Size >= 0) { if (nl != item.Size) { throw new Exception(Strings.Controller.DownloadedFileSizeError(item.RemoteFilename, nl, item.Size)); } } else { item.Size = nl; } if (!string.IsNullOrEmpty(item.Hash)) { if (filehash != item.Hash) { throw new Duplicati.Library.Main.BackendManager.HashMismatchException(Strings.Controller.HashMismatchError(tmpfile, item.Hash, filehash)); } } else { item.Hash = filehash; } } // Fast exit if (item.VerifyHashOnly) { return(null); } // Decrypt before returning if (!m_options.NoEncryption) { try { using (var tmpfile2 = tmpfile) { tmpfile = new Library.Utility.TempFile(); // Auto-guess the encryption module var ext = (System.IO.Path.GetExtension(item.RemoteFilename) ?? "").TrimStart('.'); if (!string.Equals(m_options.EncryptionModule, ext, StringComparison.OrdinalIgnoreCase)) { // Check if the file is encrypted with something else if (DynamicLoader.EncryptionLoader.Keys.Contains(ext, StringComparer.OrdinalIgnoreCase)) { using (var encmodule = DynamicLoader.EncryptionLoader.GetModule(ext, m_options.Passphrase, m_options.RawOptions)) if (encmodule != null) { Logging.Log.WriteVerboseMessage(LOGTAG, "AutomaticDecryptionDetection", "Filename extension \"{0}\" does not match encryption module \"{1}\", using matching encryption module", ext, m_options.EncryptionModule); encmodule.Decrypt(tmpfile2, tmpfile); } } // Check if the file is not encrypted else if (DynamicLoader.CompressionLoader.Keys.Contains(ext, StringComparer.OrdinalIgnoreCase)) { Logging.Log.WriteVerboseMessage(LOGTAG, "AutomaticDecryptionDetection", "Filename extension \"{0}\" does not match encryption module \"{1}\", guessing that it is not encrypted", ext, m_options.EncryptionModule); } // Fallback, lets see what happens... else { Logging.Log.WriteVerboseMessage(LOGTAG, "AutomaticDecryptionDetection", "Filename extension \"{0}\" does not match encryption module \"{1}\", attempting to use specified encryption module as no others match", ext, m_options.EncryptionModule); using (var encmodule = DynamicLoader.EncryptionLoader.GetModule(m_options.EncryptionModule, m_options.Passphrase, m_options.RawOptions)) encmodule.Decrypt(tmpfile2, tmpfile); } } else { using (var encmodule = DynamicLoader.EncryptionLoader.GetModule(m_options.EncryptionModule, m_options.Passphrase, m_options.RawOptions)) encmodule.Decrypt(tmpfile2, tmpfile); } } } 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); } } } var res = tmpfile; tmpfile = null; return(res); } finally { try { if (tmpfile != null) { tmpfile.Dispose(); } } catch { } } }
public static void TestBackend(IBackend b) { // Should be empty //~ keys, err := b.List("") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if len(keys) != 0 { //~ t.Fatalf("bad: %v", keys) //~ } var keys = b.List(""); Assert.AreEqual(0, keys.Count()); // Delete should work if it does not exist //~ err = b.Delete("foo") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } b.Delete("foo"); // Get should fail //~ out, err := b.Get("foo") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if out != nil { //~ t.Fatalf("bad: %v", out) //~ } var @out = b.Get("foo"); Assert.IsNull(@out); // Make an entry //~ e := &Entry{Key: "foo", Value: []byte("test")} //~ err = b.Put(e) //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } var e = new Entry { Key = "foo", Value = "test".ToUtf8Bytes() }; b.Put(e); // Get should work //~ out, err = b.Get("foo") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if !reflect.DeepEqual(out, e) { //~ t.Fatalf("bad: %v expected: %v", out, e) //~ } @out = b.Get("foo"); Assert.IsNotNull(@out); // List should not be empty //~ keys, err = b.List("") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if len(keys) != 1 { //~ t.Fatalf("bad: %v", keys) //~ } //~ if keys[0] != "foo" { //~ t.Fatalf("bad: %v", keys) //~ } keys = b.List(""); Assert.AreEqual(1, keys.Count()); Assert.AreEqual("foo", keys.ElementAt(0)); // Delete should work //~ err = b.Delete("foo") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } b.Delete("foo"); // Should be empty //~ keys, err = b.List("") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if len(keys) != 0 { //~ t.Fatalf("bad: %v", keys) //~ } keys = b.List(""); Assert.AreEqual(0, keys.Count()); // Get should fail //~ out, err = b.Get("foo") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if out != nil { //~ t.Fatalf("bad: %v", out) //~ } @out = b.Get("foo"); Assert.IsNull(@out); // Multiple Puts should work; GH-189 //~ e = &Entry{Key: "foo", Value: []byte("test")} //~ err = b.Put(e) //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ e = &Entry{Key: "foo", Value: []byte("test")} //~ err = b.Put(e) //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } e = new Entry { Key = "foo", Value = "test".ToUtf8Bytes() }; b.Put(e); e = new Entry { Key = "foo", Value = "test".ToUtf8Bytes() }; b.Put(e); // Make a nested entry //~ e = &Entry{Key: "foo/bar", Value: []byte("baz")} //~ err = b.Put(e) //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } e = new Entry { Key = "foo/bar", Value = "baz".ToUtf8Bytes() }; b.Put(e); //~ keys, err = b.List("") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if len(keys) != 2 { //~ t.Fatalf("bad: %v", keys) //~ } //~ sort.Strings(keys) //~ if keys[0] != "foo" || keys[1] != "foo/" { //~ t.Fatalf("bad: %v", keys) //~ } keys = b.List(""); Assert.AreEqual(2, keys.Count()); keys = keys.OrderBy(x => x); Assert.AreEqual("foo", keys.ElementAt(0)); Assert.AreEqual("foo/", keys.ElementAt(1)); // Delete with children should work //~ err = b.Delete("foo") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } b.Delete("foo"); // Get should return the child //~ out, err = b.Get("foo/bar") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if out == nil { //~ t.Fatalf("missing child") //~ } @out = b.Get("foo/bar"); Assert.IsNotNull(@out); // Removal of nested secret should not leave artifacts //~ e = &Entry{Key: "foo/nested1/nested2/nested3", Value: []byte("baz")} //~ err = b.Put(e) //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } e = new Entry { Key = "foo/nested1/nested2/nested3", Value = "baz".ToUtf8Bytes() }; b.Put(e); //~ err = b.Delete("foo/nested1/nested2/nested3") //~ if err != nil { //~ t.Fatalf("failed to remove nested secret: %v", err) //~ } b.Delete("foo/nested1/nested2/nested3"); //~ keys, err = b.List("foo/") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } keys = b.List("foo/"); //~ if len(keys) != 1 { //~ t.Fatalf("there should be only one key left after deleting nested "+ //~ "secret: %v", keys) //~ } Assert.AreEqual(1, keys.Count()); //~ if keys[0] != "bar" { //~ t.Fatalf("bad keys after deleting nested: %v", keys) //~ } Assert.AreEqual("bar", keys.ElementAt(0)); // Make a second nested entry to test prefix removal //~ e = &Entry{Key: "foo/zip", Value: []byte("zap")} //~ err = b.Put(e) //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } e = new Entry { Key = "foo/zip", Value = "zap".ToUtf8Bytes() }; b.Put(e); // Delete should not remove the prefix //~ err = b.Delete("foo/bar") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } b.Delete("foo/bar"); //~ keys, err = b.List("") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if len(keys) != 1 { //~ t.Fatalf("bad: %v", keys) //~ } //~ if keys[0] != "foo/" { //~ t.Fatalf("bad: %v", keys) //~ } keys = b.List(""); Assert.AreEqual(1, keys.Count()); Assert.AreEqual("foo/", keys.ElementAt(0)); // Delete should remove the prefix //~ err = b.Delete("foo/zip") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } b.Delete("foo/zip"); //~ keys, err = b.List("") //~ if err != nil { //~ t.Fatalf("err: %v", err) //~ } //~ if len(keys) != 0 { //~ t.Fatalf("bad: %v", keys) //~ } keys = b.List(""); Assert.AreEqual(0, keys.Count()); }