Ifstream open() не устанавливает биты ошибок, когда аргумент является каталогом

В программе на С++, используя std:: ifstream, я пытаюсь открыть файл, указанный пользователем, настолько хороший. Тем не менее, я случайно ввел имя файла, которое фактически является каталогом, и я был очень удивлен, увидев, что попытка открыть() этот каталог не вызвала никаких ошибок.

Здесь минимальный пример:

std::ifstream f;
f.open("..");
if(!f.is_open() || !f.good() || f.bad() || f.fail()) {
    std::cout << "error bit set on open" << std::endl;
    return 1;
}

Никаких признаков ошибки здесь. Если я продолжаю и пытаюсь getline(), getline() устанавливает бит ошибки в порядке.

std::string str;
getline(f, str);

if(f.eof()) std::cout << "getline set eofbit" << std::endl;
else if(f.bad()) std::cout << "getline set badbit" << std::endl;
else if(f.fail()) std::cout << "getline set failbit" << std::endl;

Это выводит "getline set badbit", что является разумным. Используя оператор → , выдает исключение underflow, что тоже нормально.

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

Кроме того, почему это так? Я понимаю, что все это одни и те же данные с точки зрения программы, но я бы предположил, что ОС также отправит сообщение типа "эй, это каталог".

Ответ 1

Вы не говорите, что ваша система, так что трудно сказать, но в целом, filebuf::open будет возвращать только ошибку, если уровень вашей системы открыт выходит из строя. И я работал в Unix-системах, где вы могли бы open() a каталог; Я даже работал над некоторыми, где вы могли прочитать его после open (по крайней мере, если это локально смонтированная файловая система).

Что касается того, что делать с этим: обо всем, что я могу придумать, - попытаться get первый символ, затем верните его. Но это не удается, если файл пустой, так что это тоже не решение. На системном уровне (и с точки зрения QoI, я ожидал бы filebuf::open сделать это, если система позволила открыть каталог), вы можете использовать вызов системного уровня (stat в Unix), чтобы определить, является ли файл каталогом или нет. (Конечно, есть состояние гонки: между моментом, когда вы обнаруживаете, что это обычный файл, а в тот момент, когда вы открываете, другой процесс может удалить файл и создать каталог. Вероятно, это не частое появление.)