Дублирующий файловый дескриптор с собственным смещением файла
-
22-09-2019 - |
Вопрос
Как можно создать новый файловый дескриптор из существующего файлового дескриптора таким образом, чтобы новый дескриптор не использовал ту же внутреннюю файловую структуру / запись в файловой таблице?В частности, такие атрибуты, как смещение файла (и предпочтительно разрешения, общий доступ и режимы), не должны использоваться совместно между новым и старым файловыми дескрипторами.
Как под Windows, так и под Linux, dup()
будет дублировать файловый дескриптор, но оба дескриптора по-прежнему указывают на одну и ту же файловую структуру в файловой таблице процесса.Любой поиск по любому из дескрипторов также скорректирует позицию для других дескрипторов.
Примечание
С тех пор я получал ответы как для Windows, так и для Linux и слишком часто корректировал вопрос, из-за чего людям было трудно ответить.Я скорректирую свои голоса и приму самый чистый ответ, который охватывает оба окна и Linux.Приношу свои извинения всем, я все еще новичок в парадигме SO.Спасибо за отличные ответы!
Решение
Итак, по сути, вам действительно нужно получить дескриптор файла и, по сути, открыть тот же файл снова, чтобы получить отдельную позицию, общий доступ, режим и т. д.И вы хотите сделать это в Windows (где «дескриптор файла» по сути является внешним объектом, а не чем-то, используемым непосредственно ОС). или библиотека времени выполнения вообще.
Как ни странно, там является способ сделать это, по крайней мере, с MS VС++.Все шаги, кроме двух, используют только Win32 API, поэтому перенос на другие компиляторы/библиотеки должен быть вполне разумным (я думаю, что большинство версий этих двух функций предоставляют).Они предназначены для преобразования дескриптора файла в стиле Unix в собственный дескриптор файла Win32 и преобразования собственного дескриптора файла Win32 обратно в дескриптор файла в стиле Unix.
- Преобразуйте дескриптор файла в собственный дескриптор файла с помощью _get_osfhandle()
- Получите имя файла с помощью GetFileInformationByHandleEx(FILE_NAME_INFO)1
- Используйте CreateFile, чтобы открыть новый дескриптор этого файла.
- Создайте файловый дескриптор для этого дескриптора с помощью _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 (но это только предположение;есть большая вероятность, что ни с одним из них это не сработает).
- Требуется распространяемый Библиотека API Win32 FileID
Другие советы
Итак, я рекомендую ознакомиться с этим немного подробнее.Тот Самый dup()
и связанные функции служат для создания повторяющегося значения в таблице файловых дескрипторов, указывающего на ту же запись в таблице открытых файлов.Это предназначенный чтобы иметь такое же смещение.Если ты позвонишь open()
, вы создадите новую запись в таблице открытых файлов.
Не имеет никакого смысла создавать дубликат файлового дескриптора, и этот новый файловый дескриптор имеет другое смещение в таблице открытых файлов (это, по-видимому, противоречит тому, что означает слово "дублировать").
Я не уверен, в чем на самом деле заключается ваш вопрос.Я имею в виду, что это не то же самое, что дубликат.Вы могли бы прочитать:
/proc/self/fd/[descriptor]
и получите строку, которая была использована для открытия этого файлового дескриптора;имейте в виду, что это может привести к некоторым подводным камням, некоторые из которых вы действительно отметили в своем наблюдении за вызовом open()
снова.
Может быть, вы сможете объяснить немного больше, и я попытаюсь обновить, чтобы помочь.
Почему бы вам просто не открыть файл второй раз с помощью open() или CreateFile() в Windows?Это дает вам полную свободу различных прав доступа и отдельного смещения.
Это, конечно, имеет тот недостаток, что вы не можете открыть файл самостоятельно, но это очень просто решает вашу проблему.