Do not include link/inode information for directories.
[cumulus.git] / scandir.cc
index 0820c16..d35c552 100644 (file)
@@ -135,6 +135,7 @@ int64_t dumpfile(int fd, dictionary &file_info, const string &path,
 {
     int64_t size = 0;
     list<string> object_list;
+    const char *status = NULL;          /* Status indicator printed out */
 
     /* Look up this file in the old stat cache, if we can.  If the stat
      * information indicates that the file has not changed, do not bother
@@ -152,6 +153,7 @@ int64_t dumpfile(int fd, dictionary &file_info, const string &path,
             const ObjectReference &ref = *i;
             if (!db->IsAvailable(ref)) {
                 cached = false;
+                status = "repack";
                 break;
             }
         }
@@ -173,8 +175,6 @@ int64_t dumpfile(int fd, dictionary &file_info, const string &path,
     /* If the file is new or changed, we must read in the contents a block at a
      * time. */
     if (!cached) {
-        printf("    [new]\n");
-
         SHA1Checksum hash;
         while (true) {
             ssize_t bytes = file_read(fd, block_buf, LBS_BLOCK_SIZE);
@@ -211,10 +211,14 @@ int64_t dumpfile(int fd, dictionary &file_info, const string &path,
                  * Additionally, keep track of the age of the data by looking
                  * up the age of the block which was expired and using that
                  * instead of the current time. */
-                if (db->IsOldObject(block_csum, bytes, &block_age))
+                if (db->IsOldObject(block_csum, bytes, &block_age)) {
                     o->set_group("compacted");
-                else
+                    if (status == NULL)
+                        status = "partial";
+                } else {
                     o->set_group("data");
+                    status = "new";
+                }
 
                 o->set_data(block_buf, bytes);
                 o->write(tss);
@@ -227,11 +231,17 @@ int64_t dumpfile(int fd, dictionary &file_info, const string &path,
             segment_list.insert(ref.get_segment());
             db->UseObject(ref);
             size += bytes;
+
+            if (status == NULL)
+                status = "old";
         }
 
         file_info["checksum"] = hash.checksum_str();
     }
 
+    if (status != NULL)
+        printf("    [%s]\n", status);
+
     statcache->Save(path, &stat_buf, file_info["checksum"], object_list);
 
     /* For files that only need to be broken apart into a few objects, store
@@ -280,7 +290,7 @@ void dump_inode(const string& path,         // Path within snapshot
 
     printf("%s\n", path.c_str());
 
-    file_info["mode"] = encode_int(stat_buf.st_mode & 07777);
+    file_info["mode"] = encode_int(stat_buf.st_mode & 07777, 8);
     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);
@@ -295,6 +305,13 @@ void dump_inode(const string& path,         // Path within snapshot
         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);
+        file_info["inode"] = encode_int(major(stat_buf.st_dev))
+            + "/" + encode_int(minor(stat_buf.st_dev))
+            + "/" + encode_int(stat_buf.st_ino);
+    }
+
     char inode_type;
 
     switch (stat_buf.st_mode & S_IFMT) {
@@ -554,16 +571,17 @@ void usage(const char *program)
         "                           (defaults to \"bzip2 -c\")\n"
         "  --filter-extension=EXT\n"
         "                       string to append to segment files\n"
-        "                           (defaults to \".bz2\")\n",
+        "                           (defaults to \".bz2\")\n"
+        "  --scheme=NAME        optional name for this snapshot\n",
         program
     );
 }
 
 int main(int argc, char *argv[])
 {
-    string backup_source = ".";
     string backup_dest = "";
     string localdb_dir = "";
+    string backup_scheme = "";
 
     while (1) {
         static struct option long_options[] = {
@@ -572,6 +590,7 @@ int main(int argc, char *argv[])
             {"filter", 1, 0, 0},            // 2
             {"filter-extension", 1, 0, 0},  // 3
             {"dest", 1, 0, 0},              // 4
+            {"scheme", 1, 0, 0},            // 5
             {NULL, 0, 0, 0},
         };
 
@@ -601,6 +620,9 @@ int main(int argc, char *argv[])
             case 4:     // --dest
                 backup_dest = optarg;
                 break;
+            case 5:     // --scheme
+                backup_scheme = optarg;
+                break;
             default:
                 fprintf(stderr, "Unhandled long option!\n");
                 return 1;
@@ -611,20 +633,14 @@ int main(int argc, char *argv[])
         }
     }
 
-    if (argc < optind + 2) {
+    if (optind == argc) {
         usage(argv[0]);
         return 1;
     }
 
     searches.push_back(".");
-    if (optind == argc) {
-        add_include(".");
-    } else {
-        for (int i = optind; i < argc; i++)
-            add_include(argv[i]);
-    }
-
-    backup_source = argv[optind];
+    for (int i = optind; i < argc; i++)
+        add_include(argv[i]);
 
     if (backup_dest == "") {
         fprintf(stderr,
@@ -677,11 +693,13 @@ int main(int argc, char *argv[])
      * snapshot. */
     string database_path = localdb_dir + "/localdb.sqlite";
     db = new LocalDb;
-    db->Open(database_path.c_str(), desc_buf);
+    db->Open(database_path.c_str(), desc_buf,
+             backup_scheme.size() ? backup_scheme.c_str() : NULL);
 
     /* Initialize the stat cache, for skipping over unchanged files. */
     statcache = new StatCache;
-    statcache->Open(localdb_dir.c_str(), desc_buf);
+    statcache->Open(localdb_dir.c_str(), desc_buf,
+                    backup_scheme.size() ? backup_scheme.c_str() : NULL);
 
     scanfile(".", false);
 
@@ -710,13 +728,18 @@ int main(int argc, char *argv[])
     /* Write a backup descriptor file, which says which segments are needed and
      * where to start to restore this snapshot.  The filename is based on the
      * current time. */
-    string desc_filename = backup_dest + "/snapshot-" + desc_buf + ".lbs";
+    string desc_filename = backup_dest + "/snapshot-";
+    if (backup_scheme.size() > 0)
+        desc_filename += backup_scheme + "-";
+    desc_filename = desc_filename + desc_buf + ".lbs";
     std::ofstream descriptor(desc_filename.c_str());
 
-    descriptor << "Format: LBS Snapshot v0.1\n";
+    descriptor << "Format: LBS Snapshot v0.2\n";
     descriptor << "Producer: LBS " << lbs_version << "\n";
     strftime(desc_buf, sizeof(desc_buf), "%Y-%m-%d %H:%M:%S %z", &time_buf);
     descriptor << "Date: " << desc_buf << "\n";
+    if (backup_scheme.size() > 0)
+        descriptor << "Scheme: " << backup_scheme << "\n";
     descriptor << "Root: " << backup_root << "\n";
 
     descriptor << "Segments:\n";