file_info["group"] += " (" + uri_encode(grp->gr_name) + ")";
}
- if (stat_buf.st_nlink > 1) {
+ 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))
file_size = dumpfile(fd, file_info, path, stat_buf);
file_info["size"] = encode_int(file_size);
- close(fd);
if (file_size < 0)
return; // error occurred; do not dump file
printf(" %s\n", i->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
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,
string backup_root = root->get_ref().to_string();
delete root;
- db->Close();
-
statcache->Close();
delete statcache;
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. */
descriptor << "Scheme: " << backup_scheme << "\n";
descriptor << "Root: " << backup_root << "\n";
+ SHA1Checksum checksum_csum;
+ if (checksum_csum.process_file(checksum_filename.c_str())) {
+ descriptor << "Checksum-File: " << checksum_csum.checksum_str() << "\n";
+ }
+
descriptor << "Segments:\n";
for (std::set<string>::iterator i = segment_list.begin();
i != segment_list.end(); ++i) {