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!

Share

2 Comments

  1. @mr700: I don’t remember exactly what I needed it for at the time, but I’m pretty sure the writes were needed for something. Anyway I didn’t know about truncate until you pointed it out to me, thanks for that.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>