2013-08-30 3 views
2

В UNIX, если открыть файл в режиме добавления, какКак определить, был ли файл открыт для добавления в Windows?

fd = open("filename", O_APPEND); 

то при такой дескриптор файла можно легко узнать, какие флаги он был открыт с помощью fcntl:

fcntl(fd, F_GETFL) & O_APPEND 

Я знаю, что fcntl не доступен в Windows, но мне интересно, есть ли способ определить это. Windows явно поддерживает режим добавления, например, при создании файла с CreateFile и прохождения в флагом FILE_APPEND_DATA.

Но если все, что у меня есть, является дескриптором уже открытого файла, я не могу на всю жизнь найти способ определить, какие права доступа запрашивались при первом открытии файла. This question предоставляет базовый рецепт проверки прав доступа к определенному файлу, но это, похоже, не помогает. Я попробовал это, и даже если я открою файл с режимом только для чтения, он все равно говорит мне, что у меня есть FILE_APPEND_DATAдоступ к файлу, если бы я попросил его. Другими словами, этот метод сообщает мне только, какие права доступа к процессу имеют определенный файл (как унаследованный от пользователя, который начал процесс). В нем ничего не говорится о том, какой именно запрос запрашивался при открытии файла.

Это не имеет никакого отношения к тому, как Windows отслеживает, должен ли файл прикрепляться только к нему. И это последний вопрос, что я не могу найти ответ нигде. Самое близкое, что я нашел, это GetFileInformationByHandleEx, но после расчёта в документах нет одного атрибута файла, который может быть возвращен через этот API, который предлагает «режим добавления».

Update: Для того, чтобы прояснить мой вопрос немного лучше, этот вопрос действительно только относится к библиотеке во время выполнения MS VC - файлы, открываемые с POSIX-подобные функции _open и записываются с fwrite и тому подобное. Похоже, что собственные обработчики файлов win32 не имеют понятия «append mode».

ответ

2

Автоответчик, благодаря @mehrdad и @HansPassant для указания меня в правильном направлении. Действительно, MSVCRT экспортирует массив массивов структуры, называемой ioinfo, в которой он хранит информацию о каждом дескрипторе открытого файла в процессе.

Точное содержание структуры зависит от версии VC и некоторые предопределенные, но в целом определяются его первые два члена:

typedef struct { 
     intptr_t osfhnd; /* underlying OS file HANDLE */ 
     char osfile;  /* attributes of file (e.g., open in text mode?) */ 
     .... 
} ioinfo; 

osfile член является интересным - если файл открыт с _O_APPEND на нем установлен флаг FAPPEND, определенный как 0x20.

Я написал небольшую служебную функцию в Python, основанной на подобном коде в posixmodule CPython, что может выполнить эту проверку: https://gist.github.com/embray/6444262

+0

Любой разум, объясняющий почему это было изменено, даже несмотря на то, что оно обеспечивает точное решение моей проблемы? – Iguananaut

+1

Функция API Python C _PyVerify_fd, по крайней мере, на python 3 (не проверяет 2.x) также использует __pioinfo для проверки того, что данный файловый дескриптор действителен. – jsalter

+0

@jsalter Подтверждено, Python 2 mucks around с '__pioinfo', а также в модулях/posixmodule.c. Я чувствую, что это похоже на то, что это похоже, да, это не публичный API, но это не похоже на то, что реализация будет изменяться в любое время, если вообще когда-либо, по крайней мере, для известной версии MSCRT. – Iguananaut

3

Для файла, который для Windows видит как в режиме «Append», это будет работать:

Используйте пол-документированного NtQueryInformationFile системного вызова (экспортированный из ntdll.dll) для запроса FILE_ACCESS_INFORMATION. Это должно сообщить вам маску доступа, в которой был открыт файл, который должен содержать FILE_APPEND_DATA.

Для файла, который C запускает, открывается в режиме «append», однако это не будет работать, потому что Windows фактически не открывает его в режиме добавления. Способ сделать это - каким-то образом перевести файловый дескриптор в файл-объект и проверить флаг там, но нет документального способа сделать это.

Вы можете посмотреть исходный код Visual C++ CRT, чтобы выяснить, как это сделать ... может быть какой-то способ доступа к массиву, в который индексируется индекс, но я не уверен, как это сделать.
Код в CRT выглядит _pioinfo(fd)->osfile |= FAPPEND так надеемся, что это поможет.

+0

Wow это неясное. Я не мог найти это во всех *. Я попробую и дам вам знать, может ли он сказать мне, что мне нужно знать. – Iguananaut

+0

@Iguananaut: Да, Microsoft не любит, чтобы вы использовали эти функции, поэтому к сожалению это неясно. Но практически безопасно использовать их, поэтому идите прямо вперед. – Mehrdad

+0

Стреляй - так близко, но пока. Открываю ли я файл в режиме «write» или «append», 'FILE_ACCESS_INFORMATION' точно идентичен (биты' FILE_WRITE_DATA' и 'FILE_APPEND_DATA' включены, но' FILE_READ_DATA' выключен). Несмотря на то, что файлы по-прежнему отличаются друг от друга, когда я пишу им ... – Iguananaut

3

FileMode.Append - это воплощение воображения команды .NET Framework. Это не тот режим, который поддерживает Windows. Они добавили его, чтобы сделать оболочку для собственной функции CreateFile() для winapi (FileStream) более простой в использовании. FileMode - это оболочка перечисления для аргумента dwCreationDisposition. Которая не имеет опции CREATE_APPEND.

Наиболее соответствующий код из метода FileStream.Init() является:

bool seekToEnd = (mode==FileMode.Append); 
    // Must use a valid Win32 constant here... 
    if (mode == FileMode.Append) 
     mode = FileMode.OpenOrCreate; 

Другими словами, FileMode.Append не соответствует параметр действует CreateFile() и должен быть отображен. Файл будет открыт, если он существует, создается, если это не так. И он заботится о дополнительных операции, после открытия файла, он будет искать в конце файла. Что вы, конечно, ожидаете, когда присоединитесь к существующему файлу. Некоторая дополнительная проверка ошибок существует, она также гарантирует, что вы открыли файл для записи.

Так что, скорее, стреляет в отверстие, чтобы обнаружить это назад. Функция GetFileInformationByHandleEx() winapi доступна для восстановления состояния файла. Документированная функция для недокументированного абонентского вызова api Mehrdad. Вы можете вернуть аргумент dwCreationDisposition из FileDispositionInfo, чтобы проверить, что это OpenOrCreate. Это, однако, не уникально, оно могло также начаться с файла, который открывается с помощью FileMode.OpenOrCreate из кода клиента. Редкий, но возможно.

Что вы потеряли, так это память об этом, ища конец файла. Вы можете использовать свойство FileStream.Position, но это, конечно, будет зависеть от любой записи в среднем времени. Если это действительно имеет значение, то вы do должны сохранить значение FileMode, которое было использовано.

+0

Возможно, вы уже знаете это, но я все равно его упоминаю ... 'GetFileInformationByHandleEx' документирован, но только частично. Он не упоминает' FileAccessInformation' как действительный вариант, но 'ZwQueryInformationFile' делает. И' GetFileInformationByHandleEx' предназначен только для Vista +, тогда как 'ZwQueryInformationFile' также работает и с XP. – Mehrdad

+0

В CreateFile есть файл с ограниченной документацией, называемый FILE_APPEND_DATA, который используется здесь в примере кода: https: // msdn.microsoft.com/en-us/library/windows/desktop/aa363778(v=vs.85).aspx. Кто знает, почему команда .NET не использовала его, но он есть. – jsalter

Смежные вопросы