FSKit removeItem Not Being Called

Environment

  • macOS Version: 26.1
  • Xcode Version: 16.2

Description

I'm developing a custom file system using FSKit and have encountered an issue where the removeItem(_:named:fromDirectory:) method in my FSVolume.Operations implementation is not being invoked when attempting to delete files or directories through Finder or the command line.

Implementation

My volume implements the required FSVolume.Operations protocol with the following removeItem implementation:

func removeItem(
    _ item: FSItem,
    named name: FSFileName,
    fromDirectory directory: FSItem
) async throws {
    logger.info("remove: \(name)")
    if let item = item as? MyFSItem, let directory = directory as? MyFSItem {
        directory.removeItem(item)
    } else {
        throw fs_errorForPOSIXError(POSIXError.EIO.rawValue)
    }
}


Steps to Reproduce

  1. Mount the custom FSKit-based file system using: mount -F -t MyFS /dev/diskX /tmp/mountpoint

  2. Create files using Finder or terminal (works correctly - createItem is called)

  3. Attempt to delete a file using any of the following methods:

    • Terminal command: rm -rf /path/to/mounted/file
    • option + cmd + delete to remove the file in Finder

Expected Behavior

The removeItem(_:named:fromDirectory:) method should be called, logging "remove: [filename]" and removing the item from the directory's children collection.

Actual Behavior

The removeItem method is never invoked. No logs appear from this method in Console.app. The deletion operation either fails silently or returns an error, but the callback never occurs.

Additional Context

  • Working operations: Other operations work correctly including:
    • createItem - files and directories can be created
    • lookupItem - items can be looked up successfully
    • enumerateDirectory - directory listing works
    • read and write - file I/O operations work correctly
  • Volume state:
    • The volume is properly mounted and accessible
    • Files can be created, read, and written successfully
  • Volume capabilities configured:
  var supportedVolumeCapabilities: FSVolume.SupportedCapabilities {
      let capabilities = FSVolume.SupportedCapabilities()
      capabilities.supportsHardLinks = true
      capabilities.supportsSymbolicLinks = true
      capabilities.supportsPersistentObjectIDs = true
      capabilities.doesNotSupportVolumeSizes = true
      capabilities.supportsHiddenFiles = true
      capabilities.supports64BitObjectIDs = true
      capabilities.caseFormat = .insensitiveCasePreserving
      return capabilities
  }

Questions

  1. Are there specific volume capabilities or entitlements required for removeItem to be invoked?
  2. Is there a specific way deletion operations need to be enabled in FSKit?
  3. Could this be related to how file permissions or attributes are set during createItem?
  4. Are there any known issues with deletion operations in the current FSKit implementation?
  5. Do I need to implement additional protocols or set specific flags to support item deletion?

Any guidance would be greatly appreciated. Has anyone successfully implemented deletion operations in FSKit?

Thank you!

Could this be related to how file permissions or attributes are set during createItem?

Yes, absolutely. FSKit and the VFS layer may be using this data, but even if they weren’t, many tools/apps preflight operations before they perform them. Related to that point, this kind of "real world" testing:

Terminal command: rm -rf /path/to/mounted/file option + cmd + delete to remove the file in Finder

...isn't all that useful when you're trying to get a file system working. A "simple" tool like rm is 600+ lines of code, but that's ignoring the fact that it's built on fts which pulls in even more code. For diagnostic purposes, you want to know exactly which syscalls occurred and what/how they failed, but either of those tests is FAR too high a level to determine that. The better approach here is to write your own very basic test tool, so you can see exactly what's going on.

Looking at specific details:

entitlements required for removeItem to be invoked?

No, nothing like that is required.

Similarly:

Is there a specific way deletion operations need to be enabled in FSKit?

...

Do I need to implement additional protocols or set specific flags to support item deletion?

...there isn't really a specific "allow deletion" flag or protocol

Having said that:

Are there specific volume capabilities or ... Are there any known issues with deletion operations in the current FSKit implementation?

What can go wrong here is that the configuration you’re presenting to the system means that remove can't happen. For example, remove won't occur if:

  • FSKit thinks the volume/directory is read-only or otherwise can't be modified.

  • FSKit thinks the directory isn't empty (since only empty directories can be removed).

...or "something else" about your configuration means that the system thinks the directory can't be removed. The place to start here is with the simplest possible test (I'd start by removing a single file at the root of the volume) and then slowly building up complexity.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks — I followed your suggestion and replaced the rm/mv tests with a small C probe that invokes rename() and unlink() directly and records the return value, errno, and lstat() state before and after each syscall.

Environment: macOS 26.5.2 (25F84), path-backed FSUnaryFileSystem, with same-directory operations at the volume root.

I also ran the identical binary against the native temporary filesystem as a control.

Results:

  • Plain rename(source, destination) with no existing destination succeeds both natively and through FSKit. FSKit dispatches renameItem, and the extension’s backing rename() succeeds.

  • Replace rename(source, destination) with an existing destination succeeds natively but returns -1/ENOENT through FSKit.

  • Immediately before the failing syscall, both source and destination successfully lstat() as regular files. Both are mode 0644, uid 501, gid 20, and flags 0. They are children of the same writable root directory, which is mode 0700, uid 501, gid 20, and flags 0.

  • Immediately after the failure, both files still exist unchanged.

  • The result is identical when the files are created through the mounted volume and when they are pre-seeded directly in the backing directory before mounting. This appears to rule out an issue specific to the attributes returned by createItem.

  • During one replace-rename attempt, the extension receives 1,026 successful lookups for the source and 1,026 successful lookups for the destination, with corresponding successful attribute requests, but receives no renameItem call.

  • A direct unlink() returns success, but removeItem is not dispatched. An immediate lstat() still sees the item; our historical FSEvents workaround removes the backing item shortly afterward.

The same extension handles plain rename correctly, and the same metadata is presented for the replace case.

Is there an attribute or capability that VFS uses specifically for overwrite rename which would cause it to return ENOENT after repeatedly and successfully looking up both items?

Are the 1,026 lookup retries expected behavior?

Is there another VFS/FSKit diagnostic channel you would recommend capturing to identify why dispatch stops before renameItem?

Is the way you're determining that removeItem isn't being called simply looking for the logged line in Console and not seeing it? I see the original code uses

logger.info("remove: \(name)")

and the info level doesn't appear in Console by default when streaming live logs. It might simply be that the function is actually being called but Console just isn't showing the message. You should make sure that Console > Action > Include Info Messages is selected, or use logger.log/a more severe log level instead.

FSKit removeItem Not Being Called
 
 
Q