Questions related to file ``undeletion''

Barry Bouwsma freebsd-misuser at remove-NOSPAM-to-reply.NOSPAM.dyndns.dk
Mon Dec 22 16:02:12 PST 2003


[Drop my (IPv6-only) address from replies; I catch the archives]

Salve,

I decided one day, purely for entertainment value, to see if I could
undelete a file I had mistakenly `rm'ed before fully waking up, in
order to to convince me to fall asleep much further from any keyboards.

To my great glee, I had success using little more than shell commands
and tools.  However, there were a few things I had questions about,
or don't quite comprehend.  FreeBSD-4 in use here, UFS1, sans softdep.

First, my introduction to `fsdb'.  I think I read in the archives that
it should work on mounted filesystems, but I couldn't get any changes
I made to work.  Also, it mentions giving the `-u -o reload' mount
command, which does not seem to be a mount option.  (This was also
mentioned in the archives.)

Finding the inode number was easy, though I can't remember exactly
how I did it, and if `cat'ing the directory file itself was it, or
what I did to verify the inode number.

Finding the inode itself was something I wasn't able to figure out.
Probably I need to study more headers, or else there's a tool out there
I don't know about to do it for me.

Now, `ffsinfo' reported the addresses of the various direct blocks, and
the indirect block, as 0, rather than that of the blocks which held
the data.  Since I didn't find the inode proper to inspect its contents,
I have to ask, when a file is unlinked, are these values in the inode
cleared, or is this an artifact of `ffsinfo' when presented with an
unallocaed inode?

As a note, when I found the indirect block, its contents were intact,
pointing to all the rest of the file.  However, when I've deleted very
large files, it's taken a while for the command to complete (without
softupdates).  Is there an explanation somewhere of exactly what is
done on the disk when an unlink is done, other than the source, out
there?  Are the indirect blocks being cleared then, meaning I should
not expect success finding a file larger than some number times the
block size?

I was lucky that my file fell in one cylinder group, and another file
being written at the time I deleted the wrong file was going elsewhere.
Also, in retrospect, I was lucky that my file was the only free space
in that cylinder group, which I had filled with other data after writing
the file.  But that aside,

My attempts to use `fsdb' to `ln' or to increase the link count did not
succeed.  Probably because I didn't panic the machine promptly.  Using
`fsdb' later on a test file led me to think there's some activity done
at `umount' to clear the inodes; else I'm seeing artifacts of a mounted
filesystem.

Anyway, `fsdb' always printed that my inode I had `ln'ed was now of
size 0, and the db/ib fields were all zeroed.  This probably is to be
expected in the particular case of filesystem activity I did, whatever
that may be.

So anyway, I had no idea where on the disk the contents of my inode
would be found, so I somewhat exhaustively searched the list of free
blocks as printed by `dumpfs'.

This didn't work as hoped.  The block numbers are relative to the
cylinder group offset.  `dumpfs' led me to believe that its value of
`tell' could be used for this.  That was close, but no cigar, as it
turned out in my case to be offset by 4 fragments / 2 blocks below the
actual free block number, when plugging the values into `dd'.

Specific numbers:
cg 3:
magic   90255   tell    6d5020000       time    Tue Dec 16 12:29:50 2003
cgx     3       ncyl    4664    niblk   512     ndblk   298496
nbfree  2244    ndir    1       nifree  511     nffree  0
rotor   192382  irotor  1       frotor  192376
frsum   0
sum of frsum: 0
iused:  0
free:   192502-192503, 192506-192507, 192510-192511, 192514-192515, 192518-192519, 192522-192523,
        192526-192527, 192530-192531, 192534-192535, 192538-192539, 192542-192543, 192546-192547,
[snip]

When I plug 0x6d5020000 and 192502 and my fragment size here of 32768
into `dd', I don't get the first free block.  I need to use 192498.

Is there a constant formula I should be using with `dd', based on `tell'
for the cylinder group, and the listed `free' block number?  Will the
difference always be 4 less than my fragment size, 2 less than the
block size, or some multiple of something, like superblock size?

Or should I use a different formula to convert cg / free into a `dd'
offset?

Anyway, lucky for me, once I found the start of my file, all the
remaining free blocks comprised it, plus the indirect block after
the first 12 direct data blocks.  So I could write a shell script
to write the first data blocks, then pull each pointer out of the
indirect block and append the contents.  Those block numbers needed
no massaging, unlike the ones given by `dumpfs' above.  (Or I could
have skipped over the indirect block and just written all the rest,
for the brute force solution.)  There was my file, padded with NULs
to be trimmed, then added as needed to fill the data structure.  Yay.


I haven't read the entire archives, and only grepped specific terms to
try to find info useful for recovering a deleted file, so I've certainly
overlooked something, like, say, I'm looking to find a ``Welcome to the
Wonderful World of Unix File Deletion'' tutorial to enhance my knowledge.
This way I'll understand that under favourable conditions, I should be
able to find my direct blocks and indirect block, and when it's futile.
For the benefit of anyone who wants to try their hand at undeleting
a file, like me.


thanks,
barry bouwsma



More information about the freebsd-fs mailing list