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

dav_coda2.c

/* 
** Interface to the coda kernel module CODA_KERNEL_VERSION 2.
 */

/*
 *  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 <limits.h>
#include <signal.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>

#ifdef ENABLE_NLS
#   include <libintl.h>
#   define _(String) gettext(String)
#else
#   define _(String) String
#endif

#include "defaults.h"
#include "cache.h"
#include "kernel_interface.h"
#include "coda2.h"


#if SIZEOF_VOID_P == 8


void dav_coda2_loop(int device, size_t bufsize, time_t idle_time,
                    dav_is_mounted_fn is_mounted,
                    volatile int *keep_on_running, int dbg) {
    kill(getppid(), SIGHUP);
    return;
}


#else   /* SIZEOF_VOID_P != 8, should be 4 */


/* Constants */
/*===========*/

/* Size of buffer for communication with kernel module. */
#define BUF_SIZE   2048

/* This constants are used by davfs2 to fill fields of struct CodaFid that
   are not used by davfs2, but are expected by coda. */   
#define DAV_VOL   0x01234567
#define DAV_VNODE 0xffffffff


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

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

/* The preferred blocksize used by the local filesystem for cache files.
   Used by set_attr(). */
static unsigned int blocksize;

/* Alignment boundary of dav_node in byte.
   Used to compute file numbers from node pointers. */
static size_t alignment;

/* Send debug messages to syslog if != 0. */
int debug;


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

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

static uint32_t coda_access(void);

static uint32_t coda_close(void);

static uint32_t coda_create(void);

static uint32_t coda_getattr(void);

static uint32_t coda_lookup(void);

static uint32_t coda_mkdir(void);

static uint32_t coda_open_by_fd(void);

static uint32_t coda_root(void);

static uint32_t coda_setattr(void);

static uint32_t coda_statfs(void);

/* Functions that will do a downcall to the kernel module. */

static void coda_flush(int device);

/* 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 coda_vattr *attr, const dav_node *node);


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

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

    debug = dbg;
    if (debug)
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "coda kernel version 2");

    buf = malloc(BUF_SIZE);
    if (buf == NULL) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
               _("can't allocate message buffer"));
        return;
    }
    static int flush = 0;
    alignment = dav_register_kernel_interface(&write_dir_entry, &flush,
                                              &blocksize);

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

    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 == EAGAIN) {
                    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 coda_in_hdr *ih = (struct coda_in_hdr *) buf;
        struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
        uint32_t len;
        switch (ih->opcode) {
        case CODA_ROOT:
            len = coda_root();
            break;
        case CODA_OPEN_BY_FD:
            len = coda_open_by_fd();
            break;
        case CODA_OPEN:
            if (debug)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_OPEN:");
            oh->result = ENOTSUP;
            len = sizeof(struct coda_out_hdr);
            break;
        case CODA_CLOSE:
            len = coda_close();
            last_tidy_cache = 0;
            break;
        case CODA_IOCTL:
            if (debug)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_IOCTL:");
            oh->result = ENOTSUP;
            len = sizeof(struct coda_out_hdr);
            break;
        case CODA_GETATTR:
            len = coda_getattr();
            break;
        case CODA_SETATTR:
            len = coda_setattr();
            break;
        case CODA_ACCESS:
            len = coda_access();
            break;
        case CODA_LOOKUP:
            len = coda_lookup();
            break;
        case CODA_CREATE:
            len = coda_create();
            break;
        case CODA_REMOVE: {
            struct coda_remove_in *in = (struct coda_remove_in *) buf;
            if (debug) {
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_REMOVE:");
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  p 0x%x, %s",
                       in->VFid.opaque[2], buf + in->name);
            }
            oh->result = dav_remove((dav_node *) in->VFid.opaque[2],
                                    buf + in->name, ih->cred.cr_euid);
            len = sizeof(struct coda_out_hdr);
            break; }
        case CODA_LINK:
            if (debug)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_LINK:");
            oh->result = ENOTSUP;
            len = sizeof(struct coda_out_hdr);
            break;
        case CODA_RENAME: {
            struct coda_rename_in *in = (struct coda_rename_in *) buf;
            if (debug) {
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_RENAME:");
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  sp 0x%x, %s",
                       in->sourceFid.opaque[2], buf + in->srcname);
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  dp 0x%x, %s",
                       in->destFid.opaque[2], buf + in->destname);
            }
            oh->result = dav_rename((dav_node *) in->sourceFid.opaque[2],
                                    buf + in->srcname,
                                    (dav_node *) in->destFid.opaque[2],
                                    buf + in->destname, ih->cred.cr_euid);
            len = sizeof(struct coda_out_hdr);
            break; }
        case CODA_MKDIR:
            len = coda_mkdir();
            break;
        case CODA_RMDIR: {
            struct coda_rmdir_in *in = (struct coda_rmdir_in *) buf;
            if (debug) {
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_RMDIR:");
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  p 0x%x, %s",
                       in->VFid.opaque[2], buf + in->name);
            }
            oh->result = dav_rmdir((dav_node *) in->VFid.opaque[2],
                                   buf + in->name, ih->cred.cr_euid);
            len = sizeof(struct coda_out_hdr);
            break; }
        case CODA_SYMLINK:
            if (debug)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_SYMLINK:");
            oh->result = ENOTSUP;
            len = sizeof(struct coda_out_hdr);
            break;
        case CODA_READLINK:
            if (debug)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_READLINK:");
            oh->result = ENOTSUP;
            len = sizeof(struct coda_out_hdr);
            break;
        case CODA_FSYNC: {
            struct coda_fsync_in *in = (struct coda_fsync_in *) buf;
            if (debug) {
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_FSYNC:");
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  n 0x%x",
                       in->VFid.opaque[2]);
            }
            oh->result = dav_sync((dav_node *) in->VFid.opaque[2]);
            len = sizeof(struct coda_out_hdr);
            break; }
        case CODA_VGET:
            if (debug)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_VGET:");
            oh->result = ENOTSUP;
            len = sizeof(struct coda_out_hdr);
            break;
        case CODA_OPEN_BY_PATH:
            if (debug)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
                       "CODA_OPEN_BY_PATH:");
            oh->result = ENOTSUP;
            len = sizeof(struct coda_out_hdr);
            break;
        case CODA_STATFS:
            len = coda_statfs();
            break;
        case CODA_STORE: {
            struct coda_store_in *in = (struct coda_store_in *) buf;
            if (debug) {
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_STORE:");
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  n 0x%x, f 0x%x",
                       in->VFid.opaque[2], in->flags);
            }
            oh->result = dav_sync((dav_node *) in->VFid.opaque[2]);
            len = sizeof(struct coda_out_hdr);
            break; }
        case CODA_RELEASE:
            len = coda_close();
            last_tidy_cache = 0;
            break;
        default:
            if (debug)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG),
                       "UNKNOWN CODA CALL %u", ih->opcode);
            oh->result = ENOTSUP;
            len = sizeof(struct coda_out_hdr);
            break;
        }

        if (debug)
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "RET: %s",
                   strerror(oh->result));

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

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

        if (flush) {
            coda_flush(device);
            flush = 0;
        }
    }
}


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

/* Functions to handle upcalls from the 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 coda_access(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_access_in *in = (struct coda_access_in *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    if (debug) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_ACCESS:");
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  n 0x%x, f %x",
               in->VFid.opaque[2], in->flags);
    }

    int how = (in->flags & C_A_R_OK) ? R_OK : 0;
    how |= (in->flags & C_A_W_OK) ? W_OK : 0;
    how |= (in->flags & C_A_X_OK) ? X_OK : 0;
    how |= (in->flags & C_A_F_OK) ? F_OK : 0;
    
    oh->result = dav_access((dav_node *) in->VFid.opaque[2], ih->cred.cr_euid,
                            how);

    return sizeof(struct coda_out_hdr);
}


static uint32_t coda_close(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_close_in *in = (struct coda_close_in *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    if (debug) {
        if (ih->opcode == CODA_CLOSE) {
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_CLOSE:");
        } else {
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_RELEASE:");
        }
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  n 0x%x, f %x",
               in->VFid.opaque[2], in->flags);
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  pid %i, pgid %i",
               ih->pid, ih->pgid);
    }

    int flags = 0;
    if ((in->flags & C_O_READ) && (in->flags & C_O_WRITE)) {
        flags = O_RDWR;
    } else if (in->flags & C_O_READ) {
        flags = O_RDONLY;
    } else if (in->flags & C_O_WRITE) {
        flags = O_WRONLY;
    }

    oh->result = dav_close((dav_node *) in->VFid.opaque[2], 0, flags, ih->pid,
                           ih->pgid);

    return sizeof(struct coda_out_hdr);
}


static uint32_t coda_create(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_create_in *in = (struct coda_create_in *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    struct coda_create_out *out = (struct coda_create_out *) buf;
    if (debug) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_CREATE:");
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  p 0x%x, m %o",
               in->VFid.opaque[2], in->mode);
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  %s", buf + in->name);
    }

    dav_node *node = NULL;
    oh->result = dav_create(&node, (dav_node *) in->VFid.opaque[2],
                            buf + in->name, ih->cred.cr_euid,
                            in->mode & DAV_A_MASK);

    if (oh->result != 0 || node == NULL) {
        if (oh->result == 0)
            oh->result = EIO;
        return sizeof(struct coda_out_hdr);
    }

    out->VFid.opaque[0] = DAV_VOL;
    out->VFid.opaque[1] = DAV_VNODE;
    out->VFid.opaque[2] = (size_t) node;
    set_attr(&out->attr, node);

    return sizeof(struct coda_create_out);
}


static uint32_t coda_getattr(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_getattr_in *in = (struct coda_getattr_in *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    struct coda_getattr_out *out = (struct coda_getattr_out *) buf;
    if (debug) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_GETATTR:");
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  n 0x%x",
               in->VFid.opaque[2]);
    }

    oh->result = dav_getattr((dav_node *) in->VFid.opaque[2],
                             ih->cred.cr_euid);

    if (oh->result != 0)
        return sizeof(struct coda_out_hdr);

    set_attr(&out->attr, (dav_node *) in->VFid.opaque[2]);

    return sizeof(struct coda_getattr_out);
}


static uint32_t coda_lookup(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_lookup_in *in = (struct coda_lookup_in *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    struct coda_lookup_out *out = (struct coda_lookup_out *) buf;
    if (debug) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_LOOKUP:");
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  p 0x%x, %s",
               in->VFid.opaque[2], buf + in->name);
    }

    dav_node *node = NULL;
    oh->result = dav_lookup(&node, (dav_node *) in->VFid.opaque[2],
                            buf + in->name, ih->cred.cr_euid);

    if (oh->result != 0 || node == NULL) {
        if (oh->result == 0)
            oh->result = EIO;
        return sizeof(struct coda_out_hdr);
    }

    out->VFid.opaque[0] = DAV_VOL;
    out->VFid.opaque[1] = DAV_VNODE;
    out->VFid.opaque[2] = (size_t) node;
    out->vtype = (node->mode & S_IFDIR) ? CDT_DIR : CDT_REG;

    return sizeof(struct coda_lookup_out);
}


static uint32_t coda_mkdir(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_mkdir_in *in = (struct coda_mkdir_in *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    struct coda_mkdir_out *out = (struct coda_mkdir_out *) buf;
    if (debug) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_MKDIR:");
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  p 0x%x, %s",
               in->VFid.opaque[2], buf + in->name);
    }

    dav_node *node = NULL;
    oh->result = dav_mkdir(&node, (dav_node *) in->VFid.opaque[2],
                           buf + in->name, ih->cred.cr_euid,
                           in->attr.va_mode & DAV_A_MASK);

    if (oh->result != 0 || node == NULL) {
        if (oh->result == 0)
            oh->result = EIO;
        return sizeof(struct coda_out_hdr);
    }

    out->VFid.opaque[0] = DAV_VOL;
    out->VFid.opaque[1] = DAV_VNODE;
    out->VFid.opaque[2] = (size_t) node;
    set_attr(&out->attr, node);

    return sizeof(struct coda_mkdir_out);
}


static uint32_t coda_open_by_fd(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_open_by_fd_in *in = (struct coda_open_by_fd_in *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    struct coda_open_by_fd_out *out = (struct coda_open_by_fd_out *) buf;
    if (debug) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_OPEN_BY_FD:");
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  n 0x%x, f %x",
               in->VFid.opaque[2], in->flags);
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  pid %i, pgid %i",
               ih->pid, ih->pgid);
    }

    int flags = 0;
    if ((in->flags & C_O_READ) && (in->flags & C_O_WRITE)) {
        flags = O_RDWR;
    } else if (in->flags & C_O_READ) {
        flags = O_RDONLY;
    } else if (in->flags & C_O_WRITE) {
        flags = O_WRONLY;
    }
    flags |= (in->flags & C_O_TRUNC) ? O_TRUNC : 0;

    oh->result = dav_open(&out->fd, (dav_node *) in->VFid.opaque[2],
                          flags, ih->pid, ih->pgid, ih->cred.cr_euid);

    if (oh->result != 0 || out->fd == 0) {
        if (oh->result == 0)
            oh->result = EIO;
        return sizeof(struct coda_out_hdr);
    }

    return sizeof(struct coda_open_by_fd_out);
}


static uint32_t coda_root(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    struct coda_root_out *out = (struct coda_root_out *) buf;
    if (debug)
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_ROOT:");

    dav_node *node = NULL;
    oh->result = dav_root(&node, ih->cred.cr_euid);

    if (oh->result != 0 || node == NULL) {
        if (oh->result == 0)
            oh->result = EIO;
        return sizeof(struct coda_out_hdr);
    }

    out->VFid.opaque[0] = DAV_VOL;
    out->VFid.opaque[1] = DAV_VNODE;
    out->VFid.opaque[2] = (size_t) node;

    return sizeof(struct coda_root_out);
}


static uint32_t coda_setattr(void) {

    struct coda_in_hdr *ih = (struct coda_in_hdr *) buf;
    struct coda_setattr_in *in = (struct coda_setattr_in *) buf;
    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    if (debug) {
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_SETATTR:");
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  n 0x%x, m %o",
               in->VFid.opaque[2], in->attr.va_mode);
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  uid: %i, gid: %i",
               in->attr.va_uid, in->attr.va_gid);
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  at %li, mt %li",
               in->attr.va_atime.tv_sec, in->attr.va_mtime.tv_sec);
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  ct %li, sz %llu",
               in->attr.va_ctime.tv_sec, in->attr.va_size);
    }

    oh->result = dav_setattr((dav_node *) in->VFid.opaque[2], ih->cred.cr_euid,
                             in->attr.va_mode != USHRT_MAX,
                             in->attr.va_mode & DAV_A_MASK,
                             in->attr.va_uid != UINT32_MAX, in->attr.va_uid,
                             in->attr.va_gid != UINT32_MAX, in->attr.va_gid,
                             in->attr.va_atime.tv_sec != -1,
                             in->attr.va_atime.tv_sec,
                             in->attr.va_mtime.tv_sec != -1,
                             in->attr.va_mtime.tv_sec,
                             in->attr.va_size != UINT64_MAX,
                             in->attr.va_size);

    return sizeof(struct coda_out_hdr);
}


static uint32_t coda_statfs(void) {

    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    struct coda_statfs_out *out = (struct coda_statfs_out *) buf;
    if (debug)
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "CODA_STATFS:");

    dav_stat st = dav_statfs();

    out->stat.f_blocks = st.blocks;
    out->stat.f_bfree = st.bfree;
    out->stat.f_bavail = st.bavail;
    out->stat.f_files = st.files;
    out->stat.f_ffree = st.ffree;

    oh->result = 0;
    return sizeof(struct coda_statfs_out);
}


/* Functions that will do a downcall to the kernel module. */

/* Downcall to inform the kernel that nodes have been added or removed. */
static void coda_flush(int device) {

    struct coda_out_hdr *oh = (struct coda_out_hdr *) buf;
    if (debug)
        syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "  CODA_FLUSH:");

    oh->opcode = CODA_FLUSH;
    oh->unique = 0;
    oh->result = 0;

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


/* Auxiliary functions. */

/* Writes a struct venus_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) {

    struct venus_dirent entry;
    size_t head = offsetof(struct venus_dirent, d_name);

    if (name != NULL) {
        entry.d_fileno = (size_t) node / alignment;
        entry.d_type = (S_ISDIR(node->mode)) ? CDT_DIR : CDT_REG;
        entry.d_namlen = (strlen(name) > CODA_MAXNAMLEN)
                         ? CODA_MAXNAMLEN : strlen(name);
        entry.d_reclen = (head + entry.d_namlen +4) & ~3;
    } else {
        entry.d_fileno = 0;
        entry.d_type = 0;
        entry.d_namlen = 0;
        entry.d_reclen = (head + 4) & ~3;
    }

    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.d_namlen)) {
        ret = write(fd, name + size - head, entry.d_namlen - size + head);
        size += ret;
    }
    if (size != (head + entry.d_namlen))
        return -1;

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

    return off + entry.d_reclen;
}


/* Translates attribute from node to attr.
   Note: Members va_fileid, v_gen, va_flags, va_rdev and va_filerev have no
   meaning for davfs. va_fileid is treated like d_fileno in struct venus_dirent,
   the other are set to zero. The meaning of va_type is not clear at all.
   Times are only set with 1 second precision, as this is the precision of the
   last-modified time in HTTP. */
static void set_attr(struct coda_vattr *attr, const dav_node *node) {

    attr->va_type = 0;
    attr->va_mode = node->mode;
    if (S_ISDIR(node->mode)) {
        attr->va_nlink = node->nref;
    } else {
        attr->va_nlink = 1;
    }
    attr->va_uid = node->uid;
    attr->va_gid = node->gid;
    attr->va_fileid = (size_t) node / alignment;
    attr->va_size = node->size;
    attr->va_blocksize = blocksize;
    attr->va_atime.tv_sec = node->atime;
    attr->va_atime.tv_nsec = 0;
    attr->va_mtime.tv_sec = node->mtime;
    attr->va_mtime.tv_nsec = 0;
    attr->va_ctime.tv_sec = node->ctime;
    attr->va_ctime.tv_nsec = 0;
    attr->va_gen = 0;
    attr->va_flags = 0;
    attr->va_rdev = 0;
    attr->va_bytes = node->size;
    attr->va_filerev = 0;
}

#endif   /* SIZEOF_VOID_P != 8, should be 4 */

Generated by  Doxygen 1.6.0   Back to index