This is the mail archive of the cygwin mailing list for the Cygwin project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [1.7] Invalid UTF8 while creating a file -> cannot delete?

On Sep 16 00:38, Lapo Luchini wrote:
> Andy Koppe wrote:
> > Hmm, we've lost the \xDF somewhere, and I'd guess it was when the
> > filename got translated to UTF-16 in fopen(), which would explain what
> > you're seeing
> More data: it's not simply "the last character", is something more
> complex than that.
> % cat t.c
> int main() {
>     fopen("a-\xF6\xE4\xFC\xDF", "w"); //ISO-8859-1
>     fopen("b-\xF6\xE4\xFC\xDFz", "w");
>     fopen("c-\xF6\xE4\xFC\xDFzz", "w");
>     fopen("d-\xF6\xE4\xFC\xDFzzz", "w");
>     fopen("e-\xF6\xE4\xFC\xDF\xF6\xE4\xFC\xDF", "w");
>     return 0;
> }

Ok, I see what happens.  The problem is that the mechanism which is
supposed to handle invalid multibyte sequences handles the first such
byte, but misses to reset the multibyte shift state after the byte has
been handled.  Basically, resetting the shift state after such a
sequence has been encountered fixes that problem.

Unfortunately this is only the first half of a solution.  This is what
`ls' prints after running t:

  $ ls -l --show-control-chars
  total 21
  -rw-r--r-- 1 corinna vinschen     0 Sep 21 17:35 a-öäü�
  -rw-r--r-- 1 corinna vinschen     0 Sep 21 17:35 c-öäü�zz
  -rw-r--r-- 1 corinna vinschen     0 Sep 21 17:35 d-öäü�zzz
  -rw-r--r-- 1 corinna vinschen     0 Sep 21 17:35 e-öäü�öäü�

But this is what ls prints when setting $LANG to something "non-C":

  $ setenv LANG en	(implies codepage 1252)
  $ ls -l --show-control-chars
  ls: cannot access a-öäü�: No such file or directory
  ls: cannot access c-öäü�zz: No such file or directory
  ls: cannot access d-öäü�zzz: No such file or directory
  ls: cannot access e-öäü�öäü�: No such file or directory
  total 21
  -????????? ? ?       ?            ?                ? a-öäü�
  -????????? ? ?       ?            ?                ? c-öäü�zz
  -????????? ? ?       ?            ?                ? d-öäü�zzz
  -????????? ? ?       ?            ?                ? e-öäü�öäü�

As you might know, invalid bytes >= 0x80 are translated to UTF-16 by
transposing them into the 0xdc00 - 0xdcff range by just or'ing 0xdc00.
The problem now is that readdir() will return the transposed characters
as if they are the original characters.  ls uses some mbtowc function
to create a valid widechar string, and then uses the resulting widechar
string in some wctomb function to call stat().  However, *that* string
will use a valid mutlibyte sequence to represent the character and the
resulting filename is suddenly different from the actual filename on
disk and stat returns with errno set to ENOENT.
Since the conversion fro and to is independent of each other, there's
no way to detect whether the incoming string of a wctomb was originally
based on a transposed character or not.

I'm not sure if I could explain this clear enough...

So it looks like the current mechanism to handle invalid multibyte
sequences is too complicated for us.  As far as I can see, it would be
much simpler and less error prone to translate the invalid bytes simply
to the equivalent UTF-16 value.  That creates filenames with UTF-16
values from the ISO-8859-1 range.  I tested this with the files created
by the above testcase.  While the filenames appeared to be different
dependent on the used charset, ls always handled the files gracefully.

Any objections?  I can also just check it in and the entire locale
challenged part of the community can test it...


Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

Problem reports:
Unsubscribe info:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]