示例#1
0
int _9p_rename(struct _9p_request_data *req9p, void *worker_data,
	       u32 *plenout, char *preply)
{
	char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;

	u16 *msgtag = NULL;
	u32 *fid = NULL;
	u32 *dfid = NULL;
	u16 *name_len = NULL;
	char *name_str = NULL;	/* for unused-but-set-variable */
	struct _9p_fid *pfid = NULL;
	struct _9p_fid *pdfid = NULL;

	char newname[MAXNAMLEN];
	cache_inode_status_t cache_status;

	/* Get data */
	_9p_getptr(cursor, msgtag, u16);
	_9p_getptr(cursor, fid, u32);
	_9p_getptr(cursor, dfid, u32);
	_9p_getstr(cursor, name_len, name_str);

	LogDebug(COMPONENT_9P, "TRENAME: tag=%u fid=%u dfid=%u name=%.*s",
		 (u32) *msgtag, *fid, *dfid, *name_len, name_str);

	if (*fid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout,
				  preply);

	pfid = req9p->pconn->fids[*fid];

	/* Check that it is a valid fid */
	if (pfid == NULL || pfid->pentry == NULL) {
		LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
		return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout,
				  preply);
	}

	if (*dfid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout,
				  preply);

	pdfid = req9p->pconn->fids[*dfid];

	/* Check that it is a valid fid */
	if (pdfid == NULL || pdfid->pentry == NULL) {
		LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
		return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout,
				  preply);
	}

	snprintf(newname, MAXNAMLEN, "%.*s", *name_len, name_str);

	cache_status =
	    cache_inode_rename(pfid->ppentry, pfid->name, pdfid->pentry,
			       newname, &pfid->op_context);
	if (cache_status != CACHE_INODE_SUCCESS)
		return _9p_rerror(req9p, worker_data, msgtag,
				  _9p_tools_errno(cache_status), plenout,
				  preply);

	/* Build the reply */
	_9p_setinitptr(cursor, preply, _9P_RRENAME);
	_9p_setptr(cursor, msgtag, u16);

	_9p_setendptr(cursor, preply);
	_9p_checkbound(cursor, preply, plenout);

	LogDebug(COMPONENT_9P, "RRENAMEAT: tag=%u fid=%u dfid=%u newname=%.*s",
		 (u32) *msgtag, *fid, *dfid, *name_len, name_str);

	/*  _9p_stat_update(*pmsgtype, TRUE, &pwkrdata->stats._9p_stat_req); */
	return 1;
}
示例#2
0
int _9p_renameat( _9p_request_data_t * preq9p, 
                void  * pworker_data,
                u32 * plenout, 
                char * preply)
{
  char * cursor = preq9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE ;

  u16  * msgtag      = NULL ;
  u32  * oldfid      = NULL ;
  u16  * oldname_len = NULL ;
  char * oldname_str = NULL ;
  u32  * newfid      = NULL ;
  u16  * newname_len = NULL ;
  char * newname_str = NULL ;

  _9p_fid_t * poldfid = NULL ;
  _9p_fid_t * pnewfid = NULL ;

  fsal_attrib_list_t    oldfsalattr ;
  fsal_attrib_list_t    newfsalattr ;

  cache_inode_status_t  cache_status ;

  fsal_name_t           oldname ;
  fsal_name_t           newname ;

  if ( !preq9p || !pworker_data || !plenout || !preply )
   return -1 ;

  /* Get data */
  _9p_getptr( cursor, msgtag, u16 ) ; 

  _9p_getptr( cursor, oldfid,   u32 ) ; 
  _9p_getstr( cursor, oldname_len, oldname_str ) ;
  _9p_getptr( cursor, newfid,   u32 ) ; 
  _9p_getstr( cursor, newname_len, newname_str ) ;

  LogDebug( COMPONENT_9P, "TRENAMEAT: tag=%u oldfid=%u oldname=%.*s newfid=%u newname=%.*s",
            (u32)*msgtag, *oldfid, *oldname_len, oldname_str, *newfid, *newname_len, newname_str ) ;

  if( *oldfid >= _9P_FID_PER_CONN )
   return _9p_rerror( preq9p, msgtag, ERANGE, plenout, preply ) ;

  poldfid = &preq9p->pconn->fids[*oldfid] ;

  if( *newfid >= _9P_FID_PER_CONN )
   return _9p_rerror( preq9p, msgtag, ERANGE, plenout, preply ) ;

  pnewfid = &preq9p->pconn->fids[*newfid] ;

  /* Let's do the job */
  snprintf( oldname.name, FSAL_MAX_NAME_LEN, "%.*s", *oldname_len, oldname_str ) ;
  oldname.len = *oldname_len + 1 ;
  snprintf( newname.name, FSAL_MAX_NAME_LEN, "%.*s", *newname_len, newname_str ) ;
  newname.len = *newname_len + 1 ;

  if( cache_inode_rename( poldfid->pentry,
                          &oldname,
                          pnewfid->pentry,
                          &newname,
                          &oldfsalattr,
                          &newfsalattr,
                          &poldfid->fsal_op_context, 
                          &cache_status) != CACHE_INODE_SUCCESS )
    return _9p_rerror( preq9p, msgtag, _9p_tools_errno( cache_status ), plenout, preply ) ;

  /* Build the reply */
  _9p_setinitptr( cursor, preply, _9P_RRENAMEAT ) ;
  _9p_setptr( cursor, msgtag, u16 ) ;

  _9p_setendptr( cursor, preply ) ;
  _9p_checkbound( cursor, preply, plenout ) ;

  LogDebug( COMPONENT_9P, "RRENAMEAT: tag=%u oldfid=%u oldname=%.*s newfid=%u newname=%.*s",
            (u32)*msgtag, *oldfid, *oldname_len, oldname_str, *newfid, *newname_len, newname_str ) ;

  return 1 ;
}
示例#3
0
int nfs3_rename(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res)
{
	const char *entry_name = arg->arg_rename3.from.name;
	const char *new_entry_name = arg->arg_rename3.to.name;
	cache_entry_t *parent_entry = NULL;
	cache_entry_t *new_parent_entry = NULL;
	cache_inode_status_t cache_status;
	short to_exportid = 0;
	short from_exportid = 0;
	int rc = NFS_REQ_OK;

	pre_op_attr pre_parent = {
		.attributes_follow = false
	};
	pre_op_attr pre_new_parent = {
		.attributes_follow = false
	};

	if (isDebug(COMPONENT_NFSPROTO)) {
		char strto[LEN_FH_STR], strfrom[LEN_FH_STR];

		nfs_FhandleToStr(req->rq_vers,
				 &arg->arg_rename3.from.dir,
				 NULL,
				 strfrom);

		nfs_FhandleToStr(req->rq_vers,
				 &arg->arg_rename3.to.dir,
				 NULL,
				 strto);

		LogDebug(COMPONENT_NFSPROTO,
			 "REQUEST PROCESSING: Calling nfs_Rename from handle: %s name %s to handle: %s name: %s",
			 strfrom, entry_name, strto, new_entry_name);
	}

	/* to avoid setting it on each error case */
	res->res_rename3.RENAME3res_u.resfail.fromdir_wcc.before.
	    attributes_follow = FALSE;
	res->res_rename3.RENAME3res_u.resfail.fromdir_wcc.after.
	    attributes_follow = FALSE;
	res->res_rename3.RENAME3res_u.resfail.todir_wcc.before.
	    attributes_follow = FALSE;
	res->res_rename3.RENAME3res_u.resfail.todir_wcc.after.
	    attributes_follow = FALSE;

	/* Get the exportids for the two handles. */
	to_exportid = nfs3_FhandleToExportId(&(arg->arg_rename3.to.dir));
	from_exportid = nfs3_FhandleToExportId(&(arg->arg_rename3.from.dir));

	/* Validate the to_exportid */
	if (to_exportid < 0 || from_exportid < 0) {
		LogInfo(COMPONENT_DISPATCH,
			"NFS%d RENAME Request from client %s has badly formed handle for to dir",
			req->rq_vers,
			op_ctx->client
				? op_ctx->client->hostaddr_str
				: "unknown client");

		/* Bad handle, report to client */
		res->res_rename3.status = NFS3ERR_BADHANDLE;
		goto out;
	}

	/* Both objects have to be in the same filesystem */
	if (to_exportid != from_exportid) {
		res->res_rename3.status = NFS3ERR_XDEV;
		goto out;
	}

	/* Convert fromdir file handle into a cache_entry */
	parent_entry = nfs3_FhandleToCache(&arg->arg_rename3.from.dir,
					   &res->res_create3.status,
					   &rc);

	if (parent_entry == NULL) {
		/* Status and rc have been set by nfs3_FhandleToCache */
		goto out;
	}

	nfs_SetPreOpAttr(parent_entry, &pre_parent);

	/* Convert todir file handle into a cache_entry */
	new_parent_entry = nfs3_FhandleToCache(&arg->arg_rename3.to.dir,
					       &res->res_create3.status,
					       &rc);

	if (new_parent_entry == NULL) {
		/* Status and rc have been set by nfs3_FhandleToCache */
		goto out;
	}

	nfs_SetPreOpAttr(new_parent_entry, &pre_new_parent);

	if (entry_name == NULL || *entry_name == '\0' || new_entry_name == NULL
	    || *new_entry_name == '\0') {
		cache_status = CACHE_INODE_INVALID_ARGUMENT;
		goto out_fail;
	}

	cache_status = cache_inode_rename(parent_entry,
					  entry_name,
					  new_parent_entry,
					  new_entry_name);

	if (cache_status != CACHE_INODE_SUCCESS)
		goto out_fail;

	res->res_rename3.status = NFS3_OK;

	nfs_SetWccData(&pre_parent, parent_entry,
		       &res->res_rename3.RENAME3res_u.resok.fromdir_wcc);

	nfs_SetWccData(&pre_new_parent, new_parent_entry,
		       &res->res_rename3.RENAME3res_u.resok.todir_wcc);

	rc = NFS_REQ_OK;

	goto out;

 out_fail:
	res->res_rename3.status = nfs3_Errno(cache_status);

	nfs_SetWccData(&pre_parent, parent_entry,
		       &res->res_rename3.RENAME3res_u.resfail.fromdir_wcc);

	nfs_SetWccData(&pre_new_parent, new_parent_entry,
		       &res->res_rename3.RENAME3res_u.resfail.todir_wcc);

	/* If we are here, there was an error */
	if (nfs_RetryableError(cache_status))
		rc = NFS_REQ_DROP;

 out:
	if (parent_entry)
		cache_inode_put(parent_entry);

	if (new_parent_entry)
		cache_inode_put(new_parent_entry);

	return rc;
}

/**
 * @brief Free the result structure allocated for nfs3_rename.
 *
 * This function frees the result structure allocated for nfs3_rename.
 *
 * @param[in,out] res Result structure
 *
 */
void nfs3_rename_free(nfs_res_t *res)
{
	/* Nothing to do here */
}
示例#4
0
int nfs4_op_rename(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_rename";

  cache_entry_t        * dst_entry = NULL;
  cache_entry_t        * src_entry = NULL;
  cache_entry_t        * tst_entry_dst = NULL;
  cache_entry_t        * tst_entry_src = NULL;
  fsal_attrib_list_t     attr_dst;
  fsal_attrib_list_t     attr_src;
  fsal_attrib_list_t     attr_tst_dst;
  fsal_attrib_list_t     attr_tst_src;
  cache_inode_status_t   cache_status;
  fsal_status_t          fsal_status;
  fsal_handle_t        * handlenew = NULL;
  fsal_handle_t        * handleold = NULL;
  fsal_name_t            oldname;
  fsal_name_t            newname;

  resp->resop = NFS4_OP_RENAME;
  res_RENAME4.status = NFS4_OK;

  /* Do basic checks on a filehandle */
  res_RENAME4.status = nfs4_sanity_check_FH(data, 0LL);
  if(res_RENAME4.status != NFS4_OK)
    return res_RENAME4.status;

  /* Do basic checks on saved filehandle */

  /* If there is no FH */
  if(nfs4_Is_Fh_Empty(&(data->savedFH)))
    {
      res_RENAME4.status = NFS4ERR_NOFILEHANDLE;
      return res_RENAME4.status;
    }

  /* If the filehandle is invalid */
  if(nfs4_Is_Fh_Invalid(&(data->savedFH)))
    {
      res_RENAME4.status = NFS4ERR_BADHANDLE;
      return res_RENAME4.status;
    }

  /* Tests if the Filehandle is expired (for volatile filehandle) */
  if(nfs4_Is_Fh_Expired(&(data->savedFH)))
    {
      res_RENAME4.status = NFS4ERR_FHEXPIRED;
      return res_RENAME4.status;
    }

  /* Pseudo Fs is explictely a Read-Only File system */
  if(nfs4_Is_Fh_Pseudo(&(data->savedFH)))
    {
      res_RENAME4.status = NFS4ERR_ROFS;
      return res_RENAME4.status;
    }

  if (nfs_in_grace())
    {
      res_RENAME4.status = NFS4ERR_GRACE;
      return res_RENAME4.status;
    }

  /* get the names from the RPC input */
  cache_status = utf8_to_name(&arg_RENAME4.oldname, &oldname);

  if(cache_status != CACHE_INODE_SUCCESS)
    {
      res_RENAME4.status = nfs4_Errno(cache_status);
      return res_RENAME4.status;
    }

  cache_status = utf8_to_name(&arg_RENAME4.newname, &newname);

  if(cache_status != CACHE_INODE_SUCCESS)
    {
      res_RENAME4.status = nfs4_Errno(cache_status);
      return res_RENAME4.status;
    }

  /* Sanuty check: never rename to '.' or '..' */
  if(!FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT)
     || !FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT_DOT))
    {
      res_RENAME4.status = NFS4ERR_BADNAME;
      return res_RENAME4.status;
    }

  /* Sanuty check: never rename to '.' or '..' */
  if(!FSAL_namecmp(&oldname, (fsal_name_t *) & FSAL_DOT)
     || !FSAL_namecmp(&oldname, (fsal_name_t *) & FSAL_DOT_DOT))
    {
      res_RENAME4.status = NFS4ERR_BADNAME;
      return res_RENAME4.status;
    }

  /*
   * This operation renames 
   *             - the object in directory pointed by savedFH, named arg_RENAME4.oldname
   *       into
   *             - an object in directory pointed by currentFH, named arg_RENAME4.newname
   *
   * Because of this, we will use 2 entry and we have verified both currentFH and savedFH */

  /* No Cross Device */
  if(((file_handle_v4_t *) (data->currentFH.nfs_fh4_val))->exportid !=
     ((file_handle_v4_t *) (data->savedFH.nfs_fh4_val))->exportid)
    {
      res_RENAME4.status = NFS4ERR_XDEV;
      return res_RENAME4.status;
    }

  /* destination must be a directory */
  dst_entry = data->current_entry;

  if(data->current_filetype != DIRECTORY)
    {
      res_RENAME4.status = NFS4ERR_NOTDIR;
      return res_RENAME4.status;
    }

  /* Convert saved FH into a vnode */
  src_entry = data->saved_entry;

  /* Source must be a directory */
  if(data->saved_filetype != DIRECTORY)
    {
      res_RENAME4.status = NFS4ERR_NOTDIR;
      return res_RENAME4.status;
    }

  /* Renaming a file to himself is allowed, returns NFS4_OK */
  if(src_entry == dst_entry)
    {
      if(!FSAL_namecmp(&oldname, &newname))
        {
          res_RENAME4.status = NFS4_OK;
          return res_RENAME4.status;
        }
    }

  /* For the change_info4, get the 'change' attributes for both directories */
  if((cache_status = cache_inode_getattr(src_entry,
                                         &attr_src,
                                         data->pcontext,
                                         &cache_status)) != CACHE_INODE_SUCCESS)
    {
      res_RENAME4.status = nfs4_Errno(cache_status);
      return res_RENAME4.status;
    }
#ifdef BUGAZOMEU
  /* Ne devrait pas se produire dans le cas de exportid differents */

  /* Both object must resides on the same filesystem, return NFS4ERR_XDEV if not */
  if(attr_src.va_rdev != attr_dst.va_rdev)
    {
      res_RENAME4.status = NFS4ERR_XDEV;
      return res_RENAME4.status;
    }
#endif
  /* Lookup oldfile to see if it exists (refcount +1) */
  if((tst_entry_src = cache_inode_lookup(src_entry,
                                         &oldname,
                                         &attr_tst_src,
                                         data->pcontext,
                                         &cache_status)) == NULL)
    {
      res_RENAME4.status = nfs4_Errno(cache_status);
      goto release;
    }

  /* Lookup file with new name to see if it already exists (refcount +1),
   * I expect to get NO_ERROR or ENOENT, anything else means an error */
  tst_entry_dst = cache_inode_lookup(dst_entry,
                                     &newname,
                                     &attr_tst_dst,
                                     data->pcontext,
                                     &cache_status);
  if((cache_status != CACHE_INODE_SUCCESS) &&
     (cache_status != CACHE_INODE_NOT_FOUND))
    {
        /* Unexpected status at this step, exit with an error */
        res_RENAME4.status = nfs4_Errno(cache_status);
        goto release;
    }

  if(cache_status == CACHE_INODE_NOT_FOUND)
    tst_entry_dst = NULL;       /* Just to make sure */

  /* Renaming a file to one of its own hardlink is allowed, return NFS4_OK */
  if(tst_entry_src == tst_entry_dst) {
      res_RENAME4.status = NFS4_OK;
      goto release;
    }

  /* Renaming dir into existing file should return NFS4ERR_EXIST */
  if ((tst_entry_src->type == DIRECTORY) &&
      ((tst_entry_dst != NULL) &&
       (tst_entry_dst->type == REGULAR_FILE)))
    {
      res_RENAME4.status = NFS4ERR_EXIST;
      goto release;
    }

  /* Renaming file into existing dir should return NFS4ERR_EXIST */
  if(tst_entry_src->type == REGULAR_FILE)
    {
      if(tst_entry_dst != NULL)
        {
          if(tst_entry_dst->type == DIRECTORY)
            {
              res_RENAME4.status = NFS4ERR_EXIST;
              goto release;
            }
        }
    }

  /* Renaming dir1 into existing, nonempty dir2 should return NFS4ERR_EXIST
   * Renaming file into existing, nonempty dir should return NFS4ERR_EXIST */
  if(tst_entry_dst != NULL)
    {
      if((tst_entry_dst->type == DIRECTORY)
         && ((tst_entry_src->type == DIRECTORY)
             || (tst_entry_src->type == REGULAR_FILE)))
        {
          if(cache_inode_is_dir_empty_WithLock(tst_entry_dst) ==
             CACHE_INODE_DIR_NOT_EMPTY)
            {
              res_RENAME4.status = NFS4ERR_EXIST;
              goto release;
            }
        }
    }

  res_RENAME4.RENAME4res_u.resok4.source_cinfo.before
       = cache_inode_get_changeid4(src_entry);
  res_RENAME4.RENAME4res_u.resok4.target_cinfo.before
       = cache_inode_get_changeid4(dst_entry);

  if(cache_status == CACHE_INODE_SUCCESS)
    {
      /* New entry already exists, its attributes are in attr_tst_*,
         check for old entry to see if types are compatible */
      handlenew = &tst_entry_dst->handle;
      handleold = &tst_entry_src->handle;

      if(!FSAL_handlecmp(handlenew, handleold, &fsal_status))
        {
          /* For the change_info4, get the 'change' attributes for both directories */
          res_RENAME4.RENAME4res_u.resok4.source_cinfo.before
            = cache_inode_get_changeid4(src_entry);
          res_RENAME4.RENAME4res_u.resok4.target_cinfo.before
            = cache_inode_get_changeid4(dst_entry);
          res_RENAME4.RENAME4res_u.resok4.target_cinfo.atomic = FALSE;
          res_RENAME4.RENAME4res_u.resok4.source_cinfo.atomic = FALSE;

          res_RENAME4.status = NFS4_OK;
          goto release;
        }
      else
        {
          /* Destination exists and is something different from source */
          if(( tst_entry_src->type == REGULAR_FILE &&
              tst_entry_dst->type == REGULAR_FILE ) ||
              ( tst_entry_src->type == DIRECTORY &&
              tst_entry_dst->type == DIRECTORY ))
            {
              if(cache_inode_rename(src_entry,
                                    &oldname,
                                    dst_entry,
                                    &newname,
                                    &attr_src,
                                    &attr_dst,
                                    data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
               {

                 res_RENAME4.status = nfs4_Errno(cache_status);
                 goto release;
               }
            }
          else
            { 
              res_RENAME4.status = NFS4ERR_EXIST;
              goto release;
            }
        }
    }
  else
    {
      /* New entry does not already exist, call cache_entry_rename */
      if(cache_inode_rename(src_entry,
                            &oldname,
                            dst_entry,
                            &newname,
                            &attr_src,
                            &attr_dst,
                            data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
        {
          res_RENAME4.status = nfs4_Errno(cache_status);
          goto release;
        }
    }

  /* If you reach this point, then everything was alright */
  /* For the change_info4, get the 'change' attributes for both directories */

  res_RENAME4.RENAME4res_u.resok4.source_cinfo.after =
       cache_inode_get_changeid4(src_entry);
  res_RENAME4.RENAME4res_u.resok4.target_cinfo.after =
       cache_inode_get_changeid4(dst_entry);
  res_RENAME4.RENAME4res_u.resok4.target_cinfo.atomic = FALSE;
  res_RENAME4.RENAME4res_u.resok4.source_cinfo.atomic = FALSE;
  res_RENAME4.status = nfs4_Errno(cache_status);

release:
  if (tst_entry_src)
      (void) cache_inode_put(tst_entry_src);
  if (tst_entry_dst)
      (void) cache_inode_put(tst_entry_dst);

  return (res_RENAME4.status);
}                               /* nfs4_op_rename */
示例#5
0
int nfs_Rename(nfs_arg_t * parg /* IN  */ ,
               exportlist_t * pexport /* IN  */ ,
               fsal_op_context_t * pcontext /* IN  */ ,
               cache_inode_client_t * pclient /* IN  */ ,
               hash_table_t * ht /* INOUT */ ,
               struct svc_req *preq /* IN  */ ,
               nfs_res_t * pres /* OUT */ )
{
  static char __attribute__ ((__unused__)) funcName[] = "nfs_Rename";

  char *str_entry_name = NULL;
  fsal_name_t entry_name;
  char *str_new_entry_name = NULL;
  fsal_name_t new_entry_name;
  cache_entry_t *pentry = NULL;
  cache_entry_t *new_pentry = NULL;
  cache_entry_t *parent_pentry = NULL;
  cache_entry_t *new_parent_pentry = NULL;
  cache_entry_t *should_not_exists = NULL;
  cache_entry_t *should_exists = NULL;
  cache_inode_status_t cache_status;
  int rc;
  fsal_attrib_list_t *ppre_attr;
  fsal_attrib_list_t pre_attr;
  fsal_attrib_list_t *pnew_pre_attr;
  fsal_attrib_list_t new_attr;
  fsal_attrib_list_t new_parent_attr;
  fsal_attrib_list_t attr;
  fsal_attrib_list_t tst_attr;
  cache_inode_file_type_t parent_filetype;
  cache_inode_file_type_t new_parent_filetype;

  if(preq->rq_vers == NFS_V3)
    {
      /* to avoid setting it on each error case */
      pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc.before.attributes_follow = FALSE;
      pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc.after.attributes_follow = FALSE;
      pres->res_rename3.RENAME3res_u.resfail.todir_wcc.before.attributes_follow = FALSE;
      pres->res_rename3.RENAME3res_u.resfail.todir_wcc.after.attributes_follow = FALSE;
      ppre_attr = NULL;
      pnew_pre_attr = NULL;
    }

  /* Convert fromdir file handle into a cache_entry */
  if((parent_pentry = nfs_FhandleToCache(preq->rq_vers,
                                         &(parg->arg_rename2.from.dir),
                                         &(parg->arg_rename3.from.dir),
                                         NULL,
                                         &(pres->res_dirop2.status),
                                         &(pres->res_create3.status),
                                         NULL,
                                         &pre_attr, pcontext, pclient, ht, &rc)) == NULL)
    {
      /* Stale NFS FH ? */
      return rc;
    }

  /* Convert todir file handle into a cache_entry */
  if((new_parent_pentry = nfs_FhandleToCache(preq->rq_vers,
                                             &(parg->arg_rename2.to.dir),
                                             &(parg->arg_rename3.to.dir),
                                             NULL,
                                             &(pres->res_dirop2.status),
                                             &(pres->res_create3.status),
                                             NULL,
                                             &new_parent_attr,
                                             pcontext, pclient, ht, &rc)) == NULL)
    {
      /* Stale NFS FH ? */
      return rc;
    }

  /* get the attr pointers */
  ppre_attr = &pre_attr;
  pnew_pre_attr = &new_parent_attr;

  /* Get the filetypes */
  parent_filetype = cache_inode_fsal_type_convert(pre_attr.type);
  new_parent_filetype = cache_inode_fsal_type_convert(new_parent_attr.type);

  /*
   * Sanity checks: we must manage directories
   */
  if((parent_filetype != DIR_BEGINNING && parent_filetype != DIR_CONTINUE) ||
     (new_parent_filetype != DIR_BEGINNING && new_parent_filetype != DIR_CONTINUE))
    {
      switch (preq->rq_vers)
        {
        case NFS_V2:
          pres->res_stat2 = NFSERR_NOTDIR;
          break;

        case NFS_V3:
          pres->res_rename3.status = NFS3ERR_NOTDIR;
          break;
        }

      return NFS_REQ_OK;
    }

  switch (preq->rq_vers)
    {
    case NFS_V2:
      str_entry_name = parg->arg_rename2.from.name;
      str_new_entry_name = parg->arg_rename2.to.name;
      break;

    case NFS_V3:
      str_entry_name = parg->arg_rename3.from.name;
      str_new_entry_name = parg->arg_rename3.to.name;
      break;
    }

  pentry = new_pentry = NULL;

  if(str_entry_name == NULL ||
     strlen(str_entry_name) == 0 ||
     str_new_entry_name == NULL ||
     strlen(str_new_entry_name) == 0 ||
     FSAL_IS_ERROR(FSAL_str2name(str_entry_name, FSAL_MAX_NAME_LEN, &entry_name)) ||
     FSAL_IS_ERROR(FSAL_str2name(str_new_entry_name, FSAL_MAX_NAME_LEN, &new_entry_name)))
    {
      cache_status = CACHE_INODE_INVALID_ARGUMENT;
    }
  else
    {
      /*
       * Lookup file to see if new entry exists
       *
       */
      should_not_exists = cache_inode_lookup(new_parent_pentry,
                                             &new_entry_name,
                                             &tst_attr,
                                             ht, pclient, pcontext, &cache_status);

      if(cache_status == CACHE_INODE_NOT_FOUND)
        {
          /* We need to lookup over the old entry also */
          should_exists = cache_inode_lookup(parent_pentry,
                                             &entry_name,
                                             &tst_attr,
                                             ht, pclient, pcontext, &cache_status);

          /* Rename entry */
          if(cache_status == CACHE_INODE_SUCCESS)
            cache_inode_rename(parent_pentry,
                               &entry_name,
                               new_parent_pentry,
                               &new_entry_name,
                               &attr, &new_attr, ht, pclient, pcontext, &cache_status);

          if(cache_status == CACHE_INODE_SUCCESS)
            {
              switch (preq->rq_vers)
                {
                case NFS_V2:
                  pres->res_stat2 = NFS_OK;
                  break;

                case NFS_V3:
                  /*
                   * Build Weak Cache Coherency
                   * data 
                   */
                  nfs_SetWccData(pcontext, pexport,
                                 parent_pentry,
                                 ppre_attr,
                                 &attr,
                                 &(pres->res_rename3.RENAME3res_u.resok.fromdir_wcc));

                  nfs_SetWccData(pcontext, pexport,
                                 new_parent_pentry,
                                 pnew_pre_attr,
                                 &new_attr,
                                 &(pres->res_rename3.RENAME3res_u.resok.todir_wcc));

                  pres->res_rename3.status = NFS3_OK;
                  break;

                }

              return NFS_REQ_OK;
            }
        }
      else
        {
          /* If name are the same (basically renaming a/file1 to a/file1, this is a non-erroneous situation to be managed */
          if(new_parent_pentry == parent_pentry)
            {
              if(!FSAL_namecmp(&new_entry_name, &entry_name))
                {
                  /* trying to rename a file to himself, this is allowed */
                  cache_status = CACHE_INODE_SUCCESS;
                  switch (preq->rq_vers)
                    {
                    case NFS_V2:
                      pres->res_stat2 = NFS_OK;
                      break;

                    case NFS_V3:
                      /*
                       * Build Weak Cache Coherency
                       * data 
                       */
                      nfs_SetWccData(pcontext, pexport,
                                     parent_pentry,
                                     ppre_attr,
                                     &attr,
                                     &(pres->res_rename3.RENAME3res_u.resok.fromdir_wcc));

                      nfs_SetWccData(pcontext, pexport,
                                     parent_pentry,
                                     ppre_attr,
                                     &attr,
                                     &(pres->res_rename3.RENAME3res_u.resok.todir_wcc));

                      pres->res_rename3.status = NFS3_OK;
                      break;

                    }

                  return NFS_REQ_OK;
                }

            }

          /* New entry already exists. In this case (see RFC), entry should be compatible: Both are non-directories or 
           * both are directories and 'todir' is empty. If compatible, old 'todir' entry is scratched, if not returns EEXISTS */
          if(should_not_exists != NULL)
            {
              /* We need to lookup over the old entry also */
              if((should_exists = cache_inode_lookup(parent_pentry,
                                                     &entry_name,
                                                     &tst_attr,
                                                     ht,
                                                     pclient,
                                                     pcontext, &cache_status)) != NULL)
                {
                  if(cache_inode_type_are_rename_compatible
                     (should_exists, should_not_exists))
                    {
                      /* Remove the old entry before renaming it */
                      if(cache_inode_remove(new_parent_pentry,
                                            &new_entry_name,
                                            &tst_attr,
                                            ht,
                                            pclient,
                                            pcontext,
                                            &cache_status) == CACHE_INODE_SUCCESS)
                        {
                          if(cache_inode_rename(parent_pentry,
                                                &entry_name,
                                                new_parent_pentry,
                                                &new_entry_name,
                                                &attr,
                                                &new_attr,
                                                ht,
                                                pclient,
                                                pcontext,
                                                &cache_status) == CACHE_INODE_SUCCESS)
                            {
                              /* trying to rename a file to himself, this is allowed */
                              switch (preq->rq_vers)
                                {
                                case NFS_V2:
                                  pres->res_stat2 = NFS_OK;
                                  break;

                                case NFS_V3:
                                  /*
                                   * Build Weak Cache Coherency
                                   * data 
                                   */
                                  nfs_SetWccData(pcontext, pexport,
                                                 parent_pentry,
                                                 ppre_attr,
                                                 &attr,
                                                 &(pres->res_rename3.RENAME3res_u.resok.
                                                   fromdir_wcc));

                                  nfs_SetWccData(pcontext, pexport,
                                                 parent_pentry,
                                                 ppre_attr,
                                                 &attr,
                                                 &(pres->res_rename3.RENAME3res_u.resok.
                                                   todir_wcc));

                                  pres->res_rename3.status = NFS3_OK;
                                  break;

                                }

                              return NFS_REQ_OK;
                            }
                        }

                    }
                }               /*  if( cache_inode_type_are_rename_compatible( should_exists, should_not_exists ) ) */
            }

          /* if( ( should_exists = cache_inode_lookup( parent_pentry, .... */
          /* If this point is reached, then destination object already exists with that name in the directory 
             and types are not compatible, we should return that the file exists */
          cache_status = CACHE_INODE_ENTRY_EXISTS;
        }                       /* if( should_not_exists != NULL ) */
    }

  /* If we are here, there was an error */
  if(nfs_RetryableError(cache_status))
    {
      return NFS_REQ_DROP;
    }

  nfs_SetFailedStatus(pcontext, pexport,
                      preq->rq_vers,
                      cache_status,
                      &pres->res_stat2,
                      &pres->res_rename3.status,
                      NULL, NULL,
                      parent_pentry,
                      ppre_attr,
                      &(pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc),
                      new_parent_pentry,
                      pnew_pre_attr, &(pres->res_rename3.RENAME3res_u.resfail.todir_wcc));

  return NFS_REQ_OK;

}                               /* nfs_Rename */