DiogoNeves
DiogoNeves

Reputation: 1777

How to know which file failed during rename?

I have a simple example:

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

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

and I want to distinguish between 2 of the possible failures:

  1. filea doesn't exist
  2. directory for fileb doesn't exist

but it always returns errno = 2 when either doesn't exist... uhm Any ideas how can I approach this?

Thanks

EDIT: If possible without manually checking if the files exist.

EDIT2: Not checking if the file exists is a stupid constraint ;) so, I've accepted one of the answers already. Thanks!

Upvotes: 0

Views: 1345

Answers (4)

Alex Reynolds
Alex Reynolds

Reputation: 96974

I don't know how you're going to check if a file exists without checking if a file exists, but hopefully this function will help you out:

#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;
}

If your goal is to keep the code clean, then just use functions:

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; 
}

You could return custom error codes from renameFiles() and conditionally handle errors based on which file does or does not exist, or if there is some other problem with the rename() call.

Upvotes: 1

undur_gongor
undur_gongor

Reputation: 15954

The ISO C standard does not even require the library function rename to set errno in case of error. All that is guaranteed is a non-zero return value on error (7.19.4.2, §3).

So whether this is possible or not depends on your platform (and it is not portable).

E.g. in Linux there is no way to distinguish which of them is missing by just looking at errno after rename (according to this man page).

Upvotes: 1

fdk1342
fdk1342

Reputation: 3564

If the errno is always 2 ENOENT "No such file or directory" on your system you are going to HAVE to check for the existence of something. On my system I get errno of 2 if old does not existent or if the directory path of new does not exist.

However there is much more then 2 possible errors. The link http://man.chinaunix.net/unix/susv3/functions/rename.html has 20 distinct errno values specified.

I would suggest that if the rename fails and the errno is 2 then check for the existence of old. If found then the problem is that the directory specified in the new doesn't exist.

Upvotes: 0

jim mcnamara
jim mcnamara

Reputation: 16399

Call access() (unistd.h) first. Or stat(). And you are probably getting an ENOENT error when filea does not exist. Some ways you can get an error on fileB:

  1. path cannot be found
  2. no permissions on the path
  3. fileB exists and you do not have permissions
  4. you have a too long or malformed name

There are others but they are not very common.

There is no case where you should get an error when fileB is not there. You execute a mv filea fileb (what rename does) and all of the errors for mv apply here. Missing destination file is not one of them.

You should also have

#include <errno.h>

since you reference errno.

Upvotes: 1

Related Questions