How to walk a directory in C
Asked Answered
S

5

8

I am using glib in my application, and I see there are convenience wrappers in glib for C's remove, unlink and rmdir. But these only work on a single file or directory at a time.

As far as I can see, neither the C standard nor glib include any sort of recursive directory walk functionality. Nor do I see any specific way to delete an entire directory tree at once, as with rm -rf.

For what I'm doing this I'm not worried about any complications like permissions, symlinks back up the tree (infinite recursion), or anything that would rule out a very naive implementation... so I am not averse to writing my own function for it.

However, I'm curious if this functionality is out there somewhere in the standard libraries gtk or glib (or in some other easily reused C library) already and I just haven't stumbled on it. Googling this topic generates a lot of false leads.

Otherwise my plan is to use this type of algorithm:

dir_walk(char* path, void* callback(char*) {
  if(is_dir(path) && has_entries(path)) {
    entries = get_entries(path);
    for(entry in intries) { dir_walk(entry, callback); }
  }
  else { callback(path) }
}

dir_walk("/home/user/trash", remove);

Obviously I would build in some error handling and the like to abort the process as soon as a fatal error is encountered.

Soap answered 7/2, 2010 at 17:18 Comment(3)
technically only remove() is in the C standard, the other 2 are POSIX :)Baptism
In addition to the existing answers, please note that one does not simply walk a directory into Mordor, be it in C or any other language.Lindsy
In addition to the existing answers, i would like to point out that robust code should not use recursion. Use iteration and a stack instead.Eversole
C
5

You can use GFileEnumerator if you want to do it with glib.

Churchgoer answered 7/2, 2010 at 17:24 Comment(2)
Is a GFileEnumerator recursive? I read the documentation but it does not mention this. Of course, I can try it and find out...Soap
No it's not. There are few tutorials available but you should take a look at gezeiten.org/post/2009/04/Writing-Your-Own-GIO-Jobs, which shows recursive file listing (search for "g_file_deep_count").Churchgoer
L
7

Have you looked at <dirent.h>? AFAIK this belongs to the POSIX specification, which should be part of the standard library of most, if not all C compilers. See e.g. this <dirent.h> reference (Single UNIX specification Version 2 by the Open Group).

P.S., before someone comments on this: No, this does not offer recursive directory traversal. But then I think this is best implemented by the developer; requirements can differ quite a lot, so one-size-fits-all recursive traversal function would have to be very powerful. (E.g.: Are symlinks followed up? Should recursion depth be limited? etc.)

Lying answered 7/2, 2010 at 17:24 Comment(1)
On windows it's opendir/closedir and the like. Or FindFirstFile FindNextFile.Secession
C
5

You can use GFileEnumerator if you want to do it with glib.

Churchgoer answered 7/2, 2010 at 17:24 Comment(2)
Is a GFileEnumerator recursive? I read the documentation but it does not mention this. Of course, I can try it and find out...Soap
No it's not. There are few tutorials available but you should take a look at gezeiten.org/post/2009/04/Writing-Your-Own-GIO-Jobs, which shows recursive file listing (search for "g_file_deep_count").Churchgoer
C
5

Several platforms include ftw and nftw: "(new) file tree walk". Checking the man page on an imac shows that these are legacy, and new users should prefer fts. Portability may be an issue with either of these choices.

Chasechaser answered 7/2, 2010 at 17:32 Comment(0)
R
3

Standard C libraries are meant to provide primitive functionality. What you are talking about is composite behavior. You can easily implement it using the low level features present in your API of choice -- take a look at this tutorial.

Reina answered 7/2, 2010 at 17:21 Comment(0)
P
-1

Note that the "convenience wrappers" you mention for remove(), unlink() and rmdir(), assuming you mean the ones declared in <glib/gstdio.h>, are not really "convenience wrappers". What is the convenience in prefixing totally standard functions with a "g_"? (And note that I say this even if I who introduced them in the first place.)

The only reason these wrappers exist is for file name issues on Windows, where these wrappers actually consist of real code; they take file name arguments in Unicode, encoded in UTF-8. The corresponding "unwrapped" Microsoft C library functions take file names in system codepage.

If you aren't specifically writing code intended to be portable to Windows, there is no reason to use the g_remove() etc wrappers.

Peterec answered 15/2, 2010 at 10:46 Comment(1)
The convenience is that the g_ versions handle the cases you discuss. Since I am using glib and gtk for many other things it does make sense to be consistent and use the g_ functions. Not doing so makes it certain that my code will not be portable. I did not mean to imply that the g_ versions did nothing more than call the standard library.Soap

© 2022 - 2024 — McMap. All rights reserved.