34

I have essentially the following code:

int fileWrite(int file, void * pBuffer, size_t size)
{
    size_t bytesWritten = (size_t)write( file, pBuffer, size ) ;
    if (bytesWritten != size)
    {
       return -1;
    }
    return 0;
}

It works if the size is 1GB, but when the size is ~2GB, it get 4K bytes left consistently. I can fix this by wrapping write in a loop and moving the buffer up but I'm curious as to why it is always failing.

For example if size is 2147483648, write only writes 2147479552, leaving 4096 unwritten. Why would this happen and is it correct to always wrap write in a loop?

TreeWater
  • 761
  • 6
  • 13
  • 2
    Are you running it in 32-bit mode? 2gig is the maximum 32-bit number. – Barmar Apr 10 '20 at 18:51
  • 2
    The rules for how much data `write` will consume at once depend on what type of data sink `file` is (e.g. "regular" file, pipe, stream socket, datagram socket, ...). Can you be more specific? – zwol Apr 10 '20 at 18:52
  • This is 64 bit software. `file` is just a regular file – TreeWater Apr 10 '20 at 20:41
  • 7
    Wait, are you trying to `write` the whole file at once? The usual approach is to stream the data a buffer-size at a time until you write everything. – Luaan Apr 11 '20 at 07:10
  • 4
    @Luaan If you already have all the data I don't see that there's anything _wrong_ writing it all at once but as this question and answer illustrates, `write()` doesn't have to write it all (which goes for small buffers too) – pipe Apr 11 '20 at 16:18
  • 8
    "I can fix this by wrapping write in a loop" and you need to, regardless of the `SSIZE_MAX` restriction. The `write()` spec says it is under no obligation to write the full buffer, even if it almost always does. The loop-less code in the question is a bug. – Adam Apr 11 '20 at 17:58
  • I fully agree with what Adam said. You can easily see it write less than requested when writing to pipes and sockets, but it could happen for files as well. It's up to the system. – ikegami Apr 11 '20 at 19:25
  • The title is confusing; `write` does not modify its input. The buffer pointed to by `pBuffer` is the same before and after the write. Do you mean simply that it returns a bytesWritten value smaller than the requested size? – M.M Apr 12 '20 at 02:11
  • Yes I think it is clear from the body that is what I meant even if the wording in the title is not technically correct. Also I was not saying that this code is correct, and I have used a loop in my code. I ran into this when writing my code in the first place. I was just curious why it was consistently leaving the same amount of bytes left unwritten, which points to some deterministic reason. – TreeWater Apr 12 '20 at 20:10
  • Can afford to use mmap() instead of write? With mmap the OS virtual memory takes care of writing all buffer contents into disk transparently. – Iñigo González Apr 14 '20 at 06:16
  • It all has to do with the size of packets being transferred over the internet. The theoretical maximum size of an IP packet is 65535 bytes including the headers. Therefore, you should not expect to transmit more than this size packets AND the max packet size is often/usually much smaller – user3629249 Apr 14 '20 at 17:42
  • Please clarify via edtis, not comments. – philipxy Apr 15 '20 at 11:00

1 Answers1

53

You can find the answer in man 2 write:

It is not an error if this number is smaller than the number of bytes requested; this may happen for example because the disk device was filled.


And from the write() man page description:

ssize_t write(int fd, const void *buf, size_t count);

According to POSIX.1, if count is greater than SSIZE_MAX, the result is implementation-defined; see NOTES for the upper limit on Linux.

NOTES

On Linux, write() (and similar system calls) will transfer at most 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes actually transferred. (This is true on both 32-bit and 64-bit systems.)

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
bobah
  • 18,364
  • 2
  • 37
  • 70