Add a cache around getpwuid/getgrgid to avoid repeated calls.
[cumulus.git] / main.cc
diff --git a/main.cc b/main.cc
index 8af3175..c700173 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -18,8 +18,8 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-/* Main entry point for LBS.  Contains logic for traversing the filesystem and
- * constructing a backup. */
+/* Main entry point for Cumulus.  Contains logic for traversing the filesystem
+ * and constructing a backup. */
 
 #include <dirent.h>
 #include <errno.h>
@@ -41,6 +41,7 @@
 #include <fstream>
 #include <iostream>
 #include <list>
+#include <map>
 #include <set>
 #include <sstream>
 #include <string>
@@ -55,6 +56,7 @@
 #include "util.h"
 
 using std::list;
+using std::map;
 using std::string;
 using std::vector;
 using std::ostream;
@@ -327,6 +329,39 @@ int64_t dumpfile(int fd, dictionary &file_info, const string &path,
     return size;
 }
 
+/* Look up a user/group and convert it to string form (either strictly numeric
+ * or numeric plus symbolic).  Caches the results of the call to
+ * getpwuid/getgrgid. */
+string user_to_string(uid_t uid) {
+    static map<uid_t, string> user_cache;
+    map<uid_t, string>::const_iterator i = user_cache.find(uid);
+    if (i != user_cache.end())
+        return i->second;
+
+    string result = encode_int(uid);
+    struct passwd *pwd = getpwuid(uid);
+    if (pwd != NULL && pwd->pw_name != NULL) {
+        result += " (" + uri_encode(pwd->pw_name) + ")";
+    }
+    user_cache[uid] = result;
+    return result;
+}
+
+string group_to_string(gid_t gid) {
+    static map<gid_t, string> group_cache;
+    map<gid_t, string>::const_iterator i = group_cache.find(gid);
+    if (i != group_cache.end())
+        return i->second;
+
+    string result = encode_int(gid);
+    struct group *grp = getgrgid(gid);
+    if (grp != NULL && grp->gr_name != NULL) {
+        result += " (" + uri_encode(grp->gr_name) + ")";
+    }
+    group_cache[gid] = result;
+    return result;
+}
+
 /* Dump a specified filesystem object (file, directory, etc.) based on its
  * inode information.  If the object is a regular file, an open filehandle is
  * provided. */
@@ -348,24 +383,14 @@ void dump_inode(const string& path,         // Path within snapshot
     file_info["mode"] = encode_int(stat_buf.st_mode & 07777, 8);
     file_info["ctime"] = encode_int(stat_buf.st_ctime);
     file_info["mtime"] = encode_int(stat_buf.st_mtime);
-    file_info["user"] = encode_int(stat_buf.st_uid);
-    file_info["group"] = encode_int(stat_buf.st_gid);
+    file_info["user"] = user_to_string(stat_buf.st_uid);
+    file_info["group"] = group_to_string(stat_buf.st_gid);
 
     time_t now = time(NULL);
     if (now - stat_buf.st_ctime < 30 || now - stat_buf.st_mtime < 30)
         if ((stat_buf.st_mode & S_IFMT) != S_IFDIR)
             file_info["volatile"] = "1";
 
-    struct passwd *pwd = getpwuid(stat_buf.st_uid);
-    if (pwd != NULL && pwd->pw_name != NULL) {
-        file_info["user"] += " (" + uri_encode(pwd->pw_name) + ")";
-    }
-
-    struct group *grp = getgrgid(stat_buf.st_gid);
-    if (grp != NULL && grp->gr_name != NULL) {
-        file_info["group"] += " (" + uri_encode(grp->gr_name) + ")";
-    }
-
     if (stat_buf.st_nlink > 1 && (stat_buf.st_mode & S_IFMT) != S_IFDIR) {
         file_info["links"] = encode_int(stat_buf.st_nlink);
     }
@@ -812,11 +837,12 @@ int main(int argc, char *argv[])
     /* Store the time when the backup started, so it can be included in the
      * snapshot name. */
     time_t now;
-    struct tm time_buf;
+    struct tm time_buf_local, time_buf_utc;
     char desc_buf[256];
     time(&now);
-    localtime_r(&now, &time_buf);
-    strftime(desc_buf, sizeof(desc_buf), "%Y%m%dT%H%M%S", &time_buf);
+    localtime_r(&now, &time_buf_local);
+    gmtime_r(&now, &time_buf_utc);
+    strftime(desc_buf, sizeof(desc_buf), "%Y%m%dT%H%M%S", &time_buf_utc);
 
     /* Open the local database which tracks all objects that are stored
      * remotely, for efficient incrementals.  Provide it with the name of this
@@ -919,9 +945,10 @@ int main(int argc, char *argv[])
     }
     FILE *descriptor = fdopen(descriptor_fd, "w");
 
-    fprintf(descriptor, "Format: LBS Snapshot v0.8\n");
+    fprintf(descriptor, "Format: Cumulus Snapshot v0.11\n");
     fprintf(descriptor, "Producer: Cumulus %s\n", cumulus_version);
-    strftime(desc_buf, sizeof(desc_buf), "%Y-%m-%d %H:%M:%S %z", &time_buf);
+    strftime(desc_buf, sizeof(desc_buf), "%Y-%m-%d %H:%M:%S %z",
+             &time_buf_local);
     fprintf(descriptor, "Date: %s\n", desc_buf);
     if (backup_scheme.size() > 0)
         fprintf(descriptor, "Scheme: %s\n", backup_scheme.c_str());