blob: 3ad64a16bf565511180f1e90ced041d1db924b9f [file] [log] [blame]
/*
* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright CEA/DAM/DIF (2008)
* contributeur : Philippe DENIEL philippe.deniel@cea.fr
* Thomas LEIBOVICI thomas.leibovici@cea.fr
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* ---------------------------------------
*/
/**
* @file cache_inode_create.c
* @brief Creation of a file through the cache layer.
*
* Creation of an entry through the cache layer
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef _SOLARIS
#include "solaris_port.h"
#endif /* _SOLARIS */
#include "log.h"
#include "HashData.h"
#include "HashTable.h"
#include "fsal.h"
#include "cache_inode.h"
#include "cache_inode_lru.h"
#include "cache_inode_weakref.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <time.h>
#include <pthread.h>
#include <assert.h>
/**
* @brief Creates an object in a directory
*
* This function creates an entry in the cache and underlying
* filesystem. If an entry is returned, its refcount charged to the
* call path is +1. An entry is returned for both CACHE_INODE_SUCCESS
* and CACHE_INODE_ENTRY_EXISTS.
*
* @param[in] parent Parent directory
* @param[in] name Name of the object to create
* @param[in] type Type of the object to create
* @param[in] mode Mode to be used at file creation
* @param[in] create_arg Additional argument for object creation
* @param[in] req_ctx Request context
* @param[out] status Returned status
*
* @return Cache entry for the file created or found.
*/
cache_entry_t *
cache_inode_create(cache_entry_t *parent,
const char *name,
object_file_type_t type,
uint32_t mode,
cache_inode_create_arg_t *create_arg,
struct req_op_context *req_ctx,
cache_inode_status_t *status)
{
cache_entry_t *entry = NULL;
fsal_status_t fsal_status = {0, 0};
struct fsal_obj_handle *object_handle;
struct attrlist object_attributes;
struct fsal_obj_handle *dir_handle;
cache_inode_create_arg_t zero_create_arg;
fsal_accessflags_t access_mask = 0;
memset(&zero_create_arg, 0, sizeof(zero_create_arg));
memset(&object_attributes, 0, sizeof(object_attributes));
if (create_arg == NULL) {
create_arg = &zero_create_arg;
}
/* Set the return default to CACHE_INODE_SUCCESS */
*status = CACHE_INODE_SUCCESS;
if ((type != REGULAR_FILE) && (type != DIRECTORY) &&
(type != SYMBOLIC_LINK) && (type != SOCKET_FILE) &&
(type != FIFO_FILE) && (type != CHARACTER_FILE) &&
(type != BLOCK_FILE)) {
*status = CACHE_INODE_BAD_TYPE;
entry = NULL;
goto out;
}
/*
* Check if caller is allowed to perform the operation
*/
access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) |
FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE |
FSAL_ACE_PERM_ADD_SUBDIRECTORY);
*status = cache_inode_access(parent,
access_mask,
req_ctx, status);
if (*status != CACHE_INODE_SUCCESS)
{
entry = NULL;
goto out;
}
/* Check if an entry of the same name exists */
entry = cache_inode_lookup(parent,
name,
req_ctx,
status);
if (entry != NULL) {
*status = CACHE_INODE_ENTRY_EXISTS;
if (entry->type != type) {
/* Incompatible types, returns NULL */
cache_inode_lru_unref(entry, LRU_FLAG_NONE);
entry = NULL;
goto out;
} else {
goto out;
}
}
/* The entry doesn't exist, so we can create it. */
dir_handle = parent->obj_handle;
/* we pass in attributes to the create. We will get them back below */
FSAL_SET_MASK(object_attributes.mask, ATTR_MODE|ATTR_OWNER|ATTR_GROUP);
object_attributes.owner = req_ctx->creds->caller_uid;
object_attributes.group = req_ctx->creds->caller_gid; /* be more selective? */
object_attributes.mode = mode;
switch (type) {
case REGULAR_FILE:
fsal_status = dir_handle->ops->create(dir_handle, req_ctx,
name,
&object_attributes,
&object_handle);
break;
case DIRECTORY:
fsal_status = dir_handle->ops->mkdir(dir_handle, req_ctx,
name,
&object_attributes,
&object_handle);
break;
case SYMBOLIC_LINK:
fsal_status = dir_handle->ops->symlink(dir_handle, req_ctx,
name,
create_arg->link_content,
&object_attributes,
&object_handle);
break;
case SOCKET_FILE:
case FIFO_FILE:
fsal_status = dir_handle->ops->mknode(dir_handle, req_ctx,
name,
type,
NULL, /* no dev_t needed */
&object_attributes,
&object_handle);
break;
case BLOCK_FILE:
case CHARACTER_FILE:
fsal_status = dir_handle->ops->mknode(dir_handle, req_ctx,
name,
type,
&create_arg->dev_spec,
&object_attributes,
&object_handle);
break;
default:
/* we should never go there */
*status = CACHE_INODE_INCONSISTENT_ENTRY;
entry = NULL;
goto out;
break;
}
/* Check for the result */
if (FSAL_IS_ERROR(fsal_status)) {
if (fsal_status.major == ERR_FSAL_STALE) {
cache_inode_kill_entry(parent);
}
*status = cache_inode_error_convert(fsal_status);
entry = NULL;
goto out;
}
entry = cache_inode_new_entry(object_handle,
CACHE_INODE_FLAG_CREATE,
status);
if (entry == NULL) {
goto out;
}
pthread_rwlock_wrlock(&parent->content_lock);
/* Add this entry to the directory (also takes an internal ref) */
cache_inode_add_cached_dirent(parent,
name, entry,
NULL,
status);
pthread_rwlock_unlock(&parent->content_lock);
if (*status != CACHE_INODE_SUCCESS) {
cache_inode_lru_unref(entry, LRU_FLAG_NONE);
entry = NULL;
goto out;
}
pthread_rwlock_wrlock(&parent->attr_lock);
/* Update the parent cached attributes */
cache_inode_set_time_current(&parent->obj_handle->attributes.mtime);
parent->obj_handle->attributes.ctime
= parent->obj_handle->attributes.mtime;
/* if the created object is a directory, it contains a link
to its parent : '..'. Thus the numlink attr must be increased. */
if (type == DIRECTORY) {
++(parent->obj_handle->attributes.numlinks);
}
pthread_rwlock_unlock(&parent->attr_lock);
*status = CACHE_INODE_SUCCESS;
out:
return entry;
}