<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:media="http://search.yahoo.com/mrss/"
>

<channel>
	<title>FileManager &#8211; Wade Tregaskis</title>
	<atom:link href="https://wadetregaskis.com/tags/filemanager/feed/" rel="self" type="application/rss+xml" />
	<link>https://wadetregaskis.com</link>
	<description></description>
	<lastBuildDate>Mon, 20 May 2024 03:37:59 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://wadetregaskis.com/wp-content/uploads/2016/03/Stitch-512x512-1-256x256.png</url>
	<title>FileManager &#8211; Wade Tregaskis</title>
	<link>https://wadetregaskis.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">226351702</site>	<item>
		<title>Copy-on-write on APFS</title>
		<link>https://wadetregaskis.com/copy-on-write-on-apfs/</link>
					<comments>https://wadetregaskis.com/copy-on-write-on-apfs/#respond</comments>
		
		<dc:creator><![CDATA[]]></dc:creator>
		<pubDate>Thu, 16 May 2024 21:14:10 +0000</pubDate>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Education]]></category>
		<category><![CDATA[Howto]]></category>
		<category><![CDATA[APFS]]></category>
		<category><![CDATA[clonefile]]></category>
		<category><![CDATA[copy-on-write]]></category>
		<category><![CDATA[copyfile]]></category>
		<category><![CDATA[FileManager]]></category>
		<category><![CDATA[Foundation]]></category>
		<guid isPermaLink="false">https://wadetregaskis.com/?p=8138</guid>

					<description><![CDATA[APFS (like many modern file systems but unlike its predecessor HFS+) supports copy-on-write. This means you can logically copy a file &#8211; it looks and behaves like a distinct file &#8211; but it doesn&#8217;t immediately copy the file&#8217;s contents on disk &#8211; it merely shares them with the original. Only if and as you modify&#8230; <a class="read-more-link" href="https://wadetregaskis.com/copy-on-write-on-apfs/" data-wpel-link="internal">Read more</a>]]></description>
										<content:encoded><![CDATA[
<p><a href="https://en.wikipedia.org/wiki/Apple_File_System" data-wpel-link="external" target="_blank" rel="external noopener">APFS</a> (like many modern file systems but unlike its predecessor <a href="https://en.wikipedia.org/wiki/HFS_Plus" data-wpel-link="external" target="_blank" rel="external noopener">HFS+</a>) supports <a href="https://eclecticlight.co/2017/06/23/what-is-copy-on-write-and-how-is-it-good/" data-wpel-link="external" target="_blank" rel="external noopener">copy-on-write</a>.  This means you can <em>logically</em> copy a file &#8211; it <em>looks</em> and <em>behaves</em> like a distinct file &#8211; but it doesn&#8217;t <em>immediately</em> copy the file&#8217;s contents on disk &#8211; it merely shares them with the original.  Only if and as you modify either version do they start to diverge on disk, with APFS dynamically allocating new storage for the modified parts<sup data-fn="fd9542d5-ca23-49bc-ae00-3d2b57caf906" class="fn"><a href="#fd9542d5-ca23-49bc-ae00-3d2b57caf906" id="fd9542d5-ca23-49bc-ae00-3d2b57caf906-link">1</a></sup>.</p>



<p>This is kind of a sister function to hard links, which similarly avoid copying the file&#8217;s contents <em>but</em> where modifications apply to <em>all</em> copies.  See also <a href="https://eclecticlight.co/2019/01/05/aliases-hard-links-symlinks-and-copies-in-mojaves-apfs/" data-wpel-link="external" target="_blank" rel="external noopener">this article on the differences</a>, including versus aliases and symlinks.</p>



<p>Copy-on-write is beneficial for several reasons:</p>



<ul class="wp-block-list">
<li>Copies don&#8217;t take up any significant space (just whatever tiny amount is necessary for their metadata).</li>



<li>The initial copy operation is practically instantaneous (just a few small metadata writes &amp; updates).</li>



<li>Deferring (if not entirely avoiding) the actual disk I/O reduces wear on the disk.</li>



<li>The copies can share common segments, saving disk space even when they&#8217;re not ultimately identical copies.</li>
</ul>



<p>It does have some potential downsides:</p>



<ul class="wp-block-list">
<li>You don&#8217;t get the increased data redundancy and error resilience that <em>actual</em> copies provide (although if you&#8217;re aiming for data redundancy or backup, you should be using separate physical disks anyway).</li>



<li>It can make subsequent modifications of the file slower, as even just modifying a single byte can trigger the actual copy to be performed.</li>
</ul>



<p>And some basic limitations:</p>



<ul class="wp-block-list">
<li>It&#8217;s only supported on APFS (and <em>maybe</em> additional file systems added by 3rd party extensions, but I haven&#8217;t tested nor can I find any accounts of this).</li>



<li>It only works within individual volumes (it doesn&#8217;t work even between two volumes in the same APFS container, or sharing the same physical disk).</li>
</ul>



<p>Contrary to what I saw online in a few places, copy-on-write works on <em>all</em> APFS volumes, irrespective of whether they are backed by SSDs, HDDs, or some other type of storage.</p>



<h2 class="wp-block-heading">Should I use it?</h2>



<p>Yes!</p>



<p>For most purposes those downsides aren&#8217;t an issue, and the limitations merely mean that it&#8217;s wise to have a fallback option (of just copying the actual file contents) whenever copy-on-write isn&#8217;t available.  And many of the tools &amp; APIs fallback automatically (unless you explicitly require them not to, such as with <code>COPYFILE_CLONE_FORCE</code> to <code>copyfile</code>).</p>



<h2 class="wp-block-heading">How do I use it?</h2>



<figure class="wp-block-table aligncenter"><table><thead><tr><th>Method</th><th class="has-text-align-center" data-align="center">Uses copy-on-write<br>(where possible)</th><th class="has-text-align-center" data-align="center">Does actual copy<br>if copy-on-write<br> isn&#8217;t available</th></tr></thead><tbody><tr><td>cp</td><td class="has-text-align-center" data-align="center">❌</td><td class="has-text-align-center" data-align="center">N/A</td></tr><tr><td>cp -c</td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">❌</td></tr><tr><td>ditto</td><td class="has-text-align-center" data-align="center">❌</td><td class="has-text-align-center" data-align="center">N/A</td></tr><tr><td>ditto &#8211;clone</td><td class="has-text-align-center" data-align="center">❌</td><td class="has-text-align-center" data-align="center">N/A</td></tr><tr><td>dd</td><td class="has-text-align-center" data-align="center">❌</td><td class="has-text-align-center" data-align="center">N/A</td></tr><tr><td>scp</td><td class="has-text-align-center" data-align="center">❌</td><td class="has-text-align-center" data-align="center">N/A</td></tr><tr><td>Finder Copy then Paste</td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">✅</td></tr><tr><td>Finder Duplicate</td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">✅</td></tr><tr><td>Finder ⌥-drag</td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">✅</td></tr><tr><td><code><a href="https://www.manpagez.com/man/2/clonefile/" data-wpel-link="external" target="_blank" rel="external noopener">clonefile</a></code><sup data-fn="1bebdb6f-7e69-4ebb-bca6-692795e4e8f7" class="fn"><a href="#1bebdb6f-7e69-4ebb-bca6-692795e4e8f7" id="1bebdb6f-7e69-4ebb-bca6-692795e4e8f7-link">2</a></sup></td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">❌</td></tr><tr><td><code><a href="https://keith.github.io/xcode-man-pages/copyfile.3.html" data-wpel-link="external" target="_blank" rel="external noopener">copyfile</a>(…, …, …, COPYFILE_DATA)</code></td><td class="has-text-align-center" data-align="center">❌</td><td class="has-text-align-center" data-align="center">N/A</td></tr><tr><td><code><a href="https://keith.github.io/xcode-man-pages/copyfile.3.html" data-wpel-link="external" target="_blank" rel="external noopener">copyfile</a>(…, …, …, COPYFILE_CLONE)</code></td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">✅</td></tr><tr><td><code><a href="https://keith.github.io/xcode-man-pages/copyfile.3.html" data-wpel-link="external" target="_blank" rel="external noopener">copyfile</a>(…, …, …, COPYFILE_CLONE_FORCE)</code></td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">❌</td></tr><tr><td><code><a href="https://developer.apple.com/documentation/foundation/filemanager/1412957-copyitem" data-wpel-link="external" target="_blank" rel="external noopener">FileManager.copyItem(at:to:)</a></code></td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">✅</td></tr><tr><td><code><a href="https://developer.apple.com/documentation/foundation/filemanager/1407903-copyitem" data-wpel-link="external" target="_blank" rel="external noopener">FileManager.copyItem(atPath:toPath:)</a></code></td><td class="has-text-align-center" data-align="center">✅</td><td class="has-text-align-center" data-align="center">✅</td></tr></tbody></table><figcaption class="wp-element-caption">This is accurate for macOS 14.5 (23F79).  The behaviour might vary across OS releases.</figcaption></figure>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots"/>



<h3 class="wp-block-heading">Testing method</h3>



<p>Not that this is interesting, just for posterity and to show my work a bit, in case I made a mistake.</p>



<p>I created large-enough files on each of my test volumes (APFS on SSD, APFS on HDD, HFS+ on SSD) that an actual copy would take tens of seconds at least, using <code>dd</code> e.g.:</p>



<figure class="wp-block-pullquote"><blockquote><p><code>dd if=/dev/random of=/tmp/bigfile oflag=direct status=progress bs=1k count=104857600</code></p></blockquote></figure>



<p>I then ran the various command line tools on these files, attempting to clone the file to a different name in the same folder, and observed disk I/O activity with Activity Monitor and iStat Menus.</p>



<p>For actual copy-on-writes I would observe that the program successfully concluded practically instantly, and there&#8217;d be at most a small blip of disk writes (for metadata modifications).</p>



<p>For failed copy-on-writes I would observe that the program would not exit promptly and I&#8217;d see voluminous disk writes (hundreds of megabytes to gigabytes per second, depending on the disk, sustained for many seconds until I was satisfied with the results and killed the test).</p>



<p>For API tests the overall approach was the same, but the APIs were invoked from inside <code>swift repl</code> where possible, and from a throw-away Swift script otherwise<sup data-fn="4f593842-632c-4279-83ba-435dde24c411" class="fn"><a href="#4f593842-632c-4279-83ba-435dde24c411" id="4f593842-632c-4279-83ba-435dde24c411-link">3</a></sup>.</p>


<ol class="wp-block-footnotes"><li id="fd9542d5-ca23-49bc-ae00-3d2b57caf906">I haven&#8217;t tested it, but as far as I&#8217;ve heard APFS does <em>not</em> actually check if the modifications actually diverge the files.  e.g. if you &#8220;modify&#8221; a byte of the file to the value it already has &#8211; a pointless but technically possible operation that leaves both copies still identical &#8211; APFS <em>will still copy the modified block</em>.<br><br>Furthermore, APFS &amp; Apple&#8217;s operating systems appear to have no tools (nor APIs) to deduplicate files &#8211; e.g. to detect full or partial copies and deduplicate their actual storage on disk.  Not even tools that you could invoke manually if you do the hard work of first determining that two files&#8217; contents are identical.<br><br>APFS / Apple&#8217;s operating systems rely entirely on user applications using copy-on-write explicitly and upfront. <a href="#fd9542d5-ca23-49bc-ae00-3d2b57caf906-link" aria-label="Jump to footnote reference 1">↩︎</a></li><li id="1bebdb6f-7e69-4ebb-bca6-692795e4e8f7">Curiously, <code>clonefile</code> first shipped in macOS 10.12 (Sierra), <a href="https://www.manpagez.com/man/2/clonefile/" data-wpel-link="external" target="_blank" rel="external noopener">according to its man page</a>, which is the release <em>preceding</em> the introduction of APFS in macOS 10.13 (High Sierra).  Yet, as far as I can tell HFS+ doesn&#8217;t and never did support cloning &#8211; nor do any of the other file systems supported by macOS 10.12 (e.g. FAT16 &amp; FAT32, exFAT, NFS).  It&#8217;s possible it was just convenient for Apple to include it in the prior release as they were probably testing APFS with it internally, during APFS&#8217;s development.<br><br><strong>Update</strong>: <a href="https://mjtsai.com" data-wpel-link="external" target="_blank" rel="external noopener">Michael Tsai</a> <a href="https://mastodon.social/@mjtsai/112456863768132668" data-wpel-link="external" target="_blank" rel="external noopener">pointed out</a> that <a href="https://www.pcmag.com/news/what-macos-sierras-new-apfs-file-system-means-to-you" data-wpel-link="external" target="_blank" rel="external noopener">Sierra included APFS support in beta form</a> (e.g. you could create disk images with it, but not use it for a boot disk).  Thus why <code>clonefile</code> (and other APFS-related tools) were included in Sierra.  <a href="#1bebdb6f-7e69-4ebb-bca6-692795e4e8f7-link" aria-label="Jump to footnote reference 2">↩︎</a></li><li id="4f593842-632c-4279-83ba-435dde24c411">While the C APIs worked just fine inside <code>swift repl</code> irrespective of what volumes I was targeting, the Foundation APIs oddly refused to work whenever the files were not on the boot volume, throwing &#8220;Operation not permitted&#8221; errors (NSCocoaErrorDomain 513, with no user info).  If it weren&#8217;t for the C APIs working just fine I&#8217;d think it&#8217;s a sandboxing issue, but clearly it&#8217;s not (and <code>swift repl -disable-sandbox</code> makes no difference). 🤔 <a href="#4f593842-632c-4279-83ba-435dde24c411-link" aria-label="Jump to footnote reference 3">↩︎</a></li></ol>]]></content:encoded>
					
					<wfw:commentRss>https://wadetregaskis.com/copy-on-write-on-apfs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8138</post-id>	</item>
		<item>
		<title>Bad API example: FileManager&#8217;s url(for:in:appropriateFor:create:)</title>
		<link>https://wadetregaskis.com/bad-api-example-filemanagers-urlforinappropriateforcreate/</link>
					<comments>https://wadetregaskis.com/bad-api-example-filemanagers-urlforinappropriateforcreate/#respond</comments>
		
		<dc:creator><![CDATA[]]></dc:creator>
		<pubDate>Wed, 31 Jan 2024 20:40:07 +0000</pubDate>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Broken by design]]></category>
		<category><![CDATA[FileManager]]></category>
		<category><![CDATA[Sad]]></category>
		<category><![CDATA[Swift]]></category>
		<category><![CDATA[Undocumented]]></category>
		<guid isPermaLink="false">https://wadetregaskis.com/?p=7631</guid>

					<description><![CDATA[I find FileManager&#8216;s url(for:in:appropriateFor:create:) to be very unintuitive. It seems to have multiple, largely-orthogonal functions. It can provide paths to common folders (albeit badly). It can create temporary folders. It can locate volume-specific bins (Trash folders). It is an example of bad API design. Specifically, regarding cohesion: the principle that an API should have one&#8230; <a class="read-more-link" href="https://wadetregaskis.com/bad-api-example-filemanagers-urlforinappropriateforcreate/" data-wpel-link="internal">Read more</a>]]></description>
										<content:encoded><![CDATA[
<p>I find <code><a href="https://developer.apple.com/documentation/foundation/filemanager" data-wpel-link="external" target="_blank" rel="external noopener">FileManager</a></code>&#8216;s <code><a href="https://developer.apple.com/documentation/foundation/filemanager/1407693-url" data-wpel-link="external" target="_blank" rel="external noopener">url(for:in:appropriateFor:create:)</a></code> to be very unintuitive.  It seems to have multiple, largely-orthogonal functions.  It can provide paths to common folders (albeit badly).  It can create temporary folders.  It can locate volume-specific bins (Trash folders).</p>



<p>It is an example of bad API design.  Specifically, regarding cohesion: the principle that an API should have one purpose.  A litmus test for this is whether all the method parameters are always applicable<sup data-fn="dd2453d4-5a23-4b69-983a-8d13728f39f4" class="fn"><a href="#dd2453d4-5a23-4b69-983a-8d13728f39f4" id="dd2453d4-5a23-4b69-983a-8d13728f39f4-link">1</a></sup>.</p>



<p>It wasn&#8217;t until I wrote a test driver which explores its entire parameter space, that I was finally able to grok what the hell it&#8217;s doing and delineate its multiple modes of operation.</p>



<p>I&#8217;ve contrasted it with the results from its sibling <code><a href="https://developer.apple.com/documentation/foundation/filemanager/1407726-urls" data-wpel-link="external" target="_blank" rel="external noopener">urls(for:in:)</a></code>, to better understand what it&#8217;s doing (and expose some more of its flaws).</p>



<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Test driver</summary>
<p>You can run this in a Swift playground, or as CLI app, but to observe the behaviour inside an <a href="https://developer.apple.com/documentation/security/app_sandbox" data-wpel-link="external" target="_blank" rel="external noopener">App Sandbox</a> it&#8217;s easiest to create a new GUI app in Xcode and just dump this into the @main <code>App</code> struct&#8217;s <code>init</code> method.</p>



<div class="wp-block-kevinbatdorf-code-block-pro padding-disabled" data-code-block-pro-font-family="" style="font-size:.875rem;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #0000FF">let</span><span style="color: #000000"> fm = FileManager.</span><span style="color: #001080">default</span></span>
<span class="line"></span>
<span class="line"><span style="color: #0000FF">let</span><span style="color: #000000"> searchPathDirectories = [(</span><span style="color: #A31515">&quot;applicationDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">applicationDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;demoApplicationDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">demoApplicationDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;developerApplicationDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">developerApplicationDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;adminApplicationDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">adminApplicationDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;libraryDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">libraryDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;developerDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">developerDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;userDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">userDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;documentationDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">documentationDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;documentDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">documentDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;coreServiceDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">coreServiceDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;autosavedInformationDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">autosavedInformationDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;desktopDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">desktopDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;cachesDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">cachesDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;applicationSupportDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">applicationSupportDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;downloadsDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">downloadsDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;inputMethodsDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">inputMethodsDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;moviesDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">moviesDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;musicDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">musicDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;picturesDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">picturesDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;printerDescriptionDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">printerDescriptionDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;sharedPublicDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">sharedPublicDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;preferencePanesDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">preferencePanesDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;applicationScriptsDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">applicationScriptsDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;itemReplacementDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">itemReplacementDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;allApplicationsDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">allApplicationsDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;allLibrariesDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">allLibrariesDirectory</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;trashDirectory&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDirectory</span><span style="color: #000000">.</span><span style="color: #001080">trashDirectory</span><span style="color: #000000">)]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #0000FF">let</span><span style="color: #000000"> searchPathDomainMasks = [(</span><span style="color: #A31515">&quot;userDomainMask&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDomainMask</span><span style="color: #000000">.</span><span style="color: #001080">userDomainMask</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;localDomainMask&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDomainMask</span><span style="color: #000000">.</span><span style="color: #001080">localDomainMask</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;systemDomainMask&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDomainMask</span><span style="color: #000000">.</span><span style="color: #001080">systemDomainMask</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             (</span><span style="color: #A31515">&quot;networkDomainMask&quot;</span><span style="color: #000000">, FileManager.</span><span style="color: #001080">SearchPathDomainMask</span><span style="color: #000000">.</span><span style="color: #001080">networkDomainMask</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">                             </span><span style="color: #008000">/*(&quot;allDomainsMask&quot;, FileManager.SearchPathDomainMask.allDomainsMask)*/</span><span style="color: #000000">]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #795E26">print</span><span style="color: #000000">(</span><span style="color: #A31515">&quot;urls(for:in:):&quot;</span><span style="color: #000000">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #AF00DB">for</span><span style="color: #000000"> (dirName, dir) </span><span style="color: #AF00DB">in</span><span style="color: #000000"> searchPathDirectories {</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #795E26">print</span><span style="color: #000000">(</span><span style="color: #A31515">&quot;</span><span style="color: #EE0000">\n</span><span style="color: #0000FF">\(</span><span style="color: #000000FF">dirName</span><span style="color: #0000FF">)</span><span style="color: #A31515">:&quot;</span><span style="color: #000000">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #AF00DB">for</span><span style="color: #000000"> (domainName, domain) </span><span style="color: #AF00DB">in</span><span style="color: #000000"> searchPathDomainMasks {</span></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #0000FF">let</span><span style="color: #000000"> dirs = fm.</span><span style="color: #795E26">urls</span><span style="color: #000000">(</span><span style="color: #795E26">for</span><span style="color: #000000">: dir, </span><span style="color: #795E26">in</span><span style="color: #000000">: domain)</span></span>
<span class="line"><span style="color: #000000">            .</span><span style="color: #795E26">map</span><span style="color: #000000"> { </span><span style="color: #0000FF">$0</span><span style="color: #000000">.</span><span style="color: #795E26">path</span><span style="color: #000000">(</span><span style="color: #795E26">percentEncoded</span><span style="color: #000000">: </span><span style="color: #0000FF">false</span><span style="color: #000000">) }</span></span>
<span class="line"><span style="color: #000000">            .</span><span style="color: #795E26">joined</span><span style="color: #000000">(</span><span style="color: #795E26">separator</span><span style="color: #000000">: </span><span style="color: #A31515">&quot;</span><span style="color: #EE0000">\n</span><span style="color: #A31515">&quot;</span><span style="color: #000000"> + </span><span style="color: #267F99">String</span><span style="color: #000000">(</span><span style="color: #795E26">repeating</span><span style="color: #000000">: </span><span style="color: #A31515">&quot; &quot;</span><span style="color: #000000">, </span><span style="color: #795E26">count</span><span style="color: #000000">: </span><span style="color: #098658">23</span><span style="color: #000000">))</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #795E26">print</span><span style="color: #000000">(</span><span style="color: #A31515">&quot;    </span><span style="color: #0000FF">\(</span><span style="color: #000000FF">domainName</span><span style="color: #0000FF">)</span><span style="color: #A31515">: </span><span style="color: #0000FF">\(</span><span style="color: #267F99">String</span><span style="color: #000000FF">(</span><span style="color: #795E26">repeating</span><span style="color: #000000FF">: </span><span style="color: #A31515">&quot; &quot;</span><span style="color: #000000FF">, </span><span style="color: #795E26">count</span><span style="color: #000000FF">: </span><span style="color: #098658">17</span><span style="color: #000000FF"> </span><span style="color: #000000">-</span><span style="color: #000000FF"> domainName.</span><span style="color: #001080">count</span><span style="color: #000000FF">)</span><span style="color: #0000FF">)\(</span><span style="color: #000000FF">dirs</span><span style="color: #0000FF">)</span><span style="color: #A31515">&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">    }</span></span>
<span class="line"><span style="color: #000000">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #795E26">print</span><span style="color: #000000">(</span><span style="color: #A31515">&quot;</span><span style="color: #EE0000">\n\n</span><span style="color: #A31515">url(for:in:appropriateFor:create:):&quot;</span><span style="color: #000000">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #0000FF">let</span><span style="color: #000000"> paths = [</span><span style="color: #0000FF">nil</span><span style="color: #000000">,</span></span>
<span class="line"><span style="color: #000000">             </span><span style="color: #795E26">URL</span><span style="color: #000000">(</span><span style="color: #795E26">filePath</span><span style="color: #000000">: </span><span style="color: #A31515">&quot;/&quot;</span><span style="color: #000000">),</span></span>
<span class="line"><span style="color: #000000">             FileManager.</span><span style="color: #001080">default</span><span style="color: #000000">.</span><span style="color: #001080">temporaryDirectory</span><span style="color: #000000">,</span></span>
<span class="line"><span style="color: #000000">             </span><span style="color: #795E26">URL</span><span style="color: #000000">(</span><span style="color: #795E26">filePath</span><span style="color: #000000">: </span><span style="color: #A31515">&quot;/Volumes/Flash/&quot;</span><span style="color: #000000">)]</span></span>
<span class="line"><span style="color: #0000FF">let</span><span style="color: #000000"> pathDesc: (URL?) -&gt; </span><span style="color: #267F99">String</span><span style="color: #000000"> = { </span><span style="color: #0000FF">$0</span><span style="color: #000000">?.</span><span style="color: #795E26">path</span><span style="color: #000000">(</span><span style="color: #795E26">percentEncoded</span><span style="color: #000000">: </span><span style="color: #0000FF">false</span><span style="color: #000000">) ?? </span><span style="color: #A31515">&quot;nil&quot;</span><span style="color: #000000"> }</span></span>
<span class="line"><span style="color: #0000FF">let</span><span style="color: #000000"> maxPathLength = paths.</span><span style="color: #795E26">map</span><span style="color: #000000"> { </span><span style="color: #795E26">pathDesc</span><span style="color: #000000">(</span><span style="color: #0000FF">$0</span><span style="color: #000000">).</span><span style="color: #001080">count</span><span style="color: #000000"> }.</span><span style="color: #795E26">max</span><span style="color: #000000">() ?? </span><span style="color: #098658">0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #AF00DB">for</span><span style="color: #000000"> (dirName, dir) </span><span style="color: #AF00DB">in</span><span style="color: #000000"> searchPathDirectories {</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #795E26">print</span><span style="color: #000000">(</span><span style="color: #A31515">&quot;</span><span style="color: #EE0000">\n</span><span style="color: #0000FF">\(</span><span style="color: #000000FF">dirName</span><span style="color: #0000FF">)</span><span style="color: #A31515">:&quot;</span><span style="color: #000000">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #AF00DB">for</span><span style="color: #000000"> (domainName, domain) </span><span style="color: #AF00DB">in</span><span style="color: #000000"> searchPathDomainMasks {</span></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #0000FF">var</span><span style="color: #000000"> results = [</span><span style="color: #267F99">String</span><span style="color: #000000">: </span><span style="color: #267F99">String</span><span style="color: #000000">]()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #AF00DB">for</span><span style="color: #000000"> appropriateForPath </span><span style="color: #AF00DB">in</span><span style="color: #000000"> paths {</span></span>
<span class="line"><span style="color: #000000">            </span><span style="color: #0000FF">let</span><span style="color: #000000"> path: </span><span style="color: #267F99">String</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">            </span><span style="color: #AF00DB">do</span><span style="color: #000000"> {</span></span>
<span class="line"><span style="color: #000000">                </span><span style="color: #0000FF">let</span><span style="color: #000000"> folderURL = </span><span style="color: #AF00DB">try</span><span style="color: #000000"> FileManager.</span><span style="color: #001080">default</span><span style="color: #000000">.</span><span style="color: #001080">url</span><span style="color: #000000">(</span><span style="color: #795E26">for</span><span style="color: #000000">: dir,</span></span>
<span class="line"><span style="color: #000000">                                                            </span><span style="color: #795E26">in</span><span style="color: #000000">: domain,</span></span>
<span class="line"><span style="color: #000000">                                                            </span><span style="color: #795E26">appropriateFor</span><span style="color: #000000">: appropriateForPath,</span></span>
<span class="line"><span style="color: #000000">                                                            </span><span style="color: #795E26">create</span><span style="color: #000000">: </span><span style="color: #0000FF">false</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">                path = </span><span style="color: #795E26">pathDesc</span><span style="color: #000000">(folderURL)</span></span>
<span class="line"><span style="color: #000000">            } </span><span style="color: #AF00DB">catch</span><span style="color: #000000"> {</span></span>
<span class="line"><span style="color: #000000">                path = </span><span style="color: #A31515">&quot;ERROR (</span><span style="color: #0000FF">\(</span><span style="color: #000000FF">error</span><span style="color: #0000FF">)</span><span style="color: #A31515">)&quot;</span></span>
<span class="line"><span style="color: #000000">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">            results[</span><span style="color: #795E26">pathDesc</span><span style="color: #000000">(appropriateForPath)] = path</span></span>
<span class="line"><span style="color: #000000">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #0000FF">let</span><span style="color: #000000"> uniquePaths = </span><span style="color: #267F99">Set</span><span style="color: #000000">(results.</span><span style="color: #001080">values</span><span style="color: #000000">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #AF00DB">if</span><span style="color: #000000"> </span><span style="color: #098658">1</span><span style="color: #000000"> == uniquePaths.</span><span style="color: #001080">count</span><span style="color: #000000"> {</span></span>
<span class="line"><span style="color: #000000">            </span><span style="color: #795E26">print</span><span style="color: #000000">(</span><span style="color: #A31515">&quot;    </span><span style="color: #0000FF">\(</span><span style="color: #000000FF">domainName</span><span style="color: #0000FF">)</span><span style="color: #A31515">: </span><span style="color: #0000FF">\(</span><span style="color: #267F99">String</span><span style="color: #000000FF">(</span><span style="color: #795E26">repeating</span><span style="color: #000000FF">: </span><span style="color: #A31515">&quot; &quot;</span><span style="color: #000000FF">, </span><span style="color: #795E26">count</span><span style="color: #000000FF">: </span><span style="color: #098658">17</span><span style="color: #000000FF"> </span><span style="color: #000000">-</span><span style="color: #000000FF"> domainName.</span><span style="color: #001080">count</span><span style="color: #000000FF">)</span><span style="color: #0000FF">)\(</span><span style="color: #000000FF">uniquePaths.</span><span style="color: #001080">first</span><span style="color: #000000">!</span><span style="color: #0000FF">)</span><span style="color: #A31515">&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">        } </span><span style="color: #AF00DB">else</span><span style="color: #000000"> {</span></span>
<span class="line"><span style="color: #000000">            </span><span style="color: #795E26">print</span><span style="color: #000000">(</span><span style="color: #A31515">&quot;    </span><span style="color: #0000FF">\(</span><span style="color: #000000FF">domainName</span><span style="color: #0000FF">)</span><span style="color: #A31515">:&quot;</span><span style="color: #000000">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #000000">            </span><span style="color: #AF00DB">for</span><span style="color: #000000"> (appropriateForPath, path) </span><span style="color: #AF00DB">in</span><span style="color: #000000"> results.</span><span style="color: #795E26">sorted</span><span style="color: #000000">(</span><span style="color: #795E26">by</span><span style="color: #000000">: { </span><span style="color: #0000FF">$0</span><span style="color: #000000">.</span><span style="color: #001080">key</span><span style="color: #000000"> &lt; </span><span style="color: #0000FF">$1</span><span style="color: #000000">.</span><span style="color: #001080">key</span><span style="color: #000000"> }) {</span></span>
<span class="line"><span style="color: #000000">                </span><span style="color: #795E26">print</span><span style="color: #000000">(</span><span style="color: #A31515">&quot;        </span><span style="color: #0000FF">\(</span><span style="color: #000000FF">appropriateForPath</span><span style="color: #0000FF">)</span><span style="color: #A31515">: </span><span style="color: #0000FF">\(</span><span style="color: #267F99">String</span><span style="color: #000000FF">(</span><span style="color: #795E26">repeating</span><span style="color: #000000FF">: </span><span style="color: #A31515">&quot; &quot;</span><span style="color: #000000FF">, </span><span style="color: #795E26">count</span><span style="color: #000000FF">: maxPathLength </span><span style="color: #000000">-</span><span style="color: #000000FF"> appropriateForPath.</span><span style="color: #001080">count</span><span style="color: #000000FF">)</span><span style="color: #0000FF">)\(</span><span style="color: #000000FF">path</span><span style="color: #0000FF">)</span><span style="color: #A31515">&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">            }</span></span>
<span class="line"><span style="color: #000000">        }</span></span>
<span class="line"><span style="color: #000000">    }</span></span>
<span class="line"><span style="color: #000000">}</span></span></code></pre></div>
</details>



<p>And here&#8217;s the output:</p>



<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow" open><summary>When running inside an <a href="https://developer.apple.com/documentation/security/app_sandbox" data-wpel-link="external" target="_blank" rel="external noopener">App Sandbox</a>:</summary>
<pre class="wp-block-preformatted">urls(for:in:):

applicationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/
    localDomainMask:   /Applications/
    systemDomainMask:  /System/Applications/
                       /System/Cryptexes/App/System/Applications/
    networkDomainMask: /Network/Applications/

demoApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/Demos/
    localDomainMask:   /Applications/Demos/
    systemDomainMask:  /Applications/Demos/
    networkDomainMask: /Network/Applications/Demos/

developerApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Developer/Applications/
    localDomainMask:   /Developer/Applications/
    systemDomainMask:  /Developer/Applications/
    networkDomainMask: /Network/Developer/Applications/

adminApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/Utilities/
    localDomainMask:   /Applications/Utilities/
    systemDomainMask:  /System/Applications/Utilities/
                       /System/Cryptexes/App/System/Applications/Utilities/
    networkDomainMask: /Network/Applications/Utilities/

libraryDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/
    localDomainMask:   /Library/
    systemDomainMask:  /System/Library/
                       /System/Cryptexes/App/System/Library/
    networkDomainMask: /Network/Library/

developerDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Developer/
    localDomainMask:   /Developer/
    systemDomainMask:  /Developer/
    networkDomainMask: /Network/Developer/

userDirectory:
    userDomainMask:    
    localDomainMask:   /Users/
    systemDomainMask:  
    networkDomainMask: /Network/Users/

documentationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Documentation/
    localDomainMask:   /Library/Documentation/
    systemDomainMask:  /System/Library/Documentation/
                       /System/Cryptexes/App/System/Library/Documentation/
    networkDomainMask: /Network/Library/Documentation/

documentDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Documents/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

coreServiceDirectory:
    userDomainMask:    
    localDomainMask:   
    systemDomainMask:  /System/Library/CoreServices/
                       /System/Cryptexes/App/System/Library/CoreServices/
    networkDomainMask: 

autosavedInformationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Autosave Information/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

desktopDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Desktop/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

cachesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Caches/
    localDomainMask:   /Library/Caches/
    systemDomainMask:  /System/Library/Caches/
    networkDomainMask: 

applicationSupportDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Application Support/
    localDomainMask:   /Library/Application Support/
    systemDomainMask:  /Library/Application Support/
    networkDomainMask: /Network/Library/Application Support/

downloadsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Downloads/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

inputMethodsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Input Methods/
    localDomainMask:   /Library/Input Methods/
    systemDomainMask:  /System/Library/Input Methods/
                       /System/Cryptexes/App/System/Library/Input Methods/
    networkDomainMask: /Network/Library/Input Methods/

moviesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Movies/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

musicDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Music/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

picturesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Pictures/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

printerDescriptionDirectory:
    userDomainMask:    
    localDomainMask:   
    systemDomainMask:  /System/Library/Printers/PPDs/
                       /System/Cryptexes/App/System/Library/Printers/PPDs/
    networkDomainMask: 

sharedPublicDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Public/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

preferencePanesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/PreferencePanes/
    localDomainMask:   /Library/PreferencePanes/
    systemDomainMask:  /System/Library/PreferencePanes/
                       /System/Cryptexes/App/System/Library/PreferencePanes/
    networkDomainMask: 

applicationScriptsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Application Scripts/com.SadPanda.MyApp/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

itemReplacementDirectory:
    userDomainMask:    
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

allApplicationsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/
                       /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/Utilities/
                       /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Developer/Applications/
                       /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/Demos/
    localDomainMask:   /Applications/
                       /Applications/Utilities/
                       /Developer/Applications/
                       /Applications/Demos/
    systemDomainMask:  /System/Applications/
                       /System/Applications/Utilities/
                       /System/Developer/Applications/
                       /System/Applications/Demos/
                       /System/Cryptexes/App/System/Applications/
                       /System/Cryptexes/App/System/Applications/Utilities/
                       /System/Cryptexes/App/System/Developer/Applications/
                       /System/Cryptexes/App/System/Applications/Demos/
    networkDomainMask: /Network/Applications/
                       /Network/Applications/Utilities/
                       /Network/Developer/Applications/
                       /Network/Applications/Demos/

allLibrariesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/
                       /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Developer/
    localDomainMask:   /Library/
                       /Developer/
    systemDomainMask:  /System/Library/
                       /Developer/
                       /System/Cryptexes/App/System/Library/
                       /System/Cryptexes/App/System/Developer/
    networkDomainMask: /Network/Library/
                       /Network/Developer/

trashDirectory:
    userDomainMask:    /Users/SadPanda/.Trash/
    localDomainMask:   /Users/SadPanda/.Trash/
    systemDomainMask:  
    networkDomainMask: 


url(for:in:appropriateFor:create:):

applicationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/
    localDomainMask:   /Applications/
    systemDomainMask:  /System/Applications/
    networkDomainMask: /Network/Applications/

demoApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/Demos/
    localDomainMask:   /Applications/Demos/
    systemDomainMask:  /Applications/Demos/
    networkDomainMask: /Network/Applications/Demos/

developerApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Developer/Applications/
    localDomainMask:   /Developer/Applications/
    systemDomainMask:  /Developer/Applications/
    networkDomainMask: /Network/Developer/Applications/

adminApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/Utilities/
    localDomainMask:   /Applications/Utilities/
    systemDomainMask:  /System/Applications/Utilities/
    networkDomainMask: /Network/Applications/Utilities/

libraryDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/
    localDomainMask:   /Library/
    systemDomainMask:  /System/Library/
    networkDomainMask: /Network/Library/

developerDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Developer/
    localDomainMask:   /Developer/
    systemDomainMask:  /Developer/
    networkDomainMask: /Network/Developer/

userDirectory:
    userDomainMask:    ERROR (nilError)
    localDomainMask:   /Users/
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: /Network/Users/

documentationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Documentation/
    localDomainMask:   /Library/Documentation/
    systemDomainMask:  /System/Library/Documentation/
    networkDomainMask: /Network/Library/Documentation/

documentDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Documents/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

coreServiceDirectory:
    userDomainMask:    ERROR (nilError)
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  /System/Library/CoreServices/
    networkDomainMask: ERROR (nilError)

autosavedInformationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Autosave Information/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

desktopDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Desktop/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

cachesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Caches/
    localDomainMask:   /Library/Caches/
    systemDomainMask:  /System/Library/Caches/
    networkDomainMask: ERROR (nilError)

applicationSupportDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Application Support/
    localDomainMask:   /Library/Application Support/
    systemDomainMask:  /Library/Application Support/
    networkDomainMask: /Network/Library/Application Support/

downloadsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Downloads/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

inputMethodsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/Input Methods/
    localDomainMask:   /Library/Input Methods/
    systemDomainMask:  /System/Library/Input Methods/
    networkDomainMask: /Network/Library/Input Methods/

moviesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Movies/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

musicDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Music/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

picturesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Pictures/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

printerDescriptionDirectory:
    userDomainMask:    ERROR (nilError)
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  /System/Library/Printers/PPDs/
    networkDomainMask: ERROR (nilError)

sharedPublicDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Public/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

preferencePanesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/PreferencePanes/
    localDomainMask:   /Library/PreferencePanes/
    systemDomainMask:  /System/Library/PreferencePanes/
    networkDomainMask: ERROR (nilError)

applicationScriptsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Application Scripts/com.SadPanda.MyApp/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

itemReplacementDirectory:
    userDomainMask:
        /:                                                               /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/tmp/TemporaryItems/NSIRD_MyApp_oflT6r/
        /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/tmp/: /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/tmp/TemporaryItems/NSIRD_MyApp_xkFfky/
        /Volumes/Other/:                                                 /Volumes/Other/.TemporaryItems/folders.501/TemporaryItems/NSIRD_MyApp_bLj7gn/
        nil:                                                             ERROR (nilError)
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

allApplicationsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Applications/
    localDomainMask:   /Applications/
    systemDomainMask:  /System/Applications/Demos/
    networkDomainMask: /Network/Applications/

allLibrariesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/Library/
    localDomainMask:   /Library/
    systemDomainMask:  /Developer/
    networkDomainMask: /Network/Library/

trashDirectory:
    userDomainMask:
        /:                                                               /Users/SadPanda/.Trash/
        /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/tmp/: /Users/SadPanda/.Trash/
        /Volumes/Other/:                                                 /Volumes/Other/.Trashes/501/
        nil:                                                             /Users/SadPanda/.Trash/
    localDomainMask:
        /:                                                               /Users/SadPanda/.Trash/
        /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/tmp/: /Users/SadPanda/.Trash/
        /Volumes/Other/:                                                 /Volumes/Other/.Trashes/501/
        nil:                                                             /Users/SadPanda/.Trash/
    systemDomainMask:
        /:                                                               /Users/SadPanda/.Trash/
        /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/tmp/: /Users/SadPanda/.Trash/
        /Volumes/Other/:                                                 /Volumes/Other/.Trashes/501/
        nil:                                                             ERROR (nilError)
    networkDomainMask:
        /:                                                               /Users/SadPanda/.Trash/
        /Users/SadPanda/Library/Containers/com.SadPanda.MyApp/Data/tmp/: /Users/SadPanda/.Trash/
        /Volumes/Other/:                                                 /Volumes/Other/.Trashes/501/
        nil:                                                             ERROR (nilError)</pre>
</details>



<p>The output outside of an App Sandbox is pretty similar, just different paths in some cases as you&#8217;d expect.</p>



<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>When running without App Sandboxing</summary>
<pre class="wp-block-preformatted">urls(for:in:):

applicationDirectory:
    userDomainMask:    /Users/SadPanda/Applications/
    localDomainMask:   /Applications/
    systemDomainMask:  /System/Applications/
                       /System/Cryptexes/App/System/Applications/
    networkDomainMask: /Network/Applications/

demoApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Applications/Demos/
    localDomainMask:   /Applications/Demos/
    systemDomainMask:  /Applications/Demos/
    networkDomainMask: /Network/Applications/Demos/

developerApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Developer/Applications/
    localDomainMask:   /Developer/Applications/
    systemDomainMask:  /Developer/Applications/
    networkDomainMask: /Network/Developer/Applications/

adminApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Applications/Utilities/
    localDomainMask:   /Applications/Utilities/
    systemDomainMask:  /System/Applications/Utilities/
                       /System/Cryptexes/App/System/Applications/Utilities/
    networkDomainMask: /Network/Applications/Utilities/

libraryDirectory:
    userDomainMask:    /Users/SadPanda/Library/
    localDomainMask:   /Library/
    systemDomainMask:  /System/Library/
                       /System/Cryptexes/App/System/Library/
    networkDomainMask: /Network/Library/

developerDirectory:
    userDomainMask:    /Users/SadPanda/Developer/
    localDomainMask:   /Developer/
    systemDomainMask:  /Developer/
    networkDomainMask: /Network/Developer/

userDirectory:
    userDomainMask:    
    localDomainMask:   /Users/
    systemDomainMask:  
    networkDomainMask: /Network/Users/

documentationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Documentation/
    localDomainMask:   /Library/Documentation/
    systemDomainMask:  /System/Library/Documentation/
                       /System/Cryptexes/App/System/Library/Documentation/
    networkDomainMask: /Network/Library/Documentation/

documentDirectory:
    userDomainMask:    /Users/SadPanda/Documents/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

coreServiceDirectory:
    userDomainMask:    
    localDomainMask:   
    systemDomainMask:  /System/Library/CoreServices/
                       /System/Cryptexes/App/System/Library/CoreServices/
    networkDomainMask: 

autosavedInformationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Autosave Information/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

desktopDirectory:
    userDomainMask:    /Users/SadPanda/Desktop/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

cachesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Caches/
    localDomainMask:   /Library/Caches/
    systemDomainMask:  /System/Library/Caches/
    networkDomainMask: 

applicationSupportDirectory:
    userDomainMask:    /Users/SadPanda/Library/Application Support/
    localDomainMask:   /Library/Application Support/
    systemDomainMask:  /Library/Application Support/
    networkDomainMask: /Network/Library/Application Support/

downloadsDirectory:
    userDomainMask:    /Users/SadPanda/Downloads/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

inputMethodsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Input Methods/
    localDomainMask:   /Library/Input Methods/
    systemDomainMask:  /System/Library/Input Methods/
                       /System/Cryptexes/App/System/Library/Input Methods/
    networkDomainMask: /Network/Library/Input Methods/

moviesDirectory:
    userDomainMask:    /Users/SadPanda/Movies/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

musicDirectory:
    userDomainMask:    /Users/SadPanda/Music/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

picturesDirectory:
    userDomainMask:    /Users/SadPanda/Pictures/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

printerDescriptionDirectory:
    userDomainMask:    
    localDomainMask:   
    systemDomainMask:  /System/Library/Printers/PPDs/
                       /System/Cryptexes/App/System/Library/Printers/PPDs/
    networkDomainMask: 

sharedPublicDirectory:
    userDomainMask:    /Users/SadPanda/Public/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

preferencePanesDirectory:
    userDomainMask:    /Users/SadPanda/Library/PreferencePanes/
    localDomainMask:   /Library/PreferencePanes/
    systemDomainMask:  /System/Library/PreferencePanes/
                       /System/Cryptexes/App/System/Library/PreferencePanes/
    networkDomainMask: 

applicationScriptsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Application Scripts/com.SadPanda.MyApp/
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

itemReplacementDirectory:
    userDomainMask:    
    localDomainMask:   
    systemDomainMask:  
    networkDomainMask: 

allApplicationsDirectory:
    userDomainMask:    /Users/SadPanda/Applications/
                       /Users/SadPanda/Applications/Utilities/
                       /Users/SadPanda/Developer/Applications/
                       /Users/SadPanda/Applications/Demos/
    localDomainMask:   /Applications/
                       /Applications/Utilities/
                       /Developer/Applications/
                       /Applications/Demos/
    systemDomainMask:  /System/Applications/
                       /System/Applications/Utilities/
                       /System/Developer/Applications/
                       /System/Applications/Demos/
                       /System/Cryptexes/App/System/Applications/
                       /System/Cryptexes/App/System/Applications/Utilities/
                       /System/Cryptexes/App/System/Developer/Applications/
                       /System/Cryptexes/App/System/Applications/Demos/
    networkDomainMask: /Network/Applications/
                       /Network/Applications/Utilities/
                       /Network/Developer/Applications/
                       /Network/Applications/Demos/

allLibrariesDirectory:
    userDomainMask:    /Users/SadPanda/Library/
                       /Users/SadPanda/Developer/
    localDomainMask:   /Library/
                       /Developer/
    systemDomainMask:  /System/Library/
                       /Developer/
                       /System/Cryptexes/App/System/Library/
                       /System/Cryptexes/App/System/Developer/
    networkDomainMask: /Network/Library/
                       /Network/Developer/

trashDirectory:
    userDomainMask:    /Users/SadPanda/.Trash/
    localDomainMask:   /Users/SadPanda/.Trash/
    systemDomainMask:  
    networkDomainMask: 


url(for:in:appropriateFor:create:):

applicationDirectory:
    userDomainMask:    /Users/SadPanda/Applications/
    localDomainMask:   /Applications/
    systemDomainMask:  /System/Applications/
    networkDomainMask: /Network/Applications/

demoApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Applications/Demos/
    localDomainMask:   /Applications/Demos/
    systemDomainMask:  /Applications/Demos/
    networkDomainMask: /Network/Applications/Demos/

developerApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Developer/Applications/
    localDomainMask:   /Developer/Applications/
    systemDomainMask:  /Developer/Applications/
    networkDomainMask: /Network/Developer/Applications/

adminApplicationDirectory:
    userDomainMask:    /Users/SadPanda/Applications/Utilities/
    localDomainMask:   /Applications/Utilities/
    systemDomainMask:  /System/Applications/Utilities/
    networkDomainMask: /Network/Applications/Utilities/

libraryDirectory:
    userDomainMask:    /Users/SadPanda/Library/
    localDomainMask:   /Library/
    systemDomainMask:  /System/Library/
    networkDomainMask: /Network/Library/

developerDirectory:
    userDomainMask:    /Users/SadPanda/Developer/
    localDomainMask:   /Developer/
    systemDomainMask:  /Developer/
    networkDomainMask: /Network/Developer/

userDirectory:
    userDomainMask:    ERROR (nilError)
    localDomainMask:   /Users/
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: /Network/Users/

documentationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Documentation/
    localDomainMask:   /Library/Documentation/
    systemDomainMask:  /System/Library/Documentation/
    networkDomainMask: /Network/Library/Documentation/

documentDirectory:
    userDomainMask:    /Users/SadPanda/Documents/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

coreServiceDirectory:
    userDomainMask:    ERROR (nilError)
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  /System/Library/CoreServices/
    networkDomainMask: ERROR (nilError)

autosavedInformationDirectory:
    userDomainMask:    /Users/SadPanda/Library/Autosave Information/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

desktopDirectory:
    userDomainMask:    /Users/SadPanda/Desktop/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

cachesDirectory:
    userDomainMask:    /Users/SadPanda/Library/Caches/
    localDomainMask:   /Library/Caches/
    systemDomainMask:  /System/Library/Caches/
    networkDomainMask: ERROR (nilError)

applicationSupportDirectory:
    userDomainMask:    /Users/SadPanda/Library/Application Support/
    localDomainMask:   /Library/Application Support/
    systemDomainMask:  /Library/Application Support/
    networkDomainMask: /Network/Library/Application Support/

downloadsDirectory:
    userDomainMask:    /Users/SadPanda/Downloads/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

inputMethodsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Input Methods/
    localDomainMask:   /Library/Input Methods/
    systemDomainMask:  /System/Library/Input Methods/
    networkDomainMask: /Network/Library/Input Methods/

moviesDirectory:
    userDomainMask:    /Users/SadPanda/Movies/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

musicDirectory:
    userDomainMask:    /Users/SadPanda/Music/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

picturesDirectory:
    userDomainMask:    /Users/SadPanda/Pictures/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

printerDescriptionDirectory:
    userDomainMask:    ERROR (nilError)
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  /System/Library/Printers/PPDs/
    networkDomainMask: ERROR (nilError)

sharedPublicDirectory:
    userDomainMask:    /Users/SadPanda/Public/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

preferencePanesDirectory:
    userDomainMask:    /Users/SadPanda/Library/PreferencePanes/
    localDomainMask:   /Library/PreferencePanes/
    systemDomainMask:  /System/Library/PreferencePanes/
    networkDomainMask: ERROR (nilError)

applicationScriptsDirectory:
    userDomainMask:    /Users/SadPanda/Library/Application Scripts/com.SadPanda.MyApp/
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

itemReplacementDirectory:
    userDomainMask:
        /:                                                 /var/folders/v3/8anb56f64adf3_35gj346jg13000xa/T/TemporaryItems/NSIRD_MyApp_6D4CLt/
        /Volumes/Other/:                                   /Volumes/Other/.TemporaryItems/folders.501/TemporaryItems/NSIRD_MyApp_fdKnpT/
        /var/folders/v3/8anb56f64adf3_35gj346jg13000xa/T/: /var/folders/v3/8anb56f64adf3_35gj346jg13000xa/T/TemporaryItems/NSIRD_MyApp_bcHf11/
        nil:                                               ERROR (nilError)
    localDomainMask:   ERROR (nilError)
    systemDomainMask:  ERROR (nilError)
    networkDomainMask: ERROR (nilError)

allApplicationsDirectory:
    userDomainMask:    /Users/SadPanda/Applications/
    localDomainMask:   /Applications/
    systemDomainMask:  /System/Applications/Demos/
    networkDomainMask: /Network/Applications/

allLibrariesDirectory:
    userDomainMask:    /Users/SadPanda/Library/
    localDomainMask:   /Library/
    systemDomainMask:  /Developer/
    networkDomainMask: /Network/Library/

trashDirectory:
    userDomainMask:
        /:                                                 /Users/SadPanda/.Trash/
        /Volumes/Other/:                                   /Volumes/Other/.Trashes/501/
        /var/folders/v3/8anb56f64adf3_35gj346jg13000xa/T/: /Users/SadPanda/.Trash/
        nil:                                               /Users/SadPanda/.Trash/
    localDomainMask:
        /:                                                 /Users/SadPanda/.Trash/
        /Volumes/Other/:                                   /Volumes/Other/.Trashes/501/
        /var/folders/v3/8anb56f64adf3_35gj346jg13000xa/T/: /Users/SadPanda/.Trash/
        nil:                                               /Users/SadPanda/.Trash/
    systemDomainMask:
        /:                                                 /Users/SadPanda/.Trash/
        /Volumes/Other/:                                   /Volumes/Other/.Trashes/501/
        /var/folders/v3/8anb56f64adf3_35gj346jg13000xa/T/: /Users/SadPanda/.Trash/
        nil:                                               ERROR (nilError)
    networkDomainMask:
        /:                                                 /Users/SadPanda/.Trash/
        /Volumes/Other/:                                   /Volumes/Other/.Trashes/501/
        /var/folders/v3/8anb56f64adf3_35gj346jg13000xa/T/: /Users/SadPanda/.Trash/
        nil:                                               ERROR (nilError)
</pre>
</details>



<p>Note how <code>urls(for:in:)</code> works for every <code><a href="https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory" data-wpel-link="external" target="_blank" rel="external noopener">SearchPathDirectory</a></code> <em>except</em> <code><a href="https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/itemreplacementdirectory" data-wpel-link="external" target="_blank" rel="external noopener">itemReplacementDirectory</a></code>.</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<p>Also, something is broken regarding <code>applicationScriptsDirectory</code>.  When used with <code>urls(for:in:)</code> you get this output to stdout:</p>



<pre class="wp-block-preformatted">cannot open file at line 49259 of [1b37c146ee]
os_unix.c:49259: (0) open(/private/var/db/DetachedSignatures) - Undefined error: 0</pre>



<p>And if you use it with <code>url(for:in:appropriateFor:create:)</code> you get <em>eight</em> lines of this output to stderr:</p>



<pre class="wp-block-preformatted">This method should not be called on the main thread as it may lead to UI unresponsiveness.</pre>



<p>I haven&#8217;t delved into the implementation to figure out what&#8217;s going on &#8211; apparently that particular <code>SearchPathDirectory</code> has some kind of special code path all of its own, which is doing something it seemingly should not be doing.</p>
</div></div>



<p>Some observations about <code>urls(for:in:appropriateFor:create:)</code>:</p>



<ul class="wp-block-list">
<li>It returns a <em>single</em> URL, even though there are often multiple folders for a given search path.  Note how it <em>never</em> returns a path to a Cryptex folder, for example.<br><br>If you&#8217;re looking for <em>search paths</em> &#8211; the set of folders to search for a resource &#8211; use <code>urls(for:in:)</code> only.</li>



<li>The <code>appropriateFor</code> argument is completely irrelevant to every <code>SearchPathDirectory</code> <em>except</em> <code>itemReplacementDirectory</code> and <code><a href="https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/trashdirectory" data-wpel-link="external" target="_blank" rel="external noopener">trashDirectory</a></code>.</li>



<li>It will only ever return a path inside the App Sandbox for <code><a href="https://developer.apple.com/documentation/foundation/filemanager/searchpathdomainmask/1408037-userdomainmask" data-wpel-link="external" target="_blank" rel="external noopener">userDomainMask</a></code> (if it doesn&#8217;t fail by throwing an exception).</li>



<li>It won&#8217;t allow <code>nil</code> as an argument for <code>appropriateFor</code> when targeting <code>itemReplacementDirectory</code>, yet it will allow <code>nil</code> when targeting <code>trashDirectory</code>, but <em>only</em> for <code>userDomainMask</code> and <code>localDomainMask</code>.  I cannot think of any explanation for this inconsistency.<br><br>If you ignore that inconsistency, the <code>SearchPathDomainMask</code> is irrelevant to <code>trashDirectory</code> (as it logically should be &#8211; bin folders are tied to <em>volumes</em>, not apps, users, or computers.</li>



<li>It always throws an exception for <code>itemReplacementDirectory</code> if the <code><a href="https://developer.apple.com/documentation/foundation/filemanager/searchpathdomainmask" data-wpel-link="external" target="_blank" rel="external noopener">SearchPathDomainMask</a></code> is not <code>userDomainMask</code>.  This might actually be explicable, even if a bit unintuitive and misguided &#8211; it seems to be presuming that, because you&#8217;re running inside an App Sandbox, you cannot modify any files except the current user&#8217;s.  I&#8217;m not sure that&#8217;s not accurate &#8211; there&#8217;s the possibility of special entitlements and exclusions &#8211; although nor do I know that it&#8217;s not.</li>



<li>Whenever it fails, it throws a <code>nilError</code> exception which is largely useless.  Even the name doesn&#8217;t provide any real insight into what its problem is.<br><br>It&#8217;s unsurprising to me that it does such a poor job, given the rest of the API &#8211; good error messages are a hallmark of good API design, or put conversely, happy path programming produces bad code.</li>
</ul>



<p>I did not explore use of the <code>create</code> argument (I always left it as <code>false</code>).  I didn&#8217;t need to in order to know it has its own problems, too &#8211; the documentation states that it <em>also</em> has inconsistent behaviour, in that it is completely ignored for <code>itemReplacementDirectory</code> (and <em>only</em> that <code>SearchPathDirectory</code>).</p>



<p>The root of all these problems is the API&#8217;s bad design:</p>



<ul class="wp-block-list">
<li><code>itemReplacementDirectory</code> and <code>trashDirectory</code> should not be part of <code>SearchPathDirectory</code>.  They do not behave like any of the other cases; they do not have broadly correct generic values, requiring instead some context regarding the items being replaced or trashed.</li>



<li><code>url(for:in:appropriateFor:create)</code> should be three independent methods &#8211; one of which already exists, in the form of <code>urls(for:in:)</code>.  The other two should handle each of the special cases of <code>itemReplacementDirectory</code> and <code>trashDirectory</code>.  i.e.:</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro padding-disabled" data-code-block-pro-font-family="" style="font-size:.875rem;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #008000">// Existing method</span></span>
<span class="line"><span style="color: #0000FF">func</span><span style="color: #000000"> </span><span style="color: #795E26">urls</span><span style="color: #000000">(</span><span style="color: #795E26">for</span><span style="color: #000000"> </span><span style="color: #001080">directory</span><span style="color: #000000">: FileManager.SearchPathDirectory,</span></span>
<span class="line"><span style="color: #000000">          </span><span style="color: #795E26">in</span><span style="color: #000000"> </span><span style="color: #001080">domainMask</span><span style="color: #000000">: FileManager.SearchPathDomainMask) -&gt; [URL]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #008000">// New methods</span></span>
<span class="line"><span style="color: #0000FF">func</span><span style="color: #000000"> </span><span style="color: #795E26">replacementItemFolder</span><span style="color: #000000">(</span><span style="color: #795E26">appropriateFor</span><span style="color: #000000"> </span><span style="color: #001080">url</span><span style="color: #000000">: URL) </span><span style="color: #AF00DB">throws</span><span style="color: #000000">(InvalidURLError) -&gt; URL</span></span>
<span class="line"></span>
<span class="line"><span style="color: #0000FF">func</span><span style="color: #000000"> </span><span style="color: #795E26">trashFolder</span><span style="color: #000000">(</span><span style="color: #795E26">appropriateFor</span><span style="color: #000000"> </span><span style="color: #001080">url</span><span style="color: #000000">: URL) </span><span style="color: #AF00DB">throws</span><span style="color: #000000">(InvalidURLError) -&gt; URL</span></span></code></pre></div>



<p><em>So</em> much clearer and easier to use than what we have now.</p>



<p>The two specialised methods still need to throw, because they take <code>URL</code>s which could be invalid, but that&#8217;s now the <em>only</em> reason they might throw (I&#8217;ve used a hypothetical <code>InvalidURLError</code> type to express that formally).</p>



<p>They could arguably be combined into one method (taking an enum that delineates the two cases), but I see little practical value in that &#8211; it&#8217;s simpler and easier to read if they&#8217;re simply distinct methods, even though their shape is similar.  I can&#8217;t imagine any reasonable scenario where you only decide at runtime if you&#8217;re going to replace something or delete it.</p>



<p>☝️ I&#8217;ve removed the <code>create</code> parameter entirely, as I think it presumes too much (e.g. what if you want to create a <em>file</em> with the replacement item URL, not a folder?), though arguably it could be added back in (though if it were, it should <em>actually</em> be obeyed).</p>


<ol class="wp-block-footnotes"><li id="dd2453d4-5a23-4b69-983a-8d13728f39f4">Note that I wrote <em>applicable</em>, not necessarily <em>used</em>.  The distinction is important.  e.g. it makes sense to supply the request headers for a HTTP request to an API which makes such requests, even if the request might be served from a local cache in which case those headers aren&#8217;t actually used, <em>in that instance</em>.<br><br>Another way to frame this is that it&#8217;s a design flaw to have parameters whose utility depends only on the value of other parameters.<br><br>If you can know at compile time that some parameters are unnecessary, then you shouldn&#8217;t be forced to provide them. <a href="#dd2453d4-5a23-4b69-983a-8d13728f39f4-link" aria-label="Jump to footnote reference 1">↩︎</a></li></ol>]]></content:encoded>
					
					<wfw:commentRss>https://wadetregaskis.com/bad-api-example-filemanagers-urlforinappropriateforcreate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">7631</post-id>	</item>
	</channel>
</rss>
