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. Put your thread in the App & System Services > Core OS topic area and tag it with Files and Storage.
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)
App container protection (macOS 14 and later)
App group container protection (macOS 15 and later)
Data Vaults (see below) and other internal techniques used by various macOS subsystems
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 more information about app and app group container protection, see the links in Trusted Execution Resources. For more information about app groups in general, see App Groups: macOS vs iOS: Fight!
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 Settings 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
2024-11-08 Added info about app group container protection. Clarified that Data Vaults are just one example of the techniques used internally by macOS. Made other editorial changes.
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 app 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
throughout all of Foundation's URL documentation, its called out in multiple places that data stored inside an app sandox's caches directory doesn't count towards data and documents usage in the settings app
but in practice, it looks like storing data there does in fact count towards documents & data for the app
i'm trying to understand if the docs are wrong, if theres a bug in the settings app, or if this is a mistake on my part
there are other unresolved posts on this issue but maybe mine is solvable.
I copied the files I contributed from a working project to a new project using the finder (drag and drop). So I did not copy entitlements. Xcode automatically added the files to the project just fine. My app uses data on a removable drive, or used to, because I now get the error above. At one point I copied the product app to the desktop hoping to get the permissions alert window, but it never came. Oddly, in System Settings/Privacy & Security/Files & Folders my "new" app is listed with "Removable Volumes" slider = on.
The file permissions (unix-like) on that drive haven't changed between projects and allow everyone to read.
How can I fix this?
I have NTFS which is mounted on '/Volumes/usb_vol'
#mount
Filesystem Mounted on
/dev/disk5s1 /Volumes/usb_vol
The following simple code reports different values of device Id for device-file and mount point directory
struct stat buf;
for (int i = 1; i < argc; i++)
{
std::cout << argv[i] << std::endl;
if (stat(argv[i], &buf) < 0)
{
continue;
}
if (S_ISBLK(buf.st_mode))
{
std::cout << "st_rdev (" << major(buf.st_rdev) << "/" << minor(buf.st_rdev) << ") hex: " << std::hex << buf.st_rdev << std::endl;
}
else
{
std::cout << "st_dev (" << major(buf.st_dev) << "/" << minor(buf.st_dev) << ") hex: " << std::hex << buf.st_dev << std::endl;
}
}
Output:
/dev/disk5s1
st_rdev (1/22) hex: 1000016
/Volumes/usb_vol
st_dev (48/119) hex: 30000077
I believe this is expected but I have not found any explanation of this behaviour.
Are there any explanation of difference these values?
I can assume the stat() will report (48/119) for all objects which are located on this file system. Is it correct?
Thank you for the help!
I am writing SwiftData app, using a group container.
When editing a SwiftUI file, every couple of seconds a dialog - that the app wants to access data from other apps - pops up. It is impossible to edit
a view file while Canvas preview is open.
If preview is resumed the dialog has to be confirmed twice.
Each time the app is started from Xcode, the dialog has to be confirmed again.
Any idea, how to stop these boring dialogs?
Hello,
I am encountering an issue with user-generated files stored in the Documents directory on an iPhone 11 running iOS 18.2.
The problem occurs as follows:
1.The app generates and saves files in the Documents directory using FileManager.
2.These files are successfully saved and remain accessible while the app is running.
3.After restarting the app, the files appear to have been deleted from the Documents directory.
I have confirmed that:
1.The files are being saved to the correct location (Documents directory) and can be accessed during the current app session.
2.The app is not explicitly deleting these files during shutdown or restart.
3.This behavior is consistent across multiple app restarts.
Hello,
I am encountering an issue with user-generated files stored in the Documents directory on an iPhone 11 running iOS 18.2.
The problem occurs as follows:
1.The app generates and saves files in the Documents directory using FileManager.
2.These files are successfully saved and remain accessible while the app is running.
3.After restarting the app, the files appear to have been deleted from the Documents directory.
I have confirmed that:
1.The files are being saved to the correct location (Documents directory) and can be accessed during the current app session and from iExplorer.
2.The app is not explicitly deleting these files during shutdown or restart.
3.This behavior is consistent across multiple app restarts.
I recently started saving a file, where I hold some app state, to an AppGroup in order to share it with my widget extension.
Of the some 16k daily active users of my app, 55 are initially unable to read the file (it might not yet be created). And they are unable to write a file to the AppGroup as well. I only know this due to logging the error to Crashlytics.
Error Reading: "The file “BFTPreferences” couldn’t be opened because you don’t have permission to view it.
Error Code:257"
My App sees this error and informs the user to restart their device. I have not been contacted by any of these users for support, so I assume the restart fixes things.
Has anyone seen this before? Is restarting the device the only fix? Am I doing something wrong?
The only solution I can think of currently is to save the file to the app's Documents directory and save a copy to the AppGroup for use in my extensions. At least then the main app won't have an issue and it will just be the widget unable to display data until a restart.
Reading the file:
do {
// archive data
let data = try PropertyListSerialization.data(fromPropertyList: preferences, format: .xml, options: 0)
// write data
do {
if let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) {
let fullPath = groupURL.appendingPathComponent(preferencesFileName)
try data.write(to: fullPath)
}
else {
fatalError("Unable to find app group \(appGroupIdentifier)")
}
}
catch {
logthis("Failed to write dictionary data to disk. \(error.localizedDescription)")
}
}
catch {
logthis("Failed to archive dictionary. \(error.localizedDescription)")
}
Writing the file:
do {
if let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) {
let fullPath = groupURL.appendingPathComponent(preferencesFileName)
let data = try Data(contentsOf: fullPath)
if let dictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as? NSMutableDictionary {
preferences = dictionary
}
}
else {
fatalError("Unable to find app group \(appGroupIdentifier)")
}
} catch {
if (error as NSError).code == NSFileReadNoSuchFileError {
// file doesn't exist so create it
}
else {
logthis("Couldn't read BFTPreferences:\(error.localizedDescription)\nError Code:\((error as NSError).code)") <--error code 257 is caught here
}
}
Hi, I am trying to build a command line app that read local mov files and print the text to the terminal. When I open the file with VNImageRequestHandler(url: url), where the url is a hardcode path to my desktop file, the terminal reports CRImage Reader Detector was given zero-dimensioned image (0 x 0). Anyone can help? Thanks!
Hello everyone,
I hope you’ll all bear with me as I get up to speed. My background is in Unix, procedural languages, mission critical databases and enterprise applications.
I’ve just started heading a team with an iOS app used in healthcare that contains confidential patient information (PHI) that's governed by HIPAA and FDA cybersecurity, etc.
It seems there’s some contention in the team over whether the app, SQLite db, and medical images belong in the Documents or an Application Support directory in the Library.
From everything I’ve read, it seems that Apple’s intent is Library/Application Support.
Two questions:
Which is the correct location? And hopefully, a few compelling justifications.
On one of our iPads, the app stopped displaying what was two years of data in SQLite. I haven’t yet tested for index corruption, however one of the programmers believes this resulted from an iOS update that needed space and cleared data in the cache (but that makes no sense to myself).
Feedback highly appreciated. Many thanks,
David
Why, because somebody has to
Hey everyone,
TL;DR
How do I enable a draggable TableView to drop Audio Files into Apple Music / Rekordbox / Finder?
Intro / skip me
I've been dabbling into Swift / SwiftUI for a few weeks now, after roughly a decade of web development.
So far I've been able to piece together many things, but this time I'm stuck for hours with no success using Forums / ChatGPT / Perplexity / Trial and Error.
The struggle
Sometimes the target doesn't accept the dropping at all
sometimes the file data is failed to be read
when the drop succeeds, then only as a stream in apple music
My lack of understanding / where exactly I'm stuck
I think the right way is to use UTType.fileUrl but this is not accepted by other applications.
I don't understand low-level aspects well enough to do things right.
The code
I'm just going to dump everything here, it includes failed / commented out attempts and might give you an Idea of what I'm trying to achieve.
//
// Tracks.swift
// Tuna Family
//
// Created by Jan Wirth on 12/12/24.
//
import SwiftySandboxFileAccess
import Files
import SwiftUI
import TunaApi
struct LegacyTracks: View {
@State var tracks: TunaApi.LoadTracksQuery.Data?
func fetchData() {
print("fetching data")
Network.shared.apollo.fetch(query: TunaApi.LoadTracksQuery()) { result in
switch result {
case .success(let graphQLResult):
self.tracks = graphQLResult.data
case .failure(let error):
print("Failure! Error: \(error)")
}
}
}
@State private var selection = Set<String>()
var body: some View {
Text("Tracks").onAppear{
fetchData()
}
if let tracks = tracks?.track {
Table(of: LoadTracksQuery.Data.Track.self, selection: $selection) {
TableColumn("Title", value: \.title)
} rows : {
ForEach(tracks) { track in
TableRow(track)
.draggable(track)
// .draggable((try? File(path: track.dropped_source?.path ?? "").url) ?? test_audio.url) // This causes a compile-time error
// .draggable(test_audio.url)
// .draggable(DraggableTrack(url: test_audio.url))
// .itemProvider {
// let provider = NSItemProvider()
// if let path = self.dropped_source?.path {
// if let f = try? File(path: path) {
// print("Transferring", f.url)
//
//
// }
// }
//
// provider.register(track)
// return provider
// } // This does not
}
}
.contextMenu(forSelectionType: String.self) { items in
// ...
Button("yoooo") {}
} primaryAction: { items in
print(items)
// This is executed when the row is double clicked
}
} else {
Text("Loading")
}
// }
}
}
//extension Files.File: Transferable {
// public static var transferRepresentation: some TransferRepresentation {
// FileRepresentation(exportedContentType: .audio) { url in
// SentTransferredFile( self.)
// }
// }
//}
struct DraggableTrack: Transferable {
var url: URL
public static var transferRepresentation: some TransferRepresentation {
FileRepresentation (exportedContentType: .fileURL) { item in
SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true)
}
// FileRepresentation(contentType: .init(filenameExtension: "m4a")) {
// print("file", $0)
// print("Transferring fallback", test_audio.url)
// return SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true)
// }
// importing: { received in
// // let copy = try Self.(source: received.file)
// return Self.init(url: received.file)
// }
// ProxyRepresentation(exporting: \.url.absoluteString)
}
}
extension LoadTracksQuery.Data.Track: @retroactive Identifiable {
}
import UniformTypeIdentifiers
extension LoadTracksQuery.Data.Track: @retroactive Transferable {
// static func getKind() -> UTType {
// var kind: UTType = UTType.item
// if let path = self.dropped_source?.path {
// if let f = try? File(path: path) {
// print("Transferring", f.url)
// if (f.extension == "m4a") {
// kind = UTType.mpeg4Audio
// }
// if (f.extension == "mp3") {
// kind = UTType.mp3
// }
// if (f.extension == "flac") {
// kind = UTType.flac
// }
// if (f.extension == "wav") {
// kind = UTType.wav
// }
//
// }
// }
// return kind
// }
public static var transferRepresentation: some TransferRepresentation {
ProxyRepresentation {
$0.dropped_source?.path ?? ""
}
FileRepresentation(exportedContentType: .fileURL) { <#Transferable#> in
SentTransferredFile(<#T##file: URL##URL#>, allowAccessingOriginalFile: <#T##Bool#>)
}
// FileRepresentation(contentType: .fileURL) {
// print("file", $0)
// if let path = $0.dropped_source?.path {
// if let f = try? File(path: path) {
// print("Transferring", f.url)
// return SentTransferredFile(f.url, allowAccessingOriginalFile: true)
// }
// }
// print("Transferring fallback", test_audio.url)
// return SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true)
// }
// importing: { received in
// // let copy = try Self.(source: received.file)
// return Self.init(_fieldData: received.file)
// }
// ProxyRepresentation(exporting: \.title)
}
}
I recorded a 20 minute session with my iPhone 11 Pro running ios 18.1.1. It was in 4K however, my phone had 130GB of free space! Halfway along the recording it displayed the error that my storage was full, and that recording stopped. I then proceeded to go to settings and check the storage, still 127 GB free. I have iCloud photos on, and my media is syncing.
How to show MyApp Icon to Document Folder shared by UIFileSharingEnabled in "On my iPhone"
I would like to show my app (Falcon) on Chrome, Udemy, etc.
This app is currently under development.
Please let me know if there are any requirements to show it.
I would be happy if iCloud also solves this problem at the same time because the icon is not displayed.
For example, can it be displayed even if it is not released in the AppStore?
This is my Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>Falcon Package</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>lamina1331.Falcon</string>
</array>
</dict>
</array>
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.lamina1331.Falcon</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerName</key>
<string>Falcon</string>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>
<key>UIFileSharingEnabled</key>
<true/>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>Falcon Package</string>
<key>UTTypeIconFiles</key>
<array>
<string>DocumentIcon</string>
</array>
<key>UTTypeIdentifier</key>
<string>lamina1331.Falcon</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>flcpkg</string>
</array>
</dict>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>Falcon Package</string>
<key>UTTypeIconFiles</key>
<array>
<string>DocumentIcon</string>
</array>
<key>UTTypeIdentifier</key>
<string>lamina1331.Falcon</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>flcpkg</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>
We have a Push-To-Talk application, which also allow user's to share the PDF file documents.
On receiving a PDF file document, which has a space in its file name.
On saving the document in the DB with space. When user is trying to access the PDF file, in order to rule out issues where there can be special character's in its file name, we are encoding the file name using stringByAddingPercentEncodingWithAllowedCharacters, and URLPathAllowedCharacterSet is the character set used which converts space character (" ") to %20.
Later, path of the same encoded file name is sent to fileURLWithPath:.
When the encoded URL is passed to [NSFileManager fileExistsAtPath:] the file is not found in the since in DB, file is saved with a space, but in the URL %20 is been swapped in-place of space character.
Issue case: Here, on passing the same encoded URL path of the PDF file to [NSFileManager fileExistsAtPath:] is returning false;
Query: On passing the filename with spaces encoded with stringByAddingPercentEncodingWithAllowedCharacters to [NSFileManager fileExistsAtPath:], the path is not converted back to the decoded file name and returning false
We have used a work around on this case, by forming the URL of the PDF file without encoding and passing it to fileURLWithPath, issue is not seen here.
We have a query here, i.e. will fileURLWithPath will be able to handle different special characters without encoding.
We have also raised a Feedback Ticket on same: https://feedbackassistant.apple.com/feedback/16049504
I've developed a new Quicklook data-based preview extension for a custom file type that generates an image preview of the file. I previously used a Quick Look generator plug-in but support for it was deprecated and now removed in macOS Sequoia.
My app opens files using a
open(url.path, O_RDWR | O_NONBLOCK | O_EXLOCK)
call. The locking flags are used to prevent other clients from writing the file if it's already open.
I discovered that when Finder is showing the “large” file previews (such as when in column or gallery modes) from a SMB share, the open call fails with EWOULDBLOCK as if the file is locked.
It does work just fine on local files. Opening with O_SHLOCK also has the issue. Surprisingly it does work just fine for previews that return Plain Text data instead of Image data.
Using the lsof command, it seems like the Quicklook process has some kind of lock on the file.
This is the output of the lsof command:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE
QuickLook 48487 XXXX txt REG 1,15 125000611 3161369
Attached is a test project that tries a few different opening and locking functions. It also includes a test file and a sample image preview extension that displays a red square.
When everything is working, regular console messages show the progress of the tests. When the file is on a SMB share and selected in Finder Gallery mode, the open test will fail with a fault message in the console.
Notably, locking with flock works, which is weird because it should have similar semantics according to the man page for open(2).
Filed this as FB15051186
Hi there,
I've encountered a file permission bug in iOS 18.1.1 when using FileManager.default.copyItem(at:to:) to copy files from an iCloud shared folder to the app sandbox. This issue occurs under the following conditions:
The source file resides in an iCloud shared folder.
The iCloud shared folder is owned by another iCloud user and shared with read-only permissions.
The app copies the file to its sandbox using the copyItem(at:to:) method.
Observed Behavior:
After copying the file to the app sandbox, the original file's read-only permissions are propagated to the copied file. This results in an inability to delete the copied file from the app sandbox, with the following error message:
NSCocoaErrorDomain, Code 513: "The file couldn’t be removed because you don’t have permission to access it."
Steps to Reproduce:
Access a shared iCloud folder owned by another user with read-only permissions.
Copy a file from this folder to the app sandbox using FileManager.default.copyItem(at:to:).
Attempt to delete the copied file within the app sandbox.
Workaround:
Until this issue is resolved, the bug can be avoided by initializing the UIDocumentPickerViewController with the asCopy: true parameter:
UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true)
This ensures that the copied file does not inherit the original permissions from the shared source file.
Example Project:
To reproduce the issue and observe the error, I’ve created a sample project hosted on GitHub:
https://github.com/giomurru/FileDeletePermissionBug
This project provides step-by-step instructions for testing and reproducing the bug.
Environment:
iOS/iPadOS Version: 18.1.1
Devices: [iPhone 15, iPad 9th Gen]
Development Tool: Xcode 16.1
I hope this helps Apple engineers and other developers experiencing the same issue. Feedback or additional insights would be appreciated.
Giovanni
Since iOS 18, I have gotten user reports that the UIDocumentPickerViewController directoryURL is no longer opening the correct folder. Instead it is just loading the root directory of the Files app/iCloud files.
Did something change in iOS 18 that I need to account for? Not all users are having this issue, but some are and they are frustrated because a major feature of my app was to allow users to save files at the ubiquityURL.
I use the following to get the path:
NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil] URLByAppendingPathComponent:[NSString stringWithFormat:@"Documents/Photos/%@", folderName]];
Is there something that I need to do differently now in iOS 18 to prevent this from happening?
I properly copy a scrFile to a dstFile with
mManager = [NSFileManager defaultManager];
[mManager copyItemAtPath:srcPath toPath:dstPath error:&error];
but on "some destination disks" the dstFile gets a modificationDate with truncated milliseconds. For instance, with this format
"yyyy.MM.dd - HH:mm:ss:SSS" I visualize
srcDate = 2024.11.03 - 12:42:35:772
dstDate = 2024.11.03 - 12:42:35:000
After the copyItemAtPath I even unsuccessfully tried to set the dstFile modificationDate this way
NSMutableDictionary *dstAttrs = [NSMutableDictionary dictionaryWithDictionary:[mManager attributesOfItemAtPath:dstPath error:nil]];
[dstAttrs setObject:srcDate forKey:NSFileModificationDate];
[mManager setAttributes:dstAttrs ofItemAtPath:dstPath error:nil];
Again, the dstDate is 2024.11.03 - 12:42:35:000.
I unsuccessfully tried even
FSSetCatalogInfo(&dstRef, fsInfo, &srcFsCatInfo);
No way. I noticed that the destination disk is an USB External Physical Volume, Mac OS Extended (Journaled) with "Ignore Ownership on this volume" on. Could this flag be the cause of the trouble? Shouldn't this flag regard only the files ownership?
This issue brings another trouble. Since the srcDate and the dstDate are not equal, my macOS app performing a backup, copies the srcFile to the dstFile again and again.
To workaround the trouble, I actually compare srcDate with dstDate after truncating their milliseconds. But I guess this is not a good practice.
Any idea on how to fix this trouble? Thanks.
P.S. I attach here the disk info
Disk_Info.txt
Hi,
With UIDocumentPickerViewController, there is a directoryURL property that says we can use to 'specify the starting directory for the document picker'. But it's not clear how to get the directory of a folder in iCloud Drive / Files app. How can I get the 'root' directory for a user's iCloud Drive or Dropbox folder, or the Downloads folder on their device, that I could pass to this directoryURL to make it easier for the user to pick their files?
Thanks.
I have the following setup:
Managed domain (pdfforge.org)
Managed app (Dropbox) with Files app integration.
This can also occur with the following setup:
A custom browser is installed as managed (ex Firefox)
No managed domains
Managed app (Dropbox) with Files app integration.
Trying to upload a file from Dropbox in this managed domain by clicking on the Dropbox folder causes the folder to disappear and instead I am rerouted to the On My Phone directory.
On subsequent tries, sometimes the folder opens and I can see the files, but while scrolling the files disappear.
This makes it unable to upload any files from Dropbox to this managed domain.
If both the managed app and domains are not set up, then everything works normally.
Is this happening to everyone else? I also tried with Nextcloud and Google Drive.
I have an application that can be used completely offline. It doesn't require an internet connection. In the application, I encrypt only certain parameters of the data created by the users with AES. It is an individual, non-commercial project. Should I tick Yes in the App Encryption Documentation section. Do I need to add a document here? Is it a problem if I tick no?