Можно ли спасти файловый дескриптор из FILE *?

Мне нужно использовать некую кроссплатформенную библиотеку, которая передает FILE* объекты.

Я получаю дескриптор файла из другого источника (унаследованного), я хочу сохранить тот же fd во всех fork процессах.

В настоящее время я использую fdopen для преобразования дескриптора файла в объект FILE*.

Моя проблема в том, что fclose, используемый для очистки FILE* объектов, закрывает подключенный файловый дескриптор.

Я бы очень хотел сохранить этот файловый дескриптор после того, как он был использован.

есть ли способ спасти дескриптор файла от FILE*?

Есть ли способ его отсоединить?

Или способ заменить файловый дескриптор в FILE* на фиктивный?

P.S. это должно быть кроссплатформенным, в любом случае, в POSIX.


person Dima Tisnek    schedule 11.04.2014    source источник


Ответы (4)


Предположим, что fd - ваш файловый дескриптор и f ваш ФАЙЛ * получен от него. Может быть, что-то вроде следующего поможет:

fd2 = dup(fd);
fclose(f);
dup2(fd2, fd);
close(fd2);
person Marian    schedule 11.04.2014

Моя проблема в том, что fclose, используемый для очистки FILE* объектов, закрывает связанный файловый дескриптор.

Вы можете использовать dup(2), чтобы получить копию дескриптора. Тогда close(2), который делает fclose(3), ничего не сделает.

Мне нужно поддерживать точно такой же номер fd

Затем снова вызовите dup2 после fclose: dup2(savedfd, rescuedfd)

person cnicutar    schedule 11.04.2014
comment
Пожалуйста, прочтите еще раз, мне нужно сохранить тот же номер fd из-за fork - person Dima Tisnek; 11.04.2014
comment
Эй, это может сработать. Однако это не является поточно-ориентированным, поскольку другой поток может выделить это самое число fd между close и dup2. dup3 выделит этот случай, но не решит его. Я подумаю об этом! - person Dima Tisnek; 11.04.2014
comment
@qarma Есть и другие уловки, которые могут вам помочь, например, угон fclose и т. д. Я бы не пошел по этому пути. - person cnicutar; 11.04.2014

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

Как только вы получите имя файла, откройте его снова и получите FILE *, выполните свою работу и очистите его с помощью fclose.

Ваш оригинальный fd не будет нарушен.

person Jeegar Patel    schedule 11.04.2014
comment
+1 за умную идею, я могу сделать это на linux с open("/proc/self/fd/9"), но не на OSX или каком-либо клоне BSD. - person Dima Tisnek; 11.04.2014

Вот непереносимая идея (проголосуйте, если считаете, что это хорошо / лучше всего):

GNU libc предоставляет fopencookie, а BSD предоставляет эквивалент funopen.

Они возвращают реальный FILE* дескриптор, но реализация ваша:

В таком случае относительно просто сопоставить функции чтения / записи / поиска / закрытия с базовыми системными вызовами:

read/readfn(cookie, buf, size){ return read((int)cookie, buf, size); }
write/writefn(cookie, buf, size) { return write((int)cookie, buf, size); }
seek/seekfn(cookie, offs, arg) { return seek((int)cookie, offs, arg); } // may require arg mapping to whence
close/closefn(cookie) {} // that's the whole point!
person Dima Tisnek    schedule 11.04.2014