Avoid the need to allocate 128K of storage for the upcase table, which makes it easier to use libntfs-3g with very little memory available.
Add a new struct, ntfs_upcase, containing the information needed to load
the upcase table on demand. Modify all functions taking the pointer and
length for the upcase table to take an ntfs_upcase pointer instead.
Modify ntfs_upcase_table_build to support building only part of an
upcase table. Add new function ntfs_upcase_lookup to perform an upcase
table lookup.
---
include/ntfs-3g/unistr.h | 35 ++++++++++++---
include/ntfs-3g/volume.h | 11 +++--
libntfs-3g/attrib.c | 27 +++++-------
libntfs-3g/collate.c | 4 +-
libntfs-3g/dir.c | 10 ++--
libntfs-3g/inode.c | 2 +-
libntfs-3g/unistr.c | 106 ++++++++++++++++++++++++++-------------------
libntfs-3g/volume.c | 61 ++++++++------------------
8 files changed, 133 insertions(+), 123 deletions(-)
This patch applies to ntfs-3g-0.20061031-BETA.
diff --git a/include/ntfs-3g/unistr.h b/include/ntfs-3g/unistr.h
index b45101e..b47c112 100644
--- a/include/ntfs-3g/unistr.h
+++ b/include/ntfs-3g/unistr.h
@@ -25,45 +25,66 @@
#include "types.h"
#include "layout.h"
+#include "attrib.h"
+
+typedef struct _ntfs_upcase {
+ ntfschar *upcase; /* Upper case equivalents of the Unicode
+ characters from upcase_offset to
+ upcase_offset+upcase_len-1. Obtained from
+ $UpCase. */
+ u32 len; /* Length in Unicode characters of the
+ currently loaded portion of the upcase
+ table. */
+ u32 total_len; /* Length in Unicode characters of the on-disk
+ upcase table, or 65536 if attr is NULL. */
+ u32 offset; /* Offset in Unicode characters of the
+ currently loaded portion of the upcase table
+ from Unicode character 0. */
+ ntfs_attr *attr; /* ntfs_attr for the data of the upcase file.
+ If NULL, build them with
+ ntfs_upcase_table_build. */
+} ntfs_upcase;
extern BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_size);
+ ntfs_upcase *upcase);
extern int ntfs_names_collate(const ntfschar *name1, const u32 name1_len,
const ntfschar *name2, const u32 name2_len,
const int err_val, const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_len);
+ ntfs_upcase *upcase);
extern int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n);
extern int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
- const ntfschar *upcase, const u32 upcase_size);
+ ntfs_upcase *upcase);
extern u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen);
extern ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen);
extern void ntfs_name_upcase(ntfschar *name, u32 name_len,
- const ntfschar *upcase, const u32 upcase_len);
+ ntfs_upcase *upcase);
extern void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
- const ntfschar *upcase, const u32 upcase_len);
+ ntfs_upcase *upcase);
extern int ntfs_file_values_compare(const FILE_NAME_ATTR *file_name_attr1,
const FILE_NAME_ATTR *file_name_attr2,
const int err_val, const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_len);
+ ntfs_upcase *upcase);
extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
int outs_len);
extern int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len);
-extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len);
+extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len, u32 uc_offset);
extern ntfschar *ntfs_str2ucs(const char *s, int *len);
extern void ntfs_ucsfree(ntfschar *ucs);
+extern ntfschar ntfs_upcase_lookup(ntfs_upcase *upcase, ntfschar c);
+
#endif /* defined _NTFS_UNISTR_H */
diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h
index 7f14ab9..6044027 100644
--- a/include/ntfs-3g/volume.h
+++ b/include/ntfs-3g/volume.h
@@ -61,6 +61,9 @@
#endif
#endif
+/* Upcase table uses 64K if not set, 512 bytes if set. */
+#define MS_NTFS_SMALL_UPCASE_TABLE 1073741824 /* 2**30 */
+
/* Forward declaration */
typedef struct _ntfs_volume ntfs_volume;
@@ -69,6 +72,7 @@ typedef struct _ntfs_volume ntfs_volume;
#include "device.h"
#include "inode.h"
#include "attrib.h"
+#include "unistr.h"
/**
* enum ntfs_mount_flags -
@@ -195,11 +199,8 @@ struct _ntfs_volume {
ntfs_attr *mftmirr_na; /* ntfs_attr structure for the data attribute
of FILE_MFTMirr. */
- ntfschar *upcase; /* Upper case equivalents of all 65536 2-byte
- Unicode characters. Obtained from
- FILE_UpCase. */
- u32 upcase_len; /* Length in Unicode characters of the upcase
- table. */
+ ntfs_upcase upcase; /* ntfs_upcase table to use for
+ case-insensitive comparisons. */
ATTR_DEF *attrdef; /* Attribute definitions. Obtained from
FILE_AttrDef. */
diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c
index e35f220..ed0fa04 100644
--- a/libntfs-3g/attrib.c
+++ b/libntfs-3g/attrib.c
@@ -1542,15 +1542,13 @@ static int ntfs_attr_find(const ATTR_TYPES type, const
ntfschar *name,
{
ATTR_RECORD *a;
ntfs_volume *vol;
- ntfschar *upcase;
- u32 upcase_len;
+ ntfs_upcase *upcase;
ntfs_log_trace("attribute type 0x%x.\n", type);
if (ctx->ntfs_ino) {
vol = ctx->ntfs_ino->vol;
- upcase = vol->upcase;
- upcase_len = vol->upcase_len;
+ upcase = &vol->upcase;
} else {
if (name && name != AT_UNNAMED) {
errno = EINVAL;
@@ -1558,7 +1556,6 @@ static int ntfs_attr_find(const ATTR_TYPES type, const
ntfschar *name,
}
vol = NULL;
upcase = NULL;
- upcase_len = 0;
}
/*
* Iterate over attributes in mft record starting at @ctx->attr, or the
@@ -1601,14 +1598,14 @@ static int ntfs_attr_find(const ATTR_TYPES type, const
ntfschar *name,
}
} else if (name && !ntfs_names_are_equal(name, name_len,
(ntfschar*)((char*)a + le16_to_cpu(a->name_offset)),
- a->name_length, ic, upcase, upcase_len)) {
+ a->name_length, ic, upcase)) {
register int rc;
rc = ntfs_names_collate(name, name_len,
(ntfschar*)((char*)a +
le16_to_cpu(a->name_offset)),
a->name_length, 1, IGNORE_CASE,
- upcase, upcase_len);
+ upcase);
/*
* If @name collates before a->name, there is no
* matching attribute.
@@ -1624,7 +1621,7 @@ static int ntfs_attr_find(const ATTR_TYPES type, const
ntfschar *name,
(ntfschar*)((char*)a +
le16_to_cpu(a->name_offset)),
a->name_length, 1, CASE_SENSITIVE,
- upcase, upcase_len);
+ upcase);
if (rc == -1) {
errno = ENOENT;
return -1;
@@ -1909,13 +1906,12 @@ find_attr_list_attr:
if (al_name_len)
goto not_found;
} else if (name && !ntfs_names_are_equal(al_name, al_name_len,
- name, name_len, ic, vol->upcase,
- vol->upcase_len)) {
+ name, name_len, ic, &vol->upcase)) {
register int rc;
rc = ntfs_names_collate(name, name_len, al_name,
al_name_len, 1, IGNORE_CASE,
- vol->upcase, vol->upcase_len);
+ &vol->upcase);
/*
* If @name collates before al_name, there is no
* matching attribute.
@@ -1935,7 +1931,7 @@ find_attr_list_attr:
*/
rc = ntfs_names_collate(name, name_len, al_name,
al_name_len, 1, CASE_SENSITIVE,
- vol->upcase, vol->upcase_len);
+ &vol->upcase);
if (rc == -1)
goto not_found;
if (rc)
@@ -1960,7 +1956,7 @@ find_attr_list_attr:
next_al_entry->name_offset),
next_al_entry->name_length,
al_name, al_name_len, CASE_SENSITIVE,
- vol->upcase, vol->upcase_len))
+ &vol->upcase))
continue;
is_enumeration:
if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {
@@ -2029,7 +2025,7 @@ do_next_attr_loop:
le16_to_cpu(a->name_offset)),
a->name_length, al_name,
al_name_len, CASE_SENSITIVE,
- vol->upcase, vol->upcase_len))
+ &vol->upcase))
break;
ctx->attr = a;
/*
@@ -2182,8 +2178,7 @@ int ntfs_attr_lookup(const ATTR_TYPES type, const
ntfschar *name,
ntfs_inode *base_ni;
if (!ctx || !ctx->mrec || !ctx->attr || (name && name != AT_UNNAMED &&
- (!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol) ||
- !vol->upcase || !vol->upcase_len))) {
+ (!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol)))) {
errno = EINVAL;
return -1;
}
diff --git a/libntfs-3g/collate.c b/libntfs-3g/collate.c
index 2352423..c76acb7 100644
--- a/libntfs-3g/collate.c
+++ b/libntfs-3g/collate.c
@@ -141,11 +141,11 @@ static int ntfs_collate_file_name(ntfs_volume *vol,
ntfs_log_trace("Entering.\n");
rc = ntfs_file_values_compare(data1, data2, NTFS_COLLATION_ERROR,
- IGNORE_CASE, vol->upcase, vol->upcase_len);
+ IGNORE_CASE, &vol->upcase);
if (!rc)
rc = ntfs_file_values_compare(data1, data2,
NTFS_COLLATION_ERROR, CASE_SENSITIVE,
- vol->upcase, vol->upcase_len);
+ &vol->upcase);
ntfs_log_trace("Done, returning %i.\n", rc);
return rc;
}
diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c
index 328a7bf..e529410 100644
--- a/libntfs-3g/dir.c
+++ b/libntfs-3g/dir.c
@@ -175,7 +175,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const
ntfschar *uname,
rc = ntfs_names_collate(uname, uname_len,
(ntfschar*)&ie->key.file_name.file_name,
ie->key.file_name.file_name_length, 1,
- IGNORE_CASE, vol->upcase, vol->upcase_len);
+ IGNORE_CASE, &vol->upcase);
/*
* If uname collates before the name of the current entry, there
* is definitely no such name in this index but we might need to
@@ -194,7 +194,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const
ntfschar *uname,
rc = ntfs_names_collate(uname, uname_len,
(ntfschar*)&ie->key.file_name.file_name,
ie->key.file_name.file_name_length, 1,
- CASE_SENSITIVE, vol->upcase, vol->upcase_len);
+ CASE_SENSITIVE, &vol->upcase);
if (rc == -1)
break;
if (rc)
@@ -323,7 +323,7 @@ descend_into_child_node:
rc = ntfs_names_collate(uname, uname_len,
(ntfschar*)&ie->key.file_name.file_name,
ie->key.file_name.file_name_length, 1,
- IGNORE_CASE, vol->upcase, vol->upcase_len);
+ IGNORE_CASE, &vol->upcase);
/*
* If uname collates before the name of the current entry, there
* is definitely no such name in this index but we might need to
@@ -342,7 +342,7 @@ descend_into_child_node:
rc = ntfs_names_collate(uname, uname_len,
(ntfschar*)&ie->key.file_name.file_name,
ie->key.file_name.file_name_length, 1,
- CASE_SENSITIVE, vol->upcase, vol->upcase_len);
+ CASE_SENSITIVE, &vol->upcase);
if (rc == -1)
break;
if (rc)
@@ -1437,7 +1437,7 @@ search:
if (ntfs_names_are_equal(fn->file_name, fn->file_name_length,
name, name_len, case_sensitive,
- ni->vol->upcase, ni->vol->upcase_len)){
+ &ni->vol->upcase)){
if (fn->file_name_type == FILE_NAME_WIN32) {
looking_for_dos_name = TRUE;
diff --git a/libntfs-3g/inode.c b/libntfs-3g/inode.c
index 7e22f34..5a5e561 100644
--- a/libntfs-3g/inode.c
+++ b/libntfs-3g/inode.c
@@ -1148,7 +1148,7 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
if (ustr && ntfs_names_are_equal(ustr, len,
(ntfschar *)((u8 *)attr +
le16_to_cpu(attr->name_offset)),
- attr->name_length, 0, NULL, 0))
+ attr->name_length, 0, NULL))
ret = 1;
ntfs_ucsfree(ustr);
diff --git a/libntfs-3g/unistr.c b/libntfs-3g/unistr.c
index 4eb9dee..b04d2fb 100644
--- a/libntfs-3g/unistr.c
+++ b/libntfs-3g/unistr.c
@@ -83,7 +83,6 @@ static const u8 legal_ansi_char_array[0x40] = {
* @s2_len: length in Unicode characters of @s2
* @ic: ignore case bool
* @upcase: upcase table (only if @ic == IGNORE_CASE)
- * @upcase_size: length in Unicode characters of @upcase (if present)
*
* Compare the names @s1 and @s2 and return TRUE (1) if the names are
* identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE,
@@ -91,8 +90,7 @@ static const u8 legal_ansi_char_array[0x40] = {
*/
BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
const ntfschar *s2, size_t s2_len,
- const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_size)
+ const IGNORE_CASE_BOOL ic, ntfs_upcase *upcase)
{
if (s1_len != s2_len)
return FALSE;
@@ -100,8 +98,7 @@ BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
return TRUE;
if (ic == CASE_SENSITIVE)
return ntfs_ucsncmp(s1, s2, s1_len) ? FALSE: TRUE;
- return ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size) ? FALSE:
- TRUE;
+ return ntfs_ucsncasecmp(s1, s2, s1_len, upcase) ? FALSE: TRUE;
}
/**
@@ -113,7 +110,6 @@ BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
* @err_val: if @name1 contains an invalid character return this value
* @ic: either CASE_SENSITIVE or IGNORE_CASE
* @upcase: upcase table (ignored if @ic is CASE_SENSITIVE)
- * @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE)
*
* ntfs_names_collate() collates two Unicode names and returns:
*
@@ -127,14 +123,13 @@ BOOL ntfs_names_are_equal(const ntfschar *s1, size_t
s1_len,
int ntfs_names_collate(const ntfschar *name1, const u32 name1_len,
const ntfschar *name2, const u32 name2_len,
const int err_val __attribute__((unused)),
- const IGNORE_CASE_BOOL ic, const ntfschar *upcase,
- const u32 upcase_len)
+ const IGNORE_CASE_BOOL ic, ntfs_upcase *upcase)
{
u32 cnt;
ntfschar c1, c2;
#ifdef DEBUG
- if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) {
+ if (!name1 || !name2 || (ic && !upcase)) {
ntfs_log_debug("ntfs_names_collate received NULL pointer!\n");
exit(1);
}
@@ -145,10 +140,8 @@ int ntfs_names_collate(const ntfschar *name1, const u32
name1_len,
c2 = le16_to_cpu(*name2);
name2++;
if (ic) {
- if (c1 < upcase_len)
- c1 = le16_to_cpu(upcase[c1]);
- if (c2 < upcase_len)
- c2 = le16_to_cpu(upcase[c2]);
+ c1 = le16_to_cpu(ntfs_upcase_lookup(upcase, c1));
+ c2 = le16_to_cpu(ntfs_upcase_lookup(upcase, c2));
}
#if 0
if (c1 < 64 && legal_ansi_char_array[c1] & 8)
@@ -216,7 +209,6 @@ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2,
size_t n)
* @s2: second string
* @n: maximum unicode characters to compare
* @upcase: upcase table
- * @upcase_size: upcase table size in Unicode characters
*
* Compare the first @n characters of the Unicode strings @s1 and @s2,
* ignoring case. The strings in little endian format and appropriate
@@ -229,7 +221,7 @@ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2,
size_t n)
* to be less than, to match, or be greater than @s2.
*/
int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
- const ntfschar *upcase, const u32 upcase_size)
+ ntfs_upcase *upcase)
{
ntfschar c1, c2;
size_t i;
@@ -241,10 +233,8 @@ int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar
*s2, size_t n,
}
#endif
for (i = 0; i < n; ++i) {
- if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
- c1 = le16_to_cpu(upcase[c1]);
- if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
- c2 = le16_to_cpu(upcase[c2]);
+ c1 = le16_to_cpu(ntfs_upcase_lookup(upcase,
le16_to_cpu(s1[i])));
+ c2 = le16_to_cpu(ntfs_upcase_lookup(upcase,
le16_to_cpu(s2[i])));
if (c1 < c2)
return -1;
if (c1 > c2)
@@ -314,38 +304,31 @@ ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen)
* @name:
* @name_len:
* @upcase:
- * @upcase_len:
*
* Description...
*
* Returns:
*/
-void ntfs_name_upcase(ntfschar *name, u32 name_len, const ntfschar *upcase,
- const u32 upcase_len)
+void ntfs_name_upcase(ntfschar *name, u32 name_len, ntfs_upcase *upcase)
{
u32 i;
- ntfschar u;
-
for (i = 0; i < name_len; i++)
- if ((u = le16_to_cpu(name[i])) < upcase_len)
- name[i] = upcase[u];
+ name[i] = ntfs_upcase_lookup(upcase, le16_to_cpu(name[i]));
}
/**
* ntfs_file_value_upcase - Convert a filename to upper case
* @file_name_attr:
* @upcase:
- * @upcase_len:
*
* Description...
*
* Returns:
*/
-void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
- const ntfschar *upcase, const u32 upcase_len)
+void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr, ntfs_upcase
*upcase)
{
ntfs_name_upcase((ntfschar*)&file_name_attr->file_name,
- file_name_attr->file_name_length, upcase, upcase_len);
+ file_name_attr->file_name_length, upcase);
}
/**
@@ -355,7 +338,6 @@ void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
* @err_val:
* @ic:
* @upcase:
- * @upcase_len:
*
* Description...
*
@@ -364,13 +346,13 @@ void ntfs_file_value_upcase(FILE_NAME_ATTR
*file_name_attr,
int ntfs_file_values_compare(const FILE_NAME_ATTR *file_name_attr1,
const FILE_NAME_ATTR *file_name_attr2,
const int err_val, const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_len)
+ ntfs_upcase *upcase)
{
return ntfs_names_collate((ntfschar*)&file_name_attr1->file_name,
file_name_attr1->file_name_length,
(ntfschar*)&file_name_attr2->file_name,
file_name_attr2->file_name_length,
- err_val, ic, upcase, upcase_len);
+ err_val, ic, upcase);
}
/**
@@ -642,13 +624,13 @@ err_out:
* ntfs_upcase_table_build - build the default upcase table for NTFS
* @uc: destination buffer where to store the built table
* @uc_len: size of destination buffer in bytes
+ * @uc_offset: desired offset of the start of the table in Unicode characters
*
- * ntfs_upcase_table_build() builds the default upcase table for NTFS and
- * stores it in the caller supplied buffer @uc of size @uc_len.
- *
- * Note, @uc_len must be at least 128kiB in size or bad things will happen!
+ * ntfs_upcase_table_build() builds the default upcase table for NTFS, starting
+ * from Unicode character uc_offset, and stores it in the caller supplied
+ * buffer @uc of size @uc_len.
*/
-void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
+void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len, u32 uc_offset)
{
static int uc_run_table[][3] = { /* Start, End, Add */
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
@@ -688,20 +670,20 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
};
int i, r;
+#define uc_set(i, v) do { if (i > uc_offset && i < uc_len + uc_offset) uc[i -
uc_offset] = v; } while(0)
memset((char*)uc, 0, uc_len);
uc_len >>= 1;
- if (uc_len > 65536)
- uc_len = 65536;
- for (i = 0; (u32)i < uc_len; i++)
- uc[i] = i;
+ for (i = uc_offset; (u32)i < uc_offset + uc_len; i++)
+ uc_set(i, i);
for (r = 0; uc_run_table[r][0]; r++)
for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
- uc[i] += uc_run_table[r][2];
+ uc_set(i, i + uc_run_table[r][2]);
for (r = 0; uc_dup_table[r][0]; r++)
for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
- uc[i + 1]--;
+ uc_set(i + 1, uc[i + 1 - uc_offset] - 1);
for (r = 0; uc_byte_table[r][0]; r++)
- uc[uc_byte_table[r][0]] = uc_byte_table[r][1];
+ uc_set(uc_byte_table[r][0], uc_byte_table[r][1]);
+#undef uc_set
}
/**
@@ -755,3 +737,37 @@ void ntfs_ucsfree(ntfschar *ucs)
free(ucs);
}
+/**
+ * ntfs_upcase_lookup - upcase a character via an upcase table
+ * @upcase upcase table
+ * @c character to upcase
+ *
+ * upcase the character @c via the upcase table @upcase.
+ *
+ * Return value: upcased character.
+ */
+ntfschar ntfs_upcase_lookup(ntfs_upcase *upcase, ntfschar c)
+{
+ if(c >= upcase->total_len)
+ return cpu_to_le16(c);
+
+ if(!(upcase->offset <= c && c < upcase->offset + upcase->len)) {
+ upcase->offset = (c + upcase->len - 1) & (upcase->len - 1);
+ if(upcase->attr) {
+ u32 len = upcase->len;
+ if(upcase->offset + len > upcase->total_len)
+ len = upcase->total_len - upcase->offset;
+ if(ntfs_attr_pread(upcase->attr, upcase->offset << 1,
+ len << 1, upcase->upcase) != (len <<
1)) {
+ ntfs_log_perror("Failed to read upcase file;
not upcasing character.");
+ upcase->offset = 65536;
+ return cpu_to_le16(c);
+ }
+ } else {
+ ntfs_upcase_table_build(upcase->upcase, upcase->len,
+ upcase->offset);
+ }
+ }
+
+ return upcase->upcase[c - upcase->offset];
+}
diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c
index 7088ba8..e1945ba 100644
--- a/libntfs-3g/volume.c
+++ b/libntfs-3g/volume.c
@@ -120,7 +120,11 @@ static void __ntfs_volume_release(ntfs_volume *v)
ntfs_log_perror("Eeek! Failed to close the device.
Error: ");
}
free(v->vol_name);
- free(v->upcase);
+ if (v->upcase.attr) {
+ ntfs_attr_close(v->upcase.attr);
+ ntfs_inode_close(v->upcase.attr->ni);
+ }
+ free(v->upcase.upcase);
free(v->attrdef);
free(v);
}
@@ -417,14 +421,16 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
unsigned long flags)
vol = ntfs_volume_alloc();
if (!vol)
goto error_exit;
+
/* Create the default upcase table. */
- vol->upcase_len = 65536;
- vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar));
- if (!vol->upcase)
+ vol->upcase.len = (flags & MS_NTFS_SMALL_UPCASE_TABLE) ? 256 : 65536;
+ vol->upcase.total_len = 65536;
+ vol->upcase.offset = 65536; /* Force the first lookup to fail. */
+ vol->upcase.attr = NULL;
+ vol->upcase.upcase = ntfs_malloc(vol->upcase.len * sizeof(ntfschar));
+ if (!vol->upcase.upcase)
goto error_exit;
- ntfs_upcase_table_build(vol->upcase,
- vol->upcase_len * sizeof(ntfschar));
if (flags & MS_RDONLY)
NVolSetReadOnly(vol);
if (flags & MS_NOATIME)
@@ -903,43 +909,14 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
unsigned long flags)
ntfs_log_perror("Failed to open ntfs attribute");
goto error_exit;
}
- /*
- * Note: Normally, the upcase table has a length equal to 65536
- * 2-byte Unicode characters but allow for different cases, so no
- * checks done. Just check we don't overflow 32-bits worth of Unicode
- * characters.
- */
- if (na->data_size & ~0x1ffffffffULL) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Error: Upcase table is too big (max 32-bit "
- "allowed).\n");
- errno = EINVAL;
- goto error_exit;
- }
- if (vol->upcase_len != na->data_size >> 1) {
- vol->upcase_len = na->data_size >> 1;
- /* Throw away default table. */
- free(vol->upcase);
- vol->upcase = ntfs_malloc(na->data_size);
- if (!vol->upcase) {
- ntfs_log_debug(FAILED);
- goto error_exit;
- }
- }
- /* Read in the $DATA attribute value into the buffer. */
- l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
- if (l != na->data_size) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Amount of data read does not correspond to
expected "
- "length!\n");
- errno = EIO;
- goto error_exit;
- }
- /* Done with the $UpCase mft record. */
+ /* Save off the data attribute and length for upcase table lookups. */
+ vol->upcase.attr = na;
+ vol->upcase.total_len = na->data_size >> 1;
+ if(vol->upcase.total_len > 65536)
+ vol->upcase.total_len = 65536;
+ /* Don't keep using the currently-loaded upcase table. */
+ vol->upcase.offset = 65536;
ntfs_log_debug(OK);
- ntfs_attr_close(na);
- if (ntfs_inode_close(ni))
- ntfs_log_perror("Failed to close inode, leaking memory");
/*
* Now load $Volume and set the version information and flags in the
--
1.4.4.2
signature.asc
Description: Digital signature
------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________ ntfs-3g-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ntfs-3g-devel
