Beispiel #1
0
        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());
        }