dirops.c revision eaaf3e046ba9d319f5a391f7eccaa7b45c69bc92
/** @file
*
* vboxsf -- VirtualBox Guest Additions for Linux:
* Directory 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.
*/
#include "vfsmod.h"
/**
* Open a directory. Read the complete content into a buffer.
*
* @param inode inode
* @param file file
* @returns 0 on success, Linux error code otherwise
*/
{
int rc;
int err;
struct sf_dir_info *sf_d;
TRACE();
if (file->private_data)
{
LogFunc(("sf_dir_open() called on already opened directory '%s'\n",
return 0;
}
sf_d = sf_dir_info_alloc();
if (!sf_d)
{
LogRelFunc(("could not allocate directory info for '%s'\n",
return -ENOMEM;
}
params.CreateFlags = 0
;
LogFunc(("sf_dir_open(): calling vboxCallCreate, folder %s, flags %#x\n",
if (RT_SUCCESS(rc))
{
{
if (!err)
}
else
if (RT_FAILURE(rc))
LogFunc(("sf_dir_open(): vboxCallClose(%s) after err=%d failed rc=%Rrc\n",
}
else
if (err)
return err;
}
/**
* This is called when reference count of [file] goes to zero. Notify
* the host that it can free whatever is associated with this directory
* and deallocate our own internal buffers
*
* @param inode inode
* @param file file
* returns 0 on success, Linux error code otherwise
*/
{
TRACE();
if (file->private_data)
return 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.
*/
{
struct sf_glob_info *sf_g;
struct sf_dir_info *sf_d;
struct sf_inode_info *sf_i;
TRACE();
if (sf_i->force_reread)
{
int rc;
int err;
params.CreateFlags = 0
;
LogFunc(("sf_getdent: calling vboxCallCreate, folder %s, flags %#x\n",
if (RT_FAILURE(rc))
{
LogFunc(("vboxCallCreate(%s) failed rc=%Rrc\n",
return -EPERM;
}
{
return -ENOENT;
}
if (RT_FAILURE(rc))
if (err)
return err;
sf_i->force_reread = 0;
}
cur = 0;
{
struct sf_dir_buf *b;
loff_t i;
{
continue;
}
{
}
}
return 1;
}
/**
* This is called when vfs wants to populate internal buffers with
* directory [dir]s contents. [opaque] is an argument to the
* [filldir]. [filldir] magically modifies it's argument - [opaque]
* and takes following additional arguments (which i in turn get from
* the host via sf_getdent):
*
* name : name of the entry (i must also supply it's length huh?)
* type : type of the entry (FILE | DIR | etc) (i ellect to use DT_UNKNOWN)
* ino : inode number of the entry (i fake those)
*
* [dir] contains:
* f_pos : cursor into the directory listing
* private_data : mean of communication with the host side
*
* Extract elements from the directory listing (incrementing f_pos
* along the way) and feed them to [filldir] until:
*
* a. there are no more entries (i.e. sf_getdent set done to 1)
* b. failure to compute fake inode number
* c. filldir returns an error (see comment on that)
*/
{
TRACE();
for (;;)
{
int err;
switch (err)
{
case 1:
return 0;
case 0:
break;
case -1:
default:
/* skip erroneous entry and proceed */
continue;
}
/* d_name now contains a valid entry name */
{
LogRelFunc(("can not compute ino\n"));
return -EINVAL;
}
if (err)
{
/* Rely on the fact that filldir returns error
only when it runs out of space in opaque */
return 0;
}
}
BUG();
}
struct file_operations sf_dir_fops =
{
.open = sf_dir_open,
.readdir = sf_dir_read,
#endif
};
/* iops */
/**
* 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
*/
, unsigned int flags
#endif
)
{
int err;
struct sf_glob_info *sf_g;
TRACE();
if (err)
goto fail0;
if (err)
{
{
/* -ENOENT: add NULL inode to dentry so it later can be
}
else
goto fail1;
}
else
{
if (!sf_new_i)
{
LogRelFunc(("could not allocate memory for new inode info\n"));
goto fail1;
}
sf_new_i->force_reread = 0;
#else
#endif
if (!inode)
{
LogFunc(("iget failed\n"));
goto fail2;
}
#endif
}
sf_i->force_restat = 0;
#else
#endif
return NULL;
}
/**
* This should allocate memory for sf_inode_info, compute a unique inode
* number, get an inode from vfs, initialize inode info, instantiate
* dentry.
*
* @param parent inode entry of the directory
* @param dentry directory cache entry
* @param path path name
* @param info file information
* @param handle handle
* @returns 0 on success, Linux error code otherwise
*/
{
int err;
struct sf_inode_info *sf_new_i;
TRACE();
if (!sf_new_i)
{
LogRelFunc(("could not allocate inode info.\n"));
goto fail0;
}
#else
#endif
if (!inode)
{
LogFunc(("iget failed\n"));
goto fail1;
}
#else
#endif
sf_new_i->force_reread = 0;
#endif
/* Store this handle if we leave the handle open. */
return 0;
return err;
}
/**
* 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
*/
{
TRACE();
if (err)
goto fail0;
params.CreateFlags = 0
| (fDirectory ? SHFL_CF_DIRECTORY : 0)
;
;
LogFunc(("sf_create_aux: calling vboxCallCreate, folder %s, flags %#x\n",
if (RT_FAILURE(rc))
{
if (rc == VERR_WRITE_PROTECT)
{
goto fail1;
}
LogFunc(("(%d): vboxCallCreate(%s) failed rc=%Rrc\n",
goto fail1;
}
{
LogFunc(("(%d): could not create file %s result=%d\n",
goto fail1;
}
if (err)
{
LogFunc(("(%d): could not instantiate dentry for %s err=%d\n",
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)
{
if (RT_FAILURE(rc))
}
return 0;
if (RT_FAILURE(rc))
return err;
}
/**
* Create a new regular file.
*
* @param parent inode of the directory
* @param dentry directory cache entry
* @param mode file mode
* @returns 0 on success, Linux error code otherwise
*/
static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode, struct nameidata *nd)
#else
#endif
{
TRACE();
}
/**
* Create a new directory.
*
* @param parent inode of the directory
* @param dentry directory cache entry
* @param mode file mode
* @returns 0 on success, Linux error code otherwise
*/
#else
#endif
{
TRACE();
}
/**
* 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
*/
{
TRACE();
if (err)
goto fail0;
if ( dentry
if (RT_FAILURE(rc))
{
goto fail1;
}
/* directory content changed */
err = 0;
return err;
}
/**
* Remove a regular file.
*
* @param parent inode of the directory
* @param dentry directory cache entry
* @returns 0 on success, Linux error code otherwise
*/
{
TRACE();
}
/**
* Remove a directory.
*
* @param parent inode of the directory
* @param dentry directory cache entry
* @returns 0 on success, Linux error code otherwise
*/
{
TRACE();
}
/**
* 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
*/
{
TRACE();
{
LogFunc(("rename with different roots\n"));
}
else
{
/* As we save the relative path inside the inode structure, we need to change
this if the rename is successful. */
new_dentry, &new_path);
if (err)
LogFunc(("failed to create new path\n"));
else
{
if (RT_SUCCESS(rc))
{
/* Set the new relative path in the inode. */
}
else
{
}
}
}
return err;
}
{
int err;
int rc;
struct sf_inode_info *sf_i;
struct sf_glob_info *sf_g;
TRACE();
if (err)
goto fail0;
if (!ssymname)
{
LogRelFunc(("kmalloc failed, caller=sf_symlink\n"));
goto fail1;
}
if (RT_FAILURE(rc))
{
if (rc == VERR_WRITE_PROTECT)
{
goto fail1;
}
LogFunc(("vboxCallSymlink(%s) failed rc=%Rrc\n",
goto fail1;
}
if (err)
{
LogFunc(("could not instantiate dentry for %s err=%d\n",
goto fail1;
}
return 0;
return err;
}
#endif
struct inode_operations sf_dir_iops =
{
#else
.getattr = sf_getattr,
.setattr = sf_setattr,
#endif
};