Как получить путь из инода во FreeBSD (ZFS и UFS)?

В Windows (NtQueryObject), Linux (/proc/self/fd/x) и OS X (F_GETPATH) есть методы для получения пути к дескриптору открытого в данный момент файла. Предположительно, FreeBSD делает то же самое с помощью следующего кода:

        size_t len;
        int mib[4]={CTL_KERN, KERN_PROC, KERN_PROC_FILEDESC, getpid()};
        BOOST_AFIO_ERRHOS(sysctl(mib, 4, NULL, &len, NULL, 0));
        std::vector<char> buffer(len*2);
        BOOST_AFIO_ERRHOS(sysctl(mib, 4, buffer.data(), &len, NULL, 0));
        for(char *p=buffer.data(); p<buffer.data()+len;)
        {
          struct kinfo_file *kif=(struct kinfo_file *) p;
          if(kif->kf_fd==fd)
          {
            lock_guard<pathlock_t> g(pathlock);
            _path=path::string_type(kif->kf_path);
            return _path;
          }
          p+=kif->kf_structsize;
        }

Это досадно работает почти со всеми типами файловых дескрипторов, кроме обычных файлов, которые возвращают нулевой путь, по крайней мере, в FreeBSD 10. Я предполагаю, что это недосмотр, так как при изучении кода ядра это может показаться тривиальным. вернуть путь, хотя, возможно, по соображениям производительности этого не делать.

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

Итак, позвольте мне задать этот вопрос: можно ли попросить UFS или ZFS вернуть фрагмент пути из индексного узла, возможно, используя какой-нибудь магический ioctl или sysctl, или даже какую-нибудь служебную библиотеку? Рассматриваемому коду не нужен путь, с которым был открыт файловый дескриптор, ему нужен только некоторый канонический путь, по которому в данный момент находится файловый дескриптор (это для обработки отслеживание переименований сторонних файлов для предложенного Boost.AFIO).

Заранее благодарю за любую помощь. FreeBSD — единственная из основных операционных систем, демонстрирующая эту функцию, и без нее она делает невозможным написание кода обнаружения гонки файловой системы :(

Редактировать: я нашел обсуждение о том, как заставить ZFS преобразовывать индексные дескрипторы в пути, по адресу http://comments.gmane.org/gmane.os.solaris.opensolaris.zfs/38277. Судя по всему есть ioctl ZFS_IOC_OBJ_TO_PATH, но это не проторенный путь кода судя по гуглу


person Niall Douglas    schedule 14.02.2015    source источник
comment
Как бы вы это ни делали, это будет медленно. Я предполагаю, что вы не хотите делать что-то подобное... find . -inum 6811865   -  person Mark Setchell    schedule 14.02.2015
comment
К сожалению, нет, это должна быть очень быстрая операция. Это особенно необходимо, чтобы быть быстрым, чтобы обойти другие гонки файловых систем, используя openat/statat/unlinkat.   -  person Niall Douglas    schedule 14.02.2015


Ответы (1)


Оказывается, тот факт, что KERN_PROC_FILEDESC не работает, на самом деле является ошибкой в ​​ядре FreeBSD. Я зарегистрировал его на странице https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197695.

KERN_PROC_FILEDESC отлично работает с дескрипторами файлов каталогов, включая отслеживание переименований и удалений. Он несовершенно работает для обычных файловых дескрипторов, иногда возвращая путь, а затем совершенно внезапно возвращая нулевой путь, а затем случайно возвращая путь снова. Думаю где-то в релизе 10.x что-то где-то сломалось :(

Надеюсь, что это поможет кому-то еще так же застрял.

person Niall Douglas    schedule 28.02.2015