diff --git a/include/ntfs-3g/attrib.h b/include/ntfs-3g/attrib.h index 4b76d90d..186c9931 100644 --- a/include/ntfs-3g/attrib.h +++ b/include/ntfs-3g/attrib.h @@ -200,7 +200,8 @@ typedef enum { NA_Initialized, /* 1: structure is initialized. */ NA_NonResident, /* 1: Attribute is not resident. */ NA_BeingNonResident, /* 1: Attribute is being made not resident. */ - NA_FullyMapped, /* 1: Attribute has beed fully mapped */ + NA_FullyMapped, /* 1: Attribute has been fully mapped */ + NA_ComprClosing, /* 1: Compressed attribute is being closed */ } ntfs_attr_state_bits; #define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state) @@ -223,6 +224,10 @@ typedef enum { #define NAttrSetFullyMapped(na) set_nattr_flag(na, FullyMapped) #define NAttrClearFullyMapped(na) clear_nattr_flag(na, FullyMapped) +#define NAttrComprClosing(na) test_nattr_flag(na, ComprClosing) +#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing) +#define NAttrClearComprClosing(na) clear_nattr_flag(na, ComprClosing) + #define GenNAttrIno(func_name, flag) \ extern int NAttr##func_name(ntfs_attr *na); \ extern void NAttrSet##func_name(ntfs_attr *na); \ diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index ab707467..50a7ac6d 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -2127,6 +2127,7 @@ int ntfs_attr_pclose(ntfs_attr *na) if (!compressed || !NAttrNonResident(na)) goto out; + NAttrSetComprClosing(na); /* for safety checks */ /* * For a compressed attribute, we must be sure there are two * available entries, so reserve them before it gets too late. @@ -4518,6 +4519,13 @@ int ntfs_attr_make_non_resident(ntfs_attr *na, - 1) & ~(vol->cluster_size - 1); if (new_allocated_size > 0) { + if ((a->flags & ATTR_COMPRESSION_MASK) + == ATTR_IS_COMPRESSED) { + /* must allocate full compression blocks */ + new_allocated_size = ((new_allocated_size - 1) + | ((1L << (STANDARD_COMPRESSION_UNIT + + vol->cluster_size_bits)) - 1)) + 1; + } /* Start by allocating clusters to hold the attribute value. */ rl = ntfs_cluster_alloc(vol, 0, new_allocated_size >> vol->cluster_size_bits, -1, DATA_ZONE); @@ -4791,6 +4799,20 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize) ntfs_attr_close(tna); continue; } + if (((tna->data_flags & ATTR_COMPRESSION_MASK) + == ATTR_IS_COMPRESSED) + && (NAttrComprClosing(tna) || ntfs_attr_pclose(tna))) { + /* safety check : no recursion on close */ + if (NAttrComprClosing(tna)) { + err = EIO; + ntfs_log_error("Bad ntfs_attr_pclose" + " recursion on inode %lld\n", + (long long)tna->ni->mft_no); + } else + err = errno; + ntfs_attr_close(tna); + goto put_err_out; + } ntfs_inode_mark_dirty(tna->ni); ntfs_attr_close(tna); ntfs_attr_put_search_ctx(ctx);