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

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

diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/dir.c linux/fs/ntfs/dir.c
@@ -27,8 +27,7 @@
  * be restored. */
 int ntfs_check_index_record(ntfs_inode *ino, char *record)
 {
-	return ntfs_fixup_record(ino->vol, record, "INDX",
-				 ino->u.index.recordsize);
+	return ntfs_fixup_record(record, "INDX", ino->u.index.recordsize);
 }
 
 static inline int ntfs_is_top(ntfs_u64 stack)
@@ -95,15 +94,15 @@
 #endif
 
 /* True if the entry points to another block of entries. */
-static inline int ntfs_entry_has_subnodes(char* entry)
+static inline int ntfs_entry_has_subnodes(char *entry)
 {
-	return (int)NTFS_GETU8(entry + 12) & 1;
+	return (NTFS_GETU16(entry + 0xc) & 1);
 }
 
 /* True if it is not the 'end of dir' entry. */
-static inline int ntfs_entry_is_used(char* entry)
+static inline int ntfs_entry_is_used(char *entry)
 {
-	return (int)(NTFS_GETU8(entry + 12) & 2) == 0;
+	return !(NTFS_GETU16(entry + 0xc) & 2);
 }
 
 /*
@@ -268,12 +267,21 @@
 		ntfs_resize_attr(walk->dir, a, used);
 	} else {
 		NTFS_PUTU16(buf + 0x1C, used - 0x18);
-		ntfs_insert_fixups(buf, vol->sector_size);
 		io.size = walk->dir->u.index.recordsize;
+		error = ntfs_insert_fixups(buf, io.size);
+		if (error) {
+			printk(KERN_ALERT "NTFS: ntfs_index_writeback() caught "
+					"corrupt index record ntfs record "
+					"header. Refusing to write corrupt "
+					"data to disk. Unmount and run chkdsk "
+					"immediately!\n");
+			return -EIO;
+		}
 		error = ntfs_write_attr(walk->dir, vol->at_index_allocation,
-			I30, (__s64)block << vol->cluster_size_bits, &io);
+				I30, (__s64)block << vol->cluster_size_bits,
+				&io);
 		if (error || (io.size != walk->dir->u.index.recordsize &&
-							(error = -EIO, 1)))
+				(error = -EIO, 1)))
 			return error;
 	}
 	return 0;
@@ -422,7 +430,7 @@
 
 	ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30);
 	if (!ra)
-		return -E2BIG;
+		return -ENOTDIR;
 	bsize = ino->vol->mft_record_size;
 	root = ntfs_malloc(bsize);
 	if (!root)
@@ -467,7 +475,7 @@
 	NTFS_PUTU32(index + 0x24, NTFS_GETU32(root + 0x1C));
 	error = ntfs_index_writeback(&walk, index, walk.newblock, 
 				     isize + NTFS_GETU16(index + 0x18) + 0x18);
-	if(error)
+	if (error)
 		goto out;
 	/* Mark root as split. */
 	NTFS_PUTU32(root + 0x1C, 1);
@@ -732,7 +740,7 @@
 
 /* Find an entry in the directory. Return 0 if not found, otherwise copy the
  * entry to the result buffer. */
-int ntfs_getdir(ntfs_iterate_s* walk)
+int ntfs_getdir(ntfs_iterate_s *walk)
 {
 	int length = walk->dir->vol->mft_record_size;
 	int retval, error;
@@ -780,145 +788,190 @@
 	return ntfs_getdir(walk);
 }
 
-int ntfs_getdir_unsorted(ntfs_inode *ino, ntfs_u32 *p_high, ntfs_u32* p_low,
-			 int (*cb)(ntfs_u8*, void*), void *param)
+int ntfs_getdir_unsorted(ntfs_inode *ino, u32 *p_high, u32 *p_low,
+		int (*cb)(ntfs_u8 *, void *), void *param)
 {
+	s64 ib_ofs;
 	char *buf = 0, *entry = 0;
-	ntfs_io io;
-	int length;
-	int block;
-	int start;
 	ntfs_attribute *attr;
 	ntfs_volume *vol;
-	int byte, bit;
-	int error = 0;
+	int byte, bit, err = 0;
+	u32 start, finish, ibs, max_size;
+	ntfs_io io;
+	u8 ibs_bits;
 
 	if (!ino) {
-		ntfs_error("No inode passed to getdir_unsorted\n");
+		ntfs_error(__FUNCTION__ "(): No inode! Returning -EINVAL.\n");
 		return -EINVAL;
 	}
 	vol = ino->vol;
 	if (!vol) {
-		ntfs_error("Inode %d has no volume\n", ino->i_number);
+		ntfs_error(__FUNCTION__ "(): Inode 0x%lx has no volume. "
+				"Returning -EINVAL.\n", ino->i_number);
 		return -EINVAL;
 	}
-	ntfs_debug(DEBUG_DIR3, "unsorted 1\n");
-	/* Are we still in the index root? */
-	if (*p_high == 0) {
-		buf = ntfs_malloc(length = vol->mft_record_size);
+	ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 1: Entering for "
+			"inode 0x%lx, p_high = 0x%x, p_low = 0x%x.\n",
+			ino->i_number, *p_high, *p_low);
+	if (!*p_high) {
+		/* We are still in the index root. */
+		buf = ntfs_malloc(io.size = vol->mft_record_size);
 		if (!buf)
 			return -ENOMEM;
 		io.fn_put = ntfs_put;
 		io.param = buf;
-		io.size = length;
-		error = ntfs_read_attr(ino, vol->at_index_root, I30, 0, &io);
-		if (error) {
-			ntfs_free(buf);
-			return error;
-		}
-		ino->u.index.recordsize = NTFS_GETU32(buf + 0x8);
+		err = ntfs_read_attr(ino, vol->at_index_root, I30, 0, &io);
+		if (err || !io.size)
+			goto read_err_ret;
+		ino->u.index.recordsize = ibs = NTFS_GETU32(buf + 0x8);
 		ino->u.index.clusters_per_record = NTFS_GETU32(buf + 0xC);
 		entry = buf + 0x20;
-		ntfs_debug(DEBUG_DIR3, "unsorted 2\n");
-	} else { /* we are in an index record */
-		length = ino->u.index.recordsize;
-		buf = ntfs_malloc(length);
+		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 2: In index "
+				"root.\n");
+		ibs_bits = ffs(ibs) - 1;
+		/* Compensate for faked "." and "..". */
+		start = 2;
+	} else { /* We are in an index record. */
+		io.size = ibs = ino->u.index.recordsize;
+		buf = ntfs_malloc(ibs);
 		if (!buf)
 			return -ENOMEM;
+		ibs_bits = ffs(ibs) - 1;
 		io.fn_put = ntfs_put;
 		io.param = buf;
-		io.size = length;
-		/* 0 is index root, index allocation starts with 4. */
-		block = *p_high - ino->u.index.clusters_per_record;
-		error = ntfs_read_attr(ino, vol->at_index_allocation, I30,
-				(__s64)block << vol->cluster_size_bits, &io);
-		if (!error && io.size != length)
-			error = -EIO;
-		if (error) {
-			ntfs_error("read failed\n");
-			ntfs_free(buf);
-			return error;
-		}
+		/*
+		 * 0 is index root, index allocation starts at 1 and works in
+		 * units of index block size (ibs).
+		 */
+		ib_ofs = (s64)(*p_high - 1) << ibs_bits;
+		err = ntfs_read_attr(ino, vol->at_index_allocation, I30, ib_ofs,
+				&io);
+		if (err || io.size != ibs)
+			goto read_err_ret;
 		if (!ntfs_check_index_record(ino, buf)) {
-			ntfs_error("%x is not an index record\n", block);
+			ntfs_error(__FUNCTION__ "(): Index block 0x%x is not "
+					"an index record. Returning "
+					"-ENOTDIR.\n", *p_high - 1);
 			ntfs_free(buf);
 			return -ENOTDIR;
 		}
-		entry = buf + NTFS_GETU16(buf + 0x18) + 0x18;
-		ntfs_debug(DEBUG_DIR3, "unsorted 3\n");
+		entry = buf + 0x18 + NTFS_GETU16(buf + 0x18);
+		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 3: In index "
+				"allocation.\n");
+		start = 0;
 	}
 	/* Process the entries. */
-	start = *p_low;
-	while (ntfs_entry_is_used(entry)) {
-		ntfs_debug(DEBUG_DIR3, "unsorted 4\n");
-		if (start)
-			start--; /* Skip entries that were already processed. */
-		else {
-			ntfs_debug(DEBUG_DIR3, "unsorted 5\n");
-			if ((error = cb(entry, param)))
-				/* The entry could not be processed. */
-				break;
-			(*p_low)++;
+	finish = *p_low;
+	for (; entry < (buf + ibs) && ntfs_entry_is_used(entry);
+			entry += NTFS_GETU16(entry + 8)) {
+		if (start < finish) {
+			/* Skip entries that were already processed. */
+			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 4: "
+					"Skipping already processed entry "
+					"p_high 0x%x, p_low 0x%x.\n", *p_high,
+					start);
+			start++;
+			continue;
 		}
-		entry += NTFS_GETU16(entry + 8);
-	}
-	ntfs_debug(DEBUG_DIR3, "unsorted 6\n");
-	/* Caller did not process all entries. */
-	if (error) {
-		ntfs_free(buf);
-		ntfs_debug(DEBUG_DIR3, "unsorted 7\n");
-		return error;
+		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 5: "
+				"Processing entry p_high 0x%x, p_low 0x%x.\n",
+				*p_high, *p_low);
+		if ((err = cb(entry, param))) {
+			/* filldir signalled us to stop. */
+			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): "
+					"Unsorted 6: cb returned %i, "
+					"returning 0, p_high 0x%x, p_low 0x%x."
+					"\n", *p_high, *p_low);
+			ntfs_free(buf);
+			return 0;
+		}
+		++*p_low;
 	}
+	ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 7: After processing "
+			"entries, p_high 0x%x, p_low 0x%x.\n", *p_high, *p_low);
 	/* We have to locate the next record. */
 	ntfs_free(buf);
 	buf = 0;
 	*p_low = 0;
 	attr = ntfs_find_attr(ino, vol->at_bitmap, I30);
 	if (!attr) {
-		/* Directory does not have index allocation. */
-		*p_high = 0xFFFFFFFF;
-		*p_low = 0;
-		ntfs_debug(DEBUG_DIR3, "unsorted 8\n");
+		/* Directory does not have index bitmap and index allocation. */
+		*p_high = 0x7fff;
+		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 8: No index "
+				"allocation. Returning 0, p_high 0x7fff, "
+				"p_low 0x0.\n");
 		return 0;
 	}
-	buf = ntfs_malloc(length = attr->size);
+	max_size = attr->size;
+	if (max_size > 0x7fff >> 3) {
+		ntfs_error(__FUNCTION__ "(): Directory too large. Visible "
+				"length is truncated.\n");
+		max_size = 0x7fff >> 3;
+	}
+	buf = ntfs_malloc(max_size);
 	if (!buf)
 		return -ENOMEM;
 	io.param = buf;
-	io.size = length;
-	error = ntfs_read_attr(ino, vol->at_bitmap, I30, 0, &io);
-	if (!error && io.size != length)
-		error = -EIO;
-	if (error) {
-		ntfs_free(buf);
-		ntfs_debug(DEBUG_DIR3, "unsorted 9\n");
-		return -EIO;
-	}
+	io.size = max_size;
+	err = ntfs_read_attr(ino, vol->at_bitmap, I30, 0, &io);
+	if (err || io.size != max_size)
+		goto read_err_ret;
 	attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
 	if (!attr) {
 		ntfs_free(buf);
-		ntfs_debug(DEBUG_DIR3, "unsorted 9.5\n");
+		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 9: Find "
+				"attr failed. Returning -EIO.\n");
 		return -EIO;
 	}
+	if (attr->resident) {
+		ntfs_free(buf);
+		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 9.5: IA is "
+				"resident. Not allowed. Returning EINVAL.\n");
+		return -EINVAL;
+	}
+	/* Loop while going through non-allocated index records. */
+	max_size <<= 3;
 	while (1) {
-		if ((__s64)*p_high << vol->cluster_size_bits > attr->size) {
+		if (++*p_high >= 0x7fff) {
+			ntfs_error(__FUNCTION__ "(): Unsorted 10: Directory "
+					"inode 0x%lx overflowed the maximum "
+					"number of index allocation buffers "
+					"the driver can cope with. Pretending "
+					"to be at end of directory.\n",
+					ino->i_number);
+			goto fake_eod;
+		}
+		if (*p_high > max_size || (s64)*p_high << ibs_bits >
+				attr->initialized) {
+fake_eod:
 			/* No more index records. */
-			*p_high = 0xFFFFFFFF;
+			*p_high = 0x7fff;
+			*p_low = 0;
 			ntfs_free(buf);
-			ntfs_debug(DEBUG_DIR3, "unsorted 10\n");
+			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted "
+					"10.5: No more index records. "
+					"Returning 0, p_high 0x7fff, p_low "
+					"0.\n");
 			return 0;
 		}
-		*p_high += ino->u.index.clusters_per_record;
-		byte = *p_high / ino->u.index.clusters_per_record - 1;
+		byte = (ntfs_cluster_t)(*p_high - 1);
 		bit = 1 << (byte & 7);
-		byte = byte >> 3;
-		/* This record is allocated. */
-		if (buf[byte] & bit)
+		byte >>= 3;
+		if ((buf[byte] & bit))
 			break;
-	}
-	ntfs_debug(DEBUG_DIR3, "unsorted 11\n");
+	};
+	ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 11: Done. "
+			"Returning 0, p_high 0x%x, p_low 0x%x.\n", *p_high,
+			*p_low);
 	ntfs_free(buf);
 	return 0;
+read_err_ret:
+	if (!err)
+		err = -EIO;
+	ntfs_error(__FUNCTION__ "(): Read failed. Returning error code %i.\n",
+			err);
+	ntfs_free(buf);
+	return err;
 }
 
 int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name)
@@ -1025,7 +1078,7 @@
 				data, sizeof(data), &da);
 }
 
-int ntfs_mkdir(ntfs_inode* dir, const char* name, int namelen,
+int ntfs_mkdir(ntfs_inode *dir, const char *name, int namelen,
 	       ntfs_inode *result)
 {
 	int error;

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