Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv12694/libntfs
Modified Files:
attrib.c volume.c
Log Message:
Allow variable length upcase table.
Progressing on find_next_attr().
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -r1.4 -r1.5
*** attrib.c 2001/03/05 03:04:40 1.4
--- attrib.c 2001/03/06 02:10:55 1.5
***************
*** 137,174 ****
* @attr: last found attribute record inside mft record to search
* @type: attribute type to find
! * @name: attribute name to find (optional)
! * @ic: ignore case of @name (boolean)
* @val: attribute value to find (optional, resident attributes only)
! * @len: attribute value length (only present if @val present)
*
! * Decsription...
*
! * find_attr() takes an attribute record header @a as a parameter, which must
! * be the address of a pointer into an mft record. It specifies the attribute
! * at which to begin the search, i.e. it is useful as a search context in
! * attribute enumerations.
*/
ATTR_RECORD *find_next_attr(const ntfs_volume *vol, const ATTR_RECORD **attr,
const ATTR_TYPES type, const wchar_t *name,
! const __u8 ic, const __u8 *val, const __u32 len)
{
ATTR_RECORD a;
void *mft_rec;
- if (!vol || !attr || !*attr) {
#ifdef DEBUG
puts("Sanity checks failed in find_attr()!");
- #endif
return NULL;
}
a = *attr;
/*
* Calculate the beginning of the mft record, assuming that it is
* aligned on mft_record_size boundary. In the kernel, this is
! * guaranteed as it is either on a page (cache page) boundary (and a
* page is larger than an mft record in any case) or it is inside a
! * page (cache page) on an mft_record_size boundary (by definition).
*/
! mft_rec = (void*)(p2n(a) & (vol->mft_record_size - 1));
/*
* Iterate over attributes in mft record starting at @attr.
--- 137,189 ----
* @attr: last found attribute record inside mft record to search
* @type: attribute type to find
! * @name: attribute name to find (optional, i.e. NULL means don't care)
! * @ic: ignore case of @name (boolean, only present if @name present)
* @val: attribute value to find (optional, resident attributes only)
! * @val_len: attribute value length
*
! * find_next_attr() takes an attribute record @attr as a parameter, which must
! * be the address of a pointer into an mft record, and searches the mft record,
! * beginning at @attr, for an attribute of @type and optionally @name. If @ic
! * is TRUE, the @name comparisson is not case sensitive. It is case sensitive
! * if @ic is FALSE. Note: When @name is present, @val is ignored.
*
! * If @name is not present (NULL), no attribute name checking is performed at
! * all. Thus, to find an unnamed attribute, specify a @name pointing to a zero
! * length string. Then, the resident attribute value @val is looked for, if
! * present. Note: If @val is not present (NULL), @val_len is undefined.
! *
! * Warning: Never use @val when looking for attribute types which can be
! * non-resident as this most likely will result in a crash!
! *
! * In userspace consider passing in the MFT_RECORD* to do the checks,
! * as there is no way we can assume alignment on mft_record_size boundaries.
! * (Unless we write our own memory allocator, of course...)
! *
! * Note: This function's code paths are optimised to be shortest and most direct
! * for the most common cases of calling. Don't mess with it unless you find a
! * bug or actually do some profiling and prove a code path inefficient.
*/
ATTR_RECORD *find_next_attr(const ntfs_volume *vol, const ATTR_RECORD **attr,
const ATTR_TYPES type, const wchar_t *name,
! const __u8 ic, const __u8 *val, const __u32 val_len)
{
ATTR_RECORD a;
void *mft_rec;
#ifdef DEBUG
+ if (!vol || !attr || !*attr) {
puts("Sanity checks failed in find_attr()!");
return NULL;
}
+ #endif
a = *attr;
/*
* Calculate the beginning of the mft record, assuming that it is
* aligned on mft_record_size boundary. In the kernel, this is
! * guaranteed as it is either on a pagecache page boundary (and a
* page is larger than an mft record in any case) or it is inside a
! * pagecache page on an mft_record_size boundary (by definition).
*/
! mft_rec = p2n(a) & (vol->mft_record_size - 1);
/*
* Iterate over attributes in mft record starting at @attr.
***************
*** 176,250 ****
* code does not get indented out of the screen... (AIA)
*/
! search_loop:
*attr = a;
/* We catch $END with this more general check, too... */
if (le32_to_cpu(a->type) > le32_to_cpu(type))
goto not_found;
if (!a->length)
- goto file_corrupt;
- if (a->type == type)
- goto attr_type_matches;
- do_next:
- a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
- if (a < mft_rec || a > (char*)mft_rec + vol->mft_record_size)
goto file_corrupt;
! goto search_loop;
! attr_type_matches:
! /* If want an unnamed attribute, check if current one
! is unnamed and if so we have found it! */
! if (!n) {
! if (!a->name_length) {
! /* FIXME: Check the value first! */
! return a;
! }
! /* If we want a named attribute, check that the string
! length is equal and if so, compare the two strings
! and if they match, we have found it! */
! } else if (a->name_length && a->name_length == wcslen(n)) {
! /* Sanity check. */
! if (a->name_length * 2 + le16_to_cpu(a->name_offset)
! > le32_to_cpu(a->length)) {
! #ifdef DEBUG
! puts("Warning: Encountered out of "
! "bounds attribute name length in "
! "find_attr()!");
! #endif
! /* Even though this one is illegal,
! maybe it wasn't the right one, so
! continue with the search (i.e. don't
! return NULL).
! FIXME: Shouldn't we doing a hotfix
! here, i.e. truncate the name to the
! indicated size or change the
! indicated size, whichever makes more
! sense? */
! /* FIXME: Should we really be case sensitive?
! If not, use ntfs_wcsncasecmp(). */
! } else if (!ntfs_wcsncmp(n, (wchar_t*)((char*)a +
! le16_to_cpu(a->name_offset))),
! a->name_length) {
! /* FIXME: Check the value. */
return a;
}
}
not_found:
! #ifdef DEBUG
! if (name)
! printf("find_attr(): Named attribute 0x%x (\"%s\") not "
! "found.\n", type, name);
! else
! printf("find_attr(): Unnamed attribute 0x%x not found.\n",
! type);
! #endif
! return NULL;
file_corrupt:
#ifdef DEBUG
! printf(stderr, "find_attr(): File is corrupt. Run ntfsck or chkdsk.\n");
#endif
! return NULL;
}
-
-
-
/*
--- 191,271 ----
* code does not get indented out of the screen... (AIA)
*/
! goto search_loop;
! do_next:
! a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
! if (a < mft_rec || a > (char*)mft_rec + vol->mft_record_size)
! goto file_corrupt;
*attr = a;
+ search_loop:
/* We catch $END with this more general check, too... */
if (le32_to_cpu(a->type) > le32_to_cpu(type))
goto not_found;
if (!a->length)
goto file_corrupt;
! if (a->type != type)
! goto do_next;
! /* If no @name is specified, check for @val. */
! if (!name) {
! register int rv;
! /* If no @val specified, we are done. */
! if (!val) {
! found_it:
return a;
}
+ /*
+ * Compare the values. If they don't match, but the value we are
+ * looking for collates behind the current attribute's value,
+ * there might be another attribute of the same type, that does
+ * have a matching attribute value, so we continue searching.
+ */
+ rv = memcmp(val, (char*)a + le16_to_cpu(a->value_offset),
+ min(val_len, le32_to_cpu(a->value_length)));
+ if (!rv) {
+ register __u32 avl = le32_to_cpu(a->value_length);
+ if (val_len == avl)
+ goto found_it;
+ if (val_len > avl)
+ goto do_next;
+ } else if (rv > 0)
+ goto do_next;
+ goto not_found;
}
+ /*
+ * Compare the attribute names and if they match, we are finished.
+ * If they don't match, continue searching.
+ */
+ if (ic) { /* Case sensitive. */
+ if (!ntfs_wcsncmp(name, (wchar_t*)((char*)a +
+ le16_to_cpu(a->name_offset)),
+ a->name_length))
+ goto found_it;
+ } else { /* Ignore case. */
+ if (!ntfs_wcsncasecmp(name, (wchar_t*)((char*)a +
+ le16_to_cpu(a->name_offset)),
+ a->name_length, vol->upcase, vol->upcase_len))
+ goto found_it;
+ }
+ /* Attribute names didn't match on first try... */
+ /*
+ * Note: Attribute names are considered invalid if they contain any of the
+ * following characters: '"', '*', '<', '>', '?'. Or at least attribute name
+ * collation function will act on them.
+ */
+ // If case insensitive collation of names collates @name before a->name,
+ goto not_found;
+ // else if it returned that the strings are not equal
+ goto do_next;
+ // else if case sensitive collation of names doesn't collate @name
+ // before a->name
+ goto do_next;
not_found:
! return NULL;
file_corrupt:
#ifdef DEBUG
! printf(stderr,
! "find_next_attr(): File is corrupt. Run ntfsck or chkdsk.\n");
#endif
! goto not_found;
}
/*
Index: volume.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/volume.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -r1.5 -r1.6
*** volume.c 2001/03/05 03:04:40 1.5
--- volume.c 2001/03/06 02:10:55 1.6
***************
*** 372,388 ****
l = get_attribute_value_length(a);
if (!l) {
! puts(OK);
puts("Error: $DATA in $UpCase has zero length! T'is weird!");
errno = EIO;
goto error_exit;
}
! /* The upcase table has by definition to have a length equal to
! 65536 2-byte Unicode characters. */
! if (l != 65536 * 2) {
! puts(OK);
! puts("Error: Upcase table (in $UpCase) has incorrect length!");
errno = EINVAL;
goto error_exit;
}
vol->upcase = (__u16*)malloc(l);
if (!vol->upcase) {
--- 372,391 ----
l = get_attribute_value_length(a);
if (!l) {
! puts(FAILED);
puts("Error: $DATA in $UpCase has zero length! T'is weird!");
errno = EIO;
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 (l & ~0x1ffffffffULL) {
! puts(FAILED);
! puts("Error: Upcase table is too big (max 32-bit allowed).");
errno = EINVAL;
goto error_exit;
}
+ vol->upcase_len = l >> 1;
vol->upcase = (__u16*)malloc(l);
if (!vol->upcase) {
|