`pkg-config --cflags $(PACKAGES)` -DLBS_VERSION=`cat version`
LDFLAGS=$(DEBUG) `pkg-config --libs $(PACKAGES)`
-SRCS=localdb.cc ref.cc scandir.cc sha1.cc statcache.cc store.cc util.cc
+SRCS=localdb.cc metadata.cc ref.cc scandir.cc sha1.cc statcache.cc store.cc \
+ util.cc
OBJS=$(SRCS:.cc=.o)
lbs : $(OBJS)
--- /dev/null
+/* LBS: An LFS-inspired filesystem backup system
+ * Copyright (C) 2007 Michael Vrable
+ *
+ * Handling of metadata written to backup snapshots. This manages the writing
+ * of file metadata into new backup snapshots, including breaking the metadata
+ * log apart across separate objects. Eventually this should include unified
+ * handling of the statcache, and re-use of metadata between snapshots.
+ */
+
+#include <string>
+#include <iostream>
+
+#include "metadata.h"
+#include "store.h"
+#include "statcache.h"
+#include "util.h"
+
+using std::string;
+using std::ostream;
+
+static const size_t LBS_METADATA_BLOCK_SIZE = 65536;
+
+/* TODO: Move to header file */
+void add_segment(const string& segment);
+
+MetadataWriter::MetadataWriter(TarSegmentStore *store)
+{
+ this->store = store;
+}
+
+/* Ensure contents of metadata are flushed to an object. */
+void MetadataWriter::metadata_flush()
+{
+ string m = metadata.str();
+ if (m.size() == 0)
+ return;
+
+ /* Write current metadata information to a new object. */
+ LbsObject *meta = new LbsObject;
+ meta->set_group("metadata");
+ meta->set_data(m.data(), m.size());
+ meta->write(store);
+ meta->checksum();
+
+ /* Write a reference to this block in the root. */
+ ObjectReference ref = meta->get_ref();
+ metadata_root << "@" << ref.to_string() << "\n";
+ add_segment(ref.get_segment());
+
+ delete meta;
+
+ metadata.str("");
+}
+
+void MetadataWriter::add(const string& path, dictionary info)
+{
+ metadata << "path: " << uri_encode(path) << "\n";
+ metadata << encode_dict(info);
+ metadata << "\n";
+
+ if (metadata.str().size() > LBS_METADATA_BLOCK_SIZE)
+ metadata_flush();
+}
+
+ObjectReference MetadataWriter::close()
+{
+ metadata_flush();
+ const string root_data = metadata_root.str();
+
+ LbsObject *root = new LbsObject;
+ root->set_group("metadata");
+ root->set_data(root_data.data(), root_data.size());
+ root->write(store);
+ root->checksum();
+ add_segment(root->get_ref().get_segment());
+
+ ObjectReference ref = root->get_ref();
+ delete root;
+ return ref;
+}
--- /dev/null
+/* LBS: An LFS-inspired filesystem backup system
+ * Copyright (C) 2007 Michael Vrable
+ *
+ * Handling of metadata written to backup snapshots. This manages the writing
+ * of file metadata into new backup snapshots, including breaking the metadata
+ * log apart across separate objects. Eventually this should include unified
+ * handling of the statcache, and re-use of metadata between snapshots.
+ */
+
+#ifndef _LBS_METADATA_H
+#define _LBS_METADATA_H
+
+#include <string>
+#include <sstream>
+
+#include "store.h"
+#include "ref.h"
+#include "util.h"
+
+class MetadataWriter {
+public:
+ MetadataWriter(TarSegmentStore *store);
+ void add(const std::string& path, dictionary info);
+ ObjectReference close();
+
+private:
+ void metadata_flush();
+
+ TarSegmentStore *store;
+ std::ostringstream metadata, metadata_root;
+};
+
+#endif // _LBS_METADATA_H
#include <vector>
#include "localdb.h"
+#include "metadata.h"
#include "store.h"
#include "sha1.h"
#include "statcache.h"
static const char lbs_version[] = LBS_STRINGIFY(LBS_VERSION);
static TarSegmentStore *tss = NULL;
+static MetadataWriter *metawriter = NULL;
/* Buffer for holding a single block of data read from a file. */
static const size_t LBS_BLOCK_SIZE = 1024 * 1024;
static char *block_buf;
-static const size_t LBS_METADATA_BLOCK_SIZE = 65536;
-
/* Local database, which tracks objects written in this and previous
* invocations to help in creating incremental snapshots. */
LocalDb *db;
* skipping files which have not changed. */
StatCache *statcache;
-/* Contents of the root object. This will contain a set of indirect links to
- * the metadata objects. */
-std::ostringstream metadata_root;
-
-/* Buffer for building up metadata. */
-std::ostringstream metadata;
-
/* Keep track of all segments which are needed to reconstruct the snapshot. */
std::set<string> segment_list;
bool relative_paths = true;
-/* Ensure contents of metadata are flushed to an object. */
-void metadata_flush()
+/* Ensure that the given segment is listed as a dependency of the current
+ * snapshot. */
+void add_segment(const string& segment)
{
- string m = metadata.str();
- if (m.size() == 0)
- return;
-
- /* Write current metadata information to a new object. */
- LbsObject *meta = new LbsObject;
- meta->set_group("metadata");
- meta->set_data(m.data(), m.size());
- meta->write(tss);
- meta->checksum();
-
- /* Write a reference to this block in the root. */
- ObjectReference ref = meta->get_ref();
- metadata_root << "@" << ref.to_string() << "\n";
- segment_list.insert(ref.get_segment());
-
- delete meta;
-
- metadata.str("");
+ segment_list.insert(segment);
}
/* Read data from a file descriptor and return the amount of data read. A
file_info["type"] = string(1, inode_type);
- metadata << "name: " << uri_encode(path) << "\n";
- dict_output(metadata, file_info);
- metadata << "\n";
-
- // Break apart metadata listing if it becomes too large.
- if (metadata.str().size() > LBS_METADATA_BLOCK_SIZE)
- metadata_flush();
+ metawriter->add(path, file_info);
}
void scanfile(const string& path, bool include)
tss = new TarSegmentStore(backup_dest, db);
+ metawriter = new MetadataWriter(tss);
+
/* Initialize the stat cache, for skipping over unchanged files. */
statcache = new StatCache;
statcache->Open(localdb_dir.c_str(), desc_buf,
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;
+ ObjectReference root_ref = metawriter->close();
+ add_segment(root_ref.get_segment());
+ string backup_root = root_ref.to_string();
statcache->Close();
delete statcache;
+ delete metawriter;
+
tss->sync();
tss->dump_stats();
delete tss;
-/* LBS: An LFS-inspired filesystem backup system Copyright (C) 2007 Michael
- * Vrable
+/* LBS: An LFS-inspired filesystem backup system
+ * Copyright (C) 2007 Michael Vrable
*
* To speed backups, we maintain a "stat cache" containing selected information
* about all regular files, including modification times and the list of blocks
return strtoll(s.c_str(), NULL, 0);
}
-/* Output a dictionary of string key/value pairs to the given output stream.
- * The format is a sequence of lines of the form "key: value". */
-void dict_output(ostream &o, map<string, string> dict)
+/* Encode a dictionary of string key/value pairs into a sequence of lines of
+ * the form "key: value". */
+string encode_dict(const map<string, string>& dict)
{
+ string result;
for (map<string, string>::const_iterator i = dict.begin();
i != dict.end(); ++i) {
- o << i->first << ": " << i->second << "\n";
+ result += i->first + ": " + i->second + "\n";
}
+ return result;
+}
+
+/* Output a dictionary of string key/value pairs to the given output stream.
+ * The format is a sequence of lines of the form "key: value". */
+void dict_output(ostream &o, const map<string, string>& dict)
+{
+ o << encode_dict(dict);
}
std::string uri_encode(const std::string &in);
std::string uri_decode(const std::string &in);
std::string encode_int(long long n, int base=10);
-void dict_output(std::ostream &o, std::map<std::string, std::string> dict);
+std::string encode_dict(const std::map<std::string, std::string>& dict);
+void dict_output(std::ostream &o,
+ const std::map<std::string, std::string>& dict);
long long parse_int(const std::string &s);