beegfs/meta/source/storage/IncompleteInode.cpp
2025-08-10 01:34:16 +02:00

118 lines
3.2 KiB
C++

#include "IncompleteInode.h"
#include <common/app/log/Logger.h>
#include <program/Program.h>
#include <sys/xattr.h>
#include <sys/types.h>
#include <unistd.h>
IncompleteInode::~IncompleteInode()
{
if (fd >= 0 && close(fd) < 0)
LOG(GENERAL, ERR, "Failed to close file", fd, sysErr);
}
FhgfsOpsErr IncompleteInode::setXattr(const char* name, const void* value, size_t size)
{
int setRes = ::fsetxattr(fd, name, value, size, 0);
if (setRes != 0)
return FhgfsOpsErrTk::fromSysErr(errno);
xattrsSet.insert(name);
return FhgfsOpsErr_SUCCESS;
}
FhgfsOpsErr IncompleteInode::setContent(const char* attrName, const void* value, size_t size)
{
if (Program::getApp()->getConfig()->getStoreUseExtendedAttribs())
return setXattr(attrName, value, size);
if (strcmp(attrName, META_XATTR_NAME) != 0)
{
LOG(GENERAL, ERR, "Setting attribute data as file contents is not supported.", attrName);
return FhgfsOpsErr_INVAL;
}
if (hasContent)
{
int truncRes = ::ftruncate(fd, size);
if (truncRes)
return FhgfsOpsErrTk::fromSysErr(errno);
}
ssize_t writeRes = ::write(fd, value, size);
if (writeRes < 0 || size_t(writeRes) < size)
return FhgfsOpsErrTk::fromSysErr(errno);
hasContent = true;
return FhgfsOpsErr_SUCCESS;
}
FhgfsOpsErr IncompleteInode::clearUnsetXAttrs()
{
std::set<std::string> xattrsOnInode;
char xattrNameBuf[XATTR_LIST_MAX];
const ssize_t listRes = ::flistxattr(fd, xattrNameBuf, sizeof(xattrNameBuf));
if (listRes < 0)
{
LOG(GENERAL, ERR, "could not list xattrs", fileName(), sysErr);
return FhgfsOpsErr_INTERNAL;
}
for (ssize_t offset = 0; offset < listRes; )
{
std::string currentName = xattrNameBuf + offset;
offset += currentName.size() + 1;
xattrsOnInode.insert(std::move(currentName));
}
for (auto it = xattrsOnInode.begin(); it != xattrsOnInode.end(); it++)
{
if (xattrsSet.count(*it))
continue;
// do not sync the system namespaces.
// * security. cannot be synced at all, since userspace can't write to it
// * trusted. is unused by us and thus not interesting
// * system. contains only acls, which we don't use to represent metadata
if (it->compare(0, 5, "user.") != 0)
continue;
int removeRes = ::fremovexattr(fd, it->c_str());
if (removeRes != 0)
{
LOG(GENERAL, ERR, "could not remove superfluous xattr",
fileName(), ("name", *it), sysErr);
return FhgfsOpsErr_INTERNAL;
}
}
return FhgfsOpsErr_SUCCESS;
}
std::string IncompleteInode::fileName() const
{
static const char* FD_FORMAT = "/proc/self/fd/%i";
// reserve enough space for the entire format string, the trailing \0, and the fd value
// in octal. in decimal, that will be more than enough.
char buffer[strlen(FD_FORMAT) + 3 * sizeof(fd) + 1];
::sprintf(buffer, FD_FORMAT, fd);
std::string result;
result.resize(PATH_MAX + 1);
ssize_t readRes = ::readlink(buffer, &result[0], PATH_MAX);
if (readRes < 0)
{
LOG(GENERAL, ERR, "Failed to resolve file for fd", fd, sysErr);
return "<resolve error>";
}
result.resize(readRes);
return result;
}