Почему dirent.h не работает на дисках sshfs?

Вот код, который я использовал для его проверки. Он работает на обычных каталогах, но не на тех, которые смонтированы под sshfs. Моя цель - использовать эти методы в https://github.com/jlettvin/Greased-Grep который предназначен для глобального нечеткого поиска ключевых слов, которые должны присутствовать, и ключевых слов, которые должны отсутствовать.

#include <iostream>
#include <string>
#include <functional>
#include <dirent.h>

using std::cout;
using std::endl;
using std::string;
using std::function;

bool neither (const char* path)
{
        bool ret = (path != nullptr);
        if (ret)
        {
                if (path[0] == '.')
                {
                        if (path[1] == '\0') ret = false;
                        if (path[1] == '.' && path[2] == '\0') ret = false;
                }
        }
        return ret;
}

void walk (const string &path, function<void (const string &)> talk)
{
    if (auto dir = opendir (path.c_str ())) {
        while (auto f = readdir (dir)) {
                        auto name = f->d_name;
                        auto type = f->d_type;
                        if (neither (name))
                        {
                                switch (type)
                                {
                                        case DT_DIR: walk (path + name + "/", talk); break;
                                        case DT_REG: talk (path + name            ); break;
                                }
                        }
        }
        closedir(dir);
    }
}

int main (int argc, char** argv)
{
        walk ("./", [](const string &path) { cout << path << endl; });
        return 0;
}

2 ответа

Вам необходимо просмотреть следующую документацию в Linux readdir(3) страница справочника:

  unsigned char       d_type;     /* Type of file; not supported
                                by all filesystem types */

В частности, ваше внимание направлено на часть "не поддерживается всеми типами файловых систем".

Ваш код ожидает d_type установить. Тем не мение, readdir(3) не гарантирует, что это будет.

Одно из возможных значений для d_type является:

DT_UNKNOWN

    The file type could not be determined.

Код, который должен быть подготовлен для обработки всех возможностей, должен явно проверять DT_UNKNOWN и, если да, добавить d_name на имя каталога, stat() имя файла, а затем получить тип файла оттуда.

d_type это ярлык Если это установлено, замечательно. У вас это есть сразу. Если нет, вам придется работать, чтобы получить его.

sshfs очевидно, не поддерживает возвращение d_type от readdir(3), С надеждой, sshfs инвентарь stat(),

PS, кроме того, что кроме каталога и обычных файлов, есть также несколько других специальных типов, с которыми вы можете или не можете обращаться (при условии, что sshfs могу даже предоставить их вам). Это то, что вам нужно исследовать самостоятельно.

У меня есть код, который я хотел работать.

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

Я отношусь ко всему найденному как к каталогу, так и к файлу. Если это не каталог, я обнаруживаю и игнорирую все ошибки и продолжаю. Если это каталог, я открываю его и ищу в нем то, что хочу. Это преимущество в Greased-Grep, цель которого - найти подходящие вещи. Имена файлов - это такие же вещи, как и их содержимое.

Итак, мой ответ: мне плевать на неудачи. Меня волнуют только успехи, поэтому я отказываюсь от неудач без каких-либо испытаний.

Это прекрасно работает, когда спускаются каталоги, смонтированные по sshfs.

Любой, кто интересуется тем, как этот код выглядит, может подписаться на мой github: https://github.com/jlettvin/Greased-Grep/blob/master/gg.cpp

Вот выдающийся код:

void walk (const string& a_path)
{
    // Don't attempt to assess validity of filenames... just fail.
    // Treat directories like files and search filenames in directories.
    // This enables gg to work on sshfs mounted filesystems.
    auto d{a_path};
    auto s{d.size ()};
    if (s && d[s - 1] == '/') d.resize (s-1);
    errno = 0;
    if (auto dir = opendir (d.c_str ()))
    {
        while (!errno)
        {
            if (auto f = readdir (dir))
            {
                if (auto p = f->d_name)
                {
                    if (auto q = p)
                    {
                        if (!(*q++ == '.' && (!*q || (*q++ == '.' && !*q))))
                        {
                            auto e = d + "/" + p;
                            walk (e);
                            mapped_search (e.c_str ());
                            errno = 0;
                        }
                    }
                    else break;
                }
                else break;
            }
            else break;
        }
    }
}
Другие вопросы по тегам