Question

I'm seeing strange behavior on FSEvents where I mount my drive in recovery mode and on reboot get zero fsevents in my stream. I do the following:

  1. Boot regularly
  2. Record current event with FSEventsGetCurrentEventId()
  3. Boot in recovery mode and modify a file in the watched path
  4. Restart the system

When this happens, I get no events at all when I use the fsevents API. The only flag it sends in the kFSEventStreamEventFlagHistoryDone sentinel, even if I had made other changes on the regular OS.

This ars technica review seems to imply that when you mount on some other device you should get the kFSEventStreamEventFlagMustScanSubDirs flag, but I'm not seeing that behavior. Has anybody encountered this before? Is there a better way of detecting and dealing with the case that the drive has been mounted somewhere else while the OS was off?

Update: I tried the same thing booting from linux and modifying the file system. I did not get the same strange behavior of 0 events no matter what, but I also didn't get an event from the directory I changed or a MustScanSubdirs flag.

Update 2: In this thread, the accepted response says that when this happens, time machine detects that the logs are out of date in the above situations. Anybody know how to detect if the logs are out of date? This date could be used instead of a flag.

Was it helpful?

Solution

I think you need to also store the UUID of the FSEvents database in step #2, and check for it in step #4.

This behavior is vaguely mentioned in Apple's documentation (emphasis added):

Note: Because disks can be modified by computers running earlier versions of OS X (or potentially other operating systems), you should treat the events list as advisory rather than a definitive list of all changes to the volume. If a disk is modified by a computer running a previous version of OS X, the historical log is discarded.

For example, backup software should still periodically perform a full sweep of any volume to ensure that no changes fall through the cracks.

Note the bit about the historical log being discarded, then look at the reference (emphasis added):

FSEventStreamGetLatestEventId() -> Initially, this returns the sinceWhen value supplied when the stream was created; thereafter, it is updated with the highest-numbered event ID mentioned in the current batch of events just before invoking the client's callback. Clients can store this value persistently as long as they also store the UUID for the device (obtained via FSEventsCopyUUIDForDevice()). Clients can then later supply this event ID as the sinceWhen parameter to FSEventStreamCreateRelativeToDevice(), as long as its UUID matches what you stored. This works because the FSEvents service stores events in a persistent, per-volume database. In this regard,the stream of event IDs acts like a global, system-wide clock, but bears no relation to any particular timebase.

FSEventsCopyUUIDForDevice() -> Gets a UUID that uniquely identifies the FSEvents database for that volume. If the database gets discarded then its replacement will have a different UUID so that clients will be able to detect this situation and avoid trying to use event IDs that they stored as the sinceWhen parameter to the FSEventStreamCreate...() functions.

Note that the UUID is per-device, so if you have any filesystems mounted inside your directory tree, you'll probably need to get the UUID of each of them.

Good luck!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top