Ejemplo n.º 1
0
int fsal_internal_proxy_fsal_utf8_2_name(fsal_name_t * pname, utf8string * utf8str)
{
  char tmpstr[FSAL_MAX_NAME_LEN];
  fsal_status_t fsal_status;

  if(pname == NULL || utf8str == NULL)
    return FALSE;

  if(utf82str(tmpstr, sizeof(tmpstr), utf8str) == -1)
    return FALSE;

  fsal_status = FSAL_str2name(tmpstr, FSAL_MAX_NAME_LEN, pname);
  if(fsal_status.major != ERR_FSAL_NO_ERROR)
    return FALSE;

  return TRUE;
}                               /* fsal_internal_proxy_fsal_utf8_2_name */
Ejemplo n.º 2
0
int fsal_internal_proxy_fsal_utf8_2_path(fsal_path_t * ppath, utf8string * utf8str)
{
  char tmpstr[FSAL_MAX_PATH_LEN];
  fsal_status_t fsal_status;

  if(ppath == NULL || utf8str == NULL)
    return FALSE;

  if(utf82str(tmpstr, sizeof(tmpstr), utf8str) == -1)
    return FALSE;

  fsal_status = FSAL_str2path(tmpstr, FSAL_MAX_PATH_LEN, ppath);
  if(fsal_status.major != ERR_FSAL_NO_ERROR)
    return FALSE;

  return TRUE;
}                               /* fsal_internal_proxy_fsal_utf8_2_path */
Ejemplo n.º 3
0
/**
 *
 *  utf82gid: converts a utf8 string descriptorto a gid .
 *
 * Converts a utf8 string descriptor to a gid .
 *
 * @param utf8str [IN]  group's name as UTF8 string.
 * @param Gid     [OUT] pointer to the computed gid.
 *
 * @return 0 in all cases
 */
int utf82gid(utf8string * utf8str, gid_t * Gid)
{
  char buff[2 * NFS4_MAX_DOMAIN_LEN];
  char gidname[NFS4_MAX_DOMAIN_LEN];
#ifndef _USE_NFSIDMAP
  char domainname[NFS4_MAX_DOMAIN_LEN];
#endif
  int  rc;

  if(utf8str->utf8string_len == 0)
    {
      *Gid = -1;                /* Nobody */
      LogCrit(COMPONENT_IDMAPPER,
              "utf82gid: empty group name");
      return 0;
    }

  utf82str(buff, sizeof(buff), utf8str);

#ifndef _USE_NFSIDMAP
  /* Group is shown as a string 'group@domain' , remove it if libnfsidmap is not used */
  nfs4_stringid_split(buff, gidname, domainname);
#else
  strncpy(gidname, buff, NFS4_MAX_DOMAIN_LEN);
#endif

  rc = name2gid(gidname, Gid);

  if(rc == 0)
    {
      *Gid = -1;                /* Nobody */
      return 0;
    }

  LogDebug(COMPONENT_IDMAPPER,
           "utf82gid: Mapped %s to gid = %d",
           buff, *Gid);

  return 0;
}                               /* utf82gid */
Ejemplo n.º 4
0
int nfs4_op_lookup(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  fsal_name_t name;
  char strname[MAXNAMLEN];
#ifndef _NO_XATTRD
  char objname[MAXNAMLEN];
#endif
  unsigned int xattr_found = FALSE;
  cache_entry_t *dir_pentry = NULL;
  cache_entry_t *file_pentry = NULL;
  fsal_attrib_list_t attrlookup;
  cache_inode_status_t cache_status;

  fsal_handle_t *pfsal_handle = NULL;

  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_lookup";

  resp->resop = NFS4_OP_LOOKUP;
  res_LOOKUP4.status = NFS4_OK;

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

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

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

  /* Check for empty name */
  if(op->nfs_argop4_u.oplookup.objname.utf8string_len == 0 ||
     op->nfs_argop4_u.oplookup.objname.utf8string_val == NULL)
    {
      res_LOOKUP4.status = NFS4ERR_INVAL;
      return res_LOOKUP4.status;
    }

  /* Check for name to long */
  if(op->nfs_argop4_u.oplookup.objname.utf8string_len > FSAL_MAX_NAME_LEN)
    {
      res_LOOKUP4.status = NFS4ERR_NAMETOOLONG;
      return res_LOOKUP4.status;
    }

  /* If Filehandle points to a pseudo fs entry, manage it via pseudofs specific functions */
  if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    return nfs4_op_lookup_pseudo(op, data, resp);

#ifndef _NO_XATTRD
  /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */
  if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
    return nfs4_op_lookup_xattr(op, data, resp);
#endif

  /* UTF8 strings may not end with \0, but they carry their length */
  utf82str(strname, sizeof(strname), &arg_LOOKUP4.objname);

#ifndef _NO_XATTRD
  /* Is this a .xattr.d.<object> name ? */
  if(nfs_XattrD_Name(strname, objname))
    {
      strcpy(strname, objname);
      xattr_found = TRUE;
    }
#endif

  if((cache_status = cache_inode_error_convert(FSAL_str2name(strname,
                                                             MAXNAMLEN,
                                                             &name))) !=
     CACHE_INODE_SUCCESS)
    {
      res_LOOKUP4.status = nfs4_Errno(cache_status);
      return res_LOOKUP4.status;
    }

  /* No 'cd .' is allowed return NFS4ERR_BADNAME in this case */
  /* No 'cd .. is allowed, return EINVAL in this case. NFS4_OP_LOOKUPP should be use instead */
  if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT)
     || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT))
    {
      res_LOOKUP4.status = NFS4ERR_BADNAME;
      return res_LOOKUP4.status;
    }

  /* Do the lookup in the HPSS Namespace */
  file_pentry = NULL;
  dir_pentry = data->current_entry;

  /* Sanity check: dir_pentry should be ACTUALLY a directory */
  if(dir_pentry->internal_md.type != DIR_BEGINNING
     && dir_pentry->internal_md.type != DIR_CONTINUE)
    {
      /* This is not a directory */
      if(dir_pentry->internal_md.type == SYMBOLIC_LINK)
        res_LOOKUP4.status = NFS4ERR_SYMLINK;
      else
        res_LOOKUP4.status = NFS4ERR_NOTDIR;

      /* Return failed status */
      return res_LOOKUP4.status;
    }

  /* BUGAZOMEU: Faire la gestion des cross junction traverse */
  if((file_pentry = cache_inode_lookup(dir_pentry,
                                       &name,
                                       &attrlookup,
                                       data->ht,
                                       data->pclient,
                                       data->pcontext, &cache_status)) != NULL)
    {
      /* Extract the fsal attributes from the cache inode pentry */
      pfsal_handle = cache_inode_get_fsal_handle(file_pentry, &cache_status);

      if(cache_status != CACHE_INODE_SUCCESS)
        {
          res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
          return res_LOOKUP4.status;
        }

      /* Convert it to a file handle */
      if(!nfs4_FSALToFhandle(&data->currentFH, pfsal_handle, data))
        {
          res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
          return res_LOOKUP4.status;
        }

      /* Copy this to the mounted on FH (if no junction is traversed */
      memcpy((char *)(data->mounted_on_FH.nfs_fh4_val),
             (char *)(data->currentFH.nfs_fh4_val), data->currentFH.nfs_fh4_len);
      data->mounted_on_FH.nfs_fh4_len = data->currentFH.nfs_fh4_len;

#if 0
      print_buff((char *)cache_inode_get_fsal_handle(file_pentry, &cache_status),
                 sizeof(fsal_handle_t));
      print_buff((char *)cache_inode_get_fsal_handle(dir_pentry, &cache_status),
                 sizeof(fsal_handle_t));
#endif
      if(isFullDebug(COMPONENT_NFS_V4))
        {
          LogFullDebug(COMPONENT_NFS_V4,
                       "----> nfs4_op_lookup: name=%s  dir_pentry=%p  looked up pentry=%p",
                       strname, dir_pentry, file_pentry);
          LogFullDebug(COMPONENT_NFS_V4,
                       "----> FSAL handle parent puis fils dans nfs4_op_lookup");
          print_buff(COMPONENT_NFS_V4,
                     (char *)cache_inode_get_fsal_handle(file_pentry, &cache_status),
                     sizeof(fsal_handle_t));
          print_buff(COMPONENT_NFS_V4,
                     (char *)cache_inode_get_fsal_handle(dir_pentry, &cache_status),
                     sizeof(fsal_handle_t));
        }
      LogHandleNFS4("NFS4 LOOKUP CURRENT FH: ", &data->currentFH);

      /* Keep the pointer within the compound data */
      data->current_entry = file_pentry;
      data->current_filetype = file_pentry->internal_md.type;

      /* Return successfully */
      res_LOOKUP4.status = NFS4_OK;

#ifndef _NO_XATTRD
      /* If this is a xattr ghost directory name, update the FH */
      if(xattr_found == TRUE)
        res_LOOKUP4.status = nfs4_fh_to_xattrfh(&(data->currentFH), &(data->currentFH));
#endif

      if((data->current_entry->internal_md.type == DIR_BEGINNING) &&
         (data->current_entry->object.dir_begin.referral != NULL))
        {
          if(!nfs4_Set_Fh_Referral(&(data->currentFH)))
            {
              res_LOOKUP4.status = NFS4ERR_SERVERFAULT;
              return res_LOOKUP4.status;
            }
        }

      return NFS4_OK;

    }

  /* If the part of the code is reached, then something wrong occured in the lookup process, status is not HPSS_E_NOERROR 
   * and contains the code for the error */

  res_LOOKUP4.status = nfs4_Errno(cache_status);

  return res_LOOKUP4.status;
}                               /* nfs4_op_lookup */
Ejemplo n.º 5
0
int nfs4_op_create(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  cache_entry_t *pentry_parent = NULL;
  cache_entry_t *pentry_new = NULL;

  fsal_attrib_list_t attr_parent;
  fsal_attrib_list_t attr_new;
  fsal_attrib_list_t sattr;

  fsal_handle_t *pnewfsal_handle = NULL;

  nfs_fh4 newfh4;
  cache_inode_status_t cache_status;
  int convrc = 0;

  fsal_accessmode_t mode = 0600;
  fsal_name_t name;

  cache_inode_create_arg_t create_arg;

  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_create";
  unsigned int i = 0;

  resp->resop = NFS4_OP_CREATE;
  res_CREATE4.status = NFS4_OK;

  /* If the filehandle is Empty */
  if(nfs4_Is_Fh_Empty(&(data->currentFH)))
    {
      res_CREATE4.status = NFS4ERR_NOFILEHANDLE;
      return res_CREATE4.status;
    }

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

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

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

  /* Ask only for supported attributes */
  if(!nfs4_Fattr_Supported(&arg_CREATE4.createattrs))
    {
      res_CREATE4.status = NFS4ERR_ATTRNOTSUPP;
      return res_CREATE4.status;
    }

  /* Do not use READ attr, use WRITE attr */
  if(!nfs4_Fattr_Check_Access(&arg_CREATE4.createattrs, FATTR4_ATTR_WRITE))
    {
      res_CREATE4.status = NFS4ERR_INVAL;
      return res_CREATE4.status;
    }

  /* Check for name to long */
  if(arg_CREATE4.objname.utf8string_len > FSAL_MAX_NAME_LEN)
    {
      res_CREATE4.status = NFS4ERR_NAMETOOLONG;
      return res_CREATE4.status;
    }

  /* 
   * This operation is used to create a non-regular file, 
   * this means: - a symbolic link
   *             - a block device file
   *             - a character device file
   *             - a socket file
   *             - a fifo
   *             - a directory 
   *
   * You can't use this operation to create a regular file, you have to use NFS4_OP_OPEN for this
   */

  /* Convert the UFT8 objname to a regular string */
  if(arg_CREATE4.objname.utf8string_len == 0)
    {
      res_CREATE4.status = NFS4ERR_INVAL;
      return res_CREATE4.status;
    }

  if(utf82str(name.name, &arg_CREATE4.objname) == -1)
    {
      res_CREATE4.status = NFS4ERR_INVAL;
      return res_CREATE4.status;
    }
  name.len = strlen(name.name);

  /* Sanuty check: never create a directory named '.' or '..' */
  if(arg_CREATE4.objtype.type == NF4DIR)
    {
      if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT)
         || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT))
        {
          res_CREATE4.status = NFS4ERR_BADNAME;
          return res_CREATE4.status;
        }

    }

  /* Filename should contain not slash */
  for(i = 0; i < name.len; i++)
    {
      if(name.name[i] == '/')
        {
          res_CREATE4.status = NFS4ERR_BADCHAR;
          return res_CREATE4.status;
        }
    }
  /* Convert current FH into a cached entry, the current_pentry (assocated with the current FH will be used for this */
  pentry_parent = data->current_entry;

  /* The currentFH must point to a directory (objects are always created within a directory) */
  if(data->current_filetype != DIR_BEGINNING && data->current_filetype != DIR_CONTINUE)
    {
      res_CREATE4.status = NFS4ERR_NOTDIR;
      return res_CREATE4.status;
    }

  /* get attributes of parent directory, for 'change4' info replyed */
  if((cache_status = cache_inode_getattr(pentry_parent,
                                         &attr_parent,
                                         data->ht,
                                         data->pclient,
                                         data->pcontext,
                                         &cache_status)) != CACHE_INODE_SUCCESS)
    {
      res_CREATE4.status = nfs4_Errno(cache_status);
      return res_CREATE4.status;
    }
  /* Change info for client cache coherency, pentry internal_md is used for that */
  memset(&(res_CREATE4.CREATE4res_u.resok4.cinfo.before), 0, sizeof(changeid4));
  res_CREATE4.CREATE4res_u.resok4.cinfo.before =
      (changeid4) pentry_parent->internal_md.mod_time;

  /* Convert the incoming fattr4 to a vattr structure, if such arguments are supplied */
  if(arg_CREATE4.createattrs.attrmask.bitmap4_len != 0)
    {
      /* Arguments were supplied, extract them */
      convrc = nfs4_Fattr_To_FSAL_attr(&sattr, &(arg_CREATE4.createattrs));

      if(convrc == 0)
        {
          res_CREATE4.status = NFS4ERR_ATTRNOTSUPP;
          return res_CREATE4.status;
        }

      if(convrc == -1)
        {
          res_CREATE4.status = NFS4ERR_BADXDR;
          return res_CREATE4.status;
        }
    }

  /* Create either a symbolic link or a directory */
  switch (arg_CREATE4.objtype.type)
    {
    case NF4LNK:
      /* Convert the name to link from into a regular string */
      if(arg_CREATE4.objtype.createtype4_u.linkdata.utf8string_len == 0)
        {
          res_CREATE4.status = NFS4ERR_INVAL;
          return res_CREATE4.status;
        }
      else
        {
          if(utf82str
             (create_arg.link_content.path,
              &arg_CREATE4.objtype.createtype4_u.linkdata) == -1)
            {
              res_CREATE4.status = NFS4ERR_INVAL;
              return res_CREATE4.status;
            }
          create_arg.link_content.len = strlen(create_arg.link_content.path);
        }

      /* do the symlink operation */
      if((pentry_new = cache_inode_create(pentry_parent,
                                          &name,
                                          SYMBOLIC_LINK,
                                          mode,
                                          &create_arg,
                                          &attr_new,
                                          data->ht,
                                          data->pclient,
                                          data->pcontext, &cache_status)) == NULL)
        {
          res_CREATE4.status = nfs4_Errno(cache_status);
          return res_CREATE4.status;
        }

      /* If entry exists pentry_new is not null but cache_status was set */
      if(cache_status == CACHE_INODE_ENTRY_EXISTS)
        {
          res_CREATE4.status = NFS4ERR_EXIST;
          return res_CREATE4.status;
        }

      break;
    case NF4DIR:
      /* Create a new directory */
      /* do the symlink operation */
      if((pentry_new = cache_inode_create(pentry_parent,
                                          &name,
                                          DIR_BEGINNING,
                                          mode,
                                          &create_arg,
                                          &attr_new,
                                          data->ht,
                                          data->pclient,
                                          data->pcontext, &cache_status)) == NULL)
        {
          res_CREATE4.status = nfs4_Errno(cache_status);
          return res_CREATE4.status;
        }

      /* If entry exists pentry_new is not null but cache_status was set */
      if(cache_status == CACHE_INODE_ENTRY_EXISTS)
        {
          res_CREATE4.status = NFS4ERR_EXIST;
          return res_CREATE4.status;
        }
      break;

    case NF4SOCK:

      /* Create a new socket file */
      if((pentry_new = cache_inode_create(pentry_parent,
                                          &name,
                                          SOCKET_FILE,
                                          mode,
                                          NULL,
                                          &attr_new,
                                          data->ht,
                                          data->pclient,
                                          data->pcontext, &cache_status)) == NULL)
        {
          res_CREATE4.status = nfs4_Errno(cache_status);
          return res_CREATE4.status;
        }

      /* If entry exists pentry_new is not null but cache_status was set */
      if(cache_status == CACHE_INODE_ENTRY_EXISTS)
        {
          res_CREATE4.status = NFS4ERR_EXIST;
          return res_CREATE4.status;
        }
      break;

    case NF4FIFO:

      /* Create a new socket file */
      if((pentry_new = cache_inode_create(pentry_parent,
                                          &name,
                                          FIFO_FILE,
                                          mode,
                                          NULL,
                                          &attr_new,
                                          data->ht,
                                          data->pclient,
                                          data->pcontext, &cache_status)) == NULL)
        {
          res_CREATE4.status = nfs4_Errno(cache_status);
          return res_CREATE4.status;
        }

      /* If entry exists pentry_new is not null but cache_status was set */
      if(cache_status == CACHE_INODE_ENTRY_EXISTS)
        {
          res_CREATE4.status = NFS4ERR_EXIST;
          return res_CREATE4.status;
        }
      break;

    case NF4CHR:

      create_arg.dev_spec.major = arg_CREATE4.objtype.createtype4_u.devdata.specdata1;
      create_arg.dev_spec.minor = arg_CREATE4.objtype.createtype4_u.devdata.specdata2;

      /* Create a new socket file */
      if((pentry_new = cache_inode_create(pentry_parent,
                                          &name,
                                          CHARACTER_FILE,
                                          mode,
                                          &create_arg,
                                          &attr_new,
                                          data->ht,
                                          data->pclient,
                                          data->pcontext, &cache_status)) == NULL)
        {
          res_CREATE4.status = nfs4_Errno(cache_status);
          return res_CREATE4.status;
        }

      /* If entry exists pentry_new is not null but cache_status was set */
      if(cache_status == CACHE_INODE_ENTRY_EXISTS)
        {
          res_CREATE4.status = NFS4ERR_EXIST;
          return res_CREATE4.status;
        }
      break;

    case NF4BLK:

      create_arg.dev_spec.major = arg_CREATE4.objtype.createtype4_u.devdata.specdata1;
      create_arg.dev_spec.minor = arg_CREATE4.objtype.createtype4_u.devdata.specdata2;

      /* Create a new socket file */
      if((pentry_new = cache_inode_create(pentry_parent,
                                          &name,
                                          BLOCK_FILE,
                                          mode,
                                          &create_arg,
                                          &attr_new,
                                          data->ht,
                                          data->pclient,
                                          data->pcontext, &cache_status)) == NULL)
        {
          res_CREATE4.status = nfs4_Errno(cache_status);
          return res_CREATE4.status;
        }

      /* If entry exists pentry_new is not null but cache_status was set */
      if(cache_status == CACHE_INODE_ENTRY_EXISTS)
        {
          res_CREATE4.status = NFS4ERR_EXIST;
          return res_CREATE4.status;
        }
      break;

    default:
      /* Should never happen, but return NFS4ERR_BADTYPE in this case */
      res_CREATE4.status = NFS4ERR_BADTYPE;
      return res_CREATE4.status;
      break;
    }                           /* switch( arg_CREATE4.objtype.type ) */

  /* Now produce the filehandle to this file */
  if((pnewfsal_handle = cache_inode_get_fsal_handle(pentry_new, &cache_status)) == NULL)
    {
      res_CREATE4.status = nfs4_Errno(cache_status);
      return res_CREATE4.status;
    }

  /* Allocation of a new file handle */
  if(nfs4_AllocateFH(&newfh4) != NFS4_OK)
    {
      res_CREATE4.status = NFS4ERR_SERVERFAULT;
      return res_CREATE4.status;
    }

  /* Building the new file handle */
  if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
    {
      res_CREATE4.status = NFS4ERR_SERVERFAULT;
      return res_CREATE4.status;
    }

  /* This new fh replaces the current FH */
  data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
  memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len);

  /* No do not need newfh any more */
  Mem_Free((char *)newfh4.nfs_fh4_val);

  /* Set the mode if requested */
  /* Use the same fattr mask for reply, if one attribute was not settable, NFS4ERR_ATTRNOTSUPP was replyied */
  res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len =
      arg_CREATE4.createattrs.attrmask.bitmap4_len;

  if(arg_CREATE4.createattrs.attrmask.bitmap4_len != 0)
    {
      if((cache_status = cache_inode_setattr(pentry_new,
                                             &sattr,
                                             data->ht,
                                             data->pclient,
                                             data->pcontext,
                                             &cache_status)) != CACHE_INODE_SUCCESS)

        {
          res_CREATE4.status = nfs4_Errno(cache_status);
          return res_CREATE4.status;
        }

      /* Allocate a new bitmap */
      res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val =
          (unsigned int *)Mem_Alloc(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len *
                                    sizeof(u_int));

      if(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val == NULL)
        {
          res_CREATE4.status = NFS4ERR_SERVERFAULT;
          return res_CREATE4.status;
        }
      memset(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val, 0,
             res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len);

      memcpy(res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_val,
             arg_CREATE4.createattrs.attrmask.bitmap4_val,
             res_CREATE4.CREATE4res_u.resok4.attrset.bitmap4_len * sizeof(u_int));
    }

  /* Get the change info on parent directory after the operation was successfull */
  if((cache_status = cache_inode_getattr(pentry_parent,
                                         &attr_parent,
                                         data->ht,
                                         data->pclient,
                                         data->pcontext,
                                         &cache_status)) != CACHE_INODE_SUCCESS)
    {
      res_CREATE4.status = nfs4_Errno(cache_status);
      return res_CREATE4.status;
    }
  memset(&(res_CREATE4.CREATE4res_u.resok4.cinfo.after), 0, sizeof(changeid4));
  res_CREATE4.CREATE4res_u.resok4.cinfo.after =
      (changeid4) pentry_parent->internal_md.mod_time;

  /* Operation is supposed to be atomic .... */
  res_CREATE4.CREATE4res_u.resok4.cinfo.atomic = TRUE;

  LogFullDebug(COMPONENT_NFS_V4, "           CREATE CINFO before = %llu  after = %llu  atomic = %d\n",
         res_CREATE4.CREATE4res_u.resok4.cinfo.before,
         res_CREATE4.CREATE4res_u.resok4.cinfo.after,
         res_CREATE4.CREATE4res_u.resok4.cinfo.atomic);

  /* @todo : BUGAZOMEU: fair ele free dans cette fonction */

  /* Keep the vnode entry for the file in the compound data */
  data->current_entry = pentry_new;
  data->current_filetype = pentry_new->internal_md.type;

  /* If you reach this point, then no error occured */
  res_CREATE4.status = NFS4_OK;

  return res_CREATE4.status;
}                               /* nfs4_op_create */