// ----------------------------------------------------------------------
// File: Xattr.cc
// Author: Andreas-Joachim Peters - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2018 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "common/Logging.hh"
#include "common/LayoutId.hh"
#include "namespace/interface/IView.hh"
#include "namespace/interface/IFileMD.hh"
#include "namespace/utils/Checksum.hh"
#include "mgm/Stat.hh"
#include "mgm/XrdMgmOfs.hh"
#include "mgm/Macros.hh"
#include
//----------------------------------------------------------------------------
// Extended attribute operations
//----------------------------------------------------------------------------
int
XrdMgmOfs::Xattr(const char* path,
const char* ininfo,
XrdOucEnv& env,
XrdOucErrInfo& error,
eos::common::VirtualIdentity& vid,
const XrdSecEntity* client)
{
ACCESSMODE_W;
MAYSTALL;
MAYREDIRECT;
gOFS->MgmStats.Add("Fuse-XAttr", vid.uid, vid.gid, 1);
eos_thread_debug("cmd=xattr subcmd=%s path=%s", env.Get("mgm.subcmd"), path);
int envlen = 0;
const char* sub_cmd = env.Get("mgm.subcmd");
if (!sub_cmd) {
eos_thread_err("xattr missing subcmd information: %s", env.Env(envlen));
XrdOucString response = "xattr: retc=";
response += EINVAL;
error.setErrInfo(response.length() + 1, response.c_str());
return SFS_DATA;
}
int retc = 0; // return code of the function
XrdOucString response; // return value of the function
struct stat buf;
XrdOucString subcmd = sub_cmd;
// Check if path is a file or directory
int rc = lstat(path, &buf, error, client, 0);
if (!rc) {
if (S_ISDIR(buf.st_mode)) {
// Extended attributes for directories
if (subcmd == "ls") {
// lsxattr
eos::IContainerMD::XAttrMap map;
rc = gOFS->attr_ls(path, error, client, 0, map);
if (rc == SFS_OK) {
response = " ";
for (auto& xattr : map) {
response += xattr.first.c_str();
response += "&";
}
response += "\0";
while (response.replace("tmp.", "user.eos.")) {}
while (response.replace("sys.", "user.admin.")) {}
} else {
retc = error.getErrInfo();
}
} else if (subcmd == "get") {
// getxattr
XrdOucString value;
XrdOucString key = env.Get("mgm.xattrname");
key.replace("user.admin.", "sys.");
rc = gOFS->attr_get(path, error, client, "eos.attr.val.encoding=base64",
key.c_str(), value);
if (rc == SFS_OK) {
response = " value=";
response += value;
} else {
retc = error.getErrInfo();
}
} else if (subcmd == "set") {
// setxattr
XrdOucString key = env.Get("mgm.xattrname");
XrdOucString value = env.Get("mgm.xattrvalue");
key.replace("user.admin.", "sys.");
if (gOFS->attr_set(path, error, client, 0, key.c_str(), value.c_str())) {
retc = error.getErrInfo();
}
} else if (subcmd == "rm") {
// rmxattr
XrdOucString key = env.Get("mgm.xattrname");
key.replace("user.admin.", "sys.");
if (gOFS->attr_rem(path, error, client, 0, key.c_str())) {
retc = error.getErrInfo();
}
}
} else if (S_ISREG(buf.st_mode)) {
// Extended attributes for files
if (subcmd == "ls") {
// lsxattr
eos::IContainerMD::XAttrMap map;
rc = gOFS->attr_ls(path, error, client, 0, map);
retc = rc ? error.getErrInfo() : 0;
response = " ";
if (rc == SFS_OK) {
for (auto& xattr : map) {
response += xattr.first.c_str();
response += "&";
}
}
response += "user.eos.cid&";
response += "user.eos.fid&";
response += "user.eos.lid&";
response += "user.eos.XStype&";
response += "user.eos.XS&";
response += "\0";
} else if (subcmd == "get") {
// getxattr
XrdOucString key = env.Get("mgm.xattrname");
XrdOucString value;
std::shared_ptr fmd;
{
eos::common::RWMutexReadLock vlock(gOFS->eosViewRWMutex);
try {
fmd = gOFS->eosView->getFile(path);
} catch (eos::MDException& e) {
eos_thread_debug("msg=\"exception\" ec=%d emsg=\"%s\"",
e.getErrno(), e.getMessage().str().c_str());
XrdOucString eresponse = "getxattr: retc=";
eresponse += ENOENT;
error.setErrInfo(eresponse.length() + 1, eresponse.c_str());
return SFS_DATA;
}
}
if (key.find("eos.cid") != STR_NPOS) {
XrdOucString sizestring;
value = eos::common::StringConversion::GetSizeString(sizestring,
(unsigned long long) fmd->getContainerId());
} else if (key.find("eos.fid") != STR_NPOS) {
char fid[32];
snprintf(fid, 32, "%llu", (unsigned long long) fmd->getId());
value = fid;
} else if (key.find("eos.lid") != STR_NPOS) {
value = eos::common::LayoutId::GetLayoutTypeString(fmd->getLayoutId());
} else if (key.find("eos.XStype") != STR_NPOS) {
value = eos::common::LayoutId::GetChecksumString(fmd->getLayoutId());
} else if (key.find("eos.XS") != STR_NPOS) {
eos::appendChecksumOnStringAsHex(fmd.get(), value, '_');
} else {
key.replace("user.admin.", "sys.");
if (gOFS->attr_get(path, error, client, 0, key.c_str(), value)) {
retc = error.getErrInfo();
value = "";
}
}
if (value.length()) {
response = " value=";
response += value;
}
} else if (subcmd == "set") {
// setxattr
XrdOucString key = env.Get("mgm.xattrname");
if ((key == "user.eos.cid") || (key == "user.eos.fid") ||
(key == "user.eos.lid") || (key == "user.eos.XStype") ||
(key == "user.eos.XS")) {
retc = ENOSYS;
} else {
const char* value = env.Get("mgm.xattrvalue");
key.replace("user.admin.", "sys.");
if (gOFS->attr_set(path, error, client, 0, key.c_str(), value)) {
retc = error.getErrInfo();
}
}
} else if (subcmd == "rm") {
// rmxattr
XrdOucString key = env.Get("mgm.xattrname");
key.replace("user.admin.", "sys.");
if (gOFS->attr_rem(path, error, client, 0, key.c_str())) {
retc = error.getErrInfo();
}
}
} else {
eos_thread_err("cannot identify type for path=%s env=%s",
path, env.Env(envlen));
retc = EINVAL;
}
} else {
eos_thread_err("failed to stat path=%s env=%s", path, env.Env(envlen));
retc = error.getErrInfo();
}
XrdOucString prefix = subcmd;
prefix += "xattr: retc=";
prefix += retc;
response.insert(prefix, 0);
error.setErrInfo(response.length() + 1, response.c_str());
return SFS_DATA;
}