Skip to content

Commit 02e0197

Browse files
jeffhostetlerGit for Windows Build Agent
authored andcommitted
fsmonitor: on macOS also emit NFC spelling for NFD pathname
Emit NFC or NFC and NFD spellings of pathnames on macOS. MacOS is Unicode composition insensitive, so NFC and NFD spellings are treated as aliases and collide. While the spelling of pathnames in filesystem events depends upon the underlying filesystem, such as APFS, HFS+ or FAT32, the OS enforces such collisions regardless of filesystem. Teach the daemon to always report the NFC spelling and to report the NFD spelling when stored in that format on the disk. This is slightly more general than "core.precomposeUnicode". Signed-off-by: Jeff Hostetler <[email protected]>
1 parent 69df7c5 commit 02e0197

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

compat/fsmonitor/fsm-listen-darwin.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,35 @@ static int ef_ignore_xattr(const FSEventStreamEventFlags ef)
155155
return ((ef & mask) == kFSEventStreamEventFlagItemXattrMod);
156156
}
157157

158+
/*
159+
* On MacOS we have to adjust for Unicode composition insensitivity
160+
* (where NFC and NFD spellings are not respected). The different
161+
* spellings are essentially aliases regardless of how the path is
162+
* actually stored on the disk.
163+
*
164+
* This is related to "core.precomposeUnicode" (which wants to try
165+
* to hide NFD completely and treat everything as NFC). Here, we
166+
* don't know what the value the client has (or will have) for this
167+
* config setting when they make a query, so assume the worst and
168+
* emit both when the OS gives us an NFD path.
169+
*/
170+
static void my_add_path(struct fsmonitor_batch *batch, const char *path)
171+
{
172+
char *composed;
173+
174+
/* add the NFC or NFD path as received from the OS */
175+
fsmonitor_batch__add_path(batch, path);
176+
177+
/* if NFD, also add the corresponding NFC spelling */
178+
composed = (char *)precompose_string_if_needed(path);
179+
if (!composed || composed == path)
180+
return;
181+
182+
fsmonitor_batch__add_path(batch, composed);
183+
free(composed);
184+
}
185+
186+
158187
static void fsevent_callback(ConstFSEventStreamRef streamRef,
159188
void *ctx,
160189
size_t num_of_events,
@@ -305,7 +334,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
305334

306335
if (!batch)
307336
batch = fsmonitor_batch__new();
308-
fsmonitor_batch__add_path(batch, rel);
337+
my_add_path(batch, rel);
309338
}
310339

311340
if (event_flags[k] & kFSEventStreamEventFlagItemIsDir) {
@@ -318,7 +347,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef,
318347

319348
if (!batch)
320349
batch = fsmonitor_batch__new();
321-
fsmonitor_batch__add_path(batch, tmp.buf);
350+
my_add_path(batch, tmp.buf);
322351
}
323352

324353
break;

0 commit comments

Comments
 (0)