Search code examples
cmacososx-snow-leopardposix

pwrite() on OSX 10.6 not honoring 64-bit offsets


I seem to be having an odd problem with pwrite() on OSX 10.6.8 when attempting to write to an offset beyond 2GB. I keep catching a SIGXFSZ signal, meaning that the file-size limit has been exceeded. Ignoring the signal doesn't help because pwrite() will then simply return EFBIG.

It seems that OSX does not support the explicit open64() and pwrite64() functions. It also seems that sizeof(off_t) is a proper 8-bytes in size, meaning that pwrite() should take a 64-bit offset. Is there a flag I'm missing when calling open(), or some OSX-specific setting I should be passing for my file-descriptor to fcntl() to enable large-file support?

Finally, when I check getrlimit(), with the RLIMIT_FSIZE option, it says that both the current and the max file-size limit is 9223372036854775807 bytes. So that doesn't seem to be preventing me from writing large files via pwrite().

Has anyone else had problems with pwrite() under 64-bit OSX?


EDIT: Per request, I'm adding the code that calls pwrite() ... note that this code is inside a write-thread:

for (int i=0; i < data->iterations; i++)
{
    unsigned char* ptr = data->buffer;
    int temp_buff_size = data->buff_size;
    int offset = i * data->buff_size;

    while(temp_buff_size > 0)
    {
        int temp_bytes_written = pwrite(data->fd, ptr, temp_buff_size, offset);

        if (temp_bytes_written >= 0)
        {
            temp_buff_size -= temp_bytes_written;
            ptr += temp_bytes_written;
            offset += temp_bytes_written;
        }
        else if (errno == EINTR)
        {
            continue;
        }
        else
        {
            perror("Write thread exiting");
            write_thread_finished = 1;
                return (void*)-1;
        }
    }
}

I'm calling it inside a loop since it's my understanding that pwrite() is not guaranteed to write all the data requested, and so I need to make sure that the data I am requesting be written is actually written to disk, and if less bytes are written, then I properly offset into the buffer I'm writing to get the rest of the buffer onto the disk. The role of data->iterations is just passing to the thread information on how many times to write the buffer to disk ... this is part of a bandwidth test, so I'm trying to write a large file to see how fast it can be written to disk. The only problem is I'm not able to pass an offset larger than 2GB to pwrite().


Solution

  • On OSX int is still kept at 32 bits even on 64-bit systems. So when the signed integer rolls over to negative, you try to write at a negative offset.

    Edit: The correct type, as per the manual, is off_t which should be of correct size and signedness whether the underlying OS is 32 or 64 bits.