Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv12722/libntfs
Modified Files:
attrib.c attrib_RE.c bootsect.c inode.c mft.c volume.c
Log Message:
Port attribute lookup functions with attribute list support from ntfs tng driver. Port/reimplement extent mft record handling code as well. Rename out all dollar signs from type names and constants. Adapt all callers to new API. Note mkntfs is currently broken due to some needed work.
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -U2 -r1.25 -r1.26
--- attrib.c 19 Apr 2002 21:21:46 -0000 1.25
+++ attrib.c 20 Apr 2002 23:09:42 -0000 1.26
@@ -22,168 +22,14 @@
*/
-#include <stddef.h>
#include <stdio.h>
-#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
-#include "types.h"
#include "attrib.h"
-#include "unistr.h"
-#include "endians.h"
#include "disk_io.h"
-#include "support.h"
#include "mft.h"
#include "debug.h"
-/**
- * find_attr - find (next) attribute in mft record
- * @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)
- * @upcase: unicode upcase table
- * @ucpase_len: length of upcase table in unicode characters
- * @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_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), we assume that the unnamed attribute is
- * being searched for.
- *
- * 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 usually described by the attribute list
- * attribute only. - Note that it is possible that the first extent is only in
- * the attribute list while the last extent is in the base mft record, so don't
- * rely on being able to find the first extent in the base mft record.
- *
- * Warning: Never use @val when looking for attribute types which can be
- * non-resident as this most likely will result in a crash!
- */
-BOOL find_attr(const ATTR_TYPES type, const uchar_t *name, const __u32 name_len,
- const IGNORE_CASE_BOOL ic, const uchar_t *upcase,
- const __u32 upcase_len, const __u8 *val, const __u32 val_len,
- ntfs_attr_search_ctx *ctx)
-{
- ATTR_RECORD *a;
-
-#ifdef DEBUG
- if (!ctx || !ctx->mrec || !ctx->attr) {
- Dputs("find_attr() received NULL pointer!");
- return FALSE;
- }
-#endif
- /*
- * Iterate over attributes in mft record starting at @ctx->attr, or the
- * attribute following that, if @ctx->is_first is TRUE.
- */
- 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 (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
- if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec +
- le32_to_cpu(ctx->mrec->bytes_allocated))
- 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 is
- * missing, assume we want an unnamed attribute.
- */
- if (!name) {
- /* The search failed if the found attribute is named. */
- if (a->name_length)
- return FALSE;
- } else if (!ntfs_are_names_equal(name, name_len,
- (uchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
- a->name_length, ic, upcase, upcase_len)) {
- register int rc;
-
- rc = ntfs_collate_names(name, name_len,
- (uchar_t*)((char*)a +
- le16_to_cpu(a->name_offset)),
- a->name_length, 1, IGNORE_CASE,
- upcase, upcase_len);
- /*
- * 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(name, name_len,
- (uchar_t*)((char*)a +
- le16_to_cpu(a->name_offset)),
- a->name_length, 1, CASE_SENSITIVE,
- upcase, upcase_len);
- if (rc == -1)
- return FALSE;
- if (rc)
- continue;
- }
- /*
- * The names match or @name not present and attribute is
- * unnamed. 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;
- }
- }
- Dputs("find_attr(): File is corrupt. Run chkdsk.");
- return FALSE;
-}
-
/* FIXME: Need to write the new flags to disk. */
int set_ntfs_volume_flags(ntfs_volume *v, MFT_RECORD *b, const __u16 flags)
@@ -202,5 +48,5 @@
return 0;
}
- if (!find_attr($VOLUME_INFORMATION, NULL, 0, 0, NULL, 0, NULL, 0,
+ if (ntfs_lookup_attr(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0,
ctx)) {
Dputs("Error: Attribute $VOLUME_INFORMATION was not found in "
@@ -686,5 +532,5 @@
/**
- * vcn_to_lcn - convert a vcn into a lcn given a run list
+ * ntfs_vcn_to_lcn - convert a vcn into a lcn given a run list
* @rl: run list to use for conversion
* @vcn: vcn to convert
@@ -704,5 +550,5 @@
* -4 = LCN_EINVAL Input parameter error.
*/
-LCN vcn_to_lcn(const run_list_element *rl, const VCN vcn)
+LCN ntfs_vcn_to_lcn(const run_list_element *rl, const VCN vcn)
{
int i;
@@ -742,4 +588,526 @@
* Internal function:
*
+ * ntfs_find_attr - find (next) attribute in mft record
+ * @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
+ *
+ * You shouldn't need to call this function directly. Use lookup_attr() instead.
+ *
+ * ntfs_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, ntfs_find_attr()
+ * returns 0 and @ctx->attr will point to the found attribute. If not found,
+ * ntfs_find_attr() returns -1, with errno set to the error code 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
+ * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
+ * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at
+ * the upcase table. If @ic 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), we assume that the unnamed attribute is
+ * being searched for.
+ *
+ * Finally, the resident attribute value @val is looked for, if present.
+ * If @val is not present (NULL), @val_len is ignored.
+ *
+ * ntfs_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
+ * ntfs_lookup_attr() instead (see below). This also means that you cannot use
+ * ntfs_find_attr() to search for extent records of non-resident attributes, as
+ * extents with lowest_vcn != 0 are usually described by the attribute list
+ * attribute only. - Note that it is possible that the first extent is only in
+ * the attribute list while the last extent is in the base mft record, so don't
+ * rely on being able to find the first extent in the base mft record.
+ *
+ * Warning: Never use @val when looking for attribute types which can be
+ * non-resident as this most likely will result in a crash!
+ */
+static int ntfs_find_attr(const ATTR_TYPES type, const uchar_t *name,
+ const __u32 name_len, const IGNORE_CASE_BOOL ic,
+ const __u8 *val, const __u32 val_len, ntfs_attr_search_ctx *ctx)
+{
+ ATTR_RECORD *a;
+ ntfs_volume *vol;
+ uchar_t *upcase;
+ __u32 upcase_len;
+
+ if (!ctx || !ctx->mrec || !ctx->attr) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (ic == IGNORE_CASE) {
+ vol = ctx->ntfs_ino->vol;
+ upcase = vol->upcase;
+ upcase_len = vol->upcase_len;
+ } else {
+ vol = NULL;
+ upcase = NULL;
+ upcase_len = 0;
+ }
+ /*
+ * Iterate over attributes in mft record starting at @ctx->attr, or the
+ * attribute following that, if @ctx->is_first is TRUE.
+ */
+ 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 (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
+ if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec +
+ le32_to_cpu(ctx->mrec->bytes_allocated))
+ break;
+ ctx->attr = a;
+ /* We catch $END with this more general check, too... */
+ if (le32_to_cpu(a->type) > le32_to_cpu(type)) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (!a->length)
+ break;
+ if (a->type != type)
+ continue;
+ /*
+ * If @name is present, compare the two names. If @name is
+ * missing, assume we want an unnamed attribute.
+ */
+ if (!name) {
+ /* The search failed if the found attribute is named. */
+ if (a->name_length) {
+ errno = ENOENT;
+ return -1;
+ }
+ } else if (!ntfs_are_names_equal(name, name_len,
+ (uchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
+ a->name_length, ic, upcase, upcase_len)) {
+ register int rc;
+
+ rc = ntfs_collate_names(name, name_len,
+ (uchar_t*)((char*)a +
+ le16_to_cpu(a->name_offset)),
+ a->name_length, 1, IGNORE_CASE,
+ upcase, upcase_len);
+ /*
+ * If @name collates before a->name, there is no
+ * matching attribute.
+ */
+ if (rc == -1) {
+ errno = ENOENT;
+ return -1;
+ }
+ /* If the strings are not equal, continue search. */
+ if (rc)
+ continue;
+ rc = ntfs_collate_names(name, name_len,
+ (uchar_t*)((char*)a +
+ le16_to_cpu(a->name_offset)),
+ a->name_length, 1, CASE_SENSITIVE,
+ upcase, upcase_len);
+ if (rc == -1) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (rc)
+ continue;
+ }
+ /*
+ * The names match or @name not present and attribute is
+ * unnamed. If no @val specified, we have found the attribute
+ * and are done.
+ */
+ if (!val)
+ return 0;
+ /* @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 0;
+ if (val_len < avl) {
+ errno = ENOENT;
+ return -1;
+ }
+ } else if (rc < 0) {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+ }
+ Dputs("ntfs_find_attr(): File is corrupt. Run chkdsk.");
+ errno = EIO;
+ return -1;
+}
+
+/*
+ * Internal function:
+ *
+ * ntfs_find_external_attr - find an attribute in the attribute list of an inode
+ * @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)
+ * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only)
+ * @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
+ *
+ * You shouldn't need to call this function directly. Use ntfs_lookup_attr()
+ * instead.
+ *
+ * Find an attribute by searching the attribute list for the corresponding
+ * attribute list entry. Having found the entry, map the mft record for read
+ * if the attribute is in a different mft record/inode, find the attribute in
+ * there and return it.
+ *
+ * On first search @ctx->ntfs_ino must be the base mft record and @ctx must
+ * have been obtained from a call to ntfs_get_attr_search_ctx(). On subsequent
+ * calls @ctx->ntfs_ino can be any extent inode, too (@ctx->base_ntfs_ino is
+ * then the base inode).
+ *
+ * After finishing with the attribute/mft record you need to call
+ * ntfs_release_attr_search_ctx() to cleanup the search context (unmapping any
+ * mapped extent inodes, etc).
+ *
+ * Return 0 if the search was successful and -1 if not, with errno set to the
+ * error code.
+ *
+ * On success, @ctx->attr is the found attribute and it is in mft record
+ * @ctx->mrec.
+ *
+ * On error, @ctx->attr is the attribute which collates just after the attribute
+ * being searched for in the base ntfs inode, i.e. if one wants to add the
+ * attribute to the mft record this is the correct place to insert it into,
+ * and if there is not enough space, the attribute should be placed in an
+ * extent mft record. @ctx->al_entry points to the position within
+ * @ctx->base_ntfs_ino->attr_list at which the new attribute's attribute list
+ * entry should be inserted.
+ *
+ * The following error codes are defined:
+ * ENOENT Attribute not found, not an error as such.
+ * EINVAL Invalid arguments.
+ * EIO I/O error or corrupt data structures found.
+ * ENOMEM Not enough memory to allocate necessary buffers.
+ */
+static int ntfs_find_external_attr(const ATTR_TYPES type, const uchar_t *name,
+ const __u32 name_len, const IGNORE_CASE_BOOL ic,
+ const VCN lowest_vcn, const __u8 *val, const __u32 val_len,
+ ntfs_attr_search_ctx *ctx)
+{
+ ntfs_inode *base_ni, *ni;
+ ntfs_volume *vol;
+ ATTR_LIST_ENTRY *al_entry, *next_al_entry;
+ char *al_start, *al_end;
+ ATTR_RECORD *a;
+ uchar_t *al_name;
+ __u32 al_name_len;
+
+ ni = ctx->ntfs_ino;
+ base_ni = ctx->base_ntfs_ino;
+ Dprintf("Entering for inode %Lu, type 0x%x.\n",
+ (unsigned long long)ni->mft_no, type);
+ if (!base_ni) {
+ /* First call happens with the base mft record. */
+ base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
+ ctx->base_mrec = ctx->mrec;
+ }
+ if (ni == base_ni)
+ ctx->base_attr = ctx->attr;
+ vol = base_ni->vol;
+ al_start = base_ni->attr_list;
+ al_end = al_start + base_ni->attr_list_size;
+ if (!ctx->al_entry)
+ ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
+ /*
+ * Iterate over entries in attribute list starting at @ctx->al_entry,
+ * or the entry following that, if @ctx->is_first is TRUE.
+ */
+ if (ctx->is_first) {
+ al_entry = ctx->al_entry;
+ ctx->is_first = FALSE;
+ } else
+ al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry +
+ le16_to_cpu(ctx->al_entry->length));
+ for (;; al_entry = next_al_entry) {
+ /* Out of bounds check. */
+ if ((__u8*)al_entry < base_ni->attr_list ||
+ (char*)al_entry > al_end)
+ break; /* Inode is corrupt. */
+ ctx->al_entry = al_entry;
+ /* Catch the end of the attribute list. */
+ if ((char*)al_entry == al_end)
+ goto not_found;
+ if (!al_entry->length)
+ break;
+ if ((char*)al_entry + 6 > al_end || (char*)al_entry +
+ le16_to_cpu(al_entry->length) > al_end)
+ break;
+ next_al_entry = (ATTR_LIST_ENTRY*)((char*)al_entry +
+ le16_to_cpu(al_entry->length));
+ if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))
+ goto not_found;
+ if (type != al_entry->type)
+ continue;
+ /*
+ * If @name is present, compare the two names. If @name is
+ * missing, assume we want an unnamed attribute.
+ */
+ al_name_len = al_entry->name_length;
+ al_name = (uchar_t*)((char*)al_entry + al_entry->name_offset);
+ if (!name) {
+ if (al_name_len)
+ goto not_found;
+ } else if (!ntfs_are_names_equal(al_name, al_name_len, name,
+ name_len, ic, vol->upcase, vol->upcase_len)) {
+ register int rc;
+
+ rc = ntfs_collate_names(name, name_len, al_name,
+ al_name_len, 1, IGNORE_CASE,
+ vol->upcase, vol->upcase_len);
+ /*
+ * If @name collates before al_name, there is no
+ * matching attribute.
+ */
+ if (rc == -1)
+ goto not_found;
+ /* If the strings are not equal, continue search. */
+ if (rc)
+ continue;
+ /*
+ * FIXME: Reverse engineering showed 0, IGNORE_CASE but
+ * that is inconsistent with ntfs_find_attr(). The
+ * subsequent rc checks were also different. Perhaps I
+ * made a mistake in one of the two. Need to recheck
+ * which is correct or at least see what is going
+ * on... (AIA)
+ */
+ rc = ntfs_collate_names(name, name_len, al_name,
+ al_name_len, 1, CASE_SENSITIVE,
+ vol->upcase, vol->upcase_len);
+ if (rc == -1)
+ goto not_found;
+ if (rc)
+ continue;
+ }
+ /*
+ * The names match or @name not present and attribute is
+ * unnamed. Now check @lowest_vcn. Continue search if the
+ * next attribute list entry still fits @lowest_vcn. Otherwise
+ * we have reached the right one or the search has failed.
+ */
+ if (lowest_vcn && (char*)next_al_entry >= al_start &&
+ (char*)next_al_entry + 6 < al_end &&
+ (char*)next_al_entry + le16_to_cpu(
+ next_al_entry->length) <= al_end &&
+ sle64_to_cpu(next_al_entry->lowest_vcn) <=
+ sle64_to_cpu(lowest_vcn) &&
+ next_al_entry->type == al_entry->type &&
+ next_al_entry->name_length == al_name_len &&
+ ntfs_are_names_equal((uchar_t*)((char*)
+ next_al_entry +
+ next_al_entry->name_offset),
+ next_al_entry->name_length,
+ al_name, al_name_len, CASE_SENSITIVE,
+ vol->upcase, vol->upcase_len))
+ continue;
+ if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {
+ if (MSEQNO_LE(al_entry->mft_reference) !=
+ le16_to_cpu(
+ ni->mrec->sequence_number)) {
+ Dputs("Found stale mft reference in attribute "
+ "list!");
+ break;
+ }
+ } else { /* Mft references do not match. */
+ /* If there is a mapped extent inode unmap it first. */
+ if (ni != base_ni)
+ ntfs_close_inode(ni);
+ /* Do we want the base record back? */
+ if (MREF_LE(al_entry->mft_reference) ==
+ base_ni->mft_no) {
+ ni = ctx->ntfs_ino = base_ni;
+ ctx->mrec = ctx->base_mrec;
+ } else {
+ /* We want an extent record. */
+ ni = ntfs_open_extent_inode(base_ni,
+ al_entry->mft_reference);
+ if (!ni) {
+ Dperror("Failed to map extent inode");
+ break;
+ }
+ ctx->ntfs_ino = ni;
+ ctx->mrec = ni->mrec;
+ }
+ ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec +
+ le16_to_cpu(ctx->mrec->attrs_offset));
+ }
+ /*
+ * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the
+ * mft record containing the attribute represented by the
+ * current al_entry.
+ */
+ /*
+ * We could call into ntfs_find_attr() to find the right
+ * attribute in this mft record but this would be less
+ * efficient and not quite accurate as ntfs_find_attr() ignores
+ * the attribute instance numbers for example which become
+ * important when one plays with attribute lists. Also, because
+ * a proper match has been found in the attribute list entry
+ * above, the comparison can now be optimized. So it is worth
+ * re-implementing a simplified ntfs_find_attr() here.
+ */
+ a = ctx->attr;
+ /*
+ * Use a manual loop so we can still use break and continue
+ * with the same meanings as above.
+ */
+do_next_attr_loop:
+ if ((char*)a < (char*)ctx->mrec || (char*)a > (char*)ctx->mrec +
+ le32_to_cpu(ctx->mrec->bytes_allocated))
+ break;
+ if (a->type == AT_END)
+ continue;
+ if (!a->length)
+ break;
+ if (al_entry->instance != a->instance)
+ goto do_next_attr;
+ if (al_entry->type != a->type)
+ continue;
+ if (name) {
+ if (a->name_length != al_name_len)
+ continue;
+ if (!ntfs_are_names_equal((uchar_t*)((char*)a +
+ le16_to_cpu(a->name_offset)),
+ a->name_length, al_name, al_name_len,
+ CASE_SENSITIVE, vol->upcase,
+ vol->upcase_len))
+ continue;
+ }
+ ctx->attr = a;
+ /*
+ * If no @val specified or @val specified and it matches, we
+ * have found it!
+ */
+ if (!val || (!a->non_resident && le32_to_cpu(a->value_length)
+ == val_len && !memcmp((char*)a +
+ le16_to_cpu(a->value_offset), val, val_len))) {
+ return 0;
+ }
+do_next_attr:
+ /* Proceed to the next attribute in the current mft record. */
+ a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
+ goto do_next_attr_loop;
+ }
+ if (ni != base_ni) {
+ if (ni)
+ ntfs_close_inode(ni);
+ ctx->ntfs_ino = base_ni;
+ ctx->mrec = ctx->base_mrec;
+ ctx->attr = ctx->base_attr;
+ }
+ Dputs("Inode is corrupt.");
+ errno = EIO;
+ return -1;
+not_found:
+ /*
+ * Seek to the end of the base mft record, i.e. when we return false,
+ * ctx->mrec and ctx->attr indicate where the attribute should be
+ * inserted into the attribute record.
+ * And of course ctx->al_entry points to the end of the attribute
+ * list inside ctx->base_ntfs_ino->attr_list.
+ *
+ * FIXME: Do we really want to do this here? Think about it... (AIA)
+ */
+ ntfs_reinit_attr_search_ctx(ctx);
+ return ntfs_find_attr(type, name, name_len, ic, val, val_len, ctx);
+}
+
+/**
+ * ntfs_lookup_attr - find an attribute in an ntfs inode
+ * @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)
+ * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only)
+ * @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 an attribute in an ntfs inode. On first search @ctx->ntfs_ino must
+ * be the base mft record and @ctx must have been obtained from a call to
+ * ntfs_get_attr_search_ctx().
+ *
+ * This function transparently handles attribute lists and @ctx is used to
+ * continue searches where they were left off at.
+ *
+ * After finishing with the attribute/mft record you need to call
+ * ntfs_release_attr_search_ctx() to cleanup the search context (unmapping any
+ * mapped extent inodes, etc).
+ *
+ * Return 0 if the search was successful and -1 if not, with errno set to the
+ * error code.
+ *
+ * On success, @ctx->attr is the found attribute and it is in mft record
+ * @ctx->mrec.
+ *
+ * On error, @ctx->attr is the attribute which collates just after the attribute
+ * being searched for, i.e. if one wants to add the attribute to the mft
+ * record this is the correct place to insert it into. @ctx->al_entry points to
+ * the position within @ctx->base_ntfs_ino->attr_list at which the new
+ * attribute's attribute list entry should be inserted.
+ *
+ * The following error codes are defined:
+ * ENOENT Attribute not found, not an error as such.
+ * EINVAL Invalid arguments.
+ * EIO I/O error or corrupt data structures found.
+ * ENOMEM Not enough memory to allocate necessary buffers.
+ */
+int ntfs_lookup_attr(const ATTR_TYPES type, const uchar_t *name,
+ const __u32 name_len, const IGNORE_CASE_BOOL ic,
+ const VCN lowest_vcn, const __u8 *val, const __u32 val_len,
+ ntfs_attr_search_ctx *ctx)
+{
+ ntfs_inode *base_ni;
+
+ if (!ctx || !ctx->mrec || !ctx->attr) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (ctx->base_ntfs_ino)
+ base_ni = ctx->base_ntfs_ino;
+ else
+ base_ni = ctx->ntfs_ino;
+ if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST)
+ return ntfs_find_attr(type, name, name_len, ic, val, val_len,
+ ctx);
+ return ntfs_find_external_attr(type, name, name_len, ic, lowest_vcn,
+ val, val_len, ctx);
+}
+
+/*
+ * Internal function:
+ *
* ntfs_init_attr_search_ctx - initialize an attribute search context
* @ctx: attribute search context to initialize
@@ -788,6 +1156,5 @@
} /* Attribute list. */
if (ctx->ntfs_ino != ctx->base_ntfs_ino)
- fprintf(stderr, __FUNCTION__ "(): FIXME: EEEEEK!\n");
- // unmap_mft_record(READ, ctx->ntfs_ino);
+ ntfs_close_inode(ctx->ntfs_ino);
ntfs_init_attr_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
return;
@@ -803,6 +1170,7 @@
* and return it. Return NULL on error with errno set to ENOMEM.
*
- * @ni can be NULL if the search context is only going to be used in
- * combination with find_attr().
+ * @ni can be NULL if the search context is only going to be used for searching
+ * for the attribute list attribute and for searches ignoring the contents of
+ * the attribute list attribute.
*
* If @ni is specified, @mrec can be NULL, in which case the mft record is
@@ -830,6 +1198,5 @@
{
if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino)
- fprintf(stderr, __FUNCTION__ "(): FIXME: EEEEEK!\n");
- //unmap_mft_record(READ, ctx->ntfs_ino);
+ ntfs_close_inode(ctx->ntfs_ino);
free(ctx);
return;
Index: attrib_RE.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib_RE.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -U2 -r1.3 -r1.4
--- attrib_RE.c 20 Apr 2002 01:53:02 -0000 1.3
+++ attrib_RE.c 20 Apr 2002 23:09:42 -0000 1.4
@@ -218,5 +218,5 @@
if (attr_pos < mrec || attr_pos > (char*)mrec + vol->mft_record_size)
goto file_corrupt;
- if (attr_pos->type == $END)
+ if (attr_pos->type == AT_END)
goto do_next_al_entry;
if (!attr_pos->length)
@@ -306,19 +306,19 @@
* which collate before the attribute list (i.e. $STANDARD_INFORMATION).
*/
- if (le32_to_cpu(a->type) > le32_to_cpu($ATTRIBUTE_LIST))
+ if (le32_to_cpu(a->type) > le32_to_cpu(AT_ATTRIBUTE_LIST))
goto no_attr_list;
do_next:
if (!a->length)
goto file_corrupt;
- if (a->type == $ATTRIBUTE_LIST)
+ if (a->type == AT_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))
+ if (le32_to_cpu(a->type) <= le32_to_cpu(AT_ATTRIBUTE_LIST))
goto do_next;
no_attr_list:
- if (!type ||
- type == $STANDARD_INFORMATION && a->type == $STANDARD_INFORMATION)
+ if (!type || type == AT_STANDARD_INFORMATION &&
+ a->type == AT_STANDARD_INFORMATION)
goto found_it;
call_find_attr:
@@ -340,5 +340,5 @@
if (a < m || a > (char*)m + vol->mft_record_size)
goto file_corrupt;
- if (a->type == $END)
+ if (a->type == AT_END)
return FALSE;
if (!a->length)
@@ -355,5 +355,5 @@
if (!type)
goto search_attr_list;
- if (type == $ATTRIBUTE_LIST)
+ if (type == AT_ATTRIBUTE_LIST)
return TRUE;
search_attr_list:
Index: bootsect.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/bootsect.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -U2 -r1.6 -r1.7
--- bootsect.c 18 Apr 2002 18:15:46 -0000 1.6
+++ bootsect.c 20 Apr 2002 23:09:42 -0000 1.7
@@ -127,7 +127,7 @@
if (!silent)
printf("Checking clusters per index block... ");
- if ((__u8)b->clusters_per_index_block < 0xe1 ||
- (__u8)b->clusters_per_index_block > 0xf7) {
- switch (b->clusters_per_index_block) {
+ if ((__u8)b->clusters_per_index_record < 0xe1 ||
+ (__u8)b->clusters_per_index_record > 0xf7) {
+ switch (b->clusters_per_index_record) {
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
break;
Index: inode.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/inode.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -U2 -r1.4 -r1.5
--- inode.c 20 Apr 2002 01:53:02 -0000 1.4
+++ inode.c 20 Apr 2002 23:09:42 -0000 1.5
@@ -23,4 +23,5 @@
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
@@ -44,4 +45,6 @@
static __inline__ int __release_ntfs_inode(ntfs_inode *ni)
{
+ if (NInoDirty(ni))
+ Dputs("Eeek. Discarding dirty inode!");
if (NInoAttrList(ni) && ni->attr_list)
free(ni->attr_list);
@@ -76,6 +79,6 @@
* ntfs_inode structure (->attr_list_rl).
*
- * Return the ntfs_inode structure on success or NULL on error, with errno set
- * to the error code.
+ * Return a pointer to the ntfs_inode structure on success or NULL on error,
+ * with errno set ...
[truncated message content] |