Logo Search packages:      
Sourcecode: davfs2 version File versions  Download package

dav_fuse5.c

/* 
** Interface to the fuse kernel module FUSE_KERNEL_VERSION 5.
 */

/*
 *  This file is part of davfs2.
 *
 *  davfs2 is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  davfs2 is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with davfs2; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */


#include "config.h"

#include <argz.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>

#include "dav_debug.h"
#include "defaults.h"
#include "cache.h"
#include "kernel_interface.h"
#include "fuse5_kernel.h"


/* Private global variables */
/*==========================*/

/* Buffer used for communication with the kernel module (in and out). */
static size_t buf_size;
static char *buf;

/* fuse wants the nodeid of the root node to be 1, so we have to translate
   between the real nodeid and what fuse wants. */
static uint64_t root;


/* Private function prototypes */
/*=============================*/

/* Functions to handle upcalls fromthe kernel module. */

static uint32_t fuse_getattr(void);

static uint32_t fuse_init(void);

static uint32_t fuse_lookup(void);

static uint32_t fuse_mkdir(void);

static uint32_t fuse_mknod(void);

static uint32_t fuse_open(void);

static uint32_t fuse_read(void);

static uint32_t fuse_release(void);

static uint32_t fuse_rename(void);

static uint32_t fuse_setattr(void);

static uint32_t fuse_stat(void);

static uint32_t fuse_write(void);

/* Auxiliary functions. */

static off_t write_dir_entry(int fd, off_t off, const dav_node *node,
                             const char *name);

static void set_attr(struct fuse_attr *attr, const dav_node *node);


/* Public functions */
/*==================*/

void dav_fuse5_loop(int device, size_t bufsize, time_t idle_time,
                    dav_is_mounted_fn is_mounted,
                    volatile int *keep_on_running) {

    buf_size = bufsize;
    buf = malloc(buf_size);
    if (buf == NULL) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
               "Could not allocate message buffer.");
        return;
    }

    dav_register_kernel_interface(&write_dir_entry, NULL, NULL);

    struct timeval tv;
    tv.tv_sec = idle_time;
    tv.tv_usec = 0;
    time_t last_tidy_cache = time(NULL);
    int delay_tidy = 0;

    while (*keep_on_running) {

        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(device, &fds);
        int ret = select(device + 1, &fds, NULL, NULL, &tv);

        if (ret > 0) {
            ssize_t bytes_read = read(device, buf, buf_size);
            if (bytes_read <= 0) {
                if (bytes_read == 0 || errno == EINTR || errno == ENOENT) {
                    if (time(NULL) < (last_tidy_cache + idle_time)) {
                        tv.tv_sec = last_tidy_cache + idle_time - time(NULL);
                    } else {
                        tv.tv_sec = 0;
                    }
                    continue;
                }
                break;
            }
        } else if (ret == 0) {
            if (!is_mounted())
                break;
            if (dav_tidy_cache() == 0) {
                tv.tv_sec = idle_time;
                last_tidy_cache = time(NULL);
            } else {
                tv.tv_sec = 0;
            }
            continue;
        } else {
            break;
        }

        struct fuse_in_header *ih = (struct fuse_in_header *) buf;
        struct fuse_out_header *oh = (struct fuse_out_header *) buf;
        if (ih->nodeid == 1)
              ih->nodeid = root;

        switch (ih->opcode) {
        case FUSE_LOOKUP:
            DBG0("FUSE_LOOKUP:");
            oh->len = fuse_lookup();
            break;
        case FUSE_FORGET:
            DBG0("FUSE_FORGET: no reply");
            oh->len = 0;
            break;
        case FUSE_GETATTR:
            DBG0("FUSE_GETATTR:");
            oh->len = fuse_getattr();
            break;
        case FUSE_SETATTR:
            DBG0("FUSE_SETATTR:");
            oh->len = fuse_setattr();
            break;
        case FUSE_READLINK:
            DBG0("FUSE_READLINK: not supported");
            oh->error = -ENOTSUP;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_SYMLINK:
            DBG0("FUSE_SYMLINK: not supported");
            oh->error = -ENOTSUP;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_MKNOD:
            DBG0("FUSE_MKNOD:");
            oh->len = fuse_mknod();
            break;
        case FUSE_MKDIR:
            DBG0("FUSE_MKDIR:");
            oh->len = fuse_mkdir();
            break;
        case FUSE_UNLINK:
            DBG0("FUSE_UNLINK:");
            DBG2("  p 0x%llx, %s", ih->nodeid,
                 (char *) (buf + sizeof(struct fuse_in_header)));
            oh->error = dav_remove((dav_node *) ((size_t) ih->nodeid),
                             (char *) (buf + sizeof(struct fuse_in_header)),
                             ih->uid);
            DBG_RET(oh->error);
            if (oh->error != 0)
                oh->error *= -1;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_RMDIR:
            DBG0("FUSE_RMDIR:");
            DBG2("  p 0x%llx, %s", ih->nodeid,
                 (char *) (buf + sizeof(struct fuse_in_header)));
            oh->error = dav_rmdir((dav_node *) ((size_t) ih->nodeid),
                            (char *) (buf + sizeof(struct fuse_in_header)),
                            ih->uid);
            DBG_RET(oh->error);
            if (oh->error != 0)
                oh->error *= -1;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_RENAME:
            DBG0("FUSE_RENAME:");
            oh->len = fuse_rename();
            break;
        case FUSE_LINK:
            DBG0("FUSE_LINK: not supported");
            oh->error = -ENOTSUP;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_OPEN:
            DBG0("FUSE_OPEN:");
            oh->len = fuse_open();
            break;
        case FUSE_READ:
            DBG0("FUSE_READ:");
            oh->len = fuse_read();
            break;
        case FUSE_WRITE:
            DBG0("FUSE_WRITE:");
            oh->len = fuse_write();
            break;
        case FUSE_STATFS:
            DBG0("FUSE_STATFS:");
            oh->len = fuse_stat();
            break;
        case FUSE_RELEASE:
            DBG0("FUSE_RELEASE:");
            oh->len = fuse_release();
            delay_tidy = 1;
            break;
        case FUSE_FSYNC:
            DBG0("FUSE_FSYNC:");
            DBG1("  n 0x%llx", ih->nodeid);
            oh->error = dav_sync((dav_node *) ((size_t) ih->nodeid));
            DBG_RET(oh->error);
            if (oh->error != 0)
                oh->error *= -1;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_SETXATTR:
            DBG0("FUSE_SETXATTR: not supported");
            oh->error = -ENOTSUP;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_GETXATTR:
            DBG0("FUSE_GETXATTR: not supported");
            oh->error = -ENOTSUP;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_LISTXATTR:
            DBG0("FUSE_LISTXATTR: not supported");
            oh->error = -ENOTSUP;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_REMOVEXATTR:
            DBG0("FUSE_REMOVEXATTR: not supported");
            oh->error = -ENOTSUP;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_FLUSH:
            DBG0("FUSE_FLUSH: ignored");
            oh->error = 0;
            oh->len = sizeof(struct fuse_out_header);
            break;
        case FUSE_INIT:
            DBG0("FUSE_INIT:");
            oh->len = fuse_init();
            break;
        case FUSE_OPENDIR:
            DBG0("FUSE_OPENDIR:");
            oh->len = fuse_open();
            break;
        case FUSE_READDIR:
            DBG0("FUSE_READDIR:");
            oh->len = fuse_read();
            break;
        case FUSE_RELEASEDIR:
            DBG0("FUSE_RELEASEDIR:");
            oh->len = fuse_release();
            break;
        default:
            DBG1("UNKNOWN FUSE CALL %i", ih->opcode);
            oh->error = -ENOTSUP;
            oh->len = sizeof(struct fuse_out_header);
            break;
        }

        ssize_t n = 0;
        ssize_t w = 0;
        while (n < oh->len && w >= 0) {
            w = write(device, buf + n, oh->len - n);
            n += w;
        }

        if (time(NULL) < (last_tidy_cache + idle_time)) {
            tv.tv_sec = last_tidy_cache + idle_time - time(NULL);
        } else if (delay_tidy) {
            tv.tv_sec = 1;
            last_tidy_cache = time(NULL) - idle_time + 2;
            delay_tidy = 0;
        } else if (dav_tidy_cache() == 0) {
            tv.tv_sec = idle_time;
            last_tidy_cache = time(NULL);
        } else {
            tv.tv_sec = 0;
        }

    }
}


/* Private functions */
/*===================*/

/* Functions to handle upcalls fromthe kernel module.
   The cache module only uses data types from the C-library. For file access,
   mode and the like it only uses symbolic constants defined in the C-library.
   So the main porpose of this functions is to translate from kernel specific
   types and constants to types and constants from the C-library, and back.
   All of this functions return the amount of data in buf that is to be
   send to the kernel module. */

static uint32_t fuse_getattr(void) {

    struct fuse_in_header *ih = (struct fuse_in_header *) buf;
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_attr_out *out = (struct fuse_attr_out *)
                                (buf + sizeof(struct fuse_out_header));
    DBG1("  n 0x%llx", ih->nodeid);

    oh->error = dav_getattr((dav_node *) ((size_t) ih->nodeid), ih->uid);

    DBG_RET(oh->error);
    if (oh->error != 0) {
        oh->error *= -1;
        return sizeof(struct fuse_out_header);
    }

    set_attr(&out->attr, (dav_node *) ((size_t) ih->nodeid));
    out->attr_valid = 1;
    out->attr_valid_nsec = 0;
    out->dummy = 0;

    return sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out);
}


static uint32_t fuse_init(void) {

    struct fuse_in_header *ih = (struct fuse_in_header *) buf;
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_init_in_out *out = (struct fuse_init_in_out *)
                                   (buf + sizeof(struct fuse_out_header));

    dav_node *node;
    oh->error = dav_root(&node, ih->uid);

    DBG_RET(oh->error);
    if (oh->error != 0 || node == NULL) {
        if (oh->error == 0)
            oh->error = EIO;
        oh->error *= -1;
        return sizeof(struct fuse_out_header);
    }

    root = (size_t) node;
    out->major = FUSE_KERNEL_VERSION;
    out->minor = FUSE_KERNEL_MINOR_VERSION;

    return sizeof(struct fuse_out_header) + sizeof(struct fuse_init_in_out);
}


static uint32_t fuse_lookup(void) {

    struct fuse_in_header *ih = (struct fuse_in_header *) buf;
    char * name = (char *) (buf + sizeof(struct fuse_in_header));
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_entry_out *out = (struct fuse_entry_out *)
                                 (buf + sizeof(struct fuse_out_header));
    DBG2("  p 0x%llx, %s", ih->nodeid, name);

    dav_node *node = NULL;
    oh->error = dav_lookup(&node, (dav_node *) ((size_t) ih->nodeid), name,
                           ih->uid);

    if (oh->error != 0 || node == NULL) {
        if (oh->error == 0)
            oh->error = EIO;
        DBG_RET(oh->error);
        oh->error *= -1;
        return sizeof(struct fuse_out_header);
    }

    out->nodeid = (size_t) node;
    out->generation = out->nodeid;
    out->entry_valid = 1;
    out->attr_valid = 1;
    out->entry_valid_nsec = 0;
    out->attr_valid_nsec = 0;
    set_attr(&out->attr, node);

    DBG_RET(oh->error);
    return sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out);
}


static uint32_t fuse_mkdir(void) {

    struct fuse_in_header *ih = (struct fuse_in_header *) buf;
    struct fuse_mkdir_in *in = (struct fuse_mkdir_in *)
                               (buf + sizeof(struct fuse_in_header));
    char *name = (char *) (buf + sizeof(struct fuse_in_header)
                           + sizeof(struct fuse_mkdir_in));
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_entry_out *out = (struct fuse_entry_out *)
                                 (buf + sizeof(struct fuse_out_header));
    DBG2("  p 0x%llx, %s", ih->nodeid, name);

    dav_node *node = NULL;
    oh->error = dav_mkdir(&node, (dav_node *) ((size_t) ih->nodeid), name,
                          ih->uid, in->mode & DAV_A_MASK);

    if (oh->error != 0 || node == NULL) {
        if (oh->error == 0)
            oh->error = EIO;
        DBG_RET(oh->error);
        oh->error *= -1;
        return sizeof(struct fuse_out_header);
    }

    out->nodeid = (size_t) node;
    out->generation = out->nodeid;
    out->entry_valid = 1;
    out->attr_valid = 1;
    out->entry_valid_nsec = 0;
    out->attr_valid_nsec = 0;
    set_attr(&out->attr, node);

    DBG_RET(oh->error);
    return sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out);
}


static uint32_t fuse_mknod(void) {

    struct fuse_in_header *ih = (struct fuse_in_header *) buf;
    struct fuse_mknod_in *in = (struct fuse_mknod_in *)
                               (buf + sizeof(struct fuse_in_header));
    char *name = (char *) (buf + sizeof(struct fuse_in_header)
                           + sizeof(struct fuse_mknod_in));
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_entry_out *out = (struct fuse_entry_out *)
                                 (buf + sizeof(struct fuse_out_header));
    DBG2("  p 0x%llx, m 0%o", ih->nodeid, in->mode);
    DBG1("  %s", name);

    if (!S_ISREG(in->mode)) {
        DBG_RET(ENOTSUP);
        oh->error = -ENOTSUP;
        return sizeof(struct fuse_out_header);
    }

    dav_node *node = NULL;
    oh->error = dav_create(&node, (dav_node *) ((size_t) ih->nodeid), name,
                           ih->uid, in->mode & DAV_A_MASK);

    if (oh->error != 0 || node == NULL) {
        if (oh->error == 0)
            oh->error = EIO;
        DBG_RET(oh->error);
        oh->error *= -1;
        return sizeof(struct fuse_out_header);
    }

    out->nodeid = (size_t) node;
    out->generation = out->nodeid;
    out->entry_valid = 1;
    out->attr_valid = 1;
    out->entry_valid_nsec = 0;
    out->attr_valid_nsec = 0;
    set_attr(&out->attr, node);

    DBG_RET(oh->error);
    return sizeof(struct fuse_out_header) + sizeof(struct fuse_entry_out);
}


static uint32_t fuse_open(void) {

    struct fuse_in_header *ih= (struct fuse_in_header *) buf;
    struct fuse_open_in *in = (struct fuse_open_in *)
                              (buf + sizeof(struct fuse_in_header));
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_open_out *out = (struct fuse_open_out *)
                                (buf + sizeof(struct fuse_out_header));
    DBG2("  n 0x%llx, f 0%o", ih->nodeid, in->flags);
    DBG1("  pid %i", ih->pid);

    int fd = 0;
    oh->error = dav_open(&fd, (dav_node *) ((size_t) ih->nodeid),
                         in->flags, ih->pid, 0, ih->uid);

    if (oh->error != 0 || fd == 0) {
        if (oh->error == 0)
            oh->error = EIO;
        DBG_RET(oh->error);
        oh->error *= -1;
        return sizeof(struct fuse_out_header);
    }

    out->open_flags = in->flags & (O_ACCMODE | O_APPEND);
    out->fh = fd;

    DBG1("  fd %i", fd);
    DBG_RET(oh->error);
    return sizeof(struct fuse_out_header) + sizeof(struct fuse_open_out);
}


static uint32_t fuse_read(void) {

    struct fuse_in_header *ih= (struct fuse_in_header *) buf;
    struct fuse_read_in *in = (struct fuse_read_in *)
                              (buf + sizeof(struct fuse_in_header));
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    DBG2("  n 0x%llx, fd %llu", ih->nodeid, in->fh);
    DBG1("  pid %i", ih->pid);
    DBG2("  size %u, off %llu", in->size, in->offset);

    if (in->size > (buf_size - sizeof(struct fuse_out_header))) {
        DBG_RET(EINVAL);
        oh->error = -EINVAL;
        return sizeof(struct fuse_out_header);
    }

    ssize_t len;
    oh->error = dav_read(&len, (dav_node *) ((size_t) ih->nodeid),
                         in->fh, buf + sizeof(struct fuse_out_header),
                         in->size, in->offset);

    DBG_RET(oh->error);
    if (oh->error != 0)
        oh->error *= -1;

    return len + sizeof(struct fuse_out_header);
}


static uint32_t fuse_release(void) {

    struct fuse_in_header *ih = (struct fuse_in_header *) buf;
    struct fuse_release_in *in = (struct fuse_release_in *)
                                 (buf + sizeof(struct fuse_in_header));
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    DBG2("  n 0x%llx, f 0%o", ih->nodeid, in->flags);
    DBG2("  pid %i, fd %llu", ih->pid, in->fh);

    oh->error = dav_close((dav_node *) ((size_t) ih->nodeid), in->fh,
                          in->flags, ih->pid, 0);

    DBG_RET(oh->error);
    if (oh->error != 0)
        oh->error *= -1;

    return sizeof(struct fuse_out_header);
}


static uint32_t fuse_rename(void) {

    struct fuse_in_header *ih = (struct fuse_in_header *) buf;
    struct fuse_rename_in *in = (struct fuse_rename_in *)
                                (buf + sizeof(struct fuse_in_header));
    char *old = (char *) (buf + sizeof(struct fuse_in_header)
                          + sizeof(struct fuse_rename_in));
    char *new = old + strlen(old) + 1;
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    DBG2("  sp 0x%llx, %s", ih->nodeid, old);
    DBG2("  dp 0x%llx, %s", in->newdir, new);

    if (in->newdir == 1)
        in->newdir = root;
    oh->error = dav_rename((dav_node *) ((size_t) ih->nodeid), old,
                           (dav_node *) ((size_t) in->newdir), new, ih->uid);

    DBG_RET(oh->error);
    if (oh->error != 0)
        oh->error *= -1;

    return sizeof(struct fuse_out_header);
}


static uint32_t fuse_setattr(void) {

    struct fuse_in_header *ih = (struct fuse_in_header *) buf;
    struct fuse_setattr_in *in = (struct fuse_setattr_in *)
                                 (buf + sizeof(struct fuse_in_header));
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_attr_out *out = (struct fuse_attr_out *)
                                (buf + sizeof(struct fuse_out_header));
    DBG2("  n 0x%llx, m 0%o", ih->nodeid, in->attr.mode);
    DBG2("  uid %i, gid %i", in->attr.uid, in->attr.gid);
    DBG2("  sz %llu, at %llu,", in->attr.size, in->attr.atime);
    DBG2("  mt %llu, ct %llu", in->attr.mtime, in->attr.ctime);

    oh->error = dav_setattr((dav_node *) ((size_t) ih->nodeid), ih->uid,
                            in->valid & FATTR_MODE, in->attr.mode,
                            in->valid & FATTR_UID, in->attr.uid,
                            in->valid & FATTR_GID, in->attr.gid,
                            in->valid & FATTR_ATIME, in->attr.atime,
                            in->valid & FATTR_MTIME, in->attr.mtime,
                            in->valid & FATTR_CTIME, in->attr.ctime,
                            in->valid & FATTR_SIZE, in->attr.size);

    DBG_RET(oh->error);
    if (oh->error != 0) {
        oh->error *= -1;
        return sizeof(struct fuse_out_header);
    }

    set_attr(&out->attr, (dav_node *) ((size_t) ih->nodeid));
    out->attr_valid = 1;
    out->attr_valid_nsec = 0;
    out->dummy = 0;

    return sizeof(struct fuse_out_header) + sizeof(struct fuse_attr_out);
}


static uint32_t fuse_stat(void) {

    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_statfs_out *out = (struct fuse_statfs_out *)
                                  (buf + sizeof(struct fuse_out_header));

    dav_stat st = dav_statfs();

    out->st.blocks = st.blocks;
    out->st.bfree = st.bfree;
    out->st.bavail = st.bavail;
    out->st.files = st.files;
    out->st.ffree = st.ffree;
    if (st.bsize > buf_size) {
        out->st.bsize = (buf_size - 4096) & ~1023;
    } else {
        out->st.bsize = st.bsize;
    }
    out->st.namelen = st.namelen;

    oh->error = 0;
    DBG_RET(oh->error);
    return sizeof(struct fuse_out_header) + sizeof(struct fuse_statfs_out);
}


static uint32_t fuse_write(void) {

    struct fuse_in_header *ih= (struct fuse_in_header *) buf;
    struct fuse_write_in *in = (struct fuse_write_in *)
                               (buf + sizeof(struct fuse_in_header));
    struct fuse_out_header *oh = (struct fuse_out_header *) buf;
    struct fuse_write_out *out = (struct fuse_write_out *)
                                 (buf + sizeof(struct fuse_out_header));
    DBG2("  n 0x%llx, fd %llu", ih->nodeid, in->fh);
    DBG2("  pid %i, flags 0%o", ih->pid, in->write_flags);
    DBG2("  size %u, off %llu", in->size, in->offset);

    if (in->size > (buf_size - sizeof(struct fuse_in_header)
                    - sizeof(struct fuse_write_in))) {
        DBG_RET(EINVAL);
        oh->error = -EINVAL;
        return sizeof(struct fuse_out_header);
    }

    size_t size;
    oh->error = dav_write(&size, (dav_node *) ((size_t) ih->nodeid),
                          in->fh, buf + sizeof(struct fuse_in_header)
                          + sizeof(struct fuse_write_in),
                          in->size, in->offset);

    DBG_RET(oh->error);
    if (oh->error != 0) {
        oh->error *= -1;
        return sizeof(struct fuse_out_header);
    }

    out->size = size;

    return sizeof(struct fuse_out_header) + sizeof(struct fuse_write_out);
}


/* Auxiliary functions. */

/* Writes a struct fuse_dirent to file with file descriptor fd.
   fd     : An open file descriptor to write to.
   off    : The current file size.
   name   : File name; if NULL, the last, empty entry is written.
   return value : New size of the file. -1 in case of an error. */
static off_t write_dir_entry(int fd, off_t off, const dav_node *node,
                             const char *name) {

    if (name == NULL)
        return off;

    struct fuse_dirent entry;
    size_t head = offsetof(struct fuse_dirent, name);
    size_t reclen = (head + strlen(name) + sizeof(uint64_t) -1)
                    & ~(sizeof(uint64_t) - 1);

    entry.ino = (((size_t) node) == root) ? 1 : (size_t) node;
    entry.namelen = strlen(name);
    entry.type = (node->mode & S_IFMT) >> 12;

    size_t size = 0;
    ssize_t ret = 0;
    while (ret >= 0 && size < head) {
        ret = write(fd, (char *) &entry + size, head - size);
        size += ret;
    }
    if (size != head)
        return -1;

    ret = 0;
    while (ret >= 0 && size < (head + entry.namelen)) {
        ret = write(fd, name + size - head, entry.namelen - size + head);
        size += ret;
    }
    if (size != (head + entry.namelen))
        return -1;

    ret = 0;
    while (ret >= 0 && size < reclen) {
        ret = write(fd, "\0", 1);
        size += ret;
    }
    if (size != reclen)
        return -1;

    return off + reclen;
}


/* Translates attribute from node to attr. */
static void set_attr(struct fuse_attr *attr, const dav_node *node) {

    attr->ino = (((size_t) node) == root) ? 1 : (size_t) node;
    attr->size = node->size;
    attr->blocks = (node->size + 511) / 512;
    attr->atime = node->atime;
    attr->mtime = node->mtime;
    attr->ctime = node->ctime;
    attr->atimensec = 0;
    attr->mtimensec = 0;
    attr->ctimensec = 0;
    attr->mode = node->mode;
    if (S_ISDIR(node->mode)) {
        attr->nlink = node->nref;
    } else {
        attr->nlink = 1;
    }
    attr->uid = node->uid;
    attr->gid = node->gid;
    attr->rdev = 0;
}

Generated by  Doxygen 1.6.0   Back to index