Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67bb1037 authored by Anton Altaparmakov's avatar Anton Altaparmakov
Browse files

NTFS: Fixup handling of sparse, compressed, and encrypted attributes in


      fs/ntfs/inode.c::ntfs_read_locked_{,attr_,index_}inode().

Signed-off-by: default avatarAnton Altaparmakov <aia21@cantab.net>
parent 1c7d469d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -75,6 +75,8 @@ ToDo/Notes:
	  which leads to lock reversal.
	- Truncate {a,c,m}time to the ntfs supported time granularity when
	  updating the times in the inode in ntfs_setattr().
	- Fixup handling of sparse, compressed, and encrypted attributes in
	  fs/ntfs/inode.c::ntfs_read_locked_{,attr_,index_}inode().

2.1.23 - Implement extension of resident files and make writing safe as well as
	 many bug fixes, cleanups, and enhancements...
+114 −101
Original line number Diff line number Diff line
@@ -1013,10 +1013,7 @@ skip_large_dir_stuff:
		}
		a = ctx->attr;
		/* Setup the state. */
		if (a->non_resident) {
			NInoSetNonResident(ni);
			if (a->flags & (ATTR_COMPRESSION_MASK |
					ATTR_IS_SPARSE)) {
		if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
			if (a->flags & ATTR_COMPRESSION_MASK) {
				NInoSetCompressed(ni);
				if (vol->cluster_size > 4096) {
@@ -1031,21 +1028,33 @@ skip_large_dir_stuff:
				}
				if ((a->flags & ATTR_COMPRESSION_MASK)
						!= ATTR_IS_COMPRESSED) {
						ntfs_error(vi->i_sb, "Found "
							"unknown compression "
							"method or corrupt "
							"file.");
					ntfs_error(vi->i_sb, "Found unknown "
							"compression method "
							"or corrupt file.");
					goto unm_err_out;
				}
			}
			if (a->flags & ATTR_IS_SPARSE)
				NInoSetSparse(ni);
		}
		if (a->flags & ATTR_IS_ENCRYPTED) {
			if (NInoCompressed(ni)) {
				ntfs_error(vi->i_sb, "Found encrypted and "
						"compressed data.");
				goto unm_err_out;
			}
			NInoSetEncrypted(ni);
		}
		if (a->non_resident) {
			NInoSetNonResident(ni);
			if (NInoCompressed(ni) || NInoSparse(ni)) {
				if (a->data.non_resident.compression_unit !=
						4) {
					ntfs_error(vi->i_sb, "Found "
						"nonstandard compression unit "
						"(%u instead of 4).  Cannot "
						"handle this.",
							"nonstandard "
							"compression unit (%u "
							"instead of 4).  "
							"Cannot handle this.",
							a->data.non_resident.
							compression_unit);
					err = -EOPNOTSUPP;
@@ -1065,14 +1074,6 @@ skip_large_dir_stuff:
						a->data.non_resident.
						compressed_size);
			}
			if (a->flags & ATTR_IS_ENCRYPTED) {
				if (a->flags & ATTR_COMPRESSION_MASK) {
					ntfs_error(vi->i_sb, "Found encrypted "
							"and compressed data.");
					goto unm_err_out;
				}
				NInoSetEncrypted(ni);
			}
			if (a->data.non_resident.lowest_vcn) {
				ntfs_error(vi->i_sb, "First extent of $DATA "
						"attribute has non zero "
@@ -1212,6 +1213,75 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
	if (unlikely(err))
		goto unm_err_out;
	a = ctx->attr;
	if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
		if (a->flags & ATTR_COMPRESSION_MASK) {
			NInoSetCompressed(ni);
			if ((ni->type != AT_DATA) || (ni->type == AT_DATA &&
					ni->name_len)) {
				ntfs_error(vi->i_sb, "Found compressed "
						"non-data or named data "
						"attribute.  Please report "
						"you saw this message to "
						"linux-ntfs-dev@lists."
						"sourceforge.net");
				goto unm_err_out;
			}
			if (vol->cluster_size > 4096) {
				ntfs_error(vi->i_sb, "Found compressed "
						"attribute but compression is "
						"disabled due to cluster size "
						"(%i) > 4kiB.",
						vol->cluster_size);
				goto unm_err_out;
			}
			if ((a->flags & ATTR_COMPRESSION_MASK) !=
					ATTR_IS_COMPRESSED) {
				ntfs_error(vi->i_sb, "Found unknown "
						"compression method.");
				goto unm_err_out;
			}
		}
		/*
		 * The encryption flag set in an index root just means to
		 * compress all files.
		 */
		if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) {
			ntfs_error(vi->i_sb, "Found mst protected attribute "
					"but the attribute is %s.  Please "
					"report you saw this message to "
					"linux-ntfs-dev@lists.sourceforge.net",
					NInoCompressed(ni) ? "compressed" :
					"sparse");
			goto unm_err_out;
		}
		if (a->flags & ATTR_IS_SPARSE)
			NInoSetSparse(ni);
	}
	if (a->flags & ATTR_IS_ENCRYPTED) {
		if (NInoCompressed(ni)) {
			ntfs_error(vi->i_sb, "Found encrypted and compressed "
					"data.");
			goto unm_err_out;
		}
		/*
		 * The encryption flag set in an index root just means to
		 * encrypt all files.
		 */
		if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) {
			ntfs_error(vi->i_sb, "Found mst protected attribute "
					"but the attribute is encrypted.  "
					"Please report you saw this message "
					"to linux-ntfs-dev@lists.sourceforge."
					"net");
			goto unm_err_out;
		}
		if (ni->type != AT_DATA) {
			ntfs_error(vi->i_sb, "Found encrypted non-data "
					"attribute.");
			goto unm_err_out;
		}
		NInoSetEncrypted(ni);
	}
	if (!a->non_resident) {
		/* Ensure the attribute name is placed before the value. */
		if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
@@ -1220,11 +1290,10 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
					"the attribute value.");
			goto unm_err_out;
		}
		if (NInoMstProtected(ni) || a->flags) {
		if (NInoMstProtected(ni)) {
			ntfs_error(vi->i_sb, "Found mst protected attribute "
					"or attribute with non-zero flags but "
					"the attribute is resident.  Please "
					"report you saw this message to "
					"but the attribute is resident.  "
					"Please report you saw this message to "
					"linux-ntfs-dev@lists.sourceforge.net");
			goto unm_err_out;
		}
@@ -1250,50 +1319,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
					"the mapping pairs array.");
			goto unm_err_out;
		}
		if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
			if (a->flags & ATTR_COMPRESSION_MASK) {
				NInoSetCompressed(ni);
				if ((ni->type != AT_DATA) || (ni->type ==
						AT_DATA && ni->name_len)) {
					ntfs_error(vi->i_sb, "Found compressed "
							"non-data or named "
							"data attribute.  "
							"Please report you "
							"saw this message to "
							"linux-ntfs-dev@lists."
							"sourceforge.net");
					goto unm_err_out;
				}
				if (vol->cluster_size > 4096) {
					ntfs_error(vi->i_sb, "Found compressed "
							"attribute but "
							"compression is "
							"disabled due to "
							"cluster size (%i) > "
							"4kiB.",
							vol->cluster_size);
					goto unm_err_out;
				}
				if ((a->flags & ATTR_COMPRESSION_MASK) !=
						ATTR_IS_COMPRESSED) {
					ntfs_error(vi->i_sb, "Found unknown "
							"compression method.");
					goto unm_err_out;
				}
			}
			if (NInoMstProtected(ni)) {
				ntfs_error(vi->i_sb, "Found mst protected "
						"attribute but the attribute "
						"is %s.  Please report you "
						"saw this message to "
						"linux-ntfs-dev@lists."
						"sourceforge.net",
						NInoCompressed(ni) ?
						"compressed" : "sparse");
				goto unm_err_out;
			}
			if (a->flags & ATTR_IS_SPARSE)
				NInoSetSparse(ni);
		if ((NInoCompressed(ni) || NInoSparse(ni)) &&
				ni->type != AT_INDEX_ROOT) {
			if (a->data.non_resident.compression_unit != 4) {
				ntfs_error(vi->i_sb, "Found nonstandard "
						"compression unit (%u instead "
@@ -1313,23 +1340,6 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
			ni->itype.compressed.size = sle64_to_cpu(
					a->data.non_resident.compressed_size);
		}
		if (a->flags & ATTR_IS_ENCRYPTED) {
			if (a->flags & ATTR_COMPRESSION_MASK) {
				ntfs_error(vi->i_sb, "Found encrypted and "
						"compressed data.");
				goto unm_err_out;
			}
			if (NInoMstProtected(ni)) {
				ntfs_error(vi->i_sb, "Found mst protected "
						"attribute but the attribute "
						"is encrypted.  Please report "
						"you saw this message to "
						"linux-ntfs-dev@lists."
						"sourceforge.net");
				goto unm_err_out;
			}
			NInoSetEncrypted(ni);
		}
		if (a->data.non_resident.lowest_vcn) {
			ntfs_error(vi->i_sb, "First extent of attribute has "
					"non-zero lowest_vcn.");
@@ -1348,12 +1358,12 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
		vi->i_mapping->a_ops = &ntfs_mst_aops;
	else
		vi->i_mapping->a_ops = &ntfs_aops;
	if (NInoCompressed(ni) || NInoSparse(ni))
	if ((NInoCompressed(ni) || NInoSparse(ni)) && ni->type != AT_INDEX_ROOT)
		vi->i_blocks = ni->itype.compressed.size >> 9;
	else
		vi->i_blocks = ni->allocated_size >> 9;
	/*
	 * Make sure the base inode doesn't go away and attach it to the
	 * Make sure the base inode does not go away and attach it to the
	 * attribute inode.
	 */
	igrab(base_vi);
@@ -1480,7 +1490,10 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
				"after the attribute value.");
		goto unm_err_out;
	}
	/* Compressed/encrypted/sparse index root is not allowed. */
	/*
	 * Compressed/encrypted/sparse index root is not allowed, except for
	 * directories of course but those are not dealt with here.
	 */
	if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED |
			ATTR_IS_SPARSE)) {
		ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index "