· 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



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.0091 sec