Проверка существования каталога в Unix (системный вызов)

Не могу найти решение своей проблемы в сети.

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

Есть ли удобный способ сделать это, пожалуйста?


person Jary    schedule 30.09.2010    source источник
comment
почему вы написали системный вызов на вопрос? вам действительно нужен системный вызов, который может работать только на одном типе ОС (linux, BSD и т. д.), или функция POSIX из заголовков posix c (которая должна работать на любом дистрибутиве UNIX)?   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 16.06.2013
comment
Если вы ищете дополнительные ответы, которые не зависят от системных вызовов, см. C++ - Определение существования каталога (не файла) в Linux   -  person Roi Danton    schedule 26.08.2018


Ответы (4)


В системах POSIX есть две соответствующие функции: stat() и lstat(). Они используются, чтобы выяснить, относится ли имя пути к фактическому объекту, на доступ к которому у вас есть разрешение, и если да, возвращаемые данные сообщают вам, к какому типу относится этот объект. Разница между stat() и lstat() заключается в том, что если имя, которое вы даете, является символической ссылкой, stat() следует за символической ссылкой (или ссылками, если они связаны вместе) и сообщает об объекте в конце цепочки ссылок, тогда как lstat() сообщает об объекте. сама символическая ссылка.

#include <sys/stat.h>

struct stat sb;

if (stat(pathname, &sb) == 0 && S_ISDIR(sb.st_mode))
{
    ...it is a directory...
}

Если функция указывает, что она прошла успешно, вы используете макрос S_ISDIR() из <sys/stat.h> чтобы определить, действительно ли файл является каталогом.

Вы также можете проверить другие типы файлов, используя другие макросы S_IS*:

  • S_ISDIR каталог
  • S_ISREG обычный файл
  • S_ISCHR символьное устройство
  • S_ISBLK блочное устройство
  • S_ISFIFO ФИФО
  • S_ISLNK символическая ссылка
  • S_ISSOCK розетка

(Некоторые системы также предоставляют несколько других типов файлов; например, S_ISDOOR доступен в Solaris.)

person Jonathan Leffler    schedule 30.09.2010
comment
stat ожидает, что параметр pathname будет char? - person IgorGanapolsky; 14.06.2017
comment
Не char, а char * — строка. Ссылки на спецификацию POSIX для функций показывают, что первым аргументом для stat() и lstat() является const char * restrict pathname. - person Jonathan Leffler; 14.06.2017
comment
проверьте здесь чтобы увидеть больше информации о макросах S_IS* - person m4l490n; 01.02.2020
comment
@ m4l490n: из спецификации POSIX для <sys/stat.h>, как указано в ответе. Он имеет такие определения, как: S_ISBLK(m) — Проверка специального файла блока. - person Jonathan Leffler; 01.02.2020

Вы можете использовать системный вызов stat, передав ему имя каталог в качестве первого аргумента. Если каталог существует, возвращается 0, в противном случае возвращается -1, а для errno будет установлено значение ENOENT.

РЕДАКТИРОВАТЬ:

Если возвращаемое значение равно 0, вам потребуется дополнительная проверка, чтобы убедиться, что аргумент на самом деле является каталогом, а не файлом/символической ссылкой/специальным файлом char/специальным файлом blk/файлом FIFO. Вы можете использовать поле st_mode в stat structure. для этого.

person codaddict    schedule 30.09.2010

Если вас не волнует тип этого объекта файловой системы, access(name, F_OK) проверяет существование чего-то с этим именем. Если вам нужно убедиться, что это каталог, используйте stat() и проверьте тип с помощью макроса S_ISDIR().

person blaze    schedule 30.09.2010
comment
Обратите внимание, что если реальный и эффективный UID не совпадают (вы используете программу setuid), то системные вызовы access() отвечают на вопрос, отличный от stat(). В частности, он проверяет, может ли реальный UID (RUID) получить доступ к файлу, тогда как все остальные системные вызовы работают с действующим UID (EUID), включая opendir(). - person Jonathan Leffler; 03.08.2016
comment
При использовании флага F_OK access() фактически не проверяет права доступа, а только проверяет наличие файла/каталога/и т.д. - person blaze; 04.08.2016
comment
Но даже с F_OK вы можете столкнуться с EACCES, если имя, переданное access(), имеет несколько компонентов пути, а текущий процесс (EUID) не имеет разрешения на поиск одного из ведущих компонентов каталога (поэтому он проверяет наличие простого имени файла ОК , но могут возникнуть проблемы с непростым именем файла). - person Jonathan Leffler; 04.08.2016

Другой простой способ:

int check(unsigned const char type) {
    if(type == DT_REG)
        return 1;
    if(type == DT_DIR)
        return 0;
    return -1;
}

Затем вы можете передать d_type объекта struct dirent* в функцию check.

Если проверка возвращает 1, то этот путь указывает на обычный файл.

Если проверка возвращает 0, то этот путь указывает на каталог.

В противном случае это не файл и не каталог (это может быть блочное устройство/символическая ссылка и т. д.).

person Aishwary Dewangan    schedule 22.08.2018