#include <iostream>
#include <list>
#include <map>
+#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <vector>
-#include "cumulus.h"
#include "exclude.h"
#include "hash.h"
#include "localdb.h"
using std::string;
using std::vector;
using std::ostream;
+using std::unique_ptr;
/* Version information. This will be filled in by the Makefile. */
#ifndef CUMULUS_VERSION
/* If the file is new or changed, we must read in the contents a block at a
* time. */
if (!cached) {
- scoped_ptr<Hash> file_hash(Hash::New());
+ unique_ptr<Hash> file_hash(Hash::New());
Subfile subfile(db);
subfile.load_old_blocks(old_blocks);
double block_age = 0.0;
ObjectReference ref;
- scoped_ptr<Hash> block_hash(Hash::New());
+ unique_ptr<Hash> block_hash(Hash::New());
block_hash->update(block_buf, bytes);
string block_csum = block_hash->digest_str();
string(block_buf, bytes));
}
+/* Tests whether the specified file identifies a directory as a cache
+ * directory, by the rules of the Cache Directory Tagging Specification
+ * (https://bford.info/cachedir/).
+ *
+ * Conditions that must be met:
+ * 1. File is named "CACHEDIR.TAG".
+ * 2. File is a regular file (not a symlink or other type).
+ * 3. First bytes of the file must be identical to CACHEDIR_SIGNATURE.
+ * Remaining bytes of the file are ignored and can have any contents.
+ *
+ * It is up to the caller to check the file name; other conditions are checked
+ * in this function. */
+bool is_cachedir_tag_file(const string& path) {
+ struct stat stat_buf;
+ if (lstat(path.c_str(), &stat_buf) < 0) {
+ return false;
+ }
+ if ((stat_buf.st_mode & S_IFMT) != S_IFREG) {
+ return false;
+ }
+
+ static const char CACHEDIR_SIGNATURE[]
+ = "Signature: 8a477f597d28d172789f06886806bc55";
+ ssize_t CACHEDIR_SIGLEN = strlen(CACHEDIR_SIGNATURE);
+
+ int fd = safe_open(path, NULL);
+ if (fd < 0)
+ return false;
+
+ ssize_t bytes = file_read(fd, block_buf, CACHEDIR_SIGLEN);
+ close(fd);
+ if (bytes != CACHEDIR_SIGLEN) {
+ return false;
+ }
+
+ if (memcmp(block_buf, CACHEDIR_SIGNATURE, CACHEDIR_SIGLEN) != 0) {
+ return false;
+ }
+
+ return true;
+}
+
void scanfile(const string& path)
{
int fd = -1;
}
try_merge_filter(filename, output_path);
}
+ if (*i == CACHEDIR_TAG_FILE && is_cachedir_tag_file(filename)) {
+ if (verbose) {
+ printf("Cache directory found at %s\n",
+ output_path.c_str());
+ }
+ filter_rules.activate_cachedir(output_path);
+ }
}
/* Second pass: recursively scan all items in the directory for backup;
" --exclude=PATTERN exclude files matching PATTERN from snapshot\n"
" --include=PATTERN include files matching PATTERN in snapshot\n"
" --dir-merge=PATTERN parse files matching PATTERN to read additional\n"
+ " --cachedir-check insert a CACHEDIR.TAG check in filter rules\n"
" subtree-specific include/exclude rules during backup\n"
" --localdb=PATH local backup metadata is stored in PATH\n"
" --tmpdir=PATH path for temporarily storing backup files\n"
{"include", 1, 0, 0}, // 11
{"exclude", 1, 0, 0}, // 12
{"dir-merge", 1, 0, 0}, // 13
+ {"cachedir-check", 0, 0, 0}, // 14
// Aliases for short options
{"verbose", 0, 0, 'v'},
{NULL, 0, 0, 0},
case 13: // --dir-merge
filter_rules.add_pattern(PathFilterList::DIRMERGE, optarg, "");
break;
+ case 14: // --cachedir-check
+ filter_rules.add_pattern(PathFilterList::CACHEDIR_CHECK, "",
+ "");
+ break;
default:
fprintf(stderr, "Unhandled long option!\n");
return 1;
dbmeta_filename += backup_scheme + "-";
dbmeta_filename += timestamp + ".meta" + filter_extension;
RemoteFile *dbmeta_file = remote->alloc_file(dbmeta_filename, "meta");
- scoped_ptr<FileFilter> dbmeta_filter(FileFilter::New(dbmeta_file->get_fd(),
+ unique_ptr<FileFilter> dbmeta_filter(FileFilter::New(dbmeta_file->get_fd(),
filter_program));
if (dbmeta_filter == NULL) {
fprintf(stderr, "Unable to open descriptor output file: %m\n");
RemoteFile *descriptor_file = remote->alloc_file(desc_filename,
"snapshots");
- scoped_ptr<FileFilter> descriptor_filter(
+ unique_ptr<FileFilter> descriptor_filter(
FileFilter::New(descriptor_file->get_fd(), signature_filter.c_str()));
if (descriptor_filter == NULL) {
fprintf(stderr, "Unable to open descriptor output file: %m\n");