syncfiles/tech/safe-saving.html
2022-04-14 12:50:38 -04:00

15 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <title>Safe Saving - SyncFiles Documentation</title> <link rel="shortcut icon" href="/syncfiles/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/syncfiles/assets/css/just-the-docs-default.css"> <script type="text/javascript" src="/syncfiles/assets/js/vendor/lunr.min.js"></script> <script type="text/javascript" src="/syncfiles/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.8.0 --> <title>Safe Saving | SyncFiles Documentation</title> <meta name="generator" content="Jekyll v4.2.2" /> <meta property="og:title" content="Safe Saving" /> <meta property="og:locale" content="en_US" /> <meta name="description" content="Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description." /> <meta property="og:description" content="Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description." /> <link rel="canonical" href="https://depp.github.io/syncfiles/tech/safe-saving" /> <meta property="og:url" content="https://depp.github.io/syncfiles/tech/safe-saving" /> <meta property="og:site_name" content="SyncFiles Documentation" /> <meta property="og:type" content="website" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Safe Saving" /> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"WebPage","description":"Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.","headline":"Safe Saving","url":"https://depp.github.io/syncfiles/tech/safe-saving"}</script> <!-- End Jekyll SEO tag --> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> </svg> <div class="side-bar"> <div class="site-header"> <a href="https://depp.github.io/syncfiles/" class="site-title lh-tight"> SyncFiles Documentation </a> <a href="#" id="menu-button" class="site-button"> <svg viewBox="0 0 24 24" class="icon"><use xlink:href="#svg-menu"></use></svg> </a> </div> <nav role="navigation" aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="https://depp.github.io/syncfiles/tech/" class="nav-list-link">Technical Guide</a><ul class="nav-list "><li class="nav-list-item "><a href="https://depp.github.io/syncfiles/tech/archive-formats" class="nav-list-link">Archive Formats</a></li><li class="nav-list-item "><a href="https://depp.github.io/syncfiles/tech/resource-forks" class="nav-list-link">Resource Forks</a></li><li class="nav-list-item "><a href="https://depp.github.io/syncfiles/tech/finder-info" class="nav-list-link">Finder Info</a></li><li class="nav-list-item "><a href="https://depp.github.io/syncfiles/tech/apis" class="nav-list-link">File APIs</a></li><li class="nav-list-item "><a href="https://depp.github.io/syncfiles/tech/filesystems" class="nav-list-link">Filesystems</a></li><li class="nav-list-item active"><a href="https://depp.github.io/syncfiles/tech/safe-saving" class="nav-list-link active">Safe Saving</a></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="https://depp.github.io/syncfiles/" class="nav-list-link">Home</a><ul class="nav-list "></ul></li></ul> </nav> <footer class="site-footer"> This site uses <a href="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer> </div> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search SyncFiles Documentation" aria-label="Search SyncFiles Documentation" autocomplete="off"> <label for="search-input" class="search-label"><svg viewBox="0 0 24 24" class="search-icon"><use xlink:href="#svg-search"></use></svg></label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div id="main-content-wrap" class="main-content-wrap"> <nav aria-label="Breadcrumb" class="breadcrumb-nav"> <ol class="breadcrumb-nav-list"> <li class="breadcrumb-nav-list-item"><a href="https://depp.github.io/syncfiles/tech/">Technical Guide</a></li> <li class="breadcrumb-nav-list-item"><span>Safe Saving</span></li> </ol> </nav> <div id="main-content" class="main-content" role="main"> <h1 id="safe-saving"> <a href="#safe-saving" class="anchor-heading" aria-labelledby="safe-saving"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Safe Saving </h1> <p>There are a number of different goals for when your program saves a file:</p> <ul> <li> <p>I/O errors should be reported. If the data does not make it to disk, then tell the user that the operation failed.</p> </li> <li> <p>Saves are atomic. After saving, you either get the old version of the file or the complete new version of the file. If your program crashes, its okay if the old file is untouched, but its not okay if its been partially overwritten.</p> </li> <li> <p>Saves preserve file references. Any references to a document (aliases or bookmarks) remain valid after modifying the document.</p> </li> <li> <p>Saves do not change the creation date, or other metadata associated with the file.</p> </li> </ul> <p>If your first thought is, “that sounds like it could be complicated”, then youre in good company. Theodore Tso wrote an article in 2009, <a href="https://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/">Dont fear the fsync!</a> which covers some of these issues on Linux in detail.</p> <h2 id="classic-mac-os"> <a href="#classic-mac-os" class="anchor-heading" aria-labelledby="classic-mac-os"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Classic Mac OS </h2> <p>HFS and HFS+ support an operation which exchanges the contents of files. The high-level API call looks like this:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">OSErr</span> <span class="nf">FSpExchangeFiles</span><span class="p">(</span>
<span class="k">const</span> <span class="n">FSSpec</span> <span class="o">*</span> <span class="n">source</span><span class="p">,</span>
<span class="k">const</span> <span class="n">FSSpec</span> <span class="o">*</span> <span class="n">dest</span><span class="p">);</span>
</code></pre></div></div> <p>This function exchanges the <em>contents</em> of the two files (both forks), and exchanges the modification dates, but leaves the other metadata alone.</p> <p>The recipe for safe saving on HFS volumes is:</p> <ol> <li> <p>Save the document to a temporary file on the same volume.</p> </li> <li> <p>Exchange the contents of the original file and the temporary file with <code class="language-plaintext highlighter-rouge">FSpExchangeFiles</code>.</p> </li> </ol> <p>You can test that <code class="language-plaintext highlighter-rouge">FSpExchangeFiles</code> is supported by a volume by getting the volume parameters. Not all filesystems support this operation.</p> <h2 id="mac-os-x"> <a href="#mac-os-x" class="anchor-heading" aria-labelledby="mac-os-x"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Mac OS X </h2> <p>Mac OS X provides a Unix system call that provides the same functionality as <code class="language-plaintext highlighter-rouge">FSpExchangeFiles</code>, but with a Unix API.</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">exchangedata</span><span class="p">(</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">path1</span>
<span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">path2</span><span class="p">,</span>
<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">options</span><span class="p">);</span>
</code></pre></div></div> <p>However, this function does not work on APFS.</p> <h2 id="mac-os-x-106"> <a href="#mac-os-x-106" class="anchor-heading" aria-labelledby="mac-os-x-106"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Mac OS X 10.6+ </h2> <p>Starting on Mac OS X 10.6, the Foundation framework provides a method for safely replacing an item on the filesystem with a new item. This method is present on <code class="language-plaintext highlighter-rouge">NSFileManager</code>:</p> <div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">-</span> <span class="p">(</span><span class="n">BOOL</span><span class="p">)</span><span class="nf">replaceItemAtURL</span><span class="p">:(</span><span class="n">NSURL</span> <span class="o">*</span><span class="p">)</span><span class="nv">originalItemURL</span>
<span class="nf">withItemAtURL</span><span class="p">:(</span><span class="n">NSURL</span> <span class="o">*</span><span class="p">)</span><span class="nv">newItemURL</span>
<span class="nf">backupItemName</span><span class="p">:(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">backupItemName</span>
<span class="nf">options</span><span class="p">:(</span><span class="n">NSFileManagerItemReplacementOptions</span><span class="p">)</span><span class="nv">options</span>
<span class="nf">resultingItemURL</span><span class="p">:(</span><span class="n">NSURL</span> <span class="o">*</span> <span class="n">_Nullable</span> <span class="o">*</span><span class="p">)</span><span class="nv">resultingURL</span>
<span class="nf">error</span><span class="p">:(</span><span class="n">NSError</span> <span class="o">*</span> <span class="n">_Nullable</span> <span class="o">*</span><span class="p">)</span><span class="nv">error</span><span class="p">;</span>
</code></pre></div></div> <p>This method should be preferred for Mac OS X 10.6 and newer. Unlike <code class="language-plaintext highlighter-rouge">exchangedata()</code>, this function works on APFS.</p> </div> </div> <div class="search-overlay"></div> </div> </body> </html>