Как узнать, какой файл не удалось переименовать? - PullRequest
0 голосов
/ 02 февраля 2012

У меня есть простой пример:

#include <stdio.h>
#include <errno.h>

int main() {
  int result = rename("filea", "doesntexist/fileb");
  if (result != 0) {
    printf("NOOOO %d\n", errno);
  }
  return 0;
}

, и я хочу различить 2 возможных отказа:

  1. filea не существует
  2. директории для fileb не существует

, но она всегда возвращает errno = 2, когда ни одна из них не существует ... хм Есть идеи, как я могу подойти к этому?

Спасибо

РЕДАКТИРОВАТЬ: Если возможно, не проверяя вручную, существуют ли файлы.

EDIT2: Не проверять, существует ли файл, глупое ограничение;) так что,Я уже принял один из ответов.Спасибо!

Ответы [ 4 ]

1 голос
/ 02 февраля 2012

Стандарт ISO C даже не требует от библиотечной функции rename установки errno в случае ошибки.Все, что гарантировано, это ненулевое возвращаемое значение при ошибке (7.19.4.2, §3).

Так что, возможно это или нет, зависит от вашей платформы (и она не переносима).

Например, в Linux нет способа определить, какой из них отсутствует, просто взглянув на errno после rename (согласно этой справочной странице ).

1 голос
/ 02 февраля 2012

Сначала позвоните access() (unistd.h). Или stat(). И вы, вероятно, получаете ошибку ENOENT, когда filea не существует. Несколько способов получить сообщение об ошибке в файле B:

  1. путь не найден
  2. нет разрешений на пути
  3. файлB существует, и у вас нет прав
  4. у вас слишком длинное или искаженное имя

Есть и другие, но они не очень распространены.

Ни в одном случае вы не получите сообщение об ошибке, если fileB отсутствует. Вы выполняете fileb mv filea (что делает rename), и все ошибки для mv применяются здесь. Отсутствующий файл назначения не является одним из них.

Вы также должны иметь

#include <errno.h>

, так как вы ссылаетесь errno.

1 голос
/ 02 февраля 2012

Я не знаю, как вы собираетесь проверить, существует ли файл, не проверяя, существует ли файл, но, надеюсь, эта функция поможет вам:

#include <sys/stat.h>

if (!fileExists("foo")) { /* foo does not exist */ }

int fileExists (const char *fn)
{
    struct stat buf;
    int i = stat(fn, &buf);
    if (i == 0)
        return 1; /* file found */
    return 0;
}

Если ваша цель - сохранить код в чистоте, просто используйте функции:

int main() 
{
    if (! renameFiles("fileA", "fileB")) { 
        fprintf(stderr, "rename failed...\n"); 
        exit EXIT_FAILURE; 
    }
    return EXIT_SUCCESS;
}

int renameFiles(const char *source, const char *destination)
{
    int result = -1;

    if ( (fileExists(source)) && (!fileExists(destination)) )
        result = rename(source, destination);

    if (result == 0)
        return 1; /* rename succeeded */

    /* 
        Either `source` does not exist, or `destination` 
        already exists, or there is some other error (take 
        a look at `errno` and handle appropriately)
    */

    return 0; 
}

Вы можете возвращать пользовательские коды ошибок из renameFiles() и условно обрабатывать ошибки, основываясь на том, какой файл существует или не существует, или если есть какая-то другая проблема с вызовом rename().

0 голосов
/ 02 февраля 2012

Если значение errno всегда равно 2 ENOENT «Нет такого файла или каталога» в вашей системе, вы собираетесь ДОЛЖНЫ проверить наличие чего-либо.В моей системе я получаю errno 2, если old не существует или если путь к каталогу new не существует.

Однако существует гораздо больше, чем 2 возможныхошибки.В ссылке http://man.chinaunix.net/unix/susv3/functions/rename.html указано 20 различных значений errno.

Я бы предложил, чтобы при переименовании произошел сбой и значение errno равнялось 2, тогда проверяли наличие old .Если найдено, то проблема в том, что каталог, указанный в new , не существует.

...