X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=scandir.cc;h=2d5a3a8f89a16ce79090b087b7926f42ad1d7152;hb=c58e9ce625efbdecd2e505102ed273eacad409d2;hp=4ffd0784e9042bc1a4dda46ce6a370b2502194f6;hpb=def20364a3596d7b1fa4a07f3d3ee056cfff2d1e;p=cumulus.git diff --git a/scandir.cc b/scandir.cc index 4ffd078..2d5a3a8 100644 --- a/scandir.cc +++ b/scandir.cc @@ -135,6 +135,7 @@ int64_t dumpfile(int fd, dictionary &file_info, const string &path, { int64_t size = 0; list 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) { @@ -334,7 +351,6 @@ void dump_inode(const string& path, // Path within snapshot 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 @@ -543,6 +559,7 @@ void usage(const char *program) { fprintf( stderr, + "LBS %s\n\n" "Usage: %s [OPTION]... --dest=DEST PATHS...\n" "Produce backup snapshot of files in SOURCE and store to DEST.\n" "\n" @@ -556,13 +573,12 @@ void usage(const char *program) " string to append to segment files\n" " (defaults to \".bz2\")\n" " --scheme=NAME optional name for this snapshot\n", - program + lbs_version, program ); } int main(int argc, char *argv[]) { - string backup_source = "."; string backup_dest = ""; string localdb_dir = ""; string backup_scheme = ""; @@ -617,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, @@ -666,7 +676,6 @@ int main(int argc, char *argv[]) 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 @@ -686,9 +695,12 @@ int main(int argc, char *argv[]) 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); + statcache->Open(localdb_dir.c_str(), desc_buf, + backup_scheme.size() ? backup_scheme.c_str() : NULL); scanfile(".", false); @@ -705,8 +717,6 @@ int main(int argc, char *argv[]) string backup_root = root->get_ref().to_string(); delete root; - db->Close(); - statcache->Close(); delete statcache; @@ -714,6 +724,42 @@ int main(int argc, char *argv[]) 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::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. */ @@ -723,7 +769,7 @@ int main(int argc, char *argv[]) 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"; @@ -731,6 +777,11 @@ int main(int argc, char *argv[]) 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::iterator i = segment_list.begin(); i != segment_list.end(); ++i) {