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

davfsd.c

/* 
** DAV and CODA  connection, request and response process
**
** This library and program is free software; you can redistribute it and/or
** modify it under the terms of the GNU Library General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**   
** This library 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
** Library General Public License for more details.
**
** You should have received a copy of the GNU Library General Public
** License along with this library; if not, write to the Free
** Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
** MA 02111-1307, USA
*/

#include "config.h"

#include <error.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mount.h>

/* Neon */
#include <ne_basic.h>
#include <ne_alloc.h>
#include <ne_socket.h>

#include "davfsd.h"
#include "webdav.h"
#include "util.h"

/* Variables set at start up and needed for cleanup before exit */
char *dav_url;
char *dav_mpoint;
char *dav_pidfile;
int dav_locks;

/* File descriptor of coda device. */
int dav_cfs;

/* a linked list of the above objects */
static davfs_list *davfs_list_root;

static int count = 0;

/* default stat */
struct stat dav_file_stat;
struct stat dav_dir_stat;
/*2005-05-29, werner, security fix
int dav_noexec;*/

int dav_has_permission(struct coda_in_hdr *ih) {
#if CODA_KERNEL_VERSION > 2
    DBG1("id: %i\n", ih->uid);
    if ((ih->uid != dav_file_stat.st_uid) && (ih->uid != 0))
        return 0;
#else
    DBG1("id: %i\n", ih->cred.cr_uid);
    if ((ih->cred.cr_uid != dav_file_stat.st_uid) && (ih->cred.cr_uid != 0))
        return 0;
#endif /* CODA_KERNEL_VERSION */
    return 1;
}

static void put_all() {
    DBG0("Saving open files on exit.");
    davfs_list *node = davfs_list_root;
    while (node != NULL) {
        struct v_list *h = (struct v_list *) node->data;
        if (h->has_changed && !h->is_dir && !h->is_created) {
            if (dav_put_unlock(h->real_name, h->local_name) < 0)
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                       "Error saving %s", h->real_name);
        }
        if (h->local_name != NULL)
            remove(h->local_name);
        node = node->next;
    }
}


static void default_signal_handler(int signo)
{
    DBG1("signal_handler(%d)\n", signo);
    signal(SIGTERM, SIG_IGN);
    signal(SIGHUP, SIG_IGN);
    signal(SIGINT, SIG_IGN);
    put_all();
    remove(dav_pidfile);
    dav_close_connection();
    exit(EXIT_SUCCESS);
}


static void sigchld_signal_handler(int signo)
{
    DBG1("signal_handler(%d)\n", signo);
    dav_close_connection();
    exit(EXIT_FAILURE);
}


static void dav_set_signal() {
    signal(SIGTERM, default_signal_handler);
    signal(SIGHUP, default_signal_handler);
    signal(SIGINT, default_signal_handler);
#ifdef DEBUG
    /* ignore child signal in debug mode to avoid premature termination */
    signal(SIGCHLD, SIG_IGN);
#else
    signal(SIGCHLD, sigchld_signal_handler);
#endif
    signal(SIGPIPE, SIG_IGN);    
}

/* Clear coda cache of a file entry */
static void zap_file(union inputArgs *in_buf)
{
    struct coda_zapfile_out cmd;
    cmd.oh.opcode = CODA_PURGEFID;
    cmd.oh.unique = 0;
    cmd.CodaFid = in_buf->coda_close.VFid;
    write(dav_cfs, &cmd, sizeof(cmd));
}


static char *look_name(DAVCodaFid *id, int *is_dir)
{
    char *name;

    if ((id->Volume != MY_VOL) || (id->Vnode != MY_VNODE)) {
         syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                "Bad handle passed %x/%x/%p\n", id->Volume, id->Vnode,
                 id->List);
        kill(getpid(), SIGTERM);
    }
    if (PARANOIA) {
        davfs_list *walk;
        for (walk = davfs_list_root; walk; walk = walk->next) {
            if (walk->data == id->List)
                break;
        }
        if (!walk) {
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                   "Bad handle passed %x/%x/%p\n", id->Volume, id->Vnode,
                   id->List);
            return NULL;    
        }
    }                /* paranoia */
    name = id->List->real_name;
    *is_dir = id->List->is_dir;
    
    return name;
}


static void alloc_vfid(DAVCodaFid *res, char *name, int is_dir)
{
    struct v_list *h = ne_calloc(sizeof(*h));
    davfs_list *new_node = ne_calloc(sizeof(*new_node));
    new_node->data = h;

    if (davfs_list_root != NULL) {
        new_node->next = davfs_list_root;
    }

    davfs_list_root = new_node;

    h->real_name = ne_strdup(name);
    h->is_dir = is_dir;
    count++;

    if (res != NULL) {
        res->Volume = MY_VOL;
        res->Vnode = MY_VNODE;
        res->List = h;
    }
    DBG3("New vfid created at %p (file <%s: %d>)\n", 
         h, h->real_name, h->is_dir);
}


/*
** Delete name from the list 
*/
static void delete_name(const char *real_name)
{
    davfs_list *walk, *prev;

    DBG1("Delete_name %s\n", real_name);
    /* at this point, the paranoid would check for a dirty file and write it out */
    for (prev = walk = davfs_list_root; walk; walk = walk->next) {
        if (!strcmp(((struct v_list *) walk->data)->real_name, real_name)) {
            struct v_list *v = (struct v_list *) (walk->data);
            NE_FREE(v->real_name);
            NE_FREE(v->local_name);
        
            /* remove walk */
            if(walk==davfs_list_root) 
                davfs_list_root = walk->next;
            else 
                prev->next = walk->next;

            NE_FREE(walk->data);
            NE_FREE(walk);

            count--;
            return;
        }
        /* Save prev pointer */
        prev = walk;

    }
    DBG1("Failure trying to delete the file %s\n", real_name);
}


/*
** Delete name from the list 
*/
static void replace_name(const char *old_name, const char *new_name)
{
    davfs_list *walk;
    
    DBG2("Replace name %s to %s\n", old_name, new_name);
    /* at this point, the paranoid would check for a dirty file and write it out */
    for (walk = davfs_list_root; walk; walk = walk->next) {
        if (!strcmp(((struct v_list *) walk->data)->real_name, old_name)) {
            struct v_list *v = (struct v_list *) (walk->data);
            NE_FREE(v->real_name);
            v->real_name = ne_strdup(new_name);
            return;
        }
    }
    DBG1("Failure trying to replace the file %s\n", old_name);
}

static inline int CodaToVfsFlags(int flags)
{
    int ret=0;

    if (flags & (C_O_READ | C_O_WRITE))
        ret |= O_RDWR;
    
    if(flags & C_O_TRUNC)
        ret |= O_TRUNC;
    if(flags & C_O_CREAT)
        ret |= O_CREAT;
    
    if(flags & C_O_EXCL) 
        ret|=O_EXCL;

    return ret;
}


/*********************local copy management ********************************/
static inline char *get_local_copy(DAVCodaFid id, int flags)
{
    int fd;
    struct v_list *v = id.List;

    if ((flags & C_O_TRUNC) || v->is_created){
        v->local_name = dav_get_tempnam("trunc", &fd);
        if(fd==-1) {
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                   "Could not create temp file.");
        } else {
            DBG1("  cache-file: %s", v->local_name);
            v->has_changed = 1;
            v->is_created = 0;
            v->is_trunc = 1;
            close(fd);
        }
        return v->local_name;

    } else {
        v->local_name = dav_getlocalcopy(v->real_name);
        if (v->local_name == NULL) {
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                   "get_local_copy: NULL for '%s'\n", v->real_name);
        } else {
            DBG1("  cache-file: %s", v->local_name);
            if (flags & C_O_WRITE)
                v->has_changed = 1;
        }
        return v->local_name;
    }
}

static void write_dir_entry(int handle, const char *name, 
                int *offset, int is_dir)
{
    struct venus_dirent ent;
    static unsigned long ino = MY_INODE;    /* this must be ulong */

    ent.d_fileno = ino++;    /* FIXME: there should be a "better" way to get unique filenos... */
    
    if (is_dir) 
        ent.d_type = CDT_DIR;    /* the kernel does not use this */
    else
        ent.d_type = CDT_REG;    /* the kernel does not use this */

    strncpy(ent.d_name, name, CODA_MAXNAMLEN);
    ent.d_name[CODA_MAXNAMLEN] = '\0';
    ent.d_namlen = strlen(ent.d_name);

    ent.d_reclen = DIRSIZ(&ent);    /* carefull: DIRSIZ() uses ent.d_namlen 
                     * to calculate record size 
                     */
    /* DIRSIZ() does some padding, therefore... 
     * be sure that this structure doesn't contain zeros (two zero bytes 
     * at the end are the end-of-dir-marker for this IO command !!)
     */
    if ((ent.d_namlen + 1) <= CODA_MAXNAMLEN)
        ent.d_name[ent.d_namlen + 1] = 0x00;
    if ((ent.d_namlen + 2) <= CODA_MAXNAMLEN)
        ent.d_name[ent.d_namlen + 2] = 0x00;
    if ((ent.d_namlen + 3) <= CODA_MAXNAMLEN)
        ent.d_name[ent.d_namlen + 3] = 0x00;

    *offset += ent.d_reclen;

    if (write(handle, &ent, ent.d_reclen) != ent.d_reclen)
        /* FIXME: we should propagate error */
        perror("\a" PACKAGE_NAME ": error writing dirent");    

    DBG3("['%s', handle=%x, ino=%x]", name, handle, ent.d_fileno);
}

/* Global variable for directory cache */
char *prev_base_dir;
dav_prop_result *prev_list_result;

/* Get directory info to the file 
 * Save information for directory cache */
static char *get_dir_copy(DAVCodaFid id)
{
    struct v_list *v = id.List;
    dav_prop_result *one_res;
    dav_prop_result *result = dav_opendir(v->real_name);
    char *cache;
    int handle;
    int num = 0;
    int offset = 0;
    struct venus_dirent final_dirent;

    /* No result */
    if (!result)
        return NULL;

    /* Save it for reuse */
    prev_list_result = result;
    prev_base_dir = ne_strdup(v->real_name);
    dav_no_trail(prev_base_dir);
    /* It's directory */
    v->is_dir = 1;

    DBG0("converting dir to file ");
    cache = dav_get_tempnam("dir", &handle);
    if(handle==-1) {
        perror("\a" PACKAGE_NAME ": can not open temp file for directory list");
        dav_closedir(result);
        NE_FREE(cache);
        return NULL;
    }
    
    /* Set mode */
    /* FIXME : Do we need this?? */
    /*
    setmode(handle, O_WRONLY | O_CREAT | O_EXCL);
    */
    DBG1("%s:", cache);

    DBG0(" { ");

    /* copy a list file names out to a file */
    for (one_res = result; one_res; one_res= one_res->next) {
        DBG2("FNAME: %s:%d\n", one_res->fname, S_ISDIR(one_res->f_st.st_mode));
        write_dir_entry(handle, one_res->fname, 
                        &offset, S_ISDIR(one_res->f_st.st_mode));
        num++;
        DBG0(", ");
    }

    DBG0("}, EOD= ");

    /* write last venus_dirent with fileno==0. Be sure to include padding, too. */
    final_dirent.d_fileno = 0;
    final_dirent.d_reclen =
                    ((offset + (DIRBLKSIZ - 1)) & ~(DIRBLKSIZ - 1)) - offset;
#ifndef SOLARIS
    final_dirent.d_type = 0;
#endif
    final_dirent.d_namlen = 0;

#define minEntry 12        /* FIXME: is this true for all platforms ?? */
#if 1
    final_dirent.d_reclen = (final_dirent.d_reclen > minEntry) ?
                                      (final_dirent.d_reclen) : (minEntry);
#endif

    write(handle, &final_dirent, final_dirent.d_reclen);
    
    DBG1(" (wrote %d entries) ", num);
    if (close(handle) != 0)
        perror("\n\a" PACKAGE_NAME ": error closing temp file dir directory list");

    /* Let's free it when we close */
    /*
    dav_closedir(result);
    */
    return v->local_name = cache;
}

static int sync_file(DAVCodaFid id) {
    struct v_list *v = id.List;

    if (v->is_dir)
        return 0;

    if (access(v->local_name, F_OK) != 0) {
        DBG1("  %s: missing cache file on a fsync", v->real_name);
        return EIO;
    }

    if (v->has_changed) {
        DBG1("  saving the file %s ", v->local_name);
        return dav_put(v->real_name, v->local_name);
    }
    
    return 0;
}

static int unget_local_copy(DAVCodaFid id)
{
    int ret = 0;
    struct v_list *v = id.List;

    DBG3("  unget_: u%i c%i cr%i", v->usage, v->has_changed, v->is_created);
    if (v->local_name == NULL) {
        DBG1("  %s: empty local_name on a close", v->real_name);
        if (dav_locks && v->has_changed)
            dav_unlock(v->real_name);
        v->has_changed = 0;
        v->is_trunc = 0;
        return EIO;
    }

    if (access(v->local_name, F_OK) != 0) {
        DBG1("  %s: missing cache file on a close", v->real_name);
        if (dav_locks && v->has_changed)
            dav_unlock(v->real_name);
        v->has_changed = 0;
        v->is_trunc = 0;
        return EIO;
    }

    if (v->is_dir) {
        dav_closedir(prev_list_result);
        prev_list_result = NULL;
        NE_FREE(prev_base_dir);
    } else if (v->has_changed) {
        DBG1("  saving the file %s ", v->local_name);
        if (dav_put_unlock(v->real_name, v->local_name) < 0)
            ret = dav_get_errno();
    }
    
    DBG1("  removing %s ", v->local_name);
    unlink(v->local_name);
    NE_FREE(v->local_name);
    v->has_changed = 0;
    return ret;
}

/****************** attribute mangling *************************************/
static inline int st2type(struct stat *s)
{
    if (S_ISDIR(s->st_mode))
        return C_VDIR;
    if (S_ISREG(s->st_mode))
        return C_VREG;
    if (S_ISBLK(s->st_mode))
        return C_VBLK;
    if (S_ISCHR(s->st_mode))
        return C_VCHR;
    if (S_ISLNK(s->st_mode))
        return C_VLNK;
    if (S_ISSOCK(s->st_mode))
        return C_VSOCK;
    if (S_ISFIFO(s->st_mode))
        return C_VFIFO;
    DBG1("Unknown type in st2type (%o)\n", s->st_mode);
    return C_VNON;
}

static void st2attr(struct stat *s, struct coda_vattr *a)
{
    static long id = 0;        /* must be long */

    memset(a, 0x00, sizeof(struct coda_vattr));
    DBG1("(mode = %o)", s->st_mode);

    a->va_type = st2type(s);
    a->va_mode = s->st_mode;
    a->va_nlink = s->st_nlink;
    a->va_nlink = 1;
    a->va_uid = s->st_uid;
    a->va_gid = s->st_gid;
    a->va_fileid = id++;
    a->va_size = s->st_size;
    a->va_blocksize = 1024;    /* s->st_blksize; */
    a->va_atime.tv_nsec = a->va_ctime.tv_nsec = a->va_mtime.tv_nsec = 0;
    a->va_atime.tv_sec = s->st_atime;
    a->va_mtime.tv_sec = s->st_mtime;
    a->va_ctime.tv_sec = s->st_ctime;
    a->va_gen = 0;
    a->va_flags = 0;

    a->va_bytes = s->st_blocks * s->st_blksize;
    a->va_filerev = 0;
}


/* 
** General Open function 
*/
static char *coda_open(char *name, DAVCodaFid id, int flags,
               union inputArgs *in_buf, union outputArgs *out_buf)
{
    struct stat st;
    struct v_list *v = id.List;

    DBG3("  open: u%i c%i cr%i", v->usage, v->has_changed, v->is_created);
    if (!v_created(id)) {
        if (dav_stat((name), &st, 0, 0) == -1) {
            out_buf->oh.result = dav_get_errno();
            if (out_buf->oh.result == ENOENT && strlen(name) > 0) {
                DBG1("  file '%s' probably does not exist.", name);
                delete_name(name);
                zap_file(in_buf);
            }
            return NULL;
        }
    } else {
        st = dav_file_stat;
    }

    if (S_ISDIR(st.st_mode)) {
        DBG0("  open request on a directory");
        if (v->local_name != NULL) {
            if (access(v->local_name, F_OK) == 0)
                remove(v->local_name);
            NE_FREE(v->local_name);
            v->usage = 0;
            dav_closedir(prev_list_result);
            prev_list_result = NULL;
            NE_FREE(prev_base_dir);
        }
        get_dir_copy(id);
        if (v->local_name == NULL) {
            out_buf->oh.result = EIO;
            return NULL;
        } 

    } else if (v->usage > 0) {
        DBG0("  open request on already open file");
        if (v->local_name == NULL) {
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                   "%s: no local_name but usage >0", name);
            v->usage = 0;
            v->has_changed = 0;
            dav_unlock(name);
            out_buf->oh.result = EIO;
            return NULL;
        }
        if (access(v->local_name, F_OK) != 0) {
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                   "%s: missing cache file", name);
            NE_FREE(v->local_name);
            v->usage = 0;
            v->has_changed = 0;
            dav_unlock(name);
            out_buf->oh.result = EIO;
            return NULL;
        }
        if ((flags & C_O_WRITE) && dav_locks && !v->has_changed) {
            if (dav_lock(name) < 0) {
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                       "%s: LOCK failed", name);
                out_buf->oh.result = dav_get_errno();
                return NULL;
            }
        }

    } else {
        if (flags & C_O_WRITE) {
            if (dav_locks && dav_lock(name)) {
                syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                       "%s: LOCK failed", name);
                out_buf->oh.result = dav_get_errno();
                return NULL;
            }
        }
        get_local_copy(id, flags);
        if (v->local_name == NULL) {
            out_buf->oh.result = dav_get_errno();
            dav_unlock(name);
            syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR),
                   "%s: failed to get local copy", name);
            return NULL;
        }
    }

    v->usage++;
    return v->local_name;
}

#define DAVFS_DEBUG \
(NE_DBG_HTTP | NE_DBG_SOCKET | NE_DBG_HTTPBODY | NE_DBG_HTTPAUTH | \
  NE_DBG_LOCKS | NE_DBG_XMLPARSE | NE_DBG_XML | NE_DBG_SSL)


/* For CODA compatable */
#ifndef CODA_RELEASE
#define CODA_RELEASE -10
#endif
#ifndef CODA_STORE
#define CODA_STORE -11
#endif

/* Main part */
int main(int argc, char *argv[]) {

    DBG1("Setting euid=%i", getuid());
    if (seteuid(getuid()) < 0)
        error(EXIT_FAILURE, 0, "Can't change user id");

    DBG0("Parsing command line");
    dav_args *args = dav_get_args(argc, argv);
    
    DBG0("Checking permissions and configuration");
    dav_check_config(args);

    DBG1("Open device %s", args->device);
    dav_cfs = open(args->device, O_RDWR, 0);    
    if (dav_cfs < 0)
        error(EXIT_FAILURE, 0,
              "Could not open %s:\n"
              "\tKernel does not support coda,"
              "or the coda-module is not loaded.", args->device);
    u_int coda_kernel_version;
/*    ioctl(dav_cfs, CIOC_KERNEL_VERSION, &coda_kernel_version);
    if (coda_kernel_version != CODA_KERNEL_VERSION)
        error(EXIT_FAILURE, 0, "CODA kernel version mismatch:\n"
                          "\tcompiled for version %d, version %d available",
                          CODA_KERNEL_VERSION, coda_kernel_version);
*/
    DBG0("Allocate message buffers");
    char buf[2048];        /* must be at least PATH_MAX+1 !! */
    union inputArgs *in_buf = ne_calloc(SIZEOF_INBUF);
    union outputArgs *out_buf = ne_calloc(SIZEOF_OUTBUF);
    if ((in_buf == NULL) || (out_buf == NULL))
        error(EXIT_FAILURE, 0, "Can't allocate message buffers.");
        
    DBG1("Open connection to %s", dav_url);    
#ifdef DEBUG
    ne_debug_init(stderr, NE_DBG_HTTP);
#endif
    if (ne_sock_init())
        error(EXIT_FAILURE, 0, "Socket library initalization failed");
    if (dav_open_connection(args) < 0)
        error(EXIT_FAILURE, 0, "Could not connect to %s.", dav_url);

    DBG0("Create root VFid");
    struct stat st;
    alloc_vfid(NULL, "", 1);
    dav_stat("", &st, 1, 0);

    DBG0("Fork into daemon mode; parent will mount");
    dav_set_signal();
    pid_t childpid = fork();
    if (childpid > 0) {
        /* Parent */
        if (dav_mount(dav_cfs, args) != 0) {
            /* Fails. Kill child pid and exit */
            kill(childpid, SIGTERM);
            exit(EXIT_FAILURE);
        }
        DBG1("Parent leaves now. Good luck to child no. %i!", childpid);
        exit(EXIT_SUCCESS);
    } else if (childpid < 0) {
        error(EXIT_FAILURE, 0, "Could not start child process for daemon.");
    }

    DBG0("Child: No way back to root privileges.\n");
    if (setuid(getuid()) == -1) {
        perror("setuid");
    }
          
    DBG0("Child: Write pid-file and free args-struct");
    dav_save_mount_pid();
    dav_delete_args(args);
    
    DBG0("Child: Start message queue");
    setsid();

    for ( ; ; ) {
    /* Look out: This variable is really mad. It sometimes points to
       real_name, sometimes points to local_name, hoping to get you confused. */
    char *name;
    int msg, size, retval;
    fd_set rfds;
    struct timeval tv;
    int toclose = -1;
    int is_dir;

    FD_ZERO(&rfds);
    FD_SET(dav_cfs, &rfds);
    tv.tv_sec = SELECT_TIME_OUT;
    tv.tv_usec = 0;

    retval = select(dav_cfs + 1, &rfds, NULL, NULL, &tv);
    if (retval == 0) {
        DBG1("Waited for %i s\n", SELECT_TIME_OUT);
        if (!dav_still_mounted())
            kill(getpid(), SIGTERM);
        continue;
    } else if (retval < 0) {
        kill(getpid(), SIGTERM);
    }

    memset(in_buf, 0, SIZEOF_INBUF);
    memset(out_buf, 0, SIZEOF_OUTBUF);
    msg = read(dav_cfs, in_buf, (SIZEOF_INBUF - 1));
    if ((msg == -1) || (msg == 0))
        continue;

    DBG2("got %3.3d byte command: opcode = %2.2d ", msg,
            in_buf->ih.opcode);
    
    out_buf->oh.opcode = in_buf->ih.opcode;
    out_buf->oh.unique = in_buf->ih.unique;
    out_buf->oh.result = ENOSYS;
    size = sizeof(out_buf->oh);

    switch (in_buf->ih.opcode) {
    case CODA_ROOT:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(root);
        davfs_list *node = davfs_list_root;
        while (node->next != NULL) {
            node = node->next;
        }
        memset(&out_buf->coda_root.VFid, 0, sizeof(DAVCodaFid));
        ((DAVCodaFid *)&out_buf->coda_root.VFid)->Volume = MY_VOL;
        ((DAVCodaFid *)&out_buf->coda_root.VFid)->Vnode = MY_VNODE;
        ((DAVCodaFid *)&out_buf->coda_root.VFid)->List = (struct v_list*) node->data;
        break;
        
        /********************* file props & access *******************/
    case CODA_GETATTR:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(getattr);
        DUMP(getattr);
        GET_VFID_name(getattr);
        if (!v_created(in_buf->coda_getattr.VFid)) {
            STAT(name);    /* fills in st */
        }
        else
        st = dav_file_stat;
        st2attr(&st, &out_buf->coda_getattr.attr);
        break;

    case CODA_SETATTR:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD_NOREP(setattr);
        DUMP(setattr);
        GET_VFID_name(setattr);
        DBG3(" m:%o, o:%d, g:%d",
             in_buf->coda_setattr.attr.va_mode,
             in_buf->coda_setattr.attr.va_uid,
             in_buf->coda_setattr.attr.va_gid);
        DBG3(" at:%lu, mt:%lu, ct:%lu",
             in_buf->coda_setattr.attr.va_atime.tv_sec,
             in_buf->coda_setattr.attr.va_mtime.tv_sec,
             in_buf->coda_setattr.attr.va_ctime.tv_sec);
        /*2005-05-29, werner, security fix*/
        if ((in_buf->coda_setattr.attr.va_uid != -1)
                || (in_buf->coda_setattr.attr.va_gid != -1))
            /*dav_chmod( name, in_buf->coda_setattr.attr.va_mode );*/
            out_buf->oh.result = ENOTSUP;
            /* cannot change owner, group or dates ....... */
        break;

    case CODA_ACCESS:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        /* this always returns TRUE; this seems to be ok with current CODA design */
        CMD_NOREP(access);
        DUMP(access);
        DBG1("flags:%x ", in_buf->coda_access.flags);
        GET_VFID_name(access);
        break;

    case CODA_LOOKUP:    /* !! ttd: search for existing VFid's instead of making many new ones */
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(lookup);
        DUMP_NAME(lookup);
        GET_VFID_name(lookup);
        DBG1("flags=%d: ", in_buf->coda_lookup.flags);
        BUILD_NAME(lookup);
        DBG1("(stat: %s)", buf);
        STAT(buf);        /* fills in st */
        alloc_vfid((DAVCodaFid *)&out_buf->coda_lookup.VFid, buf,S_ISDIR(st.st_mode));
        out_buf->coda_lookup.vtype = st2type(&st);
        break;

    case CODA_READLINK:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(readlink);
        DUMP(readlink);
        GET_VFID_name(readlink);
        /* put the string at the end of the structure
         * the reply packet must be smaller than the request packet
         */
        //      retval = mc_readlink(name, (char*)&out_buf + sizeof(out_buf->coda_readlink),
        //                     msg - sizeof(out_buf->coda_readlink));
        if (retval <= 0) {
            out_buf->oh.result = ENOENT;
        }
        else {
            out_buf->coda_readlink.count = retval;    /* == strlen(sym_link_string) */
            out_buf->coda_readlink.data = (void *) sizeof(out_buf->coda_readlink);
            size += retval;    /* the structure is longer by this amount */
        }
        break;

      /************************ open, close, create & mkdir ******************/
    case CODA_OPEN_BY_FD:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(open);
        DUMP(open);
        DBG1("flags:%#x ", in_buf->coda_open.flags);
        GET_VFID_name(open);

        if (!(name =
                   coda_open(name,*(DAVCodaFid *)&in_buf->coda_open_by_fd.VFid,
                             in_buf->coda_open_by_fd.flags, in_buf, out_buf)))
            break;
        out_buf->coda_open_by_fd.fd = toclose = open(name, O_RDWR);
        if (out_buf->coda_open_by_fd.fd == -1)
            out_buf->oh.result = EPERM;
        break;

    case CODA_OPEN:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(open);
        DUMP(open);
        DBG1("flags:%#x ", in_buf->coda_open.flags);
        GET_VFID_name(open);
        if (!coda_open(name, *(DAVCodaFid *)&in_buf->coda_open.VFid,
                       in_buf->coda_open.flags, in_buf, out_buf))
            break;
        {
            struct stat st;
            if (!name || (stat(name, &st) == -1)) {
                out_buf->oh.result = dav_get_errno();
                break;
            }
            out_buf->coda_open.dev = st.st_dev;
            out_buf->coda_open.inode = st.st_ino;
        }
        break;

    case CODA_OPEN_BY_PATH:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(open_by_path);
        DUMP(open_by_path);
        DBG1("flags:%#x ", in_buf->coda_open_by_path.flags);
        GET_VFID_name(open_by_path);

        if (!coda_open(name, *(DAVCodaFid *)&in_buf->coda_open_by_path.VFid,
                       in_buf->coda_open_by_path.flags, in_buf, out_buf))
            break;

        {
            char *namebuf;
            namebuf = (char *) ((&out_buf->coda_open_by_path.path) + 1);
            out_buf->coda_open_by_path.path = namebuf - (char *) out_buf;
            strncpy(namebuf, name, CODA_MAXNAMLEN);
            namebuf[CODA_MAXNAMLEN] = '\0';    /* strncpy() may not add '\0' */
            size = (namebuf + strlen(namebuf) + 1) - (char *) out_buf;
        }
        break;

    case CODA_RELEASE:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD_NOREP(release);
        DUMP(release);
        GET_VFID_name(release);
        v_usage(in_buf->coda_close.VFid)--;
        if (v_usage(in_buf->coda_close.VFid) < 0)
            v_usage(in_buf->coda_close.VFid) = 0;
        if (v_usage(in_buf->coda_close.VFid) == 0) {
            out_buf->oh.result =
                    unget_local_copy(*(DAVCodaFid *)&in_buf->coda_close.VFid);
            if (out_buf->oh.result != 0)
                zap_file(in_buf);
        }
        DBG1(" the current VFid list has %d elements\n", count);
        break;
        
    case CODA_CLOSE:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD_NOREP(close);
        DUMP(close);
        GET_VFID_name(close);
        v_usage(in_buf->coda_close.VFid)--;
        if (v_usage(in_buf->coda_close.VFid) < 0)
            v_usage(in_buf->coda_close.VFid) = 0;
        if (v_usage(in_buf->coda_close.VFid) == 0) {
            out_buf->oh.result =
                    unget_local_copy(*(DAVCodaFid *)&in_buf->coda_close.VFid);
            if (out_buf->oh.result != 0)
                zap_file(in_buf);
        }
        DBG1(" the current VFid list has %d elements\n", count);
        break;
        
        
    /*# FIXME : What should I do ? */
    case CODA_FSYNC:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD_NOREP(fsync);
        DUMP(fsync);
        out_buf->oh.result = sync_file(*(DAVCodaFid *)&in_buf->coda_close.VFid);
        break;

    case CODA_CREATE:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(create);
        DUMP_NAME(create);
        GET_VFID_name(create);
        BUILD_NAME(create);
        DBG1("(create_name: %s)", buf);
        
        alloc_vfid((DAVCodaFid *)&out_buf->coda_create.VFid, buf, 0);
        v_created(out_buf->coda_create.VFid) = 1;

        /* get inherient */
        out_buf->coda_create.attr = in_buf->coda_create.attr;
        st2attr(&dav_file_stat, &(out_buf->coda_create.attr));
        break;

    case CODA_MKDIR:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(mkdir);
        DUMP_NAME(mkdir);
        GET_VFID_name(mkdir);
        BUILD_NAME(mkdir);
        DBG1("(mkdir: %s)", buf);
        if (dav_mkdir(buf, in_buf->coda_mkdir.attr.va_mode) == 0) {
            alloc_vfid((DAVCodaFid *)&out_buf->coda_mkdir.VFid, buf, 1);
        
            /* get inherient */
            out_buf->coda_mkdir.attr = in_buf->coda_mkdir.attr;
            st2attr(&dav_dir_stat, &(out_buf->coda_create.attr));
        }
        else
            out_buf->oh.result = dav_get_errno();
        break;

      /********************* deletions & rename ******************/
    case CODA_RMDIR:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD_NOREP(rmdir);
        DUMP_NAME(rmdir);
        GET_VFID_name(rmdir);
        BUILD_NAME(rmdir);
        DBG1("(rmdir: %s)", buf);
        if (dav_rmdir(buf) == 0) {
            out_buf->oh.result = 0;
            delete_name(buf);
        }
        else
            out_buf->oh.result = dav_get_errno();
        break;
    case CODA_REMOVE:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD_NOREP(remove);
        DUMP_NAME(remove);
        GET_VFID_name(remove);
        BUILD_NAME(remove);
        DBG1("(remove: %s)", buf);
        if (dav_delete(buf) == 0) {
            out_buf->oh.result = 0;
            delete_name(buf);
        }
        else
            out_buf->oh.result = dav_get_errno();
        break;
    case CODA_RENAME:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD_NOREP(rename);
        {
            int is_dir_src;
            char buf2[PATH_MAX + 1];
            name = ((char *) in_buf) + in_buf->coda_rename.srcname;
            if (!name) {
                out_buf->oh.result = ENOENT;
                break;
            }
            sprintf(buf, "%s/%s",
                    look_name((DAVCodaFid *)&in_buf->coda_rename.sourceFid,
                              &is_dir_src), name);
            name = ((char *) in_buf) + in_buf->coda_rename.destname;
            sprintf(buf2, "%s/%s",
                    look_name((DAVCodaFid *)&in_buf->coda_rename.destFid,
                              &is_dir), name);
            DBG2("src name=%s:%d,",   buf, is_dir_src); 
            DBG2("dest name %s:%d \n", buf2, is_dir);
        
            if (dav_rename(buf, buf2, is_dir_src, 0) == 0) {
                out_buf->oh.result = 0;
                replace_name(buf, buf2);
            }
            else
                out_buf->oh.result = dav_get_errno();
        }
        break;
        
    case CODA_STATFS:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD(statfs);
        DBG0(" Faking free disk space to satisfy Nautilus and the like.\n");
        out_buf-> coda_statfs.stat.f_blocks=9000000;
        out_buf-> coda_statfs.stat.f_bfree=9000000;
        out_buf-> coda_statfs.stat.f_bavail=9000000;
        out_buf-> coda_statfs.stat.f_files=9000000;
        out_buf-> coda_statfs.stat.f_ffree=9000000;
        break;

    /* Not implemented, but should return OK */
    case CODA_STORE:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        CMD_NOREP(store);
        DBG0(" What should I save?");
        break;

    default:
        if (!dav_has_permission(&in_buf->ih)) {
            out_buf->oh.result = EPERM;
            break;
        }
        DBG0(" unimplemented coda call");
        break;
    }
    
    DBG3(" returning %s (%d), %d bytes\n\n",
            out_buf->oh.result ? "FAILURE" : "SUCCESS",
            out_buf->oh.result, size);
    msg = write(dav_cfs, out_buf, size);
    if (toclose != -1)
        close(toclose);
    fflush(stdout);
    fflush(stderr);
    }                /* while */
}

/* start emacs stuff */
/* 
 * local variables: 
 * eval: (load-file "../tools/davfs-emacs.el") 
 * end: 
 */ 


Generated by  Doxygen 1.6.0   Back to index