1

This function is supposed to delete all the contents of a folder in Linux, using Linux system calls (stat, readdir, unlink, rmdir, etc.).

It takes the path of a folder as a parameter, and it runs as expected when you call it on a folder that has files or empty folders.

If the target folder contains a subfolder, my function recursively makes another call to itself with that subfolder as the target parameter. This is done to empty all the subfolders before rmdir'ing them - since rmdir() cannot unlink a folder unless it is empty.

However, the recursion aspect does not work. It does delete files in subfolders, but not subfolders themselves.

Possible cause: As the recursion unwinds, the value of itemPath (which I believe should be local to the calling function instance) is altered by the recursive call and changed to the value of itemPath that I thought should be unique to the recursive function instance.

I suspect that I'm misunderstanding something about how C allocates new variables during recursive calls, but I can't figure out how to fix this.

Example run: Debug output

Note that the value of itemPath has changed between "beginning recursive call" and "end of recursion".

Example run is on this directory structure:

/tmp/testPopd/      <--- target parameter for test
/tmp/testPopd/file
/tmp/testPopd/dir/
/tmp/testPopd/dir/subfile
/tmp/testPopd/dir/subdir/

Code:

void deleteContents(const char* targetDir)
{
    printf("func called with %s as parameter\n", targetDir);
    
    // Oper targetDir
    DIR* targetDirstream = opendir(targetDir);
    struct dirent* targetDirent;

    // This loop scans across all items in targetDir
    int numEntries = 0;
    while( ((targetDirent = readdir(targetDirstream)) != NULL) ) 
    {
        // Ensure that we do not delete the first 2 dir entries (. and ..)
        numEntries++;
        if (numEntries <= 2)
            continue;

        // Assemble the directory path and the filename into the full path for the item
        char* itemPath;
        strcpy(itemPath, targetDir);
        strcat(itemPath, "/");
        strcat(itemPath, targetDirent->d_name);

        // Determine if the item is a directory, in order to apply correct system call
        struct stat itemStat;
        stat(itemPath, &itemStat);

        if (S_ISDIR(itemStat.st_mode))      // Item is a directory, recur and remove using rmdir()
        {
            printf("beginning recursive call, var itemPath is %s \n", itemPath);

            // Recur into subfolder to ensure it is empty
            deleteContents(itemPath);
            
            printf("end of recursion, var itemPath is %s \n", itemPath);

            rmdir(itemPath);            
        }
        else                                // Item is a file, remove using unlink()
        {
            printf("deleting file %s \n", itemPath);
            
            unlink(itemPath);
        }
    }

    closedir(targetDirstream);
}
Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
Era J
  • 11
  • 1
  • 7
    You never allocated any memory for `char* itemPath;` so `strcpy(itemPath, targetDir);` causes undefined behavior. – Barmar Aug 30 '22 at 01:15
  • `itemPath` is a pointer. What does it point to? – user253751 Aug 30 '22 at 01:34
  • Either use `malloc` to allocate memory for `itemPath`, or else change it to an array. At it is now, you're writing through an undefined pointer value, so of course you're corrupting memory. Memory corruption bugs are always severe problems that you should always take pains to avoid. – Tom Karzes Aug 30 '22 at 02:12
  • If you try to delete a directory when it is the CWD of another process, the OS will refuse. You're not concerned about return codes from `unlink()` (ownership) or `rmdir()`??? – Fe2O3 Aug 30 '22 at 03:10
  • Rather than "building paths" off in the void, can you not simply `chdir()` and work with the buffers you have? – Fe2O3 Aug 30 '22 at 03:37

0 Answers0