afs: Ensure afs_calc_inum yields nonzero ino
authorAndrew Deason <adeason@sinenomine.net>
Wed, 22 Jun 2011 18:44:38 +0000 (13:44 -0500)
committerDerrick Brashear <shadow@dementia.org>
Wed, 6 Jul 2011 20:41:46 +0000 (13:41 -0700)
afs_calc_inum can currently yield an inode of 0 if MD5-based inode
numbers are turned on. Some userspace applications (and for some
platforms, maybe even the kernel) make certain assumptions about the
inode number for a file; in particular for example, 'ls' will not
display a file with inode 0 in a normal directory listing.

So, read the md5 digest until we get a non-zero result. Fall back to
the non-md5 calculation if we still somehow end up with a 0.

While this case may at first glance seem to be extremely rare, in
practice it can occur, as the current calculation for volume
538313506, vnode 26178 does actually yield a 0.

Change-Id: Iee1ef4cc2ad66269f2c677e29d586ef0964d7c70
Reviewed-on: http://gerrit.openafs.org/4901
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: BuildBot <buildbot@rampaginggeek.com>

src/afs/afs_util.c

index 7dfc5c7..783ebc1 100644 (file)
@@ -372,18 +372,32 @@ afs_data_pointer_to_int32(const void *p)
 afs_int32
 afs_calc_inum(afs_int32 volume, afs_int32 vnode)
 {
-    afs_int32 ino, vno = vnode;
+    afs_int32 ino = 0, vno = vnode;
     char digest[16];
     struct md5 ct;
 
     if (afs_new_inum) {
+       int offset;
        MD5_Init(&ct);
        MD5_Update(&ct, &volume, 4);
        MD5_Update(&ct, &vnode, 4);
        MD5_Final(digest, &ct);
-       memcpy(&ino, digest, sizeof(afs_int32));
-       ino ^= (ino ^ vno) & 1;
-    } else {
+
+       /* Userspace may react oddly to an inode number of 0 or 1, so keep
+        * reading more of the md5 digest if we get back one of those.
+        * Make sure not to read beyond the end of the digest; if we somehow
+        * still have a 0, we will fall through to the non-md5 calculation. */
+       for (offset = 0;
+            (ino == 0 || ino == 1) &&
+             offset + sizeof(ino) <= sizeof(digest);
+            offset++) {
+
+           memcpy(&ino, &digest[offset], sizeof(ino));
+           ino ^= (ino ^ vno) & 1;
+           ino &= 0x7fffffff;      /* Assumes 32 bit ino_t ..... */
+       }
+    }
+    if (ino == 0 || ino == 1) {
        ino = (volume << 16) + vnode;
     }
     ino &= 0x7fffffff;      /* Assumes 32 bit ino_t ..... */