{"id":57,"date":"2010-05-18T19:11:00","date_gmt":"2010-05-18T17:11:00","guid":{"rendered":"http:\/\/dev.bratched.fr\/en\/?p=57"},"modified":"2010-05-18T19:11:00","modified_gmt":"2010-05-18T17:11:00","slug":"transactional-ntfs-part-12","status":"publish","type":"post","link":"https:\/\/bratched.com\/en\/2010\/05\/18\/transactional-ntfs-part-12\/","title":{"rendered":"Transactional NTFS (part 1\/2)"},"content":{"rendered":"<h1>Transactional NTFS and DotNet<\/h1>\n<p>Starting from Windows Vista and Windows Server 2008, Microsoft introduced a great new feature called <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363764(VS.85).aspx\" rel=\"nofollow\">Transactional NTFS<\/a> (TxF).<\/p>\n<p>It allows developers to write file I\/O functions that are guaranteed to either succeed completely or fail completely.<br \/>\nUnfortunately there are no classes in the .NET framework that would allows us to perform, such operations.<br \/>\nWe need to resort to P\/Invoke to use the newly introduced functions <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa366011(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">CreateTransaction<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa366001(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">CommitTransaction<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa366366(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">RollbackTransaction<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363916(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">DeleteFileTransacted<\/a>.<!--more--><\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:213de820-e122-453a-83a2-b1d276e57746\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre class=\"lang:default decode:true\">class Win32Native\n    {\n        [StructLayout(LayoutKind.Sequential)]\n        public struct SECURITY_ATTRIBUTES\n        {\n            int nLength;\n            IntPtr lpSecurityDescriptor;\n            int bInheritHandle;\n        }\n\n        [DllImport(\"ktmw32.dll\", SetLastError = true, CharSet = CharSet.Auto)]\n        public static extern SafeFileHandle CreateTransaction(SECURITY_ATTRIBUTES securityAttributes, IntPtr guid, int options, int isolationLevel, int isolationFlags, int milliSeconds, string description);\n\n        [DllImport(\"ktmw32.dll\", SetLastError = true, CharSet = CharSet.Auto)]\n        public static extern bool CommitTransaction(SafeFileHandle transaction);\n\n        [DllImport(\"ktmw32.dll\", SetLastError = true, CharSet = CharSet.Auto)]\n        public static extern bool RollbackTransaction(SafeFileHandle transaction);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, CharSet = CharSet.Auto)]\n        public static extern bool DeleteFileTransacted(string filename, SafeFileHandle transaction);\n    }<\/pre>\n<\/div>\n<p>Note that I am using <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.win32.safehandles.safefilehandle.aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">SafeFileHandle<\/a> in method signatures instead of <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.intptr(VS.71).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">IntPtr<\/a> to hold unmanaged resources which guarantees that they will be properly disposed even if the AppDomain was to stop.<\/p>\n<p>The next thing is to define a helper class which would allow us to easily invoke those functions:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:4290e31e-f0c3-4ba8-bc6e-66a43e71bb5c\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre class=\"lang:default decode:true\">public class FileManager : IDisposable\n    {\n        private bool _commited = false;\n        private SafeFileHandle _tx = null;\n\n        public FileManager()\n        {\n            _tx = Win32Native.CreateTransaction(new Win32Native.SECURITY_ATTRIBUTES(), IntPtr.Zero, 0, 0, 0, 0, null);\n        }\n\n        public bool DeleteFile(string filename)\n        {\n            return Win32Native.DeleteFileTransacted(filename, _tx);\n        }\n\n        public void Commit()\n        {\n            if (Win32Native.CommitTransaction(_tx))\n                _commited = true;\n        }\n\n        private void Rollback()\n        {\n            Win32Native.RollbackTransaction(_tx);\n        }\n\n        protected virtual void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                if (!_commited)\n                {\n                    Rollback();\n                }\n            }\n        }\n\n        public void Dispose()\n        {\n            Dispose(true);\n        }\n    }<\/pre>\n<\/div>\n<h1>Sample with delete two files<\/h1>\n<p>Now suppose that you need to atomically delete two files: either both files are deleted or neither of them, but you never want to have only one of the two files deleted:<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:9169fafe-54c8-4c20-a946-a84bf4b4635c\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre class=\"lang:default decode:true crayon-selected\">using (FileManager manager = new FileManager())\n    {\n        manager.DeleteFile(\"file1.txt\");\n        Console.WriteLine(\"file1.txt is marked for deletion in current transaction. Press Enter...\");\n        Console.ReadLine();\n\n        \/\/throw new Exception(\"something very bad happens here\");\n\n        manager.DeleteFile(\"file2.txt\");\n        Console.WriteLine(\"file2.txt is marked for deletion in current transaction.\");\n\n        manager.Commit();\n    }<\/pre>\n<\/div>\n<p>The method DeleteFile marks the file for deletion in the current transaction, but it will physically delete it only when the Commit method is called. Thanks to TxF and distributed transactions file and SQL operations can be performed inside the same transaction.<\/p>\n<p>In part 2 we will see how to use the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363859(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">CreateFileTransacted<\/a> function to perform atomic file read\/writes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Transactional NTFS and DotNet Starting from Windows Vista and Windows Server 2008, Microsoft introduced a great new feature called Transactional NTFS (TxF). It allows developers to write file I\/O functions that are guaranteed to either succeed completely or fail completely. Unfortunately there are no classes in the .NET framework that would allows us to perform, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[263,266],"tags":[284,319],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/57"}],"collection":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/comments?post=57"}],"version-history":[{"count":0,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/posts\/57\/revisions"}],"wp:attachment":[{"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/media?parent=57"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/categories?post=57"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bratched.com\/en\/wp-json\/wp\/v2\/tags?post=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}