Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions src/GlobusDirectory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,20 @@ void GlobusDirectory::Reset() {
m_directories.clear();
m_stat_buf = nullptr;
m_object = "";
m_route = nullptr;
}

int GlobusDirectory::ListGlobusDir() {
m_log.Log(XrdHTTPServer::Debug, "GlobusDirectory::ListGlobusDir",
"Listing directory:", m_object.c_str());

auto token = m_fs.getTransferToken();
if (!token) {
if (!m_route || !m_route->transfer_token) {
m_log.Emsg("Listing", "Failed to get transfer token");
return -ENOENT;
}
auto token = m_route->transfer_token.get();

HTTPDownload listCommand(m_fs.getLsUrl(), m_object, m_log, token);
HTTPDownload listCommand(m_fs.getLsUrl(*m_route), m_object, m_log, token);
if (!listCommand.SendRequest(0, 0)) {
return HTTPRequest::HandleHTTPError(
listCommand, m_log, "Globus directory listing", m_object.c_str());
Expand Down Expand Up @@ -122,20 +123,16 @@ int GlobusDirectory::Opendir(const char *path, XrdOucEnv &env) {
realPath = realPath + "/";
}

std::string storagePrefix = m_fs.getStoragePrefix();
std::string object;

if (realPath.find(storagePrefix) == 0) {
object = realPath.substr(storagePrefix.length());
} else {
object = realPath;
std::string relative_path;
int rv = m_fs.ResolvePath(realPath, m_route, relative_path);
if (rv != 0) {
return rv;
}

if (!object.empty() && object[0] == '/') {
object = object.substr(1);
if (!relative_path.empty() && relative_path[0] == '/') {
relative_path = relative_path.substr(1);
}

m_object = object;
m_object = relative_path;

return ListGlobusDir();
}
Expand Down
2 changes: 1 addition & 1 deletion src/GlobusDirectory.hh
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ class GlobusDirectory : public XrdOssDF {
ssize_t m_idx{0};
std::vector<GlobusObjectInfo> m_objInfo;
std::vector<GlobusObjectInfo> m_directories;
std::string m_prefix;
std::string m_object;
XrdSysError &m_log;
const GlobusFileSystem &m_fs;
const GlobusFileSystem::GlobusRouteConfig *m_route{nullptr};
struct stat *m_stat_buf{nullptr};
};
201 changes: 133 additions & 68 deletions src/GlobusFileSystem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ class GlobusMkdirRequest final : public HTTPRequest {

GlobusFileSystem::GlobusFileSystem(XrdOss *oss, XrdSysLogger *lp,
const char *configfn, XrdOucEnv *envP)
: XrdOssWrapper(*oss), m_oss(oss), m_log(lp, "globus_"),
m_transfer_token("", nullptr) {
: XrdOssWrapper(*oss), m_oss(oss), m_log(lp, "globus_") {
m_log.Say("------ Initializing the Globus filesystem plugin.");

if (!Config(lp, configfn)) {
Expand Down Expand Up @@ -111,61 +110,123 @@ bool GlobusFileSystem::Config(XrdSysLogger *lp, const char *configfn) {
return false;
}

std::string attribute;
std::string transfer_token_file;
std::string endpoint_path;
bool saw_blocks = false;
bool in_block = false;
GlobusRouteConfig default_route;
std::shared_ptr<GlobusRouteConfig> route(new GlobusRouteConfig(default_route));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
std::shared_ptr<GlobusRouteConfig> route(new GlobusRouteConfig(default_route));
std::shared_ptr<GlobusRouteConfig> route(
new GlobusRouteConfig(default_route));


m_log.setMsgMask(0);

while (globus_conf.GetLine()) {
attribute = globus_conf.GetToken();
std::string attribute = globus_conf.GetToken();
if (!strcmp(attribute.c_str(), "globus.trace")) {
if (!XrdHTTPServer::ConfigLog(globus_conf, m_log)) {
m_log.Emsg("Config", "Failed to configure the log level");
}
continue;
}

if (!strcmp(attribute.c_str(), "globus.begin")) {
if (in_block) {
m_log.Emsg("Config", "Nested globus.begin blocks are not allowed");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
m_log.Emsg("Config", "Nested globus.begin blocks are not allowed");
m_log.Emsg("Config",
"Nested globus.begin blocks are not allowed");

return false;
}
in_block = true;
saw_blocks = true;
route.reset(new GlobusRouteConfig(default_route));
continue;
}
if (!strcmp(attribute.c_str(), "globus.end")) {
if (!in_block) {
m_log.Emsg("Config", "Encountered globus.end without matching begin");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
m_log.Emsg("Config", "Encountered globus.end without matching begin");
m_log.Emsg("Config",
"Encountered globus.end without matching begin");

return false;
}
if (route->storage_prefix.empty() || route->endpoint_path.empty() ||
route->transfer_url.empty()) {
m_log.Emsg("Config", "globus route is missing one or more required settings");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
m_log.Emsg("Config", "globus route is missing one or more required settings");
m_log.Emsg(
"Config",
"globus route is missing one or more required settings");

return false;
}
if (route->storage_prefix[0] != '/') {
route->storage_prefix = "/" + route->storage_prefix;
}
m_routes[route->storage_prefix] = route;
in_block = false;
continue;
}

auto value = globus_conf.GetToken();
if (!value) {
continue;
}

auto &target = in_block ? *route : default_route;

if (!handle_required_config(attribute, "globus.endpoint_path", value,
endpoint_path) ||
target.endpoint_path) ||
!handle_required_config(attribute, "globus.storage_prefix", value,
m_storage_prefix) ||
target.storage_prefix) ||
!handle_required_config(attribute, "globus.transfer_url_base",
value, m_transfer_url) ||
!handle_required_config(attribute, "globus.transfer_token_file",
value, transfer_token_file)) {
value, target.transfer_url)) {
return false;
}
if (!strcmp(attribute.c_str(), "globus.transfer_token_file")) {
target.transfer_token = std::make_shared<TokenFile>(value, &m_log);
}
}

// Build the complete URLs
m_endpoint_path = endpoint_path;
if (!m_transfer_url.empty() && !endpoint_path.empty()) {
// Strip the trailing slash from endpoint_path before embedding it in
// the URL template. extractRelativePath() always returns a path that
// starts with '/', so concatenating a trailing slash here would produce
// a double-slash (e.g. "?path=//top_level_path/custom_path"). Globus interprets
// "?path=//" as the root path and returns a 200 instead of a 404,
// causing parent-directory existence checks to spuriously succeed.
std::string ep = endpoint_path;
if (!ep.empty() && ep.back() == '/') {
ep.pop_back();
}
m_transfer_url += "/%s?path=" + ep;
if (in_block) {
m_log.Emsg("Config", "Encountered unterminated globus.begin block");
return false;
}

if (!transfer_token_file.empty()) {
m_transfer_token = TokenFile(transfer_token_file, &m_log);
if (!saw_blocks) {
auto final_route = std::make_shared<GlobusRouteConfig>(default_route);
if (final_route->storage_prefix.empty() || final_route->endpoint_path.empty() ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
if (final_route->storage_prefix.empty() || final_route->endpoint_path.empty() ||
if (final_route->storage_prefix.empty() ||
final_route->endpoint_path.empty() ||

final_route->transfer_url.empty()) {
m_log.Emsg("Config", "globus route is missing one or more required settings");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
m_log.Emsg("Config", "globus route is missing one or more required settings");
m_log.Emsg("Config",
"globus route is missing one or more required settings");

return false;
}
if (final_route->storage_prefix[0] != '/') {
final_route->storage_prefix = "/" + final_route->storage_prefix;
}
m_routes[final_route->storage_prefix] = final_route;
}

return true;
}

int GlobusFileSystem::ResolvePath(const std::string &path,
const GlobusRouteConfig *&route,
std::string &relative_path) const {
const GlobusRouteConfig *best_route = nullptr;
std::string best_object;
size_t best_len = 0;
for (const auto &entry : m_routes) {
std::string candidate_object;
if (parse_path(entry.second->storage_prefix, path.c_str(),
candidate_object) != 0) {
continue;
}
size_t candidate_len = entry.second->storage_prefix.size();
if (!best_route || candidate_len > best_len) {
best_route = entry.second.get();
best_object = candidate_object;
best_len = candidate_len;
}
}
if (!best_route) {
return -ENOENT;
}
route = best_route;
relative_path = best_object;
if (relative_path.empty()) {
relative_path = "/";
} else if (relative_path[0] != '/') {
relative_path = "/" + relative_path;
}
return 0;
}

XrdOssDF *GlobusFileSystem::newDir(const char *user) {
return new GlobusDirectory(m_log, *this);
}
Expand All @@ -177,19 +238,23 @@ XrdOssDF *GlobusFileSystem::newFile(const char *user) {

int GlobusFileSystem::Stat(const char *path, struct stat *buff, int opts,
XrdOucEnv *env) {
// Extract the part of path that comes after the storage prefix
std::string relative_path = extractRelativePath(path);
const GlobusRouteConfig *route = nullptr;
std::string relative_path;
int rv = ResolvePath(path, route, relative_path);
if (rv != 0) {
return rv;
}

m_log.Log(LogMask::Debug, "GlobusFileSystem::Stat", "Stat'ing path",
relative_path.c_str());

auto token = getTransferToken();
auto token = route->transfer_token.get();
if (!token) {
m_log.Emsg("Stat", "Failed to get transfer token");
return -ENOENT;
}

HTTPDownload statCommand(getStatUrl(relative_path), "", m_log, token);
HTTPDownload statCommand(getStatUrl(*route, relative_path), "", m_log, token);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
HTTPDownload statCommand(getStatUrl(*route, relative_path), "", m_log, token);
HTTPDownload statCommand(getStatUrl(*route, relative_path), "", m_log,
token);

if (!statCommand.SendRequest(0, 0)) {
return HTTPRequest::HandleHTTPError(statCommand, m_log, "GET", "");
}
Expand Down Expand Up @@ -254,13 +319,18 @@ int GlobusFileSystem::Mkdir(const char *path, mode_t mode, int mkpath,
return -ENOENT;
}

auto token = getTransferToken();
const GlobusRouteConfig *route = nullptr;
std::string relative_path;
int rv = ResolvePath(path, route, relative_path);
if (rv != 0) {
return rv;
}

auto token = route->transfer_token.get();
if (!token) {
m_log.Emsg("Mkdir", "Failed to get transfer token");
return -ENOENT;
}

std::string relative_path = extractRelativePath(path);
if (relative_path.empty()) {
relative_path = "/";
}
Expand All @@ -276,9 +346,9 @@ int GlobusFileSystem::Mkdir(const char *path, mode_t mode, int mkpath,
// anywhere in the path. In this case, it returns HTTP code 404

if (!mkpath) {
GlobusMkdirRequest mkdirCommand(getMkdirUrl(), m_log, token);
GlobusMkdirRequest mkdirCommand(getMkdirUrl(*route), m_log, token);
nlohmann::json body = {{"DATA_TYPE", "mkdir"},
{"path", buildEndpointPath(relative_path)}};
{"path", buildEndpointPath(*route, relative_path)}};
Comment on lines 350 to +351

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
nlohmann::json body = {{"DATA_TYPE", "mkdir"},
{"path", buildEndpointPath(relative_path)}};
{"path", buildEndpointPath(*route, relative_path)}};
nlohmann::json body = {
{"DATA_TYPE", "mkdir"},
{"path", buildEndpointPath(*route, relative_path)}};

if (!mkdirCommand.SendRequest(body.dump())) {
unsigned long httpCode = mkdirCommand.getResponseCode();
// Globus mkdir semantics: 202 = success, 502 = exists, 403 = perms,
Expand Down Expand Up @@ -326,7 +396,7 @@ int GlobusFileSystem::Mkdir(const char *path, mode_t mode, int mkpath,
int first_missing_idx = 0;
for (int idx = static_cast<int>(prefixes.size()) - 1; idx >= 0; --idx) {
struct stat sb;
int stat_rv = Stat((m_storage_prefix + prefixes[idx]).c_str(), &sb, 0, env);
int stat_rv = Stat((route->storage_prefix + prefixes[idx]).c_str(), &sb, 0, env);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
int stat_rv = Stat((route->storage_prefix + prefixes[idx]).c_str(), &sb, 0, env);
int stat_rv =
Stat((route->storage_prefix + prefixes[idx]).c_str(), &sb, 0, env);

if (stat_rv == 0) {
if (!S_ISDIR(sb.st_mode)) {
return -ENOTDIR;
Expand All @@ -343,9 +413,9 @@ int GlobusFileSystem::Mkdir(const char *path, mode_t mode, int mkpath,
// EEXIST if another writer creates a directory between our Stat and Mkdir.
for (int idx = first_missing_idx;
idx < static_cast<int>(prefixes.size()); ++idx) {
Comment on lines 414 to 415

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
for (int idx = first_missing_idx;
idx < static_cast<int>(prefixes.size()); ++idx) {
for (int idx = first_missing_idx; idx < static_cast<int>(prefixes.size());
++idx) {

GlobusMkdirRequest mkdirCommand(getMkdirUrl(), m_log, token);
GlobusMkdirRequest mkdirCommand(getMkdirUrl(*route), m_log, token);
nlohmann::json body = {{"DATA_TYPE", "mkdir"},
{"path", buildEndpointPath(prefixes[idx])}};
{"path", buildEndpointPath(*route, prefixes[idx])}};
Comment on lines 417 to +418

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
nlohmann::json body = {{"DATA_TYPE", "mkdir"},
{"path", buildEndpointPath(prefixes[idx])}};
{"path", buildEndpointPath(*route, prefixes[idx])}};
nlohmann::json body = {
{"DATA_TYPE", "mkdir"},
{"path", buildEndpointPath(*route, prefixes[idx])}};

int rv = 0;
if (!mkdirCommand.SendRequest(body.dump())) {
unsigned long httpCode = mkdirCommand.getResponseCode();
Expand All @@ -371,22 +441,25 @@ int GlobusFileSystem::Mkdir(const char *path, mode_t mode, int mkpath,
}

const std::string
GlobusFileSystem::getLsUrl(const std::string &relative_path) const {
return getOperationUrl("ls", relative_path);
GlobusFileSystem::getLsUrl(const GlobusRouteConfig &route,
const std::string &relative_path) const {
return getOperationUrl(route, "ls", relative_path);
}

const std::string
GlobusFileSystem::getStatUrl(const std::string &relative_path) const {
return getOperationUrl("stat", relative_path);
GlobusFileSystem::getStatUrl(const GlobusRouteConfig &route,
const std::string &relative_path) const {
return getOperationUrl(route, "stat", relative_path);
}

const std::string GlobusFileSystem::getMkdirUrl() const {
return getOperationUrl("mkdir");
const std::string GlobusFileSystem::getMkdirUrl(const GlobusRouteConfig &route) const {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
const std::string GlobusFileSystem::getMkdirUrl(const GlobusRouteConfig &route) const {
const std::string
GlobusFileSystem::getMkdirUrl(const GlobusRouteConfig &route) const {

return getOperationUrl(route, "mkdir");
}

std::string
GlobusFileSystem::buildEndpointPath(const std::string &relative_path) const {
std::string endpoint = m_endpoint_path.empty() ? "/" : m_endpoint_path;
GlobusFileSystem::buildEndpointPath(const GlobusRouteConfig &route,
const std::string &relative_path) const {
std::string endpoint = route.endpoint_path.empty() ? "/" : route.endpoint_path;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[lint] reported by reviewdog 🐶

Suggested change
std::string endpoint = route.endpoint_path.empty() ? "/" : route.endpoint_path;
std::string endpoint =
route.endpoint_path.empty() ? "/" : route.endpoint_path;

if (endpoint[0] != '/') {
endpoint = "/" + endpoint;
}
Expand All @@ -412,14 +485,23 @@ GlobusFileSystem::buildEndpointPath(const std::string &relative_path) const {
}

const std::string
GlobusFileSystem::getOperationUrl(const std::string &operation,
GlobusFileSystem::getOperationUrl(const GlobusRouteConfig &route,
const std::string &operation,
const std::string &relative_path) const {
if (m_transfer_url.empty()) {
if (route.transfer_url.empty()) {
return "";
}

size_t format_pos = m_transfer_url.find("%s");
std::string result = m_transfer_url;
std::string transfer_url = route.transfer_url;
if (!route.endpoint_path.empty()) {
std::string ep = route.endpoint_path;
if (!ep.empty() && ep.back() == '/') {
ep.pop_back();
}
transfer_url += "/%s?path=" + ep;
}
size_t format_pos = transfer_url.find("%s");
std::string result = transfer_url;
result.replace(format_pos, 2, operation);

// Append the relative path to the URL
Expand All @@ -429,23 +511,6 @@ GlobusFileSystem::getOperationUrl(const std::string &operation,

return result;
}

std::string
GlobusFileSystem::extractRelativePath(const std::string &path) const {
std::string relative_path = "/";

if (!m_storage_prefix.empty() && path.find(m_storage_prefix) == 0) {
relative_path = path.substr(m_storage_prefix.length());
if (relative_path.empty()) {
relative_path = "/";
} else if (relative_path[0] != '/') {
relative_path = "/" + relative_path;
}
}

return relative_path;
}

time_t GlobusFileSystem::parseTimestamp(const std::string &last_modified) {
if (!last_modified.empty()) {
struct tm tm_time = {};
Expand Down
Loading
Loading