//------------------------------------------------------------------------------ // @file: QuotaCmd.cc // @author: Andreas-Joachim Peters - CERN //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2022 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 "QuotaCmd.hh" #include "mgm/proc/ProcInterface.hh" #include "mgm/XrdMgmOfs.hh" #include "mgm/Policy.hh" #include "common/Path.hh" #include "common/Constants.hh" #include "namespace/Prefetcher.hh" #include "namespace/interface/IQuota.hh" #include "mgm/proc/admin/FileRegisterCmd.hh" EOSMGMNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Method implementing the specific behavior of the command executed by the // asynchronous thread //------------------------------------------------------------------------------ eos::console::ReplyProto FileRegisterCmd::ProcessRequest() noexcept { eos::console::ReplyProto reply; eos::console::FileRegisterProto reg = mReqProto.record(); eos::common::Path cPath(reg.path()); std::shared_ptr dir; std::shared_ptr fmd; eos::IContainerMD::XAttrMap attrmap; { eos::Prefetcher::prefetchContainerMDAndWait(gOFS->eosView, cPath.GetParentPath()); eos::common::RWMutexReadLock lock(gOFS->eosViewRWMutex); // Check for the parent directory try { dir = gOFS->eosView->getContainer(cPath.GetParentPath()); attrmap = dir->getAttributes(); std::string name = cPath.GetName(); auto exists = dir->findItem(name); if (exists.value().file || exists.value().container) { if (reg.update() && exists.value().file) { fmd = dir->findFile(name.c_str()); } else { reply.set_retc(EEXIST); reply.set_std_err("file already exists"); return reply; } } else { if (reg.update()) { reply.set_retc(ENOENT); reply.set_std_err("no suche file"); return reply; } } uid_t uid = reg.owner().uid(); uid_t gid = reg.owner().gid(); if (reg.owner().username().length()) { int errc = 0; uid = eos::common::Mapping::UserNameToUid(reg.owner().username().c_str(), errc); } if (reg.owner().groupname().length()) { int errc = 0; gid = eos::common::Mapping::GroupNameToGid(reg.owner().groupname().c_str(), errc); } if (!reg.update()) { // create with given uid/gid fmd = gOFS->eosView->createFile(cPath.GetFullPath().c_str(), uid, gid); } else { if (uid) { fmd->setCUid(uid); } if (gid) { fmd->setCGid(gid); } } if (reg.mode()) { //store mode fmd->setFlags(reg.mode()); } if (reg.checksum().length()) { //store checksum size_t out_sz = 0; auto xs_binary = eos::common::StringConversion::Hex2BinDataChar (reg.checksum(), out_sz, SHA256_DIGEST_LENGTH); eos::Buffer xs_buff; xs_buff.putData(xs_binary.get(), SHA256_DIGEST_LENGTH); fmd->setChecksum(xs_buff); } if (reg.ctime().sec()) { // add ctime struct timespec tvp; tvp.tv_sec = reg.ctime().sec(); tvp.tv_nsec = reg.ctime().nsec(); fmd->setCTime(tvp); } if (reg.mtime().sec()) { // add mtime struct timespec tvp; tvp.tv_sec = reg.mtime().sec(); tvp.tv_nsec = reg.mtime().nsec(); fmd->setMTime(tvp); } if (reg.atime().sec()) { // add atime struct timespec tvp; struct timespec tvnow; tvp.tv_sec = reg.atime().sec(); tvp.tv_nsec = reg.atime().nsec(); if (reg.atimeifnewer()) { // only update if the input atime is actually newer than the existing one fmd->getATime(tvnow); if ( (tvp.tv_sec > tvnow.tv_sec) || ( (tvp.tv_sec == tvnow.tv_sec) && (tvp.tv_nsec > tvnow.tv_nsec) ) ) { fmd->setATime(tvp); } else { reply.set_std_out("warning: atime is not newer than existing one"); } } else { fmd->setATime(tvp); } } if (reg.btime().sec()) { // add btime char btime[256]; snprintf(btime, sizeof(btime), "%lu.%lu", reg.btime().sec(), reg.btime().nsec()); fmd->setAttribute("sys.eos.btime", btime); } else { // add btime char btime[256]; snprintf(btime, sizeof(btime), "%lu.%lu", time(NULL), 0l); fmd->setAttribute("sys.eos.btime", btime); } // add locations for (const auto& fsid : reg.locations()) { if ((fsid > 0) && (fsid <= eos::common::TAPE_FS_ID)) { fmd->addLocation(fsid); } } // add xattr for (const auto& elem : reg.attr()) { fmd->setAttribute(elem.first, elem.second); } if (reg.layoutid()) { fmd->setLayoutId(reg.layoutid()); } else { // automatically get a layout id for this registration unsigned long layoutId; XrdOucString space; XrdOucEnv env; unsigned long forcedfsid = 0; long forcedgroup = 0; std::string bandwidth; bool schedule = false; std::string iopriority; std::string iotype; Policy::GetLayoutAndSpace(cPath.GetFullPath().c_str(), attrmap, vid, layoutId, space, env, forcedfsid, forcedgroup, bandwidth, schedule, iopriority, iotype, true, false); fmd->setLayoutId(layoutId); } try { eos::IQuotaNode* ns_quota = gOFS->eosView->getQuotaNode(dir.get()); if (ns_quota) { if (!reg.update()) { fmd->setSize(reg.size()); ns_quota->addFile(fmd.get()); } else { ns_quota->removeFile(fmd.get()); fmd->setSize(reg.size()); } } else { fmd->setSize(reg.size()); } } catch (const eos::MDException& eq) { // no quota node } gOFS->eosView->updateFileStore(fmd.get()); dir->setMTimeNow(); gOFS->eosView->updateContainerStore(dir.get()); lock.Release(); dir->notifyMTimeChange(gOFS->eosDirectoryService); return reply; } catch (eos::MDException& e) { eos_debug("msg=\"exception\" ec=%d emsg=\"%s\"\n", e.getErrno(), e.getMessage().str().c_str()); dir.reset(); reply.set_retc(e.getErrno()); reply.set_std_err(e.getMessage().str().c_str()); return reply; } } reply.set_retc(EINVAL); reply.set_std_err("error: not supported"); return reply; } EOSMGMNAMESPACE_END