Two identical filenames in one directory!

John Chambers jc at minya.UUCP
Thu Sep 28 07:26:09 AEST 1989



Hi, folks.  Here I am again with another puzzle.  You might recognize
the following output:

|	foo: ls -ltr |tail -6
|	 1956 -rw-rw-rw-   1 news     news         797 Sep 27 13:13 errlog
|	 2241 -rw-rw-rw-   1 news     news       14751 Sep 27 14:10 oactive
|	  256 drwxrwxrwx   2 news     news         224 Sep 27 16:08 history.od
|	  128 drwxrwxrwx   2 news     news         224 Sep 27 16:08 history.d
|	 1777 -rw-rw-rw-   1 news     news       14751 Sep 27 16:40 active
|	 1898 -rw-rw-rw-   1 news     news       14751 Sep 27 16:40 active

Those two "active" files are a bit curious.  Perhaps one of them has
a nonprinting character in its name?  Next I tried:

|	foo: mv active active.save
|	foo: ls -ltr |tail -6
|	./active not found
|	 1922 -rw-rw-rw-   1 news     news           3 Sep 26 17:03 seq
|	 1956 -rw-rw-rw-   1 news     news         797 Sep 27 13:13 errlog
|	 2241 -rw-rw-rw-   1 news     news       14751 Sep 27 14:10 oactive
|	  256 drwxrwxrwx   2 news     news         224 Sep 27 16:08 history.od
|	  128 drwxrwxrwx   2 news     news         224 Sep 27 16:08 history.d
|	 1777 -rw-rw-rw-   1 news     news       14751 Sep 27 16:40 active.save

Curiouser and curiouser.  The "active" file didn't just disappear; ls
told me that it wasn't there.  If it had a funny nonprinting character
in its name, we'd expect to see it still.  I undid the change, and fed
the listing to a hexdump program.  I won't bore you with the results of
this; suffice it to say that there was no funny character at the end of 
the last two lines.  (No remarks about the funny character sitting at the 
keyboard, please!)  My next try was to feed the directory itself to the 
hexdumper, and edit out most of the lines so you don't have to wade thru 
them like I did.  The two active files nicely turned out to be neighbors:

|	foo: hd . 
|	...
|	   192:_qactive_________jactive_________$errlog__________active--______
|	    C0:0F6676760000000106667676000000000A677666000000000066767622000000
|	       611349650000000F7A1349650000000074522CF70000000000134965DD000000
|	...

This is the "vertical" hexdump format, where each character in a vertical
3-byte slice.  Thus byte 195 is 'c' which is 0x63.  You all realized that
this was Sys/V without needing to be told, of course, as soon as you saw
this dump.  If we chop it into 16-byte chunks, we have the entries:
|	   _qactive________
|	   0F66767600000001
|	   611349650000000F
and:
|	   _jactive________
|	   0666767600000000
|	   7A13496500000000
Now we see what happened.  Some gremlin (I almost said daemon ;-) has changed
the last byte of one entry from 0x00 to 0x1F.  When ls scans the directory, 
it sees a file called "active", properly null-terminated.  It then tries to
stat("active",&status), and this fails, because the kernel's namei() routine
fills it with 8 null bytes, compares all 14 bytes, and they don't match.  This
also explains why the duplicate active files have all the data but the inode
numbers the same; they are both listings for the second file.

On earlier versions of Unix, I'd know instantly what to do.  It's easy enough
to write a program that runs thru a directory and extends each null byte to 
the end of the entry.  But on Sys/V, this doesn't work, because nobody, not
even root, can write a directory.  

I might observe that this is a clear violation of the principle that sofware
should be conservative in what it produces and liberal in what it accepts.
Sys/V allows the creation of such a directory entry; the proof is above; it
should properly handle references to them.  I might also make nasty remarks 
about the folks who decided that this sort of thing couldn't happen, so they 
didn't have to allow root to open directories for writing.  I might even make 
comments about people who add code to kernels that does nothing productive; 
it just wastes cycles preventing me from doing something I want to do.  But 
I won't.  I'll just ask:  Does anyone know a solution to this problem, short 
of zeroing the directory, running fsck, and reinstalling from backup?  The 
best way would be to say "Yes, root can write a directory; here's how..."

Alternatively, I guess I could try to find a pirate copy of the source to
fsck, and add this to its repertoire.  It'd probably only take an hour or
two.  Ain't binary-only systems nice?

-- 
#echo 'Opinions Copyright 1989 by John Chambers; for licensing information contact:'
echo '	John Chambers <{adelie,ima,mit-eddie}!minya!{jc,root}> (617/484-6393)'
echo ''
saying



More information about the Comp.unix.wizards mailing list