about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libnix/archive.cc12
-rw-r--r--src/libnix/exec.cc25
-rw-r--r--src/libnix/references.cc8
-rw-r--r--src/libnix/store.cc4
-rw-r--r--src/libnix/util.cc93
-rw-r--r--src/libnix/util.hh37
6 files changed, 123 insertions, 56 deletions
diff --git a/src/libnix/archive.cc b/src/libnix/archive.cc
index 9039ad7db4..ed57df4c9f 100644
--- a/src/libnix/archive.cc
+++ b/src/libnix/archive.cc
@@ -51,7 +51,7 @@ static void dump(const string & path, DumpSink & sink);
 
 static void dumpEntries(const Path & path, DumpSink & sink)
 {
-    DIR * dir = opendir(path.c_str());
+    AutoCloseDir dir = opendir(path.c_str());
     if (!dir) throw SysError("opening directory " + path);
 
     vector<string> names;
@@ -77,8 +77,6 @@ static void dumpEntries(const Path & path, DumpSink & sink)
         dump(path + "/" + *it, sink);
         writeString(")", sink);
     }
-    
-    closedir(dir); /* !!! close on exception */
 }
 
 
@@ -88,7 +86,7 @@ static void dumpContents(const Path & path, unsigned int size,
     writeString("contents", sink);
     writeInt(size, sink);
 
-    int fd = open(path.c_str(), O_RDONLY);
+    AutoCloseFD fd = open(path.c_str(), O_RDONLY);
     if (fd == -1) throw SysError(format("opening file `%1%'") % path);
     
     unsigned char buf[65536];
@@ -105,8 +103,6 @@ static void dumpContents(const Path & path, unsigned int size,
         throw SysError("file changed while reading it: " + path);
 
     writePadding(size, sink);
-
-    close(fd); /* !!! close on exception */
 }
 
 
@@ -262,7 +258,7 @@ static void restore(const Path & path, RestoreSource & source)
     if (s != "(") throw badArchive("expected open tag");
 
     enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown;
-    int fd = -1; /* !!! close on exception */
+    AutoCloseFD fd;
 
     while (1) {
         s = readString(source);
@@ -326,8 +322,6 @@ static void restore(const Path & path, RestoreSource & source)
         }
         
     }
-
-    if (fd != -1) close(fd);
 }
 
 
diff --git a/src/libnix/exec.cc b/src/libnix/exec.cc
index 2e092b2e0d..a51b605d81 100644
--- a/src/libnix/exec.cc
+++ b/src/libnix/exec.cc
@@ -11,29 +11,6 @@
 #include "globals.hh"
 
 
-class AutoDelete
-{
-    string path;
-    bool del;
-public:
-
-    AutoDelete(const string & p) : path(p) 
-    {
-        del = true;
-    }
-
-    ~AutoDelete()
-    {
-        if (del) deletePath(path);
-    }
-
-    void cancel()
-    {
-        del = false;
-    }
-};
-
-
 static string pathNullDevice = "/dev/null";
 
 
@@ -140,5 +117,3 @@ void runProgram(const string & program,
         throw Error("unable to build package");
     }
 }
-
-
diff --git a/src/libnix/references.cc b/src/libnix/references.cc
index be432665b8..ab743f76d2 100644
--- a/src/libnix/references.cc
+++ b/src/libnix/references.cc
@@ -36,7 +36,7 @@ void checkPath(const string & path,
         throw SysError(format("getting attributes of path `%1%'") % path);
 
     if (S_ISDIR(st.st_mode)) {
-        DIR * dir = opendir(path.c_str());
+        AutoCloseDir dir = opendir(path.c_str());
 
         struct dirent * dirent;
         while (errno = 0, dirent = readdir(dir)) {
@@ -45,15 +45,13 @@ void checkPath(const string & path,
             search(name, ids, seen);
             checkPath(path + "/" + name, ids, seen);
         }
-
-        closedir(dir); /* !!! close on exception */
     }
 
     else if (S_ISREG(st.st_mode)) {
         
         debug(format("checking `%1%'") % path);
 
-        int fd = open(path.c_str(), O_RDONLY);
+        AutoCloseFD fd = open(path.c_str(), O_RDONLY);
         if (fd == -1) throw SysError(format("opening file `%1%'") % path);
 
         unsigned char * buf = new unsigned char[st.st_size];
@@ -63,8 +61,6 @@ void checkPath(const string & path,
         search(string((char *) buf, st.st_size), ids, seen);
         
         delete buf; /* !!! autodelete */
-
-        close(fd); /* !!! close on exception */
     }
     
     else if (S_ISLNK(st.st_mode)) {
diff --git a/src/libnix/store.cc b/src/libnix/store.cc
index 2d223313b6..c40d9efbeb 100644
--- a/src/libnix/store.cc
+++ b/src/libnix/store.cc
@@ -304,14 +304,12 @@ void addTextToStore(const Path & dstPath, const string & s)
 
         /* !!! locking? -> parallel writes are probably idempotent */
 
-        int fd = open(dstPath.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666);
+        AutoCloseFD fd = open(dstPath.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0666);
         if (fd == -1) throw SysError(format("creating store file `%1%'") % dstPath);
 
         if (write(fd, s.c_str(), s.size()) != (ssize_t) s.size())
             throw SysError(format("writing store file `%1%'") % dstPath);
 
-        close(fd); /* !!! close on exception */
-
         Transaction txn(nixDB);
         registerValidPath(txn, dstPath);
         txn.commit();
diff --git a/src/libnix/util.cc b/src/libnix/util.cc
index c1d0fedea8..016ee991a4 100644
--- a/src/libnix/util.cc
+++ b/src/libnix/util.cc
@@ -118,17 +118,17 @@ void deletePath(const Path & path)
 
     if (S_ISDIR(st.st_mode)) {
 	Strings names;
+        
+        {
+            AutoCloseDir dir = opendir(path.c_str());
 
-        DIR * dir = opendir(path.c_str());
-
-        struct dirent * dirent;
-        while (errno = 0, dirent = readdir(dir)) {
-            string name = dirent->d_name;
-            if (name == "." || name == "..") continue;
-	    names.push_back(name);
-        }
-
-        closedir(dir); /* !!! close on exception */
+            struct dirent * dirent;
+            while (errno = 0, dirent = readdir(dir)) {
+                string name = dirent->d_name;
+                if (name == "." || name == "..") continue;
+                names.push_back(name);
+            }
+        } /* scoped to ensure that dir is closed at this point */
 
 	/* Make the directory writable. */
 	if (!(st.st_mode & S_IWUSR)) {
@@ -157,7 +157,7 @@ void makePathReadOnly(const Path & path)
     }
 
     if (S_ISDIR(st.st_mode)) {
-        DIR * dir = opendir(path.c_str());
+        AutoCloseDir dir = opendir(path.c_str());
 
         struct dirent * dirent;
         while (errno = 0, dirent = readdir(dir)) {
@@ -165,8 +165,6 @@ void makePathReadOnly(const Path & path)
             if (name == "." || name == "..") continue;
 	    makePathReadOnly(path + "/" + name);
         }
-
-        closedir(dir); /* !!! close on exception */
     }
 }
 
@@ -251,3 +249,72 @@ void writeFull(int fd, const unsigned char * buf, size_t count)
         buf += res;
     }
 }
+
+
+AutoDelete::AutoDelete(const string & p) : path(p)
+{
+    del = true;
+}
+
+AutoDelete::~AutoDelete()
+{
+    if (del) deletePath(path);
+}
+
+void AutoDelete::cancel()
+{
+    del = false;
+}
+
+
+AutoCloseFD::AutoCloseFD()
+{
+    fd = -1;
+}
+
+AutoCloseFD::AutoCloseFD(int fd)
+{
+    this->fd = fd;
+}
+
+AutoCloseFD::~AutoCloseFD()
+{
+    if (fd != -1) close(fd);
+}
+
+void AutoCloseFD::operator =(int fd)
+{
+    this->fd = fd;
+}
+
+AutoCloseFD::operator int()
+{
+    return fd;
+}
+
+
+AutoCloseDir::AutoCloseDir()
+{
+    dir = 0;
+}
+
+AutoCloseDir::AutoCloseDir(DIR * dir)
+{
+    this->dir = dir;
+}
+
+AutoCloseDir::~AutoCloseDir()
+{
+    if (dir) closedir(dir);
+}
+
+void AutoCloseDir::operator =(DIR * dir)
+{
+    this->dir = dir;
+}
+
+AutoCloseDir::operator DIR *()
+{
+    return dir;
+}
+
diff --git a/src/libnix/util.hh b/src/libnix/util.hh
index 016289176b..02a9b7fcb8 100644
--- a/src/libnix/util.hh
+++ b/src/libnix/util.hh
@@ -6,6 +6,8 @@
 #include <set>
 #include <sstream>
 
+#include <sys/types.h>
+#include <dirent.h>
 #include <unistd.h>
 
 #include <boost/format.hpp>
@@ -113,4 +115,39 @@ void readFull(int fd, unsigned char * buf, size_t count);
 void writeFull(int fd, const unsigned char * buf, size_t count);
 
 
+/* Automatic cleanup of resources. */
+
+class AutoDelete
+{
+    string path;
+    bool del;
+public:
+    AutoDelete(const string & p);
+    ~AutoDelete();
+    void cancel();
+};
+
+class AutoCloseFD
+{
+    int fd;
+public:
+    AutoCloseFD();
+    AutoCloseFD(int fd);
+    ~AutoCloseFD();
+    void operator =(int fd);
+    operator int();
+};
+
+class AutoCloseDir
+{
+    DIR * dir;
+public:
+    AutoCloseDir();
+    AutoCloseDir(DIR * dir);
+    ~AutoCloseDir();
+    void operator =(DIR * dir);
+    operator DIR *();
+};
+
+
 #endif /* !__UTIL_H */