stat против mkdir с EEXIST

Мне нужно создать папку, если она не существует, поэтому я использую:

bool mkdir_if_not_exist(const char *dir)
{
  bool ret = false;
  if (dir) {
     // first check if folder exists
     struct stat folder_info;
     if (stat(dir, &folder_info) != 0) {
    if (errno == ENOENT) { // create folder
        if (mkdir(dir, S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH) ?!= 0) // 755
        perror("mkdir");
        else
        ret = true;
    } else
         perror("stat");
    } else
         ret = true; ?// dir exists
     }
     return ret;
 }

Папка создается только при первом запуске программы - дальше только проверка. Есть предложение пропустить вызов stat и вызвать mkdir и проверить errno на EEXIST. Дает ли это реальную пользу?


person eugene    schedule 11.06.2011    source источник


Ответы (3)


Что еще более важно, при подходе stat + mkdir возникает состояние гонки: между stat и mkdir другая программа может выполнить mkdir, поэтому ваша mkdir все еще может потерпеть неудачу с EEXIST.

person andrewdski    schedule 11.06.2011

Есть небольшое преимущество. Найдите 'LBYL vs EAFP' или "Посмотрите, прежде чем прыгать" или "Проще Просите прощения, а не разрешения».

Небольшое преимущество заключается в том, что системный вызов stat() должен проанализировать имя каталога и добраться до индексного дескриптора — или в данном случае отсутствующего индексного дескриптора — а затем mkdir() должен сделать то же самое. Конечно, данные, необходимые для mkdir(), уже находятся в пуле буферов ядра, но это все еще требует двух обходов указанного пути вместо одного. Таким образом, в этом случае использование EAFP немного эффективнее, чем использование LBYL, как вы это делаете.

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

Возможно, вам придется иметь дело со случаем, когда strcmp(dir, "/some/where/or/another") == 0, но хотя "/some/where" существует, ни "/some/where/or", ни (по необходимости) "/some/where/or/another" не существуют. Ваш текущий код не обрабатывает отсутствующие каталоги в середине пути. Он просто сообщает ENOENT, о котором сообщит mkdir(). Ваш код, который выглядит, также не проверяет, что dir на самом деле является каталогом - он просто предполагает, что если он существует, то это каталог. Правильная обработка этих вариаций сложнее.

person Jonathan Leffler    schedule 11.06.2011

Аналогично условию гонки со статистикой и mkdir в последовательности ваше решение неверно не только из-за состояния гонки (как уже указывалось в других ответах здесь), но и потому, что вы никогда не проверяете, является ли существующий файл каталогом или нет.

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

Например, посмотрите, как mkdir(1) -p option реализуется в BSD (bin/mkdir/mkdir.c#mkpath в OpenBSD и NetBSD), все из которых на mkdir(2), кажется, немедленно вызывает stat(2) для затем запустите макрос S_ISDIR, чтобы убедиться, что существующий файл является каталогом , а не просто любой другой тип файла.

person cnst    schedule 20.06.2016