Exemplo n.º 1
0
/**
 * Rename a regular file / directory.
 *
 * @param old_parent    inode of the old parent directory
 * @param old_dentry    old directory cache entry
 * @param new_parent    inode of the new parent directory
 * @param new_dentry    new directory cache entry
 * @returns 0 on success, Linux error code otherwise
 */
static int sf_rename(struct inode *old_parent, struct dentry *old_dentry,
                     struct inode *new_parent, struct dentry *new_dentry)
{
    int err = 0, rc = VINF_SUCCESS;
    struct sf_glob_info *sf_g = GET_GLOB_INFO(old_parent->i_sb);

    TRACE();

    if (sf_g != GET_GLOB_INFO(new_parent->i_sb))
    {
        LogFunc(("rename with different roots\n"));
        err = -EINVAL;
    }
    else
    {
        struct sf_inode_info *sf_old_i = GET_INODE_INFO(old_parent);
        struct sf_inode_info *sf_new_i = GET_INODE_INFO(new_parent);
        /* As we save the relative path inside the inode structure, we need to change
           this if the rename is successful. */
        struct sf_inode_info *sf_file_i = GET_INODE_INFO(old_dentry->d_inode);
        SHFLSTRING *old_path;
        SHFLSTRING *new_path;

        BUG_ON(!sf_old_i);
        BUG_ON(!sf_new_i);
        BUG_ON(!sf_file_i);

        old_path = sf_file_i->path;
        err = sf_path_from_dentry(__func__, sf_g, sf_new_i,
                                  new_dentry, &new_path);
        if (err)
            LogFunc(("failed to create new path\n"));
        else
        {
            int fDir = ((old_dentry->d_inode->i_mode & S_IFDIR) != 0);

            rc = vboxCallRename(&client_handle, &sf_g->map, old_path,
                                new_path, fDir ? 0 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
            if (RT_SUCCESS(rc))
            {
                kfree(old_path);
                sf_new_i->force_restat = 1;
                sf_old_i->force_restat = 1; /* XXX: needed? */
                /* Set the new relative path in the inode. */
                sf_file_i->path = new_path;
            }
            else
            {
                LogFunc(("vboxCallRename failed rc=%Rrc\n", rc));
                err = -RTErrConvertToErrno(rc);
                kfree(new_path);
            }
        }
    }
    return err;
}
Exemplo n.º 2
0
static void *sf_follow_link(struct dentry *dentry, struct nameidata *nd)
# endif
{
    struct inode *inode = dentry->d_inode;
    struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
    struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
    int error = -ENOMEM;
    char *path = (char*)get_zeroed_page(GFP_KERNEL);
    int rc;

    if (path)
    {
        error = 0;
        rc = vboxReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path);
        if (RT_FAILURE(rc))
        {
            LogFunc(("vboxReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc));
            free_page((unsigned long)path);
            error = -EPROTO;
        }
    }
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
    return error ? ERR_PTR(error) : (*cookie = path);
# else
    nd_set_link(nd, error ? ERR_PTR(error) : path);
    return NULL;
# endif
}
Exemplo n.º 3
0
/**
 * Close a regular file.
 *
 * @param inode         the inode
 * @param file          the file
 * @returns 0 on success, Linux error code otherwise
 */
static int sf_reg_release(struct inode *inode, struct file *file)
{
    int rc;
    struct sf_reg_info *sf_r;
    struct sf_glob_info *sf_g;
    struct sf_inode_info *sf_i = GET_INODE_INFO(inode);

    TRACE();
    sf_g = GET_GLOB_INFO(inode->i_sb);
    sf_r = file->private_data;

    BUG_ON(!sf_g);
    BUG_ON(!sf_r);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
    /* See the smbfs source (file.c). mmap in particular can cause data to be
     * written to the file after it is closed, which we can't cope with.  We
     * copy and paste the body of filemap_write_and_wait() here as it was not
     * defined before 2.6.6 and not exported until quite a bit later. */
    /* filemap_write_and_wait(inode->i_mapping); */
    if (   inode->i_mapping->nrpages
        && filemap_fdatawrite(inode->i_mapping) != -EIO)
        filemap_fdatawait(inode->i_mapping);
#endif
    rc = vboxCallClose(&client_handle, &sf_g->map, sf_r->handle);
    if (RT_FAILURE(rc))
        LogFunc(("vboxCallClose failed rc=%Rrc\n", rc));

    kfree(sf_r);
    sf_i->file = NULL;
    sf_i->handle = SHFL_HANDLE_NIL;
    file->private_data = NULL;
    return 0;
}
Exemplo n.º 4
0
static void sf_clear_inode(struct inode *inode)
{
    struct sf_inode_info *sf_i;

    TRACE();
    sf_i = GET_INODE_INFO(inode);
    if (!sf_i)
        return;

    BUG_ON(!sf_i->path);
    kfree(sf_i->path);
    kfree(sf_i);
    SET_INODE_INFO(inode, NULL);
}
Exemplo n.º 5
0
static void sf_evict_inode(struct inode *inode)
{
    struct sf_inode_info *sf_i;

    TRACE();
    truncate_inode_pages(&inode->i_data, 0);
    end_writeback(inode);

    sf_i = GET_INODE_INFO(inode);
    if (!sf_i)
        return;

    BUG_ON(!sf_i->path);
    kfree(sf_i->path);
    kfree(sf_i);
    SET_INODE_INFO(inode, NULL);
}
Exemplo n.º 6
0
static int sf_remount_fs(struct super_block *sb, int *flags, char *data)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23)
    struct sf_glob_info *sf_g;
    struct vbsf_mount_info_new *info;
    struct sf_inode_info *sf_i;
    struct inode *iroot;
    SHFLFSOBJINFO fsinfo;
    int err;

    printk(KERN_DEBUG "ENTER: sf_remount_fs\n");
    sf_g = GET_GLOB_INFO(sb);
    BUG_ON(!sf_g);
    BUG_ON(data[0] != 0);
    info = (struct vbsf_mount_info_new *)data;
    BUG_ON(   info->signature[0] != VBSF_MOUNT_SIGNATURE_BYTE_0
           || info->signature[1] != VBSF_MOUNT_SIGNATURE_BYTE_1
           || info->signature[2] != VBSF_MOUNT_SIGNATURE_BYTE_2);

    sf_g->uid = info->uid;
    sf_g->gid = info->gid;
    sf_g->ttl = info->ttl;
    sf_g->dmode = info->dmode;
    sf_g->fmode = info->fmode;
    sf_g->dmask = info->dmask;
    sf_g->fmask = info->fmask;

    iroot = ilookup(sb, 0);
    if (!iroot)
    {
        printk(KERN_DEBUG "can't find root inode\n");
        return -ENOSYS;
    }
    sf_i = GET_INODE_INFO(iroot);
    err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
    BUG_ON(err != 0);
    sf_init_inode(sf_g, iroot, &fsinfo);
    /*unlock_new_inode(iroot);*/
    printk(KERN_DEBUG "LEAVE: sf_remount_fs\n");
    return 0;
#else
    return -ENOSYS;
#endif
}
Exemplo n.º 7
0
static int sf_remount_fs(struct super_block *sb, int *flags, char *data)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 23)
    struct sf_glob_info *sf_g;
    struct sf_inode_info *sf_i;
    struct inode *iroot;
    SHFLFSOBJINFO fsinfo;
    int err;

    sf_g = GET_GLOB_INFO(sb);
    BUG_ON(!sf_g);
    if (data && data[0] != 0)
    {
        struct vbsf_mount_info_new *info =
            (struct vbsf_mount_info_new *)data;
        if (   info->signature[0] == VBSF_MOUNT_SIGNATURE_BYTE_0
            && info->signature[1] == VBSF_MOUNT_SIGNATURE_BYTE_1
            && info->signature[2] == VBSF_MOUNT_SIGNATURE_BYTE_2)
        {
            sf_g->uid = info->uid;
            sf_g->gid = info->gid;
            sf_g->ttl = info->ttl;
            sf_g->dmode = info->dmode;
            sf_g->fmode = info->fmode;
            sf_g->dmask = info->dmask;
            sf_g->fmask = info->fmask;
        }
    }

    iroot = ilookup(sb, 0);
    if (!iroot)
        return -ENOSYS;

    sf_i = GET_INODE_INFO(iroot);
    err = sf_stat(__func__, sf_g, sf_i->path, &fsinfo, 0);
    BUG_ON(err != 0);
    sf_init_inode(sf_g, iroot, &fsinfo);
    /*unlock_new_inode(iroot);*/
    return 0;
#else
    return -ENOSYS;
#endif
}
Exemplo n.º 8
0
/**
 * Remove a regular file / directory.
 *
 * @param parent        inode of the directory
 * @param dentry        directory cache entry
 * @param fDirectory    true if directory, false otherwise
 * @returns 0 on success, Linux error code otherwise
 */
static int sf_unlink_aux(struct inode *parent, struct dentry *dentry, int fDirectory)
{
    int rc, err;
    struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
    struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
    SHFLSTRING *path;
    uint32_t fFlags;

    TRACE();
    BUG_ON(!sf_g);

    err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
    if (err)
        goto fail0;

    fFlags = fDirectory ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
    if (   dentry
        && dentry->d_inode
        && ((dentry->d_inode->i_mode & S_IFLNK) == S_IFLNK))
        fFlags |= SHFL_REMOVE_SYMLINK;
    rc = vboxCallRemove(&client_handle, &sf_g->map, path, fFlags);
    if (RT_FAILURE(rc))
    {
        LogFunc(("(%d): vboxCallRemove(%s) failed rc=%Rrc\n", fDirectory,
                    path->String.utf8, rc));
        err = -RTErrConvertToErrno(rc);
        goto fail1;
    }

    /* directory access/change time changed */
    sf_i->force_restat = 1;
    /* directory content changed */
    sf_i->force_reread = 1;

    err = 0;

fail1:
    kfree(path);

fail0:
    return err;
}
Exemplo n.º 9
0
static int
sf_writepage(struct page *page, struct writeback_control *wbc)
{
    struct address_space *mapping = page->mapping;
    struct inode *inode = mapping->host;
    struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
    struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
    struct file *file = sf_i->file;
    struct sf_reg_info *sf_r = file->private_data;
    char *buf;
    uint32_t nwritten = PAGE_SIZE;
    int end_index = inode->i_size >> PAGE_SHIFT;
    loff_t off = ((loff_t) page->index) << PAGE_SHIFT;
    int err;

    TRACE();

    if (page->index >= end_index)
        nwritten = inode->i_size & (PAGE_SIZE-1);

    buf = kmap(page);

    err = sf_reg_write_aux(__func__, sf_g, sf_r, buf, &nwritten, off);
    if (err < 0)
    {
        ClearPageUptodate(page);
        goto out;
    }

    if (off > inode->i_size)
        inode->i_size = off;

    if (PageError(page))
        ClearPageError(page);
    err = 0;

out:
    kunmap(page);

    unlock_page(page);
    return err;
}
Exemplo n.º 10
0
/* this is called directly as iop on 2.4, indirectly as dop
   [sf_dentry_revalidate] on 2.4/2.6, indirectly as iop through
   [sf_getattr] on 2.6. the job is to find out whether dentry/inode is
   still valid. the test is failed if [dentry] does not have an inode
   or [sf_stat] is unsuccessful, otherwise we return success and
   update inode attributes */
int sf_inode_revalidate(struct dentry *dentry)
{
    int err;
    struct sf_glob_info *sf_g;
    struct sf_inode_info *sf_i;
    SHFLFSOBJINFO info;

    TRACE();
    if (!dentry || !dentry->d_inode)
    {
        LogFunc(("no dentry(%p) or inode(%p)\n", dentry, dentry->d_inode));
        return -EINVAL;
    }

    sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb);
    sf_i = GET_INODE_INFO(dentry->d_inode);

#if 0
    printk("%s called by %p:%p\n",
            sf_i->path->String.utf8,
            __builtin_return_address (0),
            __builtin_return_address (1));
#endif

    BUG_ON(!sf_g);
    BUG_ON(!sf_i);

    if (!sf_i->force_restat)
    {
        if (jiffies - dentry->d_time < sf_g->ttl)
            return 0;
    }

    err = sf_stat(__func__, sf_g, sf_i->path, &info, 1);
    if (err)
        return err;

    dentry->d_time = jiffies;
    sf_init_inode(sf_g, dentry->d_inode, &info);
    return 0;
}
Exemplo n.º 11
0
static void sf_evict_inode(struct inode *inode)
{
    struct sf_inode_info *sf_i;

    TRACE();
    truncate_inode_pages(&inode->i_data, 0);
# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
    clear_inode(inode);
# else
    end_writeback(inode);
# endif

    sf_i = GET_INODE_INFO(inode);
    if (!sf_i)
        return;

    BUG_ON(!sf_i->path);
    kfree(sf_i->path);
    kfree(sf_i);
    SET_INODE_INFO(inode, NULL);
}
Exemplo n.º 12
0
/*
 * Copyright (C) 2010-2011 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#include "vfsmod.h"

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)

# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
#  if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
static const char *sf_follow_link(struct dentry *dentry, void **cookie)
#  else
static void *sf_follow_link(struct dentry *dentry, struct nameidata *nd)
#  endif
{
    struct inode *inode = dentry->d_inode;
    struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
    struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
    int error = -ENOMEM;
    char *path = (char*)get_zeroed_page(GFP_KERNEL);
    int rc;

    if (path)
    {
        error = 0;
        rc = VbglR0SfReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path);
        if (RT_FAILURE(rc))
        {
            LogFunc(("VbglR0SfReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc));
            free_page((unsigned long)path);
            error = -EPROTO;
        }
    }
#  if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
    return error ? ERR_PTR(error) : (*cookie = path);
#  else
    nd_set_link(nd, error ? ERR_PTR(error) : path);
    return NULL;
#  endif
}

#  if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
static void sf_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
{
    char *page = nd_get_link(nd);
    if (!IS_ERR(page))
        free_page((unsigned long)page);
}
#  endif

# else /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) */
static const char *sf_get_link(struct dentry *dentry, struct inode *inode,
                               struct delayed_call *done)
{
    struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
    struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
    char *path;
    int rc;

    if (!dentry)
        return ERR_PTR(-ECHILD);
    path = kzalloc(PAGE_SIZE, GFP_KERNEL);
    if (!path)
        return ERR_PTR(-ENOMEM);
    rc = VbglR0SfReadLink(&client_handle, &sf_g->map, sf_i->path, PATH_MAX, path);
    if (RT_FAILURE(rc))
    {
        LogFunc(("VbglR0SfReadLink failed, caller=%s, rc=%Rrc\n", __func__, rc));
        kfree(path);
        return ERR_PTR(-EPROTO);
    }
    set_delayed_call(done, kfree_link, path);
    return path;
}
Exemplo n.º 13
0
static int sf_symlink(struct inode *parent, struct dentry *dentry, const char *symname)
{
    int err;
    int rc;
    struct sf_inode_info *sf_i;
    struct sf_glob_info *sf_g;
    SHFLSTRING *path, *ssymname;
    SHFLFSOBJINFO info;
    int symname_len = strlen(symname) + 1;

    TRACE();
    sf_g = GET_GLOB_INFO(parent->i_sb);
    sf_i = GET_INODE_INFO(parent);

    BUG_ON(!sf_g);
    BUG_ON(!sf_i);

    err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
    if (err)
        goto fail0;

    ssymname = kmalloc(offsetof(SHFLSTRING, String.utf8) + symname_len, GFP_KERNEL);
    if (!ssymname)
    {
        LogRelFunc(("kmalloc failed, caller=sf_symlink\n"));
        err = -ENOMEM;
        goto fail1;
    }

    ssymname->u16Length = symname_len - 1;
    ssymname->u16Size = symname_len;
    memcpy(ssymname->String.utf8, symname, symname_len);

    rc = vboxCallSymlink(&client_handle, &sf_g->map, path, ssymname, &info);
    kfree(ssymname);

    if (RT_FAILURE(rc))
    {
        if (rc == VERR_WRITE_PROTECT)
        {
            err = -EROFS;
            goto fail1;
        }
        LogFunc(("vboxCallSymlink(%s) failed rc=%Rrc\n",
                    sf_i->path->String.utf8, rc));
        err = -EPROTO;
        goto fail1;
    }

    err = sf_instantiate(parent, dentry, path, &info, SHFL_HANDLE_NIL);
    if (err)
    {
        LogFunc(("could not instantiate dentry for %s err=%d\n",
                 sf_i->path->String.utf8, err));
        goto fail1;
    }

    sf_i->force_restat = 1;
    return 0;

fail1:
    kfree(path);
fail0:
    return err;
}
Exemplo n.º 14
0
/**
 * Open a regular file.
 *
 * @param inode         the inode
 * @param file          the file
 * @returns 0 on success, Linux error code otherwise
 */
static int sf_reg_open(struct inode *inode, struct file *file)
{
    int rc, rc_linux = 0;
    struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
    struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
    struct sf_reg_info *sf_r;
    SHFLCREATEPARMS params;

    TRACE();
    BUG_ON(!sf_g);
    BUG_ON(!sf_i);

    LogFunc(("open %s\n", sf_i->path->String.utf8));

    sf_r = kmalloc(sizeof(*sf_r), GFP_KERNEL);
    if (!sf_r)
    {
        LogRelFunc(("could not allocate reg info\n"));
        return -ENOMEM;
    }

    /* Already open? */
    if (sf_i->handle != SHFL_HANDLE_NIL)
    {
        /*
         * This inode was created with sf_create_aux(). Check the CreateFlags:
         * O_CREAT, O_TRUNC: inherent true (file was just created). Not sure
         * about the access flags (SHFL_CF_ACCESS_*).
         */
        sf_i->force_restat = 1;
        sf_r->handle = sf_i->handle;
        sf_i->handle = SHFL_HANDLE_NIL;
        sf_i->file = file;
        file->private_data = sf_r;
        return 0;
    }

    RT_ZERO(params);
    params.Handle = SHFL_HANDLE_NIL;
    /* We check the value of params.Handle afterwards to find out if
     * the call succeeded or failed, as the API does not seem to cleanly
     * distinguish error and informational messages.
     *
     * Furthermore, we must set params.Handle to SHFL_HANDLE_NIL to
     * make the shared folders host service use our fMode parameter */

    if (file->f_flags & O_CREAT)
    {
        LogFunc(("O_CREAT set\n"));
        params.CreateFlags |= SHFL_CF_ACT_CREATE_IF_NEW;
        /* We ignore O_EXCL, as the Linux kernel seems to call create
           beforehand itself, so O_EXCL should always fail. */
        if (file->f_flags & O_TRUNC)
        {
            LogFunc(("O_TRUNC set\n"));
            params.CreateFlags |= (  SHFL_CF_ACT_OVERWRITE_IF_EXISTS
                                   | SHFL_CF_ACCESS_WRITE);
        }
        else
            params.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
    }
    else
    {
        params.CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
        if (file->f_flags & O_TRUNC)
        {
            LogFunc(("O_TRUNC set\n"));
            params.CreateFlags |= (  SHFL_CF_ACT_OVERWRITE_IF_EXISTS
                    | SHFL_CF_ACCESS_WRITE);
        }
    }

    if (!(params.CreateFlags & SHFL_CF_ACCESS_READWRITE))
    {
        switch (file->f_flags & O_ACCMODE)
        {
            case O_RDONLY:
                params.CreateFlags |= SHFL_CF_ACCESS_READ;
                break;

            case O_WRONLY:
                params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
                break;

            case O_RDWR:
                params.CreateFlags |= SHFL_CF_ACCESS_READWRITE;
                break;

            default:
                BUG ();
        }
    }

    if (file->f_flags & O_APPEND)
    {
        LogFunc(("O_APPEND set\n"));
        params.CreateFlags |= SHFL_CF_ACCESS_APPEND;
    }

    params.Info.Attr.fMode = inode->i_mode;
    LogFunc(("sf_reg_open: calling vboxCallCreate, file %s, flags=%#x, %#x\n",
              sf_i->path->String.utf8 , file->f_flags, params.CreateFlags));
    rc = vboxCallCreate(&client_handle, &sf_g->map, sf_i->path, &params);
    if (RT_FAILURE(rc))
    {
        LogFunc(("vboxCallCreate failed flags=%d,%#x rc=%Rrc\n",
                  file->f_flags, params.CreateFlags, rc));
        kfree(sf_r);
        return -RTErrConvertToErrno(rc);
    }

    if (SHFL_HANDLE_NIL == params.Handle)
    {
        switch (params.Result)
        {
            case SHFL_PATH_NOT_FOUND:
            case SHFL_FILE_NOT_FOUND:
                rc_linux = -ENOENT;
                break;
            case SHFL_FILE_EXISTS:
                rc_linux = -EEXIST;
                break;
            default:
                break;
        }
    }

    sf_i->force_restat = 1;
    sf_r->handle = params.Handle;
    sf_i->file = file;
    file->private_data = sf_r;
    return rc_linux;
}
Exemplo n.º 15
0
/**
 * Write to a regular file.
 *
 * @param file          the file
 * @param buf           the buffer
 * @param size          length of the buffer
 * @param off           offset within the file
 * @returns the number of written bytes on success, Linux error code otherwise
 */
static ssize_t sf_reg_write(struct file *file, const char *buf, size_t size, loff_t *off)
{
    int err;
    void *tmp;
    RTCCPHYS tmp_phys;
    size_t tmp_size;
    size_t left = size;
    ssize_t total_bytes_written = 0;
    struct inode *inode = GET_F_DENTRY(file)->d_inode;
    struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
    struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
    struct sf_reg_info *sf_r = file->private_data;
    loff_t pos;

    TRACE();
    BUG_ON(!sf_i);
    BUG_ON(!sf_g);
    BUG_ON(!sf_r);

    if (!S_ISREG(inode->i_mode))
    {
        LogFunc(("write to non regular file %d\n",  inode->i_mode));
        return -EINVAL;
    }

    pos = *off;
    if (file->f_flags & O_APPEND)
    {
        pos = inode->i_size;
        *off = pos;
    }

    /** XXX Check write permission according to inode->i_mode! */

    if (!size)
        return 0;

    tmp = alloc_bounce_buffer(&tmp_size, &tmp_phys, size, __PRETTY_FUNCTION__);
    if (!tmp)
        return -ENOMEM;

    while (left)
    {
        uint32_t to_write, nwritten;

        to_write = tmp_size;
        if (to_write > left)
            to_write = (uint32_t) left;

        nwritten = to_write;

        if (copy_from_user(tmp, buf, to_write))
        {
            err = -EFAULT;
            goto fail;
        }

#if 1
        if (VbglR0CanUsePhysPageList())
        {
            err = VbglR0SfWritePhysCont(&client_handle, &sf_g->map, sf_r->handle,
                                        pos, &nwritten, tmp_phys);
            err = RT_FAILURE(err) ? -EPROTO : 0;
        }
        else
#endif
            err = sf_reg_write_aux(__func__, sf_g, sf_r, tmp, &nwritten, pos);
        if (err)
            goto fail;

        pos  += nwritten;
        left -= nwritten;
        buf  += nwritten;
        total_bytes_written += nwritten;
        if (nwritten != to_write)
            break;
    }

    *off += total_bytes_written;
    if (*off > inode->i_size)
        inode->i_size = *off;

    sf_i->force_restat = 1;
    free_bounce_buffer(tmp);
    return total_bytes_written;

fail:
    free_bounce_buffer(tmp);
    return err;
}
Exemplo n.º 16
0
/**
 * Extract element ([dir]->f_pos) from the directory [dir] into [d_name].
 *
 * @returns 0 for success, 1 for end reached, Linux error code otherwise.
 */
static int sf_getdent(struct file *dir, char d_name[NAME_MAX], int *d_type)
{
    loff_t cur;
    struct sf_glob_info *sf_g;
    struct sf_dir_info *sf_d;
    struct sf_inode_info *sf_i;
    struct inode *inode;
    struct list_head *pos, *list;

    TRACE();

    inode = GET_F_DENTRY(dir)->d_inode;
    sf_i = GET_INODE_INFO(inode);
    sf_g = GET_GLOB_INFO(inode->i_sb);
    sf_d = dir->private_data;

    BUG_ON(!sf_g);
    BUG_ON(!sf_d);
    BUG_ON(!sf_i);

    if (sf_i->force_reread)
    {
        int rc;
        int err;
        SHFLCREATEPARMS params;

        RT_ZERO(params);
        params.Handle = SHFL_HANDLE_NIL;
        params.CreateFlags = 0
                           | SHFL_CF_DIRECTORY
                           | SHFL_CF_ACT_OPEN_IF_EXISTS
                           | SHFL_CF_ACT_FAIL_IF_NEW
                           | SHFL_CF_ACCESS_READ
                           ;

        LogFunc(("sf_getdent: calling vboxCallCreate, folder %s, flags %#x\n",
                  sf_i->path->String.utf8, params.CreateFlags));
        rc = vboxCallCreate(&client_handle, &sf_g->map, sf_i->path, &params);
        if (RT_FAILURE(rc))
        {
            LogFunc(("vboxCallCreate(%s) failed rc=%Rrc\n",
                        sf_i->path->String.utf8, rc));
            return -EPERM;
        }

        if (params.Result != SHFL_FILE_EXISTS)
        {
            LogFunc(("directory %s does not exist\n", sf_i->path->String.utf8));
            sf_dir_info_free(sf_d);
            return -ENOENT;
        }

        sf_dir_info_empty(sf_d);
        err = sf_dir_read_all(sf_g, sf_i, sf_d, params.Handle);
        rc = vboxCallClose(&client_handle, &sf_g->map, params.Handle);
        if (RT_FAILURE(rc))
            LogFunc(("vboxCallClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc));
        if (err)
            return err;

        sf_i->force_reread = 0;
    }

    cur = 0;
    list = &sf_d->info_list;
    list_for_each(pos, list)
    {
        struct sf_dir_buf *b;
        SHFLDIRINFO *info;
        loff_t i;

        b = list_entry(pos, struct sf_dir_buf, head);
        if (dir->f_pos >= cur + b->cEntries)
        {
            cur += b->cEntries;
            continue;
        }

        for (i = 0, info = b->buf; i < dir->f_pos - cur; ++i)
        {
            size_t size;

            size = offsetof(SHFLDIRINFO, name.String) + info->name.u16Size;
            info = (SHFLDIRINFO *) ((uintptr_t) info + size);
        }

        *d_type = sf_get_d_type(info->Info.Attr.fMode);

        return sf_nlscpy(sf_g, d_name, NAME_MAX,
                         info->name.String.utf8, info->name.u16Length);
    }

    return 1;
}
Exemplo n.º 17
0
int sf_setattr(struct dentry *dentry, struct iattr *iattr)
{
    struct sf_glob_info *sf_g;
    struct sf_inode_info *sf_i;
    SHFLCREATEPARMS params;
    SHFLFSOBJINFO info;
    uint32_t cbBuffer;
    int rc, err;

    TRACE();

    sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb);
    sf_i = GET_INODE_INFO(dentry->d_inode);
    err  = 0;

    RT_ZERO(params);
    params.Handle = SHFL_HANDLE_NIL;
    params.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
                       | SHFL_CF_ACT_FAIL_IF_NEW
                       | SHFL_CF_ACCESS_ATTR_WRITE;

    /* this is at least required for Posix hosts */
    if (iattr->ia_valid & ATTR_SIZE)
        params.CreateFlags |= SHFL_CF_ACCESS_WRITE;

    rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, &params);
    if (RT_FAILURE(rc))
    {
        LogFunc(("VbglR0SfCreate(%s) failed rc=%Rrc\n",
                 sf_i->path->String.utf8, rc));
        err = -RTErrConvertToErrno(rc);
        goto fail2;
    }
    if (params.Result != SHFL_FILE_EXISTS)
    {
        LogFunc(("file %s does not exist\n", sf_i->path->String.utf8));
        err = -ENOENT;
        goto fail1;
    }

    /* Setting the file size and setting the other attributes has to be
     * handled separately, see implementation of vbsfSetFSInfo() in
     * vbsf.cpp */
    if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME))
    {
#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? RTFS_UNIX_##r : 0)

        RT_ZERO(info);
        if (iattr->ia_valid & ATTR_MODE)
        {
            info.Attr.fMode  = mode_set(ISUID);
            info.Attr.fMode |= mode_set(ISGID);
            info.Attr.fMode |= mode_set(IRUSR);
            info.Attr.fMode |= mode_set(IWUSR);
            info.Attr.fMode |= mode_set(IXUSR);
            info.Attr.fMode |= mode_set(IRGRP);
            info.Attr.fMode |= mode_set(IWGRP);
            info.Attr.fMode |= mode_set(IXGRP);
            info.Attr.fMode |= mode_set(IROTH);
            info.Attr.fMode |= mode_set(IWOTH);
            info.Attr.fMode |= mode_set(IXOTH);

            if (iattr->ia_mode & S_IFDIR)
                info.Attr.fMode |= RTFS_TYPE_DIRECTORY;
            else
                info.Attr.fMode |= RTFS_TYPE_FILE;
        }

        if (iattr->ia_valid & ATTR_ATIME)
            sf_timespec_from_ftime(&info.AccessTime, &iattr->ia_atime);
        if (iattr->ia_valid & ATTR_MTIME)
            sf_timespec_from_ftime(&info.ModificationTime, &iattr->ia_mtime);
        /* ignore ctime (inode change time) as it can't be set from userland anyway */

        cbBuffer = sizeof(info);
        rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, params.Handle,
                            SHFL_INFO_SET | SHFL_INFO_FILE, &cbBuffer,
                            (PSHFLDIRINFO)&info);
        if (RT_FAILURE(rc))
        {
            LogFunc(("VbglR0SfFsInfo(%s, FILE) failed rc=%Rrc\n",
                        sf_i->path->String.utf8, rc));
            err = -RTErrConvertToErrno(rc);
            goto fail1;
        }
    }

    if (iattr->ia_valid & ATTR_SIZE)
    {
        RT_ZERO(info);
        info.cbObject = iattr->ia_size;
        cbBuffer = sizeof(info);
        rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, params.Handle,
                            SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer,
                            (PSHFLDIRINFO)&info);
        if (RT_FAILURE(rc))
        {
            LogFunc(("VbglR0SfFsInfo(%s, SIZE) failed rc=%Rrc\n",
                        sf_i->path->String.utf8, rc));
            err = -RTErrConvertToErrno(rc);
            goto fail1;
        }
    }

    rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
    if (RT_FAILURE(rc))
        LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc));

    return sf_inode_revalidate(dentry);

fail1:
    rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
    if (RT_FAILURE(rc))
        LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc));

fail2:
    return err;
}
Exemplo n.º 18
0
/**
 * Open a directory. Read the complete content into a buffer.
 *
 * @param inode     inode
 * @param file      file
 * @returns 0 on success, Linux error code otherwise
 */
static int sf_dir_open(struct inode *inode, struct file *file)
{
    int rc;
    int err;
    struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
    struct sf_dir_info *sf_d;
    struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
    SHFLCREATEPARMS params;

    TRACE();
    BUG_ON(!sf_g);
    BUG_ON(!sf_i);

    if (file->private_data)
    {
        LogFunc(("sf_dir_open() called on already opened directory '%s'\n",
                sf_i->path->String.utf8));
        return 0;
    }

    sf_d = sf_dir_info_alloc();
    if (!sf_d)
    {
        LogRelFunc(("could not allocate directory info for '%s'\n",
                    sf_i->path->String.utf8));
        return -ENOMEM;
    }

    RT_ZERO(params);
    params.Handle = SHFL_HANDLE_NIL;
    params.CreateFlags = 0
                       | SHFL_CF_DIRECTORY
                       | SHFL_CF_ACT_OPEN_IF_EXISTS
                       | SHFL_CF_ACT_FAIL_IF_NEW
                       | SHFL_CF_ACCESS_READ
                       ;

    LogFunc(("sf_dir_open(): calling vboxCallCreate, folder %s, flags %#x\n",
             sf_i->path->String.utf8, params.CreateFlags));
    rc = vboxCallCreate(&client_handle, &sf_g->map, sf_i->path, &params);
    if (RT_SUCCESS(rc))
    {
        if (params.Result == SHFL_FILE_EXISTS)
        {
            err = sf_dir_read_all(sf_g, sf_i, sf_d, params.Handle);
            if (!err)
                file->private_data = sf_d;
        }
        else
            err = -ENOENT;

        rc = vboxCallClose(&client_handle, &sf_g->map, params.Handle);
        if (RT_FAILURE(rc))
            LogFunc(("sf_dir_open(): vboxCallClose(%s) after err=%d failed rc=%Rrc\n",
                     sf_i->path->String.utf8, err, rc));
    }
    else
        err = -EPERM;

    if (err)
        sf_dir_info_free(sf_d);

    return err;
}
Exemplo n.º 19
0
/**
 * This is called when vfs failed to locate dentry in the cache. The
 * job of this function is to allocate inode and link it to dentry.
 * [dentry] contains the name to be looked in the [parent] directory.
 * Failure to locate the name is not a "hard" error, in this case NULL
 * inode is added to [dentry] and vfs should proceed trying to create
 * the entry via other means. NULL(or "positive" pointer) ought to be
 * returned in case of success and "negative" pointer on error
 */
static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
                                , unsigned int flags
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
                                , struct nameidata *nd
#endif
                               )
{
    int err;
    struct sf_inode_info *sf_i, *sf_new_i;
    struct sf_glob_info *sf_g;
    SHFLSTRING *path;
    struct inode *inode;
    ino_t ino;
    SHFLFSOBJINFO fsinfo;

    TRACE();
    sf_g = GET_GLOB_INFO(parent->i_sb);
    sf_i = GET_INODE_INFO(parent);

    BUG_ON(!sf_g);
    BUG_ON(!sf_i);

    err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
    if (err)
        goto fail0;

    err = sf_stat(__func__, sf_g, path, &fsinfo, 1);
    if (err)
    {
        if (err == -ENOENT)
        {
            /* -ENOENT: add NULL inode to dentry so it later can be
               created via call to create/mkdir/open */
            kfree(path);
            inode = NULL;
        }
        else
            goto fail1;
    }
    else
    {
        sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
        if (!sf_new_i)
        {
            LogRelFunc(("could not allocate memory for new inode info\n"));
            err = -ENOMEM;
            goto fail1;
        }
        sf_new_i->handle = SHFL_HANDLE_NIL;
        sf_new_i->force_reread = 0;

        ino = iunique(parent->i_sb, 1);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
        inode = iget_locked(parent->i_sb, ino);
#else
        inode = iget(parent->i_sb, ino);
#endif
        if (!inode)
        {
            LogFunc(("iget failed\n"));
            err = -ENOMEM;          /* XXX: ??? */
            goto fail2;
        }

        SET_INODE_INFO(inode, sf_new_i);
        sf_init_inode(sf_g, inode, &fsinfo);
        sf_new_i->path = path;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
        unlock_new_inode(inode);
#endif
    }

    sf_i->force_restat = 0;
    dentry->d_time = jiffies;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
    d_set_d_op(dentry, &sf_dentry_ops);
#else
    dentry->d_op = &sf_dentry_ops;
#endif
    d_add(dentry, inode);
    return NULL;

fail2:
    kfree(sf_new_i);

fail1:
    kfree(path);

fail0:
    return ERR_PTR(err);
}
Exemplo n.º 20
0
/**
 * Create a new regular file / directory.
 *
 * @param parent        inode of the directory
 * @param dentry        directory cache entry
 * @param mode          file mode
 * @param fDirectory    true if directory, false otherwise
 * @returns 0 on success, Linux error code otherwise
 */
static int sf_create_aux(struct inode *parent, struct dentry *dentry,
                         umode_t mode, int fDirectory)
{
    int rc, err;
    SHFLCREATEPARMS params;
    SHFLSTRING *path;
    struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
    struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);

    TRACE();
    BUG_ON(!sf_i);
    BUG_ON(!sf_g);

    err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
    if (err)
        goto fail0;

    RT_ZERO(params);
    params.Handle = SHFL_HANDLE_NIL;
    params.CreateFlags = 0
                       | SHFL_CF_ACT_CREATE_IF_NEW
                       | SHFL_CF_ACT_FAIL_IF_EXISTS
                       | SHFL_CF_ACCESS_READWRITE
                       | (fDirectory ? SHFL_CF_DIRECTORY : 0)
                       ;
    params.Info.Attr.fMode = 0
                           | (fDirectory ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
                           | (mode & S_IRWXUGO)
                           ;
    params.Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;

    LogFunc(("sf_create_aux: calling vboxCallCreate, folder %s, flags %#x\n",
              path->String.utf8, params.CreateFlags));
    rc = vboxCallCreate(&client_handle, &sf_g->map, path, &params);
    if (RT_FAILURE(rc))
    {
        if (rc == VERR_WRITE_PROTECT)
        {
            err = -EROFS;
            goto fail1;
        }
        err = -EPROTO;
        LogFunc(("(%d): vboxCallCreate(%s) failed rc=%Rrc\n",
                    fDirectory, sf_i->path->String.utf8, rc));
        goto fail1;
    }

    if (params.Result != SHFL_FILE_CREATED)
    {
        err = -EPERM;
        LogFunc(("(%d): could not create file %s result=%d\n",
                    fDirectory, sf_i->path->String.utf8, params.Result));
        goto fail1;
    }

    err = sf_instantiate(parent, dentry, path, &params.Info,
                         fDirectory ? SHFL_HANDLE_NIL : params.Handle);
    if (err)
    {
        LogFunc(("(%d): could not instantiate dentry for %s err=%d\n",
                    fDirectory, sf_i->path->String.utf8, err));
        goto fail2;
    }

    /*
     * Don't close this handle right now. We assume that the same file is
     * opened with sf_reg_open() and later closed with sf_reg_close(). Save
     * the handle in between. Does not apply to directories. True?
     */
    if (fDirectory)
    {
        rc = vboxCallClose(&client_handle, &sf_g->map, params.Handle);
        if (RT_FAILURE(rc))
            LogFunc(("(%d): vboxCallClose failed rc=%Rrc\n", fDirectory, rc));
    }

    sf_i->force_restat = 1;
    return 0;

fail2:
    rc = vboxCallClose(&client_handle, &sf_g->map, params.Handle);
    if (RT_FAILURE(rc))
        LogFunc(("(%d): vboxCallClose failed rc=%Rrc\n", fDirectory, rc));

fail1:
    kfree(path);

fail0:
    return err;
}