Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv17127/libntfs
Modified Files:
Makefile.in attrib.c disk_io.c ntfs_rec.c unistr.c volume.c
Added Files:
attrib_RE.c
Log Message:
Everything compiles again! Yey! (Don't know about working though, haven't tried
it... So be careful...)
The definitely final find_{first_}attr() functions are in place. Currently
still no support for attribute lists.
The two new _RE files contain the C-fied and more or less (more less than more
actually) cleaned up functions from the ntfs driver. Once they are cleaned
up (find_attr() is already completed but I left it in the _RE files for future
reference/educational value) and modified to suit my ideas of how they should
work, which are not quite the same as the driver way, they will make it into
attrib.[ch].
If anyone gives the new code a try, I would be interested in whether it worked
or not... (-;
--- NEW FILE ---
/* Reverse engineered functions in more or less modified form. find_attr()
* is quite heavily modified but should be functionally equivalent to original.
* lookup and lookup_external are less modified. Both should be functionally
* equivalent to originals. */
BOOL find_attr(const ntfs_volume *vol, const ATTR_TYPES type,
const wchar_t *name, const __u32 name_len,
const IGNORE_CASE_BOOL ic, const __u8 *val, const __u32 val_len,
attr_search_context *ctx)
{
ATTR_RECORD *a;
#ifdef DEBUG
if (!vol || !ctx || !ctx->mrec || !ctx->attr) {
printf(stderr, "find_attr() received NULL pointer!\n");
return FALSE;
}
#endif
a = ctx->attr;
/*
* Iterate over attributes in mft record starting at @ctx->attr.
* Note: Not using while/do/for loops so the comparison code
* does not get indented out of the 80 characters wide screen... (AIA)
*/
goto search_loop;
do_next:
a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
if (a < ctx->mrec || a > (char*)ctx->mrec + vol->mft_record_size)
goto file_corrupt;
ctx->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 TRUE;
}
rv = memcmp(val, (char*)a + le16_to_cpu(a->value_offset),
min(val_len, le32_to_cpu(a->value_length)));
/* If @val collates after the current attribute's value,
continue searching as a matching attribute might follow. */
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;
}
if (ntfs_are_names_equal(name, name_len,
(wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
a->name_length, ic, vol->upcase, vol->upcase_len))
goto found_it;
{ register int rc = ntfs_collate_names(vol->upcase,
vol->upcase_len, name, name_len,
(wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
a->name_length, IGNORE_CASE, 1);
/* If case insensitive collation of names collates @name
before a->name, there is no matching attribute. */
if (rc == -1)
goto not_found;
/* If the strings are not equal, continue search. */
if (rc)
goto do_next;
}
/* If case sensitive collation of names doesn't collate @name before
a->name, we continue the search. Otherwise we haven't found it. */
if (ntfs_collate_names(vol->upcase, vol->upcase_len, name, name_len,
(wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
a->name_length, CASE_SENSITIVE, 1) != -1)
goto do_next;
not_found:
return FALSE;
file_corrupt:
#ifdef DEBUG
printf(stderr, "find_attr(): File is corrupt. Run chkdsk.\n");
#endif
goto not_found;
}
BOOL lookup_external_attr(const ntfs_volume *vol, const MFT_REFERENCE mref,
const ATTR_TYPES type, const wchar_t *name,
const __u32 name_len, const IGNORE_CASE_BOOL ic,
const __s64 lowest_vcn, const __u8 *val,
const __u32 val_len, attr_search_context *ctx)
{
ATTR_LIST_ENTRY *al_pos, **al_val, *al_val_start, *al_next_pos;
ATTR_RECORD *attr_pos;
MFT_RECORD *mrec, *m;
__u8 var1 = 0;
__u8 var2 = 0;
__u8 var3;
int rc;
wchar_t *al_name;
__u32 al_name_len;
al_val = &ctx->alist_val;
if (ctx->alist_val_end <= *al_val && !ctx->is_first)
goto file_corrupt;
al_val_start = 0;
if (ctx->base) {
if (ctx->is_first)
goto already_have_the_base_and_is_first;
al_val_start = *al_val;
al_pos = (char*)*al_val + le16_to_cpu((*al_val)->length);
} else
al_pos = *al_val;
do_next:
if (al_pos < ctx->alist_val_end)
goto al_pos_below_alist_val_end;
var1 = var2 = 1;
al_pos = *al_val;
do_next_2:
*al_val = al_pos;
if (!type || var1 || type == al_pos->type)
goto compare_names;
if (le32_to_cpu(al_pos->type) > le32_to_cpu(type))
goto gone_too_far;
al_pos = al_next_pos;
goto do_next;
already_have_the_base_and_is_first:
ctx->is_first = FALSE;
if (*al_val < ctx->alist_val_end)
goto do_next;
if (ctx->base) {
// FIXME: CcUnpinData(ctx->base);
ctx->base = NULL;
}
if (!type)
return FALSE;
if (read_file_record(vol, mref, &ctx->mrec, &ctx->attr) < 0)
return FALSE;
ctx->base = ctx->mrec;
find_attr(vol, type, name, name_len, ic, val, val_len, ctx);
return FALSE;
al_pos_below_alist_val_end:
if (al_pos < ctx->alist_val)
goto file_corrupt;
if (al_pos >= ctx->alist_val_end)
goto file_corrupt;
if (!al_pos->length)
goto file_corrupt;
al_next_pos = (ATTR_LIST_ENTRY*)((char*)al_pos +
le16_to_cpu(al_pos->length));
goto do_next_2;
gone_too_far:
var1 = 1;
compare_names:
al_name_len = al_pos->name_length;
al_name = (wchar_t*)((char*)al_pos + al_pos->name_offset);
if (!name || var1)
goto compare_lowest_vcn;
if (ic == CASE_SENSITIVE) {
if (name_len == al_name_len &&
!memcmp(al_name, name, al_name_len << 1))
rc = TRUE;
else
rc = FALSE;
} else /* IGNORE_CASE */
rc = ntfs_are_names_equal(al_name, al_name_len, name, name_len,
ic, vol->upcase, vol->upcase_len);
if (rc)
goto compare_lowest_vcn;
rc = ntfs_collate_names(vol->upcase, vol->upcase_len, name, name_len,
al_name, al_name_len, IGNORE_CASE, 1);
if (rc == -1)
goto name_collates_before_al_name;
if (!rc && ntfs_collate_names(vol->upcase, vol->upcase_len, name,
name_len, al_name, al_name_len,
IGNORE_CASE, 0) == -1)
goto name_collates_before_al_name;
al_pos = al_next_pos;
goto do_next;
name_collates_before_al_name:
var1 = 1;
compare_lowest_vcn:
if (lowest_vcn && !var1 && al_next_pos < ctx->alist_val_end &&
sle64_to_cpu(al_next_pos->lowest_vcn) <= sle64_to_cpu(lowest_vcn) &&
al_next_pos->type == al_pos->type &&
al_next_pos->name_length == al_name_len &&
!memcmp((char*)al_next_pos + al_next_pos->name_offset, al_name,
al_name_len << 1)) {
al_pos = al_next_pos;
goto do_next;
}
/* Don't mask the sequence number. If it isn't equal, the ref is stale.
*/
if (al_val_start &&
al_pos->mft_reference == al_val_start->mft_reference) {
mrec = ctx->mrec;
attr_pos = (ATTR_RECORD*)((char*)mrec +
le16_to_cpu(mrec->attrs_offset));
} else {
if (ctx->base) {
// FIXME: CcUnpinData(ctx->base);
ctx->base = 0;
}
if (read_file_record(vol, le64_to_cpu(al_pos->mft_reference),
&m, &attr_pos) < 0)
return FALSE;
mrec = ctx->mrec;
ctx->base = ctx->mrec = m;
}
var3 = 0;
do_next_attr_loop_start:
if (attr_pos < mrec || attr_pos > (char*)mrec + vol->mft_record_size)
goto file_corrupt;
if (attr_pos->type == $END)
goto do_next_al_entry;
if (!attr_pos->length)
goto file_corrupt;
if (al_pos->instance != attr_pos->instance)
goto do_next_attr;
if (al_pos->type != attr_pos->type)
goto do_next_al_entry;
if (!name)
goto skip_name_comparison;
if (attr_pos->name_length != al_name_len)
goto do_next_al_entry;
if (memcmp((wchar_t*)((char*)attr_pos +
le16_to_cpu(attr_pos->name_offset)), al_name,
attr_pos->name_length << 1))
goto do_next_al_entry;
skip_name_comparison:
var3 = 1;
ctx->attr = attr_pos;
if (var1)
goto loc_5217c;
if (!val)
return TRUE;
if (attr_pos->non_resident)
goto do_next_attr;
if (le32_to_cpu(attr_pos->value_length) != val_len)
goto do_next_attr;
if (!memcmp((char*)attr_pos + le16_to_cpu(attr_pos->value_offset),
val, val_len))
return TRUE;
do_next_attr:
attr_pos = (ATTR_RECORD*)((char*)attr_pos +
le32_to_cpu(attr_pos->length));
goto do_next_attr_loop_start;
do_next_al_entry:
if (!var3)
goto file_corrupt;
al_pos = (ATTR_RECORD*)((char*)al_pos + le16_to_cpu(al_pos->length));
goto do_next;
loc_5217c:
if (var2)
*al_val = (ATTR_RECORD*)((char*)al_pos +
le16_to_cpu(al_pos->length));
if (ctx->base) {
// FIXME: CcUnpinData(ctx->base);
ctx->base = 0;
}
if (!type)
return FALSE;
if (read_file_record(vol, mref, &mrec, &ctx->attr) < 0)
return FALSE;
ctx->base = mrec;
find_attr(vol, type, name, name_len, ic, val, val_len, ctx);
return FALSE;
file_corrupt:
#ifdef DEBUG
fprintf(stderr, "lookup_attr() encountered corrupt file record.\n");
#endif
return FALSE;
}
BOOL lookup_attr(const ntfs_volume *vol, const MFT_REFERENCE *mref,
const ATTR_TYPES type, const wchar_t *name,
const __u32 name_len, const IGNORE_CASE_BOOL ic,
const __s64 lowest_vcn, const __u8 *val, const __u32 val_len,
attr<F12_search_context *ctx)
{
MFT_RECORD *m;
ATTR_RECORD *a;
__s64 len;
if (!vol || !ctx) {
#ifdef DEBUG
printf(stderr, "lookup_attr() received NULL pointer!\n");
#endif
return FALSE;
}
if (ctx->base)
goto already_have_the_base;
if (read_file_record(vol, mref, &m, &a) < 0)
return FALSE;
ctx->base = ctx->mrec = m;
ctx->attr = a;
ctx->alist_mrec = ctx->alist_attr = ctx->alist_val = NULL;
/*
* Look for an attribute list and at the same time check for attributes
* which collate before the attribute list (i.e. $STANDARD_INFORMATION).
*/
if (le32_to_cpu(a->type) > le32_to_cpu($ATTRIBUTE_LIST))
goto no_attr_list;
do_next:
if (!a->length)
goto file_corrupt;
if (a->type == $ATTRIBUTE_LIST)
goto attr_list_present;
a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
if (a < m || a > (char*)m + vol->mft_record_size)
goto file_corrupt;
if (le32_to_cpu(a->type) <= le32_to_cpu($ATTRIBUTE_LIST))
goto do_next;
no_attr_list:
if (!type ||
type == $STANDARD_INFORMATION && a->type == $STANDARD_INFORMATION)
goto found_it;
call_find_attr:
return find_attr(vol, type, name, name_len, ic, val, val_len, ctx);
found_it:
ctx->attr = a;
return TRUE;
already_have_the_base:
/*
* If ctx->is_first, search starting with ctx->attr. Otherwise
* continue search after ctx->attr.
*/
if (ctx->is_first) {
a = ctx->attr;
ctx->is_first = 0;
} else
a = (ATTR_RECORD*)((char*)ctx->attr +
le32_to_cpu(ctx->attr->length));
if (a < m || a > (char*)m + vol->mft_record_size)
goto file_corrupt;
if (a->type == $END)
return FALSE;
if (!a->length)
goto file_corrupt;
if (type)
goto call_find_attr;
goto found_it;
attr_list_present:
/*
* Looking for zero means we return the first attribute, which will
* be the first one listed in the attribute list.
*/
ctx->attr = a;
if (!type)
goto search_attr_list;
if (type == $ATTRIBUTE_LIST)
return TRUE;
search_attr_list:
/*
* "a" contains the attribute list attribute at this stage.
*/
ctx->alist_attr = a;
len = get_attribute_value_length(a);
#ifdef DEBUG
if (len > 0x40000LL) {
printf(stderr, "lookup_attr() found corrupt attribute list.\n");
return FALSE;
}
#endif
ctx->alist_val_len = len;
if (!(ctx->alist_val = malloc(ctx->alist_val_len))) {
#ifdef DEBUG
printf(stderr, "lookup_attr() failed to allocate memory for "
"attribute list value.\n");
#endif
return FALSE;
}
if (get_attribute_value(vol, ctx->mrec, a, ctx->alist_val) !=
ctx->alist_val_len) {
#ifdef DEBUG
printf(stderr, "lookup_attr() failed to read attribute list "
"value.\n");
#endif
return FALSE;
}
ctx->alist_val_end = (char*)ctx->alist_val + ctx->alist_val_len;
if (a->non_resident) {
ctx->alist_old_base = ctx->alist_val_base;
ctx->alist_val_base = ctx->base;
ctx->base = NULL;
} else if (ctx->base) {
// FIXME: CcUnpinData(ctx->base);
ctx->base = NULL;
}
lookup_external:
return lookup_external_attr(vol, mref, type, name, name_len, ic,
lowest_vcn, val, val_len, ctx);
file_corrupt:
#ifdef DEBUG
fprintf(stderr, "lookup_attr() encountered corrupt file record.\n");
#endif
return FALSE;
}
Index: Makefile.in
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/Makefile.in,v
retrieving revision 1.2
retrieving revision 1.3
diff -U2 -r1.2 -r1.3
--- Makefile.in 2001/02/03 02:03:36 1.2
+++ Makefile.in 2001/04/02 02:04:37 1.3
@@ -96,5 +96,5 @@
lib_LTLIBRARIES = libntfs.la
libntfs_la_LDFLAGS = -version-info $(LTVERSION)
-libntfs_la_SOURCES = attrib.c bootsect.c bitmap.c mft.c volume.c disk_io.c ntfs_rec.c
+libntfs_la_SOURCES = attrib.c bootsect.c bitmap.c mft.c volume.c disk_io.c ntfs_rec.c unistr.c
@@ -110,5 +110,5 @@
libntfs_la_LIBADD =
libntfs_la_OBJECTS = attrib.lo bootsect.lo bitmap.lo mft.lo volume.lo \
-disk_io.lo ntfs_rec.lo
+disk_io.lo ntfs_rec.lo unistr.lo
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -123,5 +123,6 @@
GZIP_ENV = --best
DEP_FILES = .deps/attrib.P .deps/bitmap.P .deps/bootsect.P \
-.deps/disk_io.P .deps/mft.P .deps/ntfs_rec.P .deps/volume.P
+.deps/disk_io.P .deps/mft.P .deps/ntfs_rec.P .deps/unistr.P \
+.deps/volume.P
SOURCES = $(libntfs_la_SOURCES)
OBJECTS = $(libntfs_la_OBJECTS)
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -U2 -r1.7 -r1.8
--- attrib.c 2001/03/15 23:13:45 1.7
+++ attrib.c 2001/04/02 02:04:37 1.8
@@ -33,107 +33,9 @@
#include "volume.h"
#include "unistr.h"
+#include "support.h"
-/*
- * Generic macro to convert pointers to values for comparison purposes.
- */
-#define p2n(p) ((ptrdiff_t)((ptrdiff_t*)(p)))
-
-ATTR_RECORD *find_next_attr_in_attr_list(
- const ntfs_volume *v,
- const MFT_RECORD *m,
- const ATTR_RECORD *al,
- const ATTR_TYPES t,
- const wchar_t *n,
- FIND_ATTR_CTX_FLAGS *ctx)
-{
- __u64 alen;
- ATTR_LIST_ENTRY *ale, *aend;
- int got_there = 0;
-
- if (!al || !ctx || al->type != $ATTRIBUTE_LIST) {
- errno = EINVAL;
- goto ret_now;
- }
- if (al->flags) {
-#ifdef DEBUG
- puts("Error! Compressed/sparse/encrypted attribute lists not "
- "supported.");
-#endif
- errno = ENOTSUP;
- goto ret_now;
- }
- /* Get the actual attribute list and it's length. */
- alen = get_attribute_value_length(al);
- if (!al->non_resident) {
- astart = (ATTR_LIST_ENTRY*)((char*)al +
- le16_to_cpu(al->value_offset));
- } else {
- if (!(astart = (ATTR_LIST_ENTRY*)malloc(alen)))
- goto ret_now;
- if (get_attribute_value(v, al, astart) != alen)
- goto error_ret;
- }
- /* Set aend to first byte after the attribute list. */
- aend = (ATTR_LIST_ENTRY*)((char*)astart + alen);
- /* Iterate over all attribute list entries looking for the right one. */
- for (ale = astart; ale < aend; ale = (ATTR_LIST_ENTRY*)
- ((char*)ale + le16_to_cpu(ale->length))) {
- /* If we encounter lowest_vcn != 0 then instance is 0 and we
- are currently in a list of extents. */
- if (*ctx == FIRST_SEARCH) {
- /* The attribute was not found in the base mft record
- at all. Thus take the first matching entry and
- return that. */
- *ctx = IN_ATTR_LIST | ...;
- } else {
- /* The attribute has been found before. */
- if (!(*ctx & IN_ATTR_LIST)) {
- /* We were not in the attribute list before,
- yet we had found the attribute at least once
- already. The entry we had found will be
- duplicated in the attribute list. Thus, skip
- the first matching entry (which will be the
- duplicate one). */
- /* FIXME: This won't work as we get into nested
- extents / attributes problem! Argh! We _have_
- to search the attribute list if it is present
- and ignore the base mft record otherwise.
- We search the base mft record for other
- attributes only if the attribute list entry
- points us to it. */
- *ctx |= IN_ATTR_LIST;
- } else {
- /* We were in the attribute list already, */
- }
- }
- }
- errno = ENOENT;
-error_ret:
- if (al->non_resident)
- free(astart);
-ret_now:
- return NULL;
-}
-
-__inline__ ATTR_RECORD *find_first_attr_in_attr_list(
- const ntfs_volume *v,
- const MFT_RECORD *m,
- const ATTR_RECORD *al,
- const ATTR_TYPES t,
- const wchar_t *n,
- FIND_ATTR_CTX_FLAGS *ctx)
-{
- FIND_ATTR_CTX_FLAGS c;
-
- if (!ctx)
- ctx = &c;
- *ctx = FIRST_SEARCH;
- return find_next_attr_in_attr_list(v, m, al, t, n, ctx);
-}
-
/**
- * find_next_attr - find (next) attribute in mft record
+ * find_attr - find (next) attribute in mft record
* @vol: volume on which @a resides (used to find the upcase table)
- * @attr: attribute record inside mft record where to begin the search
* @type: attribute type to find
* @name: attribute name to find (optional, i.e. NULL means don't care)
@@ -142,271 +44,178 @@
* @val: attribute value to find (optional, resident attributes only)
* @val_len: attribute value length
+ * @ctx: search context with mft record and attribute to search from
*
- * 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, @name_len is the @name length
- * in Unicode characters, and @val is ignored.
+ * find_attr() takes a search context @ctx as parameter and searches the mft
+ * record specified by @ctx->mrec, beginning at @ctx->attr, for an attribute of
+ * @type, optionally @name and @val. If found, find_attr() returns TRUE and
+ * @ctx->attr will point to the found attribute. If not found, find_attr()
+ * returns FALSE and @ctx->attr is undefined (i.e. do not rely on it not
+ * changing).
*
+ * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it
+ * is FALSE, the search begins after @ctx->attr.
+ *
+ * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and if it
+ * is CASE_SENSITIVE, the comparison is case sensitive. When @name is present,
+ * @name_len is the @name length in Unicode characters.
+ *
* 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.
+ * all. Thus, to find an unnamed attribute specifically, specify a @name
+ * pointing to a zero length string.
*
- * find_next_attr() only searches the mft record in which @attr is present and
- * it ignores the presence of an attribute list attribute (unless it is the one
- * being searched for, obviously). If you need to take attribute lists into
- * consideration, use lookup_next_attr() instead (see below).
+ * Finally, the resident attribute value @val is looked for, if present. If @val
+ * is not present (NULL), @val_len is ignored.
*
+ * find_attr() only searches the specified mft record and it ignores the
+ * presence of an attribute list attribute (unless it is the one being searched
+ * for, obviously). If you need to take attribute lists into consideration, use
+ * lookup_attr() instead (see below). This also means that you cannot use
+ * find_attr() to search for extent records of non-resident attributes, as
+ * extents with lowest_vcn != 0 are invariably described by the attribute list
+ * attribute only.
+ *
* 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, wchar_t *name,
- const __u32 name_len, const IGNORE_CASE_BOOL ic,
- const __u8 *val, const __u32 val_len)
+BOOL find_attr(const ntfs_volume *vol, const ATTR_TYPES type,
+ const wchar_t *name, const __u32 name_len,
+ const IGNORE_CASE_BOOL ic, const __u8 *val, const __u32 val_len,
+ attr_search_context *ctx)
{
ATTR_RECORD *a;
- void *mft_rec;
#ifdef DEBUG
- if (!vol || !attr || !*attr) {
- printf(stderr, "find_next_attr() received NULL pointer!\n");
- return NULL;
+ if (!vol || !ctx || !ctx->mrec || !ctx->attr) {
+ printf(stderr, "find_attr() received NULL pointer!\n");
+ return FALSE;
}
#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 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 = p2n(a) & (vol->mft_record_size - 1);
/*
- * Iterate over attributes in mft record starting at @attr.
- * Note: Not using while/do/for loops so the comparison code
- * does not get indented out of the screen... (AIA)
+ * Iterate over attributes in mft record starting at @ctx->attr, or the
+ * attribute following that, if @ctx->is_first is TRUE.
*/
- 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;
+ if (ctx->is_first) {
+ a = ctx->attr;
+ ctx->is_first = FALSE;
+ } else
+ a = (ATTR_RECORD*)((char*)ctx->attr +
+ le32_to_cpu(ctx->attr->length));
+ for (; p2n(a) >= p2n(ctx->mrec) &&
+ (char*)a <= (char*)ctx->mrec + vol->mft_record_size;
+ a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
+ if (p2n(a) < p2n(ctx->mrec) ||
+ (char*)a > (char*)ctx->mrec + vol->mft_record_size)
+ break;
+ ctx->attr = a;
+ /* We catch $END with this more general check, too... */
+ if (le32_to_cpu(a->type) > le32_to_cpu(type))
+ return FALSE;
+ if (!a->length)
+ break;
+ if (a->type != type)
+ continue;
+ /* If @name is present, compare the two names. */
+ if (name && !ntfs_are_names_equal(name, name_len,
+ (wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
+ a->name_length, ic, vol->upcase, vol->upcase_len)) {
+ register int rc;
+
+ rc = ntfs_collate_names(vol->upcase, vol->upcase_len,
+ name, name_len, (wchar_t*)((char*)a +
+ le16_to_cpu(a->name_offset)),
+ a->name_length, IGNORE_CASE, 1);
+ /*
+ * If @name collates before a->name, there is no
+ * matching attribute.
+ */
+ if (rc == -1)
+ return FALSE;
+ /* If the strings are not equal, continue search. */
+ if (rc)
+ continue;
+ rc = ntfs_collate_names(vol->upcase, vol->upcase_len,
+ name, name_len, (wchar_t*)((char*)a +
+ le16_to_cpu(a->name_offset)),
+ a->name_length, CASE_SENSITIVE, 1);
+ if (rc == -1)
+ return FALSE;
+ if (rc)
+ continue;
+ }
+ /*
+ * The names match or @name not present. If no @val specified,
+ * we have found the attribute and are done.
+ */
+ if (!val)
+ return TRUE;
+ /* @val is present; compare values. */
+ else {
+ register int rc;
+
+ rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset),
+ min(val_len, le32_to_cpu(a->value_length)));
+ /*
+ * If @val collates before the current attribute's
+ * value, there is no matching attribute.
+ */
+ if (!rc) {
+ register __u32 avl;
+ avl = le32_to_cpu(a->value_length);
+ if (val_len == avl)
+ return TRUE;
+ if (val_len < avl)
+ return FALSE;
+ } else if (rc < 0)
+ return FALSE;
}
- rv = memcmp(val, (char*)a + le16_to_cpu(a->value_offset),
- min(val_len, le32_to_cpu(a->value_length)));
- /* If @val collates after the current attribute's value,
- continue searching as a matching attribute might follow. */
- 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;
- }
- 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;
- }
- { register int rc = ntfs_collate_names(vol->upcase,
- vol->upcase_len, name, name_len,
- (wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
- a->name_length, IGNORE_CASE, 1);
- /* If case insensitive collation of names collates @name
- before a->name, there is no matching attribute. */
- if (rc == -1)
- goto not_found;
- /* If the strings are not equal, continue search. */
- if (rc)
- goto do_next;
- }
- /* If case sensitive collation of names doesn't collate @name before
- a->name, we continue the search. Otherwise we haven't found it. */
- if (ntfs_collate_names(vol->upcase, vol->upcase_len, name, name_len,
- (wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
- a->name_length, CASE_SENSITIVE, 1) != -1)
- goto do_next;
-not_found:
- return NULL;
-file_corrupt:
+ }
#ifdef DEBUG
- printf(stderr, "find_next_attr(): File is corrupt. Run chkdsk.\n");
+ printf(stderr, "find_attr(): File is corrupt. Run chkdsk.\n");
#endif
- goto not_found;
+ return FALSE;
}
-__inline__ ATTR_RECORD *find_first_attr(const ntfs_volume *vol,
- const MFT_RECORD *mft_rec, const ATTR_TYPES type,
- wchar_t *name, const __u32 name_len, const IGNORE_CASE_BOOL ic,
- const __u8 *val, const __u32 val_len)
+/**
+ * find_first_attr - find first attribute in mft record
+ * @vol: volume on which @a resides (used to find the upcase table)
+ * @type: attribute type to find
+ * @name: attribute name to find (optional, i.e. NULL means don't care)
+ * @name_len: attribute name length (only needed if @name present)
+ * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
+ * @val: attribute value to find (optional, resident attributes only)
+ * @val_len: attribute value length
+ * @ctx: search context with mft record and attribute to search from
+ *
+ * find_first_attr() is just an inlined wrapper for find_attr(). For details
+ * see description of find_attr() above.
+ */
+__inline__ BOOL find_first_attr(const ntfs_volume *vol, const ATTR_TYPES type,
+ const wchar_t *name, const __u32 name_len,
+ const IGNORE_CASE_BOOL ic, const __u8 *val, const __u32 val_len,
+ attr_search_context *ctx)
{
+ MFT_RECORD *m;
ATTR_RECORD *a;
#ifdef DEBUG
- if (!vol || !mft_rec) {
+ if (!vol || !ctx || !ctx->mrec) {
printf(stderr, "find_first_attr() received NULL pointer!\n");
- return NULL;
+ return FALSE;
}
+ if (ctx->attr)
+ printf(stderr, "find_first_attr(): received non-NULL attribute "
+ "pointer.\nThis will be overwritten resulting "
+ "in possible memory leakage.\n");
#endif
- a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
- if (a < mft_rec || a > (char*)mft_rec + vol->mft_record_size)
- goto file_corrupt;
- return find_next_attr(vol, &a, type, name, name_len, ic, val, val_len);
-}
-
-/*
- * The difference between lookup_attr and find_attr is that find_attr will only
- * look inside the mft record, ignoring attribute lists, while lookup_attr will
- * take the attribute list in consideration if present. If not, it just calls
- * find_attr. Also in kernel, lookup_attr takes and mft_reference as parameter,
- * while find_attr takes a pointer within a pinned/locked page cache page.
- *
- * v = volume
- * m = mft record to search, also consistency check the sequence number if not 0
- * (kernel), in user space @m is the buffer containing the mft record
- * type = attribute type to find (0 = find first attribute)
- * name = attribute name to find (NULL = unnamed)
- * ic = ignore case (true/false)
- * val = attribute value to find (resident attributes only, NULL = don't care)
- * len = length of attribute value to find (only valid if val != NULL)
- * lvcn = lowest_vcn to find (non-resident attributes only)
- *
- * return: memory location of attribute we are looking for. this will be
- * an offset into a (pinned/locked?) page cache page in the driver.
- * for userspace we just return a pointer into the mft record @m.
- */
-ATTR_RECORD *lookup_attr(const ntfs_volume *vol, const MFT_RECORD *m,
- const IS_FIRST_BOOL *first, const ATTR_RECORD **attr,
- const ATTR_TYPES type, const wchar_t *name,
- const __u32 name_len, const IGNORE_CASE_BOOL ic,
- const __u8 *val, const __u32 val_len)
-{
- ATTR_RECORD *a, *alist = NULL;
- int got_there = 0;
-
-#ifdef DEBUG
- /* Sanity/size/alignment checks. */
- if (!vol || !m || !attr || !is_mft_recordp(m) ||
- !(m->flags & MFT_RECORD_IN_USE) ||
- m->base_mft_record ||
- p2n((char*)m + m->attributes_offset) & 7 ||
- p2n((char*)m + m->bytes_in_use) & 7 ||
- le16_to_cpu(m->attributes_offset) >= le32_to_cpu(m->bytes_in_use)) {
- puts("Sanity/size/allignment checks failed in " \
- "lookup_attr()!");
- return NULL;
- }
-#endif
- if (!*attr) {
- /* Position of the first attribute. */
- a = (ATTR_RECORD*)(le16_to_cpu(m->attributes_offset) +
- (char*)m);
+ m = ctx->mrec;
+ ctx->is_first = TRUE;
+ ctx->attr = a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
+ if (p2n(a) >= p2n(m) && (char*)a <= (char*)m + vol->mft_record_size)
+ return find_attr(vol, type, name, name_len, ic, val, val_len,
+ ctx);
#ifdef DEBUG
- if (p2n(a) & 7) {
- puts("Alignment check (2) failed in lookup_attr()!");
- return NULL;
- }
+ printf(stderr, "find_first_attr(): file is corrupt.");
#endif
- } else {
- if (*first) {
- /* Where to commence the search. */
- a = *attr;
- } else {
- /* Where to continue the search. */
- a = (ATTR_RECORD*)((char*)*attr +
- le32_to_cpu(*attr->length));
- }
- if (a < m || a > (char*)m + vol->mft_record_size)
- goto file_corrupt;
- *first = 0;
- if (a->type == $END)
- goto not_found;
- if (!a->length)
- goto file_corrupt;
- if (!type)
- goto call_find_attr;
- goto found_it;
- }
- /*
- * Look for an attribute list and at the same time check for attributes
- * which collate before the attribute list (i.e. $STANDARD_INFORMATION).
- */
- if (le32_to_cpu(a->type) > le32_to_cpu($ATTRIBUTE_LIST))
- goto no_attr_list;
-do_next:
- if (!a->length)
- goto file_corrupt;
- if (a->type == $ATTRIBUTE_LIST)
- goto attr_list_present;
- a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
- if (a < m || a > (char*)m + vol->mft_record_size)
- goto file_corrupt;
- if (le32_to_cpu(a->type) <= le32_to_cpu($ATTRIBUTE_LIST))
- goto do_next;
-no_attr_list:
- if (!type ||
- type == $STANDARD_INFORMATION && a->type == $STANDARD_INFORMATION)
- goto found_it;
-call_find_attr:
- *attr = find_next_attr(vol, &a, type, name, name_len, ic, val, val_len);
-return_now:
- return a;
-found_it:
- *attr = a;
- goto return_now;
-not_found:
- /* The requested attribute is not present. */
- a = NULL;
- goto return_now;
-attr_list_present:
- /* Looking for zero means we return the first attribute, which will
- * be the first one listed in the attribute list. */
- if (type == 0)
- goto search_attr_list;
- if (type == $ATTRIBUTE_LIST)
- goto found_it;
-search_attr_list:
- *attr = a;
- al = a;
- _NtfsMapAttributeValue(arg_0, arg_4,
- arg_output_buf[0x24]pattr_valueOUT, attr_val_lenOUT,
- arg_output_buf[0x1c]OUT, arg_output_bufIN/OUT);
+ return FALSE;
}
@@ -417,4 +226,5 @@
ATTR_RECORD *r;
VOLUME_INFORMATION *c;
+ attr_search_context ctx;
/* Sanity checks. */
@@ -422,9 +232,13 @@
return 0;
/* Get a pointer to the volume information attribute. */
- if (!(r = find_first_attr(v, b, $VOLUME_INFORMATION, NULL))) {
+ memset(&ctx, 0, sizeof(attr_search_context));
+ ctx.mrec = b;
+ if (!find_first_attr(v, $VOLUME_INFORMATION, NULL, 0, 0, NULL, 0,
+ &ctx)) {
fprintf(stderr, "Error: Attribute $VOLUME_INFORMATION was " \
"not found in $Volume!\n");
return 0;
}
+ r = ctx.attr;
/* Sanity check. */
if (r->non_resident) {
@@ -469,5 +283,5 @@
{
/* Sanity checks. */
- if (!vol || !a || !b) {
+ if (!vol || !m || !a || !b) {
errno = EINVAL;
return 0;
@@ -576,7 +390,7 @@
}
memcpy(b + total, intbuf,
- sle64_to_cpu(NA(a)->data_size) - total);
+ sle64_to_cpu(a->data_size) - total);
free(intbuf);
- total = sle64_to_cpu(NA(a)->data_size);
+ total = sle64_to_cpu(a->data_size);
} else {
/*
@@ -615,5 +429,4 @@
free(rl);
return total;
-#undef NA
}
errno = EINVAL;
@@ -730,9 +543,4 @@
if (!attr || !attr->non_resident)
return NULL;
- /*
- * Other fail safe checks are not required since the caller is
- * assumed to have done alignment and other consistency checks.
- * See find_attribute() above for an example.
- */
/* FIXME: Compression not supported yet. */
if (attr->compression_unit) {
Index: disk_io.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/disk_io.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -U2 -r1.6 -r1.7
--- disk_io.c 2001/03/26 04:34:20 1.6
+++ disk_io.c 2001/04/02 02:04:37 1.7
@@ -118,5 +118,5 @@
finished:
/* Quickly deprotect the data again. */
- __post_read_mft_fixup((NTFS_RECORD*)b, count);
+ __post_read_mst_fixup((NTFS_RECORD*)b, count);
error_end:
return error;
@@ -266,16 +266,16 @@
* get_mft_records - read records from the mft
* @vol: volume to read from
- * @buf: output data buffer
+ * @mrec: output data buffer
* @mref: starting mft record number
* @count: number of mft records to read
*
* Read @count mft records starting at @mref from volume @vol into buffer
- * @buf. Return @count on success or -ERRNO on error, where ERRNO is the error
+ * @mrec. Return @count on success or -ERRNO on error, where ERRNO is the error
* code. This function will do the error reporting so caller really only needs
* to check for sucess / failure.
*
- * NOTE: @buf has to be at least of size @count * vol->mft_record_size.
+ * NOTE: @mrec has to be at least of size @count * vol->mft_record_size.
*/
-int get_mft_records(const ntfs_volume *vol, __u8 *buf,
+int get_mft_records(const ntfs_volume *vol, MFT_RECORD *mrec,
const MFT_REFERENCE *mref, const int count)
{
@@ -283,9 +283,9 @@
__s64 lcn, ofs;
- if (!vol || !buf)
+ if (!vol || !mrec)
return -EINVAL;
if (!vol->fd)
return -EBADF;
- m = mref->mft_reference & MFT_REFERENCE_MASK;
+ m = *(__u64*)mref & MFT_REFERENCE_MASK_CPU;
if (vol->number_of_mft_records < m + count)
return -ESPIPE;
@@ -312,5 +312,5 @@
return -eo;
}
- br = mst_pread(vol->fd, buf, vol->mft_record_size, count,
+ br = mst_pread(vol->fd, (__u8*)mrec, vol->mft_record_size, count,
(lcn << vol->cluster_size_bits) + ofs);
if (br != count) {
@@ -334,19 +334,19 @@
* get_mft_record - read a record from the mft
* @vol: volume to read from
- * @buf: output data buffer
+ * @mrec: output data buffer
* @mref: starting mft record number
* @count: number of mft records to read
*
- * Read mft record specified by @mref from volume @vol into buffer @buf.
+ * Read mft record specified by @mref from volume @vol into buffer @mrec.
* Return 1 on success or -ERRNO on error, where ERRNO is the error
* code. This function will do the error reporting so caller really only needs
* to check for sucess / failure.
*
- * NOTE: @buf has to be at least of size vol->mft_record_size.
+ * NOTE: @mrec has to be at least of size vol->mft_record_size.
*/
-__inline__ int get_mft_record(const ntfs_volume *vol, __u8 *buf,
+__inline__ int get_mft_record(const ntfs_volume *vol, MFT_RECORD *mrec,
const MFT_REFERENCE *mref)
{
- return get_mft_records(vol, buf, mref, 1);
+ return get_mft_records(vol, mrec, mref, 1);
}
@@ -361,5 +361,5 @@
* to read, including the sequence number. When the function returns, @mrec and
* @attr will contain pointers to the read mft record and to the first attribute
- * within the mft record, respectively.
+ * within the mft record, respectively. @attr is optional (can be NULL).
*
* The read mft record is checked for having the magic FILE, for being in use,
@@ -375,7 +375,8 @@
{
MFT_RECORD *m;
+ ATTR_RECORD *a;
int er = 0;
- if (!vol || !mrec || !attr) {
+ if (!vol || !mrec) {
#ifdef DEBUG
fprintf(stderr, "read_file_record() received NULL pointer!\n");
@@ -394,11 +395,11 @@
if (!(m->flags & MFT_RECORD_IN_USE))
goto file_corrupt;
- *attr = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
- if (*attr < m || *attr > (char*)m + vol->mft_record_size)
+ a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
+ if (p2n(a) < p2n(m) || (char*)a > (char*)m + vol->mft_record_size)
goto file_corrupt;
*mrec = m;
+ if (attr)
+ *attr = a;
return 0;
-file_corrupt_attr:
- *attr = NULL;
file_corrupt:
#ifdef DEBUG
@@ -420,5 +421,5 @@
if (!vol->fd)
return -EBADF;
- m = mref->mft_reference & MFT_REFERENCE_MASK;
+ m = *(__u64*)mref & MFT_REFERENCE_MASK_CPU;
if (vol->number_of_mft_records <= m)
return -ESPIPE;
Index: ntfs_rec.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/ntfs_rec.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -U2 -r1.3 -r1.4
--- ntfs_rec.c 2001/03/05 03:04:40 1.3
+++ ntfs_rec.c 2001/04/02 02:04:37 1.4
@@ -61,5 +61,5 @@
/* Size and alignement checks. */
if ( size & (NTFS_SECTOR_SIZE - 1) ||
- usa_ofs & 1 ||
+ usa_ofs & 1 ||
usa_ofs + (usa_count * 2) > size ||
(size >> NTFS_SECTOR_SIZE_BITS) != usa_count)
@@ -95,4 +95,5 @@
}
data_pos += NTFS_SECTOR_SIZE/sizeof(__u16);
+ }
/* Re-setup the variables. */
usa_count = le16_to_cpu(b->usa_count) - 1;
Index: unistr.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/unistr.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -U2 -r1.2 -r1.3
--- unistr.c 2001/03/31 15:27:34 1.2
+++ unistr.c 2001/04/02 02:04:37 1.3
@@ -22,4 +22,22 @@
#include "unistr.h"
+/*
+ * This is used by the name collation functions to quickly determine what
+ * characters are (in)valid.
+ */
+const __u8 legal_ansi_char_array[0x40] = {
+ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+
+ 0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00,
+
+ 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
+};
+
/**
* ntfs_are_names_equal - compare two Unicode names for equality
Index: volume.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/volume.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -U2 -r1.7 -r1.8
--- volume.c 2001/03/31 15:27:34 1.7
+++ volume.c 2001/04/02 02:04:37 1.8
@@ -34,6 +34,7 @@
#include "disk_io.h"
#include "mft.h"
+#include "support.h"
-ntfs_volume *ntfs_open(const char *name)
+ntfs_volume *ntfs_mount(const char *name)
{
const char *OK = "OK";
@@ -50,4 +51,6 @@
__s8 c;
attr_search_context ctx;
+ MFT_REFERENCE mref;
+ int err;
if (!name) {
@@ -223,8 +226,9 @@
}
/* Find the bitmap attribute. */
- memset(ctx, 0, sizeof(attr_search_context));
+ memset(&ctx, 0, sizeof(attr_search_context));
ctx.mrec = mb;
ctx.attr = (ATTR_RECORD*)((char*)mb + le16_to_cpu(mb->attrs_offset));
- if (ctx.attr < mb || ctx.attr > (char*)mb + vol->mft_record_size) {
+ if (p2n(ctx.attr) < p2n(mb) ||
+ (char*)ctx.attr > (char*)mb + vol->mft_record_size) {
puts(FAILED);
fprintf(stderr, "Error: corrupt mft record for $Mft.\n"
@@ -234,5 +238,5 @@
}
ctx.is_first = TRUE;
- if (!lookup_attr(vol, 0, $BITMAP, NULL, 0, 0, 0, 0, 0, &ctx)) {
+ if (!find_attr(vol, $BITMAP, NULL, 0, 0, NULL, 0, &ctx)) {
puts(FAILED);
fprintf(stderr, "$bitmap attribute not found in $Mft?!?\n");
@@ -257,5 +261,5 @@
}
/* Read in the bitmap attribute value into the buffer. */
- if (l != get_attribute_value(vol, a, vol->mft_bitmap)) {
+ if (l != get_attribute_value(vol, mb, a, vol->mft_bitmap)) {
puts(FAILED);
puts("Amount of data read does not correspond to expected "
@@ -264,12 +268,10 @@
goto error_exit;
}
- //if (ctx.alist_val)
- // free(ctx.alist_val);
/* Find the $DATA attribute in $Mft. */
- memset(ctx, 0, sizeof(attr_search_context));
+ memset(&ctx, 0, sizeof(attr_search_context));
ctx.mrec = mb;
ctx.attr = (ATTR_RECORD*)((char*)mb + le16_to_cpu(mb->attrs_offset));
ctx.is_first = TRUE;
- if (!lookup_attr(vol, 0, $DATA, NULL, 0, 0, 0, 0, 0, &ctx)) {
+ if (!find_attr(vol, $DATA, NULL, 0, 0, NULL, 0, &ctx)) {
puts(FAILED);
fprintf(stderr, "$DATA attribute not found in $Mft?!?\n");
@@ -277,4 +279,5 @@
goto error_exit;
}
+ a = ctx.attr;
/* Determine the number of mft records in $Mft. */
vol->number_of_mft_records = a->data_size >> vol->mft_record_size_bits;
@@ -296,34 +299,19 @@
}
puts(OK);
+ /* Done with the $Mft mft record. */
+ free(mb);
+ mb = NULL;
/* Now load the bitmap from $Bitmap. */
printf("Loading $Bitmap... ");
- br = get_mft_records(vol, (char*)mb, 6, 1);
- if (br != 1) {
- puts(FAILED);
- errno = EIO;
- goto error_exit;
- }
- if (is_baad_record(mb)) {
+ mref = (MFT_REFERENCE)(__u64)FILE_$BitMap;
+ if (err = read_file_record(vol, &mref, &mb, NULL)) {
puts(FAILED);
- fprintf(stderr, "Error: Incomplete multi sector "
- "transfer detected in $Bitmap.\nCannot "
- "handle this yet. )-:\n");
- errno = EIO;
+ errno = err;
goto error_exit;
}
- if (!is_mft_recordp(mb)) {
- puts(FAILED);
- fprintf(stderr, "Error: Invalid $Mft record for $Bitmap.\n"
- "Cannot handle this yet. )-:\n");
- printf("Record is of type: %c%c%c%c\n", ((char*)mb)[0],
- ((char*)mb)[1],
- ((char*)mb)[2],
- ((char*)mb)[3]);
- errno = EIO;
- goto error_exit;
- }
+ memset(&ctx, 0, sizeof(attr_search_context));
+ ctx.mrec = mb;
/* Find the bitmap (it is in the $DATA attribute). */
- a = find_first_attribute(vol, mb, $DATA, NULL);
- if (!a) {
+ if (!find_first_attr(vol, $DATA, NULL, 0, 0, NULL, 0, &ctx)) {
puts(FAILED);
fprintf(stderr, "bitmap attribute not found in $Bitmap?!?\n");
@@ -331,4 +319,5 @@
goto error_exit;
}
+ a = ctx.attr;
/* Get attribute value size and allocate a big enough buffer.*/
l = get_attribute_value_length(a);
@@ -347,5 +336,5 @@
}
/* Read in the bitmap attribute value into the buffer. */
- if (l != get_attribute_value(vol, a, vol->lcn_bitmap)) {
+ if (l != get_attribute_value(vol, mb, a, vol->lcn_bitmap)) {
puts(FAILED);
puts("Amount of data read does not correspond to expected "
@@ -354,31 +343,20 @@
goto error_exit;
}
+ /* Done with the $BitMap mft record. */
puts(OK);
+ free(mb);
+ mb = NULL;
/* Now load the upcase table from $UpCase. */
printf("Loading $UpCase... ");
- br = get_mft_records(vol, (char*)mb, 10, 1);
- if (br != 1) {
+ mref = (MFT_REFERENCE)(__u64)FILE_$UpCase;
+ if (err = read_file_record(vol, &mref, &mb, NULL)) {
puts(FAILED);
- errno = EIO;
- goto error_exit;
- }
- if (is_baad_record(mb)) {
- puts(FAILED);
- fprintf(stderr, "Error: Incomplete multi sector "
- "transfer detected in $UpCase.\nCannot "
- "handle this yet. )-:\n");
- errno = EIO;
- goto error_exit;
- }
- if (!is_mft_recordp(mb)) {
- puts(FAILED);
- fprintf(stderr, "Error: Invalid $Mft record for $UpCase.\n"
- "Cannot handle this yet. )-:\n");
- errno = EIO;
+ errno = err;
goto error_exit;
- }
+ }
+ memset(&ctx, 0, sizeof(attr_search_context));
+ ctx.mrec = mb;
/* Find the bitmap (it is in the $DATA attribute). */
- a = find_first_attribute(vol, mb, $DATA, NULL);
- if (!a) {
+ if (!find_first_attr(vol, $DATA, NULL, 0, 0, NULL, 0, &ctx)) {
puts(FAILED);
fprintf(stderr, "$DATA attribute not found in $UpCase?!?\n");
@@ -386,4 +364,5 @@
goto error_exit;
}
+ a = ctx.attr;
/* Get attribute value size and allocate a big enough buffer.*/
l = get_attribute_value_length(a);
@@ -405,5 +384,5 @@
}
vol->upcase_len = l >> 1;
- vol->upcase = (__u16*)malloc(l);
+ vol->upcase = (wchar_t*)malloc(l);
if (!vol->upcase) {
puts(FAILED);
@@ -413,5 +392,5 @@
}
/* Read in the $DATA attribute value into the buffer. */
- if (l != get_attribute_value(vol, a, (__u8*)vol->upcase)) {
+ if (l != get_attribute_value(vol, mb, a, (__u8*)vol->upcase)) {
puts(FAILED);
puts("Amount of data read does not correspond to expected "
@@ -420,32 +399,22 @@
goto error_exit;
}
+ /* Done with the $UpCase mft record. */
puts(OK);
+ free(mb);
+ mb = NULL;
/* Now load $Volume and set the version information and flags in the
- vol structure accordingly. */
+ * vol structure accordingly. */
printf("Loading $Volume... ");
- br = get_mft_records(vol, (char*)mb, 3, 1);
- if (br != 1) {
- puts(FAILED);
- errno = EIO;
- goto error_exit;
- }
- if (is_baad_record(mb)) {
+ mref = (MFT_REFERENCE)(__u64)FILE_$Volume;
+ if (err = read_file_record(vol, &mref, &mb, NULL)) {
puts(FAILED);
- fprintf(stderr, "Error: Incomplete multi sector "
- "transfer detected in $Volume.\nCannot "
- "handle this yet. )-:\n");
- errno = EIO;
+ errno = err;
goto error_exit;
}
- if (!is_mft_recordp(mb)) {
- puts(FAILED);
- fprintf(stderr, "Error: Invalid $Mft record for $Volume.\n"
- "Cannot handle this yet. )-:\n");
- errno = EIO;
- goto error_exit;
- }
+ memset(&ctx, 0, sizeof(attr_search_context));
+ ctx.mrec = mb;
/* Find the $VOLUME_INFORMATION attribute. */
- a = find_first_attribute(vol, mb, $VOLUME_INFORMATION, NULL);
- if (!a) {
+ if (!find_first_attr(vol, $VOLUME_INFORMATION, NULL, 0, 0, NULL, 0,
+ &ctx)) {
puts(FAILED);
fprintf(stderr, "$VOLUME_INFORMATION attribute not found in "
@@ -454,4 +423,5 @@
goto error_exit;
}
+ a = ctx.attr;
/* Has to be resident. */
if (a->non_resident) {
@@ -486,6 +456,7 @@
puts(OK);
free(mb);
+ mb = NULL;
- /* FIXME: Need to deal with $AttrDef (4). */
+ /* FIXME: Need to deal with FILE_$AttrDef. */
return vol;
@@ -521,5 +492,5 @@
}
-int ntfs_close(ntfs_volume *vol, const int force)
+int ntfs_umount(ntfs_volume *vol, const int force)
{
if (!vol) {
|