From bdcb0b18939b8d950df89f57a962f7e92b661bdc Mon Sep 17 00:00:00 2001 From: Andreas-Joachim Peters Date: Thu, 27 Jun 2024 10:21:02 +0200 Subject: [PATCH] XrdS3: add helper class to have extneded attributes in a file - for the time being we don't use it --- src/XrdS3/XrdS3Utils.cc | 144 +++++++++++++++++++++++++++++++++++++++- src/XrdS3/XrdS3Utils.hh | 31 ++++++++- 2 files changed, 173 insertions(+), 2 deletions(-) diff --git a/src/XrdS3/XrdS3Utils.cc b/src/XrdS3/XrdS3Utils.cc index dcd1c964226..77cfbf8c83e 100644 --- a/src/XrdS3/XrdS3Utils.cc +++ b/src/XrdS3/XrdS3Utils.cc @@ -27,11 +27,13 @@ //------------------------------------------------------------------------------ #include #include - +#include +#include #include #include #include #include +#include #include //------------------------------------------------------------------------------ #include "XrdPosix/XrdPosixExtern.hh" @@ -39,6 +41,8 @@ namespace S3 { +std::atomic S3Utils::sFileAttributes=false; // this indicates if we use native xattr (false) or xattr in hidden files + //------------------------------------------------------------------------------ //! Encode a string according to RFC 3986 //! @@ -477,4 +481,142 @@ S3Utils::ScanDir(const std::filesystem::path& fullpath, const std::filesystem::p return sentries.size(); } +S3Utils::FileAttributes::FileAttributes(const std::string& changelogFile) : changelogFile(changelogFile) { + loadChangelog(); +} + +std::string +S3Utils::FileAttributes::getattr(const std::string& name) { + auto it = attributes.find(name); + if (it != attributes.end()) { + return it->second; + } + return ""; +} + +void +S3Utils::FileAttributes::setattr(const std::string& name, const std::string& value, bool persist) { + attributes[name] = value; + if (persist) { + saveChangelog("set", name, value); + } +} + +std::vector +S3Utils::FileAttributes::listattr() { + std::vector keys; + for (const auto& pair : attributes) { + keys.push_back(pair.first); + } + return keys; +} + +void +S3Utils::FileAttributes::rmattr(const std::string& name) { + attributes.erase(name); + saveChangelog("remove", name); +} + +void +S3Utils::FileAttributes::trimChangelog() { + int tempFileDescriptor = open("temp_changelog.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (tempFileDescriptor == -1) { + std::cerr << "Failed to open temporary changelog file." << std::endl; + return; + } + for (const auto& pair : attributes) { + saveToTempFile(tempFileDescriptor, "set", pair.first, pair.second); + } + close(tempFileDescriptor); + if (unlink(changelogFile.c_str()) == -1) { + std::cerr << "Failed to unlink original changelog file." << std::endl; + return; + } + if (rename("temp_changelog.txt", changelogFile.c_str()) == -1) { + std::cerr << "Failed to rename temporary changelog file." << std::endl; + return; + } +} + +void +S3Utils::FileAttributes::loadChangelog() { + int changelogFileDescriptor = open(changelogFile.c_str(), O_RDONLY); + if (changelogFileDescriptor == -1) { + std::cerr << "Failed to open changelog file." << std::endl; + return; + } + + char buffer[4096]; + ssize_t bytesRead; + std::string jsonBuffer; + while ((bytesRead = read(changelogFileDescriptor, buffer, sizeof(buffer) - 1)) > 0) { + buffer[bytesRead] = '\0'; // Null-terminate the buffer + jsonBuffer += buffer; + } + + close(changelogFileDescriptor); + + Json::CharReaderBuilder readerBuilder; + Json::CharReader* reader = readerBuilder.newCharReader(); + Json::Value root; + std::string errs; + if (!reader->parse(jsonBuffer.c_str(), jsonBuffer.c_str() + jsonBuffer.length(), &root, &errs)) { + std::cerr << "Failed to parse changelog file: " << errs << std::endl; + delete reader; + return; + } + + delete reader; + + // Process parsed JSON data + for (const auto& entry : root) { + std::string action = entry["action"].asString(); + std::string name = entry["name"].asString(); + if (action == "set") { + std::string value = entry["value"].asString(); + attributes[name] = value; + } else if (action == "remove") { + attributes.erase(name); + } + } +} + +void +S3Utils::FileAttributes::saveChangelog(const std::string& action, const std::string& name, const std::string& value) { + Json::Value entry; + entry["action"] = action; + entry["name"] = name; + if (!value.empty()) { + entry["value"] = value; + } + std::string entryStr = entry.toStyledString() + "\n"; + + int changelogFileDescriptor = open(changelogFile.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0666); + if (changelogFileDescriptor == -1) { + std::cerr << "Failed to open changelog file." << std::endl; + return; + } + + if (write(changelogFileDescriptor, entryStr.c_str(), entryStr.size()) == -1) { + std::cerr << "Failed to write to changelog file." << std::endl; + } + + close(changelogFileDescriptor); +} + +void +S3Utils::FileAttributes::saveToTempFile(int tempFileDescriptor, const std::string& action, const std::string& name, const std::string& value) { + Json::Value entry; + entry["action"] = action; + entry["name"] = name; + if (!value.empty()) { + entry["value"] = value; + } + std::string entryStr = entry.toStyledString() + "\n"; + + if (write(tempFileDescriptor, entryStr.c_str(), entryStr.size()) == -1) { + std::cerr << "Failed to write to temporary changelog file." << std::endl; + } +} + } // namespace S3 diff --git a/src/XrdS3/XrdS3Utils.hh b/src/XrdS3/XrdS3Utils.hh index 08f274c5e9e..2abb2a83b62 100644 --- a/src/XrdS3/XrdS3Utils.hh +++ b/src/XrdS3/XrdS3Utils.hh @@ -33,10 +33,13 @@ #include #include #include +#include +#include #include #include #include #include +#include //------------------------------------------------------------------------------ namespace S3 { @@ -164,7 +167,33 @@ class S3Utils { static int ScanDir(const std::filesystem::path &path, const std::filesystem::path &basepath, std::vector& entries); - private: + + static std::atomic sFileAttributes; + + class FileAttributes { + public: + FileAttributes(const std::string& changelogFile); + + std::string getattr(const std::string& name); + void setattr(const std::string& name, const std::string& value, bool persist=false); + void persist(); + std::vector listattr(); + void rmattr(const std::string& name); + void trimChangelog(); + + private: + std::map attributes; + std::deque changes; + std::string changelogFile; + std::mutex mutex; + + void loadChangelog(); + void saveChangelog(const std::string& action, const std::string& name, const std::string& value = ""); + void saveChangeslog(const std::string& action); + void saveToTempFile(int tempFileDescriptor, const std::string& action, const std::string& name, const std::string& value = ""); + }; + +private: std::bitset<256> mEncoder; std::bitset<256> mObjectEncoder; unsigned char mDecoder[256];