diff --git a/include/ntfs-3g/attrib.h b/include/ntfs-3g/attrib.h index a11f7b6b..aa40637c 100644 --- a/include/ntfs-3g/attrib.h +++ b/include/ntfs-3g/attrib.h @@ -281,8 +281,6 @@ extern runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn); extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, const s64 size); -extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, - const ATTR_TYPES type); extern int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type); int ntfs_attr_make_non_resident(ntfs_attr *na, diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index 43bd74bb..e876af67 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -74,6 +74,16 @@ ntfschar STREAM_SDS[] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'), const_cpu_to_le16('\0') }; +ntfschar TXF_DATA[] = { const_cpu_to_le16('$'), + const_cpu_to_le16('T'), + const_cpu_to_le16('X'), + const_cpu_to_le16('F'), + const_cpu_to_le16('_'), + const_cpu_to_le16('D'), + const_cpu_to_le16('A'), + const_cpu_to_le16('T'), + const_cpu_to_le16('A') }; + static int NAttrFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) { if (na->type == AT_DATA && na->name == AT_UNNAMED) @@ -3014,16 +3024,30 @@ int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, * ENOENT - The attribute @type is not specified in $AttrDef. * EINVAL - Invalid parameters (e.g. @vol is not valid). */ -int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type) +static int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type, + const ntfschar *name, int namelen) { ATTR_DEF *ad; + BOOL allowed; - /* Find the attribute definition record in $AttrDef. */ - ad = ntfs_attr_find_in_attrdef(vol, type); - if (!ad) - return -1; - /* Check the flags and return the result. */ - if (ad->flags & ATTR_DEF_RESIDENT) { + /* + * hard-coded rule for $TXF_DATA + * see http://support.microsoft.com/kb/974729 + */ + if ((type == AT_LOGGED_UTILITY_STREAM) + && (namelen == 9) + && name + && !memcmp(name,TXF_DATA,18)) + allowed = FALSE; + else { + /* Find the attribute definition record in $AttrDef. */ + ad = ntfs_attr_find_in_attrdef(vol, type); + if (!ad) + return -1; + /* Check the flags and return the result. */ + allowed = !(ad->flags & ATTR_DEF_RESIDENT); + } + if (!allowed) { errno = EPERM; ntfs_log_trace("Attribute can't be non-resident\n"); return -1; @@ -3291,7 +3315,7 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, return -1; } - if (ntfs_attr_can_be_non_resident(ni->vol, type)) { + if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) { if (errno == EPERM) ntfs_log_perror("Attribute can't be non resident"); else @@ -3586,7 +3610,7 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, } /* Sanity checks for always resident attributes. */ - if (ntfs_attr_can_be_non_resident(ni->vol, type)) { + if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) { if (errno != EPERM) { err = errno; ntfs_log_perror("ntfs_attr_can_be_non_resident failed"); @@ -4138,6 +4162,7 @@ int ntfs_attr_make_non_resident(ntfs_attr *na, ntfs_volume *vol = na->ni->vol; ATTR_REC *a = ctx->attr; runlist *rl; + const ntfschar *name; int mp_size, mp_ofs, name_ofs, arec_size, err; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long @@ -4152,7 +4177,8 @@ int ntfs_attr_make_non_resident(ntfs_attr *na, } /* Check that the attribute is allowed to be non-resident. */ - if (ntfs_attr_can_be_non_resident(vol, na->type)) + name = (const ntfschar*)((const char*)a + le16_to_cpu(a->name_offset)); + if (ntfs_attr_can_be_non_resident(vol, na->type, name, a->name_length)) return -1; new_allocated_size = (le32_to_cpu(a->value_length) + vol->cluster_size