Quick fix for non-unique inode numbers for hard links. We use the
byte offset of the directory entry for the inode number for all types of files except directories, although this breaks hard links for non-directories even if it doesn't cause overflow. Just ignore this broken inode number for stat() and readdir() and return a less broken one (the block offset of the file), so that applications normally can't see the brokenness. This leaves at least the following brokenness: - extra inodes, vnodes and caching for hard links. - various overflow bugs. cd9660 supports 64-bit block numbers, but we silently ignore the top 32 bits in isonum_733() and then drop another 10 bits for our broken inode numbers. We may also have sign extension bugs from storing 32-bit extents in ints and longs even if ints are 32-bits. These bugs affect DVDs. mkisofs apparently limits them by writing directory entries first. Inode numbers were broken mainly in 4.4BSD-Lite2. FreeBSD-1.1.5 seems to have a correct implementation modulo the overflow bugs. We need to look up directory entries from inodes for symlinks only. FreeBSD-1.1.5 use separate fields (iso_parent_extent, iso_parent) to point to the directory entry. 4.4BSD-Lite doesn't have these, and abuses i_ino to point to the directory entry. Correct pointers are impossible for hard links, but symlinks can't be hard links.
This commit is contained in:
parent
553d6172dc
commit
8310ab84a1
@ -170,7 +170,14 @@ cd9660_getattr(ap)
|
||||
register struct iso_node *ip = VTOI(vp);
|
||||
|
||||
vap->va_fsid = dev2udev(ip->i_dev);
|
||||
vap->va_fileid = ip->i_number;
|
||||
|
||||
/*
|
||||
* Don't use ip->i_ino for this since it is wrong for hard links.
|
||||
* ip->i_ino should be the same as ip->iso_start (or not exist),
|
||||
* but this currently doesn't work since we abuse it to look up
|
||||
* parent directories from inodes.
|
||||
*/
|
||||
vap->va_fileid = ip->iso_start;
|
||||
|
||||
vap->va_mode = ip->inode.iso_mode;
|
||||
vap->va_nlink = ip->inode.iso_links;
|
||||
@ -524,11 +531,12 @@ cd9660_readdir(ap)
|
||||
break;
|
||||
}
|
||||
|
||||
if (isonum_711(ep->flags)&2)
|
||||
idp->current.d_fileno = isodirino(ep, imp);
|
||||
else
|
||||
idp->current.d_fileno = dbtob(bp->b_blkno) +
|
||||
entryoffsetinblock;
|
||||
/*
|
||||
* The "inode number" is iso_start, not i_ino, as in
|
||||
* cd9660_getattr().
|
||||
*/
|
||||
idp->current.d_fileno = isonum_711(ep->ext_attr_length) +
|
||||
isonum_733(ep->extent);
|
||||
|
||||
idp->curroff += reclen;
|
||||
|
||||
|
@ -170,7 +170,14 @@ cd9660_getattr(ap)
|
||||
register struct iso_node *ip = VTOI(vp);
|
||||
|
||||
vap->va_fsid = dev2udev(ip->i_dev);
|
||||
vap->va_fileid = ip->i_number;
|
||||
|
||||
/*
|
||||
* Don't use ip->i_ino for this since it is wrong for hard links.
|
||||
* ip->i_ino should be the same as ip->iso_start (or not exist),
|
||||
* but this currently doesn't work since we abuse it to look up
|
||||
* parent directories from inodes.
|
||||
*/
|
||||
vap->va_fileid = ip->iso_start;
|
||||
|
||||
vap->va_mode = ip->inode.iso_mode;
|
||||
vap->va_nlink = ip->inode.iso_links;
|
||||
@ -524,11 +531,12 @@ cd9660_readdir(ap)
|
||||
break;
|
||||
}
|
||||
|
||||
if (isonum_711(ep->flags)&2)
|
||||
idp->current.d_fileno = isodirino(ep, imp);
|
||||
else
|
||||
idp->current.d_fileno = dbtob(bp->b_blkno) +
|
||||
entryoffsetinblock;
|
||||
/*
|
||||
* The "inode number" is iso_start, not i_ino, as in
|
||||
* cd9660_getattr().
|
||||
*/
|
||||
idp->current.d_fileno = isonum_711(ep->ext_attr_length) +
|
||||
isonum_733(ep->extent);
|
||||
|
||||
idp->curroff += reclen;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user