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 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 found = path.find_last_of(
'/');
143 if (found == string::npos) {
146 return path.substr(0, found);
150 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 CURLcode ret = curl_global_init(CURL_GLOBAL_ALL);
167 bool acquired =
false;
169 string gateway_metadata_str;
170 char *gateway_metadata = getenv(
"CVMFS_GATEWAY_METADATA");
171 if (gateway_metadata != NULL) gateway_metadata_str = gateway_metadata;
176 &buffer, gateway_metadata_str)) {
177 string session_token;
185 return session_token;
188 if( force_cancel_lease ) {
193 sleep(refresh_interval);
197 buffer.
data.c_str(), refresh_interval);
198 sleep(refresh_interval);
202 sleep(refresh_interval);
209 static uint64_t
make_commit_on_gateway(
const std::string &old_root_hash,
const std::string &new_root_hash,
int priority) {
211 char priorityStr[100];
212 sprintf(priorityStr,
"%d", priority);
215 std::string payload =
"{\n\"old_root_hash\": \"" + old_root_hash +
"\",\n\"new_root_hash\": \""+new_root_hash+
"\",\n\"priority\": "+priorityStr+
"}";
237 if(buffer.
data ==
"Method Not Allowed\n") {
263 signal(sig, SIG_DFL);
269 if (sig == SIGINT || sig == SIGTERM) exit(1);
273 bool include_additions,
274 bool include_deletions) {
276 vector<string> paths;
278 for (vector<string>::iterator it = sqlite_db_vec.begin();
279 it != sqlite_db_vec.end(); it++) {
281 ret = sqlite3_open_v2((*it).c_str(), &db, SQLITE_OPEN_READONLY, NULL);
285 vector<string> tables;
286 if (include_additions) {
287 tables.push_back(
"dirs");
288 tables.push_back(
"links");
289 tables.push_back(
"files");
291 if (include_deletions) {
292 tables.push_back(
"deletions");
296 for (vector<string>::iterator it = tables.begin(); it != tables.end();
299 string query =
"SELECT name FROM " + *it;
300 ret = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
302 while (sqlite3_step(stmt) == SQLITE_ROW) {
303 char *name = (
char *)sqlite3_column_text(stmt, 0);
306 paths.push_back(names);
311 ret = sqlite3_finalize(stmt);
314 ret = sqlite3_close_v2(db);
322 std::ostringstream stmt_str;
323 stmt_str <<
"SELECT value FROM " << db_name <<
"properties WHERE key = 'schema_revision'";
324 int ret = sqlite3_prepare_v2(db, stmt_str.str().c_str(), -1, &stmt, NULL);
327 ret = sqlite3_step(stmt);
330 std::string schema_revision_str(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)));
332 return std::stoi(schema_revision_str);
337 std::ostringstream stmt_str;
338 stmt_str <<
"SELECT COUNT(*) FROM " << table_name;
339 int ret = sqlite3_prepare_v2(db, stmt_str.str().c_str(), -1, &stmt, NULL);
342 ret = sqlite3_step(stmt);
344 std::string count_str(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)));
346 return std::stoi(count_str);
351 while (base * 50 < total) base *= 10;
362 for (
auto it = paths.begin() + 1; it != paths.end(); ++it) {
366 auto i = lease.GetLength() - 1;
367 for (; i >= 0; --i) {
368 if (lease.GetChars()[i] ==
'/' || i == 0) {
374 if (lease.IsEmpty())
break;
377 auto prefix =
"/" + lease.ToString();
386 if (acl_string == NULL || acl_string[0] ==
'\0') {
400 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);
407 std::unordered_map<string, string>
load_config(
const string& config_file) {
408 std::unordered_map<string, string> config_map;
409 ifstream input(config_file);
414 vector<string> lines;
415 for (
string line; getline(input, line);) {
416 lines.push_back(line);
419 for (
auto it = lines.begin(); it != lines.end(); it++) {
421 size_t p = l.find(
"=", 0);
422 if (p != string::npos) {
423 string key = l.substr(0, p);
424 string val = l.substr(p + 1);
426 if (val.front() ==
'"') {
427 val = val.substr(1, val.length() - 2);
429 config_map[key] = val;
436 string retrieve_config(std::unordered_map<string, string> &config_map,
const string& key) {
437 auto kv = config_map.find(key);
438 CUSTOM_ASSERT(kv != config_map.end(),
"Parameter %s not found in config", key.c_str());
443 vector<string> paths;
444 const char *cpath = path.c_str();
446 int ret = stat(cpath, &st);
449 if (S_ISDIR(st.st_mode)) {
454 while ((dir = readdir(d)) != NULL) {
455 const char *t = strrchr(dir->d_name,
'.');
456 if (t && !strcmp(t,
".db")) {
457 paths.push_back(path +
"/" + dir->d_name);
463 paths.push_back(path);
479 bool enable_corefiles = (args.find(
'c') != args.end());
480 if( !enable_corefiles ) {
482 rlim.rlim_cur = rlim.rlim_max = 0;
483 setrlimit( RLIMIT_CORE, &rlim );
487 if (args.find(
'n') != args.end()) {
496 if (args.find(
'P') != args.end()) {
497 g_priority = atoi((*args.find(
'P')->second).c_str());
504 if (args.find(
'r') != args.end()) {
505 lease_busy_retry_interval = atoi((*args.find(
'r')->second).c_str());
508 string dir_temp =
"";
509 if (args.find(
't') != args.end()) {
511 }
else if (getenv(
"TMPDIR")) {
518 string kConfigDir(
"/etc/cvmfs/gateway-client/");
519 if (args.find(
'C') != args.end()) {
526 string repo_name = *args.find(
'N')->second;
527 string sqlite_db_path = *args.find(
'D')->second;
529 vector<string> sqlite_db_vec =
get_file_list(sqlite_db_path);
532 bool allow_deletions = (args.find(
'd') != args.end());
533 bool force_cancel_lease = (args.find(
'x') != args.end());
534 bool allow_additions = !allow_deletions || (args.find(
'a') != args.end());
536 bool check_completed_graft_property = ( args.find(
'Z') != args.end());
537 if (args.find(
'v') != args.end()) {
541 if(check_completed_graft_property) {
542 if(sqlite_db_vec.size()!=1) {
554 string config_file = kConfigDir + repo_name +
"/config";
558 string additional_prefix=
"";
559 bool has_additional_prefix=
false;
560 if (args.find(
'p') != args.end()) {
561 additional_prefix=*args.find(
'p')->second;
562 additional_prefix =
sanitise_name(additional_prefix.c_str(),
true);
563 if( additional_prefix.back() !=
'/' ) {
564 additional_prefix +=
"/";
566 has_additional_prefix=
true;
572 if (args.find(
'g') != args.end()) {
577 if (args.find(
'w') != args.end()) {
578 stratum0 = *args.find(
'w')->second;
583 if (args.find(
'@') != args.end()) {
584 proxy = *args.find(
'@')->second;
589 string lease_path=
"";
591 if (args.find(
'l') != args.end()) {
592 lease_path = *args.find(
'l')->second;
596 sqlite_db_vec, allow_additions, allow_deletions);
597 if (paths.size() == 0) {
605 if (has_additional_prefix) {
606 if (lease_path ==
"/" ) { lease_path =
"/" + additional_prefix; }
608 if ( lease_path.substr(0,1)==
"/" ) {
609 lease_path =
"/" + additional_prefix + lease_path.substr(1, lease_path.size()-1);
611 lease_path =
"/" + additional_prefix + lease_path;
615 if (lease_path.substr(0,1)!=
"/") { lease_path =
"/" + lease_path; }
619 string public_keys = kConfigDir + repo_name +
"/pubkey";
620 string key_file = kConfigDir + repo_name +
"/gatewaykey";
621 string s3_file = kConfigDir + repo_name +
"/s3.conf";
623 if( args.find(
'k') != args.end()) {
624 public_keys = *args.find(
'k')->second;
626 if( args.find(
's') != args.end()) {
627 key_file = *args.find(
's')->second;
629 if( args.find(
'3') != args.end()) {
630 s3_file = *args.find(
'3')->second;
633 CUSTOM_ASSERT(access(public_keys.c_str(), R_OK) == 0,
"%s is not readable", public_keys.c_str());
634 CUSTOM_ASSERT(access(key_file.c_str(), R_OK) == 0,
"%s is not readable", key_file.c_str());
638 string spooler_definition_string = string(
"S3,") + dir_temp +
"," + repo_name +
"@" + s3_file;
646 uint64_t current_revision=0;
647 std::string current_root_hash=
"";
654 ¤t_revision, current_root_hash, lease_busy_retry_interval);
657 char *_tmpfile = strdup( (dir_temp +
"/gateway_session_token_XXXXXX").c_str() );
658 int temp_fd = mkstemp(_tmpfile);
662 FILE *fout=fdopen(temp_fd,
"wb");
664 fputs(g_session_token.c_str(), fout);
668 pthread_t lease_thread;
682 if (args.find(
'q') != args.end()) {
691 upload::Spooler::Construct(spooler_definition_catalogs,
nullptr));
693 if (!spooler_catalogs.IsValid()) {
719 if(current_revision > 0 ) {
720 if( current_revision == manifest->revision() ) {
721 if (current_root_hash != manifest->catalog_hash().ToString() ) {
722 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() );
729 if( current_revision > manifest->revision() ) {
730 LogCvmfs(
kLogCvmfs,
kLogStdout,
"Gateway has supplied a newer revision than the current .cvmfspublished %lu > %lu", current_revision, manifest->revision() );
731 manifest->set_revision(current_revision);
733 }
else if (current_revision < manifest->revision() ) {
734 LogCvmfs(
kLogCvmfs,
kLogStdout,
"Gateway has supplied an older revision than the current .cvmfspublished %lu < %lu", current_revision, manifest->revision() );
742 string old_root_hash = manifest->catalog_hash().ToString(
true);
743 string hash = old_root_hash.substr(0, old_root_hash.length() - 1);
748 bool is_balanced =
false;
751 base_hash, stratum0, dir_temp, spooler_catalogs.weak_ref(),
756 catalog_manager.
Init();
760 vector<sqlite3*> open_dbs;
761 for (
auto&& db_file : sqlite_db_vec) {
763 CHECK_SQLITE_ERROR(sqlite3_open_v2(db_file.c_str(), &db, SQLITE_OPEN_READONLY, NULL), SQLITE_OK);
765 open_dbs.push_back(db);
768 allow_deletions, lease_path.substr(1), additional_prefix);
769 for (
auto&& db : open_dbs) {
775 if (!catalog_manager.Commit(
false,
false, manifest.
weak_ref())) {
783 spooler_catalogs->WaitForUpload();
791 const string new_root_hash = manifest->catalog_hash().ToString(
true);
816 if(check_completed_graft_property) {
834 while ((startPos = str.find(from, startPos)) != std::string::npos) {
835 str.replace(startPos, from.length(), to);
836 startPos += to.length();
842 const std::vector<sqlite3*> &dbs,
844 bool allow_additions,
bool allow_deletions,
const std::string &lease_path,
const std::string &additional_prefix)
846 std::map<std::string, Directory> all_dirs;
847 std::map<std::string, std::vector<File>> all_files;
848 std::map<std::string, std::vector<Symlink>> all_symlinks;
850 for (
auto&& db : dbs) {
851 load_dirs(db, lease_path, additional_prefix, all_dirs);
857 std::unordered_set<std::string> dir_names;
858 std::transform(all_dirs.begin(), all_dirs.end(), std::inserter(dir_names, dir_names.end()),
859 [](
const std::pair<std::string, Directory>& pair) {
865 for (
auto&& db : dbs) {
866 load_files(db, lease_path, additional_prefix, all_files);
867 load_symlinks(db, lease_path, additional_prefix, all_symlinks);
871 if (allow_deletions) {
873 for (
auto&& db : dbs) {
874 CHECK_SQLITE_ERROR(do_deletions(db, catalog_manager, lease_path, additional_prefix), SQLITE_OK);
878 if (allow_additions) {
881 do_additions(all_dirs, all_files, all_symlinks, lease_path, catalog_manager);
885 void add_dir_to_tree(std::string path, std::unordered_map<std::string, std::set<std::string>> &tree,
const std::string &lease_path) {
890 while (path != parent_path && path != lease_path && !tree[parent_path].count(path)) {
891 tree[parent_path].insert(path);
904 std::unordered_map<std::string, std::set<std::string>> tree;
905 for (
auto&& p : all_dirs) {
908 for (
auto&& p : all_files) {
911 for (
auto&& p : all_symlinks) {
914 int row_count =
static_cast<int>(tree.size());
917 LogCvmfs(
kLogCvmfs,
kLogStdout,
"Changeset: %ld dirs, %ld files, %ld symlinks", tree.size(), all_files.size(), all_symlinks.size());
924 std::stack<string> dfs_stack;
925 for (
auto&& p : tree) {
927 if (p.first ==
"" || !tree.count(
get_parent(p.first))) {
928 CUSTOM_ASSERT(dfs_stack.empty(),
"provided DB input forms more than one path trees");
929 dfs_stack.push(p.first);
932 std::set<string> visited;
933 while (!dfs_stack.empty()) {
934 string curr_dir = dfs_stack.top();
936 if (visited.count(curr_dir)) {
938 if (all_symlinks.count(curr_dir)) {
939 add_symlinks(catalog_manager, all_symlinks.at(curr_dir));
941 if (all_files.count(curr_dir)) {
942 add_files(catalog_manager, all_files.at(curr_dir));
955 SHOW_PROGRESS(
"directories", print_every, curr_row, row_count);
957 visited.insert(curr_dir);
959 auto it = tree.find(curr_dir);
960 if (it != tree.end()) {
961 for (
auto&& child : it->second) {
962 dfs_stack.push(child);
966 if (!all_dirs.count(curr_dir))
continue;
975 CUSTOM_ASSERT(!(exists && !S_ISDIR(dir_entry.
mode_)),
"Refusing to replace existing file/symlink at %s with a directory", dir.
name.c_str());
980 dir_entry.
mode_ &= (S_IFDIR | 0777);
985 bool add_nested_catalog=
false;
990 add_nested_catalog=
true;
998 if(dir.
nested) {add_nested_catalog=
true;}
1000 if (add_nested_catalog) {
1006 dir2.mtime_ = dir.
mtime / 1000000000;
1007 dir2.mode_ = (S_IFREG | 0666);
1010 dir2.has_xattrs_ = 0;
1024 CUSTOM_ASSERT(tree.empty(),
"not all directories are processed, malformed input DB?");
1032 for (
auto&& symlink : symlinks) {
1036 bool exists =
false;
1041 dir2.
mtime_ = symlink.mtime / 1000000000;
1042 dir2.
uid_ = symlink.owner;
1043 dir2.
gid_ = symlink.grp;
1046 dir2.
mode_ = S_IFLNK | 0777;
1051 if(symlink.skip_if_file_or_dir) {
1052 if(S_ISDIR(dir.
mode_) || S_ISREG(dir.
mode_)) {
1055 }
else if (S_ISLNK(dir.
mode_)) {
1057 symlink.name.c_str());
1063 CUSTOM_ASSERT(!S_ISDIR(dir.
mode_),
"Not removing directory [%s] to create symlink", symlink.name.c_str());
1065 symlink.name.c_str());
1072 catalog_manager.
AddFile(dir2, xattr, parent);
1079 if (strlen(hash)!=40) {
return 1;}
1080 for(
int i=0; i<40; i++ ) {
1082 if( hash[i]<0x30 || hash[i]>0x66 || ( hash[i]>0x39 && hash[i] <0x61 )) {
1090 if (prefix==
"" || prefix==
"/") {
return true;}
1091 if (
"/"+path == prefix ) {
return true; }
1102 string select_stmt =
"SELECT name, mode, mtime, owner, grp, acl, nested FROM dirs";
1103 if (schema_revision <= 3) {
1104 select_stmt =
"SELECT name, mode, mtime, owner, grp, acl FROM dirs";
1106 int ret = sqlite3_prepare_v2(db, select_stmt.c_str(), -1, &stmt, NULL);
1108 while (sqlite3_step(stmt) == SQLITE_ROW) {
1109 char *name_cstr = (
char *)sqlite3_column_text(stmt, 0);
1110 mode_t mode = sqlite3_column_int(stmt, 1);
1111 time_t mtime = sqlite3_column_int64(stmt, 2);
1112 uid_t owner = sqlite3_column_int(stmt, 3);
1113 gid_t grp = sqlite3_column_int(stmt, 4);
1114 int nested = schema_revision <= 3 ? 1 : sqlite3_column_int(stmt, 6);
1119 Directory dir(name, mtime, mode, owner, grp, nested);
1120 char *acl = (
char *)sqlite3_column_text(stmt, 5);
1122 all_dirs.insert(std::make_pair(name, dir));
1130 string select_stmt =
"SELECT name, mode, mtime, owner, grp, size, hashes, internal, compressed FROM files";
1131 if (schema_revision <= 2) {
1132 select_stmt =
"SELECT name, mode, mtime, owner, grp, size, hashes, internal FROM files";
1134 int ret = sqlite3_prepare_v2(db, select_stmt.c_str(), -1, &stmt, NULL);
1136 while (sqlite3_step(stmt) == SQLITE_ROW) {
1137 char *name = (
char *)sqlite3_column_text(stmt, 0);
1138 mode_t mode = sqlite3_column_int(stmt, 1);
1139 time_t mtime = sqlite3_column_int64(stmt, 2);
1140 uid_t owner = sqlite3_column_int(stmt, 3);
1141 gid_t grp = sqlite3_column_int(stmt, 4);
1142 size_t size = sqlite3_column_int64(stmt, 5);
1143 char *hashes_cstr = (
char *)sqlite3_column_text(stmt, 6);
1144 int internal = sqlite3_column_int(stmt, 7);
1145 int compressed = schema_revision <= 2 ? 0 : sqlite3_column_int(stmt, 8);
1151 if (!all_files.count(parent_dir)) {
1152 all_files[parent_dir] = vector<swissknife::IngestSQL::File>();
1154 all_files[parent_dir].emplace_back(std::move(names), mtime, size, owner, grp, mode,
internal, compressed);
1159 tok = strtok_r(hashes_cstr,
",", &ref);
1160 vector<off_t> offsets;
1161 vector<size_t> sizes;
1162 vector<shash::Any> hashes;
1165 CUSTOM_ASSERT(size>=0,
"file size cannot be negative [%s]", names.c_str());
1169 offsets.push_back(offset);
1174 tok = strtok_r(NULL,
",", &ref);
1175 offset += kChunkSize;
1178 size_t expected_num_chunks = size/kChunkSize;
1179 if (expected_num_chunks * (
size_t)kChunkSize < (
size_t) size || size==0 ) { expected_num_chunks++; }
1180 CUSTOM_ASSERT(offsets.size() == expected_num_chunks,
"offsets size %ld does not match expected number of chunks %ld", offsets.size(), expected_num_chunks);
1181 for (
size_t i = 0; i < offsets.size() - 1; i++) {
1182 sizes.push_back(
size_t(offsets[i + 1] - offsets[i]));
1185 sizes.push_back(
size_t(size - offsets[offsets.size() - 1]));
1186 for (
size_t i = 0; i < offsets.size(); i++) {
1188 all_files[parent_dir].back().chunks.PushBack(chunk);
1196 string select_stmt =
"SELECT name, target, mtime, owner, grp, skip_if_file_or_dir FROM links";
1197 int ret = sqlite3_prepare_v2(db, select_stmt.c_str(), -1, &stmt, NULL);
1199 while (sqlite3_step(stmt) == SQLITE_ROW) {
1200 char *name_cstr = (
char *)sqlite3_column_text(stmt, 0);
1201 char *target_cstr = (
char *)sqlite3_column_text(stmt, 1);
1202 time_t mtime = sqlite3_column_int64(stmt, 2);
1203 uid_t owner = sqlite3_column_int(stmt, 3);
1204 gid_t grp = sqlite3_column_int(stmt, 4);
1205 int skip_if_file_or_dir = sqlite3_column_int(stmt, 5);
1207 string names = additional_prefix +
sanitise_name(name_cstr);
1209 string target= target_cstr;
1212 if (!all_symlinks.count(parent_dir)) {
1213 all_symlinks[parent_dir] = vector<swissknife::IngestSQL::Symlink>();
1215 all_symlinks[parent_dir].emplace_back(std::move(names), std::move(target), mtime, owner, grp, skip_if_file_or_dir);
1223 for (
auto&& file : files) {
1226 bool exists =
false;
1231 dir.
mtime_ = file.mtime / 1000000000;
1232 dir.
mode_ = file.mode | S_IFREG;
1233 dir.
mode_ &= (S_IFREG | 0777);
1234 dir.
uid_ = file.owner;
1235 dir.
gid_ = file.grp;
1236 dir.
size_ = file.size;
1245 CUSTOM_ASSERT(file.internal || (!file.internal && file.compressed<2),
"compression is only allowed for internal data [%s]", file.name.c_str());
1247 switch (file.compressed) {
1260 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());
1278 int ret = sqlite3_prepare_v2(db,
"SELECT name, directory, file, link FROM deletions ORDER BY length(name) DESC", -1, &stmt, NULL);
1280 while (sqlite3_step(stmt) == SQLITE_ROW) {
1283 char *name = (
char *)sqlite3_column_text(stmt, 0);
1284 int64_t isdir = sqlite3_column_int64(stmt, 1);
1285 int64_t isfile = sqlite3_column_int64(stmt, 2);
1286 int64_t islink = sqlite3_column_int64(stmt, 3);
1292 bool exists =
false;
1296 if( (isdir && S_ISDIR(dirent.mode()) )
1297 || (islink && S_ISLNK(dirent.mode()) )
1298 || (isfile && S_ISREG(dirent.mode()) ) ) {
1299 if (S_ISDIR(dirent.mode())) {
1307 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()) );
1314 SHOW_PROGRESS(
"deletions", print_every, curr_row, row_count);
1316 ret = sqlite3_finalize(stmt);
1321 "PRAGMA journal_mode=WAL;",
1323 "CREATE TABLE IF NOT EXISTS dirs ( \
1324 name TEXT PRIMARY KEY, \
1325 mode INTEGER NOT NULL DEFAULT 493,\
1326 mtime INTEGER NOT NULL DEFAULT (unixepoch()),\
1327 owner INTEGER NOT NULL DEFAULT 0, \
1328 grp INTEGER NOT NULL DEFAULT 0, \
1329 acl TEXT NOT NULL DEFAULT '', \
1330 nested INTEGER DEFAULT 1);",
1332 "CREATE TABLE IF NOT EXISTS files ( \
1333 name TEXT PRIMARY KEY, \
1334 mode INTEGER NOT NULL DEFAULT 420, \
1335 mtime INTEGER NOT NULL DEFAULT (unixepoch()),\
1336 owner INTEGER NOT NULL DEFAULT 0,\
1337 grp INTEGER NOT NULL DEFAULT 0,\
1338 size INTEGER NOT NULL DEFAULT 0,\
1339 hashes TEXT NOT NULL DEFAULT '',\
1340 internal INTEGER NOT NULL DEFAULT 0,\
1341 compressed INTEGER NOT NULL DEFAULT 0\
1344 "CREATE TABLE IF NOT EXISTS links (\
1345 name TEXT PRIMARY KEY,\
1346 target TEXT NOT NULL DEFAULT '',\
1347 mtime INTEGER NOT NULL DEFAULT (unixepoch()),\
1348 owner INTEGER NOT NULL DEFAULT 0,\
1349 grp INTEGER NOT NULL DEFAULT 0,\
1350 skip_if_file_or_dir INTEGER NOT NULL DEFAULT 0\
1353 "CREATE TABLE IF NOT EXISTS deletions (\
1354 name TEXT PRIMARY KEY,\
1355 directory INTEGER NOT NULL DEFAULT 0,\
1356 file INTEGER NOT NULL DEFAULT 0,\
1357 link INTEGER NOT NULL DEFAULT 0\
1360 "CREATE TABLE IF NOT EXISTS properties (\
1361 key TEXT PRIMARY KEY,\
1362 value TEXT NOT NULL\
1365 "INSERT INTO properties VALUES ('schema_revision', '4') ON CONFLICT DO NOTHING;",
1372 int ret = sqlite3_open_v2(filename.c_str(), &db_out, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
1376 const char **ptr =
schema;
1377 while (*ptr!=NULL) {
1378 ret = sqlite3_exec(db_out, *ptr, NULL, NULL, NULL);
1382 sqlite3_close(db_out);
1396 for (
unsigned i = 0; i < listing_from_catalog.
size(); ++i) {
1399 entry_path.
Append(
"/", 1);
1400 entry_path.
Append(listing_from_catalog.
AtPtr(i)->name.GetChars(),
1401 listing_from_catalog.
AtPtr(i)->name.GetLength());
1403 if( S_ISDIR( listing_from_catalog.
AtPtr(i)->info.st_mode) ) {
1426 ret = sqlite3_exec(db,
"PRAGMA temp_store=2", NULL, NULL, NULL);
1428 ret = sqlite3_exec(db,
"PRAGMA synchronous=OFF", NULL, NULL, NULL);
1447 ret = sqlite3_open(dbfile, &db);
1448 if (ret!=SQLITE_OK) {
return false; }
1450 const char *req =
"SELECT value FROM properties WHERE key='completed_graft'";
1451 ret = sqlite3_prepare_v2(db, req, -1, &stmt, NULL);
1452 if (ret!=SQLITE_OK) {
1455 if(sqlite3_step(stmt) == SQLITE_ROW) {
1456 int id = sqlite3_column_int(stmt,0);
1470 ret = sqlite3_open(dbfile, &db);
1471 if (ret!=SQLITE_OK) {
return; }
1473 const char *req =
"INSERT INTO properties (key, value) VALUES ('completed_graft',1) ON CONFLICT(key) DO UPDATE SET value=1 WHERE key='completed_graft'";
1475 ret = sqlite3_exec(db, req, 0, 0, &err);
1476 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)
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
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
static uint64_t make_commit_on_gateway(const std::string &old_root_hash, const std::string &new_root_hash, int priority)
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,...)