+ string backup_source = ".";
+ string backup_dest = ".";
+ string localdb_dir = "";
+
+ while (1) {
+ static struct option long_options[] = {
+ {"localdb", 1, 0, 0}, // 0
+ {"exclude", 1, 0, 0}, // 1
+ {"filter", 1, 0, 0}, // 2
+ {"filter-extension", 1, 0, 0}, // 3
+ {NULL, 0, 0, 0},
+ };
+
+ int long_index;
+ int c = getopt_long(argc, argv, "", long_options, &long_index);
+
+ if (c == -1)
+ break;
+
+ if (c == 0) {
+ switch (long_index) {
+ case 0: // --localdb
+ localdb_dir = optarg;
+ break;
+ case 1: // --exclude
+ excludes.push_back(optarg);
+ break;
+ case 2: // --filter
+ filter_program = optarg;
+ break;
+ case 3: // --filter-extension
+ filter_extension = optarg;
+ break;
+ default:
+ fprintf(stderr, "Unhandled long option!\n");
+ return 1;
+ }
+ } else {
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if (argc < optind + 2) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ backup_source = argv[optind];
+ backup_dest = argv[argc - 1];
+
+ if (localdb_dir == "") {
+ localdb_dir = backup_dest;
+ }
+
+ printf("Source: %s\nDest: %s\nDatabase: %s\n\n",
+ backup_source.c_str(), backup_dest.c_str(), localdb_dir.c_str());
+
+ tss = new TarSegmentStore(backup_dest);
+ block_buf = new char[LBS_BLOCK_SIZE];
+
+ /* Store the time when the backup started, so it can be included in the
+ * snapshot name. */
+ time_t now;
+ struct tm time_buf;
+ 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);
+
+ /* Open the local database which tracks all objects that are stored
+ * remotely, for efficient incrementals. Provide it with the name of this
+ * snapshot. */
+ string database_path = localdb_dir + "/localdb.sqlite";
+ db = new LocalDb;
+ db->Open(database_path.c_str(), desc_buf);
+
+ /* Initialize the stat cache, for skipping over unchanged files. */
+ statcache = new StatCache;
+ statcache->Open(localdb_dir.c_str(), desc_buf);
+
+ try {
+ scanfile(".");
+ } catch (IOException e) {
+ fprintf(stderr, "IOException: %s\n", e.getError().c_str());
+ }
+
+ metadata_flush();
+ const string md = metadata_root.str();
+
+ LbsObject *root = new LbsObject;
+ root->set_group("metadata");
+ root->set_data(md.data(), md.size());
+ root->write(tss);
+ root->checksum();
+ segment_list.insert(root->get_ref().get_segment());
+
+ /* 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";
+ std::ofstream descriptor(desc_filename.c_str());
+
+ descriptor << "Format: LBS Snapshot v0.1\n";
+ strftime(desc_buf, sizeof(desc_buf), "%Y-%m-%d %H:%M:%S %z", &time_buf);
+ descriptor << "Date: " << desc_buf << "\n";
+ descriptor << "Root: " << root->get_ref().to_string() << "\n";
+
+ delete root;
+
+ descriptor << "Segments:\n";
+ for (std::set<string>::iterator i = segment_list.begin();
+ i != segment_list.end(); ++i) {
+ descriptor << " " << *i << "\n";
+ }
+
+ db->Close();
+
+ statcache->Close();
+ delete statcache;
+
+ tss->sync();
+ delete tss;