/*
|
/*
|
* util.c - Miscellaneous support
|
* util.c - Miscellaneous support
|
*
|
*
|
* Copyright (C) 1997,1999 Martin von Löwis
|
* Copyright (C) 1997,1999 Martin von Löwis
|
* Copyright (C) 1997 Régis Duchesne
|
* Copyright (C) 1997 Régis Duchesne
|
* Copyright (C) 2001 Anton Altaparmakov (AIA)
|
* Copyright (C) 2001 Anton Altaparmakov (AIA)
|
*
|
*
|
* The utf8 routines are copied from Python wstrop module.
|
* The utf8 routines are copied from Python wstrop module.
|
*/
|
*/
|
|
|
#include "ntfstypes.h"
|
#include "ntfstypes.h"
|
#include "struct.h"
|
#include "struct.h"
|
#include "util.h"
|
#include "util.h"
|
#include <linux/string.h>
|
#include <linux/string.h>
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <asm/div64.h> /* For do_div(). */
|
#include <asm/div64.h> /* For do_div(). */
|
#include "support.h"
|
#include "support.h"
|
|
|
/*
|
/*
|
* Converts a single wide character to a sequence of utf8 bytes.
|
* Converts a single wide character to a sequence of utf8 bytes.
|
* The character is represented in host byte order.
|
* The character is represented in host byte order.
|
* Returns the number of bytes, or 0 on error.
|
* Returns the number of bytes, or 0 on error.
|
*/
|
*/
|
static int to_utf8(ntfs_u16 c, unsigned char *buf)
|
static int to_utf8(ntfs_u16 c, unsigned char *buf)
|
{
|
{
|
if (c == 0)
|
if (c == 0)
|
return 0; /* No support for embedded 0 runes. */
|
return 0; /* No support for embedded 0 runes. */
|
if (c < 0x80) {
|
if (c < 0x80) {
|
if (buf)
|
if (buf)
|
buf[0] = (unsigned char)c;
|
buf[0] = (unsigned char)c;
|
return 1;
|
return 1;
|
}
|
}
|
if (c < 0x800) {
|
if (c < 0x800) {
|
if (buf) {
|
if (buf) {
|
buf[0] = 0xc0 | (c >> 6);
|
buf[0] = 0xc0 | (c >> 6);
|
buf[1] = 0x80 | (c & 0x3f);
|
buf[1] = 0x80 | (c & 0x3f);
|
}
|
}
|
return 2;
|
return 2;
|
}
|
}
|
/* c < 0x10000 */
|
/* c < 0x10000 */
|
if (buf) {
|
if (buf) {
|
buf[0] = 0xe0 | (c >> 12);
|
buf[0] = 0xe0 | (c >> 12);
|
buf[1] = 0x80 | ((c >> 6) & 0x3f);
|
buf[1] = 0x80 | ((c >> 6) & 0x3f);
|
buf[2] = 0x80 | (c & 0x3f);
|
buf[2] = 0x80 | (c & 0x3f);
|
}
|
}
|
return 3;
|
return 3;
|
}
|
}
|
|
|
/*
|
/*
|
* Decodes a sequence of utf8 bytes into a single wide character.
|
* Decodes a sequence of utf8 bytes into a single wide character.
|
* The character is returned in host byte order.
|
* The character is returned in host byte order.
|
* Returns the number of bytes consumed, or 0 on error.
|
* Returns the number of bytes consumed, or 0 on error.
|
*/
|
*/
|
static int from_utf8(const unsigned char *str, ntfs_u16 *c)
|
static int from_utf8(const unsigned char *str, ntfs_u16 *c)
|
{
|
{
|
int l = 0, i;
|
int l = 0, i;
|
|
|
if (*str < 0x80) {
|
if (*str < 0x80) {
|
*c = *str;
|
*c = *str;
|
return 1;
|
return 1;
|
}
|
}
|
if (*str < 0xc0) /* Lead byte must not be 10xxxxxx. */
|
if (*str < 0xc0) /* Lead byte must not be 10xxxxxx. */
|
return 0; /* Is c0 a possible lead byte? */
|
return 0; /* Is c0 a possible lead byte? */
|
if (*str < 0xe0) { /* 110xxxxx */
|
if (*str < 0xe0) { /* 110xxxxx */
|
*c = *str & 0x1f;
|
*c = *str & 0x1f;
|
l = 2;
|
l = 2;
|
} else if (*str < 0xf0) { /* 1110xxxx */
|
} else if (*str < 0xf0) { /* 1110xxxx */
|
*c = *str & 0xf;
|
*c = *str & 0xf;
|
l = 3;
|
l = 3;
|
} else if (*str < 0xf8) { /* 11110xxx */
|
} else if (*str < 0xf8) { /* 11110xxx */
|
*c = *str & 7;
|
*c = *str & 7;
|
l = 4;
|
l = 4;
|
} else /* We don't support characters above 0xFFFF in NTFS. */
|
} else /* We don't support characters above 0xFFFF in NTFS. */
|
return 0;
|
return 0;
|
for (i = 1; i < l; i++) {
|
for (i = 1; i < l; i++) {
|
/* All other bytes must be 10xxxxxx. */
|
/* All other bytes must be 10xxxxxx. */
|
if ((str[i] & 0xc0) != 0x80)
|
if ((str[i] & 0xc0) != 0x80)
|
return 0;
|
return 0;
|
*c <<= 6;
|
*c <<= 6;
|
*c |= str[i] & 0x3f;
|
*c |= str[i] & 0x3f;
|
}
|
}
|
return l;
|
return l;
|
}
|
}
|
|
|
/*
|
/*
|
* Converts wide string to UTF-8. Expects two in- and two out-parameters.
|
* Converts wide string to UTF-8. Expects two in- and two out-parameters.
|
* Returns 0 on success, or error code.
|
* Returns 0 on success, or error code.
|
* The caller has to free the result string.
|
* The caller has to free the result string.
|
*/
|
*/
|
static int ntfs_dupuni2utf8(ntfs_u16 *in, int in_len, char **out, int *out_len)
|
static int ntfs_dupuni2utf8(ntfs_u16 *in, int in_len, char **out, int *out_len)
|
{
|
{
|
int i, tmp;
|
int i, tmp;
|
int len8;
|
int len8;
|
unsigned char *result;
|
unsigned char *result;
|
|
|
ntfs_debug(DEBUG_NAME1, "converting l = %d\n", in_len);
|
ntfs_debug(DEBUG_NAME1, "converting l = %d\n", in_len);
|
/* Count the length of the resulting UTF-8. */
|
/* Count the length of the resulting UTF-8. */
|
for (i = len8 = 0; i < in_len; i++) {
|
for (i = len8 = 0; i < in_len; i++) {
|
tmp = to_utf8(NTFS_GETU16(in + i), 0);
|
tmp = to_utf8(NTFS_GETU16(in + i), 0);
|
if (!tmp)
|
if (!tmp)
|
/* Invalid character. */
|
/* Invalid character. */
|
return -EILSEQ;
|
return -EILSEQ;
|
len8 += tmp;
|
len8 += tmp;
|
}
|
}
|
*out = result = ntfs_malloc(len8 + 1); /* allow for zero-termination */
|
*out = result = ntfs_malloc(len8 + 1); /* allow for zero-termination */
|
if (!result)
|
if (!result)
|
return -ENOMEM;
|
return -ENOMEM;
|
result[len8] = '\0';
|
result[len8] = '\0';
|
*out_len = len8;
|
*out_len = len8;
|
for (i = len8 = 0; i < in_len; i++)
|
for (i = len8 = 0; i < in_len; i++)
|
len8 += to_utf8(NTFS_GETU16(in + i), result + len8);
|
len8 += to_utf8(NTFS_GETU16(in + i), result + len8);
|
ntfs_debug(DEBUG_NAME1, "result %p:%s\n", result, result);
|
ntfs_debug(DEBUG_NAME1, "result %p:%s\n", result, result);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/*
|
/*
|
* Converts an UTF-8 sequence to a wide string. Same conventions as the
|
* Converts an UTF-8 sequence to a wide string. Same conventions as the
|
* previous function.
|
* previous function.
|
*/
|
*/
|
static int ntfs_duputf82uni(unsigned char* in, int in_len, ntfs_u16** out,
|
static int ntfs_duputf82uni(unsigned char* in, int in_len, ntfs_u16** out,
|
int *out_len)
|
int *out_len)
|
{
|
{
|
int i, tmp;
|
int i, tmp;
|
int len16;
|
int len16;
|
ntfs_u16* result;
|
ntfs_u16* result;
|
ntfs_u16 wtmp;
|
ntfs_u16 wtmp;
|
|
|
for (i = len16 = 0; i < in_len; i += tmp, len16++) {
|
for (i = len16 = 0; i < in_len; i += tmp, len16++) {
|
tmp = from_utf8(in + i, &wtmp);
|
tmp = from_utf8(in + i, &wtmp);
|
if (!tmp)
|
if (!tmp)
|
return -EILSEQ;
|
return -EILSEQ;
|
}
|
}
|
*out = result = ntfs_malloc(2 * (len16 + 1));
|
*out = result = ntfs_malloc(2 * (len16 + 1));
|
if (!result)
|
if (!result)
|
return -ENOMEM;
|
return -ENOMEM;
|
result[len16] = 0;
|
result[len16] = 0;
|
*out_len = len16;
|
*out_len = len16;
|
for (i = len16 = 0; i < in_len; i += tmp, len16++) {
|
for (i = len16 = 0; i < in_len; i += tmp, len16++) {
|
tmp = from_utf8(in + i, &wtmp);
|
tmp = from_utf8(in + i, &wtmp);
|
NTFS_PUTU16(result + len16, wtmp);
|
NTFS_PUTU16(result + len16, wtmp);
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Encodings dispatchers. */
|
/* Encodings dispatchers. */
|
int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
|
int ntfs_encodeuni(ntfs_volume *vol, ntfs_u16 *in, int in_len, char **out,
|
int *out_len)
|
int *out_len)
|
{
|
{
|
if (vol->nls_map)
|
if (vol->nls_map)
|
return ntfs_dupuni2map(vol, in, in_len, out, out_len);
|
return ntfs_dupuni2map(vol, in, in_len, out, out_len);
|
else
|
else
|
return ntfs_dupuni2utf8(in, in_len, out, out_len);
|
return ntfs_dupuni2utf8(in, in_len, out, out_len);
|
}
|
}
|
|
|
int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out,
|
int ntfs_decodeuni(ntfs_volume *vol, char *in, int in_len, ntfs_u16 **out,
|
int *out_len)
|
int *out_len)
|
{
|
{
|
if (vol->nls_map)
|
if (vol->nls_map)
|
return ntfs_dupmap2uni(vol, in, in_len, out, out_len);
|
return ntfs_dupmap2uni(vol, in, in_len, out, out_len);
|
else
|
else
|
return ntfs_duputf82uni(in, in_len, out, out_len);
|
return ntfs_duputf82uni(in, in_len, out, out_len);
|
}
|
}
|
|
|
/* Same address space copies. */
|
/* Same address space copies. */
|
void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n)
|
void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n)
|
{
|
{
|
ntfs_memcpy(dest->param, src, n);
|
ntfs_memcpy(dest->param, src, n);
|
((char*)dest->param) += n;
|
((char*)dest->param) += n;
|
}
|
}
|
|
|
void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n)
|
void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n)
|
{
|
{
|
ntfs_memcpy(dest, src->param, n);
|
ntfs_memcpy(dest, src->param, n);
|
((char*)src->param) += n;
|
((char*)src->param) += n;
|
}
|
}
|
|
|
void *ntfs_calloc(int size)
|
void *ntfs_calloc(int size)
|
{
|
{
|
void *result = ntfs_malloc(size);
|
void *result = ntfs_malloc(size);
|
if (result)
|
if (result)
|
ntfs_bzero(result, size);
|
ntfs_bzero(result, size);
|
return result;
|
return result;
|
}
|
}
|
|
|
/* Copy len ascii characters from from to to. :) */
|
/* Copy len ascii characters from from to to. :) */
|
void ntfs_ascii2uni(short int *to, char *from, int len)
|
void ntfs_ascii2uni(short int *to, char *from, int len)
|
{
|
{
|
int i;
|
int i;
|
|
|
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
NTFS_PUTU16(to + i, from[i]);
|
NTFS_PUTU16(to + i, from[i]);
|
to[i] = 0;
|
to[i] = 0;
|
}
|
}
|
|
|
/* strncmp for Unicode strings. */
|
/* strncmp for Unicode strings. */
|
int ntfs_uni_strncmp(short int* a, short int *b, int n)
|
int ntfs_uni_strncmp(short int* a, short int *b, int n)
|
{
|
{
|
int i;
|
int i;
|
|
|
for(i = 0; i < n; i++)
|
for(i = 0; i < n; i++)
|
{
|
{
|
if (NTFS_GETU16(a + i) < NTFS_GETU16(b + i))
|
if (NTFS_GETU16(a + i) < NTFS_GETU16(b + i))
|
return -1;
|
return -1;
|
if (NTFS_GETU16(b + i) < NTFS_GETU16(a + i))
|
if (NTFS_GETU16(b + i) < NTFS_GETU16(a + i))
|
return 1;
|
return 1;
|
if (NTFS_GETU16(a + i) == 0)
|
if (NTFS_GETU16(a + i) == 0)
|
break;
|
break;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* strncmp between Unicode and ASCII strings. */
|
/* strncmp between Unicode and ASCII strings. */
|
int ntfs_ua_strncmp(short int* a, char* b, int n)
|
int ntfs_ua_strncmp(short int* a, char* b, int n)
|
{
|
{
|
int i;
|
int i;
|
|
|
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
if(NTFS_GETU16(a + i) < b[i])
|
if(NTFS_GETU16(a + i) < b[i])
|
return -1;
|
return -1;
|
if(b[i] < NTFS_GETU16(a + i))
|
if(b[i] < NTFS_GETU16(a + i))
|
return 1;
|
return 1;
|
if (b[i] == 0)
|
if (b[i] == 0)
|
return 0;
|
return 0;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
#define NTFS_TIME_OFFSET ((ntfs_time64_t)(369*365 + 89) * 24 * 3600 * 10000000)
|
#define NTFS_TIME_OFFSET ((ntfs_time64_t)(369*365 + 89) * 24 * 3600 * 10000000)
|
|
|
/* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units)
|
/* Convert the NT UTC (based 1.1.1601, in hundred nanosecond units)
|
* into Unix UTC (based 1.1.1970, in seconds). */
|
* into Unix UTC (based 1.1.1970, in seconds). */
|
ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc)
|
ntfs_time_t ntfs_ntutc2unixutc(ntfs_time64_t ntutc)
|
{
|
{
|
/* Subtract the NTFS time offset, then convert to 1s intervals. */
|
/* Subtract the NTFS time offset, then convert to 1s intervals. */
|
ntfs_time64_t t = ntutc - NTFS_TIME_OFFSET;
|
ntfs_time64_t t = ntutc - NTFS_TIME_OFFSET;
|
do_div(t, 10000000);
|
do_div(t, 10000000);
|
return (ntfs_time_t)t;
|
return (ntfs_time_t)t;
|
}
|
}
|
|
|
/* Convert the Unix UTC into NT UTC. */
|
/* Convert the Unix UTC into NT UTC. */
|
ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t)
|
ntfs_time64_t ntfs_unixutc2ntutc(ntfs_time_t t)
|
{
|
{
|
/* Convert to 100ns intervals and then add the NTFS time offset. */
|
/* Convert to 100ns intervals and then add the NTFS time offset. */
|
return (ntfs_time64_t)t * 10000000 + NTFS_TIME_OFFSET;
|
return (ntfs_time64_t)t * 10000000 + NTFS_TIME_OFFSET;
|
}
|
}
|
|
|
#undef NTFS_TIME_OFFSET
|
#undef NTFS_TIME_OFFSET
|
|
|
/* Fill index name. */
|
/* Fill index name. */
|
void ntfs_indexname(char *buf, int type)
|
void ntfs_indexname(char *buf, int type)
|
{
|
{
|
char hex[] = "0123456789ABCDEF";
|
char hex[] = "0123456789ABCDEF";
|
int index;
|
int index;
|
*buf++ = '$';
|
*buf++ = '$';
|
*buf++ = 'I';
|
*buf++ = 'I';
|
for (index = 24; index > 0; index -= 4)
|
for (index = 24; index > 0; index -= 4)
|
if ((0xF << index) & type)
|
if ((0xF << index) & type)
|
break;
|
break;
|
while (index >= 0) {
|
while (index >= 0) {
|
*buf++ = hex[(type >> index) & 0xF];
|
*buf++ = hex[(type >> index) & 0xF];
|
index -= 4;
|
index -= 4;
|
}
|
}
|
*buf = '\0';
|
*buf = '\0';
|
}
|
}
|
|
|
|
|