Banging my head against sparse files
Lately I’ve had use for sparse files to solve a problem. Simple, yes. Use lseek and write (or read). Even better, at least in this case, use pwrite and pread. Should be simple, right? Yes, should be.
I was banging my head against code equivalent to the following for quite a few hours:
#define _XOPEN_SOURCE 500
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
char buf[1024];
int
main(int argc, char **argv)
{
int n;
off_t off;
for(n = 0; n < 1024; n++) {
buf[n] = 'a';
}
int fd1;
if(-1 == (fd1 = open("file1", O_WRONLY | O_CREAT, 0666)))
error(EXIT_FAILURE, errno, "open (test1)");
off = 0x80000000;
printf("size: %d\n", sizeof(off));
if(pwrite(fd1, buf, 1024, off) != 1024)
error(EXIT_FAILURE, errno, "pwrite (%lli)", off);
return(0);
}
Can you spot the problem?
Well, I can tell you it doesn’t work. off_t becomes 64-bit due to the #define _FILE_OFFSET_BITS 64 so the off variable isn’t negative in my code. Somehow however it becomes negative on the way into pwrite, and without a single compiler or linker error at that!
Have you spot the problem yet?
Here’s the correctly working code:
#define _XOPEN_SOURCE 500
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
char buf[1024];
int
main(int argc, char **argv)
{
int n;
off_t off;
for(n = 0; n < 1024; n++) {
buf[n] = 'a';
}
int fd1;
if(-1 == (fd1 = open("file1", O_WRONLY | O_CREAT, 0666)))
error(EXIT_FAILURE, errno, "open (test1)");
off = 0x80000000;
printf("size: %d\n", sizeof(off));
if(pwrite(fd1, buf, 1024, off) != 1024)
error(EXIT_FAILURE, errno, "pwrite (%lli)", off);
return(0);
}
Don’t see any difference? Look at the list of included files!
Let me just say the C and I aren’t on speaking terms at the moment!