Recently, I had one particular file that I’d been working on that got corrupted somehow. Unfortunately, I’d let my Time Machine backup lapse somewhat and so I didn’t have a backup.
Anyway, the file wasn’t very big but it would have taken me a little while to write it again so I tried another way of getting the file back. I knew that Xcode uses atomic saves (it writes a new file and then uses a rename) so I figured, so long as I don’t write too much to the disk, there should be an old copy somewhere on the disk. Searching the entire disk would have been tedious though, so I wrote a quick program that creates a file on a volume that uses up all the free space. If you do this by conventional means, you’ll end up with a file full of zeros, but thankfully, OS X comes with the F_SETSIZE fcntl which allows you to set the size of a file without setting the contents. Here’s the code:
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <err.h>
int main (int argc, char *argv[])
{
int fd = open (argv[1], O_CREAT | O_RDWR, 0666);
uint64_t size = 4096;
for (;;) {
if (fcntl (fd, F_SETSIZE, &size)) {
if (errno == ENOSPC)
break;
else
err (1, "fcntl failed\n");
}
size *= 2;
}
uint64_t high = size;
uint64_t low = size / 2;
while (high > low + 1) {
size = low + (high - low) / 2;
if (fcntl (fd, F_SETSIZE, &size)) {
if (errno != ENOSPC)
err (1, "fcntl failed");
high = size;
} else
low = size;
}
printf ("done: %llu\n", size);
return 0;
}
Obviously, you want to run this whilst booted from another volume and you have to run it as root.
So then it was a simple case of firing up HexFiend which I happen to know has pretty fast search and I managed to find my file.
Leave a comment