Дублирующий файловый дескриптор с собственным смещением файла

StackOverflow https://stackoverflow.com/questions/1598586

Вопрос

Как можно создать новый файловый дескриптор из существующего файлового дескриптора таким образом, чтобы новый дескриптор не использовал ту же внутреннюю файловую структуру / запись в файловой таблице?В частности, такие атрибуты, как смещение файла (и предпочтительно разрешения, общий доступ и режимы), не должны использоваться совместно между новым и старым файловыми дескрипторами.

Как под Windows, так и под Linux, dup() будет дублировать файловый дескриптор, но оба дескриптора по-прежнему указывают на одну и ту же файловую структуру в файловой таблице процесса.Любой поиск по любому из дескрипторов также скорректирует позицию для других дескрипторов.

Примечание

С тех пор я получал ответы как для Windows, так и для Linux и слишком часто корректировал вопрос, из-за чего людям было трудно ответить.Я скорректирую свои голоса и приму самый чистый ответ, который охватывает оба окна и Linux.Приношу свои извинения всем, я все еще новичок в парадигме SO.Спасибо за отличные ответы!

Это было полезно?

Решение

Итак, по сути, вам действительно нужно получить дескриптор файла и, по сути, открыть тот же файл снова, чтобы получить отдельную позицию, общий доступ, режим и т. д.И вы хотите сделать это в Windows (где «дескриптор файла» по сути является внешним объектом, а не чем-то, используемым непосредственно ОС). или библиотека времени выполнения вообще.

Как ни странно, там является способ сделать это, по крайней мере, с MS VС++.Все шаги, кроме двух, используют только Win32 API, поэтому перенос на другие компиляторы/библиотеки должен быть вполне разумным (я думаю, что большинство версий этих двух функций предоставляют).Они предназначены для преобразования дескриптора файла в стиле Unix в собственный дескриптор файла Win32 и преобразования собственного дескриптора файла Win32 обратно в дескриптор файла в стиле Unix.

  1. Преобразуйте дескриптор файла в собственный дескриптор файла с помощью _get_osfhandle()
  2. Получите имя файла с помощью GetFileInformationByHandleEx(FILE_NAME_INFO)1
  3. Используйте CreateFile, чтобы открыть новый дескриптор этого файла.
  4. Создайте файловый дескриптор для этого дескриптора с помощью _open_osfhandle().

И вуаля, у нас есть новый файловый дескриптор, ссылающийся на тот же файл, но со своими разрешениями, позицией и т. д.

Ближе к концу вашего вопроса вы говорите так, будто вам также нужны «разрешения», но, похоже, это не имеет никакого реального смысла - разрешения привязаны к самому файлу, а не к тому, как файл открывается, поэтому открытие или повторное открытие файла не влияет на разрешения файла.Если вы действительно хотите это знать, вы можете получить его с помощью GetFileInformationByHandle, но имейте в виду, что права доступа к файлам в Windows немного отличаются от (традиционных) разрешений файлов в Unix.Unix имеет права владельца/группы/мирового доступа ко всем файлам, и большинство систем также имеют списки ACL (хотя способы их работы могут различаться).Windows либо вообще не имеет разрешений (например, для файлов в FAT или FAT32), либо использует списки управления доступом (например, для файлов в NTFS), но ничего, что действительно эквивалентно традиционным разрешениям владельца/группы/мира, к которым большинство людей привыкли в Unix.

Возможно, вы используете «разрешения», чтобы указать, был ли файл открыт для чтения, записи или того и другого.Получение этого значительно уродливее, чем любое из предыдущих.Проблема в том, что большая часть этого находится в библиотеке, а не в Win32, поэтому, вероятно, нет способа сделать это, который был бы даже близок к переносимости между компиляторами.С MS VC++ 9.0 SP1 (не гарантируется для любой другой компилятор) вы можете сделать это:

#include <stdio.h>

int get_perms(int fd) {
    int i;
 FILE * base = __iob_func();

    for (i=0; i<_IOB_ENTRIES; i++) 
        if (base[i]._file == fd)
            return base[i]._flag;     // we've found our file
    return 0; // file wasn't found.
}

Поскольку это потребовало некоторых рассуждений, я написал быстрый тест, чтобы убедиться, что это действительно может работать:

#ifdef TEST
#include <io.h>

void show_perms(int perms, char const *caption) { 
 printf("File opened for %s\n", caption);
 printf("Read permission = %d\n", (perms & _IOREAD)!=0);
 printf("Write permission = %d\n", (perms & _IOWRT)!=0);
}

int main(int argc, char **argv) { 
 FILE *file1, *file2;
 int perms1, perms2;

 file1=fopen(argv[1], "w");
 perms1 = get_perms(_fileno(file1));
 fclose(file1);

 file2=fopen(argv[1], "r");
 perms2 = get_perms(_fileno(file2));
 fclose(file2);

 show_perms(perms1, "writing");
 show_perms(perms2, "reading");
 return 0;
}
#endif

И результаты, кажется, указывают на успех:

File opened for writing
Read permission = 0
Write permission = 1
File opened for reading
Read permission = 1
Write permission = 0

Затем вы можете проверить этот возвращенный флаг на соответствие _IOREAD, _IOWRT и _IORW, которые определены в stdio.h.Несмотря на мои предыдущие предупреждения, мне, вероятно, следует отметить, что я подозреваю (хотя, конечно, не могу гарантировать), что эта часть библиотеки довольно стабильна, поэтому реальные шансы на серьезные изменения, вероятно, довольно минимальны.

А вот в обратном направлении шансов практически нет. совсем что он будет работать с любой другой библиотекой.Это мог (но это, конечно, не гарантировано) будет работать с другими компиляторами, использующими библиотеку MS, такими как Intel, MinGW или Comeau, использующими MS VC++ в качестве серверной части.Из них я бы сказал, что с наибольшей вероятностью сработает Comeau, а с наименьшей вероятностью — MinGW (но это только предположение;есть большая вероятность, что ни с одним из них это не сработает).

  1. Требуется распространяемый Библиотека API Win32 FileID

Другие советы

Итак, я рекомендую ознакомиться с этим немного подробнее.Тот Самый dup() и связанные функции служат для создания повторяющегося значения в таблице файловых дескрипторов, указывающего на ту же запись в таблице открытых файлов.Это предназначенный чтобы иметь такое же смещение.Если ты позвонишь open(), вы создадите новую запись в таблице открытых файлов.

Не имеет никакого смысла создавать дубликат файлового дескриптора, и этот новый файловый дескриптор имеет другое смещение в таблице открытых файлов (это, по-видимому, противоречит тому, что означает слово "дублировать").

Я не уверен, в чем на самом деле заключается ваш вопрос.Я имею в виду, что это не то же самое, что дубликат.Вы могли бы прочитать:

/proc/self/fd/[descriptor]

и получите строку, которая была использована для открытия этого файлового дескриптора;имейте в виду, что это может привести к некоторым подводным камням, некоторые из которых вы действительно отметили в своем наблюдении за вызовом open() снова.

Может быть, вы сможете объяснить немного больше, и я попытаюсь обновить, чтобы помочь.

Почему бы вам просто не открыть файл второй раз с помощью open() или CreateFile() в Windows?Это дает вам полную свободу различных прав доступа и отдельного смещения.

Это, конечно, имеет тот недостаток, что вы не можете открыть файл самостоятельно, но это очень просто решает вашу проблему.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top