Ты спросил:
Почему флаг, возвращаемый fcntl(fd, F_GETFL), включает только подмножество битов, которые я установил при открытии файла? Он показывает только те, которые можно изменить?
Нет; он показывает только те, которые «запомнены» системой, например O_RDWR
. Их действительно можно назвать «флагами». Некоторые другие биты, объединенные операцией ИЛИ в параметр oflag
, больше похожи на «императивные инструкции» для системного вызова open
: например, O_CREAT
говорит «пожалуйста, создайте этот файл, если он не существует», а O_TRUNC
говорит «пожалуйста, обрежьте его». из них «флаги». Файл, который был усечен при создании, неотличим от файла, который был не усечен при создании: они оба просто "файлы". Таким образом, после того, как open
завершил создание или усечение файла, он не удосуживается "запомнить" эту историю. Он «помнит» только важные вещи, например, открыт ли файл для чтения или записи.
Отредактировано для добавления. Эти различные виды флагов имеют полуофициальные названия. O_RDWR
— это «режим доступа» (запоминаемый, неизменяемый); O_APPEND
- это "режим работы" (запоминаемый, обычно модифицируемый); O_TRUNC
— это «флаг времени открытия» (относится к самой операции open
, а не к файловому дескриптору, поэтому не запоминается). Обратите внимание, что «режим доступа» нельзя изменить — вы не можете использовать fcntl
, чтобы превратить fd только для чтения в fd только для записи.
При использовании fcntl(fd, F_SETFL, flag)
, как мне передать параметр флага, нужно ли мне сначала прочитать флаг через fcntl(fd, F_GETFL)
, а затем изменить его и передать? Или внутренне он просто выполняет небольшую операцию &
с новым параметром?
F_SETFL
перезаписывает флаги в точности тем, что вы передаете (хотя и игнорирует ваши жалкие попытки установить биты, которые на самом деле не являются флагами, такие как O_TRUNC
). ЕСЛИ вы хотите установить определенный флаг и оставить другие флаги как есть, то вы должны F_GETFL
старые флаги, |
новый флаг, а затем F_SETFL
результат. Это должно выполняться как два отдельных системных вызова; насколько я знаю, нет атомарного или потокобезопасного способа выполнить это.
Где я могу найти полный список 32-битных (или менее) бит флагов открытых файлов?
В fcntl.h
или его документации (man fcntl
). Например, на моем MacBook справочная страница говорит:
The flags for the F_GETFL and F_SETFL commands are as follows:
O_NONBLOCK Non-blocking I/O; if no data is available to a read call, or if a write operation would block, the read or write
call returns -1 with the error EAGAIN.
O_APPEND Force each write to append at the end of file; corresponds to the O_APPEND flag of open(2).
O_ASYNC Enable the SIGIO signal to be sent to the process group when I/O is possible, e.g., upon availability of data to be
read.
Другими словами, в OS X можно установить (или снять) ровно три бита. В то время как в Linux на странице руководства указано это:
On Linux this command can change only the O_APPEND, O_ASYNC,
O_DIRECT, O_NOATIME, and O_NONBLOCK flags.
Между прочим, некоторые файловые системы Linux имеют концепцию «файла только для добавления» на уровне файловой системы; если вы откроете один из этих файлов, а затем попытаетесь сбросить флаг O_APPEND
результирующего дескриптора, вы получите ошибку EPERM
. Доступность файла только для добавления можно контролировать на уровне файловой системы с помощью chattr
а> полезность.
Вот более систематизированная версия вашей тестовой программы. Возможно, вам это будет неинтересно, но я кое-чему научился, написав это, поэтому оставлю это здесь. :)
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("/tmp/fd_share.txt", O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0644);
// append to empty file
write(fd, "aaaaaaaaaa", 10);
off_t cur = lseek(fd, 1, SEEK_SET);
printf("offset after being set to 1: %ld\n", (long)cur);
// append
write(fd, "bbbbbbbb", 8);
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after appending bbbbbbbb: %ld\n", (long)cur);
cur = lseek(fd, 2, SEEK_SET);
printf("offset after being set to 2: %ld\n", (long)cur);
// now toggle "append mode" to FALSE
int open_flag = fcntl(fd, F_GETFL);
if (fcntl(fd, F_SETFL, open_flag & ~O_APPEND) == -1) {
printf("failed to set flag\n");
return 0;
}
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after unsetting O_APPEND: %ld\n", (long)cur);
cur = lseek(fd, 3, SEEK_SET);
printf("offset after being set to 3: %ld\n", (long)cur);
// write without appending
write(fd, "cccc", 4);
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after writing cccc: %ld\n", (long)cur);
// now toggle "append mode" to TRUE
open_flag = fcntl(fd, F_GETFL);
if (fcntl(fd, F_SETFL, open_flag | O_APPEND) == -1) {
printf("failed to set flag\n");
return 0;
}
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after unsetting O_APPEND: %ld\n", (long)cur);
// append
write(fd, "dd", 2);
cur = lseek(fd, 0, SEEK_CUR);
printf("offset after appending dd: %ld\n", (long)cur);
close(fd);
}
Вывод этой программы на моем MacBook (как и должно быть в любой системе POSIX, AFAIK):
offset after being set to 1: 1
offset after appending bbbbbbbb: 18
offset after being set to 2: 2
offset after unsetting O_APPEND: 2
offset after being set to 3: 3
offset after writing cccc: 7
offset after unsetting O_APPEND: 7
offset after appending dd: 20
person
Quuxplusone
schedule
08.08.2017
O_CREAT
иO_TRUNC
— это модификаторы, управляющие поведением самого вызоваopen
; они не являются режимами, применимыми к открытому файлу. - person R.. GitHub STOP HELPING ICE   schedule 07.05.2015