Modern versions of macOS use a file system permission model that’s far more complex than the traditional BSD rwx model, and this post is my attempt at explaining that model. If you have a question about this, post it here on DevForums, tagging your thread with Files and Storage so that I see it.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
On File System Permissions
Modern versions of macOS have four different file system permission mechanisms:
Traditional BSD permissions
Access control lists (ACLs)
App Sandbox
Mandatory access control (MAC)
The first two were introduced a long time ago and rarely trip folks up. The second two are newer, more complex, and specific to macOS, and thus are the source of some confusion. This post is my attempt to clear that up.
Error Codes
App Sandbox and the mandatory access control system are both implemented using macOS’s sandboxing infrastructure. When a file system operation fails, check the error to see whether it was blocked by this sandboxing infrastructure. If an operation was blocked by BSD permissions or ACLs, it fails with EACCES (Permission denied, 13). If it was blocked by something else, it’ll fail with EPERM (Operation not permitted, 1).
If you’re using Foundation’s FileManager, these error are both reported as Foundation errors, for example, the NSFileReadNoPermissionError error. To recover the underlying error, get the NSUnderlyingErrorKey property from the info dictionary.
App Sandbox
File system access within the App Sandbox is controlled by two factors. The first is the entitlements on the main executable. There are three relevant groups of entitlements:
The com.apple.security.app-sandbox entitlement enables the App Sandbox. This denies access to all file system locations except those on a built-in allowlist (things like /System) or within the app’s containers.
The various “standard location” entitlements extend the sandbox to include their corresponding locations.
The various “file access temporary exceptions” entitlements extend the sandbox to include the items listed in the entitlement.
Collectively this is known as your static sandbox.
The second factor is dynamic sandbox extensions. The system issues these extensions to your sandbox based on user behaviour. For example, if the user selects a file in the open panel, the system issues a sandbox extension to your process so that it can access that file. The type of extension is determined by the main executable’s entitlements:
com.apple.security.files.user-selected.read-only results in an extension that grants read-only access.
com.apple.security.files.user-selected.read-write results in an extension that grants read/write access.
Note There’s currently no way to get a dynamic sandbox extension that grants executable access. For all the gory details, see this post.
These dynamic sandbox extensions are tied to your process; they go away when your process terminates. To maintain persistent access to an item, use a security-scoped bookmark. See Accessing files from the macOS App Sandbox. To pass access between processes, use an implicit security scoped bookmark, that is, a bookmark that was created without an explicit security scope (no .withSecurityScope flag) and without disabling the implicit security scope (no .withoutImplicitSecurityScope flag)).
If you have access to a directory — regardless of whether that’s via an entitlement or a dynamic sandbox extension — then, in general, you have access to all items in the hierarchy rooted at that directory. This does not overrule the MAC protection discussed below. For example, if the user grants you access to ~/Library, that does not give you access to ~/Library/Mail because the latter is protected by MAC.
Finally, the discussion above is focused on a new sandbox, the thing you get when you launch a sandboxed app from the Finder. If a sandboxed process starts a child process, that child process inherits its sandbox from its parent. For information on what happens in that case, see the Note box in Enabling App Sandbox Inheritance.
IMPORTANT The child process inherits its parent process’s sandbox regardless of whether it has the com.apple.security.inherit entitlement. That entitlement exists primarily to act as a marker for App Review. App Review requires that all main executables have the com.apple.security.app-sandbox entitlement, and that entitlements starts a new sandbox by default. Thus, any helper tool inside your app needs the com.apple.security.inherit entitlement to trigger inheritance. However, if you’re not shipping on the Mac App Store you can leave off both of these entitlement and the helper process will inherit its parent’s sandbox just fine. The same applies if you run a built-in executable, like /bin/sh, as a child process.
When the App Sandbox blocks something, it typically generates a sandbox violation report. For information on how to view these reports, see Discovering and diagnosing App Sandbox violations.
To learn more about the App Sandbox, see the various links in App Sandbox Resources. For information about how to embed a helper tool in a sandboxed app, see Embedding a Command-Line Tool in a Sandboxed App.
Mandatory Access Control
Mandatory access control (MAC) has been a feature of macOS for many releases, but it’s become a lot more prominent since macOS 10.14. There are many flavours of MAC but the ones you’re most likely to encounter are:
Full Disk Access (macOS 10.14 and later)
Files and Folders (macOS 10.15 and later)
Data container protection (macOS 14 beta and later)
Data Vaults (see below)
Mandatory access control, as the name suggests, is mandatory; it’s not an opt-in like the App Sandbox. Rather, all processes on the system, including those running as root, as subject to MAC.
Data Vaults are not a third-party developer opportunity. See this post if you’re curious.
In the Full Disk Access and Files and Folders cases, users grant a program a MAC privilege using System Settings > Privacy & Security. Some MAC privileges are per user (Files and Folders) and some are system wide (Full Disk Access). If you’re not sure, run this simple test:
On a Mac with two users, log in as user A and enable the MAC privilege for a program.
Now log in as user B. Does the program have the privilege?
If a process tries to access an item restricted by MAC, the system may prompt the user to grant it access there and then. For example, if an app tries to access the desktop, you’ll see an alert like this:
“AAA” would like to access files in your Desktop folder.
[Don’t Allow] [OK]
To customise this message, set Files and Folders properties in your Info.plist.
This system only displays this alert once. It remembers the user’s initial choice and returns the same result thereafter. This relies on your code having a stable code signing identity. If your code is unsigned, or signed ad hoc (“Signed to run locally” in Xcode parlance), the system can’t tell that version N+1 of your code is the same as version N, and thus you’ll encounter excessive prompts.
Note For information about how that works, see TN3127 Inside Code Signing: Requirements.
The Files and Folders prompts only show up if the process is running in a GUI login session. If not, the operation is allowed or denied based on existing information. If there’s no existing information, the operation is denied by default.
For all the details about data container protection, see WWDC 2023 Session 10053 What’s new in privacy.
On managed systems the site admin can use the com.apple.TCC.configuration-profile-policy payload to assign MAC privileges.
For testing purposes you can reset parts of TCC using the tccutil command-line tool. For general information about that tool, see its man page. For a list of TCC service names, see the posts on this thread.
Note TCC stands for transparency, consent, and control. It’s the subsystem within macOS that manages most of the privileges visible in System Settings > Privacy & Security. TCC has no API surface, but you see its name in various places, including the above-mentioned configuration profile payload and command-line tool, and the name of its accompanying daemon, tccd.
While tccutil is an easy way to do basic TCC testing, the most reliable way to test TCC is in a VM, restoring to a fresh snapshot between each test. If you want to try this out, crib ideas from Testing a Notarised Product.
The MAC privilege mechanism is heavily dependent on the concept of responsible code. For example, if an app contains a helper tool and the helper tool triggers a MAC prompt, we want:
The app’s name and usage description to appear in the alert.
The user’s decision to be recorded for the whole app, not that specific helper tool.
That decision to show up in System Preferences under the app’s name.
For this to work the system must be able to tell that the app is the responsible code for the helper tool. The system has various heuristics to determine this and it works reasonably well in most cases. However, it’s possible to break this link. I haven’t fully research this but my experience is that this most often breaks when the child process does something ‘odd’ to break the link, such as trying to daemonise itself.
If you’re building a launchd daemon or agent and you find that it’s not correctly attributed to your app, add the AssociatedBundleIdentifiers property to your launchd property list. See the launchd.plist man page for the details.
Scripting
MAC presents some serious challenges for scripting because scripts are run by interpreters and the system can’t distinguish file system operations done by the interpreter from those done by the script. For example, if you have a script that needs to manipulate files on your desktop, you wouldn’t want to give the interpreter that privilege because then any script could do that.
The easiest solution to this problem is to package your script as a standalone program that MAC can use for its tracking. This may be easy or hard depending on the specific scripting environment. For example, AppleScript makes it easy to export a script as a signed app, but that’s not true for shell scripts.
TCC and Main Executables
TCC expects its bundled clients — apps, app extensions, and so on — to use a native main executable. That is, it expects the CFBundleExecutable property to be the name of a Mach-O executable. If your product uses a script as its main executable, you’re likely to encounter TCC problems. To resolve these, switch to using a Mach-O executable. For an example of how you might do that, see this post.
Revision History
2023-06-13 Replaced two obsolete links with links to shiny new official documentation: Accessing files from the macOS App Sandbox and Discovering and diagnosing App Sandbox violations. Added a short discussion of data container protection and a link to WWDC 2023 Session 10053 What’s new in privacy.
2023-04-07 Added a link to my post about executable permissions. Fixed a broken link.
2023-02-10 In TCC and Main Executables, added a link to my native trampoline code. Introduced the concept of an implicit security scoped bookmark. Introduced AssociatedBundleIdentifiers. Made other minor editorial changes.
2022-04-26 Added an explanation of the TCC initialism. Added a link to Viewing Sandbox Violation Reports. Added the TCC and Main Executables section. Made significant editorial changes.
2022-01-10 Added a discussion of the file system hierarchy.
2021-04-26 First posted.
Files and Storage
RSS for tagAsk questions about file systems and block storage.
Posts under Files and Storage tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
General:
DevForums tags: Files and Storage, Finder Sync, File Provider, Disk Arbitration, APFS
File System Programming Guide
On File System Permissions DevForums post
File Provider framework
Finder Sync framework
App Extension Programming Guide > App Extension Types > Finder Sync
Disk Arbitration Programming Guide
Mass Storage Device Driver Programming Guide
Device File Access Guide for Storage Devices
Apple File System Guide
TN1150 HFS Plus Volume Format
Extended Attributes and Zip Archives
File system changes introduced in iOS 17 DevForums post
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
File system changes introduced in iOS 17
As part of iOS 17, tvOS 17, and watchOS 10, the system has reorganized where applications and their data containers are stored. In previous systems, both lived within the same volume but, starting in iOS 17, they will be stored on different volumes.
What does this mean for you?
Copying large amounts of data from the app bundle to a data container will take longer than in previous versions of iOS. Previously that copy would have occurred as an APFS file clone, but now the operation will occur as a standard copy, which may take much significantly longer.
Because the data will need to be fully duplicated, storage usage will increase more than was the case in previous versions. You should minimize the data they copy out of their app bundle and avoid any unnecessary duplication of data between the app bundle and data container.
When upgrading from previous system version, splitting the data into separate volumes may mean that there is insufficient space for all existing apps and their data. If this occurs, the app's data container will remain on the device, preserving the user's data, while the app bundle itself is removed using the same mechanism as "Offload Unused Apps". The user can then restore the app once they've freed sufficient space for the app to install.
Revision History
2023-07-11 First posted
Extracting an archive into the same directory on my custom filesystem more than once fails with the following message:
Unable to finish expanding 'misc.tar.xz' into 'extractme'.
Could not move 'misc' into destination directory.
I.e. initial extraction succeeds with archive contents extracted into extractme/misc.
Subsequent extraction fails to rename extractme.sb-db71cd27-lFjN1f/misc to extractme/misc 2.
This behaviour is observed on macOS Monterey and Ventura.
It does work as expected on macOS Sonoma though.
Dtrace(1)-ing the archive being extracted over smbfs results in the following sequence of calls being made:
2 -> smbfs_vnop_lookup AUHelperService-2163 -> extractme/misc 2 nameiop:0
2 <- smbfs_vnop_lookup AUHelperService-2163 -> extractme/misc 2 -> 2 ;ENOENT
2 -> smbfs_vnop_lookup AUHelperService-2163 -> extractme.sb-db71cd27-lFjN1f/misc nameiop:0x2 ;DELETE
2 <- smbfs_vnop_lookup AUHelperService-2163 -> extractme.sb-db71cd27-lFjN1f/misc -> 0
2 -> smbfs_vnop_lookup AUHelperService-2163 -> extractme/misc 2 nameiop:0x3 ;RENAME
2 <- smbfs_vnop_lookup AUHelperService-2163 -> extractme/misc 2 -> EJUSTRETURN
1 -> smbfs_vnop_rename AUHelperService-2163 -> extractme.sb-db71cd27-lFjN1f/misc -> extractme/nil
2 <- smbfs_vnop_rename AUHelperService-2163 -> extractme.sb-db71cd27-lFjN1f/misc -> extractme/nil -> 0
2 -> smbfs_vnop_lookup AUHelperService-2163 -> TheRooT/extractme/misc 2 nameiop:0
3 <- smbfs_vnop_lookup AUHelperService-2163 -> TheRooT/extractme/misc 2 -> 0 ;Successful lookup
What I don't understand is what causes vnop_lookup to be called for misc to be removed from the temporary directory and renamed into 'misc 2' and placed in the destination directory, 'extractme' via vnop_rename?
I had a look at smbfs_vnop_lookup and rename and didn't see anything that would cause 'misc 2' to come into being.
Based on the output of the dtrace(1) script running on my custom filesystem, there are no vnop_lookup and vnop_rename calls being made to remove the 'misc' directory from the temporary directory and to rename it to 'misc 2' and place it in the destination directory at extractme.
Archive extraction proceeds no further after extracting the archive contents into the temporary directory.
What am I missing?
I want to use ShareLink+FileRepresentation to save a small text file to my iPhone with the steps below.
Tap [Share...] to display the share sheet. This sheet contains [Save to Files].
Tap [Save to Files].
A black sheet is displayed, but it disappears instantly.
In step 3, I was expecting a browser to be displayed to select the location where the file will be saved. But in fact, a black sheet appears, which quickly disappears.
The implemented code is as follows.
import SwiftUI
@main
struct SLSandboxApp: App {
var body: some Scene {
WindowGroup {
let title = Text("File Output")
let numListString = "123,456,789"
let numListFileName = "numlist.csv"
let tagListFile = TextFile(content: numListString,
filename: numListFileName)
ShareView(title: title,
fileToShare: tagListFile,
messageToPreview: numListFileName)
}
}
}
struct ShareView: View {
let title: Text
let fileToShare: TextFile
let messageToPreview: String
var body: some View {
ShareLink(item: self.fileToShare, preview: SharePreview(self.messageToPreview))
}
}
struct TextFile: Transferable {
let content: String
let filename: String
static var transferRepresentation: some TransferRepresentation {
FileRepresentation(exportedContentType: .data) {
textFile in
let data = textFile.content.data(using: .utf8) ?? Data()
let tempDirectory = FileManager.default.temporaryDirectory
let fileURL = tempDirectory.appendingPathComponent(textFile.filename)
try data.write(to: fileURL)
return SentTransferredFile(fileURL)
}
}
}
The development environment is as follows.
Xcode 15.4 (Deployment Target = iOS Deployment Target 17.5)
macOS 14.6.1
The execution environment is as follows.
iPhone SE Gen3 17.7
The following is a console log from the time the application was launched to the time when the share sheet was displayed by tapping [Share...].
Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)}>
(501) personaAttributesForPersonaType for type:0 failed with error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction.}
Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
elapsedCPUTimeForFrontBoard couldn't generate a task port
Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
elapsedCPUTimeForFrontBoard couldn't generate a task port
Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
elapsedCPUTimeForFrontBoard couldn't generate a task port
The following is the console log that was written when I tapped [Save to file] on the share sheet.
cancelled request - error: The operation couldn’t be completed. Invalid argument
What modifications should I make to the code to get the expected result?
Supplying a complete copy the error from my log file below. Can someone tell me what changed in Sequoia that would be causing this error? If there a work around? Is there something I can do to correct this?
Thanks,
Ken
10.953 (I) DatabaseSaver.swift:207 phase1_startReadingRemoteDatabase(timeout:) Checking original database for out-of-band changes
10.975 (D) DatabaseSaver.swift:251 phase2_startResolvingConflict(localData:remoteData:remoteURL:) Original file is safe to overwrite.
10.975 (I) DatabaseSaver.swift:285 phase3_startWritingRemoteDatabase(resolvedData:) Writing database file
15.178 (E) LocalDataSource.swift:85 write(_:to:fileProvider:timeout:queue:completionQueue:completion:) Failed to write file [message: You don’t have permission to save the file “MyPasswords.kdbx” in the folder “Downloads”.
15.179 (E) FileAccessError.swift:217 make(from:fileName:fileProvider:) Failed to access the file [fileProvider: com.apple.FileProvider.LocalStorage, systemError: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “MyPasswords.kdbx” in the folder “Downloads”." UserInfo={NSUnderlyingError=0x6000014a0270 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}, NSFilePath=/Users/user123/Library/Mobile Documents/comappleCloudDocs/Downloads/MyPasswords.kdbx, NSURL=file:///Users/user123/Library/Mobile%20Documents/comappleCloudDocs/Downloads/MyPasswords.kdbx}]
15.179 (E) DatabaseSaver.swift:309 phase3_startWritingRemoteDatabase(resolvedData:) Failed to write database, cancelling
15.179 (E) DatabaseSaver.swift:432 finalize(withError:) Failed to open remote file [message: Cannot save file (macOS)]
I have seen these 2 articles that I have attached below that seem to offer some assistance. But is there a more modern way to share secured information between macOS users on same machine?
Entitlements
File System Protections
STEPS TO REPRODUCE
do
{
let baseDir = try fileMgr.url(for: .applicationSupportDirectory, in: .localDomainMask, appropriateFor: nil, create: true).appendingPathComponent("com.MyCompany.AppName", conformingTo: .directory)
try fileMgr.createDirectory(at: baseDir, withIntermediateDirectories: true, attributes: nil)
}
catch
{
Swift.print("ERROR: can't create baseDir \(baseDir)")
exit(0)
}
Hi, I encounter unexpected behavior from the FileWrapper updates that occurs when I remove file using FileManager.removeItem
If I first remove a file from the directory, then create NSFileWrapper instance, I get unexpected values from calls to matchesContents(of:)
import Foundation
let copyURL = URL(filePath: "/Users/marcinkrzyzanowski/Downloads/filewrappertest.test/COPY.png")
// THIS OPERATION BREAKS IT. REMOVE IT TO WORK AS EXPECTED
try! FileManager().removeItem(at: copyURL)
let dirURL = URL(filePath: "/Users/marcinkrzyzanowski/Downloads/filewrappertest.test")
let fw = try FileWrapper(url: dirURL)
fw.fileWrappers // ["IMG_0736.png"]
try FileManager.default.copyItem(at: URL(filePath: "/Users/marcinkrzyzanowski/Downloads/filewrappertest.test/IMG_0736.png"), to: copyURL)
fw.fileWrappers // ["IMG_0736.png"]
fw.matchesContents(of: dirURL) // true (expected: false)
try fw.read(from: dirURL)
fw.fileWrappers! // ["COPY.png", "IMG_0736.png"]
fw.matchesContents(of: dirURL) // true
I don't understand why the "FileManager.removeItem" affects the NSFileWrapper behavior in such a way. It does not change even when I add a delay after removeItem. Any idea?
I work on EdenFS, an open-source Virtual Filesystem that runs on macOS, Linux, and Windows. My team is very interested in using FSKit as the basis for EdenFS on macOS, but have found the documentation to be lacking and contains some mixed messaging on the future of FSKit. Below are a few questions that don’t seem to be fully covered by the current documentation:
Does FSKit support process attribution? Each FUSE request provides a requester Process ID (and other information) through the fuse_in_header structure. Does FSKit pass similar information along for each request?
Does the reclaimItem API function similarly to FUSE’s forget operation? If not, what are the differences? See #1 below for why forget/reclaimItem matters to us.
Is Apple committed to releasing and supporting FSKit? Is there any timeline for release that we can plan around?
Does FSKit have known performance/scalability limitations? We provide alternative methods that clients can use to make bulk requests to EdenFS, but some clients will necessarily be unable to use those and stress the default filesystem APIs. Throughput (on the order of tens of thousands of filesystem requests per minute) and request size are the main concerns, followed closely by directory size restrictions.
Why we’re interested in FSKit
As mentioned above, my team supports EdenFS on 3 platforms. On Linux, we utilize FUSE; on Windows, we utilize ProjectedFS; and on macOS, we’ve utilized a few different solutions in the past. We first utilized the macFUSE kext, which was great while it lasted. Due to (understandable) changes in supporting kernel extensions, we were forced to move to NFS version 3. NFS has been lackluster in comparison (and our initial investigations show that NFS version 4(.2) would be similar). We have had numerous scalability and reliability issues, some listed below:
NFS does not provide a forget API similar to FUSE. EdenFS is forced to remember all file handles that have been loaded because the kernel never informs us when all references to that file handle have been dropped. We can hackily infer that a file handle should never be referenced again in some cases, but a large number of file handles end up being remembered forever. Many of our algorithms scale with the number of file handles that Eden has to consider, and therefore performance issues are inevitable after some time.
NFS does not provide information about clients (requesters). We cannot tell which processes are sending EdenFS requests. This attribution is important due to issue #1. We are forced to work with tool owners to modify their applications to be VFS-friendly. If we can’t track down which tools are behaving poorly, they will continue to load excess file handles and cause performance issues.
NFS “Server connections interrupted:” dialog during heavy load. Under heavy load, either EdenFS or system-wide, our users experience this dialog pop-up and are confused as to how they should respond (Ignore or Disconnect All). They become blocked in their work, and will be further blocked if they click “Disconnect All” as that unmounts their EdenFS mount. This forces them to restart EdenFS or reboot their laptop to remediate the issue.
The above issues make us extremely motivated to use FSKit and partner with Apple to flesh out the final version of the FSKit API. Our use case likely mirrors what other user-space filesystems will be looking for in the FSKit API (albeit at a larger scale than most), and we’re willing to collaborate to work out any issues in the current FSKit offerings.
Delete the Documents path of the app
Will the files or folders in the documentDirectory path or applicationSupportDirectory path disappear or be deleted when the OS is updated?
I know that sometimes all the files in the cachesDirectory path are deleted when the OS is updated or the device is rebooted.
Sometimes, users of my app report that all the files in the documentDirectory path or applicationSupportDirectory path are deleted or disappear, or all the files are deleted and initialized.
I thought that the files or folders in the documentDirectory path or applicationSupportDirectory path were not affected by the OS update, but am I wrong?
Hello,
using UIDocumentPickerViewController and startAccessingSecurityScopedResource(), I can access to a directory on iOS using Bookmark data, but when I save a Bookmark data, security-scoped bookmark not survive quitting the app and re-launching it.
I used the Apple example here but my app doesn't appear in Settings > Privacy > Files and Folders ?
Security-scoped bookmark is-it available on iOS ?
Thanks.
I bought my M2 MacBook Air in December 2022, and now, in October 2024, it's showing that I have no storage left. I have the 256GB, 8GB RAM model. My daily activities are fairly simple—primarily using Safari and Chrome for reading papers and light graphic design in Affinity Designer. However, in just a few months, my Mac has accumulated 170GB of data under "Other Users and Shared," "macOS," and "System."
170GB out of 245GB is absurd—can anyone help me clear this up?
We have a sandboxed swift app with an associated network extension where both write to the same log file in a shared container (via NSFileCoordinator)
On sonoma all was good. With sequoia, we get a popup requesting access to the file from the user.
I realize this is all in the name of security, but is there any way to prevent this popup?
alf
HI,
I am having some discrepancies with FileManager. Currently, FileManager.default.isReadableFile(atPath: path) returns false, where fileExists(atPath: path) is true - I was able to write a new file at the same location. Does anyone have any ideas as to why I would be able to write but not read a file?
Thanks for any advice!
I'm trying to use the example code https://developer.apple.com/documentation/foundation/filemanager/2765464-enumerator to exclude a sub directory, but the .skipDescendants doesn't seem to do what I expect.
Should this work? I want to ignore everything in the __CYCLES folder inside topLevelFolder. But those paths are listed along with all the other files/folders. I never see "Skipping Cycles" in my output.
import Foundation
let rootPath = "/Volumes/volumename/topLevelFolder"
let topLevelFolderURL = URL(fileURLWithPath: rootPath)
let localFileManager = FileManager()
let resourceKeys = Set<URLResourceKey>([.nameKey, .isDirectoryKey, .fileSizeKey])
let directoryEnumerator = localFileManager.enumerator(at: topLevelFolderURL, includingPropertiesForKeys: Array(resourceKeys), options: [.skipsHiddenFiles, .skipsPackageDescendants])!
for case let fileURL as URL in directoryEnumerator {
guard let resourceValues = try? fileURL.resourceValues(forKeys: resourceKeys),
let isDirectory = resourceValues.isDirectory,
let name = resourceValues.name,
let size = resourceValues.fileSize
else {
continue
}
if isDirectory {
if name == "__CYCLES" {
directoryEnumerator.skipDescendants()
print("Skipping Cycles")
}
} else {
print("\(fileURL.path) = \(size)")
}
}
I've just upgraded to Xcode 16 and my app now fails when attempting to read a text file from the main bundle. It finds the path but can't open the file so this snippet prints: "File read error for path: /private/var/containers/Bundle/Application/AABAD428-96BC-4B34-80B4-97FA80B77E58/Test.app/csvfile.csv"
This worked fine up to 15.4. Has something changed? Thanks.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let bundle = Bundle.main
let path = bundle.path(forResource: "csvfile", ofType: "csv")!
do {
let content = try String(contentsOfFile: path, encoding: String.Encoding.ascii)
} catch {
print("File read error for path: \(String(describing: path))")
}
}
}
A customer of mine reported that since updating to macOS 15 they aren't able to use my app anymore, which performs a deep scan of selected folders by recursively calling getattrlistbulk. The problem is that the app apparently keeps scanning forever, with the number of scanned files linearly increasing to infinity.
This happens for some folders on a SMB volume.
The customer confirmed that they can reproduce the issue with a small sample app that I attach below. At first, I created a sample app that only scans the contents of the selected folder without recursively scanning the subcontents, but the issue didn't happen anymore, so it seems to be related to recursively calling getattrlistbulk.
The output of the sample app on the customer's Mac is similar to this:
start scan /Volumes/shares/Backup/Documents level 0 fileManagerCount 2847
continue scan /Volumes/shares/Backup/Documents new items 8, sum 8, errno 34
/Volumes/shares/Backup/Documents/A.doc
/Volumes/shares/Backup/Documents/B.doc
...
continue scan /Volumes/shares/Backup/Documents new items 7, sum 1903, errno 0
/Volumes/shares/Backup/Documents/FKV.pdf
/Volumes/shares/Backup/Documents/KFW.doc
/Volumes/shares/Backup/Documents/A.doc
/Volumes/shares/Backup/Documents/B.doc
...
which shows that counting the number of files in the root folder by using
try FileManager.default.contentsOfDirectory(atPath: path).count
returns 2847, while getattrlistbulk lists about 1903 files and then starts listing the files from the beginning, not even between repeated calls, but within a single call.
What could this issue be caused by?
(The website won't let me attach .swift files, so I include the source code of the sample app as a text attachment.)
ViewController.swift
Our backup app (Arq) is encountering random errors for some users on macOS Sequoia.
The method [NSFileManager contentsOfDirectoryAtPath:error:] returns nil with an NSError domain NSCocoaErrorDomain, code 256 ("NSFileReadUnknownError").
The NSError's NSUnderlyingError key is an NSError with domain NSPOSIXErrorDomain and code 4 (EINTR).
Sometimes waiting and retrying works fine; sometimes 5 retries still fail.
For some users it happens on different directories each time they try to back up.
What is causing this? Are we supposed to use a different API to get directory contents these days?
I have read that iOS data protection ensures most of the files to be stored encrypted. However, I saw someone insisting (elcomsoft blog) very few files are not encrypted. Are app’s cache files or tmp files not stored encrypted? For example, are safari history.db file and cache files stored in the flash encrypted?
I'm trying to display my images in a tableView, I'm using NSFIleManager and NSDirectoryEnumerator to get all files in the current folder:
NSString *path = @"/Users/eagle/Documents/avatars";
NSFileManager *fileManager = NSFileManager.defaultManager;
NSDirectoryEnumerator *directoryEnum = [fileManager enumeratorAtPath:path];
NSString *file;
while (file = [directoryEnum nextObject])
{
// ...
}
the problem is that this line
file = [directoryEnum nextObject]
always returns nil, what gives?
I already made sure that this folder has no subfolders and contains only images, so what's the problem here?
I tried to create dmg from folder using hdiutil and diskutility , both time it failed creation for a particular folder name, when i change folder name it worked. The error i get is
could not access /Volumes/abc/abc.app - Operation not permitted
hdiutil: create failed - Operation not permitted
When i change abc to def it works.
I'm managing the database with SQLite in Flutter.
I want to enable iCloud backup and restore on the Swift side when called from Flutter.
I am using the following source code, but it is not working.
What could be the cause?
Could you provide a method and countermeasure?
private func saveFileToICloud(fileName: String, localDatabasePath: String, result: @escaping FlutterResult) {
guard let containerName = Bundle.main.object(forInfoDictionaryKey: "ICLOUD_CONTAINER_NAME") as? String else {
result(FlutterError(code: "NO_ICLOUD_CONTAINER", message: "iCloud container is not available", details: nil))
return
}
guard let containerURL = FileManager.default.url(forUbiquityContainerIdentifier: containerName) else {
result(FlutterError(code: "NO_ICLOUD_CONTAINER", message: "iCloud container is not available", details: nil))
return
}
let fileURL = containerURL.appendingPathComponent(fileName)
let sourceURL = URL(fileURLWithPath: localDatabasePath)
do {
if FileManager.default.fileExists(atPath: fileURL.path) {
try FileManager.default.removeItem(at: fileURL)
}
try FileManager.default.copyItem(at: sourceURL, to: fileURL)
result("File saved successfully to iCloud: \(fileURL.path)")
} catch {
result(FlutterError(code: "WRITE_ERROR", message: "Failed to write file to iCloud", details: error.localizedDescription))
}
}
private func readFileFromICloud(fileName: String, localDatabasePath: String, result: @escaping FlutterResult) {
let containerName = ProcessInfo.processInfo.environment["ICLOUD_CONTAINER_NAME"]
guard let containerURL = FileManager.default.url(forUbiquityContainerIdentifier: containerName) else {
result(FlutterError(code: "NO_ICLOUD_CONTAINER", message: "iCloud container is not available", details: nil))
return
}
let fileURL = containerURL.appendingPathComponent(fileName)
let sourceURL = URL(fileURLWithPath: localDatabasePath)
do {
if FileManager.default.fileExists(atPath: sourceURL.path) {
try FileManager.default.removeItem(at: sourceURL)
}
try FileManager.default.copyItem(at: fileURL, to: sourceURL)
result("File restored successfully to sqlite: \(sourceURL.path)") } catch {
result(FlutterError(code: "READ_ERROR", message: "Failed to read file from iCloud", details: error.localizedDescription))
}
}
Am developing an iOS App, which uses a ZipFoundation wrapper around Compression. In XCode, have exported a document type with extension '.MU' in the Info.plist.
On iPhone, when attempting to open archive called: 'Snapshot-test.mu'
can OPEN as a mobile email attachment
but FAILED via Files App referring to "iCloud Drive/Desktop"
Here are the respective URLS
"file:///private/var/mobile/Containers/Data/Application/<UniqueID>/Documents/Inbox/Snapshot-test.mu"
"file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/Desktop/Snapshot-test1.mu"
Two questions:
Is it possible to grant access to files residing remotely in iCloud?
Is "iCloud Drive/Desktop" unique, whereas other iCloud locations would be OK?