LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
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


Reply
  Search this Thread
Old 09-03-2024, 05:01 AM   #1
ejinkas12
LQ Newbie
 
Registered: Sep 2024
Posts: 4

Rep: Reputation: 14
Unhappy 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.
 
Old 09-03-2024, 05:17 AM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,924
Blog Entries: 1

Rep: Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886Reputation: 1886
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.
 
Old 09-03-2024, 05:28 AM   #3
ejinkas12
LQ Newbie
 
Registered: Sep 2024
Posts: 4

Original Poster
Rep: Reputation: 14
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,
};
 
Old 09-03-2024, 05:47 AM   #4
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702

Rep: Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535
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).
 
Old 09-03-2024, 09:10 AM   #5
ejinkas12
LQ Newbie
 
Registered: Sep 2024
Posts: 4

Original Poster
Rep: Reputation: 14
Please look at the code again. I called fuse_main and passed the fuse_operations structure fo which has the callback for readdir.
 
Old 09-03-2024, 09:19 AM   #6
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702

Rep: Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535
"function not implemented" means the callback points to the default handler, which will print this message.
 
Old 09-04-2024, 12:23 PM   #7
ejinkas12
LQ Newbie
 
Registered: Sep 2024
Posts: 4

Original Poster
Rep: Reputation: 14
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.
Old 09-04-2024, 12:39 PM   #8
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,702

Rep: Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535Reputation: 7535
don't worry, you found it. That is the most important thing.
 
1 members found this post helpful.
Old 09-04-2024, 12:44 PM   #9
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,295
Blog Entries: 24

Rep: Reputation: 4254Reputation: 4254Reputation: 4254Reputation: 4254Reputation: 4254Reputation: 4254Reputation: 4254Reputation: 4254Reputation: 4254Reputation: 4254Reputation: 4254
Quote:
Originally Posted by ejinkas12 View Post
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"!
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How to solve fuse: device not found, try 'modprobe fuse' first quangvublog Linux - Server 3 06-24-2019 06:35 AM
[SOLVED] fuse: device not found, try 'modprobe fuse' first -Centos 5.4 jsaravana87 Linux - Server 2 08-02-2012 03:33 AM
fusermount: fuse device not found, try 'modprobe fuse' first maestromani Linux - Newbie 1 10-21-2010 12:53 PM
FUSE works but fuse group does not exist? violagirl23 Linux - Software 3 01-21-2008 04:01 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:31 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration