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

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

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

Примечание

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

3 ответов


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

Удивительно, но есть is способ сделать это, по крайней мере, С MS VC++. Все, кроме двух шагов, используют только 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), либо использует ACLs (например, файлы на 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. требует распространяемый Win32 FileID API Library

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

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

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

/proc/self/fd/[descriptor]

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

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


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

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