//------------------------------------------------------------------------------
// File: DavixIo.cc
// Author: Andreas-Joachim Peters - CERN
//------------------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2011 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 .*
************************************************************************/
#ifdef HAVE_DAVIX
#include "fst/XrdFstOfsFile.hh"
#include "fst/io/davix/DavixIo.hh"
#include "common/Path.hh"
EOSFSTNAMESPACE_BEGIN
#define DAVIX_QUOTA_FILE ".dav.quota"
Davix::Context DavixIo::gContext;
namespace
{
std::string getAttrUrl(std::string path)
{
size_t rfind = path.rfind("/");
if (rfind != std::string::npos) {
path.insert(rfind + 1, ".");
}
path += ".xattr";
return path;
}
}
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
DavixIo::DavixIo(std::string path, std::string s3credentials)
: FileIo(path, "DavixIo"),
mDav(&DavixIo::gContext)
{
//............................................................................
// In this case the logical file is the same as the local physical file
//............................................................................
seq_offset = 0;
mCreated = false;
mShortRead = false;
std::string lFilePath = mFilePath;
size_t qpos;
//............................................................................
// Opaque info can be part of the 'path'
//............................................................................
if (((qpos = mFilePath.find("?")) != std::string::npos)) {
mOpaque = mFilePath.substr(qpos + 1);
lFilePath.erase(qpos);
} else {
mOpaque = "";
}
//............................................................................
// Set url for xattr requests
//............................................................................
mAttrUrl = getAttrUrl(lFilePath.c_str());
//............................................................................
// Prepare Keys for S3 access
//............................................................................
if ((path.substr(0, 3) == "s3:") || (path.substr(0, 4) == "s3s:")) {
std::string id, key, credSource = "fsconfig";
mIsS3 = true;
// Passed-in credentials take priority over opaque provided
if (s3credentials.empty() && mOpaque.length()) {
XrdOucEnv* opaqueEnv = new XrdOucEnv(mOpaque.c_str());
if (opaqueEnv->Get("s3credentials")) {
s3credentials = opaqueEnv->Get("s3credentials");
}
}
if (s3credentials.length()) {
size_t pos = s3credentials.find(':');
id = s3credentials.substr(0, pos);
key = s3credentials.substr(pos + 1);
} else {
// Attempt to retrieve S3 credentials from the global environment
id = getenv("EOS_FST_S3_ACCESS_KEY") ?
getenv("EOS_FST_S3_ACCESS_KEY") : "";
key = getenv("EOS_FST_S3_SECRET_KEY") ?
getenv("EOS_FST_S3_SECRET_KEY") : "";
credSource = "globalEnv";
}
if (id.empty() || key.empty()) {
eos_warning("msg=\"s3 configuration missing\" "
"s3-access-key=\"%s\" s3-secret-key=\"%s\"",
id.c_str(), key.c_str());
} else {
mParams.setAwsAuthorizationKeys(key.c_str(), id.c_str());
eos_debug("s3-access-key=\"%s\" s3-secret-key=\"%s\" (source=%s)",
id.c_str(), key.c_str(), credSource.c_str());
}
} else {
mIsS3 = false;
}
mParams.setOperationRetry(0);
// Use path-based S3 URLs
mParams.setAwsAlternate(true);
setAttrSync(false);// by default sync attributes lazily
mAttrLoaded = false;
mAttrDirty = false;
}
//------------------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------------------
DavixIo::~DavixIo()
{
// deal with asynchronous dirty attributes
if (!mAttrSync && mAttrDirty) {
std::string lMap = mFileMap.Trim();
if (!DavixIo::Upload(mAttrUrl, lMap)) {
mAttrDirty = false;
} else {
eos_static_err("msg=\"unable to upload to remote file map\" url=\"%s\"",
mAttrUrl.c_str());
}
}
}
//------------------------------------------------------------------------------
// Convert DAVIX errors
//------------------------------------------------------------------------------
int
DavixIo::SetErrno(int errcode, Davix::DavixError** err, bool free_error)
{
eos_debug("");
if (errcode == 0) {
errno = 0;
if (free_error && err && *err) {
Davix::DavixError::clearError(err);
}
return 0;
}
if (!err || !*err) {
errno = EIO;
return -1;
}
switch ((*err)->getStatus()) {
case Davix::StatusCode::OK:
errno = EIO;
break;
case Davix::StatusCode::AuthenticationError:
case Davix::StatusCode::LoginPasswordError:
case Davix::StatusCode::CredentialNotFound:
case Davix::StatusCode::PermissionRefused:
errno = EACCES;
break;
case Davix::StatusCode::IsADirectory:
errno = EISDIR;
break;
case Davix::StatusCode::FileExist:
errno = EEXIST;
break;
case Davix::StatusCode::InvalidArgument:
errno = EINVAL;
break;
case Davix::StatusCode::TimeoutRedirectionError:
errno = ETIMEDOUT;
break;
case Davix::StatusCode::OperationNonSupported:
errno = ENOTSUP;
break;
case Davix::StatusCode::FileNotFound:
errno = ENOENT;
break;
default:
errno = EIO;
}
if (free_error) {
Davix::DavixError::clearError(err);
}
return -1;
}
//------------------------------------------------------------------------------
// Returns the s3 credentials in-use by this davix client
//------------------------------------------------------------------------------
std::string
DavixIo::RetrieveS3Credentials()
{
std::string credentials = "";
if (mIsS3) {
pair
credPair = mParams.getAwsAutorizationKeys();
credentials = credPair.second + ":" + credPair.first;
}
return credentials;
}
//------------------------------------------------------------------------------
// Open file
//------------------------------------------------------------------------------
int
DavixIo::fileOpen(XrdSfsFileOpenMode flags, mode_t mode,
const std::string& opaque, uint16_t timeout)
{
eos_debug("");
eos_info("flags=%x", flags);
Davix::DavixError* err = 0;
mParent = mFilePath.c_str();
mParent.erase(mFilePath.rfind("/"));
int pflags = 0;
if (flags & SFS_O_CREAT) {
pflags |= (O_CREAT | O_RDWR);
}
if ((flags & SFS_O_RDWR) || (flags & SFS_O_WRONLY)) {
pflags |= (O_RDWR);
}
if (!mIsS3) {
DavixIo lParent(mParent.c_str());
// create at least the direct parent path
if ((pflags & O_CREAT) && lParent.fileExists()) {
eos_info("msg=\"creating parent directory\" parent=\"%s\"", mParent.c_str());
if (Mkdir(mParent.c_str(), mode)) {
eos_err("url=\"%s\" msg=\"failed to create parent directory\"",
mParent.c_str());
return -1;
}
}
}
eos_info("open=%s flags=%x", mFilePath.c_str(), pflags);
mFd = mDav.open(&mParams, mFilePath, pflags, &err);
if (pflags & O_CREAT) {
mCreated = true;
}
if (mFd != NULL) {
return 0;
}
int rc = SetErrno(-1, &err, false);
if (errno != ENOENT) {
eos_err("url=\"%s\" msg=\"%s\" errno=%d ", mFilePath.c_str(),
err->getErrMsg().c_str(), errno);
}
if (err) {
delete err;
}
return rc;
}
//------------------------------------------------------------------------------
// Open file asynchronously
//------------------------------------------------------------------------------
std::future
DavixIo::fileOpenAsync(XrdSfsFileOpenMode flags, mode_t mode,
const std::string& opaque, uint16_t timeout)
{
std::promise open_promise;
std::future open_future = open_promise.get_future();
if (fileOpen(flags, mode, opaque, timeout) != SFS_OK) {
open_promise.set_value(XrdCl::XRootDStatus(XrdCl::stError,
XrdCl::errUnknown,
EIO, "failed open"));
} else {
open_promise.set_value(XrdCl::XRootDStatus(XrdCl::stOK, ""));
}
return open_future;
}
//------------------------------------------------------------------------------
// Read from file - sync
//------------------------------------------------------------------------------
int64_t
DavixIo::fileRead(XrdSfsFileOffset offset,
char* buffer,
XrdSfsXferSize length,
uint16_t timeout)
{
eos_debug("offset = %lld, length = %lld",
static_cast(offset),
static_cast(length));
Davix::DavixError* err = 0;
if (mShortRead) {
if (offset >= short_read_offset) {
// return an EOF read;
return 0;
}
}
int retval = mDav.pread(mFd, buffer, length, offset, &err);
if (-1 == retval) {
eos_err("url=\"%s\" msg=\"%s\"", mFilePath.c_str(), err->getErrMsg().c_str());
return SetErrno(-1, &err);
}
if (retval != length) {
// mark the offset when a short read happened ...
short_read_offset = offset + retval;
mShortRead = true;
}
return retval;
}
//------------------------------------------------------------------------------
// Read from file async - falls back on synchronous mode
//------------------------------------------------------------------------------
int64_t
DavixIo::fileReadPrefetch(XrdSfsFileOffset offset, char* buffer,
XrdSfsXferSize length, uint16_t timeout)
{
return fileRead(offset, buffer, length, timeout);
}
//------------------------------------------------------------------------------
// Read from file asynchronously - falls back to synchronous mode
//------------------------------------------------------------------------------
int64_t
DavixIo::fileReadAsync(XrdSfsFileOffset offset, char* buffer,
XrdSfsXferSize length, uint16_t timeout)
{
return fileRead(offset, buffer, length, timeout);
}
//------------------------------------------------------------------------------
// Write to file - sync
//------------------------------------------------------------------------------
int64_t
DavixIo::fileWrite(XrdSfsFileOffset offset, const char* buffer,
XrdSfsXferSize length, uint16_t timeout)
{
eos_debug("offset = %lld, length = %lld",
static_cast(offset),
static_cast(length));
errno = 0;
if (offset != seq_offset) {
eos_err("msg=\"non sequential writes are not supported\"");
errno = ENOTSUP;
return -1;
}
Davix::DavixError* err = 0;
int retval = mDav.write(mFd, buffer, length, &err);
if (-1 == retval) {
eos_err("url=\"%s\" msg=\"%s\"", mFilePath.c_str(), err->getErrMsg().c_str());
return SetErrno(-1, &err);
}
seq_offset += length;
return retval;
}
//------------------------------------------------------------------------------
// Write to file async - falls back on synchronous mode
//------------------------------------------------------------------------------
int64_t
DavixIo::fileWriteAsync(XrdSfsFileOffset offset,
const char* buffer,
XrdSfsXferSize length,
uint16_t timeout)
{
return fileWrite(offset, buffer, length, timeout);
}
//----------------------------------------------------------------------------
// Write to file - async
//--------------------------------------------------------------------------
std::future
DavixIo::fileWriteAsync(const char* buffer, XrdSfsFileOffset offset,
XrdSfsXferSize length)
{
std::promise wr_promise;
std::future wr_future = wr_promise.get_future();
int64_t nwrite = fileWrite(offset, buffer, length);
if (nwrite != length) {
wr_promise.set_value(XrdCl::XRootDStatus(XrdCl::stError, XrdCl::errUnknown,
EIO, "failed write"));
} else {
wr_promise.set_value(XrdCl::XRootDStatus(XrdCl::stOK, ""));
}
return wr_future;
}
//--------------------------------------------------------------------------
//! Close file
//--------------------------------------------------------------------------
int
DavixIo::fileClose(uint16_t timeout)
{
mCreated = false;
eos_debug("");
Davix::DavixError* err = 0;
int retval = mDav.close(mFd, &err);
if (-1 == retval) {
eos_err("url=\"%s\" msg=\"%s\"", mFilePath.c_str(), err->getErrMsg().c_str());
return SetErrno(-1, &err);
}
return retval;
}
//------------------------------------------------------------------------------
// Truncate file
//------------------------------------------------------------------------------
int
DavixIo::fileTruncate(XrdSfsFileOffset offset, uint16_t timeout)
{
eos_debug("offset = %lld",
static_cast(offset));
eos_err("msg=\"truncate is not supported by WebDAV\"");
errno = -ENOTSUP;
return -1;
}
//------------------------------------------------------------------------------
// Truncate asynchronous
//------------------------------------------------------------------------------
std::future
DavixIo::fileTruncateAsync(XrdSfsFileOffset offset, uint16_t timeout)
{
std::promise tr_promise;
std::future tr_future = tr_promise.get_future();
int retc = fileTruncate(offset, timeout);
if (retc) {
tr_promise.set_value(XrdCl::XRootDStatus(XrdCl::stError, XrdCl::errUnknown,
EIO, "failed truncate"));
} else {
tr_promise.set_value(XrdCl::XRootDStatus(XrdCl::stOK, ""));
}
return tr_future;
}
//------------------------------------------------------------------------------
// Get stats about the file
//------------------------------------------------------------------------------
int
DavixIo::fileStat(struct stat* buf, uint16_t timeout)
{
eos_debug("url=%s", mFilePath.c_str());
Davix::DavixError* err = 0;
if (mCreated) {
memset(buf, 0, sizeof(struct stat));
buf->st_size = seq_offset;
eos_debug("st-size=%llu", buf->st_size);
return 0;
}
int result = mDav.stat(&mParams, mFilePath, buf, &err);
if (-1 == result) {
eos_info("url=\"%s\" msg=\"%s\"", mFilePath.c_str(), err->getErrMsg().c_str());
return SetErrno(-1, &err);
}
return result;
}
//------------------------------------------------------------------------------
// Remove file
//------------------------------------------------------------------------------
int
DavixIo::fileRemove(uint16_t timeout)
{
eos_debug("");
Davix::DavixError* err1 = 0;
Davix::DavixError* err2 = 0;
// remove xattr file (errors are ignored)
int rc = mDav.unlink(&mParams, mAttrUrl, &err1);
SetErrno(rc, &err1);
// remove file and return error code
rc = mDav.unlink(&mParams, mFilePath, &err2);
return SetErrno(rc, &err2);
}
//------------------------------------------------------------------------------
// Check for existence by path
//------------------------------------------------------------------------------
int
DavixIo::fileExists()
{
eos_debug("");
Davix::DavixError* err = 0;
std::string url = mFilePath;
struct stat st;
int result = mDav.stat(&mParams, url, &st, &err);
if (-1 == result) {
eos_info("url=\"%s\" msg=\"%s\"", url.c_str(), err->getErrMsg().c_str());
return SetErrno(-1, &err);
}
return result;
}
//------------------------------------------------------------------------------
// Delete by path
//------------------------------------------------------------------------------
int
DavixIo::fileDelete(const char* path)
{
eos_debug("");
eos_info("path=\"%s\"", path);
Davix::DavixError* err = 0;
std::string davpath = path;
int rc = mDav.unlink(&mParams, davpath.c_str(), &err);
return SetErrno(rc, &err);
}
//--------------------------------------------------------------------------
//! Create a directory
//--------------------------------------------------------------------------
int
DavixIo::Mkdir(const char* path, mode_t mode)
{
eos_debug("");
eos_info("path=\"%s\"", path);
Davix::DavixError* err = 0;
XrdOucString davpath = path;
int rc = mDav.mkdir(&mParams, davpath.c_str(), mode, &err);
return SetErrno(rc, &err);
}
//--------------------------------------------------------------------------
//! Delete a directory
//--------------------------------------------------------------------------
int
DavixIo::Rmdir(const char* path)
{
eos_debug("");
Davix::DavixError* err = 0;
return SetErrno(mDav.rmdir(&mParams, path, &err), &err);
}
//------------------------------------------------------------------------------
// Sync file - meaningless in HTTP PUT
//------------------------------------------------------------------------------
int
DavixIo::fileSync(uint16_t timeout)
{
eos_debug("");
return 0;
}
//------------------------------------------------------------------------------
// Get pointer to async meta handler object
//------------------------------------------------------------------------------
void*
DavixIo::fileGetAsyncHandler()
{
eos_debug("");
return 0;
}
//--------------------------------------------------------------------------
//! Download a remote file into a string object
//--------------------------------------------------------------------------
int
DavixIo::Download(std::string url, std::string& download)
{
eos_static_debug("");
errno = 0;
static int s_blocksize = 65536;
DavixIo io(url.c_str(), DavixIo::RetrieveS3Credentials());
off_t offset = 0;
std::string opaque;
if (!io.fileOpen(0, 0, opaque, 10)) {
ssize_t rbytes = 0;
download.resize(s_blocksize);
do {
rbytes = io.fileRead(offset, (char*) download.c_str(), s_blocksize, 30);
if (rbytes == s_blocksize) {
download.resize(download.size() + 65536);
}
if (rbytes > 0) {
offset += rbytes;
}
} while (rbytes == s_blocksize);
io.fileClose();
download.resize(offset);
return 0;
}
if (errno == ENOENT) {
return 0;
}
return -1;
}
//--------------------------------------------------------------------------
//! Upload a string object into a remote file
//--------------------------------------------------------------------------
int
DavixIo::Upload(std::string url, std::string& upload)
{
eos_static_debug("");
errno = 0;
DavixIo io(url.c_str(), DavixIo::RetrieveS3Credentials());
std::string opaque;
int rc = 0;
io.fileRemove();
if (!io.fileOpen(SFS_O_WRONLY | SFS_O_CREAT, S_IRWXU | S_IRGRP | SFS_O_MKPTH,
opaque,
10)) {
eos_static_info("opened %s", url.c_str());
if ((io.fileWrite(0, upload.c_str(), upload.length(),
30)) != (ssize_t) upload.length()) {
eos_static_err("failed to write %d", upload.length());
rc = -1;
} else {
eos_static_info("uploaded %d\n", upload.length());
}
io.fileClose();
} else {
eos_static_err("failed to open %s", url.c_str());
rc = -1;
}
return rc;
}
//------------------------------------------------------------------------------
// Attribute Interface
//------------------------------------------------------------------------------
//----------------------------------------------------------------
//! Set a binary attribute (name has to start with 'user.' !!!)
// ------------------------------------------------------------------------
int
DavixIo::attrSet(const char* name, const char* value, size_t len)
{
eos_debug("");
std::string lBlob;
errno = 0;
if (!mAttrSync && mAttrLoaded) {
std::string key = name;
std::string val;
val.assign(value, len);
if (val == "#__DELETE_ATTR_#") {
mFileMap.Remove(key);
} else {
// just modify
mFileMap.Set(key, val);
}
mAttrDirty = true;
return 0;
}
// download
if (!DavixIo::Download(mAttrUrl, lBlob) || errno == ENOENT) {
mAttrLoaded = true;
if (mFileMap.Load(lBlob)) {
std::string key = name;
std::string val;
val.assign(value, len);
if (val == "#__DELETE_ATTR_#") {
mFileMap.Remove(key);
} else {
mFileMap.Set(key, val);
}
mAttrDirty = true;
if (mAttrSync) {
std::string lMap = mFileMap.Trim();
if (!DavixIo::Upload(mAttrUrl, lMap)) {
mAttrDirty = false;
return 0;
} else {
eos_static_err("msg=\"unable to upload to remote file map\" url=\"%s\"",
mAttrUrl.c_str());
}
}
return 0;
} else {
eos_static_err("msg=\"unable to parse remote file map\" url=\"%s\"",
mAttrUrl.c_str());
errno = EINVAL;
}
} else {
eos_static_err("msg=\"unable to download remote file map\" url=\"%s\"",
mAttrUrl.c_str());
}
return -1;
}
// ------------------------------------------------------------------------
//! Set a string attribute (name has to start with 'user.' !!!)
// ------------------------------------------------------------------------
int
DavixIo::attrSet(std::string key, std::string value)
{
return attrSet(key.c_str(), value.c_str(), value.length());
}
// ------------------------------------------------------------------------
//! Get a binary attribute by name (name has to start with 'user.' !!!)
// ------------------------------------------------------------------------
int
DavixIo::attrGet(const char* name, char* value, size_t& size)
{
eos_debug("");
errno = 0;
if (!mAttrSync && mAttrLoaded) {
std::string val = mFileMap.Get(name);
size_t len = val.length() + 1;
if (len > size) {
len = size;
}
memcpy(value, val.c_str(), len);
eos_static_info("key=%s value=%s", name, value);
return 0;
}
std::string lBlob;
if (!DavixIo::Download(mAttrUrl, lBlob) || errno == ENOENT) {
mAttrLoaded = true;
if (mFileMap.Load(lBlob)) {
std::string val = mFileMap.Get(name);
size_t len = val.length() + 1;
if (len > size) {
len = size;
}
memcpy(value, val.c_str(), len);
eos_static_info("key=%s value=%s", name, value);
return 0;
}
} else {
eos_static_err("msg=\"unable to download remote file map\" url=\"%s\"",
mAttrUrl.c_str());
}
return -1;
}
// ------------------------------------------------------------------------
//! Get a string attribute by name (name has to start with 'user.' !!!)
// ------------------------------------------------------------------------
int
DavixIo::attrGet(std::string name, std::string& value)
{
eos_debug("");
errno = 0;
if (!mAttrSync && mAttrLoaded) {
value = mFileMap.Get(name);
return 0;
}
std::string lBlob;
if (!DavixIo::Download(mAttrUrl, lBlob) || errno == ENOENT) {
mAttrLoaded = true;
if (mFileMap.Load(lBlob)) {
value = mFileMap.Get(name);
return 0;
}
} else {
eos_static_err("msg=\"unable to download remote file map\" url=\"%s\"",
mAttrUrl.c_str());
}
return -1;
}
// ------------------------------------------------------------------------
//! Delete a binary attribute by name
// ------------------------------------------------------------------------
int
DavixIo::attrDelete(const char* name)
{
eos_debug("");
errno = 0;
return attrSet(name, "#__DELETE_ATTR_#");
}
// ------------------------------------------------------------------------
//! List all attributes for the associated path
// ------------------------------------------------------------------------
int
DavixIo::attrList(std::vector& list)
{
eos_debug("");
if (!mAttrSync && mAttrLoaded) {
std::map lMap = mFileMap.GetMap();
for (auto it = lMap.begin(); it != lMap.end(); ++it) {
list.push_back(it->first);
}
return 0;
}
std::string lBlob;
if (!DavixIo::Download(mAttrUrl, lBlob) || errno == ENOENT) {
mAttrLoaded = true;
if (mFileMap.Load(lBlob)) {
std::map lMap = mFileMap.GetMap();
for (auto it = lMap.begin(); it != lMap.end(); ++it) {
list.push_back(it->first);
}
return 0;
}
} else {
eos_static_err("msg=\"unable to download remote file map\" url=\"%s\"",
mAttrUrl.c_str());
}
return -1;
}
//------------------------------------------------------------------------------
// Statfs function calling quota propfind command
//------------------------------------------------------------------------------
int
DavixIo::Statfs(struct statfs* sfs)
{
eos_debug("msg=\"davixio class statfs called\"");
std::string url = mFilePath;;
url += "/";
url += DAVIX_QUOTA_FILE;
std::string opaque;
if (mFilePath.substr(0, 2) == "s3") {
unsigned long long s3_size = 4000ll * 1000ll * 1000ll * 1000ll;
s3_size *= 1000ll;
if (getenv("EOS_FST_S3_STORAGE_SIZE")) {
s3_size = strtoull(getenv("EOS_FST_S3_STORAGE_SIZE"), 0, 10);
}
#ifdef __APPLE__
sfs->f_iosize = 4096;
sfs->f_bsize = sfs->f_iosize;
sfs->f_blocks = (fsblkcnt_t)(s3_size / sfs->f_iosize);
sfs->f_bavail = (fsblkcnt_t)(s3_size / sfs->f_iosize);
#else
sfs->f_frsize = 4096;
sfs->f_bsize = sfs->f_frsize;
sfs->f_blocks = (fsblkcnt_t)(s3_size / sfs->f_frsize);
sfs->f_bavail = (fsblkcnt_t)(s3_size / sfs->f_frsize);
#endif
sfs->f_bfree = sfs->f_bavail;
sfs->f_files = 1000000000ll;
sfs->f_ffree = 1000000000ll;
eos_debug("msg=\"emulating s3 quota\"");
return 0;
}
DavixIo io(url);;
int fd = io.fileOpen((XrdSfsFileOpenMode) 0, (mode_t) 0, opaque, (uint16_t) 0);
if (fd < 0) {
eos_err("msg=\"failed to get quota file\" path=\"%s\"", url.c_str());
return -ENODATA;
}
char buffer[65536];
memset(buffer, 0, sizeof(buffer));
if (io.fileRead(0, buffer, 65536) > 0) {
eos_debug("quota-buffer=\"%s\"", buffer);
} else {
eos_err("msg=\"failed to get the quota file\"");
}
std::map map;
std::vector keyvector;
unsigned long long total_bytes = 0;
unsigned long long free_bytes = 0;
unsigned long long total_files = 0;
unsigned long long free_files = 0;
if (eos::common::StringConversion::GetKeyValueMap(buffer,
map,
"=",
"\n")
&&
map.count("dav.total.bytes") &&
map.count("dav.free.bytes") &&
map.count("dav.total.files") &&
map.count("dav.free.files")) {
total_bytes = strtoull(map["dav.total.bytes"].c_str(), 0, 10);
free_bytes = strtoull(map["dav.free.bytes"].c_str(), 0, 10);
total_files = strtoull(map["dav.total.files"].c_str(), 0, 10);
free_files = strtoull(map["dav.free.files"].c_str(), 0, 10);
} else {
eos_err("msg=\"failed to parse key-val quota map\"");
}
#ifdef __APPLE__
sfs->f_iosize = 4096;
sfs->f_bsize = sfs->f_iosize;
sfs->f_blocks = (fsblkcnt_t)(total_bytes / sfs->f_iosize);
sfs->f_bavail = (fsblkcnt_t)(total_bytes / sfs->f_iosize);
#else
sfs->f_frsize = 4096;
sfs->f_bsize = sfs->f_frsize;
sfs->f_blocks = (fsblkcnt_t)(total_bytes / sfs->f_frsize);
sfs->f_bavail = (fsblkcnt_t)(free_bytes / sfs->f_frsize);
#endif
sfs->f_bfree = sfs->f_bavail;
sfs->f_files = total_files;
sfs->f_ffree = free_files;
return 0;
}
EOSFSTNAMESPACE_END
#endif // HAVE_DAVIX