1 /* LBS: An LFS-inspired filesystem backup system
2 * Copyright (C) 2006 Michael Vrable
4 * Backup data is stored in a collection of objects, which are grouped together
5 * into segments for storage purposes. This implementation of the object store
6 * is built on top of libtar, and represents segments as TAR files and objects
7 * as files within them. */
10 #include <sys/types.h>
15 #include <uuid/uuid.h>
24 Tarfile::Tarfile(const string &path, const string &segment)
25 : segment_name(segment)
27 if (tar_open(&t, (char *)path.c_str(), NULL, O_WRONLY | O_CREAT, 0600,
28 TAR_VERBOSE | TAR_GNU) == -1)
29 throw IOException("Error opening Tarfile");
34 string checksum_list = checksums.str();
35 internal_write_object(segment_name + "/checksums",
36 checksum_list.data(), checksum_list.size());
39 if (tar_close(t) != 0)
40 throw IOException("Error closing Tarfile");
43 void Tarfile::write_object(int id, const char *data, size_t len)
46 sprintf(buf, "%08x", id);
47 string path = segment_name + "/" + buf;
48 printf("path: %s\n", path.c_str());
50 internal_write_object(path, data, len);
52 // Compute a checksum for the data block, which will be stored at the end
55 hash.process(data, len);
56 sprintf(buf, "%08x", id);
57 checksums << buf << " " << hash.checksum_str() << "\n";
60 void Tarfile::internal_write_object(const string &path,
61 const char *data, size_t len)
63 memset(&t->th_buf, 0, sizeof(struct tar_header));
65 th_set_type(t, S_IFREG | 0600);
70 th_set_mtime(t, time(NULL));
71 th_set_path(t, const_cast<char *>(path.c_str()));
75 throw IOException("Error writing tar header");
82 size_t blocks = (len + T_BLOCKSIZE - 1) / T_BLOCKSIZE;
83 size_t padding = blocks * T_BLOCKSIZE - len;
85 for (size_t i = 0; i < blocks - 1; i++) {
86 if (tar_block_write(t, &data[i * T_BLOCKSIZE]) == -1)
87 throw IOException("Error writing tar block");
90 char block[T_BLOCKSIZE];
91 memset(block, 0, sizeof(block));
92 memcpy(block, &data[T_BLOCKSIZE * (blocks - 1)], T_BLOCKSIZE - padding);
93 if (tar_block_write(t, block) == -1)
94 throw IOException("Error writing final tar block");
97 string TarSegmentStore::write_object(const char *data, size_t len, const
100 struct segment_info *segment;
102 // Find the segment into which the object should be written, looking up by
103 // group. If no segment exists yet, create one.
104 if (segments.find(group) == segments.end()) {
105 segment = new segment_info;
110 uuid_unparse_lower(uuid, uuid_buf);
111 segment->name = uuid_buf;
113 string filename = path + "/" + segment->name + ".tar";
114 segment->file = new Tarfile(filename, segment->name);
118 segments[group] = segment;
120 segment = segments[group];
123 int id = segment->count;
125 sprintf(id_buf, "%08x", id);
127 segment->file->write_object(id, data, len);
130 return segment->name + "/" + id_buf;
133 void TarSegmentStore::sync()
135 while (!segments.empty()) {
136 const string &name = segments.begin()->first;
137 struct segment_info *segment = segments[name];
139 fprintf(stderr, "Closing segment group %s (%s)\n",
140 name.c_str(), segment->name.c_str());
142 delete segment->file;
143 segments.erase(segments.begin());