Search code examples
cregexrecursionfile-rename

C rename() FileNotFound although file exists


I am doing a recursive walk through directories to rename files. I use a bit of regex here as well as strstr() to find files However, my program is throwing a FileNotFound error when it tries to rename a file even though the file is there. I do check for file permission and it does not hit that error. Can someone explain why it's doing this.

Below is my code. Let's assume I have a bunch of files named bar and I want to rename them foo (Actually it should be bar, AbarBC, file.bar to foo, AfooBC, file.foo, but I just want to focus on this for now):

#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>

void replaceFileName(const char *pattern, const char *replace, char *fileName) {
   regex_t regex;
   int regErr, fileErr;
   char buffer[100];

   // Compile regular expression 
   regErr = regcomp(&regex, pattern, 0);
   if (regErr) {
      fprintf(stderr, "Could not compile regex\n");
      exit(1);
   }

   // Execute regular expression 
   regErr = regexec(&regex, fileName, 0, NULL, 0);
   if (!regErr) { // found match
      printf("%s\n", fileName);
      // rename file
      char *newName = "foo"; 
      // I didn't set newName = replace because of the further implementation 
      // I mentioned above

      fileErr = rename(fileName, newName);
      if (errno == EACCES) { // permission denied
         fprintf(stderr, "Permission denied when reading: %s\n", fileName);
         exit(1);
      }
      else { // other error
         fprintf(stderr, "Error renaming file: %s\n", fileName);
         fprintf(stderr, "%s\n", strerror(errno)); // THROWING ERROR HERE
         exit(1);
      }
   }

   regfree(&regex);
}

void recursiveWalk(const char *pattern, const char *replace, const char *pathName, int level) {
   DIR *dir;
   struct dirent *entry;

   dir = opendir(pathName); // open directory
   if (!dir) {
      fprintf(stderr, "Could not open directory\n");
      return;
   }

   if (!(entry = readdir(dir))) {
      fprintf(stderr, "Could not read directory\n");
      return;
   }

   do {
      if (entry->d_type == DT_DIR) { // found subdirectory
         char path[1024];

         int len = snprintf(path, sizeof(path)-1, "%s/%s", pathName, entry->d_name); // get depth
         path[len] = 0;

         // skip hidden paths
         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
         }

         fprintf(sdtout, "%*s[%s]\n", level*2, "", entry->d_name);
         recursiveWalk(pattern, replace, path, level + 1);
      }
      else { // files
         fprintf(stdout, "%*s- %s\n", level*2, "", entry->d_name);
         replaceFileName(pattern, replace, (char *)entry->d_name);
      }
   } while (entry = readdir(dir));

   closedir(dir);
}

int main(int argn, char *argv[]) {
   int level = 0;
   recursiveWalk("bar", "foo", ".", level);

   return 0;
}

Solution

  • Your walk isn't actually going anywhere.

    it all runs without ever changing directory, it just walks the tree by pathname.

    rename can't find the file because it isn't in the current directory. and you aren't telling replaceFileName what directory the file is actually in.

    probably you want to use chdir() to go into the directories you find and to back out recursively afterwards.

    alternatively you could paste the dirctory name onto the start of the filename or separately pass it to replaceFileName()