8

This question is a spinoff from the following: How to extract raw ext3 inode data from disk?

I have a file /tmp/foo, whose contents are a simple text string "AAA". I would like to locate the disk block # this data resides on, extract the data in this block and make sure it indeed contains "AAA". So I do the following:

  1. stat foo which tells me its inode number is 318903
  2. debugfs -R 'imap <318903>' /dev/vda3 which tells me that this inode is located at block 1277956, offset 0x0600
  3. dumpe2fs /dev/vda3 which tells that the block size is 4096 (bytes) and the inode size is 256 (bytes)
  4. calculate offset of inode from start of disk in 256-byte chunks (makes it simpler to use dd to extract one 256-byte chunk): (1277956 x 4096) + (1536) / 256 = 20447302
  5. extract the inode from disk (raw data): dd if=/dev/sda3 of=/tmp/inode.0 bs=256 count=1 skip=20447302
  6. Look at the structure of the ext2 inode table (the ext3 inode has identical structure): http://www.nongnu.org/ext2-doc/ext2.html#INODE-TABLE
  7. Perform some tests to determine whether I have extracted the correct inode block: chgrp 1 /tmp/foo; dd if=/dev/sda3 of=/tmp/inode.1 bs=256 count=1 skip=20447302; cmp -l /tmp/inode.1 /tmp/inode.0. The output from cmp is the following:
13 217 362
14 225 222
25   1   0

Referencing the inode structure, we see that byte 25 corresponds to i_gid, so this confirms that we truly have extracted the correct inode block from disk (previous group was 0, now it is 1). Can also perform similar tests like changing ownership, changing file size by adding data, re-extract the inode from disk, and these tests continue to confirm we have the right inode block.

  1. Now, according to the documentation, bytes 41-44 of the inode table contains a pointer to the data block (the block # of the actual contents of the file - the file's data). If we do a byte-by-byte compare of our inode with a zero file, we can see the value of bytes 41-44: cmp -l /tmp/inode.1 /tmp/zero.256
 25   1   0
 27   1   0
 29  10   0
 41  56   0
 42 220   0
 43  23   0
101 275   0
102  53   0
103 240   0
104 374   0

"cmp" gives values in octal. So, assuming byte 44 is the high-order byte, then the value of the pointer in octal is 23 | 220 | 56. converting this to binary = 10011 | 10010000 | 00101110, or 100111001000000101110. Converting this to decimal = 1282094

  1. now, is "1282094" a reasonable block number for our data? If we look again at the output from dumpefs, we see that both our inode (block 1277956) and our data (block 1282094) fall within the range covered within block group 39, so it would seem we have a reasonable number:

Group 39: (Blocks 1277952-1310719) Inode table at 1277954-1278464 (+2)

  1. So, we should be able to use dd to extract the data block from disk, examine its contents and they should match the contents our file ("AAA"). But this is not what happens. What happens is the data block contains other stuff, and there is no "AAA" anywhere: dd if=/dev/vda3 of=/tmp/data bs=4096 count=1 skip=1282094; cmp -l /tmp/data /tmp/zero.4096
   1 333   0
   2 335   0
   3   4   0
   5  14   0
   7   1   0
   8   2   0
   9  56   0
  13 221   0
  14 335   0
  15   4   0
  17 364   0
  18  17   0
  19   2   0
  20   2   0
  21  56   0
  22  56   0

This doesn't look like the contents of /tmp/foo. I was thinking maybe I was off by one block, so I also extracted the surrounding blocks (1282093 and 1282095), but still did not find what I was looking for.

What's going on here? What is this extra stuff, and why is there no "AAA"?

11/14. SOLVED. turns out the filesystem had some issues (orphaned inodes and whatnot) which I fixed with fsck and now all is behaving as expected. I want to say thanks a bunch to both Wumpus and derobert (see comments) who offered a lot of invaluable insight and suggestions. Awesome.

closed as off-topic by Braiam, Ramesh, jasonwryan, jimmij, Anthon Jan 6 '15 at 19:03

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions describing a problem that can't be reproduced and seemingly went away on its own (or went away when a typo was fixed) are off-topic as they are unlikely to help future readers." – Braiam, Ramesh, jasonwryan, jimmij, Anthon
If this question can be reworded to fit the rules in the help center, please edit the question.

  • I haven't checked all your calculations, but you can ask debugfs for a list of data blocks with stat. It will tell you immediately if 1282094 is correct. – Wumpus Q. Wumbley Nov 12 '14 at 18:35
  • Don't the docs say offsets 40 to 43, not 41 to 44? Anyway, when I try the related procedure for ext4 using ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Extent_Tree it works for me. You may find filefrag -v your-file useful, as it'll tell you which blocks. Also, you did run sync, right? To make sure its actually written to disk. – derobert Nov 12 '14 at 18:37
  • @derobert 41 to 44 is because cmp -l numbers bytes from 1 instead of 0. – Wumpus Q. Wumbley Nov 12 '14 at 18:54
  • @WumpusQ.Wumbley Ah, that makes sense. And it outputs in octal, too. Sounds like a good reason to find a better tool! I have a vbindiff here. And searching finds a dhex. Both are editors, though. Or of course wdiff on xxd output. – derobert Nov 12 '14 at 18:57
  • I run debugfs 'stat' and indeed 1282094 is the correct data block. I double-checked it with filefrag too. @derobert: which command are you using to extract the data block? – Michael Martinez Nov 12 '14 at 20:29

Browse other questions tagged or ask your own question.