162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Copyright (C) International Business Machines Corp., 2000-2004
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/fs.h>
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci#include "jfs_incore.h"
962306a36Sopenharmony_ci#include "jfs_filsys.h"
1062306a36Sopenharmony_ci#include "jfs_unicode.h"
1162306a36Sopenharmony_ci#include "jfs_debug.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * NAME:	jfs_strfromUCS()
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * FUNCTION:	Convert little-endian unicode string to character string
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ciint jfs_strfromUCS_le(char *to, const __le16 * from,
2062306a36Sopenharmony_ci		      int len, struct nls_table *codepage)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	int i;
2362306a36Sopenharmony_ci	int outlen = 0;
2462306a36Sopenharmony_ci	static int warn_again = 5;	/* Only warn up to 5 times total */
2562306a36Sopenharmony_ci	int warn = !!warn_again;	/* once per string */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (codepage) {
2862306a36Sopenharmony_ci		for (i = 0; (i < len) && from[i]; i++) {
2962306a36Sopenharmony_ci			int charlen;
3062306a36Sopenharmony_ci			charlen =
3162306a36Sopenharmony_ci			    codepage->uni2char(le16_to_cpu(from[i]),
3262306a36Sopenharmony_ci					       &to[outlen],
3362306a36Sopenharmony_ci					       NLS_MAX_CHARSET_SIZE);
3462306a36Sopenharmony_ci			if (charlen > 0)
3562306a36Sopenharmony_ci				outlen += charlen;
3662306a36Sopenharmony_ci			else
3762306a36Sopenharmony_ci				to[outlen++] = '?';
3862306a36Sopenharmony_ci		}
3962306a36Sopenharmony_ci	} else {
4062306a36Sopenharmony_ci		for (i = 0; (i < len) && from[i]; i++) {
4162306a36Sopenharmony_ci			if (unlikely(le16_to_cpu(from[i]) & 0xff00)) {
4262306a36Sopenharmony_ci				to[i] = '?';
4362306a36Sopenharmony_ci				if (unlikely(warn)) {
4462306a36Sopenharmony_ci					warn--;
4562306a36Sopenharmony_ci					warn_again--;
4662306a36Sopenharmony_ci					printk(KERN_ERR
4762306a36Sopenharmony_ci			"non-latin1 character 0x%x found in JFS file name\n",
4862306a36Sopenharmony_ci					       le16_to_cpu(from[i]));
4962306a36Sopenharmony_ci					printk(KERN_ERR
5062306a36Sopenharmony_ci				"mount with iocharset=utf8 to access\n");
5162306a36Sopenharmony_ci				}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci			}
5462306a36Sopenharmony_ci			else
5562306a36Sopenharmony_ci				to[i] = (char) (le16_to_cpu(from[i]));
5662306a36Sopenharmony_ci		}
5762306a36Sopenharmony_ci		outlen = i;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci	to[outlen] = 0;
6062306a36Sopenharmony_ci	return outlen;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * NAME:	jfs_strtoUCS()
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci * FUNCTION:	Convert character string to unicode string
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cistatic int jfs_strtoUCS(wchar_t * to, const unsigned char *from, int len,
7062306a36Sopenharmony_ci		struct nls_table *codepage)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	int charlen;
7362306a36Sopenharmony_ci	int i;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (codepage) {
7662306a36Sopenharmony_ci		for (i = 0; len && *from; i++, from += charlen, len -= charlen)
7762306a36Sopenharmony_ci		{
7862306a36Sopenharmony_ci			charlen = codepage->char2uni(from, len, &to[i]);
7962306a36Sopenharmony_ci			if (charlen < 1) {
8062306a36Sopenharmony_ci				jfs_err("jfs_strtoUCS: char2uni returned %d.",
8162306a36Sopenharmony_ci					charlen);
8262306a36Sopenharmony_ci				jfs_err("charset = %s, char = 0x%x",
8362306a36Sopenharmony_ci					codepage->charset, *from);
8462306a36Sopenharmony_ci				return charlen;
8562306a36Sopenharmony_ci			}
8662306a36Sopenharmony_ci		}
8762306a36Sopenharmony_ci	} else {
8862306a36Sopenharmony_ci		for (i = 0; (i < len) && from[i]; i++)
8962306a36Sopenharmony_ci			to[i] = (wchar_t) from[i];
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	to[i] = 0;
9362306a36Sopenharmony_ci	return i;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * NAME:	get_UCSname()
9862306a36Sopenharmony_ci *
9962306a36Sopenharmony_ci * FUNCTION:	Allocate and translate to unicode string
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ciint get_UCSname(struct component_name * uniName, struct dentry *dentry)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct nls_table *nls_tab = JFS_SBI(dentry->d_sb)->nls_tab;
10562306a36Sopenharmony_ci	int length = dentry->d_name.len;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (length > JFS_NAME_MAX)
10862306a36Sopenharmony_ci		return -ENAMETOOLONG;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	uniName->name =
11162306a36Sopenharmony_ci	    kmalloc_array(length + 1, sizeof(wchar_t), GFP_NOFS);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (uniName->name == NULL)
11462306a36Sopenharmony_ci		return -ENOMEM;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name,
11762306a36Sopenharmony_ci				       length, nls_tab);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (uniName->namlen < 0) {
12062306a36Sopenharmony_ci		kfree(uniName->name);
12162306a36Sopenharmony_ci		return uniName->namlen;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
126