[libvirt] [PATCH 03/18] Introduce a virFileDeleteTree method

Daniel P. Berrange berrange at redhat.com
Mon Apr 8 14:04:31 UTC 2013


On Thu, Apr 04, 2013 at 11:56:29AM -0600, Eric Blake wrote:
> On 04/04/2013 07:40 AM, Daniel P. Berrange wrote:
> > From: "Daniel P. Berrange" <berrange at redhat.com>
> > 
> > Introduce a method virFileDeleteTree for recursively deleting
> > an entire directory tree
> > 
> > Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> > ---
> >  src/libvirt_private.syms |  1 +
> >  src/util/virfile.c       | 78 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  src/util/virfile.h       |  2 ++
> >  3 files changed, 81 insertions(+)
> 
> Don't we already have something like this?
> 
> /me goes and looks...
> 
> yep, very similar to virCgroupRemoveRecursively - hopefully a later
> patch drops that function to use this instead.  I like the idea of a
> generalized interface.
> 
> > + * virFileDeleteTree:
> > + *
> > + * Recursively deletes all files / directories
> > + * starting from the directory @dir. Does not
> > + * follow symlinks
> > + */
> > +int virFileDeleteTree(const char *dir)
> > +{
> > +    DIR *dh = opendir(dir);
> > +    struct dirent *de;
> > +    char *filepath = NULL;
> > +    int ret = -1;
> > +
> > +    if (!dh) {
> > +        virReportSystemError(errno, _("Cannot open dir '%s'"),
> > +                             dir);
> > +        return -1;
> > +    }
> > +
> > +    errno = 0;
> > +    while ((de = readdir(dh)) != NULL) {
> > +        struct stat sb;
> > +
> > +        if (STREQ(de->d_name, ".") ||
> > +            STREQ(de->d_name, ".."))
> > +            continue;
> > +
> > +        if (virAsprintf(&filepath, "%s/%s",
> > +                        dir, de->d_name) < 0) {
> > +            virReportOOMError();
> > +            goto cleanup;
> > +        }
> 
> We should use gnulib's LGPL unlinkat.  On capable kernels, it avoids
> O(n^2) behavior that is inherent in computing filenames in a deep
> hierarchy.  On less capable kernels, it still makes this code simpler to
> write (no virAsprintf needed here).

I looked into unlinkat() but that gnulib module is GPL only.

> 
> > +
> > +        if (lstat(filepath, &sb) < 0) {
> > +            virReportSystemError(errno, _("Cannot access '%s'"),
> > +                                 filepath);
> > +            goto cleanup;
> > +        }
> 
> Potentially wasteful on systems like Linux that have d_type.  If d_type
> exists, and is not DT_UNKNOWN, then the difference between DT_DIR and
> other types can save some system call efforts.
> 
> Potential TOCTTOU race.  POSIX allows unlink("dir") to succeed (although
> most platforms reject it, either always [Linux], or based on
> capabilities [Solaris, which also has code to give up that capability,
> and where gnulib also exposes that]).  If we ever manage to unlink() a
> directory, because we lost the TOCTTOU race, then we have done bad
> things to the file system.
> 
> But you are guaranteed that rmdir() on a non-directory will gracefully
> fail; so you can minimize the race window by attempting to treat _every_
> name as a directory first, then gracefully fall back to unlink() if the
> opendir() fails with ENOTDIR, without ever having to waste time
> lstat()ing things.  Hmm, except that you don't want to follow symlinks,
> but opendir() follows them by default; so you would have to use
> open(O_DIRECTORY)/fdopendir() instead of raw opendir().

I also looked at fdopendir() but we'd want gnulib for portability
of that, and again it is GPL only.

> Very weak ACK, depending on what you answer to my commentary.

I would like to make some of the enhancements you suggest, but doing
so would require we implement a bunch of portability code since all
the things you suggest are Linux specific and the gnulib modules are
GPL only.  So I think in the immediate term, we'll just have to go
with that I have here.


Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list