Jeff
Jeff

Reputation: 27

Problems with removing directories and files recursively

I am trying to remove all files and subdirectories from my command line interpreter. When the call is made to rmdir -s newFolder, i call a function removeAll which goes through all files and subfolders and deletes all the files.

For example if i want to delete the file newFolder, i delete all the files and go into newFolder1. I delete all the files in newFolder1 and go into newFolder2 and delete all the files. So now i am in newFolder 2 and newFolder, newFolder1, and newFolder2 are empty.

My question is how do i recurse back up and delete these 3 empty folders. I have debugged and worked on this for several hours and i am just not getting it. Thank you

This is the function that will successfully delete one empty folder, otherwise it calls removeAll.

void MyShell::rmdir () {
//Error Check
if(argc != 3) {
    printf("USAGE: rmdir [-s] <directory>\n");      
    return;
}
else if(stricmp(cwd, argv[2]) == 0){
    printf("Cannot remove the current working directory");
    return;
}
if(_rmdir(argv[2]) == 0)
    return;

removeAll(argv[2]); 

}

The function removeAll successfully deletes all files in all subfolders

void removeAll(char *path)
{
    _chdir(path);

    _finddata_t data;

    intptr_t handle = _findfirst("*", &data);

    if(handle == -1)
    {
        return;
    }

    do 
    {
        if (strcmp(data.name, ".") == 0 || strcmp(data.name, "..") == 0)
        {
            continue;
        }

        remove(data.name);

        if(data.attrib & _A_SUBDIR)
        {
            removeAll(data.name);
        }

    } while(_findnext(handle, &data) != -1);

    _findclose(handle); 
}

My idea to recurse back up and delete all subfolders was to call a method after it breaks from the findnext loop

void removeDirectory(char *path)
{
    _finddata_t data;

    intptr_t handle = _findfirst("*", &data);

    if(handle == -1)
    {
        return;
    }

    do 
    {
        if (strcmp(data.name, ".") == 0 || strcmp(data.name, "..") == 0)
        {
            continue;
        }


        if(data.attrib & _A_SUBDIR)
        {
            if(_rmdir(data.name) == 0)
            {
                _chdir("..");
                removeDirectory(path);
            }

        }

    } while(_findnext(handle, &data) != -1);

    _findclose(handle); 
}

Upvotes: 0

Views: 1051

Answers (2)

Egg
Egg

Reputation: 2066

Assuming that remove() will remove empty directories as well as files, you should just need to rearrange the code to this:

do 
{
    if (strcmp(data.name, ".") == 0 || strcmp(data.name, "..") == 0)
    {
        continue;
    }

    if(data.attrib & _A_SUBDIR)
    {
        removeAll(data.name);
    }

    remove(data.name);

} while(_findnext(handle, &data) != -1);

Basically, your recursive function should follow this pseudocode:

void deleteAll(path)
{
    for each file in path
    {
        if file is folder
        {
            // empty the folder
            deleteAll(file)
        }

        delete file // whether it is a now-empty folder or a file
    }
}

That way, when you encounter a folder, you immediately enter it and delete its contents and then return to the scope of its parent folder, where you can now delete it because it is empty.

Upvotes: 1

Chris Ryding
Chris Ryding

Reputation: 1533

The whole point of recursion is that you don't have to go "back up". Each iteration of the recursed routine should handle only its own level and then either call itself again or break out. It looks like you almost had it done. Try something like this for your RemoveAll routine:

void removeAll(char *path)
{
    _chdir(path);

    _finddata_t data;

    intptr_t handle = _findfirst("*", &data);

    if(handle == -1)
    {
        return;
    }

    while(_findnext(handle, &data) != -1)   // changed from do..while to just while
    {
        if (strcmp(data.name, ".") == 0 || strcmp(data.name, "..") == 0)
        {
            continue;
        }

        if(data.attrib & _A_SUBDIR)
        {
            removeAll(data.name);
            _rmdir(data.name);    // <- moved this to here
        }
        else
        {
            remove(data.name);
        }
    }

    _findclose(handle); 
}

Upvotes: 1

Related Questions