Как получить режим файлового дескриптора?

Я хочу использовать fdopen

FILE *fdopen(int fd, const char *mode);

На страницах руководства указано, что «Режим потока (один из значения «r», «r +», «w», «w +», «a», «a +») должны быть совместимы с режимом дескриптора файла ». Итак, я должен сначала узнать режим fd (который, я полагаю, является int), чтобы выбрать подходящий const char *mode для потока.

Я понимаю, что должен использовать fcntl

int fcntl(int fd, int cmd);

для «управления дескриптором файла» (далее я цитирую этот официальный источник). Он может работать на:

Флаги дескриптора файла

Следующие команды управляют флагами, связанными с файловым дескриптором.
...

Флаги статуса файла

Каждое описание открытого файла имеет определенные ассоциированные флаги состояния, инициализируемые open (2) ...

(Я бы не знал разницы между ними. Учитывая, что fcntl полностью относится к файловым дескрипторам, я предполагаю, что второй заголовок должен быть «Флаги состояния файловых дескрипторов», и, таким образом, у нас будут «флаги» и «флаги состояния» .. ... сбивает меня с толку. Я не видел никаких подробностей по этому поводу). Я здесь мимоходом упоминаю об этом, я задаю конкретный вопрос по этому поводу.

Судя по описанию, я должен выбрать последнее. В этом случае, когда cmd=F_GETFL, возвращаемое значение - «режим доступа к файлу и флаги состояния файла». "Флаги состояния файлов и их семантика описаны в open (2) < / а> ".

После прочтения цитированных источников я не мог понять:

  1. Какие бывают все возможные режимы (ints) для fd

  2. Следовательно, какие все комбинации mode (fd) ‹-> mode (stream) являются «совместимыми».

Думаю, можно составить два списка и соединить их стрелками.

Связанный:

Могу ли я получить режим доступа для `FILE *`? < / а>

Спецификация файловых дескрипторов (я спросил об этом)

Как отловить файловый режим?

Я хочу знать внутренних членов структуры ФАЙЛ, самые свежие

Как разобраться в O_RDONLY = 0? (я спросил это)

https://www.gnu.org/software/libc/manual/html_node/Access-Modes.html

https://www.gnu.org/software/libc/manual/html_node/File-Status-Flags.html#File-Status-Flags


person sancho.s ReinstateMonicaCellio    schedule 20.05.2020    source источник
comment
Флаги файлового дескриптора файла - O_RDONLY, O_WRONLY и O_RDWR. Если вы вернетесь к связанной ссылке, вы сможете понять, как это получить. А с помощью хорошей fopen ссылки это не должно быть слишком сложно чтобы сопоставить их со строкой режима fopen (и действительно fdopen).   -  person Some programmer dude    schedule 20.05.2020
comment
@Someprogrammerdude - Спасибо. Я возвращался несколько раз и не мог этого понять. Вот почему я прихожу сюда и спрашиваю, и мне не терпится получить ответы. Это могло быть спрятано у всех на виду, по крайней мере, для меня.   -  person sancho.s ReinstateMonicaCellio    schedule 20.05.2020
comment
Используйте F_GETFL, чтобы получить флаги, которые должны включать открытый режим (для выхода из которого может потребоваться побитовое маскирование).   -  person Some programmer dude    schedule 20.05.2020
comment
@Someprogrammerdude - Как написано в OP, я дошел до использования F_GETFL и зная, что он включает открытый режим. Но я все еще не мог составить простые описательные списки, которые являются целью вопроса, и связи между ними.   -  person sancho.s ReinstateMonicaCellio    schedule 20.05.2020
comment
O_READ - это "r". O_WRITE равно "w" или "a" (в зависимости от того, где вы хотите записать в файл). O_RDWR может быть любой другой строкой для чтения и записи, в зависимости от ваших потребностей.   -  person Some programmer dude    schedule 20.05.2020
comment
@Someprogrammerdude - похоже, у меня нет O_READ, даже если я использую gcc и этот gnu.org/software/libc/manual/html_node/Access-Modes.html. И у меня есть O_ACCMODE, в fcntl-linux.h.   -  person sancho.s ReinstateMonicaCellio    schedule 20.05.2020
comment
Ой, извините за ошибку, я имел в виду O_RDONLY и O_WRONLY.   -  person Some programmer dude    schedule 20.05.2020
comment
@Someprogrammerdude - Пожалуйста, проверьте таблицу, опубликованную Тони Таннусом, и мой ответ. Они предоставляют интересную информацию, которую, я думаю, было не совсем очевидно сделать из найденных мною страниц.   -  person sancho.s ReinstateMonicaCellio    schedule 21.05.2020


Ответы (2)


Изучив ответы и комментарии, здесь и в Как разобраться в O_RDONLY = 0?, я собрал код ниже. Оттуда я получил следующую информацию о статусе дескриптора файла «слова» (я не хотел бы использовать термин «флаги», см. Примечание ниже, взятое из этот комментарий) и режим открытия файла < / em> s.

*** Flag                       O_RDONLY =     0 =            0 = x0000
*** Flag                       O_WRONLY =     1 =            1 = x0001
*** Flag                         O_RDWR =     2 =           10 = x0002
*** Flag                        O_CREAT =    64 =      1000000 = x0040
*** Flag                        O_TRUNC =   512 =   1000000000 = x0200
*** Flag                       O_APPEND =  1024 =  10000000000 = x0400
*** Flag   O_WRONLY | O_CREAT | O_TRUNC =   577 =   1001000001 = x0241
*** Flag  O_WRONLY | O_CREAT | O_APPEND =  1089 =  10001000001 = x0441
*** Flag     O_RDWR | O_CREAT | O_TRUNC =   578 =   1001000010 = x0242
*** Flag    O_RDWR | O_CREAT | O_APPEND =  1090 =  10001000010 = x0442
*** Mode  r  F_GETFL -> 32768 = 1000000000000000 = x8000
*** Mode  w  F_GETFL -> 32769 = 1000000000000001 = x8001
*** Mode  a  F_GETFL -> 33793 = 1000010000000001 = x8401
*** Mode r+  F_GETFL -> 32770 = 1000000000000010 = x8002
*** Mode w+  F_GETFL -> 32770 = 1000000000000010 = x8002
*** Mode a+  F_GETFL -> 33794 = 1000010000000010 = x8402

Числа в трех столбцах представлены в десятичном, двоичном и шестнадцатеричном формате. Искал "странный" x8000, нашел в fcntl-linux.h

# ifdef __USE_GNU
...
#  define AT_RECURSIVE      0x8000  /* Apply to the entire subtree.  */
...
# endif

Таким образом, за исключением этого флага, присутствующего во всех режимах, ассоциация будет

r   <->  O_RDONLY
w   <->  O_WRONLY
a   <->  O_WRONLY | O_APPEND
r+  <->  O_RDWR
w+  <->  O_RDWR
a+  <->  O_RDWR | O_APPEND

Это дает мне пару интригующих открытий:

  1. Список не совпадает с таблицей, приведенной Тони Таннусом.

  2. Слово для r+ такое же, как для w+. Это ставит перед кодировщиком задачу относительно того, какой режим использовать с fdopen, когда слово равно O_RDWRr+, и w+ подойдут). Согласно this, я ожидал, что w+ будет также O_CREAT (как в таблице упомянутый выше). Я тоже ожидал, что w получит это.

  3. Чтобы написать полностью переносимый код, кажется, что всякий раз, когда используется fdopen, нужно писать код, как я писал, чтобы автоматически находить mode ‹-> word соединения. (на самом деле, часть работы, которую я проделал, заключалась в ручной идентификации, и нужен дополнительный код).

РЕДАКТИРОВАТЬ. Пункты 1 и 2 в комментариях объясняются тем, что в таблице показано соответствие между режимами fopen и флагами open, то есть во время создания. Но то, что я получил с fcntl, - это постоянные флаги после создания, а не те, которые использовались во время создания. Как также объяснялось здесь, O_CREAT и O_TRUNC относятся к категории флагов создания файлов < / em> и поэтому не являются постоянными. С другой стороны, O_APPEND относится к категории флаги состояния файла и является постоянным. «Различие между этими двумя группами флагов состоит в том, что флаги создания файла влияют на семантику самой операции открытия, в то время как флаги состояния файла влияют на семантику последующих операций ввода / вывода. O операции ". [ref]

Примечание. справочная страница по открытому (2 ) сначала описывает режимы доступа к файлам, а затем добавляет: «Кроме того, ноль или более флагов создания файлов и флагов состояния файлов могут быть побитовыми или помещены в флаги ....» Но это (правильно) не упомяните, что режим доступа к файлам может быть побитовым. Для меня слово «флаг» является абсолютно неправильным и вводящим в заблуждение.


Код (можно использовать любую функцию to_binary для получения двоичной формы):

int main() {
    const char fname[100] = "test.txt";
    const char modes[][4] = { "r", "w", "a", "r+", "w+", "a+" };
    const size_t nmodes = sizeof(modes) / sizeof(modes[0]);
    const int flags[] = { O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, O_APPEND,
            O_WRONLY | O_CREAT | O_TRUNC,
            O_WRONLY | O_CREAT | O_APPEND,
            O_RDWR | O_CREAT | O_TRUNC,
            O_RDWR | O_CREAT | O_APPEND
    };
    const char flags_str[][100] = { "O_RDONLY", "O_WRONLY", "O_RDWR", "O_CREAT", "O_TRUNC", "O_APPEND",
            "O_WRONLY | O_CREAT | O_TRUNC",
            "O_WRONLY | O_CREAT | O_APPEND",
            "O_RDWR | O_CREAT | O_TRUNC",
            "O_RDWR | O_CREAT | O_APPEND"
    };
    const size_t nflags = sizeof(flags) / sizeof(flags[0]);
    for (size_t iflag = 0 ; iflag < nflags ; iflag++) {
        const int flag = flags[iflag];
        const char * flag_str = flags_str[iflag];
        char nbin[33];
        to_binary(flag, nbin);
        printf( "*** Flag %30s = %5d = %12s = x%04x\n", flag_str, flag, nbin, flag);
    }
    for (size_t imode = 0 ; imode < nmodes ; imode++) {
        const char * mode = modes[imode];
        FILE * fp1 = fopen(fname, mode);
        int fd1 = fileno(fp1);
        int retval = fcntl(fd1, F_GETFL);
        char nbin[33];
        to_binary(retval, nbin);
        printf( "*** Mode %2s  F_GETFL -> %5d = %12s = x%04x", mode, retval, nbin, retval);
        fclose(fp1);
    }
    return 0;
}
person sancho.s ReinstateMonicaCellio    schedule 21.05.2020
comment
Хороший подробный ответ, скоро удалю свой ответ. Для будущих читателей, которым интересно, о какой таблице я говорил, ее можно найти в fopen справочную страницу. - person Tony Tannous; 21.05.2020
comment
Хотя w + должен создать файл, если он не существует ... Открыт для чтения и записи, я бы ожидал O_CREAT. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file. Получено также из этого источника. Может быть, тэг Бармар? w+ создает файл, если он не существует. Проверено. - person Tony Tannous; 21.05.2020
comment
Чтобы написать полностью переносимый код, кажется, что всякий раз, когда используется fdopen, нужно писать код, как я писал, чтобы автоматически находить режим соединения В большинстве случаев вы заранее знаете, как вы собираетесь использовать файл , будь то для чтения или записи, вам не нужно получать режим динамически. - person Barmar; 21.05.2020
comment
@TonyTannous - я бы посоветовал вам не удалять ответ. Учитывая, что это официальная информация, я думаю, что она может быть полезна и другим. Тогда тот, кто его прочитает, должен будет получить полную картину, прочитав остальные ответы / комментарии. - person sancho.s ReinstateMonicaCellio; 21.05.2020
comment
@Barmar - Согласен. Что вы думаете о двух других моментах? - person sancho.s ReinstateMonicaCellio; 21.05.2020
comment
Различие между r+ и w+ имеет значение в fopen(), но не fdopen(). O_CREAT и O_TRUNC влияют только на то, что open() делает при открытии файла, они не имеют постоянного воздействия на дескриптор. - person Barmar; 21.05.2020
comment
@Barmar - Ваш комментарий, кажется, полностью устраняет разрыв между тем, что я нашел, и таблицей, опубликованной Тони ... отлично! Вы бы опубликовали это как ответ? - person sancho.s ReinstateMonicaCellio; 21.05.2020
comment
@Barmar - Что касается пункта 1, вполне может потребоваться написать функции, которые будут нацелены на любой режим (мне нужно что-то вроде этого), и в этих случаях это все еще (серьезная?) Проблема / рабочая нагрузка. Вы видите какой-нибудь способ обойти это? - person sancho.s ReinstateMonicaCellio; 21.05.2020
comment
Можете привести примеры? Это вся причина, по которой fdopen() имеет аргумент режима, потому что он не может быть выведен автоматически. - person Barmar; 21.05.2020
comment
Поэтому вам следует просто передать это требование в свои функции. - person Barmar; 21.05.2020
comment
@Barmar - Достаточно честно. - person sancho.s ReinstateMonicaCellio; 21.05.2020


В fopen вы можете проверить, как они соотносятся с w+ r и т. Д. ...

введите описание изображения здесь

person Tony Tannous    schedule 20.05.2020
comment
Кажется, что OP спрашивает о флагах открытого режима (например, O_RDWR и т. Д.), А не о типах файлов или флагах защиты, которые доступны из st_mode. Это должно совпадать с соответствующей строкой режима для fdopen. - person Some programmer dude; 20.05.2020
comment
Бинго !! Эта таблица из официального источника - именно то, что я искал. На странице руководства, на которую я попал, нет таблицы! - person sancho.s ReinstateMonicaCellio; 20.05.2020
comment
Обратите внимание, что O_RDONLY (например) не предназначен для использования для побитовых операций, см. stackoverflow.com/a/61923919/2707864 . На самом деле, я думаю, что ваш if (mode & O_RDONLY) не будет вести себя так, как вы ожидаете. Вы можете дважды проверить и исправить это на благо сообщества. - person sancho.s ReinstateMonicaCellio; 21.05.2020
comment
Пожалуйста, проверьте ответ, который я добавил, его выводы, похоже, не полностью согласуются с таблицей. - person sancho.s ReinstateMonicaCellio; 21.05.2020