7 #include <sys/resource.h>
16 #include <unordered_map>
17 #include <unordered_set>
22 #include "curl/curl.h"
32 #define CHECK_SQLITE_ERROR(ret, expected) do { \
33 if ((ret)!=expected) { \
34 LogCvmfs(kLogCvmfs, kLogStderr, "SQLite error: %d", (ret)); \
39 #define CUSTOM_ASSERT(check, msg, ...) do { \
41 LogCvmfs(kLogCvmfs, kLogStderr, msg, ##__VA_ARGS__); \
46 #define SHOW_PROGRESS(item, freq, curr, total) do { \
47 if ((curr) % freq == 0 || (curr) == total) { \
48 LogCvmfs(kLogCvmfs, kLogStdout, "Processed %d/%d %s", (curr), total, item); \
73 bool include_additions,
74 bool include_deletions);
79 static string sanitise_name(
const char *name_cstr,
bool allow_leading_slash);
81 static string acquire_lease(
const string& key_id,
const string& secret,
const string& lease_path,
82 const string& repo_service_url,
bool force_cancel_lease, uint64_t *current_revision,
string ¤t_root_hash,
83 unsigned int refresh_interval);
91 static bool check_prefix(
const std::string &path ,
const std::string &prefix);
99 bool allow_leading_slash =
false) {
101 const char *c = name_cstr;
102 while(*c ==
'/') {c++;}
103 string const name = string(c);
106 if (!allow_leading_slash &&
HasPrefix(name,
"/",
true)) {
111 if (!(allow_leading_slash &&
117 if (name.find(
"//") != string::npos) {
129 if (name.find(
"/./") != string::npos || name.find(
"/../") != string::npos) {
137 CUSTOM_ASSERT(ok,
"Name [%s] is invalid (reason %d)", name.c_str(), reason);
142 size_t const found = path.find_last_of(
'/');
143 if (found == string::npos) {
146 return path.substr(0, found);
150 const size_t found = path.find_last_of(
'/');
151 if (found == string::npos) {
154 return path.substr(found + 1);
159 return (relative_path ==
"") ?
"" :
"/" + relative_path;
162 static string acquire_lease(
const string& key_id,
const string& secret,
const string& lease_path,
163 const string& repo_service_url,
bool force_cancel_lease, uint64_t *current_revision,
string ¤t_root_hash,
164 unsigned int refresh_interval) {
165 const CURLcode ret = curl_global_init(CURL_GLOBAL_ALL);
168 string gateway_metadata_str;
169 char *gateway_metadata = getenv(
"CVMFS_GATEWAY_METADATA");
170 if (gateway_metadata != NULL) gateway_metadata_str = gateway_metadata;
175 &buffer, gateway_metadata_str)) {
176 string session_token;
183 return session_token;
186 if( force_cancel_lease ) {
191 sleep(refresh_interval);
195 buffer.
data.c_str(), refresh_interval);
196 sleep(refresh_interval);
200 sleep(refresh_interval);
207 static uint64_t
make_commit_on_gateway(
const std::string &old_root_hash,
const std::string &new_root_hash, int64_t priority) {
209 char priorityStr[100];
210 (void)sprintf(priorityStr,
"%" PRId64, priority);
213 const std::string payload =
"{\n\"old_root_hash\": \"" + old_root_hash +
"\",\n\"new_root_hash\": \""+new_root_hash+
"\",\n\"priority\": "+priorityStr+
"}";
235 if(buffer.
data ==
"Method Not Allowed\n") {
261 (void)signal(sig, SIG_DFL);
267 if (sig == SIGINT || sig == SIGTERM) exit(1);
271 bool include_additions,
272 bool include_deletions) {
274 vector<string> paths;
276 for (vector<string>::iterator it = sqlite_db_vec.begin();
277 it != sqlite_db_vec.end(); it++) {
279 ret = sqlite3_open_v2((*it).c_str(), &db, SQLITE_OPEN_READONLY, NULL);
283 vector<string> tables;
284 if (include_additions) {
285 tables.push_back(
"dirs");
286 tables.push_back(
"links");
287 tables.push_back(
"files");
289 if (include_deletions) {
290 tables.push_back(
"deletions");
294 for (vector<string>::iterator it = tables.begin(); it != tables.end();
297 const string query =
"SELECT name FROM " + *it;
298 ret = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
300 while (sqlite3_step(stmt) == SQLITE_ROW) {
301 const char *name =
reinterpret_cast<const char *
>(sqlite3_column_text(stmt, 0));
304 paths.push_back(names);
309 ret = sqlite3_finalize(stmt);
312 ret = sqlite3_close_v2(db);
320 std::ostringstream stmt_str;
321 stmt_str <<
"SELECT value FROM " << db_name <<
"properties WHERE key = 'schema_revision'";
322 int ret = sqlite3_prepare_v2(db, stmt_str.str().c_str(), -1, &stmt, NULL);
325 ret = sqlite3_step(stmt);
328 const std::string schema_revision_str(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)));
330 return std::stoi(schema_revision_str);
335 std::ostringstream stmt_str;
336 stmt_str <<
"SELECT COUNT(*) FROM " << table_name;
337 int ret = sqlite3_prepare_v2(db, stmt_str.str().c_str(), -1, &stmt, NULL);
340 ret = sqlite3_step(stmt);
342 const std::string count_str(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)));
344 return std::stoi(count_str);
349 while (base * 50 < total) base *= 10;
360 for (
auto it = paths.begin() + 1; it != paths.end(); ++it) {
364 auto i = lease.GetLength() - 1;
365 for (; i >= 0; --i) {
366 if (lease.GetChars()[i] ==
'/' || i == 0) {
372 if (lease.IsEmpty())
break;
375 auto prefix =
"/" + lease.ToString();
384 if (acl_string == NULL || acl_string[0] ==
'\0') {
398 CUSTOM_ASSERT(aclobj.
Set(
"system.posix_acl_access",
string(binary_acl, binary_size)),
"failed to set system.posix_acl_access (ACL size %ld)", binary_size);
405 std::unordered_map<string, string>
load_config(
const string& config_file) {
406 std::unordered_map<string, string> config_map;
407 ifstream input(config_file);
412 vector<string> lines;
413 for (
string line; getline(input, line);) {
414 lines.push_back(line);
417 for (
auto it = lines.begin(); it != lines.end(); it++) {
418 const string l = *it;
419 const size_t p = l.find(
'=', 0);
420 if (p != string::npos) {
421 const string key = l.substr(0, p);
422 string val = l.substr(p + 1);
424 if (val.front() ==
'"') {
425 val = val.substr(1, val.length() - 2);
427 config_map[key] = val;
434 string retrieve_config(std::unordered_map<string, string> &config_map,
const string& key) {
435 auto kv = config_map.find(key);
436 CUSTOM_ASSERT(kv != config_map.end(),
"Parameter %s not found in config", key.c_str());
441 vector<string> paths;
442 const char *cpath = path.c_str();
444 const int ret = stat(cpath, &st);
447 if (S_ISDIR(st.st_mode)) {
452 while ((dir = readdir(d)) != NULL) {
453 const char *t = strrchr(dir->d_name,
'.');
454 if (t && !strcmp(t,
".db")) {
455 paths.push_back(path +
"/" + dir->d_name);
461 paths.push_back(path);
475 || signal(SIGTERM, &
on_signal) == SIG_ERR
481 const bool enable_corefiles = (args.find(
'c') != args.end());
482 if( !enable_corefiles ) {
484 rlim.rlim_cur = rlim.rlim_max = 0;
485 setrlimit( RLIMIT_CORE, &rlim );
489 if (args.find(
'n') != args.end()) {
498 if (args.find(
'P') != args.end()) {
499 const char *arg = (*args.find(
'P')->second).c_str();
500 char* at_null_terminator_if_number;
501 g_priority = strtoll(arg, &at_null_terminator_if_number, 10);
502 if (*at_null_terminator_if_number !=
'\0') {
512 if (args.find(
'r') != args.end()) {
513 lease_busy_retry_interval = atoi((*args.find(
'r')->second).c_str());
516 string dir_temp =
"";
517 const char *env_tmpdir;
518 if (args.find(
't') != args.end()) {
520 }
else if (env_tmpdir = getenv(
"TMPDIR")) {
527 string kConfigDir(
"/etc/cvmfs/gateway-client/");
528 if (args.find(
'C') != args.end()) {
535 string const repo_name = *args.find(
'N')->second;
536 string sqlite_db_path = *args.find(
'D')->second;
538 vector<string> sqlite_db_vec =
get_file_list(sqlite_db_path);
541 bool const allow_deletions = (args.find(
'd') != args.end());
542 bool const force_cancel_lease = (args.find(
'x') != args.end());
543 bool const allow_additions = !allow_deletions || (args.find(
'a') != args.end());
545 bool const check_completed_graft_property = ( args.find(
'Z') != args.end());
546 if (args.find(
'v') != args.end()) {
550 if(check_completed_graft_property) {
551 if(sqlite_db_vec.size()!=1) {
563 string const config_file = kConfigDir + repo_name +
"/config";
567 string additional_prefix=
"";
568 bool has_additional_prefix=
false;
569 if (args.find(
'p') != args.end()) {
570 additional_prefix=*args.find(
'p')->second;
571 additional_prefix =
sanitise_name(additional_prefix.c_str(),
true);
572 if( additional_prefix.back() !=
'/' ) {
573 additional_prefix +=
"/";
575 has_additional_prefix=
true;
581 if (args.find(
'g') != args.end()) {
586 if (args.find(
'w') != args.end()) {
587 stratum0 = *args.find(
'w')->second;
592 if (args.find(
'@') != args.end()) {
593 proxy = *args.find(
'@')->second;
598 string lease_path=
"";
600 if (args.find(
'l') != args.end()) {
601 lease_path = *args.find(
'l')->second;
605 sqlite_db_vec, allow_additions, allow_deletions);
606 if (paths.size() == 0) {
614 if (has_additional_prefix) {
615 if (lease_path ==
"/" ) { lease_path =
"/" + additional_prefix; }
617 if ( lease_path.substr(0,1)==
"/" ) {
618 lease_path =
"/" + additional_prefix + lease_path.substr(1, lease_path.size()-1);
620 lease_path =
"/" + additional_prefix + lease_path;
624 if (lease_path.substr(0,1)!=
"/") { lease_path =
"/" + lease_path; }
628 string public_keys = kConfigDir + repo_name +
"/pubkey";
629 string key_file = kConfigDir + repo_name +
"/gatewaykey";
630 string s3_file = kConfigDir + repo_name +
"/s3.conf";
632 if( args.find(
'k') != args.end()) {
633 public_keys = *args.find(
'k')->second;
635 if( args.find(
's') != args.end()) {
636 key_file = *args.find(
's')->second;
638 if( args.find(
'3') != args.end()) {
639 s3_file = *args.find(
'3')->second;
642 CUSTOM_ASSERT(access(public_keys.c_str(), R_OK) == 0,
"%s is not readable", public_keys.c_str());
643 CUSTOM_ASSERT(access(key_file.c_str(), R_OK) == 0,
"%s is not readable", key_file.c_str());
647 string const spooler_definition_string = string(
"S3,") + dir_temp +
"," + repo_name +
"@" + s3_file;
655 uint64_t current_revision=0;
656 std::string current_root_hash=
"";
663 ¤t_revision, current_root_hash, lease_busy_retry_interval);
666 char *_tmpfile = strdup( (dir_temp +
"/gateway_session_token_XXXXXX").c_str() );
667 int const temp_fd = mkstemp(_tmpfile);
671 FILE *fout=fdopen(temp_fd,
"wb");
673 fputs(g_session_token.c_str(), fout);
677 pthread_t lease_thread;
691 if (args.find(
'q') != args.end()) {
700 upload::Spooler::Construct(spooler_definition_catalogs,
nullptr));
702 if (!spooler_catalogs.IsValid()) {
728 if(current_revision > 0 ) {
729 if( current_revision == manifest->revision() ) {
730 if (current_root_hash != manifest->catalog_hash().ToString() ) {
731 LogCvmfs(
kLogCvmfs,
kLogStderr,
"Mismatch between cvmfspublished and gateway hash for revision %lu (%s!=%s)", current_revision, current_root_hash.c_str(), manifest->catalog_hash().ToString().c_str() );
738 if( current_revision > manifest->revision() ) {
739 LogCvmfs(
kLogCvmfs,
kLogStdout,
"Gateway has supplied a newer revision than the current .cvmfspublished %lu > %lu", current_revision, manifest->revision() );
740 manifest->set_revision(current_revision);
742 }
else if (current_revision < manifest->revision() ) {
743 LogCvmfs(
kLogCvmfs,
kLogStdout,
"Gateway has supplied an older revision than the current .cvmfspublished %lu < %lu", current_revision, manifest->revision() );
751 string const old_root_hash = manifest->catalog_hash().ToString(
true);
752 string const hash = old_root_hash.substr(0, old_root_hash.length() - 1);
757 bool const is_balanced =
false;
760 base_hash, stratum0, dir_temp, spooler_catalogs.weak_ref(),
765 catalog_manager.
Init();
769 vector<sqlite3*> open_dbs;
770 for (
auto&& db_file : sqlite_db_vec) {
772 CHECK_SQLITE_ERROR(sqlite3_open_v2(db_file.c_str(), &db, SQLITE_OPEN_READONLY, NULL), SQLITE_OK);
774 open_dbs.push_back(db);
777 allow_deletions, lease_path.substr(1), additional_prefix);
778 for (
auto&& db : open_dbs) {
784 if (!catalog_manager.Commit(
false,
false, manifest.
weak_ref())) {
792 spooler_catalogs->WaitForUpload();
800 const string new_root_hash = manifest->catalog_hash().ToString(
true);
825 if(check_completed_graft_property) {
843 while ((startPos = str.find(from, startPos)) != std::string::npos) {
844 str.replace(startPos, from.length(), to);
845 startPos += to.length();
851 const std::vector<sqlite3*> &dbs,
853 bool allow_additions,
bool allow_deletions,
const std::string &lease_path,
const std::string &additional_prefix)
855 std::map<std::string, Directory> all_dirs;
856 std::map<std::string, std::vector<File>> all_files;
857 std::map<std::string, std::vector<Symlink>> all_symlinks;
859 for (
auto&& db : dbs) {
860 load_dirs(db, lease_path, additional_prefix, all_dirs);
866 std::unordered_set<std::string> dir_names;
867 std::transform(all_dirs.begin(), all_dirs.end(), std::inserter(dir_names, dir_names.end()),
868 [](
const std::pair<std::string, Directory>& pair) {
874 for (
auto&& db : dbs) {
875 load_files(db, lease_path, additional_prefix, all_files);
876 load_symlinks(db, lease_path, additional_prefix, all_symlinks);
880 if (allow_deletions) {
882 for (
auto&& db : dbs) {
883 CHECK_SQLITE_ERROR(do_deletions(db, catalog_manager, lease_path, additional_prefix), SQLITE_OK);
887 if (allow_additions) {
890 do_additions(all_dirs, all_files, all_symlinks, lease_path, catalog_manager);
894 void add_dir_to_tree(std::string path, std::unordered_map<std::string, std::set<std::string>> &tree,
const std::string &lease_path) {
899 while (path != parent_path && path != lease_path && !tree[parent_path].count(path)) {
900 tree[parent_path].insert(path);
913 std::unordered_map<std::string, std::set<std::string>> tree;
914 for (
auto&& p : all_dirs) {
917 for (
auto&& p : all_files) {
920 for (
auto&& p : all_symlinks) {
923 int const row_count =
static_cast<int>(tree.size());
926 LogCvmfs(
kLogCvmfs,
kLogStdout,
"Changeset: %ld dirs, %ld files, %ld symlinks", tree.size(), all_files.size(), all_symlinks.size());
933 std::stack<string> dfs_stack;
934 for (
auto&& p : tree) {
936 if (p.first ==
"" || !tree.count(
get_parent(p.first))) {
937 CUSTOM_ASSERT(dfs_stack.empty(),
"provided DB input forms more than one path trees");
938 dfs_stack.push(p.first);
941 std::set<string> visited;
942 while (!dfs_stack.empty()) {
943 string const curr_dir = dfs_stack.top();
945 if (visited.count(curr_dir)) {
947 if (all_symlinks.count(curr_dir)) {
948 add_symlinks(catalog_manager, all_symlinks.at(curr_dir));
950 if (all_files.count(curr_dir)) {
951 add_files(catalog_manager, all_files.at(curr_dir));
964 SHOW_PROGRESS(
"directories", print_every, curr_row, row_count);
966 visited.insert(curr_dir);
968 auto it = tree.find(curr_dir);
969 if (it != tree.end()) {
970 for (
auto&& child : it->second) {
971 dfs_stack.push(child);
975 if (!all_dirs.count(curr_dir))
continue;
984 CUSTOM_ASSERT(!(exists && !S_ISDIR(dir_entry.
mode_)),
"Refusing to replace existing file/symlink at %s with a directory", dir.
name.c_str());
989 dir_entry.
mode_ &= (S_IFDIR | 0777);
994 bool add_nested_catalog=
false;
999 add_nested_catalog=
true;
1007 if(dir.
nested) {add_nested_catalog=
true;}
1009 if (add_nested_catalog) {
1015 dir2.mtime_ = dir.
mtime / 1000000000;
1016 dir2.mode_ = (S_IFREG | 0666);
1019 dir2.has_xattrs_ = 0;
1033 CUSTOM_ASSERT(tree.empty(),
"not all directories are processed, malformed input DB?");
1041 for (
auto&& symlink : symlinks) {
1045 bool exists =
false;
1050 dir2.
mtime_ = symlink.mtime / 1000000000;
1051 dir2.
uid_ = symlink.owner;
1052 dir2.
gid_ = symlink.grp;
1055 dir2.
mode_ = S_IFLNK | 0777;
1060 if(symlink.skip_if_file_or_dir) {
1061 if(S_ISDIR(dir.
mode_) || S_ISREG(dir.
mode_)) {
1064 }
else if (S_ISLNK(dir.
mode_)) {
1066 symlink.name.c_str());
1072 CUSTOM_ASSERT(!S_ISDIR(dir.
mode_),
"Not removing directory [%s] to create symlink", symlink.name.c_str());
1074 symlink.name.c_str());
1079 string const parent =
get_parent(symlink.name);
1081 catalog_manager.
AddFile(dir2, xattr, parent);
1088 if (strlen(hash)!=40) {
return 1;}
1089 for(
int i=0; i<40; i++ ) {
1091 if( hash[i]<0x30 || hash[i]>0x66 || ( hash[i]>0x39 && hash[i] <0x61 )) {
1099 if (prefix==
"" || prefix==
"/") {
return true;}
1100 if (
"/"+path == prefix ) {
return true; }
1111 string select_stmt =
"SELECT name, mode, mtime, owner, grp, acl, nested FROM dirs";
1112 if (schema_revision <= 3) {
1113 select_stmt =
"SELECT name, mode, mtime, owner, grp, acl FROM dirs";
1115 int const ret = sqlite3_prepare_v2(db, select_stmt.c_str(), -1, &stmt, NULL);
1117 while (sqlite3_step(stmt) == SQLITE_ROW) {
1118 char *name_cstr = (
char *)sqlite3_column_text(stmt, 0);
1119 mode_t
const mode = sqlite3_column_int(stmt, 1);
1120 time_t
const mtime = sqlite3_column_int64(stmt, 2);
1121 uid_t
const owner = sqlite3_column_int(stmt, 3);
1122 gid_t
const grp = sqlite3_column_int(stmt, 4);
1123 int const nested = schema_revision <= 3 ? 1 : sqlite3_column_int(stmt, 6);
1125 string const name = additional_prefix +
sanitise_name(name_cstr);
1128 Directory dir(name, mtime, mode, owner, grp, nested);
1129 char *acl = (
char *)sqlite3_column_text(stmt, 5);
1131 all_dirs.insert(std::make_pair(name, dir));
1139 string select_stmt =
"SELECT name, mode, mtime, owner, grp, size, hashes, internal, compressed FROM files";
1140 if (schema_revision <= 2) {
1141 select_stmt =
"SELECT name, mode, mtime, owner, grp, size, hashes, internal FROM files";
1143 int const ret = sqlite3_prepare_v2(db, select_stmt.c_str(), -1, &stmt, NULL);
1145 while (sqlite3_step(stmt) == SQLITE_ROW) {
1146 char *name = (
char *)sqlite3_column_text(stmt, 0);
1147 mode_t
const mode = sqlite3_column_int(stmt, 1);
1148 time_t
const mtime = sqlite3_column_int64(stmt, 2);
1149 uid_t
const owner = sqlite3_column_int(stmt, 3);
1150 gid_t
const grp = sqlite3_column_int(stmt, 4);
1151 size_t const size = sqlite3_column_int64(stmt, 5);
1152 char *hashes_cstr = (
char *)sqlite3_column_text(stmt, 6);
1153 int const internal = sqlite3_column_int(stmt, 7);
1154 int const compressed = schema_revision <= 2 ? 0 : sqlite3_column_int(stmt, 8);
1160 if (!all_files.count(parent_dir)) {
1161 all_files[parent_dir] = vector<swissknife::IngestSQL::File>();
1163 all_files[parent_dir].emplace_back(std::move(names), mtime, size, owner, grp, mode,
internal, compressed);
1168 tok = strtok_r(hashes_cstr,
",", &ref);
1169 vector<off_t> offsets;
1170 vector<size_t> sizes;
1171 vector<shash::Any> hashes;
1174 CUSTOM_ASSERT(size>=0,
"file size cannot be negative [%s]", names.c_str());
1178 offsets.push_back(offset);
1183 tok = strtok_r(NULL,
",", &ref);
1184 offset += kChunkSize;
1187 size_t expected_num_chunks = size/kChunkSize;
1188 if (expected_num_chunks * (
size_t)kChunkSize < (
size_t) size || size==0 ) { expected_num_chunks++; }
1189 CUSTOM_ASSERT(offsets.size() == expected_num_chunks,
"offsets size %ld does not match expected number of chunks %ld", offsets.size(), expected_num_chunks);
1190 for (
size_t i = 0; i < offsets.size() - 1; i++) {
1191 sizes.push_back(
size_t(offsets[i + 1] - offsets[i]));
1194 sizes.push_back(
size_t(size - offsets[offsets.size() - 1]));
1195 for (
size_t i = 0; i < offsets.size(); i++) {
1197 all_files[parent_dir].back().chunks.PushBack(chunk);
1205 string const select_stmt =
"SELECT name, target, mtime, owner, grp, skip_if_file_or_dir FROM links";
1206 int const ret = sqlite3_prepare_v2(db, select_stmt.c_str(), -1, &stmt, NULL);
1208 while (sqlite3_step(stmt) == SQLITE_ROW) {
1209 char *name_cstr = (
char *)sqlite3_column_text(stmt, 0);
1210 char *target_cstr = (
char *)sqlite3_column_text(stmt, 1);
1211 time_t
const mtime = sqlite3_column_int64(stmt, 2);
1212 uid_t
const owner = sqlite3_column_int(stmt, 3);
1213 gid_t
const grp = sqlite3_column_int(stmt, 4);
1214 int const skip_if_file_or_dir = sqlite3_column_int(stmt, 5);
1216 string names = additional_prefix +
sanitise_name(name_cstr);
1218 string target= target_cstr;
1221 if (!all_symlinks.count(parent_dir)) {
1222 all_symlinks[parent_dir] = vector<swissknife::IngestSQL::Symlink>();
1224 all_symlinks[parent_dir].emplace_back(std::move(names), std::move(target), mtime, owner, grp, skip_if_file_or_dir);
1232 for (
auto&& file : files) {
1235 bool exists =
false;
1240 dir.
mtime_ = file.mtime / 1000000000;
1241 dir.
mode_ = file.mode | S_IFREG;
1242 dir.
mode_ &= (S_IFREG | 0777);
1243 dir.
uid_ = file.owner;
1244 dir.
gid_ = file.grp;
1245 dir.
size_ = file.size;
1254 CUSTOM_ASSERT(file.internal || (!file.internal && file.compressed<2),
"compression is only allowed for internal data [%s]", file.name.c_str());
1256 switch (file.compressed) {
1269 CUSTOM_ASSERT(!S_ISDIR(dir.
mode()) && !S_ISLNK(dir.
mode()),
"Refusing to replace existing dir/symlink at %s with a file", file.name.c_str());
1287 int ret = sqlite3_prepare_v2(db,
"SELECT name, directory, file, link FROM deletions ORDER BY length(name) DESC", -1, &stmt, NULL);
1289 while (sqlite3_step(stmt) == SQLITE_ROW) {
1292 char *name = (
char *)sqlite3_column_text(stmt, 0);
1293 int64_t
const isdir = sqlite3_column_int64(stmt, 1);
1294 int64_t
const isfile = sqlite3_column_int64(stmt, 2);
1295 int64_t
const islink = sqlite3_column_int64(stmt, 3);
1297 string const names = additional_prefix +
sanitise_name(name);
1301 bool exists =
false;
1305 if( (isdir && S_ISDIR(dirent.mode()) )
1306 || (islink && S_ISLNK(dirent.mode()) )
1307 || (isfile && S_ISREG(dirent.mode()) ) ) {
1308 if (S_ISDIR(dirent.mode())) {
1316 LogCvmfs(
kLogCvmfs,
kLogVerboseMsg,
"Mismatch in deletion type, not deleting: [%s] (dir %ld/%d , link %ld/%d, file %ld/%d)", names.c_str(), isdir, S_ISDIR(dirent.mode()), islink, S_ISLNK(dirent.mode()), isfile, S_ISREG(dirent.mode()) );
1323 SHOW_PROGRESS(
"deletions", print_every, curr_row, row_count);
1325 ret = sqlite3_finalize(stmt);
1330 "PRAGMA journal_mode=WAL;",
1332 "CREATE TABLE IF NOT EXISTS dirs ( \
1333 name TEXT PRIMARY KEY, \
1334 mode INTEGER NOT NULL DEFAULT 493,\
1335 mtime INTEGER NOT NULL DEFAULT (unixepoch()),\
1336 owner INTEGER NOT NULL DEFAULT 0, \
1337 grp INTEGER NOT NULL DEFAULT 0, \
1338 acl TEXT NOT NULL DEFAULT '', \
1339 nested INTEGER DEFAULT 1);",
1341 "CREATE TABLE IF NOT EXISTS files ( \
1342 name TEXT PRIMARY KEY, \
1343 mode INTEGER NOT NULL DEFAULT 420, \
1344 mtime INTEGER NOT NULL DEFAULT (unixepoch()),\
1345 owner INTEGER NOT NULL DEFAULT 0,\
1346 grp INTEGER NOT NULL DEFAULT 0,\
1347 size INTEGER NOT NULL DEFAULT 0,\
1348 hashes TEXT NOT NULL DEFAULT '',\
1349 internal INTEGER NOT NULL DEFAULT 0,\
1350 compressed INTEGER NOT NULL DEFAULT 0\
1353 "CREATE TABLE IF NOT EXISTS links (\
1354 name TEXT PRIMARY KEY,\
1355 target TEXT NOT NULL DEFAULT '',\
1356 mtime INTEGER NOT NULL DEFAULT (unixepoch()),\
1357 owner INTEGER NOT NULL DEFAULT 0,\
1358 grp INTEGER NOT NULL DEFAULT 0,\
1359 skip_if_file_or_dir INTEGER NOT NULL DEFAULT 0\
1362 "CREATE TABLE IF NOT EXISTS deletions (\
1363 name TEXT PRIMARY KEY,\
1364 directory INTEGER NOT NULL DEFAULT 0,\
1365 file INTEGER NOT NULL DEFAULT 0,\
1366 link INTEGER NOT NULL DEFAULT 0\
1369 "CREATE TABLE IF NOT EXISTS properties (\
1370 key TEXT PRIMARY KEY,\
1371 value TEXT NOT NULL\
1374 "INSERT INTO properties VALUES ('schema_revision', '4') ON CONFLICT DO NOTHING;",
1381 int ret = sqlite3_open_v2(filename.c_str(), &db_out, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
1385 const char **ptr =
schema;
1386 while (*ptr!=NULL) {
1387 ret = sqlite3_exec(db_out, *ptr, NULL, NULL, NULL);
1391 sqlite3_close(db_out);
1405 for (
unsigned i = 0; i < listing_from_catalog.
size(); ++i) {
1408 entry_path.
Append(
"/", 1);
1409 entry_path.
Append(listing_from_catalog.
AtPtr(i)->name.GetChars(),
1410 listing_from_catalog.
AtPtr(i)->name.GetLength());
1412 if( S_ISDIR( listing_from_catalog.
AtPtr(i)->info.st_mode) ) {
1435 ret = sqlite3_exec(db,
"PRAGMA temp_store=2", NULL, NULL, NULL);
1437 ret = sqlite3_exec(db,
"PRAGMA synchronous=OFF", NULL, NULL, NULL);
1456 ret = sqlite3_open(dbfile, &db);
1457 if (ret!=SQLITE_OK) {
return false; }
1459 const char *req =
"SELECT value FROM properties WHERE key='completed_graft'";
1460 ret = sqlite3_prepare_v2(db, req, -1, &stmt, NULL);
1461 if (ret!=SQLITE_OK) {
1464 if(sqlite3_step(stmt) == SQLITE_ROW) {
1465 int const id = sqlite3_column_int(stmt,0);
1479 ret = sqlite3_open(dbfile, &db);
1480 if (ret!=SQLITE_OK) {
return; }
1482 const char *req =
"INSERT INTO properties (key, value) VALUES ('completed_graft',1) ON CONFLICT(key) DO UPDATE SET value=1 WHERE key='completed_graft'";
1484 ret = sqlite3_exec(db, req, 0, 0, &err);
1485 if (ret!=SQLITE_OK) {
static bool g_lease_acquired
void load_symlinks(sqlite3 *db, const std::string &lease_path, const std::string &additional_prefix, std::map< std::string, std::vector< Symlink >> &all_symlinks)
void SetLogVerbosity(const LogLevels max_level)
static int check_hash(const char *hash)
bool IsSubPath(const PathString &parent, const PathString &path)
void AddChunkedFile(const DirectoryEntryBase &entry, const XattrList &xattrs, const std::string &parent_directory, const FileChunkList &file_chunks)
static const size_t kDefaultMaxFileChunkSize
const manifest::Manifest * manifest() const
ShortString< kDefaultMaxName, 1 > NameString
std::map< std::string, std::vector< File > > FileMap
static string g_gateway_secret
std::map< std::string, std::vector< Symlink > > SymlinkMap
void set_is_chunked_file(const bool val)
void AddDirectory(const DirectoryEntryBase &entry, const XattrList &xattrs, const std::string &parent_directory)
bool MakeEndRequest(const std::string &method, const std::string &key_id, const std::string &secret, const std::string &session_token, const std::string &repo_service_url, const std::string &request_payload, CurlBuffer *reply, bool expect_final_revision)
static void create_empty_database(string &filename)
void process_sqlite(const std::vector< sqlite3 * > &dbs, catalog::WritableCatalogManager &catalog_manager, bool allow_additions, bool allow_deletions, const std::string &lease_path, const std::string &additional_prefix)
static string get_parent(const string &path)
SpoolerDefinition Dup2DefaultCompression() const
static vector< string > get_all_dirs_from_sqlite(vector< string > &sqlite_db_vec, bool include_additions, bool include_deletions)
static const unsigned kDefaultMaxWeight
LeaseReply ParseAcquireReplyWithRevision(const CurlBuffer &buffer, std::string *session_token, uint64_t *current_revision, std::string ¤t_root_hash)
static string MakeCatalogPath(const std::string &relative_path)
bool Set(const std::string &key, const std::string &value)
static string g_gateway_url
static const unsigned kDefaultFileMbyteLimit
void RemoveDirectory(const std::string &directory_path)
void Assign(const char *chars, const unsigned length)
static void cancel_lease()
void load_files(sqlite3 *db, const std::string &lease_path, const std::string &additional_prefix, std::map< std::string, std::vector< File >> &all_files)
static const unsigned kDefaultNestedKcatalogLimit
static void setDatabaseMarkedComplete(const char *dbfile)
static const unsigned kDefaultRootKcatalogLimit
static string get_basename(const string &path)
int kCatalogDownloadMultiplier
#define SHOW_PROGRESS(item, freq, curr, total)
static void recursively_delete_directory(PathString &path, catalog::WritableCatalogManager &catalog_manager)
bool ListingStat(const PathString &path, StatEntryList *listing)
assert((mem||(size==0))&&"Out Of Memory")
static string get_lease_from_paths(vector< string > paths)
std::map< std::string, Directory > DirMap
unsigned int number_of_concurrent_uploads
void load_dirs(sqlite3 *db, const std::string &lease_path, const std::string &additional_prefix, std::map< std::string, Directory > &all_dirs)
static vector< string > get_file_list(string &path)
static string acquire_lease(const string &key_id, const string &secret, const string &lease_path, const string &repo_service_url, bool force_cancel_lease, uint64_t *current_revision, string ¤t_root_hash, unsigned int refresh_interval)
static void on_signal(int sig)
unsigned int mode() const
const unsigned kLookupDefault
static bool check_prefix(const std::string &path, const std::string &prefix)
static const unsigned kInternalChunkSize
static const size_t kDefaultMinFileChunkSize
static void relax_db_locking(sqlite3 *db)
bool IsNestedCatalogMountpoint() const
bool IsTransitionPoint(const std::string &mountpoint)
void add_dir_to_tree(std::string path, std::unordered_map< std::string, std::set< std::string >> &tree, const std::string &lease_path)
bool IsNestedCatalogRoot() const
void TouchDirectory(const DirectoryEntryBase &entry, const XattrList &xattrs, const std::string &directory_path)
static int get_db_schema_revision(sqlite3 *db, const std::string &db_name="")
std::vector< DirectoryEntry > DirectoryEntryList
zlib::Algorithms compression_algorithm_
static bool g_add_missing_catalogs
#define CHECK_SQLITE_ERROR(ret, expected)
static void refresh_lease()
void replaceAllSubstrings(std::string &str, const std::string &from, const std::string &to)
static const unsigned kDefaultLeaseBusyRetryInterval
std::unordered_map< string, string > load_config(const string &config_file)
static int calculate_print_frequency(int total)
void RemoveSingleCatalogUploadCallback()
static string g_session_token
bool HasSuffix(const std::string &str, const std::string &suffix, const bool ignore_case)
static const unsigned kDefaultMinWeight
const char kSuffixCatalog
int acl_from_text_to_xattr_value(const string &textual_acl, char *&o_binary_acl, size_t &o_size, bool &o_equiv_mode)
static string g_gateway_key_id
int add_symlinks(catalog::WritableCatalogManager &catalog_manager, const std::vector< Symlink > &symlinks)
int Main(const ArgumentList &args)
static uint64_t make_commit_on_gateway(const std::string &old_root_hash, const std::string &new_root_hash, int64_t priority)
int add_files(catalog::WritableCatalogManager &catalog_manager, const std::vector< File > &files)
static time_t g_last_lease_refresh
void AddCatalogToQueue(const std::string &path)
bool ReadKeys(const std::string &key_file_name, std::string *key_id, std::string *secret)
static bool g_stop_refresh
static int64_t g_priority
void Append(const char *chars, const unsigned length)
static const unsigned kExternalChunkSize
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
#define CUSTOM_ASSERT(check, msg,...)
void RemoveFile(const std::string &file_path)
string retrieve_config(std::unordered_map< string, string > &config_map, const string &key)
void SetupSingleCatalogUploadCallback()
int do_additions(const DirMap &all_dirs, const FileMap &all_files, const SymlinkMap &all_symlinks, const std::string &lease_path, catalog::WritableCatalogManager &catalog_manager)
static int get_row_count(sqlite3 *db, const std::string &table_name)
void RemoveNestedCatalog(const std::string &mountpoint, const bool merge=true)
std::string ToString() const
size_t writeFunction(void *ptr, size_t size, size_t nmemb, std::string *data)
int do_deletions(sqlite3 *db, catalog::WritableCatalogManager &catalog_manager, const std::string &lease_path, const std::string &additional_prefix)
ShortString< kDefaultMaxLink, 2 > LinkString
static void MakeAcquireRequest(const gateway::GatewayKey &key, const std::string &repo_path, const std::string &repo_service_url, int llvl, CurlBuffer *buffer)
uint64_t String2Uint64(const string &value)
std::map< char, SharedPtr< std::string > > ArgumentList
void * lease_refresh_thread(void *payload)
ShortString< kDefaultMaxPath, 0 > PathString
void LoadCatalogs(const std::string &base_path, const std::unordered_set< std::string > &dirs)
static const size_t kDefaultAvgFileChunkSize
Any MkFromHexPtr(const HexPtr hex, const char suffix)
void ScheduleReadyCatalogs()
static string sanitise_name(const char *name_cstr, bool allow_leading_slash)
static const unsigned kLeaseRefreshInterval
std::string MakeCanonicalPath(const std::string &path)
const upload::Spooler * spooler_catalogs() const
void AddFile(const DirectoryEntryBase &entry, const XattrList &xattrs, const std::string &parent_directory)
static XattrList marshal_xattrs(const char *acl)
const char * c_str() const
static LeaseReply ParseDropReply(const CurlBuffer &buffer, int llvl)
static bool isDatabaseMarkedComplete(const char *dbfile)
bool LookupDirEntry(const std::string &path, const LookupOptions options, DirectoryEntry *dirent)
const Item * AtPtr(const size_t index) const
void CreateNestedCatalog(const std::string &mountpoint)
static string g_session_token_file
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)