Сначала хотел пожаловаться на конкретную систему, но копнули глубже и выяснилось, что это общая проблема.
Windows
Вот берем, например, хвалёный MSDN (до линуксов тоже доберемся).
Рассмотрим функцию _write. Опустим чёртов момент, что они депрекейтнули write в пользу _write с тем же синтаксисом, опустим что под виндой есть суперкосяк с текстовым режимом. Опустим, что может быть установлен parameters_handle, который коллбекнется при передаче невалидных параметров. Опустим то, что сигнатура использует int и unsigned вместо ssize_t и size_t:
int _write(
int fd,
const void *buffer,
unsigned int count
);
Нас интересует такой момент:
If execution is allowed to continue, the function returns -1 and errno is set to one of three values: EBADF, which means the file descriptor is invalid or the file isn't opened for writing; ENOSPC, which means there isn't enough space left on the device for the operation; or EINVAL, which means that buffer was a null pointer, or that an odd count of bytes was passed in Unicode mode.
Итого нам говорят, что:
- Если передан невалидный fd - продолжать нельзя
- Если на диске
закончилосьне хватает место - то продолжать нельзя - Если передан кривой буфер - то продолжать нельзя
Ну то есть функция возвращает ошибку всего в трех случаях и все они критические. Окей, а что насчет возврата числа меньше, чем передано в count? Когда такое может быть? В теории когда выполнение функции прервано сигналом или когда записалось N байт и кончилось место. Однако под windows сигналы обрабатываются специально установленным коллбеком и такой вариант отметается. А что касается диска, то:
If the actual space remaining on the disk is less than the size of the buffer the function is trying to write to the disk, _write fails and doesn't flush any of the buffer's contents to the disk
То есть она не попытается записать то, что возможно (что неимоверно тупо, поскольку между моментом проверки места и попыткой записи это самое место могло появиться). Ну то есть _write
под windows никогда не вернет значение меньше count
(и даже больше count не вернет, несмотря на то что в текстовом режиме запишется больше(!) байтов). Еще есть прикол с 0x17 байтом.
По итогу - нигде в документации не записано - а вернет ли когда-либо _write
что-то кроме -1 или count. Если никогда не вернёт, то смысла в возвращаемом count
нет. Поведение сломано, сигнатура сломана, доломайте уже контракт. Причем (якобы) существует функция write
, но она объявлена устаревшей и плохой, негодной функцией.
The name is deprecated because it doesn’t follow the Standard C rules for implementation-specific names.
Linux
С чего, собственно, всё началось. Читали в качестве групповой терапии ман man 2 write
. И нашли такое:
The number of bytes written may be less than count if, for example,
there is insufficient space on the underlying physical medium
Note that a successful write() may transfer fewer than count bytes.
Such partial writes can occur for various reasons; for example, because
there was insufficient space on the disk device to write all of the re‐
quested bytes
Но в конце в списке errno видим:
ENOSPC The device containing the file referred to by fd has no room for
the data.
Т.е. сначала нам два раза говорят, что если на диске не хватает места то запишет сколько влезет и вернет N, а в списке ошибок нам говорят, что будет выставлено -1 и установлен ENOSPC как errno.
Разгадка тут простая - если на диске есть хотя бы один байт свободного пространства - оно запишет один байт. Если там ноль - то вернет -1 + ENOSPC. Но где конкретно это написано? Почему документация превратилась в противоречащий сам себе кусок текста без этого уточнения? Поведение, кстати, полностью противоположное тому, что задано для windows.