{"id":39355,"date":"2023-05-11T14:31:33","date_gmt":"2023-05-11T18:31:33","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=39355"},"modified":"2023-08-10T10:24:39","modified_gmt":"2023-08-10T14:24:39","slug":"getting-ready-for-dataless-files","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2023\/05\/11\/getting-ready-for-dataless-files\/","title":{"rendered":"Getting Ready for Dataless Files"},"content":{"rendered":"<p><a href=\"https:\/\/developer.apple.com\/documentation\/technotes\/tn3150-getting-ready-for-data-less-files\">TN3150<\/a>:<\/p>\n<blockquote cite=\"https:\/\/developer.apple.com\/documentation\/technotes\/tn3150-getting-ready-for-data-less-files\"><p>In a modern file system, a file&rsquo;s content may not be available locally on the device. A file that contains only metadata is known as a <em>dataless<\/em> file. The file&rsquo;s content typically resides on a remote server and is available to people or apps, transparently, when they access the file.<\/p><p>[&#8230;]<\/p><p>The system, or a person using the device, can make dataless files whenever they determine it&rsquo;s appropriate, and your app needs to be ready to handle them. Specifically, avoid unnecessarily materializing dataless files and, when your app requires access to a file&rsquo;s contents, perform that work asynchronously off the main thread.<\/p><p>[&#8230;]<\/p><p><code>UIDocument<\/code> and <code>NSDocument<\/code> automatically access the file system in a coordinated and asynchronous manner.<\/p><p>[&#8230;]<\/p><p>If your app or framework uses low-level POSIX APIs to access the file system and you&rsquo;re unable to migrate to the preferred methods, consider the following two options[&#8230;] Be aware that <code>stat<\/code> and <code>getattrlist<\/code> both trigger the materialization of any intermediate folders in the file&rsquo;s path, if they themselves are dataless.<\/p><\/blockquote>\n<p>I find this rather confusing. On macOS, it seems like nearly any file could <em>potentially<\/em> be dataless. It&rsquo;s less likely for files in <tt>Library<\/tt> but probably possible via symlinking. Even an action as simple as checking whether a file exists can now take an unexpectedly long amount of time. This breaks many longstanding assumptions.<\/p>\n<p>If your app deals with user-created files, I guess the best practice is to do everything asynchronously and using file coordination. Without coordination&mdash;at least on older systems&mdash;you can run into the opposite problem: instead of accessing an evicted file being slow, it might stay unmaterialized. So you need to use the special APIs even if you already have your file code on a background thread.<\/p>\n<p>But the <code>NSFileCoordinator<\/code> APIs are awkward, error-prone, and slow, and they infect your entire codebase. Hopefully you aren&rsquo;t relying on any cross-platform code that&rsquo;s not aware of them. And even with Apple-specific code, they make it hard to reuse the same code for working with folders that may or may not contain dataless files.<\/p>\n<p>It all feels shoehorned in, like with the security scope URL APIs. Most APIs don&rsquo;t do the right thing automatically, so you have to wrap uses of them. (But then some other APIs <a href=\"https:\/\/christiantietze.de\/posts\/2023\/02\/psa-filemanager-trashitem-uses-nsfilecoordinator-under-the-hood-automatically\/\">may secretly use coordination<\/a> so you have to <em>not<\/em> use it yourself in order to avoid <a href=\"https:\/\/mastodon.social\/@ctietze\/109862890583490114\">deadlocks<\/a>.) Any file-related code could potentially need special handling, but there&rsquo;s no way to make sure that you didn&rsquo;t miss a spot somewhere. But then, once you&rsquo;ve done this, your code is much harder to read and much slower for the <em>common<\/em> case of regular locally stored files.<\/p>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2023\/03\/14\/update-on-cloud-file-provider-extensions\/\">Update on Cloud File Provider Extensions<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2019\/10\/24\/modern-appkit-file-permissions\/\">Modern AppKit File Permissions<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2019\/03\/21\/not-relying-on-nsfilecoordinator\/\">Not Relying on NSFileCoordinator<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2018\/02\/05\/sandbox-limitation-on-number-of-files-that-can-be-opened\/\">Sandbox Limitation on Number of Files That Can Be Opened<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2015\/05\/19\/nsfilecoordinator-improvement-in-ios-8-2\/\">NSFileCoordinator Improvement in iOS 8.2<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2013\/05\/30\/document-based-icloud-problems\/\">Document-Based iCloud Problems<\/a><\/li>\n<\/ul>\n\n<p id=\"getting-ready-for-dataless-files-update-2023-05-12\">Update (2023-05-12): <a href=\"https:\/\/mastodon.social\/@tclementdev@mastodon.online\/110355529770357846\">Thomas Clement<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@tclementdev@mastodon.online\/110355529770357846\"><p>Out of curiosity I tried to <code>stat()<\/code> a non-local file as described in the tech note, but I get a &ldquo;no such file&rdquo; error. Same when trying to access it from Terminal. Not sure how we are supposed to test whether a file is dataless then.<\/p><p>Another thing that is not explained is what is the right way to monitor download progress in case the file is dataless.<\/p><\/blockquote>\n\n<p id=\"getting-ready-for-dataless-files-update-2023-08-10\">Update (2023-08-10): <a href=\"https:\/\/eclecticlight.co\/2023\/08\/06\/last-week-on-my-mac-are-we-ready-for-dataless-files\/\">Howard Oakley<\/a>:<\/p>\n<blockquote cite=\"https:\/\/eclecticlight.co\/2023\/08\/06\/last-week-on-my-mac-are-we-ready-for-dataless-files\/\">\n<p>Over the last couple of weeks I have been exploring how macOS and its features handle dataless files. While apps that take advantage of AppKit&rsquo;s NSDocument to read and write files should handle these problems seamlessly, there are some definite seams when it comes to macOS services. These result from three constraints:<\/p>\n<ul>\n<li>features reliant on the contents of file data can&rsquo;t be used with dataless files;<\/li>\n<li>features reliant on file data stored outside the file aren&rsquo;t available to other systems accessing that file from iCloud;<\/li>\n<li>limitations on the total size of extended attributes in iCloud storage may require some to be removed.<\/li>\n<\/ul>\n<\/blockquote>","protected":false},"excerpt":{"rendered":"<p>TN3150: In a modern file system, a file&rsquo;s content may not be available locally on the device. A file that contains only metadata is known as a dataless file. The file&rsquo;s content typically resides on a remote server and is available to people or apps, transparently, when they access the file.[&#8230;]The system, or a person [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2023-05-11T18:31:36Z","apple_news_api_id":"3adb99d1-22f4-47b7-b502-ef05407483be","apple_news_api_modified_at":"2023-08-10T14:24:42Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAg==","apple_news_api_share_url":"https:\/\/apple.news\/AOtuZ0SL0R7e1Au8FQHSDvg","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[1395,800,2164,913,31,2185,30,2223,476,71,174],"class_list":["post-39355","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-apple-file-system-apfs","tag-concurrency","tag-file-provider-extensions","tag-icloud-drive","tag-ios","tag-ios-16","tag-mac","tag-macos-13-ventura","tag-networking","tag-programming","tag-storage"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/39355","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=39355"}],"version-history":[{"count":3,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/39355\/revisions"}],"predecessor-version":[{"id":40308,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/39355\/revisions\/40308"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=39355"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=39355"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=39355"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}