All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Pali Rohár" <pali.rohar@gmail.com>
To: Namjae Jeon <namjae.jeon@samsung.com>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	gregkh@linuxfoundation.org, valdis.kletnieks@vt.edu, hch@lst.de,
	sj1557.seo@samsung.com, linkinjeon@gmail.com
Subject: Re: [PATCH v9 10/13] exfat: add nls operations
Date: Fri, 3 Jan 2020 13:31:14 +0100	[thread overview]
Message-ID: <20200103123114.vm23vqag5dbry2mu@pali> (raw)
In-Reply-To: <20200103094030.zg4p5bqos32gc4hy@pali>

On Friday 03 January 2020 10:40:30 Pali Rohár wrote:
> On Thursday 02 January 2020 16:20:33 Namjae Jeon wrote:
> > This adds the implementation of nls operations for exfat.
> > 
> > Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
> > Signed-off-by: Sungjong Seo <sj1557.seo@samsung.com>
> > ---
> >  fs/exfat/nls.c | 809 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 809 insertions(+)
> >  create mode 100644 fs/exfat/nls.c
> > 
> > diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c
> > new file mode 100644
> > index 000000000000..af52328e28ff
> > --- /dev/null
> > +++ b/fs/exfat/nls.c
> 
> ...
> 
> > +static int exfat_convert_uni_to_ch(struct nls_table *nls, unsigned short uni,
> > +		unsigned char *ch, int *lossy)
> > +{
> > +	int len;
> > +
> > +	ch[0] = 0x0;
> > +
> > +	if (uni < 0x0080) {
> > +		ch[0] = uni;
> > +		return 1;
> > +	}
> > +
> > +	len = nls->uni2char(uni, ch, MAX_CHARSET_SIZE);
> > +	if (len < 0) {
> > +		/* conversion failed */
> > +		if (lossy != NULL)
> > +			*lossy |= NLS_NAME_LOSSY;
> > +		ch[0] = '_';
> > +		return 1;
> > +	}
> > +	return len;
> > +}
> 
> Hello! This function takes one UCS-2 character in host endianity and
> converts it to one byte (via specified 8bit encoding).
> 
> > +static int __exfat_nls_uni16s_to_vfsname(struct super_block *sb,
> > +		struct exfat_uni_name *p_uniname, unsigned char *p_cstring,
> > +		int buflen)
> > +{
> > +	int i, j, len, out_len = 0;
> > +	unsigned char buf[MAX_CHARSET_SIZE];
> > +	const unsigned short *uniname = p_uniname->name;
> > +	struct nls_table *nls = EXFAT_SB(sb)->nls_io;
> > +
> > +	i = 0;
> > +	while (i < MAX_NAME_LENGTH && out_len < (buflen - 1)) {
> > +		if (*uniname == '\0')
> > +			break;
> > +
> > +		len = exfat_convert_uni_to_ch(nls, *uniname, buf, NULL);
> > +		if (out_len + len >= buflen)
> > +			len = buflen - 1 - out_len;
> > +		out_len += len;
> > +
> > +		if (len > 1) {
> > +			for (j = 0; j < len; j++)
> > +				*p_cstring++ = buf[j];
> > +		} else { /* len == 1 */
> > +			*p_cstring++ = *buf;
> > +		}
> > +
> > +		uniname++;
> > +		i++;
> > +	}
> > +
> > +	*p_cstring = '\0';
> > +	return out_len;
> > +}
> > +
> 
> This function takes UCS-2 buffer in host endianity and converts it to
> string in specified 8bit encoding.
> 
> > +
> > +int exfat_nls_uni16s_to_vfsname(struct super_block *sb,
> > +		struct exfat_uni_name *uniname, unsigned char *p_cstring,
> > +		int buflen)
> > +{
> 
> Looking at the code and this function is called from dir.c to translate
> exfat filename buffer stored in filesystem to format expected by VFS
> layer.
> 
> On exfat filesystem file names are always stored in UTF-16LE...
> 
> > +	if (EXFAT_SB(sb)->options.utf8)
> > +		return __exfat_nls_utf16s_to_vfsname(sb, uniname, p_cstring,
> > +				buflen);
> > +	return __exfat_nls_uni16s_to_vfsname(sb, uniname, p_cstring, buflen);
> 
> ... and therefore above "__exfat_nls_uni16s_to_vfsname" function must
> expect UTF-16LE buffer and not just UCS-2 buffer in host endianity.
> 
> So two other things needs to be done: Convert character from little
> endian to host endianity and then process UTF-16 buffer and not only
> UCS-2.
> 
> I see that in kernel NLS module is missing a function for converting
> UTF-16 string to UTF-32 (encoding in which every code point is
> represented just by one u32 variable). Kernel has only utf16s_to_utf8s()
> and utf8_to_utf32().

What about just filtering two u16 (one surrogate pair)? Existing NLS
modules do not support code points above U+FFFF so two u16 (one
surrogate pair) just needs to be converted to one replacement character.

diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c
index 81d75aed9..f626a0a89 100644
--- a/fs/exfat/nls.c
+++ b/fs/exfat/nls.c
@@ -545,7 +545,10 @@ static int __exfat_nls_vfsname_to_utf16s(struct super_block *sb,
 	return unilen;
 }
 
-static int __exfat_nls_uni16s_to_vfsname(struct super_block *sb,
+#define SURROGATE_PAIR		0x0000d800
+#define SURROGATE_LOW		0x00000400
+
+static int __exfat_nls_utf16s_to_vfsname(struct super_block *sb,
 		struct exfat_uni_name *p_uniname, unsigned char *p_cstring,
 		int buflen)
 {
@@ -559,7 +562,23 @@ static int __exfat_nls_uni16s_to_vfsname(struct super_block *sb,
 		if (*uniname == '\0')
 			break;
 
-		len = exfat_convert_uni_to_ch(nls, *uniname, buf, NULL);
+		if ((*uniname & SURROGATE_MASK) != SURROGATE_PAIR) {
+			len = exfat_convert_uni_to_ch(nls, *uniname, buf, NULL);
+		} else {
+			/* Process UTF-16 surrogate pair as one character */
+			if (!(*uniname & SURROGATE_LOW) && i+1 < MAX_NAME_LENGTH &&
+			    (*(uniname+1) & SURROGATE_MASK) == SURROGATE_PAIR &&
+			    (*(uniname+1) & SURROGATE_LOW)) {
+				uniname++;
+				i++;
+			}
+			/* UTF-16 surrogate pair encodes code points above Ux+FFFF.
+			 * Code points above U+FFFF are not supported by kernel NLS
+			 * framework therefore use replacement character */
+			len = 1;
+			buf[0] = '_';
+		}
+
 		if (out_len + len >= buflen)
 			len = buflen - 1 - out_len;
 		out_len += len;
@@ -623,7 +642,7 @@ int exfat_nls_uni16s_to_vfsname(struct super_block *sb,
 	if (EXFAT_SB(sb)->options.utf8)
 		return __exfat_nls_utf16s_to_vfsname(sb, uniname, p_cstring,
 				buflen);
-	return __exfat_nls_uni16s_to_vfsname(sb, uniname, p_cstring, buflen);
+	return __exfat_nls_utf16s_to_vfsname(sb, uniname, p_cstring, buflen);
 }
 
 int exfat_nls_vfsname_to_uni16s(struct super_block *sb,

I have not tested this code, it is just an idea how to quick & dirty
solve this problem that NLS framework works with UCS-2 encoding and
UCS-4/UTF-32 or UTF-16.

> > +}
> 
> Btw, have you tested this exfat implementation on some big endian
> system? I think it cannot work because of missing conversion from
> UTF-16LE to UTF-16 in host endianity (therefore UTF-16BE).

Now I figured out that conversion from UTF-16LE to UTF-16 host endianity
is already done in exfat_extract_uni_name() function, called from
exfat_get_uniname_from_ext_entry() function. exfat_nls_uni16s_to_vfsname
is then called on result from exfat_get_uniname_from_ext_entry(), so
UTF-16LE processing on big endian systems should work. Sorry for that.

-- 
Pali Rohár
pali.rohar@gmail.com

  reply	other threads:[~2020-01-03 12:31 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20200102082359epcas1p2aa1eca9729a6ec54ec3b8140615dca6e@epcas1p2.samsung.com>
2020-01-02  8:20 ` [PATCH v9 00/13] add the latest exfat driver Namjae Jeon
2020-01-02  8:20   ` [PATCH v9 01/13] exfat: add in-memory and on-disk structures and headers Namjae Jeon
2020-01-08 17:08     ` Christoph Hellwig
2020-01-09 22:43       ` Namjae Jeon
2020-01-02  8:20   ` [PATCH v9 02/13] exfat: add super block operations Namjae Jeon
2020-01-08 17:21     ` Christoph Hellwig
2020-01-09 23:21       ` Namjae Jeon
2020-01-02  8:20   ` [PATCH v9 03/13] exfat: add inode operations Namjae Jeon
2020-01-08 17:50     ` Christoph Hellwig
2020-01-09 23:23       ` Namjae Jeon
2020-01-02  8:20   ` [PATCH v9 04/13] exfat: add directory operations Namjae Jeon
2020-01-08 17:52     ` Christoph Hellwig
2020-01-02  8:20   ` [PATCH v9 05/13] exfat: add file operations Namjae Jeon
2020-01-08 17:56     ` Christoph Hellwig
2020-01-02  8:20   ` [PATCH v9 06/13] exfat: add exfat entry operations Namjae Jeon
2020-01-08 18:00     ` Christoph Hellwig
2020-01-09 23:24       ` Namjae Jeon
2020-01-02  8:20   ` [PATCH v9 07/13] exfat: add bitmap operations Namjae Jeon
2020-01-08 18:01     ` Christoph Hellwig
2020-01-02  8:20   ` [PATCH v9 08/13] exfat: add exfat cache Namjae Jeon
2020-01-08 18:02     ` Christoph Hellwig
2020-01-02  8:20   ` [PATCH v9 09/13] exfat: add misc operations Namjae Jeon
2020-01-02  9:19     ` Pali Rohár
2020-01-02 11:30       ` Namjae Jeon
2020-01-02 11:40         ` Pali Rohár
2020-01-03 18:36           ` Pali Rohár
2020-01-03 23:28             ` Namjae Jeon
2020-01-08 18:03       ` Christoph Hellwig
2020-01-08 19:40         ` Arnd Bergmann
2020-01-09 23:32           ` Namjae Jeon
2020-01-02  8:20   ` [PATCH v9 10/13] exfat: add nls operations Namjae Jeon
2020-01-02 13:55     ` Pali Rohár
2020-01-03  7:06       ` Namjae Jeon
2020-01-03  8:44         ` Pali Rohár
2020-01-02 14:20     ` Pali Rohár
2020-01-03  4:44       ` Namjae Jeon
2020-01-03  9:40     ` Pali Rohár
2020-01-03 12:31       ` Pali Rohár [this message]
2020-01-09 22:35         ` Namjae Jeon
2020-01-05 15:24     ` Pali Rohár
2020-01-05 16:51     ` Pali Rohár
2020-01-06 19:46       ` Gabriel Krisman Bertazi
2020-01-07 11:52         ` Pali Rohár
2020-01-09 22:04           ` [PATCH v9 09/13] exfat: add misc operations Valdis Klētnieks
2020-01-09 23:41             ` Namjae Jeon
2020-01-09 22:37       ` [PATCH v9 10/13] exfat: add nls operations Namjae Jeon
2020-01-02  8:20   ` [PATCH v9 11/13] exfat: add Kconfig and Makefile Namjae Jeon
2020-01-02 12:53     ` Pali Rohár
2020-01-02  8:20   ` [PATCH v9 12/13] exfat: add exfat in fs/Kconfig and fs/Makefile Namjae Jeon
2020-01-02 12:58     ` Pali Rohár
2020-01-02 13:07       ` Namjae Jeon
2020-01-02 13:10         ` Pali Rohár
2020-01-02 14:19         ` Greg KH
2020-01-02 23:48           ` Namjae Jeon
2020-01-04  5:22     ` kbuild test robot
2020-01-04  5:22       ` kbuild test robot
2020-01-02  8:20   ` [PATCH v9 13/13] MAINTAINERS: add exfat filesystem Namjae Jeon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200103123114.vm23vqag5dbry2mu@pali \
    --to=pali.rohar@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hch@lst.de \
    --cc=linkinjeon@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=namjae.jeon@samsung.com \
    --cc=sj1557.seo@samsung.com \
    --cc=valdis.kletnieks@vt.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.