diff --git a/include/ntfs-3g/attrib.h b/include/ntfs-3g/attrib.h index a11f7b6b..bcdb0117 100644 --- a/include/ntfs-3g/attrib.h +++ b/include/ntfs-3g/attrib.h @@ -39,6 +39,9 @@ typedef struct _ntfs_attr_search_ctx ntfs_attr_search_ctx; extern ntfschar AT_UNNAMED[]; extern ntfschar STREAM_SDS[]; +/* The little endian Unicode string $TXF_DATA as a global constant. */ +extern ntfschar TXF_DATA[10]; + /** * enum ntfs_lcn_special_values - special return values for ntfs_*_vcn_to_lcn() * @@ -281,8 +284,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 bf21544c..76cdcb0c 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -1,11 +1,12 @@ /** * attrib.c - Attribute handling code. Originated from the Linux-NTFS project. * - * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2000-2010 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2002-2008 Szabolcs Szakacsits * Copyright (c) 2004-2007 Yura Pakhuchiy - * Copyright (c) 2007-2009 Jean-Pierre Andre + * Copyright (c) 2007-2010 Jean-Pierre Andre + * Copyright (c) 2010 Erik Larsson * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -69,6 +70,17 @@ 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'), + const_cpu_to_le16('\0') }; + static int NAttrFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) { if (na->type == AT_DATA && na->name == AT_UNNAMED) @@ -3008,10 +3020,14 @@ int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, /** * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident * @vol: ntfs volume to which the attribute belongs - * @type: attribute type which to check + * @type: attribute type to check + * @name: attribute name to check + * @name_len: attribute name length * - * Check whether the attribute of @type on the ntfs volume @vol is allowed to - * be non-resident. This information is obtained from $AttrDef system file. + * Check whether the attribute of @type and @name with name length @name_len on + * the ntfs volume @vol is allowed to be non-resident. This information is + * obtained from $AttrDef system file and is augmented by rules imposed by + * Microsoft (e.g. see http://support.microsoft.com/kb/974729/). * * Return 0 if the attribute is allowed to be non-resident and -1 if not or an * error occurred. On error the error code is stored in errno. The following @@ -3020,16 +3036,34 @@ 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 name_len) { 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) { + /* + * Microsoft has decreed that $LOGGED_UTILITY_STREAM attributes with a + * name of $TXF_DATA must be resident despite the entry for + * $LOGGED_UTILITY_STREAM in $AttrDef allowing them to be non-resident. + * Failure to obey this on the root directory mft record of a volume + * causes Windows Vista and later to see the volume as a RAW volume and + * thus cannot mount it at all. + */ + if ((type == AT_LOGGED_UTILITY_STREAM) + && name + && ntfs_names_are_equal(TXF_DATA, 9, name, name_len, + CASE_SENSITIVE, vol->upcase, vol->upcase_len)) + 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; @@ -3294,7 +3328,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 @@ -3589,7 +3623,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"); @@ -4154,7 +4188,7 @@ 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)) + if (ntfs_attr_can_be_non_resident(vol, na->type, na->name, na->name_len)) return -1; new_allocated_size = (le32_to_cpu(a->value_length) + vol->cluster_size