Skip to content

expressport: a sandboxed caller cannot remove ._ files on a FAT stick, so export fails after export.pdb is written and prune stops partway #192

Description

@M-Igashi

What happens

Called from the Mac App Store app, which runs in the App Sandbox, baken_export::export writes every track, export.pdb and My Settings, and then returns Error::Io with Operation not permitted (os error 1). The Report is lost with it, so the caller cannot say what was written, although the stick is complete. With prune the run stops partway through Contents, after some unreferenced files have already been deleted.

Cause

Measured on macOS 26 with small sandboxed apps signed Apple Development:

  • Every file a sandboxed app creates carries com.apple.quarantine (and com.apple.provenance). removexattr of the quarantine attribute answers EPERM, and LSFileQuarantineEnabled = false in Info.plist does not stop it being set.
  • On FAT those attributes are stored in a ._X AppleDouble file. Inside the sandbox, unlinking ._X while X exists and carries quarantine is EPERM: it is treated as an attribute operation on X.
  • So remove_apple_double fails on the sidecar of the first file this run wrote, and prune_tree fails the same way, because the ._X of a kept file is not in wanted.
  • Unlinking X itself works, and the volume then drops ._X on its own.

The CLI never meets this: it is not sandboxed, so its files carry no quarantine.

A real run

One export of a 35-track playlist from the app (CDJ-safe, My Settings, prune) to a FAT32 stick that rekordbox had exported to the day before: all 35 tracks and export.pdb written, then the EPERM. The run left 145 ._ files behind, and prune had stopped partway. The same stick already held 13 ._ files in Contents from rekordbox's own export the day before, so sidecars are normal on a stick that rekordbox writes from a Mac.

Proposal, for 4.2.1

  1. In remove_apple_double, an EPERM removing a ._ file is not an error: skip the file and count it in Report (for example apple_double_kept), so a caller can say how many were left. Other errors stay errors.
  2. In prune_tree, do not try to remove ._X when X is kept. When X is removed, its sidecar goes with it.

After that a sandboxed caller gets its Report, and prune works there too, since unlinking the data files is allowed.

Open question

The code says Linux-based players trip on ._ files, but I found no hardware report behind it. A sandboxed app cannot remove them at all, so it would help to know whether a player behaves any differently with them on the stick. That is a question for the #116 testers.

Reproducing

The CLI cannot reproduce this. A sandboxed build of the app writing to a FAT32 disk image (hdiutil create -fs "MS-DOS FAT32" -layout MBRSPUD) does.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmac-appBake'n Deck for Mac (App Store)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions