mirror of
https://github.com/trapexit/mergerfs.git
synced 2025-05-31 21:23:34 +08:00
clearly separate usage of statvfs from stat for file existance
Used statvfs to also check for existance vs lstat. On dead symlinks this resulted in ENOENT making certain functions fail. closes #239
This commit is contained in:
82
src/fs.cpp
82
src/fs.cpp
@ -52,8 +52,16 @@ namespace fs
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
exists(const string &path,
|
exists(const string &path)
|
||||||
struct statvfs &st)
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
return exists(path,st);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
statvfs(const string &path,
|
||||||
|
struct statvfs &st)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
@ -63,22 +71,14 @@ namespace fs
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
exists(const string &path)
|
info(const string &path,
|
||||||
{
|
bool &readonly,
|
||||||
struct stat st;
|
size_t &spaceavail)
|
||||||
|
|
||||||
return exists(path,st);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
exists(const string &path,
|
|
||||||
bool &readonly,
|
|
||||||
size_t &spaceavail)
|
|
||||||
{
|
{
|
||||||
bool rv;
|
bool rv;
|
||||||
struct statvfs st;
|
struct statvfs st;
|
||||||
|
|
||||||
rv = exists(path,st);
|
rv = fs::statvfs(path,st);
|
||||||
if(rv)
|
if(rv)
|
||||||
{
|
{
|
||||||
readonly = StatVFS::readonly(st);
|
readonly = StatVFS::readonly(st);
|
||||||
@ -89,33 +89,28 @@ namespace fs
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
exists_on_rw_fs(const string &path,
|
readonly(const string &path)
|
||||||
struct statvfs &st)
|
|
||||||
{
|
{
|
||||||
int rv;
|
bool rv;
|
||||||
|
struct statvfs st;
|
||||||
|
|
||||||
rv = ::statvfs(path.c_str(),&st);
|
rv = fs::statvfs(path,st);
|
||||||
|
|
||||||
return (STATVFS_SUCCEEDED(rv) && !StatVFS::readonly(st));
|
return (rv && StatVFS::readonly(st));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
exists_on_rw_fs(const string &path)
|
spaceavail(const string &path,
|
||||||
|
size_t &spaceavail)
|
||||||
{
|
{
|
||||||
|
bool rv;
|
||||||
struct statvfs st;
|
struct statvfs st;
|
||||||
|
|
||||||
return exists_on_rw_fs(path,st);
|
rv = fs::statvfs(path,st);
|
||||||
}
|
if(rv)
|
||||||
|
spaceavail = StatVFS::spaceavail(st);
|
||||||
|
|
||||||
bool
|
return rv;
|
||||||
exists_on_rw_fs_with_at_least(const string &path,
|
|
||||||
const size_t minfreespace)
|
|
||||||
{
|
|
||||||
struct statvfs st;
|
|
||||||
|
|
||||||
return (exists_on_rw_fs(path,st)
|
|
||||||
&&
|
|
||||||
StatVFS::spaceavail(st) >= minfreespace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -224,20 +219,18 @@ namespace fs
|
|||||||
string &path)
|
string &path)
|
||||||
{
|
{
|
||||||
fsblkcnt_t mfs;
|
fsblkcnt_t mfs;
|
||||||
fsblkcnt_t spaceavail;
|
|
||||||
const string *mfsbasepath;
|
const string *mfsbasepath;
|
||||||
|
|
||||||
mfs = 0;
|
mfs = 0;
|
||||||
mfsbasepath = NULL;
|
mfsbasepath = NULL;
|
||||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
struct statvfs st;
|
size_t spaceavail;
|
||||||
const string &basepath = basepaths[i];
|
const string &basepath = basepaths[i];
|
||||||
|
|
||||||
if(!fs::exists(basepath,st))
|
if(!fs::spaceavail(basepath,spaceavail))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
spaceavail = StatVFS::spaceavail(st);
|
|
||||||
if(spaceavail < minfreespace)
|
if(spaceavail < minfreespace)
|
||||||
continue;
|
continue;
|
||||||
if(spaceavail <= mfs)
|
if(spaceavail <= mfs)
|
||||||
@ -254,23 +247,4 @@ namespace fs
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
available(const string &path,
|
|
||||||
const bool needswritablefs,
|
|
||||||
struct statvfs &st)
|
|
||||||
{
|
|
||||||
return (needswritablefs ?
|
|
||||||
fs::exists_on_rw_fs(path,st) :
|
|
||||||
fs::exists(path,st));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
available(const string &path,
|
|
||||||
const bool needswritablefs)
|
|
||||||
{
|
|
||||||
return (needswritablefs ?
|
|
||||||
fs::exists_on_rw_fs(path) :
|
|
||||||
fs::exists(path));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
27
src/fs.hpp
27
src/fs.hpp
@ -28,19 +28,19 @@ namespace fs
|
|||||||
|
|
||||||
bool exists(const string &path,
|
bool exists(const string &path,
|
||||||
struct stat &st);
|
struct stat &st);
|
||||||
bool exists(const string &path,
|
|
||||||
struct statvfs &st);
|
|
||||||
bool exists(const string &path);
|
bool exists(const string &path);
|
||||||
bool exists(const string &path,
|
|
||||||
bool &readonly,
|
|
||||||
size_t &spaceavail);
|
|
||||||
|
|
||||||
bool exists_on_rw_fs(const string &path,
|
bool statvfs(const string &path,
|
||||||
struct statvfs &st);
|
struct statvfs &st);
|
||||||
bool exists_on_rw_fs(const string &path);
|
|
||||||
|
|
||||||
bool exists_on_rw_fs_with_at_least(const string &path,
|
bool info(const string &path,
|
||||||
const size_t minfreespace);
|
bool &readonly,
|
||||||
|
size_t &spaceavail);
|
||||||
|
|
||||||
|
bool readonly(const string &path);
|
||||||
|
|
||||||
|
bool spaceavail(const string &path,
|
||||||
|
size_t &spaceavail);
|
||||||
|
|
||||||
void findallfiles(const vector<string> &srcmounts,
|
void findallfiles(const vector<string> &srcmounts,
|
||||||
const char *fusepath,
|
const char *fusepath,
|
||||||
@ -61,13 +61,6 @@ namespace fs
|
|||||||
int mfs(const vector<string> &srcs,
|
int mfs(const vector<string> &srcs,
|
||||||
const size_t minfreespace,
|
const size_t minfreespace,
|
||||||
string &path);
|
string &path);
|
||||||
|
|
||||||
bool available(const string &path,
|
|
||||||
const bool needswritablefs);
|
|
||||||
|
|
||||||
bool available(const string &path,
|
|
||||||
const bool needswritablefs,
|
|
||||||
struct statvfs &st);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __FS_HPP__
|
#endif // __FS_HPP__
|
||||||
|
@ -29,15 +29,21 @@ using std::size_t;
|
|||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_all_create(const vector<string> &srcmounts,
|
_all_create(const vector<string> &basepaths,
|
||||||
const size_t minfreespace,
|
const size_t minfreespace,
|
||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
for(size_t i = 0, ei = srcmounts.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
const string *basepath = &srcmounts[i];
|
bool readonly;
|
||||||
|
size_t spaceavail;
|
||||||
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
if(!fs::exists_on_rw_fs_with_at_least(*basepath,minfreespace))
|
if(!fs::info(*basepath,readonly,spaceavail))
|
||||||
|
continue;
|
||||||
|
if(readonly)
|
||||||
|
continue;
|
||||||
|
if(spaceavail < minfreespace)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
paths.push_back(basepath);
|
paths.push_back(basepath);
|
||||||
@ -51,15 +57,15 @@ _all_create(const vector<string> &srcmounts,
|
|||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_all(const vector<string> &srcmounts,
|
_all_other(const vector<string> &basepaths,
|
||||||
const char *fusepath,
|
const char *fusepath,
|
||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
string fullpath;
|
string fullpath;
|
||||||
|
|
||||||
for(size_t i = 0, ei = srcmounts.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
const string *basepath = &srcmounts[i];
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
fs::path::make(basepath,fusepath,fullpath);
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
|
|
||||||
@ -79,14 +85,14 @@ namespace mergerfs
|
|||||||
{
|
{
|
||||||
int
|
int
|
||||||
Policy::Func::all(const Category::Enum::Type type,
|
Policy::Func::all(const Category::Enum::Type type,
|
||||||
const vector<string> &srcmounts,
|
const vector<string> &basepaths,
|
||||||
const char *fusepath,
|
const char *fusepath,
|
||||||
const size_t minfreespace,
|
const size_t minfreespace,
|
||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
if(type == Category::Enum::create)
|
if(type == Category::Enum::create)
|
||||||
return _all_create(srcmounts,minfreespace,paths);
|
return _all_create(basepaths,minfreespace,paths);
|
||||||
|
|
||||||
return _all(srcmounts,fusepath,paths);
|
return _all_other(basepaths,fusepath,paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,75 +15,116 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/statvfs.h>
|
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include "fs_path.hpp"
|
#include "fs_path.hpp"
|
||||||
#include "policy.hpp"
|
#include "policy.hpp"
|
||||||
#include "statvfs_util.hpp"
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
using mergerfs::Policy;
|
|
||||||
using mergerfs::Category;
|
using mergerfs::Category;
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
_calc_lfs(const struct statvfs &st,
|
|
||||||
const string *basepath,
|
|
||||||
const size_t minfreespace,
|
|
||||||
fsblkcnt_t &lfs,
|
|
||||||
const string *&lfsbasepath)
|
|
||||||
{
|
|
||||||
fsblkcnt_t spaceavail;
|
|
||||||
|
|
||||||
spaceavail = StatVFS::spaceavail(st);
|
|
||||||
if((spaceavail > minfreespace) && (spaceavail < lfs))
|
|
||||||
{
|
|
||||||
lfs = spaceavail;
|
|
||||||
lfsbasepath = basepath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_eplfs(const vector<string> &basepaths,
|
_eplfs_create(const vector<string> &basepaths,
|
||||||
const char *fusepath,
|
const char *fusepath,
|
||||||
const size_t minfreespace,
|
const size_t minfreespace,
|
||||||
const bool needswritablefs,
|
vector<const string*> &paths)
|
||||||
vector<const string*> &paths)
|
|
||||||
{
|
{
|
||||||
string fullpath;
|
string fullpath;
|
||||||
struct statvfs st;
|
size_t eplfs;
|
||||||
fsblkcnt_t eplfs;
|
|
||||||
const string *eplfsbasepath;
|
const string *eplfsbasepath;
|
||||||
|
|
||||||
eplfs = -1;
|
eplfs = std::numeric_limits<size_t>::max();
|
||||||
eplfsbasepath = NULL;
|
eplfsbasepath = NULL;
|
||||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
|
bool readonly;
|
||||||
|
size_t spaceavail;
|
||||||
const string *basepath = &basepaths[i];
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
fs::path::make(basepath,fusepath,fullpath);
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
|
|
||||||
if(!fs::available(fullpath,needswritablefs,st))
|
if(!fs::exists(fullpath))
|
||||||
|
continue;
|
||||||
|
if(!fs::info(*basepath,readonly,spaceavail))
|
||||||
|
continue;
|
||||||
|
if(readonly)
|
||||||
|
continue;
|
||||||
|
if(spaceavail < minfreespace)
|
||||||
|
continue;
|
||||||
|
if(spaceavail > eplfs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_calc_lfs(st,basepath,minfreespace,eplfs,eplfsbasepath);
|
eplfs = spaceavail;
|
||||||
|
eplfsbasepath = basepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(eplfsbasepath == NULL)
|
if(eplfsbasepath == NULL)
|
||||||
return (errno=ENOENT,POLICY_FAIL);
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
paths.push_back(eplfsbasepath);
|
paths.push_back(eplfsbasepath);
|
||||||
|
|
||||||
return POLICY_SUCCESS;
|
return POLICY_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_eplfs_other(const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
string fullpath;
|
||||||
|
size_t eplfs;
|
||||||
|
const string *eplfsbasepath;
|
||||||
|
|
||||||
|
eplfs = std::numeric_limits<size_t>::max();
|
||||||
|
eplfsbasepath = NULL;
|
||||||
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
|
{
|
||||||
|
size_t spaceavail;
|
||||||
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
|
|
||||||
|
if(!fs::exists(fullpath))
|
||||||
|
continue;
|
||||||
|
if(!fs::spaceavail(*basepath,spaceavail))
|
||||||
|
continue;
|
||||||
|
if(spaceavail > eplfs)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
eplfs = spaceavail;
|
||||||
|
eplfsbasepath = basepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(eplfsbasepath == NULL)
|
||||||
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
|
paths.push_back(eplfsbasepath);
|
||||||
|
|
||||||
|
return POLICY_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_eplfs(const Category::Enum::Type type,
|
||||||
|
const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
const size_t minfreespace,
|
||||||
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
if(type == Category::Enum::create)
|
||||||
|
return _eplfs_create(basepaths,fusepath,minfreespace,paths);
|
||||||
|
|
||||||
|
return _eplfs_other(basepaths,fusepath,paths);
|
||||||
|
}
|
||||||
|
|
||||||
namespace mergerfs
|
namespace mergerfs
|
||||||
{
|
{
|
||||||
int
|
int
|
||||||
@ -94,12 +135,8 @@ namespace mergerfs
|
|||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
const bool needswritablefs =
|
|
||||||
(type == Category::Enum::create);
|
|
||||||
const size_t minfs =
|
|
||||||
((type == Category::Enum::create) ? minfreespace : 0);
|
|
||||||
|
|
||||||
rv = _eplfs(basepaths,fusepath,minfs,needswritablefs,paths);
|
rv = _eplfs(type,basepaths,fusepath,minfreespace,paths);
|
||||||
if(POLICY_FAILED(rv))
|
if(POLICY_FAILED(rv))
|
||||||
rv = Policy::Func::lfs(type,basepaths,fusepath,minfreespace,paths);
|
rv = Policy::Func::lfs(type,basepaths,fusepath,minfreespace,paths);
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/statvfs.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -23,67 +22,104 @@
|
|||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include "fs_path.hpp"
|
#include "fs_path.hpp"
|
||||||
#include "policy.hpp"
|
#include "policy.hpp"
|
||||||
#include "statvfs_util.hpp"
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
using mergerfs::Policy;
|
|
||||||
using mergerfs::Category;
|
using mergerfs::Category;
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
_calc_mfs(const struct statvfs &st,
|
|
||||||
const string *basepath,
|
|
||||||
const size_t minfreespace,
|
|
||||||
fsblkcnt_t &mfs,
|
|
||||||
const string *&mfsbasepath)
|
|
||||||
{
|
|
||||||
fsblkcnt_t spaceavail;
|
|
||||||
|
|
||||||
spaceavail = StatVFS::spaceavail(st);
|
|
||||||
if((spaceavail > minfreespace) && (spaceavail > mfs))
|
|
||||||
{
|
|
||||||
mfs = spaceavail;
|
|
||||||
mfsbasepath = basepath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_epmfs(const vector<string> &basepaths,
|
_epmfs_create(const vector<string> &basepaths,
|
||||||
const char *fusepath,
|
const char *fusepath,
|
||||||
const size_t minfreespace,
|
vector<const string*> &paths)
|
||||||
const bool needswritablefs,
|
|
||||||
vector<const string*> &paths)
|
|
||||||
{
|
{
|
||||||
string fullpath;
|
string fullpath;
|
||||||
struct statvfs st;
|
size_t epmfs;
|
||||||
fsblkcnt_t epmfs;
|
|
||||||
const string *epmfsbasepath;
|
const string *epmfsbasepath;
|
||||||
|
|
||||||
epmfs = 0;
|
epmfs = 0;
|
||||||
epmfsbasepath = NULL;
|
epmfsbasepath = NULL;
|
||||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
|
bool readonly;
|
||||||
|
size_t spaceavail;
|
||||||
const string *basepath = &basepaths[i];
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
fs::path::make(basepath,fusepath,fullpath);
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
|
|
||||||
if(!fs::available(fullpath,needswritablefs,st))
|
if(!fs::exists(fullpath))
|
||||||
|
continue;
|
||||||
|
if(!fs::info(*basepath,readonly,spaceavail))
|
||||||
|
continue;
|
||||||
|
if(readonly)
|
||||||
|
continue;
|
||||||
|
if(spaceavail < epmfs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_calc_mfs(st,basepath,minfreespace,epmfs,epmfsbasepath);
|
epmfs = spaceavail;
|
||||||
|
epmfsbasepath = basepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(epmfsbasepath == NULL)
|
if(epmfsbasepath == NULL)
|
||||||
return (errno=ENOENT,POLICY_FAIL);
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
paths.push_back(epmfsbasepath);
|
paths.push_back(epmfsbasepath);
|
||||||
|
|
||||||
return POLICY_SUCCESS;
|
return POLICY_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_epmfs_other(const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
string fullpath;
|
||||||
|
size_t epmfs;
|
||||||
|
const string *epmfsbasepath;
|
||||||
|
|
||||||
|
epmfs = 0;
|
||||||
|
epmfsbasepath = NULL;
|
||||||
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
|
{
|
||||||
|
size_t spaceavail;
|
||||||
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
|
|
||||||
|
if(!fs::exists(fullpath))
|
||||||
|
continue;
|
||||||
|
if(!fs::spaceavail(*basepath,spaceavail))
|
||||||
|
continue;
|
||||||
|
if(spaceavail < epmfs)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
epmfs = spaceavail;
|
||||||
|
epmfsbasepath = basepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(epmfsbasepath == NULL)
|
||||||
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
|
paths.push_back(epmfsbasepath);
|
||||||
|
|
||||||
|
return POLICY_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_epmfs(const Category::Enum::Type type,
|
||||||
|
const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
if(type == Category::Enum::create)
|
||||||
|
return _epmfs_create(basepaths,fusepath,paths);
|
||||||
|
|
||||||
|
return _epmfs_other(basepaths,fusepath,paths);
|
||||||
|
}
|
||||||
|
|
||||||
namespace mergerfs
|
namespace mergerfs
|
||||||
{
|
{
|
||||||
int
|
int
|
||||||
@ -94,12 +130,8 @@ namespace mergerfs
|
|||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
const size_t minfs =
|
|
||||||
((type == Category::Enum::create) ? minfreespace : 0);
|
|
||||||
const bool needswritablefs =
|
|
||||||
(type == Category::Enum::create);
|
|
||||||
|
|
||||||
rv = _epmfs(basepaths,fusepath,minfs,needswritablefs,paths);
|
rv = _epmfs(type,basepaths,fusepath,paths);
|
||||||
if(POLICY_FAILED(rv))
|
if(POLICY_FAILED(rv))
|
||||||
rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths);
|
rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths);
|
||||||
|
|
||||||
|
@ -33,6 +33,6 @@ namespace mergerfs
|
|||||||
const size_t minfreespace,
|
const size_t minfreespace,
|
||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
return (errno=EROFS,POLICY_FAIL);
|
return POLICY_FAIL_ERRNO(EROFS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,46 @@ using std::size_t;
|
|||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_ff(const vector<string> &basepaths,
|
_ff_create(const vector<string> &basepaths,
|
||||||
const char *fusepath,
|
const size_t minfreespace,
|
||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
const string *fallback;
|
||||||
|
|
||||||
|
fallback = NULL;
|
||||||
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
|
{
|
||||||
|
bool readonly;
|
||||||
|
size_t spaceavail;
|
||||||
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
|
if(!fs::info(*basepath,readonly,spaceavail))
|
||||||
|
continue;
|
||||||
|
if(readonly)
|
||||||
|
continue;
|
||||||
|
if(fallback == NULL)
|
||||||
|
fallback = basepath;
|
||||||
|
if(spaceavail < minfreespace)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
paths.push_back(basepath);
|
||||||
|
|
||||||
|
return POLICY_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fallback == NULL)
|
||||||
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
|
paths.push_back(fallback);
|
||||||
|
|
||||||
|
return POLICY_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_ff_other(const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
string fullpath;
|
string fullpath;
|
||||||
|
|
||||||
@ -52,46 +89,6 @@ _ff(const vector<string> &basepaths,
|
|||||||
return POLICY_FAIL_ENOENT;
|
return POLICY_FAIL_ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
_ff_create(const vector<string> &basepaths,
|
|
||||||
const size_t minfreespace,
|
|
||||||
vector<const string*> &paths)
|
|
||||||
{
|
|
||||||
bool readonly;
|
|
||||||
size_t spaceavail;
|
|
||||||
const string *fallback;
|
|
||||||
|
|
||||||
fallback = NULL;
|
|
||||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
|
||||||
{
|
|
||||||
const string *basepath = &basepaths[i];
|
|
||||||
|
|
||||||
if(!fs::exists(*basepath,readonly,spaceavail))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(readonly)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(fallback == NULL)
|
|
||||||
fallback = basepath;
|
|
||||||
|
|
||||||
if(spaceavail < minfreespace)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
paths.push_back(basepath);
|
|
||||||
|
|
||||||
return POLICY_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fallback == NULL)
|
|
||||||
return POLICY_FAIL_ENOENT;
|
|
||||||
|
|
||||||
paths.push_back(fallback);
|
|
||||||
|
|
||||||
return POLICY_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace mergerfs
|
namespace mergerfs
|
||||||
{
|
{
|
||||||
int
|
int
|
||||||
@ -104,6 +101,6 @@ namespace mergerfs
|
|||||||
if(type == Category::Enum::create)
|
if(type == Category::Enum::create)
|
||||||
return _ff_create(basepaths,minfreespace,paths);
|
return _ff_create(basepaths,minfreespace,paths);
|
||||||
|
|
||||||
return _ff(basepaths,fusepath,paths);
|
return _ff_other(basepaths,fusepath,paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,6 @@ namespace mergerfs
|
|||||||
const size_t minfreespace,
|
const size_t minfreespace,
|
||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
return (errno=EINVAL,POLICY_FAIL);
|
return POLICY_FAIL_ERRNO(EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,75 +15,112 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/statvfs.h>
|
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include "fs_path.hpp"
|
#include "fs_path.hpp"
|
||||||
#include "policy.hpp"
|
#include "policy.hpp"
|
||||||
#include "statvfs_util.hpp"
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
using mergerfs::Policy;
|
|
||||||
using mergerfs::Category;
|
using mergerfs::Category;
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
_calc_lfs(const struct statvfs &st,
|
|
||||||
const string *basepath,
|
|
||||||
const size_t minfreespace,
|
|
||||||
fsblkcnt_t &lfs,
|
|
||||||
const string *&lfsbasepath)
|
|
||||||
{
|
|
||||||
fsblkcnt_t spaceavail;
|
|
||||||
|
|
||||||
spaceavail = StatVFS::spaceavail(st);
|
|
||||||
if((spaceavail > minfreespace) && (spaceavail < lfs))
|
|
||||||
{
|
|
||||||
lfs = spaceavail;
|
|
||||||
lfsbasepath = basepath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_lfs(const vector<string> &basepaths,
|
_lfs_create(const vector<string> &basepaths,
|
||||||
const char *fusepath,
|
const size_t minfreespace,
|
||||||
const size_t minfreespace,
|
vector<const string*> &paths)
|
||||||
const bool needswritablefs,
|
|
||||||
vector<const string*> &paths)
|
|
||||||
{
|
{
|
||||||
string fullpath;
|
string fullpath;
|
||||||
struct statvfs st;
|
size_t lfs;
|
||||||
fsblkcnt_t lfs;
|
|
||||||
const string *lfsbasepath;
|
const string *lfsbasepath;
|
||||||
|
|
||||||
lfs = -1;
|
lfs = std::numeric_limits<size_t>::max();
|
||||||
lfsbasepath = NULL;
|
lfsbasepath = NULL;
|
||||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
|
bool readonly;
|
||||||
|
size_t spaceavail;
|
||||||
const string *basepath = &basepaths[i];
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
fs::path::make(basepath,fusepath,fullpath);
|
if(!fs::info(*basepath,readonly,spaceavail))
|
||||||
|
continue;
|
||||||
if(!fs::available(fullpath,needswritablefs,st))
|
if(readonly)
|
||||||
|
continue;
|
||||||
|
if(spaceavail < minfreespace)
|
||||||
|
continue;
|
||||||
|
if(spaceavail > lfs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_calc_lfs(st,basepath,minfreespace,lfs,lfsbasepath);
|
lfs = spaceavail;
|
||||||
|
lfsbasepath = basepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lfsbasepath == NULL)
|
if(lfsbasepath == NULL)
|
||||||
return (errno=ENOENT,POLICY_FAIL);
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
paths.push_back(lfsbasepath);
|
paths.push_back(lfsbasepath);
|
||||||
|
|
||||||
return POLICY_SUCCESS;
|
return POLICY_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_lfs_other(const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
string fullpath;
|
||||||
|
size_t lfs;
|
||||||
|
const string *lfsbasepath;
|
||||||
|
|
||||||
|
lfs = std::numeric_limits<size_t>::max();
|
||||||
|
lfsbasepath = NULL;
|
||||||
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
|
{
|
||||||
|
size_t spaceavail;
|
||||||
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
|
|
||||||
|
if(!fs::exists(fullpath))
|
||||||
|
continue;
|
||||||
|
if(!fs::spaceavail(*basepath,spaceavail))
|
||||||
|
continue;
|
||||||
|
if(spaceavail > lfs)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lfs = spaceavail;
|
||||||
|
lfsbasepath = basepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lfsbasepath == NULL)
|
||||||
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
|
paths.push_back(lfsbasepath);
|
||||||
|
|
||||||
|
return POLICY_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_lfs(const Category::Enum::Type type,
|
||||||
|
const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
const size_t minfreespace,
|
||||||
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
if(type == Category::Enum::create)
|
||||||
|
return _lfs_create(basepaths,minfreespace,paths);
|
||||||
|
|
||||||
|
return _lfs_other(basepaths,fusepath,paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace mergerfs
|
namespace mergerfs
|
||||||
{
|
{
|
||||||
int
|
int
|
||||||
@ -94,12 +131,8 @@ namespace mergerfs
|
|||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
const char *fp =
|
|
||||||
((type == Category::Enum::create) ? "" : fusepath);
|
|
||||||
const bool needswritablefs =
|
|
||||||
(type == Category::Enum::create);
|
|
||||||
|
|
||||||
rv = _lfs(basepaths,fp,minfreespace,needswritablefs,paths);
|
rv = _lfs(type,basepaths,fusepath,minfreespace,paths);
|
||||||
if(POLICY_FAILED(rv))
|
if(POLICY_FAILED(rv))
|
||||||
rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths);
|
rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths);
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/statvfs.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -23,63 +22,99 @@
|
|||||||
#include "fs.hpp"
|
#include "fs.hpp"
|
||||||
#include "fs_path.hpp"
|
#include "fs_path.hpp"
|
||||||
#include "policy.hpp"
|
#include "policy.hpp"
|
||||||
#include "statvfs_util.hpp"
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
|
using mergerfs::Category;
|
||||||
static
|
|
||||||
void
|
|
||||||
_calc_mfs(const struct statvfs &st,
|
|
||||||
const string *basepath,
|
|
||||||
fsblkcnt_t &mfs,
|
|
||||||
const string *&mfsbasepath)
|
|
||||||
{
|
|
||||||
fsblkcnt_t spaceavail;
|
|
||||||
|
|
||||||
spaceavail = StatVFS::spaceavail(st);
|
|
||||||
if(spaceavail > mfs)
|
|
||||||
{
|
|
||||||
mfs = spaceavail;
|
|
||||||
mfsbasepath = basepath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_mfs(const vector<string> &basepaths,
|
_mfs_create(const vector<string> &basepaths,
|
||||||
const char *fusepath,
|
vector<const string*> &paths)
|
||||||
const bool needswritablefs,
|
|
||||||
vector<const string*> &paths)
|
|
||||||
{
|
{
|
||||||
string fullpath;
|
string fullpath;
|
||||||
struct statvfs st;
|
size_t mfs;
|
||||||
fsblkcnt_t mfs;
|
|
||||||
const string *mfsbasepath;
|
const string *mfsbasepath;
|
||||||
|
|
||||||
mfs = 0;
|
mfs = 0;
|
||||||
mfsbasepath = NULL;
|
mfsbasepath = NULL;
|
||||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
|
bool readonly;
|
||||||
|
size_t spaceavail;
|
||||||
const string *basepath = &basepaths[i];
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
fs::path::make(basepath,fusepath,fullpath);
|
if(!fs::info(*basepath,readonly,spaceavail))
|
||||||
|
continue;
|
||||||
if(!fs::available(fullpath,needswritablefs,st))
|
if(readonly)
|
||||||
|
continue;
|
||||||
|
if(spaceavail < mfs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_calc_mfs(st,basepath,mfs,mfsbasepath);
|
mfs = spaceavail;
|
||||||
|
mfsbasepath = basepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mfsbasepath == NULL)
|
if(mfsbasepath == NULL)
|
||||||
return (errno=ENOENT,POLICY_FAIL);
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
paths.push_back(mfsbasepath);
|
paths.push_back(mfsbasepath);
|
||||||
|
|
||||||
return POLICY_SUCCESS;
|
return POLICY_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_mfs_other(const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
string fullpath;
|
||||||
|
size_t mfs;
|
||||||
|
const string *mfsbasepath;
|
||||||
|
|
||||||
|
mfs = 0;
|
||||||
|
mfsbasepath = NULL;
|
||||||
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
|
{
|
||||||
|
size_t spaceavail;
|
||||||
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
|
|
||||||
|
if(!fs::exists(fullpath))
|
||||||
|
continue;
|
||||||
|
if(!fs::spaceavail(*basepath,spaceavail))
|
||||||
|
continue;
|
||||||
|
if(spaceavail < mfs)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mfs = spaceavail;
|
||||||
|
mfsbasepath = basepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mfsbasepath == NULL)
|
||||||
|
return POLICY_FAIL_ENOENT;
|
||||||
|
|
||||||
|
paths.push_back(mfsbasepath);
|
||||||
|
|
||||||
|
return POLICY_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_mfs(const Category::Enum::Type type,
|
||||||
|
const vector<string> &basepaths,
|
||||||
|
const char *fusepath,
|
||||||
|
vector<const string*> &paths)
|
||||||
|
{
|
||||||
|
if(type == Category::Enum::create)
|
||||||
|
return _mfs_create(basepaths,paths);
|
||||||
|
|
||||||
|
return _mfs_other(basepaths,fusepath,paths);
|
||||||
|
}
|
||||||
|
|
||||||
namespace mergerfs
|
namespace mergerfs
|
||||||
{
|
{
|
||||||
int
|
int
|
||||||
@ -90,12 +125,8 @@ namespace mergerfs
|
|||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
const char *fp =
|
|
||||||
((type == Category::Enum::create) ? "" : fusepath);
|
|
||||||
const bool needswritablefs =
|
|
||||||
(type == Category::Enum::create);
|
|
||||||
|
|
||||||
rv = _mfs(basepaths,fp,needswritablefs,paths);
|
rv = _mfs(type,basepaths,fusepath,paths);
|
||||||
if(POLICY_FAILED(rv))
|
if(POLICY_FAILED(rv))
|
||||||
rv = Policy::Func::ff(type,basepaths,fusepath,minfreespace,paths);
|
rv = Policy::Func::ff(type,basepaths,fusepath,minfreespace,paths);
|
||||||
|
|
||||||
|
@ -38,13 +38,14 @@ _newest_create(const vector<string> &basepaths,
|
|||||||
{
|
{
|
||||||
time_t newest;
|
time_t newest;
|
||||||
string fullpath;
|
string fullpath;
|
||||||
struct stat st;
|
|
||||||
const string *newestbasepath;
|
const string *newestbasepath;
|
||||||
|
|
||||||
newest = std::numeric_limits<time_t>::min();
|
newest = std::numeric_limits<time_t>::min();
|
||||||
newestbasepath = NULL;
|
newestbasepath = NULL;
|
||||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
const string *basepath = &basepaths[i];
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
fs::path::make(basepath,fusepath,fullpath);
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
@ -53,10 +54,10 @@ _newest_create(const vector<string> &basepaths,
|
|||||||
continue;
|
continue;
|
||||||
if(st.st_mtime < newest)
|
if(st.st_mtime < newest)
|
||||||
continue;
|
continue;
|
||||||
if(!fs::exists_on_rw_fs(fullpath))
|
if(fs::readonly(*basepath))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
newest = st.st_mtime;
|
newest = st.st_mtime;
|
||||||
newestbasepath = basepath;
|
newestbasepath = basepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,19 +71,19 @@ _newest_create(const vector<string> &basepaths,
|
|||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_newest(const vector<string> &basepaths,
|
_newest_other(const vector<string> &basepaths,
|
||||||
const char *fusepath,
|
const char *fusepath,
|
||||||
vector<const string*> &paths)
|
vector<const string*> &paths)
|
||||||
{
|
{
|
||||||
time_t newest;
|
time_t newest;
|
||||||
string fullpath;
|
string fullpath;
|
||||||
struct stat st;
|
|
||||||
const string *newestbasepath;
|
const string *newestbasepath;
|
||||||
|
|
||||||
newest = std::numeric_limits<time_t>::min();
|
newest = std::numeric_limits<time_t>::min();
|
||||||
newestbasepath = NULL;
|
newestbasepath = NULL;
|
||||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||||
{
|
{
|
||||||
|
struct stat st;
|
||||||
const string *basepath = &basepaths[i];
|
const string *basepath = &basepaths[i];
|
||||||
|
|
||||||
fs::path::make(basepath,fusepath,fullpath);
|
fs::path::make(basepath,fusepath,fullpath);
|
||||||
@ -92,7 +93,7 @@ _newest(const vector<string> &basepaths,
|
|||||||
if(st.st_mtime < newest)
|
if(st.st_mtime < newest)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
newest = st.st_mtime;
|
newest = st.st_mtime;
|
||||||
newestbasepath = basepath;
|
newestbasepath = basepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +117,6 @@ namespace mergerfs
|
|||||||
if(type == Category::Enum::create)
|
if(type == Category::Enum::create)
|
||||||
return _newest_create(basepaths,fusepath,paths);
|
return _newest_create(basepaths,fusepath,paths);
|
||||||
|
|
||||||
return _newest(basepaths,fusepath,paths);
|
return _newest_other(basepaths,fusepath,paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user