How to create Filestream in macOS Catalina?

My application maintains a folder list to automatically save some files to users such as application logs, reports, PDFs, backups, etc.

Until High Sierra I could save the files automatically, but in Catalina whenever I try to generate any file I get the error message "Cannot create file “...”. Operation not permited".

However, if before creating the file I execute FMX.Dialogs.SelectDirectory(), I can create the files in the selected folder until the user finishes the application.

The next time the application is run the error reoccurs until FMX.Dialogs.SelectDirectory() is executed again.

I tried to enable full application access to disk (in macOS), but the issue was not resolved.

Does anyone know how to solve this problem?

I am using Delphi 10.3.3 and the save routine I use is very simple:


var
   wWork: String;
   wOutput: TFileStream;
begin
  wWork:=IncludeTrailingPathDelimiter(wPath)+ 'Backup.DMP';
  wOutput:=TFileStream.Create(wWork, fmCreate);
  Try
    wOutput.Write(...)
   wOutput.Write(...)
  Finally
    wOutput.Free;
  End;
End;

Parents
No Data
Reply
  • Until High Sierra I could save the files automatically, but in Catalina whenever I try to generate any file I get the error message "Cannot create file “...”. Operation not permited".

    It is not exactly a Delphi problem. macOS Catalina introduced some new restrictions in terms of folder access. More about protected resources here: https://developer.apple.com/documentation/bundleresources/information_property_list/protected_resources?language=objc . So, if you want to access these folders, you need to add the corresponding entry to the Info.plist file. For example, if you want access to the Documents folder, you need to add NSDocumentsFolderUsageDescription. While this is not required, it is highly recommended (and may become required soon).

    If you want to experiment with granting or denying permissions, you can always reset the default policy be executing this:

    $ tccutil reset SystemPolicyDocumentsFolder <bundleID>

    After you reset the policy and run your app, the first time it tries to access the file, macOS will prompt you to grant permission to your app (and you control the text of this dialog via the NSDocumentsFolderUsageDescription key in your plist file).

    However, if before creating the file I execute FMX.Dialogs.SelectDirectory(), I can create the files in the selected folder until the user finishes the application.

    Yes, that's how it is supposed to work. Basically, the idea is that if a file was accessed via the open/save dialog, the user explicitly consented to grant your app the right to read/write that particular file.

    The next time the application is run the error reoccurs until FMX.Dialogs.SelectDirectory() is executed again.

    In my understanding, that's because when you run it for the second time, your app's binary changes (because Delphi recompiles and redeploys it), therefore for macOS it's a new app, not the one that had originally created the file. Try to run it by double-clicking the file rather than from the Delphi IDE to make sure that exactly the same file is executed in both cases. I believe it should make difference (99% sure). What I'm 100% sure of is that for a properly signed and notarized app, macOS will prompt the user for permission only once, and that choice will be memorized until the binary is modified for whatever reason (e.g. an updated version was installed, in which case the user might be prompted again).

    I tried to enable full application access to disk (in macOS), but the issue was not resolved.

    It's not that simple. Google for "full disk access entitlement cocoa".

    Does anyone know how to solve this problem?

    Don't use restricted folders for backups, logs, etc. Use an unrestricted folder, e.g. /Users/<username>/Library/Application Support/<your-app-name>. You can get the path by calling:

    URLForDirectory(NSApplicationSupportDirectory , NSUserDomainMask, nil, true, nil)

    For any user-generated content (like a .DOC file saved by the user in MS Word), you can use restricted folders, but things should work smoothly as long as you access that exact file that had been chosen by your user through the dialog, and as long as the same signed and notarized bundle performs this operation.

    Hope this helps.

Children