Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
|
09-03-2024, 05:01 AM
|
#1
|
LQ Newbie
Registered: Sep 2024
Posts: 4
Rep:
|
FUSE does not call my 'readdir' callback
I've been trying to write a custom filesystem with fuse and I've run into a little problem. Trying to use `ls` on the mounted filesystem produced a Function not implemented error. Using the -d option helped with pinpointing the problem: FUSE thinks the readdir operation is not implemented. It just says it's not implemented
Code:
unique: 262, opcode: READDIR (28), nodeid: 1, insize: 80, pid: 4699
unique: 262, error: -38 (Function not implemented), outsize: 16
This is the full source code:
Code:
// mkdir cd
#define FUSE_USE_VERSION 31
#include <fuse3/fuse.h>
#include <stdio.h>
#include <string.h>
#include <mkern_types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <uuid/uuid.h>
#define printe(msg, ...) fprintf(stderr, msg, __VA_ARGS__)
struct file_handle
{
m_bool avail;
char *path;
uint64_t ptr;
mkern_fD dir;
};
struct file_handle *ftab;
uint64_t nEntries;
mkern_boot_block bblock;
mkern_fD_dir rootDir;
FILE *dev = NULL;
m_bool kernMod = m_false;
int brkStr(char *str, char **toks[], const char brkchr);
m_uint32 CalcC32(void *data, const m_size64 size);
int getFDInfo(mkern_fD *fdir, const char *path)
{
char *pth = NULL;
m_char8 *name = NULL;
int nlev = 0;
mkern_fD dir;
char **dirstr = NULL;
if (!strcmp("/", path))
{
memcpy(fdir, &rootDir, sizeof(dir));
return 1;
}
if (!(name = calloc(bblock.blk_size_bs - sizeof(mkern_fD), sizeof(m_char8))))
return 0;
if (!(pth = strdup(path)))
{
free(name);
return 0;
}
if (!(nlev = brkStr(pth, &dirstr, '/')))
goto exit_fail;
dir = *((mkern_fD *)&rootDir);
for (int i = 1; i < nlev; i++)
{
fseek(dev, (bblock.rootDir_off_blk + ((mkern_fD_dir *)&dir)->fDirs) * bblock.blk_size_bs, SEEK_SET);
fread(&dir, sizeof(dir), 1, dev);
fread(name, bblock.blk_size_bs - sizeof(mkern_fD), 1, dev);
while (1)
{
if (!strcmp(name, dirstr[i]))
{
if ((dir.type & MKERN_FDIR_TYPE) == MKERN_FDIR_TYPE_DIR && dir.type & MKERN_FDIR_VISIBLE | kernMod)
break;
else if (i == nlev - 1 && dir.type & MKERN_FDIR_VISIBLE | kernMod)
break;
goto exit_fail;
}
if (!dir.next_fileDir_blk)
goto exit_fail;
fseek(dev, (bblock.rootDir_off_blk + dir.next_fileDir_blk) * bblock.blk_size_bs, SEEK_SET);
fread(&dir, sizeof(dir), 1, dev);
fread(name, bblock.blk_size_bs - sizeof(mkern_fD), 1, dev);
}
}
memcpy(fdir, &dir, sizeof(dir));
free(name);
free(pth);
return 1;
exit_fail:
free(name);
free(pth);
return 0;
}
m_uint64 reassignHandle(const char *path, mkern_fD dir)
{
m_uint64 found = 0;
for (uint64_t i = 0; i < nEntries; i++)
{
if (!strcmp(path, ftab[i].path))
return 0;
if (ftab[i].avail && !found)
{
ftab[i].avail = m_false;
ftab[i].path = path;
ftab[i].ptr = 0;
ftab[i].dir = dir;
found = i;
}
}
return found;
}
m_uint64 createHandle(const char *path, mkern_fD dir)
{
for (int i = 0; i < nEntries; i++)
{
if (!strcmp(path, ftab[i].path))
return 0;
}
if (!(ftab = reallocarray(ftab, nEntries + 1, sizeof(struct file_handle))))
return 0;
ftab[nEntries].avail = m_false;
ftab[nEntries].path = path;
ftab[nEntries].ptr = 0;
ftab[nEntries].dir = dir;
nEntries++;
return nEntries - 1;
}
int releaseHandle(struct fuse_file_info *finfo)
{
if (!finfo)
return 0;
if (finfo->fh > nEntries)
return 0;
ftab[finfo->fh].avail = m_true;
return 1;
}
int getHandleFDInfo(m_uint64 fh, mkern_fD *dir)
{
if (fh > nEntries)
return 0;
*dir = ftab[fh].dir;
return 1;
}
int m_readdir(const char *path, void *private_data, fuse_fill_dir_t filler, off_t off, struct fuse_file_info *finfo, enum fuse_readdir_flags flgs)
{
mkern_fD dir;
char name[960];
struct stat sinf;
printf("what's going on\n");
if (!finfo)
return -EINVAL;
if ((dir.type & MKERN_FDIR_TYPE) != MKERN_FDIR_TYPE_DIR)
return -EACCES;
if (!getHandleFDInfo(finfo->fh, &dir))
return -EBADF;
fseek(dev, (bblock.rootDir_off_blk + ((mkern_fD_dir *)&dir)->fDirs) * bblock.blk_size_bs, SEEK_SET);
memset(&sinf, 0, sizeof(sinf));
while (1)
{
fread(&dir, sizeof(dir), 1, dev);
if (!(dir.type & MKERN_FDIR_VISIBLE) && !kernMod)
goto get_next_blk;
fread(name, sizeof(name), 1, dev);
sinf.st_uid = getuid();
sinf.st_gid = getgid();
sinf.st_atime = dir.lastAcc_time;
sinf.st_mtime = dir.lastAcc_time;
if ((dir.type & MKERN_FDIR_TYPE) == MKERN_FDIR_TYPE_DIR)
{
if (!strcmp("/", path))
sinf.st_mode = S_IFDIR | 0755;
sinf.st_mode = S_IFDIR | 0644;
}
else
{
sinf.st_mode = S_IFREG | 0644;
sinf.st_size = ((mkern_fD_file *)&dir)->size_blk * 1024;
}
filler(private_data, name, &sinf, 0, flgs);
get_next_blk:
if (!dir.next_fileDir_blk)
break;
fseek(dev, (bblock.rootDir_off_blk + dir.next_fileDir_blk) * bblock.blk_size_bs, SEEK_SET);
}
return 0;
}
int m_read(const char *path, char *data, size_t size, off_t off, struct fuse_file_info *finfo)
{
printf("as\n");
strcpy(data, "Yeah whatever rocks your boat\n");
return sizeof("Yeah whatever rocks your boat\n");
}
int m_getattr(const char *path, struct stat *st, struct fuse_file_info *finfo)
{
mkern_fD inf;
if (!path || !st)
return -EINVAL;
if (!getFDInfo(&inf, path))
return -ENOENT;
memset(st, 0, sizeof(struct stat));
st->st_uid = getuid();
st->st_gid = getgid();
st->st_atime = inf.lastAcc_time;
st->st_mtime = inf.lastAcc_time;
if ((inf.type & MKERN_FDIR_TYPE) == MKERN_FDIR_TYPE_DIR)
{
if (!strcmp("/", path))
st->st_mode = S_IFDIR | 0755;
st->st_mode = S_IFDIR | 0644;
}
else
{
st->st_mode = S_IFREG | 0644;
st->st_size = ((mkern_fD_file *)&inf)->size_blk * 1024;
}
return 0;
}
int m_create(const char *path, mode_t mode, struct fuse_file_info *finfo)
{
char **dirstr = NULL;
mkern_fD dir;
if (!path || !finfo)
return -EINVAL;
if (getFDInfo(&dir, path))
return EEXIST;
if (!(finfo->fh = reassignHandle(path, dir)))
{
if (!(finfo->fh = createHandle(path, dir)))
return -ENOMEM;
}
return 0;
}
int m_open(const char *path, struct fuse_file_info *finfo)
{
mkern_fD dir;
if (!path || !finfo)
return -EINVAL;
if (finfo->flags & O_CREAT)
printe("can't use open to create\n", NULL);
if (!getFDInfo(&dir, path))
return -ENOENT;
if ((dir.type & MKERN_FDIR_TYPE) == MKERN_FDIR_TYPE_DIR && (finfo->flags & O_ACCMODE) != O_RDONLY)
return -EACCES;
if (!(finfo->fh = reassignHandle(path, dir)))
{
if (!(finfo->fh = createHandle(path, dir)))
return -ENOMEM;
}
return 0;
}
int m_release(const char *path, struct fuse_file_info *finfo)
{
if (!path || !finfo)
return -EINVAL;
if (!releaseHandle(finfo))
return -ENOENT;
return 0;
}
int m_mkdir(const char *path, mode_t mode)
{
return 0;
}
int m_opendir(const char *path, struct fuse_file_info *finfo)
{
mkern_fD dir;
if (!path || !finfo)
return -EINVAL;
if (!getFDInfo(&dir, path))
return -ENOENT;
if ((dir.type & MKERN_FDIR_TYPE) != MKERN_FDIR_TYPE_DIR)
return -EACCES;
if (!(finfo->fh = reassignHandle(path, dir)))
{
if (!(finfo->fh = createHandle(path, dir)))
return -ENOMEM;
}
return 0;
}
int m_releasedir(const char *path, struct fuse_file_info *finfo)
{
if (!path || !finfo)
return -EINVAL;
if (!releaseHandle(finfo))
return -ENOENT;
return 0;
}
void *m_init()
{
return NULL;
}
struct fuse_operations fo = {
.open = m_open,
.release = m_release,
.readdir = m_readdir,
.read = m_read,
.getattr = m_getattr,
.create = m_create,
.opendir = m_opendir,
.releasedir = m_releasedir,
.mkdir = m_mkdir,
.init = m_init,
};
int main(int argc, char **argv)
{
char *args[6];
mkern_fD atab;
if (argc < 3)
{
printe("msh: incorrect usage\n", NULL);
return -1;
}
if (!(dev = fopen(argv[1], "r+")))
{
printe("could not open %s\n", argv[1]);
return -1;
}
fread(&bblock, sizeof(bblock), 1, dev);
fseek(dev, bblock.rootDir_off_blk * bblock.blk_size_bs, SEEK_SET);
fread(&rootDir, sizeof(rootDir), 1, dev);
ftab = calloc(4, sizeof(struct file_handle));
kernMod = m_true;
if (!getFDInfo(&atab, "/allocTab"))
{
printe("something is wrong\n", NULL);
return -1;
}
kernMod = m_false;
ftab[3].dir = atab;
ftab[3].path = "/allocTab";
nEntries = 4;
if (bblock.checksum != CalcC32(&bblock, sizeof(bblock) - 4))
{
printe("boot block corrupted\n", NULL);
return -1;
}
args[0] = argv[0];
args[1] = "-f";
args[2] = argv[2];
args[3] = "-d";
args[4] = "-oauto_unmount";
args[5] = "-s";
return fuse_main(6, args, &fo, NULL);
}
m_uint32 CalcC32(void *data, const m_size64 size)
{
m_uint32 b, crc = 0xffffffff, mask;
m_byte *bs = (m_byte *)data;
for (m_size64 i = 0; i < size; i++)
{
b = bs[i];
crc ^= b;
for (m_size64 j = 0; j < 8; j++)
{
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xedb88320 & mask);
}
}
return ~crc;
}
int brkStr(char *str, char **toks[], const char brkchr)
{
char **tmp = NULL;
int n = 0;
if (!(str && toks && brkchr))
return 0;
for (int i = 0;; i++)
{
if (!tmp || !tmp[n])
{
tmp = reallocarray(tmp, n + 2, sizeof(char *));
tmp[n] = &str[i];
tmp[n + 1] = NULL;
}
if (str[i] == brkchr)
{
str[i] = 0;
n++;
}
else if (!str[i])
{
n++;
break;
}
}
*toks = tmp;
return n;
}
Last edited by ejinkas12; 09-03-2024 at 09:10 AM.
|
|
|
09-03-2024, 05:17 AM
|
#2
|
Senior Member
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,924
|
Can it be your code that doesn't implement readdir? (readdir field of fuse_operations structure)
Code:
asm-generic/errno.h: #define ENOSYS 38 /* Function not implemented */
Last edited by NevemTeve; 09-03-2024 at 05:23 AM.
|
|
|
09-03-2024, 05:28 AM
|
#3
|
LQ Newbie
Registered: Sep 2024
Posts: 4
Original Poster
Rep:
|
I implemented the callback actually.
Code:
int m_readdir(const char *path, void *private_data, fuse_fill_dir_t filler, off_t off, struct fuse_file_info *finfo, enum fuse_readdir_flags flgs)
{
mkern_fD dir;
char name[960];
struct stat sinf;
printf("what's going on\n");
if (!finfo)
return -EINVAL;
if ((dir.type & MKERN_FDIR_TYPE) != MKERN_FDIR_TYPE_DIR)
return -EACCES;
if (!getHandleFDInfo(finfo->fh, &dir))
return -EBADF;
fseek(dev, (bblock.rootDir_off_blk + ((mkern_fD_dir *)&dir)->fDirs) * bblock.blk_size_bs, SEEK_SET);
memset(&sinf, 0, sizeof(sinf));
while (1)
{
fread(&dir, sizeof(dir), 1, dev);
if (!(dir.type & MKERN_FDIR_VISIBLE) && !kernMod)
goto get_next_blk;
fread(name, sizeof(name), 1, dev);
sinf.st_uid = getuid();
sinf.st_gid = getgid();
sinf.st_atime = dir.lastAcc_time;
sinf.st_mtime = dir.lastAcc_time;
if ((dir.type & MKERN_FDIR_TYPE) == MKERN_FDIR_TYPE_DIR)
{
if (!strcmp("/", path))
sinf.st_mode = S_IFDIR | 0755;
sinf.st_mode = S_IFDIR | 0644;
}
else
{
sinf.st_mode = S_IFREG | 0644;
sinf.st_size = ((mkern_fD_file *)&dir)->size_blk * 1024;
}
filler(private_data, name, &sinf, 0, flgs);
get_next_blk:
if (!dir.next_fileDir_blk)
break;
fseek(dev, (bblock.rootDir_off_blk + dir.next_fileDir_blk) * bblock.blk_size_bs, SEEK_SET);
}
return 0;
}
struct fuse_operations fo = {
.open = m_open,
.release = m_release,
.readdir = m_readdir,
.read = m_read,
.getattr = m_getattr,
.create = m_create,
.opendir = m_opendir,
.releasedir = m_releasedir,
.mkdir = m_mkdir,
.init = m_init,
};
|
|
|
09-03-2024, 05:47 AM
|
#4
|
LQ Addict
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702
|
it is not enough (to create a function) but you need to tell the system to use it. (that means you need to set the callback to this function).
|
|
|
09-03-2024, 09:10 AM
|
#5
|
LQ Newbie
Registered: Sep 2024
Posts: 4
Original Poster
Rep:
|
Please look at the code again. I called fuse_main and passed the fuse_operations structure fo which has the callback for readdir.
|
|
|
09-03-2024, 09:19 AM
|
#6
|
LQ Addict
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702
|
"function not implemented" means the callback points to the default handler, which will print this message.
|
|
|
09-04-2024, 12:23 PM
|
#7
|
LQ Newbie
Registered: Sep 2024
Posts: 4
Original Poster
Rep:
|
Well, this is embarrassing. Turns out that the reason everything was going haywire was because I used `pkg-config fuse --libs --cflags` when compiling instead of `pkg-config fuse3 --libs --cflags`. I think this should serve as a deterrent to me to include the compilation command I used next time.
|
|
4 members found this post helpful.
|
09-04-2024, 12:39 PM
|
#8
|
LQ Addict
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702
|
don't worry, you found it. That is the most important thing.
|
|
1 members found this post helpful.
|
09-04-2024, 12:44 PM
|
#9
|
Moderator
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,295
|
Quote:
Originally Posted by ejinkas12
Well, this is embarrassing. Turns out that the reason everything was going haywire was because I used `pkg-config fuse --libs --cflags` when compiling instead of `pkg-config fuse3 --libs --cflags`. I think this should serve as a deterrent to me to include the compilation command I used next time.
|
We all do it!
Thanks for returning to update the thread, and a belated, "Welcome to LQ and the Programming forum"!
|
|
|
All times are GMT -5. The time now is 04:31 PM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|