utils.c revision 2c629013fe1cccb4e0ca8586ece54320dfe849a2
/** @file
*
* vboxsf -- VirtualBox Guest Additions for Linux:
* Utility functions.
* Mainly conversion from/to VirtualBox/Linux data structures
*/
/*
* Copyright (C) 2006-2007 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.
*/
#include "vfsmod.h"
/* #define USE_VMALLOC */
/*
* sf_reg_aops and sf_backing_dev_info are just quick implementations to make
* sendfile work. For more information have a look at
*
*
* and the sample implementation
*
*/
static void
{
do_div (t, 1000000000);
*time = t;
}
static void
{
RTTimeSpecSetNano (ts, t);
}
#else /* >= 2.6.0 */
static void
{
}
static void
{
RTTimeSpecSetNano (ts, t);
}
#endif /* >= 2.6.0 */
void
{
int is_dir;
int mode;
TRACE ();
#endif
if (is_dir) {
/* XXX: this probably should be set to the number of entries
in the directory plus two (. ..) */
}
else {
}
#endif
#endif
/* i_blocks always in units of 512 bytes! */
}
int
{
int rc;
TRACE ();
LogFunc(("sf_stat: calling vboxCallCreate, file %s, flags %#x\n",
if (RT_FAILURE (rc)) {
LogFunc(("vboxCallCreate(%s) failed. caller=%s, rc=%Rrc\n",
return -EPROTO;
}
if (!ok_to_fail) {
LogFunc(("vboxCallCreate(%s) file does not exist. caller=%s, result=%d\n",
}
return -ENOENT;
}
return 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
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
{
int err;
struct sf_glob_info *sf_g;
struct sf_inode_info *sf_i;
TRACE ();
return -EINVAL;
}
#if 0
printk ("%s called by %p:%p\n",
__builtin_return_address (1));
#endif
if (!sf_i->force_restat) {
return 0;
}
}
if (err) {
return err;
}
return 0;
}
/* this is called during name resolution/lookup to check if the
[dentry] in the cache is still valid. the job is handled by
[sf_inode_revalidate] */
static int
#else
#endif
{
TRACE ();
if (sf_inode_revalidate (dentry)) {
return 0;
}
return 1;
}
/* on 2.6 this is a proxy for [sf_inode_revalidate] which (as a side
effect) updates inode attributes for [dentry] (given that [dentry]
has inode at all) from these new attributes we derive [kstat] via
[generic_fillattr] */
int
{
int err;
TRACE ();
if (err) {
return err;
}
return 0;
}
int
{
struct sf_glob_info *sf_g;
struct sf_inode_info *sf_i;
TRACE ();
err = 0;
/* this is at least required for Posix hosts */
if (RT_FAILURE (rc)) {
LogFunc(("vboxCallCreate(%s) failed rc=%Rrc\n",
goto fail2;
}
goto fail1;
}
/* Setting the file size and setting the other attributes has to be
* handled separately, see implementation of vbsfSetFSInfo() in
* vbsf.cpp */
{
{
else
}
/* ignore ctime (inode change time) as it can't be set from userland anyway */
(PSHFLDIRINFO)&info);
if (RT_FAILURE (rc)) {
LogFunc(("vboxCallFSInfo(%s, FILE) failed rc=%Rrc\n",
goto fail1;
}
}
{
(PSHFLDIRINFO)&info);
if (RT_FAILURE (rc)) {
LogFunc(("vboxCallFSInfo(%s, SIZE) failed rc=%Rrc\n",
goto fail1;
}
}
if (RT_FAILURE (rc))
{
LogFunc(("vboxCallClose(%s) failed rc=%Rrc\n",
}
return sf_inode_revalidate (dentry);
if (RT_FAILURE (rc))
{
LogFunc(("vboxCallClose(%s) failed rc=%Rrc\n",
}
return err;
}
#endif /* >= 2.6.0 */
static int
{
int is_root = 0;
TRACE ();
is_root = 1;
}
else {
/* lengths of constituents plus terminating zero plus slash */
if (path_len > 0xffff) {
return -ENAMETOOLONG;
}
}
if (!tmp) {
return -ENOMEM;
}
if (is_root) {
}
else {
}
return 0;
}
/* [dentry] contains string encoded in coding system that corresponds
to [sf_g]->nls, we must convert it to UTF8 here and pass down to
[sf_make_path] which will allocate SHFLSTRING and fill it in */
int
SHFLSTRING **result)
{
int err;
const char *d_name;
const char *name;
TRACE ();
const char *in;
char *out;
for (i = 0; i < d_len; ++i) {
/* We renamed the linux kernel wchar_t type to linux_wchar_t in
the-linux-kernel.h, as it conflicts with the C++ type of that name. */
int nb;
if (nb < 0) {
LogFunc(("nls->char2uni failed %x %d\n",
goto fail1;
}
#else
#endif
if (nb < 0) {
LogFunc(("nls->uni2char failed %x %d\n",
uni, out_bound_len));
goto fail1;
}
out_bound_len -= nb;
}
err = -ENAMETOOLONG;
goto fail1;
}
*out = 0;
}
else {
}
}
return err;
return err;
}
int
{
const char *in;
char *out;
out_len = 0;
while (in_bound_len) {
int nb;
#else
#endif
if (nb < 0) {
LogFunc(("utf8_mbtowc failed(%s) %x:%d\n",
return -EINVAL;
}
in_bound_len -= nb;
if (nb < 0) {
LogFunc(("nls->uni2char failed(%s) %x:%d\n",
return nb;
}
out_bound_len -= nb;
}
*out = 0;
return 0;
}
else {
return -ENAMETOOLONG;
}
else {
}
return 0;
}
}
static struct sf_dir_buf *
sf_dir_buf_alloc (void)
{
struct sf_dir_buf *b;
TRACE ();
b = kmalloc (sizeof (*b), GFP_KERNEL);
if (!b) {
LogRelFunc(("could not alloc directory buffer\n"));
return NULL;
}
#ifdef USE_VMALLOC
#else
#endif
if (!b->buf) {
kfree (b);
LogRelFunc(("could not alloc directory buffer storage\n"));
return NULL;
}
INIT_LIST_HEAD (&b->head);
b->nb_entries = 0;
b->used_bytes = 0;
b->free_bytes = 16384;
return b;
}
static void
sf_dir_buf_free (struct sf_dir_buf *b)
{
TRACE ();
#ifdef USE_VMALLOC
#else
#endif
kfree (b);
}
void
sf_dir_info_free (struct sf_dir_info *p)
{
TRACE ();
struct sf_dir_buf *b;
sf_dir_buf_free (b);
}
kfree (p);
}
void
sf_dir_info_empty(struct sf_dir_info *p)
{
TRACE ();
struct sf_dir_buf *b;
b->nb_entries = 0;
b->used_bytes = 0;
b->free_bytes = 16384;
}
}
struct sf_dir_info *
sf_dir_info_alloc (void)
{
struct sf_dir_info *p;
TRACE ();
p = kmalloc (sizeof (*p), GFP_KERNEL);
if (!p) {
LogRelFunc(("could not alloc directory info\n"));
return NULL;
}
INIT_LIST_HEAD (&p->info_list);
return p;
}
static struct sf_dir_buf *
{
struct sf_dir_buf *b;
if (!b) {
return NULL;
}
else {
if (b->used_bytes == 0) {
return b;
}
}
}
return NULL;
}
int
{
int err;
struct sf_dir_buf *b;
TRACE ();
if (err) {
goto fail0;
}
for (;;) {
int rc;
void *buf;
b = sf_get_empty_dir_buf (sf_d);
if (!b) {
b = sf_dir_buf_alloc ();
if (!b) {
LogRelFunc(("could not alloc directory buffer\n"));
goto fail1;
}
}
buf_size = b->free_bytes;
rc = vboxCallDirInfo (
mask,
0,
0,
&buf_size,
buf,
);
switch (rc) {
case VINF_SUCCESS:
/* fallthrough */
case VERR_NO_MORE_FILES:
break;
case VERR_NO_TRANSLATION:
LogFunc(("host could not translate entry\n"));
/* XXX */
break;
default:
goto fail1;
}
b->nb_entries += nb_ents;
b->free_bytes -= buf_size;
b->used_bytes += buf_size;
if (RT_FAILURE (rc))
break;
}
return 0;
return err;
}
{
struct sf_glob_info *sf_g;
int rc;
cbBuffer = sizeof(SHFLVolumeInfo);
if (RT_FAILURE(rc))
return -RTErrConvertToErrno(rc);
* that it is not possible to create any more files */
return 0;
}
struct dentry_operations sf_dentry_ops = {
};
{
int rc = 0;
| BDI_CAP_MAP_COPY /* MAP_PRIVATE */
| BDI_CAP_READ_MAP /* can be mapped for reading */
| BDI_CAP_WRITE_MAP /* can be mapped for writing */
| BDI_CAP_EXEC_MAP; /* can be mapped for execution */
# endif /* >= 2.6.12 */
if (!rc)
# endif /* >= 2.6.26 */
# endif /* >= 2.6.24 */
#endif /* >= 2.6.0 */
return rc;
}
{
#endif
}