[f-spot/taglib-metadata: 9/20] Implement a safe writing pattern for GIOTagLibFileAbstraction.



commit 2b03a815c529523c599fd826888482ce81bee922
Author: Ruben Vermeersch <ruben savanne be>
Date:   Sun Jun 13 16:32:55 2010 +0200

    Implement a safe writing pattern for GIOTagLibFileAbstraction.

 src/Utils/GIOTagLibFileAbstraction.cs |   47 ++++++++++++++++++++++++++++++--
 1 files changed, 44 insertions(+), 3 deletions(-)
---
diff --git a/src/Utils/GIOTagLibFileAbstraction.cs b/src/Utils/GIOTagLibFileAbstraction.cs
index 1f559a5..d66c624 100644
--- a/src/Utils/GIOTagLibFileAbstraction.cs
+++ b/src/Utils/GIOTagLibFileAbstraction.cs
@@ -5,9 +5,21 @@ using Hyena;
 
 namespace FSpot.Utils
 {
+    /// <summary>
+    ///   Wraps GIO into a TagLib IFileAbstraction.
+    /// </summary>
+    /// <remarks>
+    ///   Implements a safe writing pattern by first copying the file to a
+    ///   temporary location. This temporary file is used for writing. When the
+    ///   stream is closed, the temporary file is moved to the original
+    ///   location.
+    /// </remarks>
     public sealed class GIOTagLibFileAbstraction : TagLib.File.IFileAbstraction
     {
         private GioStream stream;
+        private SafeUri tmp_write_uri;
+
+        private const string TMP_INFIX = ".tmpwrite";
 
         public string Name {
             get {
@@ -33,8 +45,9 @@ namespace FSpot.Utils
         public Stream WriteStream {
             get {
                 if (stream == null) {
-                    var file = FileFactory.NewForUri (Uri);
-                    stream = new GioStream (file.ReplaceReadwrite (null, true, FileCreateFlags.None, null));
+                    CopyToTmp ();
+                    var file = FileFactory.NewForUri (tmp_write_uri);
+                    stream = new GioStream (file.OpenReadwrite (null));
                 }
                 if (!stream.CanWrite) {
                     throw new Exception ("Stream still open in reading mode!");
@@ -43,11 +56,39 @@ namespace FSpot.Utils
             }
         }
 
+        private void CopyToTmp ()
+        {
+            tmp_write_uri = CreateTmpFile ();
+            var file = FileFactory.NewForUri (Uri);
+            var tmp_file = FileFactory.NewForUri (tmp_write_uri);
+
+            file.Copy (tmp_file, GLib.FileCopyFlags.AllMetadata | GLib.FileCopyFlags.Overwrite, null, null);
+        }
+
+        private void CommitTmp ()
+        {
+            var file = FileFactory.NewForUri (Uri);
+            var tmp_file = FileFactory.NewForUri (tmp_write_uri);
+
+            tmp_file.Copy (file, GLib.FileCopyFlags.AllMetadata | GLib.FileCopyFlags.Overwrite, null, null);
+        }
+
+        private SafeUri CreateTmpFile ()
+        {
+            var uri = Uri.GetBaseUri ().Append (Uri.GetFilenameWithoutExtension ());
+            var tmp_uri = uri.ToString () + TMP_INFIX + Uri.GetExtension ();
+            return new SafeUri (tmp_uri, true);
+        }
+
         public void CloseStream (Stream stream)
         {
             stream.Close ();
-            if (stream == this.stream)
+            if (stream == this.stream) {
+                if (stream.CanWrite) {
+                    CommitTmp ();
+                }
                 this.stream = null;
+            }
         }
     }
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]