+ // Default for --localdb is the same as --dest
+ if (localdb_dir == "") {
+ localdb_dir = backup_dest;
+ }
+
+ // Dump paths for debugging/informational purposes
+ {
+ list<string>::const_iterator i;
+
+ printf("LBS Version: %s\n", lbs_version);
+
+ printf("--dest=%s\n--localdb=%s\n\n",
+ backup_dest.c_str(), localdb_dir.c_str());
+
+ printf("Includes:\n");
+ for (i = includes.begin(); i != includes.end(); ++i)
+ printf(" %s\n", i->c_str());
+
+ printf("Excludes:\n");
+ for (i = excludes.begin(); i != excludes.end(); ++i)
+ printf(" %s\n", i->c_str());
+
+ printf("Searching:\n");
+ for (i = searches.begin(); i != searches.end(); ++i)
+ printf(" %s\n", i->c_str());
+ }
+
+ 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,
+ backup_scheme.size() ? backup_scheme.c_str() : NULL);
+
+ tss = new TarSegmentStore(backup_dest, db);
+
+ /* Initialize the stat cache, for skipping over unchanged files. */
+ statcache = new StatCache;
+ statcache->Open(localdb_dir.c_str(), desc_buf,
+ backup_scheme.size() ? backup_scheme.c_str() : NULL);
+
+ scanfile(".", false);
+
+ 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());
+
+ string backup_root = root->get_ref().to_string();
+ delete root;
+
+ statcache->Close();
+ delete statcache;
+
+ tss->sync();
+ tss->dump_stats();
+ delete tss;
+
+ /* Write out a checksums file which lists the checksums for all the
+ * segments included in this snapshot. The format is designed so that it
+ * may be easily verified using the sha1sums command. */
+ const char csum_type[] = "sha1";
+ string checksum_filename = backup_dest + "/snapshot-";
+ if (backup_scheme.size() > 0)
+ checksum_filename += backup_scheme + "-";
+ checksum_filename = checksum_filename + desc_buf + "." + csum_type + "sums";
+ FILE *checksums = fopen(checksum_filename.c_str(), "w");
+ if (checksums != NULL) {
+ for (std::set<string>::iterator i = segment_list.begin();
+ i != segment_list.end(); ++i) {
+ string seg_path, seg_csum;
+ if (db->GetSegmentChecksum(*i, &seg_path, &seg_csum)) {
+ const char *raw_checksum = NULL;
+ if (strncmp(seg_csum.c_str(), csum_type,
+ strlen(csum_type)) == 0) {
+ raw_checksum = seg_csum.c_str() + strlen(csum_type);
+ if (*raw_checksum == '=')
+ raw_checksum++;
+ else
+ raw_checksum = NULL;
+ }
+
+ if (raw_checksum != NULL)
+ fprintf(checksums, "%s *%s\n",
+ raw_checksum, seg_path.c_str());
+ }
+ }
+ fclose(checksums);
+ } else {
+ fprintf(stderr, "ERROR: Unable to write checksums file: %m\n");
+ }
+
+ db->Close();
+
+ /* 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-";
+ 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.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";
+
+ SHA1Checksum checksum_csum;
+ if (checksum_csum.process_file(checksum_filename.c_str())) {
+ descriptor << "Checksums: " << checksum_csum.checksum_str() << "\n";
+ }
+
+ descriptor << "Segments:\n";
+ for (std::set<string>::iterator i = segment_list.begin();
+ i != segment_list.end(); ++i) {
+ descriptor << " " << *i << "\n";
+ }