regops.c revision 335339b2f047d0cc077224d3d724b2c3b1a6a383
/* $Id$ */
/** @file
* vboxsf - VBox Linux Shared Folders, Regular file inode and file operations.
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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.
*/
/*
* Limitations: only COW memory mapping is supported
*/
#include "vfsmod.h"
{
void *tmp;
/* try for big first. */
if (!tmp)
{
/* fall back on a page sized buffer. */
if (!tmp)
{
return NULL;
}
}
return tmp;
}
static void free_bounce_buffer(void *tmp)
{
}
/* fops */
{
/** @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is
* contiguous in physical memory (kmalloc or single page), we should
* use a physical address here to speed things up. */
if (RT_FAILURE(rc))
{
return -EPROTO;
}
return 0;
}
{
/** @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is
* contiguous in physical memory (kmalloc or single page), we should
* use a physical address here to speed things up. */
if (RT_FAILURE(rc))
{
LogFunc(("vboxCallWrite failed. caller=%s, rc=%Rrc\n",
return -EPROTO;
}
return 0;
}
/**
* Read from 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 read bytes on success, Linux error code otherwise
*/
{
int err;
void *tmp;
ssize_t total_bytes_read = 0;
TRACE();
{
return -EINVAL;
}
/** XXX Check read permission according to inode->i_mode! */
if (!size)
return 0;
if (!tmp)
return -ENOMEM;
while (left)
{
if (err)
goto fail;
{
goto fail;
}
break;
}
*off += total_bytes_read;
return total_bytes_read;
fail:
return err;
}
/**
* 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
*/
{
int err;
void *tmp;
TRACE();
{
return -EINVAL;
}
{
}
/** XXX Check write permission according to inode->i_mode! */
if (!size)
return 0;
if (!tmp)
return -ENOMEM;
while (left)
{
{
goto fail;
}
#if 1
if (VbglR0CanUsePhysPageList())
{
}
else
#endif
if (err)
goto fail;
break;
}
*off += total_bytes_written;
return total_bytes_written;
fail:
return err;
}
/**
* Open a regular file.
*
* @param inode the inode
* @param file the file
* @returns 0 on success, Linux error code otherwise
*/
{
struct sf_reg_info *sf_r;
TRACE();
if (!sf_r)
{
LogRelFunc(("could not allocate reg info\n"));
return -ENOMEM;
}
/* Already open? */
{
/*
* 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_*).
*/
return 0;
}
/* 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 */
{
LogFunc(("O_CREAT set\n"));
/* We ignore O_EXCL, as the Linux kernel seems to call create
beforehand itself, so O_EXCL should always fail. */
{
LogFunc(("O_TRUNC set\n"));
}
else
}
else
{
{
LogFunc(("O_TRUNC set\n"));
}
}
{
{
case O_RDONLY:
break;
case O_WRONLY:
break;
case O_RDWR:
break;
default:
BUG ();
}
}
{
LogFunc(("O_APPEND set\n"));
}
LogFunc(("sf_reg_open: calling vboxCallCreate, file %s, flags=%#x, %#x\n",
if (RT_FAILURE(rc))
{
LogFunc(("vboxCallCreate failed flags=%d,%#x rc=%Rrc\n",
return -RTErrConvertToErrno(rc);
}
{
{
case SHFL_PATH_NOT_FOUND:
case SHFL_FILE_NOT_FOUND:
break;
case SHFL_FILE_EXISTS:
break;
default:
break;
}
}
return rc_linux;
}
/**
* Close a regular file.
*
* @param inode the inode
* @param file the file
* @returns 0 on success, Linux error code otherwise
*/
{
int rc;
struct sf_reg_info *sf_r;
struct sf_glob_info *sf_g;
TRACE();
/* 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); */
#endif
if (RT_FAILURE(rc))
return 0;
}
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */
# define SET_TYPE(t)
#endif
{
char *buf;
int err;
TRACE();
return VM_FAULT_SIGBUS;
#else
{
return NOPAGE_SIGBUS;
}
#endif
/* Don't use GFP_HIGHUSER as long as sf_reg_read_aux() calls vboxCallRead()
* which works on virtual addresses. On Linux cannot reliably determine the
* physical address for high memory, see rtR0MemObjNativeLockKernel(). */
if (!page) {
LogRelFunc(("failed to allocate page\n"));
return VM_FAULT_OOM;
#else
return NOPAGE_OOM;
#endif
}
#else
#endif
if (err)
{
return VM_FAULT_SIGBUS;
#else
return NOPAGE_SIGBUS;
#endif
}
if (!nread)
{
#else
#endif
}
else
return 0;
#else
return page;
#endif
}
static struct vm_operations_struct sf_vma_ops =
{
#else
#endif
};
{
TRACE();
{
LogFunc(("shared mmapping not available\n"));
return -EINVAL;
}
return 0;
}
struct file_operations sf_reg_fops =
{
.read = sf_reg_read,
.open = sf_reg_open,
.write = sf_reg_write,
.mmap = sf_reg_mmap,
# else
# endif
# else
# endif
.fsync = noop_fsync,
# else
# endif
#endif
};
struct inode_operations sf_reg_iops =
{
#else
.getattr = sf_getattr,
#endif
};
{
char *buf;
int ret;
TRACE();
if (ret)
{
if (PageLocked(page))
return ret;
}
return 0;
}
static int
{
char *buf;
int err;
TRACE();
if (err < 0)
{
goto out;
}
err = 0;
out:
return err;
}
{
TRACE();
}
{
void *buf;
int err;
TRACE();
if (err >= 0) {
}
return nwritten;
}
# endif /* KERNEL_VERSION >= 2.6.24 */
struct address_space_operations sf_reg_aops =
{
.readpage = sf_readpage,
# else
# endif
};
#endif