Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c

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++?

like image 842
avd Avatar asked Feb 13 '10 08:02

avd


2 Answers

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; } 
like image 39
Andrew Gunnerson Avatar answered Sep 23 '22 02:09

Andrew Gunnerson


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; } 
like image 133
asveikau Avatar answered Sep 23 '22 02:09

asveikau