patch-2.4.10 linux/fs/ntfs/attr.c

Next file: linux/fs/ntfs/attr.h
Previous file: linux/fs/ntfs/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/attr.c linux/fs/ntfs/attr.c
@@ -13,6 +13,7 @@
 #include "attr.h"
 
 #include <linux/errno.h>
+#include <linux/ntfs_fs.h>
 #include "macros.h"
 #include "support.h"
 #include "util.h"
@@ -148,7 +149,10 @@
 					"attribute non-resident. Bug!\n");
 				return -EINVAL;
 			}
-			m = memcmp(value, a->d.data, min(int, value_len, a->size));
+			m = value_len;
+			if (m > a->size)
+				m = a->size;
+			m = memcmp(value, a->d.data, m);
 			if (m > 0)
 				continue;
 			if (m < 0) {
@@ -234,7 +238,7 @@
 		}
 		if (attr->d.r.runlist) {
 			ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
-							* sizeof(ntfs_runlist));
+					* sizeof(ntfs_runlist));
 			ntfs_vfree(attr->d.r.runlist);
 		}
 		attr->d.r.runlist = new;
@@ -243,82 +247,97 @@
 		ntfs_memmove(attr->d.r.runlist + cnum + 1,
 			     attr->d.r.runlist + cnum,
 			     (attr->d.r.len - cnum) * sizeof(ntfs_runlist));
-	attr->d.r.runlist[cnum].cluster = cluster;
+	attr->d.r.runlist[cnum].lcn = cluster;
 	attr->d.r.runlist[cnum].len = len;
 	attr->d.r.len++;
 	return 0;
 }
 
-/* Extends an attribute. Another run will be added if necessary, but we try to
- * extend the last run in the runlist first.
- * FIXME: what if there isn't enough contiguous space, we don't create
- * multiple runs?
+/**
+ * ntfs_extend_attr - extend allocated size of an attribute
+ * @ino:	ntfs inode containing the attribute to extend
+ * @attr:	attribute which to extend
+ * @len:	desired new length for @attr (_not_ the amount to extend by)
+ *
+ * Extends an attribute. Allocate clusters on the volume which @ino belongs to.
+ * Extends the run list accordingly, preferably by extending the last run of
+ * the existing run list, first.
  *
- * *len: the desired new length of the attr (_not_ the amount to extend by)
+ * Only modifies attr->allocated, i.e. doesn't touch attr->size, nor
+ * attr->initialized.
  */
-int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 *len, int flags)
+int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, const __s64 len)
 {
-	int error = 0;
-	ntfs_runlist *rl;
-	int rlen;
-	ntfs_cluster_t cluster;
-	int clen;
+	int rlen, rl2_len, err = 0;
+	ntfs_cluster_t cluster, clen;
+	ntfs_runlist *rl, *rl2;
 
-	if (attr->compressed || ino->record_count > 1)
+	if ((attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)) ||
+			ino->record_count > 1)
 		return -EOPNOTSUPP;
+	/*
+	 * FIXME: Don't make non-resident if the attribute type is not right.
+	 * For example cannot make index attribute non-resident! (AIA)
+	 */
 	if (attr->resident) {
-		error = ntfs_make_attr_nonresident(ino, attr);
-		if (error)
-			return error;
+		err = ntfs_make_attr_nonresident(ino, attr);
+		if (err)
+			return err;
 	}
-	if (*len <= attr->allocated)
-		return 0;	/* Truely stupid things do sometimes happen. */
+	if (len <= attr->allocated)
+		return 0;	/* Truly stupid things do sometimes happen. */
 	rl = attr->d.r.runlist;
-	rlen = attr->d.r.len - 1;
-	if (rlen >= 0)
-		cluster = rl[rlen].cluster + rl[rlen].len;
+	rlen = attr->d.r.len;
+	if (rlen > 0)
+		cluster = rl[rlen - 1].lcn + rl[rlen - 1].len;
 	else
 		/* No preference for allocation space. */
-		cluster = 0;
-	/* Calculate the extra space we need, and round up to multiple of
-	 * cluster size to get number of new clusters needed */
-	clen = ((*len - attr->allocated) + ino->vol->cluster_size - 1) >>
-						ino->vol->cluster_size_bits;
-	if (clen == 0)
+		cluster = (ntfs_cluster_t)-1;
+	/*
+	 * Calculate the extra space we need, and round up to multiple of
+	 * cluster size to get number of new clusters needed.
+	 */
+	clen = (len - attr->allocated + ino->vol->cluster_size - 1) >>
+			ino->vol->cluster_size_bits;
+	if (!clen)
 		return 0;
-	/* FIXME: try to allocate smaller pieces */
-	error = ntfs_allocate_clusters(ino->vol, &cluster, &clen,
-				       flags | ALLOC_REQUIRE_SIZE);
-	if (error)
-		return error;
+	err = ntfs_allocate_clusters(ino->vol, &cluster, &clen, &rl2,
+			&rl2_len, DATA_ZONE);
+	if (err)
+		return err;
 	attr->allocated += (__s64)clen << ino->vol->cluster_size_bits;
-	*len = attr->allocated;
-	/* Contiguous chunk. */
-	if (rlen >= 0 && cluster == rl[rlen].cluster + rl[rlen].len) {
-		rl[rlen].len += clen;
-		return 0;
+	if (rlen > 0) {
+		err = splice_runlists(&rl, &rlen, rl2, rl2_len);
+		ntfs_vfree(rl2);
+		if (err)
+			return err;
+	} else {
+		if (rl)
+			ntfs_vfree(rl);
+		rl = rl2;
+		rlen = rl2_len;
 	}
-	/*
-	 * FIXME: if ntfs_insert_run fails we need to deallocate the cluster
-	 * to revert to state before we were called...
-	 */
-	ntfs_insert_run(attr, rlen + 1, cluster, clen);
+	attr->d.r.runlist = rl;
+	attr->d.r.len = rlen;
 	return 0;
 }
 
 int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
 {
-	void *data = attr->d.data;
-	__s64 len = attr->size;
 	int error;
-	__s64 alen;
 	ntfs_io io;
+	void *data = attr->d.data;
+	__s64 len = attr->size;
+
 	attr->d.r.len = 0;
-	attr->d.r.runlist = 0;
+	attr->d.r.runlist = NULL;
 	attr->resident = 0;
+	/*
+	 * ->allocated is updated by ntfs_extend_attr(), while ->initialized
+	 * and ->size are updated by ntfs_readwrite_attr(). (AIA)
+	 */
 	attr->allocated = attr->initialized = 0;
-	alen = len;
-	error = ntfs_extend_attr(ino, attr, &alen, ALLOC_REQUIRE_SIZE);
+	error = ntfs_extend_attr(ino, attr, len);
 	if (error)
 		return error; /* FIXME: On error, restore old values. */
 	io.fn_put = ntfs_put;
@@ -344,21 +363,22 @@
 	return error;
 }
 
-/* Resize the attribute to a newsize. */
+/*
+ * Resize the attribute to a newsize. attr->allocated and attr->size are
+ * updated, but attr->initialized is not changed unless it becomes bigger than
+ * attr->size, in which case it is set to attr->size.
+ */
 int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize)
 {
 	int error = 0;
 	__s64 oldsize = attr->size;
 	int clustersizebits = ino->vol->cluster_size_bits;
 	int i, count, newcount;
-	ntfs_runlist *rl;
-	__s64 newlen;
+	ntfs_runlist *rl, *rlt;
 
 	if (newsize == oldsize)
 		return 0;
-	/* FIXME: Modifying compressed attributes not supported yet. */
-	if (attr->compressed)
-		/* FIXME: Extending is easy: just insert sparse runs. */
+	if (attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED))
 		return -EOPNOTSUPP;
 	if (attr->resident) {
 		void *v;
@@ -370,16 +390,18 @@
 		}
 		v = attr->d.data;
 		if (newsize) {
+			__s64 minsize = newsize;
 			attr->d.data = ntfs_malloc(newsize);
 			if (!attr->d.data) {
 				ntfs_free(v);
 				return -ENOMEM;
 			}
-			if (newsize > oldsize)
+			if (newsize > oldsize) {
+				minsize = oldsize;
 				ntfs_bzero((char*)attr->d.data + oldsize,
 					   newsize - oldsize);
-			ntfs_memcpy((char*)attr->d.data, v,
-				    min(s64, newsize, oldsize));
+			}
+			ntfs_memcpy((char*)attr->d.data, v, minsize);
 		} else
 			attr->d.data = 0;
 		ntfs_free(v);
@@ -389,59 +411,79 @@
 	/* Non-resident attribute. */
 	rl = attr->d.r.runlist;
 	if (newsize < oldsize) {
+		int rl_size;
+		/*
+		 * FIXME: We might be going awfully wrong for newsize = 0,
+		 * possibly even leaking memory really badly. But considering
+		 * in that case there is more breakage due to -EOPNOTSUPP stuff
+		 * further down the code path, who cares for the moment... (AIA)
+		 */
 		for (i = 0, count = 0; i < attr->d.r.len; i++) {
 			if ((__s64)(count + rl[i].len) << clustersizebits >
-									newsize)
+					newsize) {
+				i++;
 				break;
+			}
 			count += (int)rl[i].len;
 		}
-		newlen = i + 1;
-		/* Free unused clusters in current run, unless sparse. */
 		newcount = count;
-		if (rl[i].cluster != (ntfs_cluster_t)-1) {
-			int rounded = newsize - ((__s64)count <<
-							clustersizebits);
+		/* Free unused clusters in current run, unless sparse. */
+		if (rl[--i].lcn != (ntfs_cluster_t)-1) {
+			ntfs_cluster_t rounded = newsize - ((__s64)count <<
+					clustersizebits);
 			rounded = (rounded + ino->vol->cluster_size - 1) >>
-								clustersizebits;
-			error = ntfs_deallocate_clusters(ino->vol, 
-						rl[i].cluster + rounded,
-						(int)rl[i].len - rounded);
+					clustersizebits;
+			error = ntfs_deallocate_cluster_run(ino->vol, 
+					rl[i].lcn + rounded,
+					rl[i].len - rounded);
 			if (error)
 				return error; /* FIXME: Incomplete operation. */
 			rl[i].len = rounded;
 			newcount = count + rounded;
 		}
 		/* Free all other runs. */
-		for (i++; i < attr->d.r.len; i++)
-			if (rl[i].cluster != (ntfs_cluster_t)-1) {
-				error = ntfs_deallocate_clusters(ino->vol,
-								rl[i].cluster,
-								(int)rl[i].len);
-				if (error)
-					return error; /* FIXME: Incomplete 
-						       * operation */
+		i++;
+		error = ntfs_deallocate_clusters(ino->vol, rl + i,
+				attr->d.r.len - i);
+		if (error)
+			return error; /* FIXME: Incomplete operation. */
+		/*
+		 * Free space for extra runs in memory if enough memory left
+		 * to do so. FIXME: Only do it if it would free memory. (AIA)
+		 */
+		rl_size = ((i + 1) * sizeof(ntfs_runlist) + PAGE_SIZE - 1) &
+				PAGE_MASK;
+		if (rl_size < ((attr->d.r.len * sizeof(ntfs_runlist) +
+				PAGE_SIZE - 1) & PAGE_MASK)) {
+			rlt = ntfs_vmalloc(rl_size);
+			if (rlt) {
+				ntfs_memcpy(rlt, rl, i * sizeof(ntfs_runlist));
+				ntfs_vfree(rl);
+				attr->d.r.runlist = rl = rlt;
 			}
-		/* FIXME: Free space for extra runs in memory? */
-		attr->d.r.len = newlen;
+		}
+		rl[i].lcn = (ntfs_cluster_t)-1;
+		rl[i].len = (ntfs_cluster_t)0;
+		attr->d.r.len = i;
 	} else {
-		newlen = newsize;
-		error = ntfs_extend_attr(ino, attr, &newlen,
-					 ALLOC_REQUIRE_SIZE);
+		error = ntfs_extend_attr(ino, attr, newsize);
 		if (error)
 			return error; /* FIXME: Incomplete operation. */
-		newcount = newlen >> clustersizebits;
+		newcount = (newsize + ino->vol->cluster_size - 1) >>
+				clustersizebits;
 	}
 	/* Fill in new sizes. */
 	attr->allocated = (__s64)newcount << clustersizebits;
 	attr->size = newsize;
-	/* attr->initialized does not change. */
+	if (attr->initialized > newsize)
+		attr->initialized = newsize;
 	if (!newsize)
 		error = ntfs_make_attr_resident(ino, attr);
 	return error;
 }
 
 int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
-		     int dsize, ntfs_attribute **rattr)
+		int dsize, ntfs_attribute **rattr)
 {
 	void *name;
 	int namelen;
@@ -463,7 +505,7 @@
 		namelen = 0;
 	}
 	error = ntfs_new_attr(ino, anum, name, namelen, data, dsize, &i,
-									&found);
+			&found);
 	if (error || found) {
 		ntfs_free(name);
 		return error ? error : -EEXIST;
@@ -481,7 +523,8 @@
 				"+ 0x28) (%i)\n", attr->attrno,
 				NTFS_GETU16(ino->attr + 0x28));
 	attr->resident = 1;
-	attr->compressed = attr->cengine = 0;
+	attr->flags = 0;
+	attr->cengine = 0;
 	attr->size = attr->allocated = attr->initialized = dsize;
 
 	/* FIXME: INDEXED information should come from $AttrDef
@@ -498,7 +541,8 @@
 	return 0;
 }
 
-/* Non-resident attributes are stored in runs (intervals of clusters).
+/*
+ * Non-resident attributes are stored in runs (intervals of clusters).
  *
  * This function stores in the inode readable information about a non-resident
  * attribute.
@@ -520,7 +564,7 @@
 	 * base mft record contains the last extent instead of the first one
 	 * and the first extent is stored, like any intermediate extents in
 	 * extension mft records. This would be difficult to allow the way the
-	 * run list is stored in memory. Thus we fix else where by causing the
+	 * runlist is stored in memory. Thus we fix elsewhere by causing the
 	 * attribute list attribute to be processed immediately when found. The
 	 * extents will then be processed starting with the first one. */
 	for (cnum = 0, vcn = 0; cnum < attr->d.r.len; cnum++)
@@ -534,7 +578,7 @@
 			ntfs_error("Problem with runlist in extended record\n");
 			return -1;
 		}
-		/* Tried to insert an already inserted run list. */
+		/* Tried to insert an already inserted runlist. */
 		return 0;
 	}
 	if (!endvcn) {
@@ -630,7 +674,7 @@
 	}
 	attr = ino->attrs + i;
 	attr->resident = NTFS_GETU8(attrdata + 8) == 0;
-	attr->compressed = NTFS_GETU16(attrdata + 0xC);
+	attr->flags = *(__u16*)(attrdata + 0xC);
 	attr->attrno = NTFS_GETU16(attrdata + 0xE);
   
 	if (attr->resident) {
@@ -640,13 +684,13 @@
 		if (!attr->d.data)
 			return -ENOMEM;
 		ntfs_memcpy(attr->d.data, data, attr->size);
-		attr->indexed = NTFS_GETU16(attrdata + 0x16);
+		attr->indexed = NTFS_GETU8(attrdata + 0x16);
 	} else {
 		attr->allocated = NTFS_GETS64(attrdata + 0x28);
 		attr->size = NTFS_GETS64(attrdata + 0x30);
 		attr->initialized = NTFS_GETS64(attrdata + 0x38);
 		attr->cengine = NTFS_GETU16(attrdata + 0x22);
-		if (attr->compressed)
+		if (attr->flags & ATTR_IS_COMPRESSED)
 			attr->compsize = NTFS_GETS64(attrdata + 0x40);
 		ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: "
 			"attr->allocated = 0x%Lx, attr->size = 0x%Lx, "
@@ -664,11 +708,14 @@
 
 int ntfs_read_zero(ntfs_io *dest, int size)
 {
+	int i;
 	char *sparse = ntfs_calloc(512);
 	if (!sparse)
 		return -ENOMEM;
+	i = 512;
 	while (size) {
-		int i = min(int, size, 512);
+		if (i > size)
+			i = size;
 		dest->fn_put(dest, sparse, i);
 		size -= i;
 	}
@@ -683,7 +730,7 @@
 	int error = 0;
 	int clustersizebits;
 	int s_vcn, rnum, vcn, got, l1;
-	__s64 copied, len, chunk, offs1, l;
+	__s64 copied, len, chunk, offs1, l, chunk2;
 	ntfs_cluster_t cluster, cl1;
 	char *comp = 0, *comp1;
 	char *decomp = 0;
@@ -713,19 +760,22 @@
 	io.do_read = 1;
 	io.fn_put = ntfs_put;
 	io.fn_get = 0;
-	cluster = rl->cluster;
+	cluster = rl->lcn;
 	len = rl->len;
 	copied = 0;
 	while (l) {
 		chunk = 0;
 		if (cluster == (ntfs_cluster_t)-1) {
 			/* Sparse cluster. */
-			__s64 l1;
+			__s64 ll;
+
 			if ((len - (s_vcn - vcn)) & 15)
 				ntfs_error("Unexpected sparse chunk size.");
-			l1 = chunk = min(s64, ((__s64)(vcn + len) << clustersizebits)
-								- offset, l);
-			error = ntfs_read_zero(dest, l1);
+			ll = ((__s64)(vcn + len) << clustersizebits) - offset;
+			if (ll > l)
+				ll = l;
+			chunk = ll;
+			error = ntfs_read_zero(dest, ll);
 			if (error)
 				goto out;
 		} else if (dest->do_read) {
@@ -741,18 +791,25 @@
 			cl1 = cluster + s_vcn - vcn;
 			comp1 = comp;
 			do {
+				int delta;
+
 				io.param = comp1;
-				l1 = min(int, len - max(int, s_vcn - vcn, 0), 16 - got);
+				delta = s_vcn - vcn;
+				if (delta < 0)
+					delta = 0;
+				l1 = len - delta;
+				if (l1 > 16 - got)
+					l1 = 16 - got;
 				io.size = (__s64)l1 << clustersizebits;
 				error = ntfs_getput_clusters(ino->vol, cl1, 0,
 					       		     &io);
 				if (error)
 					goto out;
-				if (l1 + max(int, s_vcn - vcn, 0) == len) {
+				if (l1 + delta == len) {
 					rnum++;
 					rl++;
 					vcn += len;
-					cluster = cl1 = rl->cluster;
+					cluster = cl1 = rl->lcn;
 					len = rl->len;
 				}
 				got += l1;
@@ -779,8 +836,11 @@
 				comp1 = decomp;
 			}
 			offs1 = offset - ((__s64)s_vcn << clustersizebits);
-			chunk = min(s64, (16 << clustersizebits) - offs1, chunk);
-			chunk = min(s64, l, chunk);
+			chunk2 = (16 << clustersizebits) - offs1;
+			if (chunk2 > l)
+				chunk2 = l;
+			if (chunk > chunk2)
+				chunk = chunk2;
 			dest->fn_put(dest, comp1 + offs1, chunk);
 		}
 		l -= chunk;
@@ -791,11 +851,11 @@
 			rnum++;
 			rl++;
 			vcn += len;
-			cluster = rl->cluster;
+			cluster = rl->lcn;
 			len = rl->len;
 		}
 	}
- out:
+out:
 	if (comp)
 		ntfs_free(comp);
 	if (decomp)
@@ -805,7 +865,7 @@
 }
 
 int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
-			  ntfs_io *dest)
+		ntfs_io *dest)
 {
 	return -EOPNOTSUPP;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)