"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "libntfs-3g/unistr.c" between
ntfs-3g_ntfsprogs-2016.2.22.tgz and ntfs-3g_ntfsprogs-2017.3.23.tgz

About: NTFS-3G is a read-write NTFS driver for Linux and other operating systems. It provides safe handling of the Windows XP, Windows Server 2003, Windows 2000, Windows Vista, Windows Server 2008, Windows 7 and Windows 8 NTFS file systems.

unistr.c  (ntfs-3g_ntfsprogs-2016.2.22.tgz):unistr.c  (ntfs-3g_ntfsprogs-2017.3.23.tgz)
skipping to change at line 62 skipping to change at line 62
#endif /* defined(__APPLE__) || defined(__DARWIN__) */ #endif /* defined(__APPLE__) || defined(__DARWIN__) */
#include "compat.h" #include "compat.h"
#include "attrib.h" #include "attrib.h"
#include "types.h" #include "types.h"
#include "unistr.h" #include "unistr.h"
#include "debug.h" #include "debug.h"
#include "logging.h" #include "logging.h"
#include "misc.h" #include "misc.h"
#define NOREVBOM 0 /* JPA rejecting U+FFFE and U+FFFF, open to debate */ #ifndef ALLOW_BROKEN_UNICODE
/* Erik allowing broken UTF-16 surrogate pairs and U+FFFE and U+FFFF by default,
* open to debate. */
#define ALLOW_BROKEN_UNICODE 1
#endif /* !defined(ALLOW_BROKEN_UNICODE) */
/* /*
* IMPORTANT * IMPORTANT
* ========= * =========
* *
* All these routines assume that the Unicode characters are in little endian * All these routines assume that the Unicode characters are in little endian
* encoding inside the strings!!! * encoding inside the strings!!!
*/ */
static int use_utf8 = 1; /* use UTF-8 encoding for file names */ static int use_utf8 = 1; /* use UTF-8 encoding for file names */
skipping to change at line 142 skipping to change at line 146
TRUE; TRUE;
} }
/* /*
* ntfs_names_full_collate() fully collate two Unicode names * ntfs_names_full_collate() fully collate two Unicode names
* *
* @name1: first Unicode name to compare * @name1: first Unicode name to compare
* @name1_len: length of first Unicode name to compare * @name1_len: length of first Unicode name to compare
* @name2: second Unicode name to compare * @name2: second Unicode name to compare
* @name2_len: length of second Unicode name to compare * @name2_len: length of second Unicode name to compare
* @ic: either CASE_SENSITIVE or IGNORE_CASE * @ic: either CASE_SENSITIVE or IGNORE_CASE (see below)
* @upcase: upcase table (ignored if @ic is CASE_SENSITIVE) * @upcase: upcase table
* @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE) * @upcase_len: upcase table size
*
* If @ic is CASE_SENSITIVE, then the names are compared primarily ignoring
* case, but if the names are equal ignoring case, then they are compared
* case-sensitively. As an example, "abc" would collate before "BCD" (since
* "abc" and "BCD" differ ignoring case and 'A' < 'B') but after "ABC" (since
* "ABC" and "abc" are equal ignoring case and 'A' < 'a'). This matches the
* collation order of filenames as indexed in NTFS directories.
* *
* -1 if the first name collates before the second one, * If @ic is IGNORE_CASE, then the names are only compared case-insensitively
* 0 if the names match, * and are considered to match if and only if they are equal ignoring case.
* 1 if the second name collates before the first one, or
* *
* Returns:
* -1 if the first name collates before the second one,
* 0 if the names match, or
* 1 if the second name collates before the first one
*/ */
int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len, int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
const ntfschar *name2, const u32 name2_len, const ntfschar *name2, const u32 name2_len,
const IGNORE_CASE_BOOL ic, const ntfschar *upcase, const IGNORE_CASE_BOOL ic, const ntfschar *upcase,
const u32 upcase_len) const u32 upcase_len)
{ {
u32 cnt; u32 cnt;
u16 c1, c2; u16 c1, c2;
u16 u1, u2; u16 u1, u2;
#ifdef DEBUG #ifdef DEBUG
if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) { if (!name1 || !name2 || !upcase || !upcase_len) {
ntfs_log_debug("ntfs_names_collate received NULL pointer!\n"); ntfs_log_debug("ntfs_names_collate received NULL pointer!\n");
exit(1); exit(1);
} }
#endif #endif
cnt = min(name1_len, name2_len); cnt = min(name1_len, name2_len);
if (cnt > 0) { if (cnt > 0) {
if (ic == CASE_SENSITIVE) { if (ic == CASE_SENSITIVE) {
while (--cnt && (*name1 == *name2)) { while (--cnt && (*name1 == *name2)) {
name1++; name1++;
name2++; name2++;
skipping to change at line 204 skipping to change at line 218
if (name1_len < name2_len) if (name1_len < name2_len)
return -1; return -1;
if (name1_len > name2_len) if (name1_len > name2_len)
return 1; return 1;
if (c1 < c2) if (c1 < c2)
return -1; return -1;
if (c1 > c2) if (c1 > c2)
return 1; return 1;
} else { } else {
do { do {
u1 = c1 = le16_to_cpu(*name1); u1 = le16_to_cpu(*name1);
name1++; name1++;
u2 = c2 = le16_to_cpu(*name2); u2 = le16_to_cpu(*name2);
name2++; name2++;
if (u1 < upcase_len) if (u1 < upcase_len)
u1 = le16_to_cpu(upcase[u1]); u1 = le16_to_cpu(upcase[u1]);
if (u2 < upcase_len) if (u2 < upcase_len)
u2 = le16_to_cpu(upcase[u2]); u2 = le16_to_cpu(upcase[u2]);
} while ((u1 == u2) && --cnt); } while ((u1 == u2) && --cnt);
if (u1 < u2) if (u1 < u2)
return -1; return -1;
if (u1 > u2) if (u1 > u2)
return 1; return 1;
skipping to change at line 447 skipping to change at line 461
up and whenever nl_langinfo(CODESET) returns a sting starting with up and whenever nl_langinfo(CODESET) returns a sting starting with
"ANSI", use an internal UCS-2LE <-> UTF-8 codeset converter to fix "ANSI", use an internal UCS-2LE <-> UTF-8 codeset converter to fix
the bug where NTFS-3G does not show any path names which include the bug where NTFS-3G does not show any path names which include
international characters!!! (and also fails on creating them) as result. international characters!!! (and also fails on creating them) as result.
Author: Bernhard Kaindl <bk@suse.de> Author: Bernhard Kaindl <bk@suse.de>
Jean-Pierre Andre made it compliant with RFC3629/RFC2781. Jean-Pierre Andre made it compliant with RFC3629/RFC2781.
*/ */
/* /*
* Return the amount of 8-bit elements in UTF-8 needed (without the terminating * Return the number of bytes in UTF-8 needed (without the terminating null) to
* null) to store a given UTF-16LE string. * store the given UTF-16LE string.
* *
* Return -1 with errno set if string has invalid byte sequence or too long. * On error, -1 is returned, and errno is set to the error code. The following
* error codes can be expected:
* EILSEQ The input string is not valid UTF-16LE (only possible
* if compiled without ALLOW_BROKEN_UNICODE).
* ENAMETOOLONG The length of the UTF-8 string in bytes (without the
* terminating null) would exceed @outs_len.
*/ */
static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l en) static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l en)
{ {
int i, ret = -1; int i, ret = -1;
int count = 0; int count = 0;
BOOL surrog; BOOL surrog;
surrog = FALSE; surrog = FALSE;
for (i = 0; i < ins_len && ins[i]; i++) { for (i = 0; i < ins_len && ins[i] && count <= outs_len; i++) {
unsigned short c = le16_to_cpu(ins[i]); unsigned short c = le16_to_cpu(ins[i]);
if (surrog) { if (surrog) {
if ((c >= 0xdc00) && (c < 0xe000)) { if ((c >= 0xdc00) && (c < 0xe000)) {
surrog = FALSE; surrog = FALSE;
count += 4; count += 4;
} else } else {
#if ALLOW_BROKEN_UNICODE
/* The first UTF-16 unit of a surrogate pair has
* a value between 0xd800 and 0xdc00. It can be
* encoded as an individual UTF-8 sequence if we
* cannot combine it with the next UTF-16 unit
* unit as a surrogate pair. */
surrog = FALSE;
count += 3;
--i;
continue;
#else
goto fail; goto fail;
#endif /* ALLOW_BROKEN_UNICODE */
}
} else } else
if (c < 0x80) if (c < 0x80)
count++; count++;
else if (c < 0x800) else if (c < 0x800)
count += 2; count += 2;
else if (c < 0xd800) else if (c < 0xd800)
count += 3; count += 3;
else if (c < 0xdc00) else if (c < 0xdc00)
surrog = TRUE; surrog = TRUE;
#if NOREVBOM #if ALLOW_BROKEN_UNICODE
else if ((c >= 0xe000) && (c < 0xfffe)) else if (c < 0xe000)
#else count += 3;
else if (c >= 0xe000) else if (c >= 0xe000)
#endif #else
else if ((c >= 0xe000) && (c < 0xfffe))
#endif /* ALLOW_BROKEN_UNICODE */
count += 3; count += 3;
else else
goto fail; goto fail;
if (count > outs_len) {
errno = ENAMETOOLONG;
goto out;
}
} }
if (surrog)
if (surrog && count <= outs_len) {
#if ALLOW_BROKEN_UNICODE
count += 3; /* ending with a single surrogate */
#else
goto fail; goto fail;
#endif /* ALLOW_BROKEN_UNICODE */
}
if (count > outs_len) {
errno = ENAMETOOLONG;
goto out;
}
ret = count; ret = count;
out: out:
return ret; return ret;
fail: fail:
errno = EILSEQ; errno = EILSEQ;
goto out; goto out;
} }
/* /*
* ntfs_utf16_to_utf8 - convert a little endian UTF16LE string to an UTF-8 strin g * ntfs_utf16_to_utf8 - convert a little endian UTF16LE string to an UTF-8 strin g
* @ins: input utf16 string buffer * @ins: input utf16 string buffer
* @ins_len: length of input string in utf16 characters * @ins_len: length of input string in utf16 characters
* @outs: on return contains the (allocated) output multibyte string * @outs: on return contains the (allocated) output multibyte string
* @outs_len: length of output buffer in bytes * @outs_len: length of output buffer in bytes (ignored if *@outs is NULL)
* *
* Return -1 with errno set if string has invalid byte sequence or too long. * Return -1 with errno set if string has invalid byte sequence or too long.
*/ */
static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len, static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
char **outs, int outs_len) char **outs, int outs_len)
{ {
#if defined(__APPLE__) || defined(__DARWIN__) #if defined(__APPLE__) || defined(__DARWIN__)
#ifdef ENABLE_NFCONV #ifdef ENABLE_NFCONV
char *original_outs_value = *outs; char *original_outs_value = *outs;
int original_outs_len = outs_len; int original_outs_len = outs_len;
#endif /* ENABLE_NFCONV */ #endif /* ENABLE_NFCONV */
#endif /* defined(__APPLE__) || defined(__DARWIN__) */ #endif /* defined(__APPLE__) || defined(__DARWIN__) */
char *t; char *t;
int i, size, ret = -1; int i, size, ret = -1;
int halfpair; int halfpair;
halfpair = 0; halfpair = 0;
if (!*outs) if (!*outs) {
/* If no output buffer was provided, we will allocate one and
* limit its length to PATH_MAX. Note: we follow the standard
* convention of PATH_MAX including the terminating null. */
outs_len = PATH_MAX; outs_len = PATH_MAX;
}
size = utf16_to_utf8_size(ins, ins_len, outs_len); /* The size *with* the terminating null is limited to @outs_len,
* so the size *without* the terminating null is limited to one less. */
size = utf16_to_utf8_size(ins, ins_len, outs_len - 1);
if (size < 0) if (size < 0)
goto out; goto out;
if (!*outs) { if (!*outs) {
outs_len = size + 1; outs_len = size + 1;
*outs = ntfs_malloc(outs_len); *outs = ntfs_malloc(outs_len);
if (!*outs) if (!*outs)
goto out; goto out;
} }
skipping to change at line 551 skipping to change at line 599
for (i = 0; i < ins_len && ins[i]; i++) { for (i = 0; i < ins_len && ins[i]; i++) {
unsigned short c = le16_to_cpu(ins[i]); unsigned short c = le16_to_cpu(ins[i]);
/* size not double-checked */ /* size not double-checked */
if (halfpair) { if (halfpair) {
if ((c >= 0xdc00) && (c < 0xe000)) { if ((c >= 0xdc00) && (c < 0xe000)) {
*t++ = 0xf0 + (((halfpair + 64) >> 8) & 7); *t++ = 0xf0 + (((halfpair + 64) >> 8) & 7);
*t++ = 0x80 + (((halfpair + 64) >> 2) & 63); *t++ = 0x80 + (((halfpair + 64) >> 2) & 63);
*t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) < < 4); *t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) < < 4);
*t++ = 0x80 + (c & 63); *t++ = 0x80 + (c & 63);
halfpair = 0; halfpair = 0;
} else } else {
#if ALLOW_BROKEN_UNICODE
/* The first UTF-16 unit of a surrogate pair has
* a value between 0xd800 and 0xdc00. It can be
* encoded as an individual UTF-8 sequence if we
* cannot combine it with the next UTF-16 unit
* unit as a surrogate pair. */
*t++ = 0xe0 | (halfpair >> 12);
*t++ = 0x80 | ((halfpair >> 6) & 0x3f);
*t++ = 0x80 | (halfpair & 0x3f);
halfpair = 0;
--i;
continue;
#else
goto fail; goto fail;
#endif /* ALLOW_BROKEN_UNICODE */
}
} else if (c < 0x80) { } else if (c < 0x80) {
*t++ = c; *t++ = c;
} else { } else {
if (c < 0x800) { if (c < 0x800) {
*t++ = (0xc0 | ((c >> 6) & 0x3f)); *t++ = (0xc0 | ((c >> 6) & 0x3f));
*t++ = 0x80 | (c & 0x3f); *t++ = 0x80 | (c & 0x3f);
} else if (c < 0xd800) { } else if (c < 0xd800) {
*t++ = 0xe0 | (c >> 12); *t++ = 0xe0 | (c >> 12);
*t++ = 0x80 | ((c >> 6) & 0x3f); *t++ = 0x80 | ((c >> 6) & 0x3f);
*t++ = 0x80 | (c & 0x3f); *t++ = 0x80 | (c & 0x3f);
} else if (c < 0xdc00) } else if (c < 0xdc00)
halfpair = c; halfpair = c;
#if ALLOW_BROKEN_UNICODE
else if (c < 0xe000) {
*t++ = 0xe0 | (c >> 12);
*t++ = 0x80 | ((c >> 6) & 0x3f);
*t++ = 0x80 | (c & 0x3f);
}
#endif /* ALLOW_BROKEN_UNICODE */
else if (c >= 0xe000) { else if (c >= 0xe000) {
*t++ = 0xe0 | (c >> 12); *t++ = 0xe0 | (c >> 12);
*t++ = 0x80 | ((c >> 6) & 0x3f); *t++ = 0x80 | ((c >> 6) & 0x3f);
*t++ = 0x80 | (c & 0x3f); *t++ = 0x80 | (c & 0x3f);
} else } else
goto fail; goto fail;
} }
} }
#if ALLOW_BROKEN_UNICODE
if (halfpair) { /* ending with a single surrogate */
*t++ = 0xe0 | (halfpair >> 12);
*t++ = 0x80 | ((halfpair >> 6) & 0x3f);
*t++ = 0x80 | (halfpair & 0x3f);
}
#endif /* ALLOW_BROKEN_UNICODE */
*t = '\0'; *t = '\0';
#if defined(__APPLE__) || defined(__DARWIN__) #if defined(__APPLE__) || defined(__DARWIN__)
#ifdef ENABLE_NFCONV #ifdef ENABLE_NFCONV
if(nfconvert_utf8 && (t - *outs) > 0) { if(nfconvert_utf8 && (t - *outs) > 0) {
char *new_outs = NULL; char *new_outs = NULL;
int new_outs_len = ntfs_macosx_normalize_utf8(*outs, &new_outs, 0 ); // Normalize to decomposed form int new_outs_len = ntfs_macosx_normalize_utf8(*outs, &new_outs, 0 ); // Normalize to decomposed form
if(new_outs_len >= 0 && new_outs != NULL) { if(new_outs_len >= 0 && new_outs != NULL) {
if(original_outs_value != *outs) { if(original_outs_value != *outs) {
// We have allocated outs ourselves. // We have allocated outs ourselves.
skipping to change at line 694 skipping to change at line 772
return 2; return 2;
} else } else
goto fail; goto fail;
/* three-byte */ /* three-byte */
} else if (byte < 0xF0) { } else if (byte < 0xF0) {
if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80)) { if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80)) {
*wc = ((u32)(byte & 0x0F) << 12) *wc = ((u32)(byte & 0x0F) << 12)
| ((u32)(s[1] & 0x3F) << 6) | ((u32)(s[1] & 0x3F) << 6)
| ((u32)(s[2] & 0x3F)); | ((u32)(s[2] & 0x3F));
/* Check valid ranges */ /* Check valid ranges */
#if NOREVBOM #if ALLOW_BROKEN_UNICODE
if (((*wc >= 0x800) && (*wc <= 0xD7FF)) if (((*wc >= 0x800) && (*wc <= 0xD7FF))
|| ((*wc >= 0xe000) && (*wc <= 0xFFFD))) || ((*wc >= 0xD800) && (*wc <= 0xDFFF))
|| ((*wc >= 0xe000) && (*wc <= 0xFFFF)))
return 3; return 3;
#else #else
if (((*wc >= 0x800) && (*wc <= 0xD7FF)) if (((*wc >= 0x800) && (*wc <= 0xD7FF))
|| ((*wc >= 0xe000) && (*wc <= 0xFFFF))) || ((*wc >= 0xe000) && (*wc <= 0xFFFD)))
return 3; return 3;
#endif #endif /* ALLOW_BROKEN_UNICODE */
} }
goto fail; goto fail;
/* four-byte */ /* four-byte */
} else if (byte < 0xF5) { } else if (byte < 0xF5) {
if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80) if (((s[1] & 0xC0) == 0x80) && ((s[2] & 0xC0) == 0x80)
&& ((s[3] & 0xC0) == 0x80)) { && ((s[3] & 0xC0) == 0x80)) {
*wc = ((u32)(byte & 0x07) << 18) *wc = ((u32)(byte & 0x07) << 18)
| ((u32)(s[1] & 0x3F) << 12) | ((u32)(s[1] & 0x3F) << 12)
| ((u32)(s[2] & 0x3F) << 6) | ((u32)(s[2] & 0x3F) << 6)
| ((u32)(s[3] & 0x3F)); | ((u32)(s[3] & 0x3F));
skipping to change at line 807 skipping to change at line 886
#endif /* ENABLE_NFCONV */ #endif /* ENABLE_NFCONV */
#endif /* defined(__APPLE__) || defined(__DARWIN__) */ #endif /* defined(__APPLE__) || defined(__DARWIN__) */
return ret; return ret;
} }
/** /**
* ntfs_ucstombs - convert a little endian Unicode string to a multibyte string * ntfs_ucstombs - convert a little endian Unicode string to a multibyte string
* @ins: input Unicode string buffer * @ins: input Unicode string buffer
* @ins_len: length of input string in Unicode characters * @ins_len: length of input string in Unicode characters
* @outs: on return contains the (allocated) output multibyte string * @outs: on return contains the (allocated) output multibyte string
* @outs_len: length of output buffer in bytes * @outs_len: length of output buffer in bytes (ignored if *@outs is NULL)
* *
* Convert the input little endian, 2-byte Unicode string @ins, of length * Convert the input little endian, 2-byte Unicode string @ins, of length
* @ins_len into the multibyte string format dictated by the current locale. * @ins_len into the multibyte string format dictated by the current locale.
* *
* If *@outs is NULL, the function allocates the string and the caller is * If *@outs is NULL, the function allocates the string and the caller is
* responsible for calling free(*@outs); when finished with it. * responsible for calling free(*@outs); when finished with it.
* *
* On success the function returns the number of bytes written to the output * On success the function returns the number of bytes written to the output
* string *@outs (>= 0), not counting the terminating NULL byte. If the output * string *@outs (>= 0), not counting the terminating NULL byte. If the output
* string buffer was allocated, *@outs is set to it. * string buffer was allocated, *@outs is set to it.
skipping to change at line 1239 skipping to change at line 1318
/* from Windows 6.1 (Win7) */ /* from Windows 6.1 (Win7) */
{ 0x23a, 0x23e, 0x0, 4, 6, 1 }, { 0x23a, 0x23e, 0x0, 4, 6, 1 },
{ 0x250, 0x250, 0x2a1f, 2, 6, 1 }, { 0x250, 0x250, 0x2a1f, 2, 6, 1 },
{ 0x251, 0x251, 0x2a1c, 2, 6, 1 }, { 0x251, 0x251, 0x2a1c, 2, 6, 1 },
{ 0x271, 0x271, 0x29fd, 2, 6, 1 }, { 0x271, 0x271, 0x29fd, 2, 6, 1 },
{ 0x371, 0x373, -0x1, 2, 6, 1 }, { 0x371, 0x373, -0x1, 2, 6, 1 },
{ 0x377, 0x377, -0x1, 2, 6, 1 }, { 0x377, 0x377, -0x1, 2, 6, 1 },
{ 0x3c2, 0x3c2, 0x0, 2, 6, 1 }, { 0x3c2, 0x3c2, 0x0, 2, 6, 1 },
{ 0x3d7, 0x3d7, -0x8, 2, 6, 1 }, { 0x3d7, 0x3d7, -0x8, 2, 6, 1 },
{ 0x515, 0x523, -0x1, 2, 6, 1 }, { 0x515, 0x523, -0x1, 2, 6, 1 },
{ 0x1d79, 0x1d79, 0x8a04, 2, 6, 1 }, /* below, -0x75fc stands for 0x8a04 and truncation */
{ 0x1d79, 0x1d79, -0x75fc, 2, 6, 1 },
{ 0x1efb, 0x1eff, -0x1, 2, 6, 1 }, { 0x1efb, 0x1eff, -0x1, 2, 6, 1 },
{ 0x1fc3, 0x1ff3, 0x9, 48, 6, 1 }, { 0x1fc3, 0x1ff3, 0x9, 48, 6, 1 },
{ 0x1fcc, 0x1ffc, 0x0, 48, 6, 1 }, { 0x1fcc, 0x1ffc, 0x0, 48, 6, 1 },
{ 0x2c65, 0x2c65, -0x2a2b, 2, 6, 1 }, { 0x2c65, 0x2c65, -0x2a2b, 2, 6, 1 },
{ 0x2c66, 0x2c66, -0x2a28, 2, 6, 1 }, { 0x2c66, 0x2c66, -0x2a28, 2, 6, 1 },
{ 0x2c73, 0x2c73, -0x1, 2, 6, 1 }, { 0x2c73, 0x2c73, -0x1, 2, 6, 1 },
{ 0xa641, 0xa65f, -0x1, 2, 6, 1 }, { 0xa641, 0xa65f, -0x1, 2, 6, 1 },
{ 0xa663, 0xa66d, -0x1, 2, 6, 1 }, { 0xa663, 0xa66d, -0x1, 2, 6, 1 },
{ 0xa681, 0xa697, -0x1, 2, 6, 1 }, { 0xa681, 0xa697, -0x1, 2, 6, 1 },
{ 0xa723, 0xa72f, -0x1, 2, 6, 1 }, { 0xa723, 0xa72f, -0x1, 2, 6, 1 },
skipping to change at line 1400 skipping to change at line 1480
void ntfs_ucsfree(ntfschar *ucs) void ntfs_ucsfree(ntfschar *ucs)
{ {
if (ucs && (ucs != AT_UNNAMED)) if (ucs && (ucs != AT_UNNAMED))
free(ucs); free(ucs);
} }
/* /*
* Check whether a name contains no chars forbidden * Check whether a name contains no chars forbidden
* for DOS or Win32 use * for DOS or Win32 use
* *
* If @strict is TRUE, then trailing dots and spaces are forbidden.
* These names are technically allowed in the Win32 namespace, but
* they can be problematic. See comment for FILE_NAME_WIN32.
*
* If there is a bad char, errno is set to EINVAL * If there is a bad char, errno is set to EINVAL
*/ */
BOOL ntfs_forbidden_chars(const ntfschar *name, int len) BOOL ntfs_forbidden_chars(const ntfschar *name, int len, BOOL strict)
{ {
BOOL forbidden; BOOL forbidden;
int ch; int ch;
int i; int i;
static const u32 mainset = (1L << ('\"' - 0x20)) static const u32 mainset = (1L << ('\"' - 0x20))
| (1L << ('*' - 0x20)) | (1L << ('*' - 0x20))
| (1L << ('/' - 0x20)) | (1L << ('/' - 0x20))
| (1L << (':' - 0x20)) | (1L << (':' - 0x20))
| (1L << ('<' - 0x20)) | (1L << ('<' - 0x20))
| (1L << ('>' - 0x20)) | (1L << ('>' - 0x20))
| (1L << ('?' - 0x20)); | (1L << ('?' - 0x20));
forbidden = (len == 0) forbidden = (len == 0) ||
|| (name[len-1] == const_cpu_to_le16(' ')) (strict && (name[len-1] == const_cpu_to_le16(' ') ||
|| (name[len-1] == const_cpu_to_le16('.')); name[len-1] == const_cpu_to_le16('.')));
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
ch = le16_to_cpu(name[i]); ch = le16_to_cpu(name[i]);
if ((ch < 0x20) if ((ch < 0x20)
|| ((ch < 0x40) || ((ch < 0x40)
&& ((1L << (ch - 0x20)) & mainset)) && ((1L << (ch - 0x20)) & mainset))
|| (ch == '\\') || (ch == '\\')
|| (ch == '|')) || (ch == '|'))
forbidden = TRUE; forbidden = TRUE;
} }
if (forbidden) if (forbidden)
skipping to change at line 1440 skipping to change at line 1524
return (forbidden); return (forbidden);
} }
/* /*
* Check whether a name contains no forbidden chars and * Check whether a name contains no forbidden chars and
* is not a reserved name for DOS or Win32 use * is not a reserved name for DOS or Win32 use
* *
* The reserved names are CON, PRN, AUX, NUL, COM1..COM9, LPT1..LPT9 * The reserved names are CON, PRN, AUX, NUL, COM1..COM9, LPT1..LPT9
* with no suffix or any suffix. * with no suffix or any suffix.
* *
* If @strict is TRUE, then trailing dots and spaces are forbidden.
* These names are technically allowed in the Win32 namespace, but
* they can be problematic. See comment for FILE_NAME_WIN32.
*
* If the name is forbidden, errno is set to EINVAL * If the name is forbidden, errno is set to EINVAL
*/ */
BOOL ntfs_forbidden_names(ntfs_volume *vol, const ntfschar *name, int len) BOOL ntfs_forbidden_names(ntfs_volume *vol, const ntfschar *name, int len,
BOOL strict)
{ {
BOOL forbidden; BOOL forbidden;
int h; int h;
static const ntfschar dot = const_cpu_to_le16('.'); static const ntfschar dot = const_cpu_to_le16('.');
static const ntfschar con[] = { const_cpu_to_le16('c'), static const ntfschar con[] = { const_cpu_to_le16('c'),
const_cpu_to_le16('o'), const_cpu_to_le16('n') }; const_cpu_to_le16('o'), const_cpu_to_le16('n') };
static const ntfschar prn[] = { const_cpu_to_le16('p'), static const ntfschar prn[] = { const_cpu_to_le16('p'),
const_cpu_to_le16('r'), const_cpu_to_le16('n') }; const_cpu_to_le16('r'), const_cpu_to_le16('n') };
static const ntfschar aux[] = { const_cpu_to_le16('a'), static const ntfschar aux[] = { const_cpu_to_le16('a'),
const_cpu_to_le16('u'), const_cpu_to_le16('x') }; const_cpu_to_le16('u'), const_cpu_to_le16('x') };
static const ntfschar nul[] = { const_cpu_to_le16('n'), static const ntfschar nul[] = { const_cpu_to_le16('n'),
const_cpu_to_le16('u'), const_cpu_to_le16('l') }; const_cpu_to_le16('u'), const_cpu_to_le16('l') };
static const ntfschar com[] = { const_cpu_to_le16('c'), static const ntfschar com[] = { const_cpu_to_le16('c'),
const_cpu_to_le16('o'), const_cpu_to_le16('m') }; const_cpu_to_le16('o'), const_cpu_to_le16('m') };
static const ntfschar lpt[] = { const_cpu_to_le16('l'), static const ntfschar lpt[] = { const_cpu_to_le16('l'),
const_cpu_to_le16('p'), const_cpu_to_le16('t') }; const_cpu_to_le16('p'), const_cpu_to_le16('t') };
forbidden = ntfs_forbidden_chars(name, len); forbidden = ntfs_forbidden_chars(name, len, strict);
if (!forbidden && (len >= 3)) { if (!forbidden && (len >= 3)) {
/* /*
* Rough hash check to tell whether the first couple of chars * Rough hash check to tell whether the first couple of chars
* may be one of CO PR AU NU LP or lowercase variants. * may be one of CO PR AU NU LP or lowercase variants.
*/ */
h = ((le16_to_cpu(name[0]) & 31)*48) h = ((le16_to_cpu(name[0]) & 31)*48)
^ ((le16_to_cpu(name[1]) & 31)*165); ^ ((le16_to_cpu(name[1]) & 31)*165);
if ((h % 23) == 17) { if ((h % 23) == 17) {
/* do a full check, depending on the third char */ /* do a full check, depending on the third char */
switch (le16_to_cpu(name[2]) & ~0x20) { switch (le16_to_cpu(name[2]) & ~0x20) {
 End of changes. 37 change blocks. 
40 lines changed or deleted 129 lines changed or added

Home  |  About  |  All  |  Newest  |  Fossies Dox  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTPS