Re: msdosfs: Lookup of some existing files fails when mounting with long names

Stefan Esser <[email protected]> Thu, 28 May 2026 22:26:09 +0200
Newsgroups gmane.os.freebsd.devel.hackers
Message-ID <[email protected]>
Am 22.05.26 um 18:10 schrieb Stefan Esser:
> Am 21.05.26 um 23:56 schrieb [email protected]:
>> Fabian sent me the relevant part of the image, and the name
>> that is not correctly displayed contains the following UTF-16
>> sequence:
>>
>>      U+D83E U+DD10 ===> U+1F910 ===> "🤐"
>>
>> Seems that the conversion of these combined UTF-16 sequences
>> (surrogates) is not correct. This will probably affect all
>> file names that contain Unicode characters that cannot be
>> encoded in a single UTF-16 value.
>>
>> I'm going to further debug this issue tomorrow; it should be
>> easy to reproduce and fix ...
> 
> I had time to look at the sources and found that the function
> win2unixchr() does not support surrogates.
> 
> The problem with surrogates in file names is that they can be
> split between VFAT directory entry elements (i.e., last symbol
> in one group of 13, and first symbol in the preceding group of
> 13 symbols). But each 13 symbols are currently processed with
> no state kept between them.
> 
> I'll come up with a patch for review when I have decided how
> to keep the first surrogate symbol and to present it when
> the second surrogate is processed (possibly only in the next
> invocation of win2unixfn(), which causes this problem).

The patch that adds surrogate pair support to MSDOSFS is now
available for review:

	https://reviews.freebsd.org/D57313

I have performed extensive tests, but the directory reading
and writing has been complex before, is significantly more
complex with these changes. I'd rather rewrite all directory
operations to use a buffer holding the UTF-16 coded long
filename, instead of operating on directory slots that hold
up to 13 UTF-16 symbols max. and that are laid out in reverse
order (end of file name first) in the directory.

The changed code uses 32 bit variables to hold up to 2 UTF-16
symbols (i.e., the surrogate pairs). If a surrogate pair has
to be stored, the high surrogate is placed in the upper half
of the "code" variable.

While directory writing has been implemented in a way that
allows processing from the start of the file name to its end,
reading the long file name starts at the end and proceeds
towards the start of the name. Especially complex it the case
of a surrogate pair split between directory slots, since the
second half will be found as the first value in a directory
entry, but cannot be added to the result buffer yet. Only
when the following (logically preceding directory slot is
processed, the last value is the first half of the surrogate
pair and only then can the converted UTF-8 sequence be added
to the result buffer. The high surrogate must be stored in
the context of the calling function and provided on the next
iteration (also true for writing pairs over slot bondaries).
Surrogate pairs within a directory slot can easily be
converted, though.

There are already functions that have up to 1KB of local
variables, and if such a buffer was accepted to hold the
full UTF-16 encoded name, the code could be significantly
simplified.

Regards, STefan