patch-2.4.7 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.6/linux/fs/ntfs/attr.c linux/fs/ntfs/attr.c
@@ -1,10 +1,11 @@
-/*  attr.c
+/*
+ * attr.c
  *
- *  Copyright (C) 1996-1999 Martin von Löwis
- *  Copyright (C) 1996-1997 Régis Duchesne
- *  Copyright (C) 1998 Joseph Malicki
- *  Copyright (C) 1999 Steve Dodd
- *  Copyright (C) 2001 Anton Altaparmakov (AIA)
+ * Copyright (C) 1996-1999 Martin von Löwis
+ * Copyright (C) 1996-1997 Régis Duchesne
+ * Copyright (C) 1998 Joseph Malicki
+ * Copyright (C) 1999 Steve Dodd
+ * Copyright (C) 2001 Anton Altaparmakov (AIA)
  */
 
 #include "ntfstypes.h"
@@ -17,37 +18,156 @@
 #include "util.h"
 #include "super.h"
 #include "inode.h"
+#include "unistr.h"
+
+/**
+ * ntfs_find_attr_in_mft_rec - find attribute in mft record
+ * @vol:	volume on which attr resides
+ * @m:		mft record to search
+ * @type:	attribute type to find
+ * @name:	attribute name to find (optional, i.e. NULL means don't care)
+ * @name_len:	attribute name length (only needed if @name present)
+ * @ic:		ignore case if 1 or case sensitive if 0 (ignored if @name NULL)
+ * @instance:	instance number to find
+ *
+ * Only search the specified mft record and it ignores the presence of an
+ * attribute list attribute (unless it is the one being searched for,
+ * obviously, in which case it is returned).
+ */
+ntfs_u8* ntfs_find_attr_in_mft_rec(ntfs_volume *vol, ntfs_u8 *m, __u32 type,
+		wchar_t *name, __u32 name_len, int ic, __u16 instance)
+{
+	ntfs_u8 *a;
+	
+	/* Iterate over attributes in mft record @m. */
+	a = m + NTFS_GETU16(m + 20);	/* attrs_offset */
+	for (; a >= m && a <= m + vol->mft_record_size;
+				a += NTFS_GETU32(a + 4 /* length */)) {
+		/* We catch $END with this more general check, too... */
+		if (NTFS_GETU32(a + 0 /* type */) > type)
+			return NULL;
+		if (!NTFS_GETU32(a + 4 /* length */))
+			break;
+		if (NTFS_GETU32(a + 0 /* type */) != type)
+			continue;
+		/* If @name is present, compare the two names. */
+		if (name && !ntfs_are_names_equal(name, name_len, (wchar_t*)
+				(a + NTFS_GETU16(a + 10 /* name_offset */)),
+				a[9] /* name_length */, ic, vol->upcase,
+				vol->upcase_length)) {
+			register int rc;
+			
+			rc = ntfs_collate_names(vol->upcase, vol->upcase_length,
+					name, name_len, (wchar_t*)(a +
+					NTFS_GETU16(a + 10 /* name_offset */)),
+					a[9] /* name_length */, 1, 1);
+			/*
+			 * If @name collates before a->name, there is no
+			 * matching attribute.
+			 */
+			if (rc == -1)
+				return NULL;
+			/* If the strings are not equal, continue search. */
+			if (rc)
+	 			continue;
+			rc = ntfs_collate_names(vol->upcase, vol->upcase_length,
+					name, name_len, (wchar_t*)(a +
+					NTFS_GETU16(a + 10 /* name_offset */)),
+					a[9] /* name_length */, 0, 1);
+			if (rc == -1)
+				return NULL;
+			if (rc)
+				continue;
+		}
+		/*
+		 * The names match or @name not present. Check instance number.
+		 * and if it matches we have found the attribute and are done.
+		 */
+		if (instance != NTFS_GETU16(a + 14 /* instance */))
+			continue;
+		ntfs_debug(DEBUG_FILE3, "ntfs_find_attr_in_mft_record: found: "
+			"attr type 0x%x, instance number = 0x%x.\n",
+			NTFS_GETU32(a + 0), instance);
+		return a;
+	}
+	ntfs_error("ntfs_find_attr_in_mft_record: mft record 0x%x is corrupt"
+			". Run chkdsk.\n", m);
+	return NULL;
+}
 
 /* Look if an attribute already exists in the inode, and if not, create it. */
-int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen, int *pos,
-		  int *found, int do_search)
+int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen,
+		  void *value, int value_len, int *pos, int *found)
 {
 	int do_insert = 0;
-	int i;
+	int i, m;
+	ntfs_attribute *a;
 
 	for (i = 0; i < ino->attr_count; i++)
 	{
-		int n = min(namelen, ino->attrs[i].namelen);
-		int s = ntfs_uni_strncmp(ino->attrs[i].name, name, n);
-		if (do_search) {
-			/* We assume that each attribute can be uniquely 
-			 * identified by inode number, attribute type and
-			 * attribute name. */
-			if (ino->attrs[i].type == type && 
-			    ino->attrs[i].namelen == namelen && !s) {
-				*found = 1;
-				*pos = i;
-				return 0;
-			}
-		}
-		/* Attributes are ordered by type, then by name. */
-		if (ino->attrs[i].type > type || 
-		    (ino->attrs[i].type == type && s == 1)) {
+		a = ino->attrs + i;
+		if (a->type < type)
+			continue;
+		if (a->type > type) {
 			do_insert = 1;
 			break;
 		}
+		/* If @name is present, compare the two names. */
+		if (namelen && !ntfs_are_names_equal((wchar_t*)name, namelen,
+				a->name, a->namelen /* name_length */,
+				1 /* ignore case*/, ino->vol->upcase,
+				ino->vol->upcase_length)) {
+			register int rc;
+
+			rc = ntfs_collate_names(ino->vol->upcase,
+					ino->vol->upcase_length, a->name,
+					a->namelen, (wchar_t*)name, namelen,
+					1 /* ignore case */, 1);
+			if (rc == -1)
+				continue;
+			if (rc == 1) {
+	 			do_insert = 1;
+				break;
+			}
+			rc = ntfs_collate_names(ino->vol->upcase,
+					ino->vol->upcase_length, a->name,
+					a->namelen, (wchar_t*)name, namelen,
+					0 /* case sensitive */, 1);
+			if (rc == -1)
+				continue;
+			if (rc == 1) {
+				do_insert = 1;
+				break;
+			}
+		}
+		/* Names are equal or no name was asked for. */
+		/* If a value was specified compare the values. */
+		if (value_len && a->resident) {
+			if (!a->resident) {
+				ntfs_error("ntfs_new_attr: Value specified but "
+					"attribute non-resident. Bug!\n");
+				return -EINVAL;
+			}
+			m = memcmp(value, a->d.data, min(value_len, a->size));
+			if (m > 0)
+				continue;
+			if (m < 0) {
+				do_insert = 1;
+				break;
+			}
+			/* Values match until min of value lengths. */
+			if (value_len > a->size)
+				continue;
+			if (value_len < a->size) {
+				do_insert = 1;
+				break;
+			}
+		}
+		/* Full match! */
+		*found = 1;
+		*pos = i;
+		return 0;
 	}
-
 	/* Re-allocate space. */
 	if (ino->attr_count % 8 == 0)
 	{
@@ -77,7 +197,7 @@
 
 int ntfs_make_attr_resident(ntfs_inode *ino, ntfs_attribute *attr)
 {
-	int size = attr->size;
+	__s64 size = attr->size;
 	if (size > 0) {
 		/* FIXME: read data, free clusters */
 		return -EOPNOTSUPP;
@@ -87,19 +207,35 @@
 }
 
 /* Store in the inode readable information about a run. */
-void ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
+int ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster,
 		     int len)
 {
 	/* (re-)allocate space if necessary. */
-	if (attr->d.r.len % 8 == 0) {
+	if ((attr->d.r.len * sizeof(ntfs_runlist)) % PAGE_SIZE == 0) {
 		ntfs_runlist* new;
-		new = ntfs_malloc((attr->d.r.len + 8) * sizeof(ntfs_runlist));
-		if (!new)
-			return;
+		unsigned long new_size;
+
+		ntfs_debug(DEBUG_MALLOC, "ntfs_insert_run: re-allocating "
+				"space: old attr->d.r.len = 0x%x\n",
+				attr->d.r.len);
+		new_size = attr->d.r.len * sizeof(ntfs_runlist) + PAGE_SIZE;
+		if ((new_size >> PAGE_SHIFT) > num_physpages) {
+			ntfs_error("ntfs_insert_run: attempted to allocate "
+					"more pages than num_physpages."
+					"This might be a bug or a corrupt"
+					"file system.\n");
+			return -1;
+		}
+		new = ntfs_vmalloc(new_size);
+		if (!new) {
+			ntfs_error("ntfs_insert_run: ntfs_vmalloc(new_size = "
+					"0x%x) failed\n", new_size);
+			return -1;
+		}
 		if (attr->d.r.runlist) {
 			ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
 							* sizeof(ntfs_runlist));
-			ntfs_free(attr->d.r.runlist);
+			ntfs_vfree(attr->d.r.runlist);
 		}
 		attr->d.r.runlist = new;
 	}
@@ -110,6 +246,7 @@
 	attr->d.r.runlist[cnum].cluster = 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
@@ -119,7 +256,7 @@
  *
  * *len: the desired new length of the attr (_not_ the amount to extend by)
  */
-int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len, int flags)
+int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 *len, int flags)
 {
 	int error = 0;
 	ntfs_runlist *rl;
@@ -145,8 +282,8 @@
 		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->clustersize - 1) /
-		ino->vol->clustersize;
+	clen = ((*len - attr->allocated) + ino->vol->cluster_size - 1) >>
+						ino->vol->cluster_size_bits;
 	if (clen == 0)
 		return 0;
 	/* FIXME: try to allocate smaller pieces */
@@ -154,13 +291,17 @@
 				       flags | ALLOC_REQUIRE_SIZE);
 	if (error)
 		return error;
-	attr->allocated += clen * ino->vol->clustersize;
+	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;
 	}
+	/*
+	 * 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);
 	return 0;
 }
@@ -168,13 +309,14 @@
 int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
 {
 	void *data = attr->d.data;
-	int len = attr->size;
-	int error, alen;
+	__s64 len = attr->size;
+	int error;
+	__s64 alen;
 	ntfs_io io;
 	attr->d.r.len = 0;
 	attr->d.r.runlist = 0;
 	attr->resident = 0;
-	attr->allocated=attr->initialized = 0;
+	attr->allocated = attr->initialized = 0;
 	alen = len;
 	error = ntfs_extend_attr(ino, attr, &alen, ALLOC_REQUIRE_SIZE);
 	if (error)
@@ -203,13 +345,14 @@
 }
 
 /* Resize the attribute to a newsize. */
-int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
+int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize)
 {
 	int error = 0;
-	int oldsize = attr->size;
-	int clustersize = ino->vol->clustersize;
-	int i, count, newlen, newcount;
+	__s64 oldsize = attr->size;
+	int clustersizebits = ino->vol->cluster_size_bits;
+	int i, count, newcount;
 	ntfs_runlist *rl;
+	__s64 newlen;
 
 	if (newsize == oldsize)
 		return 0;
@@ -219,7 +362,7 @@
 		return -EOPNOTSUPP;
 	if (attr->resident) {
 		void *v;
-		if (newsize > ino->vol->mft_recordsize) {
+		if (newsize > ino->vol->mft_record_size) {
 			error = ntfs_make_attr_nonresident(ino, attr);
 			if (error)
 				return error;
@@ -247,16 +390,19 @@
 	rl = attr->d.r.runlist;
 	if (newsize < oldsize) {
 		for (i = 0, count = 0; i < attr->d.r.len; i++) {
-			if ((count + rl[i].len) * clustersize > newsize)
+			if ((__s64)(count + rl[i].len) << clustersizebits >
+									newsize)
 				break;
 			count += (int)rl[i].len;
 		}
 		newlen = i + 1;
 		/* Free unused clusters in current run, unless sparse. */
 		newcount = count;
-		if (rl[i].cluster != MAX_CLUSTER_T) {
-			int rounded = newsize - count * clustersize;
-			rounded = (rounded + clustersize - 1) / clustersize;
+		if (rl[i].cluster != (ntfs_cluster_t)-1) {
+			int 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);
@@ -267,7 +413,7 @@
 		}
 		/* Free all other runs. */
 		for (i++; i < attr->d.r.len; i++)
-			if (rl[i].cluster != MAX_CLUSTER_T) {
+			if (rl[i].cluster != (ntfs_cluster_t)-1) {
 				error = ntfs_deallocate_clusters(ino->vol,
 								rl[i].cluster,
 								(int)rl[i].len);
@@ -283,10 +429,10 @@
 					 ALLOC_REQUIRE_SIZE);
 		if (error)
 			return error; /* FIXME: Incomplete operation. */
-		newcount = newlen / clustersize;
+		newcount = newlen >> clustersizebits;
 	}
 	/* Fill in new sizes. */
-	attr->allocated = newcount * clustersize;
+	attr->allocated = (__s64)newcount << clustersizebits;
 	attr->size = newsize;
 	/* attr->initialized does not change. */
 	if (!newsize)
@@ -303,7 +449,7 @@
 	int error;
 	ntfs_attribute *attr;
 	
-	if (dsize > ino->vol->mft_recordsize)
+	if (dsize > ino->vol->mft_record_size)
 		/* FIXME: Non-resident attributes. */
 		return -EOPNOTSUPP;
 	if (aname) {
@@ -316,14 +462,11 @@
 		name = 0;
 		namelen = 0;
 	}
-	error = ntfs_new_attr(ino, anum, name, namelen, &i, &found, 1);
-	if (error) {
+	error = ntfs_new_attr(ino, anum, name, namelen, data, dsize, &i,
+									&found);
+	if (error || found) {
 		ntfs_free(name);
-		return error;
-	}
-	if (found) {
-		ntfs_free(name);
-		return -EEXIST;
+		return error ? error : -EEXIST;
 	}
 	*rattr = attr = ino->attrs + i;
 	/* Allocate a new number.
@@ -333,6 +476,10 @@
 	if (error)
 		return error;
 	attr->attrno = i;
+	if (attr->attrno + 1 != NTFS_GETU16(ino->attr + 0x28))
+		ntfs_error("UH OH! attr->attrno (%i) != NTFS_GETU16(ino->attr "
+				"+ 0x28) (%i)\n", attr->attrno,
+				NTFS_GETU16(ino->attr + 0x28));
 	attr->resident = 1;
 	attr->compressed = attr->cengine = 0;
 	attr->size = attr->allocated = attr->initialized = dsize;
@@ -340,9 +487,9 @@
 	/* FIXME: INDEXED information should come from $AttrDef
 	 * Currently, only file names are indexed. As of NTFS v3.0 (Win2k),
 	 * this is no longer true. Different attributes can be indexed now. */
-	if (anum == ino->vol->at_file_name) {
+	if (anum == ino->vol->at_file_name)
 		attr->indexed = 1;
-	} else
+	else
 		attr->indexed = 0;
 	attr->d.data = ntfs_malloc(dsize);
 	if (!attr->d.data)
@@ -354,7 +501,8 @@
 /* Non-resident attributes are stored in runs (intervals of clusters).
  *
  * This function stores in the inode readable information about a non-resident
- * attribute. */
+ * attribute.
+ */
 static int ntfs_process_runs(ntfs_inode *ino, ntfs_attribute* attr,
 			     unsigned char *data)
 {
@@ -362,33 +510,71 @@
 	int vcn, cnum;
 	ntfs_cluster_t cluster;
 	int len, ctype;
-	startvcn = NTFS_GETU64(data + 0x10);
-	endvcn = NTFS_GETU64(data + 0x18);
-
-	/* Check whether this chunk really belongs to the end. */
+	int er = 0;
+	startvcn = NTFS_GETS64(data + 0x10);
+	endvcn = NTFS_GETS64(data + 0x18);
+
+	/* Check whether this chunk really belongs to the end. Problem with
+	 * this: this functions can get called on the last extent first, before
+	 * it is called on the other extents in sequence. This happens when the
+	 * 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
+	 * 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++)
 		vcn += attr->d.r.runlist[cnum].len;
 	if (vcn != startvcn) {
-		ntfs_error("Problem with runlist in extended record\n");
-		return -1;
+		ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: ino = 0x%x, "
+			"attr->type = 0x%x, startvcn = 0x%x, endvcn = 0x%x, "
+			"vcn = 0x%x, cnum = 0x%x\n", ino->i_number, attr->type,
+			startvcn, endvcn, vcn, cnum);
+		if (vcn < startvcn) {
+			ntfs_error("Problem with runlist in extended record\n");
+			return -1;
+		}
+		/* Tried to insert an already inserted run list. */
+		return 0;
 	}
 	if (!endvcn) {
-		endvcn = NTFS_GETU64(data + 0x28) - 1; /* Allocated length. */
-		endvcn /= ino->vol->clustersize;
+		if (!startvcn) {
+			/* Allocated length. */
+			endvcn = NTFS_GETS64(data + 0x28) - 1;
+			endvcn >>= ino->vol->cluster_size_bits;
+		} else {
+			/* This is an extent. Allocated length is not defined!
+			 * Extents must have an endvcn though so this is an
+			 * error. */
+			ntfs_error("Corrupt attribute extent. (endvcn is "
+				"missing)\n");
+			return -1;
+		}
 	}
 	data = data + NTFS_GETU16(data + 0x20);
 	cnum = attr->d.r.len;
 	cluster = 0;
 	for (vcn = startvcn; vcn <= endvcn; vcn += len)	{
-		if (ntfs_decompress_run(&data, &len, &cluster, &ctype))
+		if (ntfs_decompress_run(&data, &len, &cluster, &ctype)) {
+			ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: "
+				"ntfs_decompress_run failed. i_number = 0x%x\n",
+				ino->i_number);
 			return -1;
+		}
 		if (ctype)
-			ntfs_insert_run(attr, cnum, -1, len);
+			er = ntfs_insert_run(attr, cnum, -1, len);
 		else
-			ntfs_insert_run(attr, cnum, cluster, len);
+			er = ntfs_insert_run(attr, cnum, cluster, len);
+		if (er)
+			break;
 		cnum++;
 	}
-	return 0;
+	if (er)
+		ntfs_error("ntfs_process_runs: ntfs_insert_run failed\n");
+	ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: startvcn = 0x%x, vcn = 0x%x"
+				", endvcn = 0x%x, cnum = %i\n", startvcn, vcn,
+				endvcn, cnum);
+	return er;
 }
   
 /* Insert the attribute starting at attr in the inode ino. */
@@ -404,6 +590,8 @@
 
 	type = NTFS_GETU32(attrdata);
 	namelen = NTFS_GETU8(attrdata + 9);
+	ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ino->i_number 0x%x, "
+			"attr type 0x%x\n", ino->i_number, type);
 	/* Read the attribute's name if it has one. */
 	if (!namelen)
 		name = 0;
@@ -415,25 +603,30 @@
 		ntfs_memcpy(name, attrdata + NTFS_GETU16(attrdata + 10),
 			    2 * namelen);
 	}
-	error = ntfs_new_attr(ino, type, name, namelen, &i, &found, 1);
+	/* If resident look for value, too. */
+	if (NTFS_GETU8(attrdata + 8) == 0)
+		error = ntfs_new_attr(ino, type, name, namelen,
+				attrdata + NTFS_GETU16(attrdata + 0x14),
+				NTFS_GETU16(attrdata + 0x10), &i, &found);
+	else
+		error = ntfs_new_attr(ino, type, name, namelen, NULL, 0, &i,
+				&found);
 	if (error) {
+		ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ntfs_new_attr "
+				"failed.\n");
 		if (name)
 			ntfs_free(name);
 		return error;
 	}
-	/* We can have in one inode two attributes with type 0x00000030 (File
-	 * Name) and without name. FIXME: We can have a lot more than two!
-	 * That is how hard links are implemented. (AIA) */
-	if (found && /*FIXME*/ type != ino->vol->at_file_name)
-	{
-		ntfs_process_runs(ino, ino->attrs + i, attrdata);
+	if (found) {
+		/* It's already there, if not resident just process the runs. */
+		if (!ino->attrs[i].resident) {
+			ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute:"
+						" processing runs 1.\n");
+			/* FIXME: Check error code! (AIA) */
+			ntfs_process_runs(ino, ino->attrs + i, attrdata);
+		}
 		return 0;
- 	} else if (found) {
- 		/* Don't understand the above, but I know it leaks memory below
-		 * as it overwrites a found entry without freeing it. So here
-		 * we call ntfs_new_attr again but this time ask it to always
-		 * allocate a new entry. */
- 		ntfs_new_attr(ino, type, name, namelen, &i, &found, 0);
 	}
 	attr = ino->attrs + i;
 	attr->resident = NTFS_GETU8(attrdata + 8) == 0;
@@ -449,14 +642,21 @@
 		ntfs_memcpy(attr->d.data, data, attr->size);
 		attr->indexed = NTFS_GETU16(attrdata + 0x16);
 	} else {
-		attr->allocated = NTFS_GETU32(attrdata + 0x28);
-		attr->size = NTFS_GETU32(attrdata + 0x30);
-		attr->initialized = NTFS_GETU32(attrdata + 0x38);
+		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)
-			attr->compsize = NTFS_GETU32(attrdata + 0x40);
+			attr->compsize = NTFS_GETS64(attrdata + 0x40);
+		ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: "
+			"attr->allocated = 0x%Lx, attr->size = 0x%Lx, "
+			"attr->initialized = 0x%Lx\n", attr->allocated,
+			attr->size, attr->initialized);
 		ino->attrs[i].d.r.runlist = 0;
 		ino->attrs[i].d.r.len = 0;
+		ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: processing "
+				"runs 2.\n");
+		/* FIXME: Check error code! (AIA) */
 		ntfs_process_runs(ino, attr, attrdata);
 	}
 	return 0;
@@ -477,12 +677,13 @@
 }
 
 /* Process compressed attributes. */
-int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
+int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
 			 ntfs_io *dest)
 {
 	int error = 0;
-	int clustersize, l;
-	int s_vcn, rnum, vcn, len, chunk, got, l1, offs1, copied;
+	int clustersizebits;
+	int s_vcn, rnum, vcn, got, l1;
+	__s64 copied, len, chunk, offs1, l;
 	ntfs_cluster_t cluster, cl1;
 	char *comp = 0, *comp1;
 	char *decomp = 0;
@@ -490,13 +691,13 @@
 	ntfs_runlist *rl;
 
 	l = dest->size;
-	clustersize = ino->vol->clustersize;
+	clustersizebits = ino->vol->cluster_size_bits;
 	/* Starting cluster of potential chunk. There are three situations:
 	   a) In a large uncompressible or sparse chunk, s_vcn is in the middle
 	      of a run.
 	   b) s_vcn is right on a run border.
 	   c) When several runs make a chunk, s_vcn is before the chunks. */
-	s_vcn = offset / clustersize;
+	s_vcn = offset >> clustersizebits;
 	/* Round down to multiple of 16. */
 	s_vcn &= ~15;
 	rl = attr->d.r.runlist;
@@ -517,18 +718,19 @@
 	copied = 0;
 	while (l) {
 		chunk = 0;
-		if (cluster == MAX_CLUSTER_T) {
+		if (cluster == (ntfs_cluster_t)-1) {
 			/* Sparse cluster. */
-			int l1;
+			__s64 l1;
 			if ((len - (s_vcn - vcn)) & 15)
 				ntfs_error("Unexpected sparse chunk size.");
-			l1 = chunk = min((vcn + len) * clustersize - offset, l);
+			l1 = chunk = min(((__s64)(vcn + len) << clustersizebits)
+								- offset, l);
 			error = ntfs_read_zero(dest, l1);
 			if (error)
 				goto out;
 		} else if (dest->do_read) {
 			if (!comp) {
-				comp = ntfs_malloc(16 * clustersize);
+				comp = ntfs_malloc(16 << clustersizebits);
 				if (!comp) {
 					error = -ENOMEM;
 					goto out;
@@ -541,7 +743,7 @@
 			do {
 				io.param = comp1;
 				l1 = min(len - max(s_vcn - vcn, 0), 16 - got);
-				io.size = l1 * clustersize;
+				io.size = (__s64)l1 << clustersizebits;
 				error = ntfs_getput_clusters(ino->vol, cl1, 0,
 					       		     &io);
 				if (error)
@@ -554,16 +756,17 @@
 					len = rl->len;
 				}
 				got += l1;
-				comp1 += l1 * clustersize;
-			} while (cluster != MAX_CLUSTER_T && got < 16);
+				comp1 += (__s64)l1 << clustersizebits;
+			} while (cluster != (ntfs_cluster_t)-1 && got < 16);
 							/* Until empty run. */
-			chunk = 16 * clustersize;
-			if (cluster != MAX_CLUSTER_T || got == 16)
+			chunk = 16 << clustersizebits;
+			if (cluster != (ntfs_cluster_t)-1 || got == 16)
 				/* Uncompressible */
 				comp1 = comp;
 			else {
 				if (!decomp) {
-					decomp = ntfs_malloc(16 * clustersize);
+					decomp = ntfs_malloc(16 << 
+							clustersizebits);
 					if (!decomp) {
 						error = -ENOMEM;
 						goto out;
@@ -575,16 +778,16 @@
 				ntfs_decompress(decomp, comp, chunk);
 				comp1 = decomp;
 			}
-			offs1 = offset - s_vcn * clustersize;
-			chunk = min(16 * clustersize - offs1, chunk);
+			offs1 = offset - ((__s64)s_vcn << clustersizebits);
+			chunk = min((16 << clustersizebits) - offs1, chunk);
 			chunk = min(l, chunk);
 			dest->fn_put(dest, comp1 + offs1, chunk);
 		}
 		l -= chunk;
 		copied += chunk;
 		offset += chunk;
-		s_vcn = offset / clustersize & ~15;
-		if (l && offset >= ((vcn + len) * clustersize)) {
+		s_vcn = (offset >> clustersizebits) & ~15;
+		if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) {
 			rnum++;
 			rl++;
 			vcn += len;
@@ -601,7 +804,7 @@
 	return error;
 }
 
-int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
+int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
 			  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)