· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
FUSE Driver Example

FUSE(Filesystem in Userspace) driver에 대한 예제

  • 작성자
    조재혁(Mminzkn@minzkn.com)

  • 고친과정
    2010년 9월 16일 : 처음씀

  • 문서의 작성기준 개발환경
    GNU/Linux

설명

  • 이것은 리눅스환경에서의 FUSE(Filesystem in Userspace)에 대한 구체적인 예제를 작성해본것입니다. FUSE는 설명이 필요없을정도로 매우 간결하게 만들수 있어서 예제만으로 충분한 설명이 되는듯 합니다.
  • 이 예제소스의 최근 버젼은 "svn://svn.hwport.com/extra/mzfusetest" 으로 checkout 받으실수 있습니다.
  • 좀더 세밀한 예제는 ""svn://svn.hwport.com/extra/mzfilesystem" 으로 checkout 받으실수 있습니다.
  • 빌드후 다음과 같이 실행하시면 mount하실수 있습니다.
    ./mzfusetest <mount entry>
    
  • mount된 FUSE entry를 unmonut하시려면 다음과 같이 하시면 됩니다.
    fusermount -u <mount entry>
    

예제소스 main.c

/*
  Copyright (C) JAEHYUK CHO
  All rights reserved.
  Code by JaeHyuk Cho <mailto:minzkn@minzkn.com>
*/

#if !defined(FUSE_USE_VERSION)
# define FUSE_USE_VERSION 26
#endif

#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include <fuse.h>

#if !defined(mzfuse_virtual_filesystem_t)
typedef struct mzfuse_virtual_filesystem_ts {
    const char *m_pathname;
    const unsigned char *m_data;
}__mzfuse_virtual_filesystem_t;
# define mzfuse_virtual_filesystem_t __mzfuse_virtual_filesystem_t
#endif

int main(int s_argc, char **s_argv);

static int mzfuse_getattr(const char *s_pathname, struct stat *s_statbuffer);
static int mzfuse_open(const char *s_pathname, struct fuse_file_info *s_fileinfo);
static int mzfuse_read(const char *s_pathname, char *s_data, size_t s_size, off_t s_offset, struct fuse_file_info *s_fileinfo);
static int mzfuse_readdir(const char *s_pathname, void *s_buffer, fuse_fill_dir_t s_filler, off_t s_offset, struct fuse_file_info *s_fileinfo);

static mzfuse_virtual_filesystem_t g_mzfuse_virtual_filesystem[] = {
    {"/.", (const unsigned char *)0},
    {"/..", (const unsigned char *)0},
    {"/TEST FILE 00", (const unsigned char *)"VIRTUAL DATA 00"},
    {"/TEST FILE 01", (const unsigned char *)"VIRTUAL DATA 01"},
    {"/TEST FILE 02", (const unsigned char *)"VIRTUAL DATA 02"},
    {"/TEST FILE 03", (const unsigned char *)"VIRTUAL DATA 03"},
    {(const char *)0, (const unsigned char *)0}
};

static struct fuse_operations g_mzfuse_operations = {
    /* int (*getattr) (const char *, struct stat *); */
    .getattr = mzfuse_getattr,
    /* int (*readlink) (const char *, char *, size_t); */
    /* int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); */
    /* int (*mknod) (const char *, mode_t, dev_t); */
    /* int (*mkdir) (const char *, mode_t); */
    /* int (*unlink) (const char *); */
    /* int (*rmdir) (const char *); */
    /* int (*symlink) (const char *, const char *); */
    /* int (*rename) (const char *, const char *); */
    /* int (*link) (const char *, const char *); */
    /* int (*chmod) (const char *, mode_t); */
    /* int (*chown) (const char *, uid_t, gid_t); */
    /* int (*truncate) (const char *, off_t); */
    /* int (*utime) (const char *, struct utimbuf *); */
    /* int (*open) (const char *, struct fuse_file_info *); */
    .open = mzfuse_open,
    /* int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); */
    .read = mzfuse_read,
    /* int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); */
    /* int (*statfs) (const char *, struct statvfs *); */
    /* int (*flush) (const char *, struct fuse_file_info *); */
    /* int (*release) (const char *, struct fuse_file_info *); */
    /* int (*fsync) (const char *, int, struct fuse_file_info *); */
    /* int (*setxattr) (const char *, const char *, const char *, size_t, int); */
    /* int (*getxattr) (const char *, const char *, char *, size_t); */
    /* int (*listxattr) (const char *, char *, size_t); */
    /* int (*removexattr) (const char *, const char *); */
    /* int (*opendir) (const char *, struct fuse_file_info *); */
    /* int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); */
    .readdir = mzfuse_readdir,
    /* int (*releasedir) (const char *, struct fuse_file_info *); */
    /* int (*fsyncdir) (const char *, int, struct fuse_file_info *); */
    /* void *(*init) (struct fuse_conn_info *conn); */
    /* void (*destroy) (void *); */
    /* int (*access) (const char *, int); */
    /* int (*create) (const char *, mode_t, struct fuse_file_info *); */
    /* int (*ftruncate) (const char *, off_t, struct fuse_file_info *); */
    /* int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); */
    /* int (*lock) (const char *, struct fuse_file_info *, int cmd, struct flock *); */
    /* int (*utimens) (const char *, const struct timespec tv[2]); */
    /* int (*bmap) (const char *, size_t blocksize, uint64_t *idx); */
    /* unsigned int flag_nullpath_ok : 1; */
    /* unsigned int flag_reserved : 31; */
    /* int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); */
    /* int (*poll) (const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp); */
};

static int mzfuse_getattr(const char *s_pathname, struct stat *s_statbuffer)
{
    int s_index = 0;

    (void)memset((void *)s_statbuffer, 0, sizeof(struct stat));

    if(strcmp(s_pathname, "/") == 0) {
        s_statbuffer->st_mode = S_IFDIR | 0755;
        s_statbuffer->st_nlink = 2;

        return(0);
    }

    while(g_mzfuse_virtual_filesystem[s_index].m_pathname != ((const char *)0)) {
        if(strcmp(s_pathname, g_mzfuse_virtual_filesystem[s_index].m_pathname) == 0) {
            break;
        }
        ++s_index;
    }

    if(g_mzfuse_virtual_filesystem[s_index].m_pathname == ((const char *)0)) {
        return(-ENOENT);
    }

    s_statbuffer->st_mode = S_IFREG | 0444;
    s_statbuffer->st_nlink = 1;
    s_statbuffer->st_size = strlen("TEST DATA");

    return(0);
}

static int mzfuse_open(const char *s_pathname, struct fuse_file_info *s_fileinfo)
{
    int s_index = 0;

    while(g_mzfuse_virtual_filesystem[s_index].m_pathname != ((const char *)0)) {
        if(strcmp(s_pathname, g_mzfuse_virtual_filesystem[s_index].m_pathname) == 0) {
            break;
        }
        ++s_index;
    }

    if(g_mzfuse_virtual_filesystem[s_index].m_pathname == ((const char *)0)) {
        return(-ENOENT);
    }

    if((s_fileinfo->flags & O_RDONLY) != O_RDONLY) {
        return(-EACCES);
    }

    return(0);
}

static int mzfuse_read(const char *s_pathname, char *s_data, size_t s_size, off_t s_offset, struct fuse_file_info *s_fileinfo)
{
    off_t s_result;
    int s_index = 0;

    while(g_mzfuse_virtual_filesystem[s_index].m_pathname != ((const char *)0)) {
        if(strcmp(s_pathname, g_mzfuse_virtual_filesystem[s_index].m_pathname) == 0) {
            break;
        }
        ++s_index;
    }

    if(g_mzfuse_virtual_filesystem[s_index].m_pathname == ((const char *)0)) {
        return(-ENOENT);
    }

    s_result = strlen((const char *)g_mzfuse_virtual_filesystem[s_index].m_data);
    if(s_offset >= s_result) {
        return(0);
    }

    if(s_result < (s_offset + ((off_t)s_size))) {
        s_size = (size_t)(s_result - s_offset);
    }

    (void)memcpy((void *)s_data, (const void *)(&g_mzfuse_virtual_filesystem[s_index].m_data[s_offset]), s_size);

    return(s_result);
}

static int mzfuse_readdir(const char *s_pathname, void *s_buffer, fuse_fill_dir_t s_filler, off_t s_offset, struct fuse_file_info *s_fileinfo)
{
    int s_index = 0;

    if(strcmp(s_pathname, "/") != 0) {
        return(-ENOENT);
    }

    while(g_mzfuse_virtual_filesystem[s_index].m_pathname != ((const char *)0)) {
        /* typedef int (*fuse_fill_dir_t) (void *buf, const char *name, const struct stat *stbuf, off_t off); */
        s_filler(s_buffer, (const char *)(&g_mzfuse_virtual_filesystem[s_index].m_pathname[1]), (const struct stat *)0, (off_t)0);

        ++s_index;
    }

    return(0);
}

int main(int s_argc, char **s_argv)
{
    /* int fuse_main(int argc, char *argv[], const struct fuse_operations *op, void *user_data); */
    return(fuse_main(s_argc, s_argv, (const struct fuse_operations *)(&g_mzfuse_operations), (void *)0));
}

/* End of source */

makefile

# Copyright (C) JAEHYUK CHO
# All rights reserved.
# Code by JaeHyuk Cho <mailto:minzkn@minzkn.com>

CROSS_COMPILE                ?=#

CC                           := $(CROSS_COMPILE)gcc#
RM                           := rm -f#
STRIP                        := $(CROSS_COMPILE)strip#

THIS_NAME                    := mzfusetest#

CFLAGS                       := -Os -pipe#
CFLAGS                       += -Wall -Werror#
CFLAGS                       += -fomit-frame-pointer#
#CFLAGS                       += -ansi#
CFLAGS                       += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64#
CFLAGS                       += -I.#

LDFLAGS                      := -s -lfuse#

TARGET                       := $(THIS_NAME)#
#OBJECTS                      := $(THIS_NAME).o#
OBJECTS                      := main.o#

.PHONY: all clean

all: $(TARGET) ; $(STRIP) --remove-section=.comment --remove-section=.note $(TARGET)
clean: ; $(RM) *.o $(TARGET)

$(TARGET): $(OBJECTS) ; $(CC) $(LDFLAGS) -o $(@) $(^)
$(OBJECTS): makefile
%.o: %.c ; $(CC) $(CFLAGS) -c -o $(@) $(<)

# End of Makefile

ID
Password
Join
You are tricky, but never to the point of dishonesty.


sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2012-01-19 12:05:21
Processing time 0.0061 sec