[BUG FIX] isofs can lose last entry in directory

RHS Linux User (lin-kern@askone.demon.co.uk)
Fri, 19 Jul 1996 22:00:38 +0100 (BST)


If the last entry in a directory lies across a block boundary then this
entry will be disregarded. The patch below fixes this on my machine.
The patch is against 2.0.7 but should work with most recent kernels. The
bug has been present since at least 1.0.8

diff -u -r --new-file linux-2.0.7/fs/isofs/dir.c linux-2.0.7-isofs/fs/isofs/dir.c
--- linux-2.0.7/fs/isofs/dir.c Fri Jul 19 18:29:59 1996
+++ linux-2.0.7-isofs/fs/isofs/dir.c Fri Jul 19 18:32:56 1996
@@ -5,9 +5,11 @@
*
* (C) 1991 Linus Torvalds - minix filesystem
*
+ * Steve Beynon : Missing last directory entries fixed
+ * (stephen@askone.demon.co.uk) : 21st June 1996
+ *
* isofs directory handling functions
*/
-
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/iso_fs.h>
@@ -133,9 +135,13 @@
#ifdef DEBUG
printk("Block, offset, f_pos: %x %x %x\n",
block, offset, filp->f_pos);
+ printk("inode->i_size = %x\n",inode->i_size);
#endif
/* Next directory_record on next CDROM sector */
if (offset >= bufsize) {
+#ifdef DEBUG
+ printk("offset >= bufsize\n");
+#endif
brelse(bh);
offset = 0;
block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
@@ -151,6 +157,10 @@
inode_number = (block << bufbits) + (offset & (bufsize - 1));

de_len = *(unsigned char *) de;
+#ifdef DEBUG
+ printk("de_len = %ld\n", de_len);
+#endif
+

/* If the length byte is zero, we should move on to the next
CDROM sector. If we are at the end of the directory, we
@@ -175,15 +185,31 @@
If not, put the two halves together in "tmpde" */
next_offset = offset + de_len;
if (next_offset > bufsize) {
+#ifdef DEBUG
+ printk("next_offset (%x) > bufsize (%x)\n",next_offset,bufsize);
+#endif
next_offset &= (bufsize - 1);
- memcpy(tmpde, de, bufsize - offset);
+ memcpy(tmpde, de, bufsize - offset);
brelse(bh);
block = isofs_bmap(inode, (filp->f_pos + de_len) >> bufbits);
if (!block)
+ {
return 0;
- bh = breada(inode->i_dev, block, bufsize, filp->f_pos+de_len, inode->i_size);
+ }
+
+ bh = breada(inode->i_dev, block, bufsize,
+ filp->f_pos,
+ inode->i_size);
if (!bh)
+ {
+#ifdef DEBUG
+ printk("!bh block=%ld, bufsize=%ld\n",block,bufsize);
+ printk("filp->f_pos = %ld\n",filp->f_pos);
+ printk("inode->i_size = %ld\n", inode->i_size);
+#endif
return 0;
+ }
+
memcpy(bufsize - offset + (char *) tmpde, bh->b_data, next_offset);
de = tmpde;
}