2019-04-25 20:51:22 +03:00
/* SPDX-License-Identifier: GPL-2.0 */
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/parser.h>
# include <linux/errno.h>
2020-07-08 12:12:34 +03:00
# include <linux/stringhash.h>
2019-04-25 20:51:22 +03:00
# include "utf8n.h"
int utf8_validate ( const struct unicode_map * um , const struct qstr * str )
{
2021-09-15 10:00:04 +03:00
if ( utf8nlen ( um , UTF8_NFDI , str - > name , str - > len ) < 0 )
2019-04-25 20:51:22 +03:00
return - 1 ;
return 0 ;
}
EXPORT_SYMBOL ( utf8_validate ) ;
int utf8_strncmp ( const struct unicode_map * um ,
const struct qstr * s1 , const struct qstr * s2 )
{
struct utf8cursor cur1 , cur2 ;
int c1 , c2 ;
2021-09-15 10:00:04 +03:00
if ( utf8ncursor ( & cur1 , um , UTF8_NFDI , s1 - > name , s1 - > len ) < 0 )
2019-04-25 20:51:22 +03:00
return - EINVAL ;
2021-09-15 10:00:04 +03:00
if ( utf8ncursor ( & cur2 , um , UTF8_NFDI , s2 - > name , s2 - > len ) < 0 )
2019-04-25 20:51:22 +03:00
return - EINVAL ;
do {
c1 = utf8byte ( & cur1 ) ;
c2 = utf8byte ( & cur2 ) ;
if ( c1 < 0 | | c2 < 0 )
return - EINVAL ;
if ( c1 ! = c2 )
return 1 ;
} while ( c1 ) ;
return 0 ;
}
EXPORT_SYMBOL ( utf8_strncmp ) ;
int utf8_strncasecmp ( const struct unicode_map * um ,
const struct qstr * s1 , const struct qstr * s2 )
{
struct utf8cursor cur1 , cur2 ;
int c1 , c2 ;
2021-09-15 10:00:04 +03:00
if ( utf8ncursor ( & cur1 , um , UTF8_NFDICF , s1 - > name , s1 - > len ) < 0 )
2019-04-25 20:51:22 +03:00
return - EINVAL ;
2021-09-15 10:00:04 +03:00
if ( utf8ncursor ( & cur2 , um , UTF8_NFDICF , s2 - > name , s2 - > len ) < 0 )
2019-04-25 20:51:22 +03:00
return - EINVAL ;
do {
c1 = utf8byte ( & cur1 ) ;
c2 = utf8byte ( & cur2 ) ;
if ( c1 < 0 | | c2 < 0 )
return - EINVAL ;
if ( c1 ! = c2 )
return 1 ;
} while ( c1 ) ;
return 0 ;
}
EXPORT_SYMBOL ( utf8_strncasecmp ) ;
2019-06-20 06:45:09 +03:00
/* String cf is expected to be a valid UTF-8 casefolded
* string .
*/
int utf8_strncasecmp_folded ( const struct unicode_map * um ,
const struct qstr * cf ,
const struct qstr * s1 )
{
struct utf8cursor cur1 ;
int c1 , c2 ;
int i = 0 ;
2021-09-15 10:00:04 +03:00
if ( utf8ncursor ( & cur1 , um , UTF8_NFDICF , s1 - > name , s1 - > len ) < 0 )
2019-06-20 06:45:09 +03:00
return - EINVAL ;
do {
c1 = utf8byte ( & cur1 ) ;
c2 = cf - > name [ i + + ] ;
if ( c1 < 0 )
return - EINVAL ;
if ( c1 ! = c2 )
return 1 ;
} while ( c1 ) ;
return 0 ;
}
EXPORT_SYMBOL ( utf8_strncasecmp_folded ) ;
2019-04-25 20:51:22 +03:00
int utf8_casefold ( const struct unicode_map * um , const struct qstr * str ,
unsigned char * dest , size_t dlen )
{
struct utf8cursor cur ;
size_t nlen = 0 ;
2021-09-15 10:00:04 +03:00
if ( utf8ncursor ( & cur , um , UTF8_NFDICF , str - > name , str - > len ) < 0 )
2019-04-25 20:51:22 +03:00
return - EINVAL ;
for ( nlen = 0 ; nlen < dlen ; nlen + + ) {
int c = utf8byte ( & cur ) ;
dest [ nlen ] = c ;
if ( ! c )
return nlen ;
if ( c = = - 1 )
break ;
}
return - EINVAL ;
}
EXPORT_SYMBOL ( utf8_casefold ) ;
2020-07-08 12:12:34 +03:00
int utf8_casefold_hash ( const struct unicode_map * um , const void * salt ,
struct qstr * str )
{
struct utf8cursor cur ;
int c ;
unsigned long hash = init_name_hash ( salt ) ;
2021-09-15 10:00:04 +03:00
if ( utf8ncursor ( & cur , um , UTF8_NFDICF , str - > name , str - > len ) < 0 )
2020-07-08 12:12:34 +03:00
return - EINVAL ;
while ( ( c = utf8byte ( & cur ) ) ) {
if ( c < 0 )
return - EINVAL ;
hash = partial_name_hash ( ( unsigned char ) c , hash ) ;
}
str - > hash = end_name_hash ( hash ) ;
return 0 ;
}
EXPORT_SYMBOL ( utf8_casefold_hash ) ;
2019-04-25 20:51:22 +03:00
int utf8_normalize ( const struct unicode_map * um , const struct qstr * str ,
unsigned char * dest , size_t dlen )
{
struct utf8cursor cur ;
ssize_t nlen = 0 ;
2021-09-15 10:00:04 +03:00
if ( utf8ncursor ( & cur , um , UTF8_NFDI , str - > name , str - > len ) < 0 )
2019-04-25 20:51:22 +03:00
return - EINVAL ;
for ( nlen = 0 ; nlen < dlen ; nlen + + ) {
int c = utf8byte ( & cur ) ;
dest [ nlen ] = c ;
if ( ! c )
return nlen ;
if ( c = = - 1 )
break ;
}
return - EINVAL ;
}
EXPORT_SYMBOL ( utf8_normalize ) ;
2021-09-15 10:00:05 +03:00
static const struct utf8data * find_table_version ( const struct utf8data * table ,
size_t nr_entries , unsigned int version )
{
size_t i = nr_entries - 1 ;
while ( version < table [ i ] . maxage )
i - - ;
if ( version > table [ i ] . maxage )
return NULL ;
return & table [ i ] ;
}
2021-09-15 10:00:00 +03:00
struct unicode_map * utf8_load ( unsigned int version )
2019-04-25 20:51:22 +03:00
{
2021-09-15 10:00:00 +03:00
struct unicode_map * um ;
2019-04-25 20:51:22 +03:00
um = kzalloc ( sizeof ( struct unicode_map ) , GFP_KERNEL ) ;
if ( ! um )
return ERR_PTR ( - ENOMEM ) ;
2021-09-15 10:00:00 +03:00
um - > version = version ;
2021-09-15 10:00:05 +03:00
um - > tables = symbol_request ( utf8_data_table ) ;
if ( ! um - > tables )
2021-09-15 10:00:04 +03:00
goto out_free_um ;
2021-09-15 10:00:05 +03:00
if ( ! utf8version_is_supported ( um , version ) )
goto out_symbol_put ;
um - > ntab [ UTF8_NFDI ] = find_table_version ( um - > tables - > utf8nfdidata ,
um - > tables - > utf8nfdidata_size , um - > version ) ;
if ( ! um - > ntab [ UTF8_NFDI ] )
goto out_symbol_put ;
um - > ntab [ UTF8_NFDICF ] = find_table_version ( um - > tables - > utf8nfdicfdata ,
um - > tables - > utf8nfdicfdata_size , um - > version ) ;
2021-09-15 10:00:04 +03:00
if ( ! um - > ntab [ UTF8_NFDICF ] )
2021-09-15 10:00:05 +03:00
goto out_symbol_put ;
2019-04-25 20:51:22 +03:00
return um ;
2021-09-15 10:00:04 +03:00
2021-09-15 10:00:05 +03:00
out_symbol_put :
symbol_put ( um - > tables ) ;
2021-09-15 10:00:04 +03:00
out_free_um :
kfree ( um ) ;
return ERR_PTR ( - EINVAL ) ;
2019-04-25 20:51:22 +03:00
}
EXPORT_SYMBOL ( utf8_load ) ;
void utf8_unload ( struct unicode_map * um )
{
2021-09-15 10:00:05 +03:00
if ( um ) {
symbol_put ( utf8_data_table ) ;
kfree ( um ) ;
}
2019-04-25 20:51:22 +03:00
}
EXPORT_SYMBOL ( utf8_unload ) ;