Removing a non empty directory programmatically in C or C++

C++C

C++ Problem Overview


How to delete a non empty directory in C or C++? Is there any function? rmdir only deletes empty directory. Please provide a way without using any external library.

Also tell me how to delete a file in C or C++?

C++ Solutions


Solution 1 - C++

You want to write a function (a recursive function is easiest, but can easily run out of stack space on deep directories) that will enumerate the children of a directory. If you find a child that is a directory, you recurse on that. Otherwise, you delete the files inside. When you are done, the directory is empty and you can remove it via the syscall.

To enumerate directories on Unix, you can use opendir(), readdir(), and closedir(). To remove you use rmdir() on an empty directory (i.e. at the end of your function, after deleting the children) and unlink() on a file. Note that on many systems the d_type member in struct dirent is not supported; on these platforms, you will have to use stat() and S_ISDIR(stat.st_mode) to determine if a given path is a directory.

On Windows, you will use FindFirstFile()/FindNextFile() to enumerate, RemoveDirectory() on empty directories, and DeleteFile() to remove files.

Here's an example that might work on Unix (completely untested):

int remove_directory(const char *path) {
   DIR *d = opendir(path);
   size_t path_len = strlen(path);
   int r = -1;

   if (d) {
      struct dirent *p;

      r = 0;
      while (!r && (p=readdir(d))) {
          int r2 = -1;
          char *buf;
          size_t len;

          /* Skip the names "." and ".." as we don't want to recurse on them. */
          if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
             continue;

          len = path_len + strlen(p->d_name) + 2; 
          buf = malloc(len);
          
          if (buf) {
             struct stat statbuf;

             snprintf(buf, len, "%s/%s", path, p->d_name);
             if (!stat(buf, &statbuf)) {
                if (S_ISDIR(statbuf.st_mode))
                   r2 = remove_directory(buf);
                else
                   r2 = unlink(buf);
             }
             free(buf);
          }
          r = r2;
      }
      closedir(d);
   }

   if (!r)
      r = rmdir(path);

   return r;
}

Solution 2 - C++

Many unix-like systems (Linux, the BSDs, and OS X, at the very least) have the fts functions for directory traversal.

To recursively delete a directory, perform a depth-first traversal (without following symlinks) and remove every visited file:

int recursive_delete(const char *dir)
{
    int ret = 0;
    FTS *ftsp = NULL;
    FTSENT *curr;

    // Cast needed (in C) because fts_open() takes a "char * const *", instead
    // of a "const char * const *", which is only allowed in C++. fts_open()
    // does not modify the argument.
    char *files[] = { (char *) dir, NULL };

    // FTS_NOCHDIR  - Avoid changing cwd, which could cause unexpected behavior
    //                in multithreaded programs
    // FTS_PHYSICAL - Don't follow symlinks. Prevents deletion of files outside
    //                of the specified directory
    // FTS_XDEV     - Don't cross filesystem boundaries
    ftsp = fts_open(files, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL);
    if (!ftsp) {
        fprintf(stderr, "%s: fts_open failed: %s\n", dir, strerror(errno));
        ret = -1;
        goto finish;
    }

    while ((curr = fts_read(ftsp))) {
        switch (curr->fts_info) {
        case FTS_NS:
        case FTS_DNR:
        case FTS_ERR:
            fprintf(stderr, "%s: fts_read error: %s\n",
                    curr->fts_accpath, strerror(curr->fts_errno));
            break;

        case FTS_DC:
        case FTS_DOT:
        case FTS_NSOK:
            // Not reached unless FTS_LOGICAL, FTS_SEEDOT, or FTS_NOSTAT were
            // passed to fts_open()
            break;

        case FTS_D:
            // Do nothing. Need depth-first search, so directories are deleted
            // in FTS_DP
            break;

        case FTS_DP:
        case FTS_F:
        case FTS_SL:
        case FTS_SLNONE:
        case FTS_DEFAULT:
            if (remove(curr->fts_accpath) < 0) {
                fprintf(stderr, "%s: Failed to remove: %s\n",
                        curr->fts_path, strerror(curr->fts_errno));
                ret = -1;
            }
            break;
        }
    }

finish:
    if (ftsp) {
        fts_close(ftsp);
    }

    return ret;
}

Solution 3 - C++

If you are using a POSIX compliant OS, you could use nftw() for file tree traversal and remove (removes files or directories). If you are in C++ and your project uses boost, it is not a bad idea to use the Boost.Filesystem as suggested by Manuel.

In the code example below I decided not to traverse symbolic links and mount points (just to avoid a grand removal:) ):

#include <stdio.h>
#include <stdlib.h>
#include <ftw.h>

static int rmFiles(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
{
	if(remove(pathname) < 0)
	{
		perror("ERROR: remove");
		return -1;
	}
    return 0;
}

int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		fprintf(stderr,"usage: %s path\n",argv[0]);
		exit(1);
	}

	// Delete the directory and its contents by traversing the tree in reverse order, without crossing mount boundaries and symbolic links

	if (nftw(argv[1], rmFiles,10, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
	{
		perror("ERROR: ntfw");
		exit(1);
	}

	return 0;
}

Solution 4 - C++

The easiest way to do this is with remove_all function of the Boost.Filesystem library. Besides, the resulting code will be portable.

If you want to write something specific for Unix (rmdir) or for Windows (RemoveDirectory) then you'll have to write a function that deletes are subfiles and subfolders recursively.

EDIT

Looks like this question was already asked, in fact someone already recommended Boost's remove_all. So please don't upvote my answer.

Solution 5 - C++

C++17 has <experimental\filesystem> which is based on the boost version.

Use std::experimental::filesystem::remove_all to remove recursively.

If you need more control, try std::experimental::filesystem::recursive_directory_iterator.

You can also write your own recursion with the non-resursive version of the iterator.

namespace fs = std::experimental::filesystem;
void IterateRecursively(fs::path path)
{
  if (fs::is_directory(path))
  {
    for (auto & child : fs::directory_iterator(path))
      IterateRecursively(child.path());
  }

  std::cout << path << std::endl;
}

Solution 6 - C++

You can use opendir and readdir to read directory entries and unlink to delete them.

Solution 7 - C++

//======================================================
// Recursely Delete files using:
//   Gnome-Glib & C++11
//======================================================

#include <iostream>
#include <string>
#include <glib.h>
#include <glib/gstdio.h>

using namespace std;

int DirDelete(const string& path)
{
   const gchar*    p;
   GError*   gerr;
   GDir*     d;
   int       r;
   string    ps;
   string    path_i;
   cout << "open:" << path << "\n";
   d        = g_dir_open(path.c_str(), 0, &gerr);
   r        = -1;

   if (d) {
      r = 0;

      while (!r && (p=g_dir_read_name(d))) {
          ps = string{p};
		  if (ps == "." || ps == "..") {
		    continue;
		  }

		  path_i = path + string{"/"} + p;


		  if (g_file_test(path_i.c_str(), G_FILE_TEST_IS_DIR) != 0) {
		    cout << "recurse:" << path_i << "\n";
  		    r = DirDelete(path_i);
		  }
		  else {
		    cout << "unlink:" << path_i << "\n";
            r = g_unlink(path_i.c_str());
		  }
      }

      g_dir_close(d);
   }

   if (r == 0) {
      r = g_rmdir(path.c_str());
     cout << "rmdir:" << path << "\n";

   }

   return r;
}

Solution 8 - C++

How to delete a non empty folder using unlinkat() in c?

Here is my work on it:

    /*
     * Program to erase the files/subfolders in a directory given as an input
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <dirent.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    void remove_dir_content(const char *path)
    {
    	struct dirent *de;
    	char fname[300];
      	DIR *dr = opendir(path);
    	if(dr == NULL)
    	{
    		printf("No file or directory found\n");
    		return;
    	}
    	while((de = readdir(dr)) != NULL)
    	{
    		int ret = -1;
    		struct stat statbuf;
    		sprintf(fname,"%s/%s",path,de->d_name);
    		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
                		continue;
    		if(!stat(fname, &statbuf))
    		{
    			if(S_ISDIR(statbuf.st_mode))
    			{
    				printf("Is dir: %s\n",fname);
    				printf("Err: %d\n",ret = unlinkat(dirfd(dr),fname,AT_REMOVEDIR));
    				if(ret != 0)
    				{
    					remove_dir_content(fname);
    					printf("Err: %d\n",ret = unlinkat(dirfd(dr),fname,AT_REMOVEDIR));
    				}
    			}
    			else
    			{
    				printf("Is file: %s\n",fname);
            		printf("Err: %d\n",unlink(fname));
    			}
    		}
    	}
    	closedir(dr);
    }
    void main()
    {
    	char str[10],str1[20] = "../",fname[300]; // Use str,str1 as your directory path where it's files & subfolders will be deleted.
    	printf("Enter the dirctory name: ");
    	scanf("%s",str);
    	strcat(str1,str);
    	printf("str1: %s\n",str1);
    	remove_dir_content(str1); //str1 indicates the directory path
    }

Solution 9 - C++

This code will open particular directory and iterate over all files and delete them which are under that directory. After that it will delete empty directory at the end.

/**
 * @file RemoveDir.c
 * @author Om Patel ([email protected])
 * @brief This program will remove non empty directory.  
 * @version 0.1
 * @date 2022-05-31
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include <unistd.h>

int main()
{
    DIR* dir = opendir("OUTPUT/Aakash");
    struct dirent* entity;
    entity = readdir(dir);
    while(entity != NULL){
        char path[30] ="OUTPUT/Aakash/";
        printf("%s\n",entity->d_name);
        strcat(path,entity->d_name);
        printf("PAth: %s\n",path);
        remove(path);
        entity = readdir(dir);
    }
    char path1[30] ="OUTPUT/Aakash";
    rmdir(path1);
    closedir(dir);
    char out[20]="OUTPUT/";
                char fol_file[30];
            sprintf(fol_file,"%s\\",out);
            printf("%s",fol_file);
    return 0;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionavdView Question on Stackoverflow
Solution 1 - C++asveikauView Answer on Stackoverflow
Solution 2 - C++Andrew GunnersonView Answer on Stackoverflow
Solution 3 - C++marcmagransdeabrilView Answer on Stackoverflow
Solution 4 - C++ManuelView Answer on Stackoverflow
Solution 5 - C++greedy52View Answer on Stackoverflow
Solution 6 - C++diciuView Answer on Stackoverflow
Solution 7 - C++BimoView Answer on Stackoverflow
Solution 8 - C++Samson PraneethView Answer on Stackoverflow
Solution 9 - C++OM PATELView Answer on Stackoverflow