root/software/FUSE_example/readdir_test.cc @ f94cb2af
| a5a5e96b | David Sorber | #include <chrono>
|
|
#include <cerrno>
|
|||
#include <cstring>
|
|||
#include <ctime>
|
|||
#include <iostream>
|
|||
#include <map>
|
|||
#include <string>
|
|||
#include <thread>
|
|||
#include <vector>
|
|||
#include <utility>
|
|||
#include <signal.h>
|
|||
#include <unistd.h>
|
|||
#include <sys/stat.h>
|
|||
#include <fuse3/fuse.h>
|
|||
// The things we do for decent logging...
|
|||
#define LOG(level, msg) {\
|
|||
std::time_t __now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());\
|
|||
char tsstr[100];\
|
|||
std::strftime(tsstr, sizeof(tsstr), "%a %b %d %T", std::localtime(&__now));\
|
|||
std::cerr << tsstr << "|" << level << "|" << __FILE__ << ":" << __LINE__ \
|
|||
<< "|" << msg << std::endl; }
|
|||
#define ERROR(msg) LOG("ERROR", msg)
|
|||
#define DEBUG(msg) LOG("DEBUG", msg)
|
|||
/******************************************************************************
|
|||
* Hardcoded file system data for testing purposes
|
|||
*****************************************************************************/
|
|||
typedef std::tuple<mode_t, uid_t, gid_t, off64_t, time_t, time_t, time_t> EntryAttrs;
|
|||
std::map<std::string, EntryAttrs> fs_data =
|
|||
{
|
|||
std::pair<std::string, EntryAttrs>{".", std::make_tuple(16893, 1000, 1000, 0, 1497357835, 1497357835, 1497357835)},
|
|||
std::pair<std::string, EntryAttrs>{"..", std::make_tuple(16893, 1000, 1000, 0, 1497357835, 1497357835, 1497357835)},
|
|||
std::pair<std::string, EntryAttrs>{"0001.bin", std::make_tuple(33188, 1000, 1000, 168593714, 1513688527, 1496839609, 1496839608)},
|
|||
std::pair<std::string, EntryAttrs>{"0002.bin", std::make_tuple(33188, 1000, 1000, 22593382637, 1513688527, 1496857810, 1496857765)},
|
|||
std::pair<std::string, EntryAttrs>{"0003.bin", std::make_tuple(33188, 1000, 0, 0, 1513688528, 1511787445, 1496859394)},
|
|||
std::pair<std::string, EntryAttrs>{"0004.bin", std::make_tuple(33188, 1000, 0, 4204, 1513688528, 1510043263, 1496859394)},
|
|||
std::pair<std::string, EntryAttrs>{"0005.bin", std::make_tuple(33188, 1000, 1000, 473253720, 1513688528, 1497007653, 1497007652)},
|
|||
std::pair<std::string, EntryAttrs>{"0006.bin", std::make_tuple(33188, 1000, 0, 77563049, 1513688528, 1497017377, 1497007822)},
|
|||
std::pair<std::string, EntryAttrs>{"0007.bin", std::make_tuple(33188, 1000, 1000, 22593382637, 1513688528, 1497351617, 1497351587)},
|
|||
std::pair<std::string, EntryAttrs>{"0008.bin", std::make_tuple(33204, 1000, 1000, 15, 1516107258, 1516107258, 1497357863)},
|
|||
std::pair<std::string, EntryAttrs>{"0009.bin", std::make_tuple(33204, 1000, 1000, 1, 1516107258, 1516107258, 1497357863)},
|
|||
std::pair<std::string, EntryAttrs>{"0010.bin", std::make_tuple(33204, 1000, 1000, 536870912, 1516201822, 1497357867, 1497357865)},
|
|||
std::pair<std::string, EntryAttrs>{"0011.bin", std::make_tuple(33204, 1000, 1000, 549, 1516107859, 1497357867, 1497357867)},
|
|||
std::pair<std::string, EntryAttrs>{"0012.bin", std::make_tuple(33204, 1000, 1000, 22593382637, 1516201816, 1497357956, 1497357871)},
|
|||
std::pair<std::string, EntryAttrs>{"0013.bin", std::make_tuple(33204, 1000, 1000, 1046, 1516109117, 1497357981, 1497357981)},
|
|||
std::pair<std::string, EntryAttrs>{"0014.bin", std::make_tuple(33204, 1000, 1000, 68157440, 1516107747, 1516107741, 1497357983)},
|
|||
std::pair<std::string, EntryAttrs>{"0015.bin", std::make_tuple(33204, 1000, 1000, 6892667, 1516109116, 1497357992, 1497357992)},
|
|||
std::pair<std::string, EntryAttrs>{"0016.bin", std::make_tuple(33204, 1000, 1000, 6892667, 1497357992, 1497357992, 1497357992)},
|
|||
std::pair<std::string, EntryAttrs>{"0017.bin", std::make_tuple(33204, 1000, 1000, 1046, 1513688532, 1497357993, 1497357993)},
|
|||
std::pair<std::string, EntryAttrs>{"0018.bin", std::make_tuple(33204, 1000, 1000, 202375168, 1513688532, 1497358008, 1497358007)},
|
|||
std::pair<std::string, EntryAttrs>{"0019.bin", std::make_tuple(33204, 1000, 1000, 536870912, 1516107330, 1497358016, 1497358013)},
|
|||
std::pair<std::string, EntryAttrs>{"0020.bin", std::make_tuple(33204, 1000, 1000, 268435456, 1516107336, 1497358020, 1497358019)},
|
|||
std::pair<std::string, EntryAttrs>{"0021.bin", std::make_tuple(33204, 1000, 1000, 8144, 1516107593, 1497358031, 1497358030)},
|
|||
std::pair<std::string, EntryAttrs>{"0022.bin", std::make_tuple(33204, 1000, 1000, 4775, 1516107734, 1497358046, 1497358046)},
|
|||
std::pair<std::string, EntryAttrs>{"0023.bin", std::make_tuple(33204, 1000, 1000, 481, 1516107371, 1497358047, 1497358047)},
|
|||
std::pair<std::string, EntryAttrs>{"0024.bin", std::make_tuple(33204, 1000, 1000, 526201714, 1497358048, 1497358049, 1497358048)},
|
|||
std::pair<std::string, EntryAttrs>{"0025.bin", std::make_tuple(33204, 1000, 1000, 4725659, 1516108145, 1497358050, 1497358049)},
|
|||
std::pair<std::string, EntryAttrs>{"0026.bin", std::make_tuple(33204, 1000, 1000, 4461205, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0027.bin", std::make_tuple(33204, 1000, 1000, 4670395, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0028.bin", std::make_tuple(33204, 1000, 1000, 4627799, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0029.bin", std::make_tuple(33204, 1000, 1000, 4588549, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0030.bin", std::make_tuple(33204, 1000, 1000, 4586073, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0031.bin", std::make_tuple(33204, 1000, 1000, 4537877, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0032.bin", std::make_tuple(33204, 1000, 1000, 4481762, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0033.bin", std::make_tuple(33204, 1000, 1000, 4529771, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0034.bin", std::make_tuple(33204, 1000, 1000, 4715336, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0035.bin", std::make_tuple(33204, 1000, 1000, 4696289, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0036.bin", std::make_tuple(33204, 1000, 1000, 4528268, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0037.bin", std::make_tuple(33204, 1000, 1000, 4539782, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0038.bin", std::make_tuple(33204, 1000, 1000, 4653329, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0039.bin", std::make_tuple(33204, 1000, 1000, 4521595, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0040.bin", std::make_tuple(33204, 1000, 1000, 4660637, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0041.bin", std::make_tuple(33204, 1000, 1000, 4581008, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0042.bin", std::make_tuple(33204, 1000, 1000, 4578016, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0043.bin", std::make_tuple(33204, 1000, 1000, 4753460, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0044.bin", std::make_tuple(33204, 1000, 1000, 4559827, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0045.bin", std::make_tuple(33204, 1000, 1000, 4586278, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0046.bin", std::make_tuple(33204, 1000, 1000, 4622489, 1516108145, 1497358050, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0047.bin", std::make_tuple(33204, 1000, 1000, 4392706, 1516108145, 1497358051, 1497358050)},
|
|||
std::pair<std::string, EntryAttrs>{"0048.bin", std::make_tuple(33204, 1000, 1000, 4592057, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0049.bin", std::make_tuple(33204, 1000, 1000, 4692335, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0050.bin", std::make_tuple(33204, 1000, 1000, 4641344, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0051.bin", std::make_tuple(33204, 1000, 1000, 4519803, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0052.bin", std::make_tuple(33204, 1000, 1000, 4580694, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0053.bin", std::make_tuple(33204, 1000, 1000, 4562114, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0054.bin", std::make_tuple(33204, 1000, 1000, 4537820, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0055.bin", std::make_tuple(33204, 1000, 1000, 4523996, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0056.bin", std::make_tuple(33204, 1000, 1000, 4680014, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0057.bin", std::make_tuple(33204, 1000, 1000, 4496418, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0058.bin", std::make_tuple(33204, 1000, 1000, 4804784, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0059.bin", std::make_tuple(33204, 1000, 1000, 4510851, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0060.bin", std::make_tuple(33204, 1000, 1000, 4651723, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0061.bin", std::make_tuple(33204, 1000, 1000, 4582348, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0062.bin", std::make_tuple(33204, 1000, 1000, 4556271, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0063.bin", std::make_tuple(33204, 1000, 1000, 4416323, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0064.bin", std::make_tuple(33204, 1000, 1000, 4584588, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0065.bin", std::make_tuple(33204, 1000, 1000, 4617515, 1516108145, 1497358051, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0066.bin", std::make_tuple(33204, 1000, 1000, 4738641, 1516108145, 1497358052, 1497358051)},
|
|||
std::pair<std::string, EntryAttrs>{"0067.bin", std::make_tuple(33204, 1000, 1000, 4521443, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0068.bin", std::make_tuple(33204, 1000, 1000, 4857734, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0069.bin", std::make_tuple(33204, 1000, 1000, 4653949, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0070.bin", std::make_tuple(33204, 1000, 1000, 4709419, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0071.bin", std::make_tuple(33204, 1000, 1000, 4390969, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0072.bin", std::make_tuple(33204, 1000, 1000, 4444072, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0073.bin", std::make_tuple(33204, 1000, 1000, 4320725, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0074.bin", std::make_tuple(33204, 1000, 1000, 4819829, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0075.bin", std::make_tuple(33204, 1000, 1000, 4686232, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0076.bin", std::make_tuple(33204, 1000, 1000, 4749938, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0077.bin", std::make_tuple(33204, 1000, 1000, 4694213, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0078.bin", std::make_tuple(33204, 1000, 1000, 4698242, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0079.bin", std::make_tuple(33204, 1000, 1000, 4794803, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0080.bin", std::make_tuple(33204, 1000, 1000, 4606039, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0081.bin", std::make_tuple(33204, 1000, 1000, 4399879, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0082.bin", std::make_tuple(33204, 1000, 1000, 4816006, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0083.bin", std::make_tuple(33204, 1000, 1000, 4663708, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0084.bin", std::make_tuple(33204, 1000, 1000, 4879173, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0085.bin", std::make_tuple(33204, 1000, 1000, 4871831, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0086.bin", std::make_tuple(33204, 1000, 1000, 4563574, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0087.bin", std::make_tuple(33204, 1000, 1000, 4847954, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0088.bin", std::make_tuple(33204, 1000, 1000, 4878237, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0089.bin", std::make_tuple(33204, 1000, 1000, 4812806, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0090.bin", std::make_tuple(33204, 1000, 1000, 4701756, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0091.bin", std::make_tuple(33204, 1000, 1000, 4418793, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0092.bin", std::make_tuple(33204, 1000, 1000, 4860231, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0093.bin", std::make_tuple(33204, 1000, 1000, 4404407, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0094.bin", std::make_tuple(33204, 1000, 1000, 4356939, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0095.bin", std::make_tuple(33204, 1000, 1000, 4517704, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0096.bin", std::make_tuple(33204, 1000, 1000, 4411777, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0097.bin", std::make_tuple(33204, 1000, 1000, 4597873, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0098.bin", std::make_tuple(33204, 1000, 1000, 4458429, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0099.bin", std::make_tuple(33204, 1000, 1000, 4776084, 1516108145, 1497358052, 1497358052)},
|
|||
std::pair<std::string, EntryAttrs>{"0100.bin", std::make_tuple(33204, 1000, 1000, 4762316, 1516108145, 1497358053, 1497358053)},
|
|||
};
|
|||
// Globals
|
|||
const std::string mountpoint("/mnt/readdir");
|
|||
const uint32_t BLK_SIZE = 512;
|
|||
struct fuse_args* p_fuseArgv = nullptr;
|
|||
struct fuse* p_fuseInstance = nullptr;
|
|||
struct fuse_loop_config loop_config;
|
|||
struct fuse_operations operations;
|
|||
std::thread* p_fuseEventThread = nullptr;
|
|||
struct sigaction exit_act;
|
|||
std::vector<std::pair<std::string, struct stat>> readdir_cache;
|
|||
// FUSE operation functions
|
|||
void* test_init(struct fuse_conn_info* info, fuse_config* config)
|
|||
{
|
|||
// Disable ATOMIC_O_TRUNC, which is enabled by default
|
|||
info->want &= (~FUSE_CAP_ATOMIC_O_TRUNC);
|
|||
// Enable FUSE_CAP_READDIRPLUS to get better performance with readdir on
|
|||
// large directories
|
|||
info->want |= FUSE_CAP_READDIRPLUS;
|
|||
info->want |= FUSE_CAP_READDIRPLUS_AUTO;
|
|||
// Disable FUSE_CAP_AUTO_INVAL_DATA because it checks file attributes after
|
|||
// each read request which slows things way down...
|
|||
info->want &= (~FUSE_CAP_AUTO_INVAL_DATA);
|
|||
// Make sure asynchronous reads are enabled
|
|||
info->want |= FUSE_CAP_ASYNC_READ;
|
|||
// None of these really seem to do anything... but we can dream
|
|||
info->max_read = 0; // no limit but the kernel will limit anyway
|
|||
info->max_readahead = 1073741824; // 1GB
|
|||
info->max_write = 1073741824; // 1GB
|
|||
// Set attr timeout to 3600 seconds (60m/1hr) to effectively enable
|
|||
// attribute caching.
|
|||
config->attr_timeout = 3600;
|
|||
DEBUG("FS (FUSE) Initialized.");
|
|||
return nullptr;
|
|||
}
|
|||
// Helper function
|
|||
inline void __populate_stat_buf(
|
|||
struct stat& stat_buf,
|
|||
std::pair<const std::string, EntryAttrs>& entry)
|
|||
{
|
|||
stat_buf.st_mode = (mode_t) std::get<0>(entry.second);
|
|||
stat_buf.st_uid = (uid_t) std::get<1>(entry.second);
|
|||
stat_buf.st_gid = (gid_t) std::get<2>(entry.second);
|
|||
stat_buf.st_size = (off64_t) std::get<3>(entry.second);
|
|||
stat_buf.st_ctime = (time_t) std::get<4>(entry.second);
|
|||
stat_buf.st_atime = (time_t) std::get<5>(entry.second);
|
|||
stat_buf.st_mtime = (time_t) std::get<6>(entry.second);
|
|||
stat_buf.st_blksize = BLK_SIZE;
|
|||
stat_buf.st_blocks = (stat_buf.st_size / stat_buf.st_blksize);
|
|||
return;
|
|||
}
|
|||
int test_getattr(
|
|||
const char* path,
|
|||
struct stat* ss,
|
|||
struct fuse_file_info* /* info */)
|
|||
{
|
|||
DEBUG("GETATTR: " << path);
|
|||
std::string path_str(path);
|
|||
if (path_str == "/")
|
|||
{
|
|||
path_str = ".";
|
|||
}
|
|||
else
|
|||
{
|
|||
// Strip on leading slash
|
|||
path_str = path_str.substr(1);
|
|||
}
|
|||
// Find the directory entry
|
|||
auto iter = fs_data.find(path_str);
|
|||
if (iter == fs_data.end())
|
|||
{
|
|||
DEBUG("GETATTR: returning ENOENT");
|
|||
return -ENOENT;
|
|||
}
|
|||
// Populate the stat buffer
|
|||
__populate_stat_buf(*ss, *iter);
|
|||
return 0;
|
|||
}
|
|||
int test_readdir(
|
|||
const char* path,
|
|||
void* buf,
|
|||
fuse_fill_dir_t filler,
|
|||
off_t offset,
|
|||
struct fuse_file_info* /* info */,
|
|||
fuse_readdir_flags flags)
|
|||
{
|
|||
DEBUG("READDIR (offset: " << offset << " flags: " << flags << "): " << path);
|
|||
bool readdir_plus = (flags & FUSE_READDIR_PLUS);
|
|||
if (offset == 0)
|
|||
{
|
|||
struct stat stat_buf;
|
|||
std::memset(&stat_buf, 0, sizeof(struct stat));
|
|||
// Iterate over the directory contents
|
|||
for (auto& iter : fs_data)
|
|||
{
|
|||
__populate_stat_buf(stat_buf, iter);
|
|||
if (iter.first == "." || iter.first == "..")
|
|||
{
|
|||
stat_buf.st_ino = 17; // must be nonzero for these entries to appear
|
|||
}
|
|||
// If readdir plus populate the cache otherwise just call filler
|
|||
if (readdir_plus)
|
|||
{
|
|||
readdir_cache.emplace_back(iter.first, stat_buf);
|
|||
}
|
|||
else
|
|||
{
|
|||
// "regular" readdir
|
|||
filler(buf, iter.first.c_str(), &stat_buf, 0, (fuse_fill_dir_flags)0);
|
|||
}
|
|||
}
|
|||
if (! readdir_plus)
|
|||
{
|
|||
return 0;
|
|||
}
|
|||
}
|
|||
// readdir plus fill in entries
|
|||
for (off_t offset_idx = offset; offset_idx < readdir_cache.size(); ++offset_idx)
|
|||
{
|
|||
if (filler(buf, readdir_cache[offset_idx].first.c_str(),
|
|||
&readdir_cache[offset_idx].second, offset_idx + 1,
|
|||
FUSE_FILL_DIR_PLUS))
|
|||
{
|
|||
break;
|
|||
}
|
|||
}
|
|||
// Clear readdir cache
|
|||
if (offset == readdir_cache.size())
|
|||
{
|
|||
DEBUG("freeing readdir cache");
|
|||
readdir_cache.clear();
|
|||
}
|
|||
return 0;
|
|||
}
|
|||
void run()
|
|||
{
|
|||
if (p_fuseInstance == nullptr)
|
|||
{
|
|||
ERROR("FUSE instance pointer is null");
|
|||
return;
|
|||
}
|
|||
std::memset(&loop_config, 0, sizeof(struct fuse_loop_config));
|
|||
loop_config.clone_fd = 1;
|
|||
loop_config.max_idle_threads = 10;
|
|||
DEBUG("about to call fuse_loop_mt()");
|
|||
fuse_loop_mt(p_fuseInstance, &loop_config);
|
|||
DEBUG("fuse_loop_mt() returned");
|
|||
}
|
|||
void stop(int signum)
|
|||
{
|
|||
DEBUG("handler triggered");
|
|||
if (p_fuseInstance != nullptr)
|
|||
{
|
|||
fuse_exit(p_fuseInstance);
|
|||
}
|
|||
}
|
|||
// g++ -std=c++11 -O3 -o readdir_test readdir_test.cc -lfuse3 -DFUSE_USE_VERSION=32
|
|||
int main(int argc, char** argv)
|
|||
{
|
|||
std::cout << "Readdir Test FS\n" << std::endl;
|
|||
// Make sure the mountpoint exists and is a directory
|
|||
struct stat stat_buf;
|
|||
int rc = stat(mountpoint.c_str(), &stat_buf);
|
|||
if (rc != 0)
|
|||
{
|
|||
ERROR("mountpoint: " << mountpoint << " " <<strerror(errno));
|
|||
return -1;
|
|||
}
|
|||
else if (! S_ISDIR(stat_buf.st_mode))
|
|||
{
|
|||
ERROR("mountpoint: " << mountpoint << " is not a directory");
|
|||
return -1;
|
|||
}
|
|||
// Install signal handler
|
|||
sigemptyset(&(exit_act.sa_mask));
|
|||
exit_act.sa_handler = stop;
|
|||
exit_act.sa_flags = 0;
|
|||
// Act on an interrupt (^C), a quit (^\), and the default kill.
|
|||
sigaction(SIGTERM, &exit_act, nullptr);
|
|||
sigaction(SIGINT, &exit_act, nullptr);
|
|||
sigaction(SIGQUIT, &exit_act, nullptr);
|
|||
// Get together the FUSE args
|
|||
p_fuseArgv = new struct fuse_args;
|
|||
*p_fuseArgv = FUSE_ARGS_INIT(0, NULL);
|
|||
// Fake the name of the binary, just as a typical argv.
|
|||
if ((rc = fuse_opt_add_arg(p_fuseArgv, argv[0])) < 0)
|
|||
{
|
|||
ERROR("unable to add fuse arg: " << rc);
|
|||
return -2;
|
|||
}
|
|||
if ((rc = fuse_opt_add_arg(p_fuseArgv, "-oallow_other")) < 0)
|
|||
{
|
|||
ERROR("unable to add fuse arg: " << rc);
|
|||
return -2;
|
|||
}
|
|||
if ((rc = fuse_opt_add_arg(p_fuseArgv, "-onosuid,noexec,nodev")) < 0)
|
|||
{
|
|||
ERROR("unable to add fuse arg: " << rc);
|
|||
return -2;
|
|||
}
|
|||
if ((rc = fuse_opt_add_arg(p_fuseArgv, "-odefault_permissions")) < 0)
|
|||
{
|
|||
ERROR("unable to add fuse arg: " << rc);
|
|||
return -2;
|
|||
}
|
|||
if ((rc = fuse_opt_add_arg(p_fuseArgv, "--")) < 0)
|
|||
{
|
|||
ERROR("unable to add fuse arg: " << rc);
|
|||
return -2;
|
|||
}
|
|||
// Install operation function pointers
|
|||
std::memset(&operations, 0, sizeof(struct fuse_operations));
|
|||
operations.init = test_init;
|
|||
operations.getattr = test_getattr;
|
|||
operations.readdir = test_readdir;
|
|||
// Create the FUSE instance
|
|||
p_fuseInstance = fuse_new(p_fuseArgv, &operations, sizeof(operations),
|
|||
nullptr);
|
|||
if (p_fuseInstance == nullptr)
|
|||
{
|
|||
ERROR("unable to create FUSE instance");
|
|||
return -3;
|
|||
}
|
|||
DEBUG("FUSE instance created");
|
|||
// Mount
|
|||
rc = fuse_mount(p_fuseInstance, mountpoint.c_str());
|
|||
if (rc != 0)
|
|||
{
|
|||
ERROR("unable to mount; fuse_mount() returned: " << rc);
|
|||
return -4;
|
|||
}
|
|||
DEBUG("FUSE mounted");
|
|||
// Start the event thread
|
|||
DEBUG("FUSE thread starting...");
|
|||
p_fuseEventThread = new std::thread(run);
|
|||
if (p_fuseEventThread == nullptr)
|
|||
{
|
|||
ERROR("unable to create FUSE even thread");
|
|||
return -5;
|
|||
}
|
|||
DEBUG("FUSE thread running...");
|
|||
// Wait for the event thread to terminate
|
|||
p_fuseEventThread->join();
|
|||
DEBUG("FUSE thread stopping...");
|
|||
// Clean up
|
|||
if (p_fuseInstance != nullptr)
|
|||
{
|
|||
fuse_unmount(p_fuseInstance);
|
|||
fuse_destroy(p_fuseInstance);
|
|||
}
|
|||
DEBUG("FUSE unmounted and destroyed");
|
|||
delete p_fuseArgv;
|
|||
delete p_fuseEventThread;
|
|||
return 0;
|
|||
}
|