Example #1
0
fsal_status_t FSAL_proxy_truncate_stateless(proxyfsal_handle_t * filehandle,    /* IN */
                                            proxyfsal_op_context_t * p_context, /* IN */
                                            fsal_size_t length, /* IN */
                                            fsal_attrib_list_t * object_attributes      /* [ IN/OUT ] */
    )
{
  int rc;

  COMPOUND4args argnfs4;
  COMPOUND4res resnfs4;
  nfs_fh4 nfs4fh;
  fsal_status_t fsal_status;
  fsal_attrib_list_t open_attrs;
  bitmap4 inbitmap;
  bitmap4 convert_bitmap;
  uint32_t inbitmap_val[2];
  uint32_t bitmap_res[2];
  uint32_t bitmap_set[2];
  uint32_t bitmap_conv_val[2];

#define FSAL_TRUNCATE_STATELESS_NB_OP_ALLOC 3
  nfs_argop4 argoparray[FSAL_TRUNCATE_STATELESS_NB_OP_ALLOC];
  nfs_resop4 resoparray[FSAL_TRUNCATE_STATELESS_NB_OP_ALLOC];

  fsal_attrib_list_t fsal_attr_set;
  fattr4 fattr_set;
  fsal_proxy_internal_fattr_t fattr_internal;
  struct timeval timeout = { 25, 0 };

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!filehandle || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate);

  if(filehandle->data.object_type_reminder != FSAL_TYPE_FILE)
    {
      Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_truncate);
    }

  /* Setup results structures */
  argnfs4.argarray.argarray_val = argoparray;
  resnfs4.resarray.resarray_val = resoparray;
  fsal_internal_proxy_setup_fattr(&fattr_internal);
  argnfs4.minorversion = 0;
  /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Truncate" ; */
  argnfs4.tag.utf8string_val = NULL;
  argnfs4.tag.utf8string_len = 0;
  argnfs4.argarray.argarray_len = 0;

  /* Get NFSv4 File handle */
  if(fsal_internal_proxy_extract_fh(&nfs4fh, filehandle) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate);

  /* Get prepared for truncate */
  fsal_attr_set.asked_attributes = FSAL_ATTR_SIZE;
  fsal_attr_set.filesize = length;

  convert_bitmap.bitmap4_val = bitmap_conv_val;
  convert_bitmap.bitmap4_len = 2;

  fsal_interval_proxy_fsalattr2bitmap4(&fsal_attr_set, &convert_bitmap);

  if(nfs4_FSALattr_To_Fattr(NULL,       /* no exportlist required here */
                            &fsal_attr_set, &fattr_set, NULL,   /* no compound data required here */
                            NULL,       /* No fh here, filehandle is not a settable attribute */
                            &convert_bitmap) == -1)
    Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_truncate);

  inbitmap.bitmap4_val = inbitmap_val;
  inbitmap.bitmap4_len = 2;
  fsal_internal_proxy_create_fattr_bitmap(&inbitmap);

#define FSAL_TRUNCATE_STATELESS_IDX_OP_PUTFH     0
#define FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR   1
#define FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR   2
  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh);
  COMPOUNDV4_ARG_ADD_OP_SETATTR(argnfs4, fattr_set);
  COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, inbitmap);

  /* For ATTR_SIZE, stateid is needed, we use the stateless "all-0's" stateid here */
  argnfs4.argarray.argarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR].nfs_argop4_u.
      opsetattr.stateid.seqid = 0;
  memset(argnfs4.argarray.argarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR].
         nfs_argop4_u.opsetattr.stateid.other, 0, 12);

  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].nfs_resop4_u.
      opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res;
  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].nfs_resop4_u.
      opgetattr.GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2;

  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].nfs_resop4_u.
      opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val =
      (char *)&fattr_internal;
  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].nfs_resop4_u.
      opgetattr.GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len =
      sizeof(fattr_internal);

  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR].nfs_resop4_u.
      opsetattr.attrsset.bitmap4_val = bitmap_set;
  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_STATELESS_IDX_OP_SETATTR].nfs_resop4_u.
      opsetattr.attrsset.bitmap4_len = 2;

  TakeTokenFSCall();

  COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc);
  if(rc != RPC_SUCCESS)
    {
      ReleaseTokenFSCall();

      Return(ERR_FSAL_IO, 0, INDEX_FSAL_truncate);
    }

  ReleaseTokenFSCall();

  if(resnfs4.status != NFS4_OK)
    return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_truncate);

  /* >> interpret error code << */

  /* >> Optionnaly retrieve post op attributes
   * If your filesystem truncate call can't return them,
   * you can proceed like this : <<
   */
  if(object_attributes)
    {
      if(nfs4_Fattr_To_FSAL_attr(object_attributes,
                                 &resnfs4.resarray.resarray_val
                                 [FSAL_TRUNCATE_STATELESS_IDX_OP_GETATTR].
                                 nfs_resop4_u.opgetattr.GETATTR4res_u.resok4.
                                 obj_attributes) != 1)
        {
          FSAL_CLEAR_MASK(object_attributes->asked_attributes);
          FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);

          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_truncate);
        }

    }

  /* No error occured */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_truncate);
}                               /* FSAL_proxy_truncate_stateless */
Example #2
0
/**
 * nfs4_op_readdir: The NFS4_OP_READDIR.
 * 
 * Implements the NFS4_OP_READDIR. If fh is a pseudo FH, then call is routed to routine nfs4_op_readdir_pseudo
 *
 * @param op    [IN]    pointer to nfs4_op arguments
 * @param data  [INOUT] Pointer to the compound request's data
 * @param resp  [IN]    Pointer to nfs4_op results
 * 
 * @return NFS4_OK if ok, any other value show an error.
 *
 */
int nfs4_op_readdir(struct nfs_argop4 *op,
                    compound_data_t * data, struct nfs_resop4 *resp)
{
  cache_entry_t *dir_pentry = NULL;
  cache_entry_t *pentry = NULL;

  cache_inode_endofdir_t eod_met;
  fsal_attrib_list_t attrlookup;
  cache_inode_status_t cache_status;
  cache_inode_status_t cache_status_attr;

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

  unsigned long dircount;
  unsigned long maxcount;
  entry4 *entry_nfs_array;
  cache_inode_dir_entry_t **dirent_array = NULL;
  verifier4 cookie_verifier;
  uint64_t cookie = 0;
  uint64_t end_cookie = 0;
  fsal_handle_t *entry_FSALhandle;
  nfs_fh4 entryFH;
  char val_fh[NFS4_FHSIZE];
  entry_name_array_item_t *entry_name_array = NULL;
  unsigned int estimated_num_entries;
  unsigned int num_entries;
  int dir_pentry_unlock = FALSE;

  unsigned int i = 0;
  unsigned int outbuffsize = 0 ;
  unsigned int entrysize = 0 ;
 
  bitmap4 RdAttrErrorBitmap = { 1, (uint32_t *) "\0\0\0\b" };   /* 0xB = 11 = FATTR4_RDATTR_ERROR */
  attrlist4 RdAttrErrorVals = { 0, NULL };      /* Nothing to be seen here */

  resp->resop = NFS4_OP_READDIR;
  res_READDIR4.status = NFS4_OK;

  entryFH.nfs_fh4_len = 0;
  entryFH.nfs_fh4_val = val_fh;

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

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

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

  /* Pseudo Fs management */
  if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    return nfs4_op_readdir_pseudo(op, data, resp);

  /* Xattrs management */
  if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
    return nfs4_op_readdir_xattr(op, data, resp);

  /* You can readdir only within a directory */
  dir_pentry = data->current_entry;
  if(data->current_filetype != DIRECTORY)
    {
      res_READDIR4.status = NFS4ERR_NOTDIR;
      return res_READDIR4.status;
    }

  /* get the characteristic value for readdir operation */
  dircount = arg_READDIR4.dircount;
  maxcount = arg_READDIR4.maxcount*0.9;
  cookie = (unsigned int)arg_READDIR4.cookie;

  /* dircount is considered meaningless by many nfsv4 client (like the CITI
   * one).  we use maxcount instead. */

  /* the Linux 3.0, 3.1.0 clients vs. TCP Ganesha comes out 10x slower
   * with 500 max entries */
#if 0
  /* takes 2s to return 2999 entries */
  estimated_num_entries = maxcount / sizeof(entry4);
#else
  /* takes 20s to return 2999 entries */
  estimated_num_entries = 50;
#endif

  LogFullDebug(COMPONENT_NFS_V4,
               "--- nfs4_op_readdir ---> dircount=%lu maxcount=%lu arg_cookie=%"
               PRIu64" cookie=%"PRIu64" estimated_num_entries=%u",
               dircount, maxcount, arg_READDIR4.cookie, cookie,
               estimated_num_entries);

  /* Do not use a cookie of 1 or 2 (reserved values) */
  if(cookie == 1 || cookie == 2)
    {
      res_READDIR4.status = NFS4ERR_BAD_COOKIE;
      return res_READDIR4.status;
    }

  /* Get only attributes that are allowed to be read */
  if(!nfs4_Fattr_Check_Access_Bitmap(&arg_READDIR4.attr_request,
                                     FATTR4_ATTR_READ))
    {
      res_READDIR4.status = NFS4ERR_INVAL;
      return res_READDIR4.status;
    }

  /* If maxcount is too short, return NFS4ERR_TOOSMALL */
  if(maxcount < sizeof(entry4) || estimated_num_entries == 0)
    {
      res_READDIR4.status = NFS4ERR_TOOSMALL;
      return res_READDIR4.status;
    }

  /*

   * If cookie verifier is used, then an non-trivial value is
   * returned to the client         This value is the mtime of
   * the pentry. If verifier is unused (as in many NFS
   * Servers) then only a set of zeros is returned (trivial
   * value) 
   */
  memset(cookie_verifier, 0, NFS4_VERIFIER_SIZE);
  if(data->pexport->UseCookieVerifier == 1)
    memcpy(cookie_verifier, &dir_pentry->internal_md.mod_time, sizeof(time_t));

  /* Cookie delivered by the server and used by the client SHOULD not ne 0, 1 or 2 (cf RFC3530, page192)
   * because theses value are reserved for special use.
   *      0 - cookie for first READDIR
   *      1 - reserved for . on client handside
   *      2 - reserved for .. on client handside
   * Entries '.' and '..' are not returned also
   * For these reason, there will be an offset of 3 between NFS4 cookie and
   * HPSS cookie */

  if((cookie != 0) && (data->pexport->UseCookieVerifier == 1))
    {
      if(memcmp(cookie_verifier, arg_READDIR4.cookieverf, NFS4_VERIFIER_SIZE) != 0)
        {

          res_READDIR4.status = NFS4ERR_BAD_COOKIE;
          return res_READDIR4.status;
        }
    }

  /* The default behaviour is to consider that eof is not reached, the
   * returned values by cache_inode_readdir will let us know if eod was
   * reached or not */
  res_READDIR4.READDIR4res_u.resok4.reply.eof = FALSE;

  /* Get prepared for readdir */
  if((dirent_array =
      (cache_inode_dir_entry_t **) Mem_Alloc(
          estimated_num_entries * sizeof(cache_inode_dir_entry_t*))) == NULL)
    {
      res_READDIR4.status = NFS4ERR_SERVERFAULT;
      goto out;
    }
  
  /* Perform the readdir operation */
  if(cache_inode_readdir(dir_pentry,
                         data->pexport->cache_inode_policy,
                         cookie,
                         estimated_num_entries,
                         &num_entries,
                         &end_cookie,
                         &eod_met,
                         dirent_array,
                         data->ht,
                         &dir_pentry_unlock,
                         data->pclient,
                         data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
    {
      res_READDIR4.status = nfs4_Errno(cache_status);
      goto out;
    }

  /* For an empty directory, we will find only . and .., so reply as if the
   * end is reached */
  if(num_entries == 0)
    {
      /* only . and .. */
      res_READDIR4.READDIR4res_u.resok4.reply.entries = NULL;
      res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE;
      memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier,
             NFS4_VERIFIER_SIZE);
    }
  else
    {
      /* Start computing the outbuffsize */
      outbuffsize = sizeof( bool_t) /* eof */ 
                  + sizeof( nfsstat4 ) /* READDIR4res::status */
                  + NFS4_VERIFIER_SIZE /* cookie verifier */ ;

      /* Allocation of reply structures */
      if((entry_name_array =
          (entry_name_array_item_t *) Mem_Alloc(num_entries *
                                                (FSAL_MAX_NAME_LEN + 1)))
         == NULL)
        {
          LogError(COMPONENT_NFS_V4, ERR_SYS, ERR_MALLOC, errno);
          res_READDIR4.status = NFS4ERR_SERVERFAULT;
          return res_READDIR4.status;
        }
      memset((char *)entry_name_array, 0,
             num_entries * (FSAL_MAX_NAME_LEN + 1));

      if((entry_nfs_array = (entry4 *) Mem_Alloc(num_entries * sizeof(entry4))) 
         == NULL)
        {
          LogError(COMPONENT_NFS_V4, ERR_SYS, ERR_MALLOC, errno);
          res_READDIR4.status = NFS4ERR_SERVERFAULT;
          return res_READDIR4.status;
        }
      memset((char *)entry_nfs_array, 0, num_entries * sizeof(entry4));

      for(i = 0; i < num_entries; i++) 
        {
          entry_nfs_array[i].name.utf8string_val = entry_name_array[i];

          if(str2utf8(dirent_array[i]->name.name,
                      &entry_nfs_array[i].name) == -1)
            {
              res_READDIR4.status = NFS4ERR_SERVERFAULT;
              goto out;
            }

          /* Set the cookie value */
          entry_nfs_array[i].cookie = dirent_array[i]->cookie;

          /* Get the pentry for the object's attributes and filehandle */
          if( ( pentry = cache_inode_lookup_no_mutex( dir_pentry,
                                                      &dirent_array[i]->name,
                                                      data->pexport->cache_inode_policy,
                                                      &attrlookup,
                                                      data->ht,
                                                      data->pclient,
                                                      data->pcontext,
                                                      &cache_status ) ) == NULL )
            {
              Mem_Free((char *)entry_nfs_array);
              /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */
              entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap;
              entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals;
              res_READDIR4.status = NFS4ERR_SERVERFAULT;
              goto out;
            }

          /* If file handle is asked in the attributes, provide it */
          if(arg_READDIR4.attr_request.bitmap4_val != NULL
             && (arg_READDIR4.attr_request.bitmap4_val[0] & FATTR4_FILEHANDLE))
            {
              if((entry_FSALhandle =
                  cache_inode_get_fsal_handle(pentry,
                                              &cache_status_attr)) == NULL)
                {
                  /* Faulty Handle or pentry */
                  Mem_Free((char *)entry_nfs_array);
                  res_READDIR4.status = NFS4ERR_SERVERFAULT;
                  goto out;
                }

              if(!nfs4_FSALToFhandle(&entryFH, entry_FSALhandle, data))
                {
                  /* Faulty type */
                  Mem_Free((char *)entry_nfs_array);
                  res_READDIR4.status = NFS4ERR_SERVERFAULT;
                  goto out;
                }
            }

          if(nfs4_FSALattr_To_Fattr(data->pexport,
                                    &attrlookup,
                                    &(entry_nfs_array[i].attrs),
                                    data, &entryFH, &(arg_READDIR4.attr_request)) != 0)
            {
              /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */
              entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap;
              entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals;
            }

          /* Update the size of the output buffer */
          entrysize = sizeof( nfs_cookie4 ) ; /* nfs_cookie4 */
          entrysize += sizeof( u_int ) ; /* pathname4::utf8strings_len */
          entrysize +=  entry_nfs_array[i].name.utf8string_len ; 
          entrysize += sizeof( u_int ) ; /* bitmap4_len */
          entrysize +=  entry_nfs_array[i].attrs.attrmask.bitmap4_len ;
          entrysize += sizeof( u_int ) ; /* attrlist4_len */
          entrysize +=  entry_nfs_array[i].attrs.attr_vals.attrlist4_len ;
          entrysize += sizeof( caddr_t ) ;
          outbuffsize += entrysize;

          LogFullDebug(COMPONENT_NFS_V4,
                  " === nfs4_op_readdir ===>   i=%u name=%s cookie=%"PRIu64" "
                  "entrysize=%u buffsize=%u",
                  i, dirent_array[i]->name.name,
                  entry_nfs_array[i].cookie,
                  entrysize,
                  outbuffsize);

          /* Chain the entries together */
          entry_nfs_array[i].nextentry = NULL;
          if(i != 0)
           {
              if( outbuffsize < maxcount )
                entry_nfs_array[i - 1].nextentry = &(entry_nfs_array[i]);
              else
               {
                   LogFullDebug(COMPONENT_NFS_V4,
                           "=== nfs4_op_readdir ===> "
                           "maxcount reached at %u entries name=%s "
                           "cookie=%llu "
                           "buffsize=%u (return early)",
                           i+1, 
                           dirent_array[i]->name.name,
                           (unsigned long long)entry_nfs_array[i].cookie,
                           outbuffsize);
                 entry_nfs_array[i - 1].nextentry = NULL ;
                 break ;
               }
           }
        }                       /* for i */

      if((i == num_entries) && (eod_met == END_OF_DIR))
      {

          LogFullDebug(COMPONENT_NFS_V4,
                  "End of directory reached:  num_entries=%d i=%d",
                  num_entries,
                  i);

          /* This is the end of the directory */
          res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE;
          memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf,
                 cookie_verifier, NFS4_VERIFIER_SIZE);
      }

      /* Put the entry's list in the READDIR reply */
      res_READDIR4.READDIR4res_u.resok4.reply.entries = entry_nfs_array;
    }

  /* Do not forget to set the verifier */
  memcpy((char *)res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier,
         NFS4_VERIFIER_SIZE);

  res_READDIR4.status = NFS4_OK;

out:
  /* release read lock on dir_pentry, if requested */
  if (dir_pentry_unlock)
      V_r(&dir_pentry->lock);

  if (dirent_array)
   {
      if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) )
        cache_inode_release_dirent( dirent_array, num_entries, data->pclient ) ;

      Mem_Free((char *)dirent_array);
   }

  return res_READDIR4.status;
}                               /* nfs4_op_readdir */
Example #3
0
/**
 *
 * nfs4_op_getattr: Gets attributes for an entry in the FSAL.
 * 
 * Gets attributes for an entry in the FSAL.
 *
 * @param op    [IN]    pointer to nfs4_op arguments
 * @param data  [INOUT] Pointer to the compound request's data
 * @param resp  [IN]    Pointer to nfs4_op results
 * 
 * @return NFS4_OK 
 * 
 */
int nfs4_op_getattr(struct nfs_argop4 *op,
                    compound_data_t * data, struct nfs_resop4 *resp)
{
  fsal_attrib_list_t attr;
  cache_inode_status_t cache_status;
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_getattr";

  /* This is a NFS4_OP_GETTAR */
  resp->resop = NFS4_OP_GETATTR;

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

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

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

  /* Pseudo Fs management */
  if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    return nfs4_op_getattr_pseudo(op, data, resp);

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

  if(isFullDebug(COMPONENT_NFS_V4))
    {
      char str[LEN_FH_STR];
      sprint_fhandle4(str, &data->currentFH);
      LogFullDebug(COMPONENT_NFS_V4, "NFS4_OP_GETATTR: Current FH %s", str);
    }

  /* Sanity check: if no attributes are wanted, nothing is to be done.
   * In this case NFS4_OK is to be returned */
  if(arg_GETATTR4.attr_request.bitmap4_len == 0)
    {
      res_GETATTR4.status = NFS4_OK;
      return res_GETATTR4.status;
    }

  /* Get only attributes that are allowed to be read */
  if(!nfs4_Fattr_Check_Access_Bitmap(&arg_GETATTR4.attr_request, FATTR4_ATTR_READ))
    {
      res_GETATTR4.status = NFS4ERR_INVAL;
      return res_GETATTR4.status;
    }

  if( !nfs4_bitmap4_Remove_Unsupported( &arg_GETATTR4.attr_request ) )
    {
      res_GETATTR4.status = NFS4ERR_SERVERFAULT ;
      return res_GETATTR4.status;
    }
   

  /*
   * Get attributes.
   */
  if(cache_inode_getattr(data->current_entry,
                         &attr,
                         data->ht,
                         data->pclient,
                         data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
    {
      if(nfs4_FSALattr_To_Fattr(data->pexport,
                                &attr,
                                &(res_GETATTR4.GETATTR4res_u.resok4.obj_attributes),
                                data,
                                &(data->currentFH), &(arg_GETATTR4.attr_request)) != 0)
        res_GETATTR4.status = NFS4ERR_SERVERFAULT;
      else
        res_GETATTR4.status = NFS4_OK;

      return res_GETATTR4.status;
    }
  res_GETATTR4.status = nfs4_Errno(cache_status);

  return res_GETATTR4.status;
}                               /* nfs4_op_getattr */
Example #4
0
fsal_status_t PROXYFSAL_symlink(proxyfsal_handle_t * parent_directory_handle,   /* IN */
                                fsal_name_t * p_linkname,       /* IN */
                                fsal_path_t * p_linkcontent,    /* IN */
                                proxyfsal_op_context_t * p_context,     /* IN */
                                fsal_accessmode_t accessmode,   /* IN (ignored) */
                                proxyfsal_handle_t * link_handle,       /* OUT */
                                fsal_attrib_list_t * link_attributes    /* [ IN/OUT ] */
    )
{

  int rc;

  COMPOUND4args argnfs4;
  COMPOUND4res resnfs4;
  nfs_fh4 nfs4fh;
  bitmap4 bitmap;
  uint32_t bitmap_val[2];
  uint32_t bitmap_res[2];
  uint32_t bitmap_mkdir[2];
  uint32_t bitmap_getattr_res[2];
  uint32_t bitmap_conv_val[2];
  fattr4 input_attr;
  bitmap4 convert_bitmap;
  component4 name;
  char nameval[MAXNAMLEN];
  component4 linkname;
  char linknameval[MAXNAMLEN];
  char padfilehandle[FSAL_PROXY_FILEHANDLE_MAX_LEN];

  fsal_proxy_internal_fattr_t fattr_internal;
  fsal_attrib_list_t create_mode_attr;
  fsal_attrib_list_t attributes;

#define FSAL_SYMLINK_NB_OP_ALLOC 4
#define FSAL_SYMLINK_VAL_BUFFER  1024

  nfs_argop4 argoparray[FSAL_SYMLINK_NB_OP_ALLOC];
  nfs_resop4 resoparray[FSAL_SYMLINK_NB_OP_ALLOC];

  char fattr_val[FSAL_SYMLINK_VAL_BUFFER];
  struct timeval timeout = TIMEOUTRPC;

  /* sanity checks.
   * note : link_attributes is optional.
   */
  if(!parent_directory_handle ||
     !p_context || !link_handle || !p_linkname || !p_linkcontent)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink);

  /* Tests if symlinking is allowed by configuration. */

  if(!global_fs_info.symlink_support)
    Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_symlink);

  /* Setup results structures */
  argnfs4.argarray.argarray_val = argoparray;
  resnfs4.resarray.resarray_val = resoparray;
  argnfs4.minorversion = 0;
  /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Symlink" ; */
  argnfs4.tag.utf8string_val = NULL;
  argnfs4.tag.utf8string_len = 0;
  argnfs4.argarray.argarray_len = 0;

  input_attr.attrmask.bitmap4_val = bitmap_val;
  input_attr.attrmask.bitmap4_len = 2;

  input_attr.attr_vals.attrlist4_val = fattr_val;
  input_attr.attr_vals.attrlist4_len = FSAL_SYMLINK_VAL_BUFFER;

  fsal_internal_proxy_setup_fattr(&fattr_internal);

  convert_bitmap.bitmap4_val = bitmap_conv_val;
  convert_bitmap.bitmap4_len = 2;

  memset((char *)&name, 0, sizeof(component4));
  name.utf8string_val = nameval;
  if(fsal_internal_proxy_fsal_name_2_utf8(p_linkname, &name) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink);

  memset((char *)&linkname, 0, sizeof(component4));
  linkname.utf8string_val = linknameval;
  if(fsal_internal_proxy_fsal_path_2_utf8(p_linkcontent, &linkname) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink);

  /* Get NFSv4 File handle */
  if(fsal_internal_proxy_extract_fh(&nfs4fh, parent_directory_handle) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink);

  bitmap.bitmap4_val = bitmap_mkdir;
  bitmap.bitmap4_len = 2;
  fsal_internal_proxy_create_fattr_bitmap(&bitmap);

  create_mode_attr.asked_attributes = FSAL_ATTR_MODE;
  create_mode_attr.mode = accessmode;
  fsal_interval_proxy_fsalattr2bitmap4(&create_mode_attr, &convert_bitmap);

  if(nfs4_FSALattr_To_Fattr(NULL,       /* no exportlist required here */
                            &create_mode_attr, &input_attr, NULL,       /* no compound data required here */
                            NULL,       /* No fh here, filehandle is not a settable attribute */
                            &convert_bitmap) == -1)
    Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_symlink);

#define FSAL_SYMLINK_IDX_OP_PUTFH     0
#define FSAL_SYMLINK_IDX_OP_SYMLINK   1
#define FSAL_SYMLINK_IDX_OP_GETFH     2
#define FSAL_SYMLINK_IDX_OP_GETATTR   3
  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh);
  COMPOUNDV4_ARG_ADD_OP_SYMLINK(argnfs4, name, linkname, input_attr);
  COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4);
  COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap);

  resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_SYMLINK].nfs_resop4_u.opcreate.
      CREATE4res_u.resok4.attrset.bitmap4_val = bitmap_res;
  resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_SYMLINK].nfs_resop4_u.opcreate.
      CREATE4res_u.resok4.attrset.bitmap4_len = 2;

  resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETFH].nfs_resop4_u.opgetfh.
      GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle;
  resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETFH].nfs_resop4_u.opgetfh.
      GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN;

  resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_getattr_res;
  resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2;

  resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val =
      (char *)&fattr_internal;
  resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len =
      sizeof(fattr_internal);

  TakeTokenFSCall();

  /* Call the NFSv4 function */
  COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc);
  if(rc != RPC_SUCCESS)
    {
      ReleaseTokenFSCall();

      Return(ERR_FSAL_IO, 0, INDEX_FSAL_symlink);
    }

  ReleaseTokenFSCall();

  /* >> convert error code, and return on error << */
  if(resnfs4.status != NFS4_OK)
    return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_symlink);

  /* Use NFSv4 service function to build the FSAL_attr */
  if(nfs4_Fattr_To_FSAL_attr(&attributes,
                             &resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETATTR].
                             nfs_resop4_u.opgetattr.GETATTR4res_u.resok4.
                             obj_attributes) != NFS4_OK)
    {
      FSAL_CLEAR_MASK(attributes.asked_attributes);
      FSAL_SET_MASK(attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR);

      Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_symlink);
    }

  if(link_attributes)
    {
      memcpy(link_attributes, &attributes, sizeof(attributes));
    }

  if(fsal_internal_proxy_create_fh
     (&
      (resnfs4.resarray.resarray_val[FSAL_SYMLINK_IDX_OP_GETFH].nfs_resop4_u.opgetfh.
       GETFH4res_u.resok4.object), FSAL_TYPE_LNK, attributes.fileid,
      link_handle) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink);

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_symlink);
}
Example #5
0
int nfs4_op_verify(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  fsal_attrib_list_t file_attr;
  cache_inode_status_t cache_status;
  fattr4 file_attr4;
  int rc = 0;

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

  resp->resop = NFS4_OP_VERIFY;
  res_VERIFY4.status = NFS4_OK;

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

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

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

  /* operation is always permitted on pseudofs */
  if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    {
      res_VERIFY4.status = NFS4_OK;
      return res_VERIFY4.status;
    }

  /* Get only attributes that are allowed to be read */
  if(!nfs4_Fattr_Check_Access(&arg_VERIFY4.obj_attributes, FATTR4_ATTR_READ))
    {
      res_VERIFY4.status = NFS4ERR_INVAL;
      return res_VERIFY4.status;
    }

  /* Ask only for supported attributes */
  if(!nfs4_Fattr_Supported(&arg_VERIFY4.obj_attributes))
    {
      res_VERIFY4.status = NFS4ERR_ATTRNOTSUPP;
      return res_VERIFY4.status;
    }

  /* Get the cache inode attribute */
  if((cache_status = cache_inode_getattr(data->current_entry,
                                         &file_attr,
                                         data->ht,
                                         data->pclient,
                                         data->pcontext,
                                         &cache_status)) != CACHE_INODE_SUCCESS)
    {
      res_VERIFY4.status = NFS4ERR_INVAL;
      return res_VERIFY4.status;
    }

  if(nfs4_FSALattr_To_Fattr(data->pexport,
                            &file_attr,
                            &file_attr4,
                            data,
                            &(data->currentFH),
                            &(arg_VERIFY4.obj_attributes.attrmask)) != 0)
    {
      res_VERIFY4.status = NFS4ERR_SERVERFAULT;
      return res_VERIFY4.status;
    }

  if((rc = nfs4_Fattr_cmp(&(arg_VERIFY4.obj_attributes), &file_attr4)) == TRUE)
    res_VERIFY4.status = NFS4_OK;
  else
    {
      if(rc == -1)
        res_VERIFY4.status = NFS4ERR_INVAL;
      else
        res_VERIFY4.status = NFS4ERR_NOT_SAME;
    }

  return res_VERIFY4.status;
}                               /* nfs4_op_verify */
static int pnfs_truncate_ds_partfile(pnfs_ds_client_t * pnfsdsclient,
                                     size_t newsize,
                                     pnfs_part_file_t * ppartfile)
{
  COMPOUND4args argnfs4;
  COMPOUND4res resnfs4;
  struct timeval timeout = { 25, 0 };
  nfs_argop4 argoparray[PNFS_LAYOUTFILE_NB_OP_TRUNCATE_DS_FILE];
  nfs_resop4 resoparray[PNFS_LAYOUTFILE_NB_OP_TRUNCATE_DS_FILE];
  fsal_attrib_list_t fsal_attr_set;
  fattr4 fattr_set;
  bitmap4 inbitmap;
  bitmap4 convert_bitmap;
  uint32_t inbitmap_val[2];
  uint32_t bitmap_res[2];
  uint32_t bitmap_set[2];
  uint32_t bitmap_conv_val[2];
  unsigned int i;

  if(!pnfsdsclient || !ppartfile )
    return NFS4ERR_SERVERFAULT;

  /* Step 1 OP4_OPEN as OPEN4_CREATE */
  argnfs4.argarray.argarray_val = argoparray;
  resnfs4.resarray.resarray_val = resoparray;
  argnfs4.minorversion = 1;

  /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Mkdir" ; */
  argnfs4.tag.utf8string_val = NULL;
  argnfs4.tag.utf8string_len = 0;
  argnfs4.argarray.argarray_len = 0;

  memset( (char *)&fsal_attr_set, 0, sizeof( fsal_attr_set ) );
  fsal_attr_set.asked_attributes = FSAL_ATTR_SIZE;
  fsal_attr_set.filesize = newsize;

  convert_bitmap.bitmap4_val = bitmap_conv_val;
  convert_bitmap.bitmap4_len = 2;
  convert_bitmap.bitmap4_val[0] = 1 << FATTR4_SIZE ;
  convert_bitmap.bitmap4_val[1] = 0 ;

  
  if(nfs4_FSALattr_To_Fattr(NULL,       /* no exportlist required here */
                            &fsal_attr_set, &fattr_set, NULL,   /* no compound data required here */
                            NULL,       /* No fh here, filehandle is not a settable attribute */
                            &convert_bitmap) == -1)
     return NFS4ERR_INVAL ;

#define PNFS_LAYOUTFILE_TRUNCATE_IDX_OP_SEQUENCE  0
#define PNFS_LAYOUTFILE_TRUNCATE_IDX_OP_PUTFH     1
#define PNFS_LAYOUTFILE_TRUNCATE_IDX_OP_SETATTR   2

  COMPOUNDV41_ARG_ADD_OP_SEQUENCE(argnfs4, pnfsdsclient->session, pnfsdsclient->sequence);
  COMPOUNDV41_ARG_ADD_OP_PUTFH(argnfs4, ppartfile->handle);
  COMPOUNDV41_ARG_ADD_OP_SETATTR(argnfs4, fattr_set);

  /* For ATTR_SIZE, stateid is needed, we use the stateless "all-0's" stateid here */
  argnfs4.argarray.argarray_val[PNFS_LAYOUTFILE_TRUNCATE_IDX_OP_SETATTR].nfs_argop4_u.
      opsetattr.stateid.seqid = 0;
  memset(argnfs4.argarray.argarray_val[PNFS_LAYOUTFILE_TRUNCATE_IDX_OP_SETATTR].
         nfs_argop4_u.opsetattr.stateid.other, 0, 12);

  resnfs4.resarray.resarray_val[PNFS_LAYOUTFILE_TRUNCATE_IDX_OP_SETATTR].nfs_resop4_u.
      opsetattr.attrsset.bitmap4_val = bitmap_set;
  resnfs4.resarray.resarray_val[PNFS_LAYOUTFILE_TRUNCATE_IDX_OP_SETATTR].nfs_resop4_u.
      opsetattr.attrsset.bitmap4_len = 2;

  /* Call the NFSv4 function */
  if(clnt_call(pnfsdsclient->rpc_client, NFSPROC4_COMPOUND,
               (xdrproc_t) xdr_COMPOUND4args, (caddr_t) & argnfs4,
               (xdrproc_t) xdr_COMPOUND4res, (caddr_t) & resnfs4, timeout) != RPC_SUCCESS)
    {
      return NFS4ERR_IO;        /* @todo: For wanting of something more appropriate */
    }

  if(resnfs4.status != NFS4_OK)
    return resnfs4.status;

  pnfsdsclient->sequence += 1;

  return NFS4_OK;
}                               /* pnfs_ds_unlink_file */
int nfs4_op_verify(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
{
  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_verify";

  fsal_attrib_list_t   file_attr;
  cache_inode_status_t cache_status;
  fattr4               file_attr4;
  int                  rc = 0;

  resp->resop = NFS4_OP_VERIFY;
  res_VERIFY4.status = NFS4_OK;

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

  /* operation is always permitted on pseudofs */
  if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    {
      res_VERIFY4.status = NFS4_OK;
      return res_VERIFY4.status;
    }

  /* Get only attributes that are allowed to be read */
  if(!nfs4_Fattr_Check_Access(&arg_VERIFY4.obj_attributes, FATTR4_ATTR_READ))
    {
      res_VERIFY4.status = NFS4ERR_INVAL;
      return res_VERIFY4.status;
    }

  /* Ask only for supported attributes */
  if(!nfs4_Fattr_Supported(&arg_VERIFY4.obj_attributes))
    {
      res_VERIFY4.status = NFS4ERR_ATTRNOTSUPP;
      return res_VERIFY4.status;
    }

  /* Get the cache inode attribute */
  if((cache_status = cache_inode_getattr(data->current_entry,
                                         &file_attr,
                                         data->pcontext,
                                         &cache_status)) != CACHE_INODE_SUCCESS)
    {
      res_VERIFY4.status = NFS4ERR_INVAL;
      return res_VERIFY4.status;
    }

  if(nfs4_FSALattr_To_Fattr(data->pexport,
                            &file_attr,
                            &file_attr4,
                            data,
                            &(data->currentFH),
                            &(arg_VERIFY4.obj_attributes.attrmask)) != 0)
    {
      res_VERIFY4.status = NFS4ERR_SERVERFAULT;
      return res_VERIFY4.status;
    }

  if((rc = nfs4_Fattr_cmp(&(arg_VERIFY4.obj_attributes), &file_attr4)) == TRUE)
    res_VERIFY4.status = NFS4_OK;
  else
    {
      if(rc == -1)
        res_VERIFY4.status = NFS4ERR_INVAL;
      else
        res_VERIFY4.status = NFS4ERR_NOT_SAME;
    }

  nfs4_Fattr_Free(&file_attr4);
  return res_VERIFY4.status;
}                               /* nfs4_op_verify */
Example #8
0
/**
 * nfs4_op_readdir: The NFS4_OP_READDIR.
 * 
 * Implements the NFS4_OP_READDIR. If fh is a pseudo FH, then call is routed to routine nfs4_op_readdir_pseudo
 *
 * @param op    [IN]    pointer to nfs4_op arguments
 * @param data  [INOUT] Pointer to the compound request's data
 * @param resp  [IN]    Pointer to nfs4_op results
 * 
 * @return NFS4_OK if ok, any other value show an error.
 *
 */
int nfs4_op_readdir(struct nfs_argop4 *op,
                    compound_data_t * data, struct nfs_resop4 *resp)
{
  cache_entry_t *dir_pentry = NULL;
  cache_entry_t *pentry = NULL;

  cache_inode_endofdir_t eod_met;
  fsal_attrib_list_t attrlookup;
  cache_inode_status_t cache_status;
  cache_inode_status_t cache_status_attr;

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

  unsigned long dircount;
  unsigned long maxcount;
  entry4 *entry_nfs_array;
  cache_inode_dir_entry_t *dirent_array;
  verifier4 cookie_verifier;
  unsigned int cookie = 0;
  unsigned int end_cookie = 0;
  unsigned int *cookie_array;
  fsal_handle_t *entry_FSALhandle;
  nfs_fh4 entryFH;
  char val_fh[NFS4_FHSIZE];
  entry_name_array_item_t *entry_name_array;
  unsigned long space_used;
  unsigned int estimated_num_entries;
  unsigned int num_entries;

  unsigned int i = 0;

  bitmap4 RdAttrErrorBitmap;
  attrlist4 RdAttrErrorVals;

  resp->resop = NFS4_OP_READDIR;
  res_READDIR4.status = NFS4_OK;

  entryFH.nfs_fh4_len = 0;
  entryFH.nfs_fh4_val = val_fh;

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

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

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

  /* Pseudo Fs management */
  if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
    return nfs4_op_readdir_pseudo(op, data, resp);

  /* Xattrs management */
  if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
    return nfs4_op_readdir_xattr(op, data, resp);

  /* You can readdir only within a directory */
  dir_pentry = data->current_entry;
  if(data->current_filetype != DIR_BEGINNING && data->current_filetype != DIR_CONTINUE)
    {
      res_READDIR4.status = NFS4ERR_NOTDIR;
      return res_READDIR4.status;
    }

  /* get the caracteristic value for readdir operation */
  dircount = arg_READDIR4.dircount;
  maxcount = arg_READDIR4.maxcount;
  cookie = (unsigned int)arg_READDIR4.cookie;
  space_used = sizeof(entry4);

  /* dircount is considered meaningless by many nfsv4 client (like the CITI one). we use maxcount instead */
  estimated_num_entries = maxcount / sizeof(entry4);    /* Estimated_num_entries is probably far too big */

  LogFullDebug(COMPONENT_NFS_V4,
      "--- nfs4_op_readdir ---> dircount=%u maxcount=%u arg_cookie=%llu cookie=%d estimated_num_entries=%u\n",
       dircount, maxcount, arg_READDIR4.cookie, cookie, estimated_num_entries);

  /* Do not use a cookie of 1 or 2 (reserved values) */
  if(cookie == 1 || cookie == 2)
    {
      res_READDIR4.status = NFS4ERR_BAD_COOKIE;
      return res_READDIR4.status;
    }

  if(cookie != 0)
    cookie = cookie - 2;        /* 0,1 and 2 are reserved, there is a delta of '3' because of this */

  /* Get only attributes that are allowed to be read */
  if(!nfs4_Fattr_Check_Access_Bitmap(&arg_READDIR4.attr_request, FATTR4_ATTR_READ))
    {
      res_READDIR4.status = NFS4ERR_INVAL;
      return res_READDIR4.status;
    }

  /* If maxcount is too short, return NFS4ERR_TOOSMALL */
  if(maxcount < sizeof(entry4) || estimated_num_entries == 0)
    {
      res_READDIR4.status = NFS4ERR_TOOSMALL;
      return res_READDIR4.status;
    }

  /*
   * If cookie verifier is used, then an non-trivial value is
   * returned to the client         This value is the mtime of
   * the pentry. If verifier is unused (as in many NFS
   * Servers) then only a set of zeros is returned (trivial
   * value) 
   */
  memset(cookie_verifier, 0, NFS4_VERIFIER_SIZE);
  if(data->pexport->UseCookieVerifier == 1)
    memcpy(cookie_verifier, &dir_pentry->internal_md.mod_time, sizeof(time_t));

  /* Cookie delivered by the server and used by the client SHOULD not ne 0, 1 or 2 (cf RFC3530, page192)
   * because theses value are reserved for special use.
   *      0 - cookie for first READDIR
   *      1 - reserved for . on client handside
   *      2 - reserved for .. on client handside
   * Entries '.' and '..' are not returned also
   * For these reason, there will be an offset of 3 between NFS4 cookie and HPSS cookie */

  if((cookie != 0) && (data->pexport->UseCookieVerifier == 1))
    {
      if(memcmp(cookie_verifier, arg_READDIR4.cookieverf, NFS4_VERIFIER_SIZE) != 0)
        {

          res_READDIR4.status = NFS4ERR_BAD_COOKIE;
          return res_READDIR4.status;
        }
    }

  /* The default behaviour is to consider that eof is not reached, the returned values by cache_inode_readdir 
   * will let us know if eod was reached or not */
  res_READDIR4.READDIR4res_u.resok4.reply.eof = FALSE;

  /* Get prepared for readdir */
  if((dirent_array =
      (cache_inode_dir_entry_t *) Mem_Alloc(estimated_num_entries *
                                            sizeof(cache_inode_dir_entry_t))) == NULL)
    {
      res_READDIR4.status = NFS4ERR_SERVERFAULT;
      return res_READDIR4.status;
    }

  if((cookie_array =
      (unsigned int *)Mem_Alloc(estimated_num_entries * sizeof(unsigned int))) == NULL)
    {
      Mem_Free((char *)dirent_array);

      res_READDIR4.status = NFS4ERR_SERVERFAULT;
      return res_READDIR4.status;
    }

  /* Perform the readdir operation */
  if(cache_inode_readdir(dir_pentry,
                         cookie,
                         estimated_num_entries,
                         &num_entries,
                         &end_cookie,
                         &eod_met,
                         dirent_array,
                         cookie_array,
                         data->ht,
                         data->pclient,
                         data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
    {
      res_READDIR4.status = nfs4_Errno(cache_status);
      return res_READDIR4.status;
    }

  /* For an empty directory, we will find only . and .., so reply af if the end if reached */
  if(num_entries == 0)
    {
      /* only . and .. */
      res_READDIR4.READDIR4res_u.resok4.reply.entries = NULL;
      res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE;
      memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier,
             NFS4_VERIFIER_SIZE);
    }
  else
    {
      /* Allocation of reply structures */
      if((entry_name_array =
          (entry_name_array_item_t *) Mem_Alloc(num_entries *
                                                (FSAL_MAX_NAME_LEN + 1))) == NULL)
        {
          LogError(COMPONENT_NFS_V4, ERR_SYS, ERR_MALLOC, errno);
          res_READDIR4.status = NFS4ERR_SERVERFAULT;
          return res_READDIR4.status;
        }
      memset((char *)entry_name_array, 0, num_entries * (FSAL_MAX_NAME_LEN + 1));

      if((entry_nfs_array = (entry4 *) Mem_Alloc(num_entries * sizeof(entry4))) == NULL)
        {
          LogError(COMPONENT_NFS_V4, ERR_SYS, ERR_MALLOC, errno);
          res_READDIR4.status = NFS4ERR_SERVERFAULT;
          return res_READDIR4.status;
        }

      for(i = 0; i < num_entries; i++)
        {
          entry_nfs_array[i].name.utf8string_val = entry_name_array[i];

          if(str2utf8(dirent_array[i].name.name, &entry_nfs_array[i].name) == -1)
            {
              res_READDIR4.status = NFS4ERR_SERVERFAULT;
              return res_READDIR4.status;
            }

          /* Set the cookie value */
          if(i != num_entries - 1)
            entry_nfs_array[i].cookie = cookie_array[i + 1] + 2;        /* 0, 1 and 2 are reserved */
          else
            entry_nfs_array[i].cookie = end_cookie + 2;

          LogFullDebug(COMPONENT_NFS_V4, " === nfs4_op_readdir ===>   i=%d name=%s cookie=%llu\n",
                 i, dirent_array[i].name.name, entry_nfs_array[i].cookie);

          /* Get the pentry for the object's attributes and filehandle */
          if((pentry = cache_inode_lookup(dir_pentry,
                                          &dirent_array[i].name,
                                          &attrlookup,
                                          data->ht,
                                          data->pclient,
                                          data->pcontext, &cache_status)) == NULL)
            {
              Mem_Free((char *)entry_nfs_array);
              Mem_Free((char *)dirent_array);
              Mem_Free((char *)cookie_array);
              /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */
              entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap;
              entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals;
              res_READDIR4.status = NFS4ERR_SERVERFAULT;
              return res_READDIR4.status;
            }

          /* If file handle is asked in the attributes, provide it */
          if(arg_READDIR4.attr_request.bitmap4_val != NULL
             && (arg_READDIR4.attr_request.bitmap4_val[0] & FATTR4_FILEHANDLE))
            {
              if((entry_FSALhandle =
                  cache_inode_get_fsal_handle(pentry, &cache_status_attr)) == NULL)
                {
                  /* Faulty Handle or pentry */
                  Mem_Free((char *)entry_nfs_array);
                  Mem_Free((char *)dirent_array);
                  Mem_Free((char *)cookie_array);
                  res_READDIR4.status = NFS4ERR_SERVERFAULT;
                  return res_READDIR4.status;
                }

              if(!nfs4_FSALToFhandle(&entryFH, entry_FSALhandle, data))
                {
                  /* Faulty type */
                  Mem_Free((char *)entry_nfs_array);
                  Mem_Free((char *)dirent_array);
                  Mem_Free((char *)cookie_array);
                  res_READDIR4.status = NFS4ERR_SERVERFAULT;
                  return res_READDIR4.status;
                }
            }

          if(nfs4_FSALattr_To_Fattr(data->pexport,
                                    &attrlookup,
                                    &(entry_nfs_array[i].attrs),
                                    data, &entryFH, &(arg_READDIR4.attr_request)) != 0)
            {
              /* Return the fattr4_rdattr_error , cf RFC3530, page 192 */
              entry_nfs_array[i].attrs.attrmask = RdAttrErrorBitmap;
              entry_nfs_array[i].attrs.attr_vals = RdAttrErrorVals;
            }

          /* Chain the entries together */
          entry_nfs_array[i].nextentry = NULL;
          if(i != 0)
            entry_nfs_array[i - 1].nextentry = &(entry_nfs_array[i]);

          /* This test is there to avoid going further than the buffer provided by the client 
           * the factor "9/10" is there for safety. Its value could be change as beta tests will be done */
          if((caddr_t)
             ((caddr_t) (&entry_nfs_array[i]) - (caddr_t) (&entry_nfs_array[0])) >
             (caddr_t) (maxcount * 9 / 10))
            break;
        }                       /* for i */

      if((eod_met == END_OF_DIR) && (i == num_entries))
        {
          /* This is the end of the directory */
          res_READDIR4.READDIR4res_u.resok4.reply.eof = TRUE;
          memcpy(res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier,
                 NFS4_VERIFIER_SIZE);
        }

      /* Put the entry's list in the READDIR reply */
      res_READDIR4.READDIR4res_u.resok4.reply.entries = entry_nfs_array;
    }

  /* Do not forget to set the verifier */
  memcpy((char *)res_READDIR4.READDIR4res_u.resok4.cookieverf, cookie_verifier,
         NFS4_VERIFIER_SIZE);

  Mem_Free((char *)dirent_array);
  Mem_Free((char *)cookie_array);
  res_READDIR4.status = NFS4_OK;

  return res_READDIR4.status;
}                               /* nfs4_op_readdir */
Example #9
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param cred (input):
 *        Authentication context for the operation (user, export...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created file.
 * \param object_attributes (optionnal input/output): 
 *        The postop attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        Can be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - ERR_FSAL_STALE        (parent_directory_handle does not address an existing object)
 *        - ERR_FSAL_FAULT        (a NULL pointer was passed as mandatory argument)
 *        - Other error codes can be returned :
 *          ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ...
 *            
 *        NB: if getting postop attributes failed,
 *        the function does not return an error
 *        but the FSAL_ATTR_RDATTR_ERR bit is set in
 *        the object_attributes->asked_attributes field.
 */
fsal_status_t PROXYFSAL_create(proxyfsal_handle_t * parent_directory_handle,    /* IN */
                               fsal_name_t * p_filename,        /* IN */
                               proxyfsal_op_context_t * p_context,      /* IN */
                               fsal_accessmode_t accessmode,    /* IN */
                               proxyfsal_handle_t * object_handle,      /* OUT */
                               fsal_attrib_list_t * object_attributes   /* [ IN/OUT ] */
    )
{
  int rc;
  COMPOUND4args argnfs4;
  COMPOUND4res resnfs4;
  nfs_fh4 nfs4fh;
  bitmap4 bitmap;
  uint32_t bitmap_val[2];
  uint32_t bitmap_res[2];
  uint32_t bitmap_conv_val[2];
  uint32_t bitmap_create[2];
  uint32_t bitmap_getattr_res[2];
  fattr4 input_attr;
  bitmap4 convert_bitmap;
  component4 name;
  char nameval[MAXNAMLEN];
  char padfilehandle[FSAL_PROXY_FILEHANDLE_MAX_LEN];
  fsal_status_t fsal_status;
  proxyfsal_file_t fd;

#define FSAL_CREATE_NB_OP_ALLOC 4
#define FSAL_CREATE_VAL_BUFFER  1024

  fsal_proxy_internal_fattr_t fattr_internal;
  fsal_attrib_list_t create_mode_attr;
  fsal_attrib_list_t attributes;
  nfs_argop4 argoparray[FSAL_CREATE_NB_OP_ALLOC];
  nfs_resop4 resoparray[FSAL_CREATE_NB_OP_ALLOC];
  char fattr_val[FSAL_CREATE_VAL_BUFFER];
  struct timeval timeout = { 25, 0 };
  char owner_val[FSAL_PROXY_OWNER_LEN];
  unsigned int owner_len = 0;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!parent_directory_handle || !p_context || !object_handle || !p_filename)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  PRINT_HANDLE("FSAL_create", parent_directory_handle);

  /* Create the owner */
  snprintf(owner_val, FSAL_PROXY_OWNER_LEN, "GANESHA/PROXY: pid=%u ctx=%p file=%llu",
           getpid(), p_context, (unsigned long long int)p_context->file_counter);
  owner_len = strnlen(owner_val, FSAL_PROXY_OWNER_LEN);
  p_context->file_counter += 1;

  /* Setup results structures */
  argnfs4.argarray.argarray_val = argoparray;
  resnfs4.resarray.resarray_val = resoparray;
  argnfs4.minorversion = 0;
  /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Mkdir" ; */
  argnfs4.tag.utf8string_val = NULL;
  argnfs4.tag.utf8string_len = 0;
  argnfs4.argarray.argarray_len = 0;

  input_attr.attrmask.bitmap4_val = bitmap_val;
  input_attr.attrmask.bitmap4_len = 2;

  input_attr.attr_vals.attrlist4_val = fattr_val;
  input_attr.attr_vals.attrlist4_len = FSAL_CREATE_VAL_BUFFER;

  fsal_internal_proxy_setup_fattr(&fattr_internal);

  convert_bitmap.bitmap4_val = bitmap_conv_val;
  convert_bitmap.bitmap4_len = 2;

  memset((char *)&name, 0, sizeof(component4));
  name.utf8string_val = nameval;
  if(fsal_internal_proxy_fsal_name_2_utf8(p_filename, &name) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  /* Get NFSv4 File handle */
  if(fsal_internal_proxy_extract_fh(&nfs4fh, parent_directory_handle) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  if(isFullDebug(COMPONENT_FSAL))
    {
      char outstr[1024];

      nfs4_sprint_fhandle(&nfs4fh, outstr);
      LogFullDebug(COMPONENT_FSAL, "FSAL_CREATE: extracted server (as client) parent handle=%s\n",
                   outstr);
    }

  bitmap.bitmap4_val = bitmap_create;
  bitmap.bitmap4_len = 2;
  fsal_internal_proxy_create_fattr_bitmap(&bitmap);

  create_mode_attr.asked_attributes = FSAL_ATTR_MODE;
  create_mode_attr.mode = accessmode;
  fsal_interval_proxy_fsalattr2bitmap4(&create_mode_attr, &convert_bitmap);

  if(nfs4_FSALattr_To_Fattr(NULL,       /* no exportlist required here */
                            &create_mode_attr, &input_attr, NULL,       /* no compound data required here */
                            NULL,       /* No fh here, filehandle is not a settable attribute */
                            &convert_bitmap) == -1)
    Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_create);

#define FSAL_CREATE_IDX_OP_PUTFH       0
#define FSAL_CREATE_IDX_OP_OPEN_CREATE 1
#define FSAL_CREATE_IDX_OP_GETFH       2
#define FSAL_CREATE_IDX_OP_GETATTR     3
  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh);
  COMPOUNDV4_ARG_ADD_OP_OPEN_CREATE(argnfs4, name, input_attr, p_context->clientid,
                                    owner_val, owner_len);
  COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4);
  COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap);

  resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen.
      OPEN4res_u.resok4.attrset.bitmap4_val = bitmap_res;
  resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen.
      OPEN4res_u.resok4.attrset.bitmap4_len = 2;

  resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh.
      GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle;
  resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh.
      GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN;

  resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_getattr_res;
  resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2;

  resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val =
      (char *)&fattr_internal;
  resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len =
      sizeof(fattr_internal);

  TakeTokenFSCall();

  /* Call the NFSv4 function */
  COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc);
  if(rc != RPC_SUCCESS)
    {
      ReleaseTokenFSCall();

      Return(ERR_FSAL_IO, rc, INDEX_FSAL_create);
    }

  ReleaseTokenFSCall();

  /* >> convert error code, and return on error << */
  if(resnfs4.status != NFS4_OK)
    return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_create);

  /* Use NFSv4 service function to build the FSAL_attr */
  if(nfs4_Fattr_To_FSAL_attr(&attributes,
                             &resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].
                             nfs_resop4_u.opgetattr.GETATTR4res_u.resok4.
                             obj_attributes) != 1)
    {
      FSAL_CLEAR_MASK(attributes.asked_attributes);
      FSAL_SET_MASK(attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR);

      Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_create);

    }

  /* Return attributes if asked */
  if(object_attributes)
    {
      memcpy(object_attributes, &attributes, sizeof(attributes));
    }

  if(isFullDebug(COMPONENT_FSAL))
    {
      char outstr[1024];

      nfs4_sprint_fhandle(&nfs4fh, outstr);
      LogFullDebug(COMPONENT_FSAL, "FSAL_CREATE: extracted server (as client) created file handle=%s\n",
           outstr);
    }

  if(fsal_internal_proxy_create_fh
     (&
      (resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh.
       GETFH4res_u.resok4.object), FSAL_TYPE_FILE, attributes.fileid,
      object_handle) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  /* Keep the information into the file descriptor as well */
  memcpy((char *)&fd.fhandle, (char *)object_handle, sizeof(fd.fhandle));

  fd.openflags = FSAL_O_RDWR;
  fd.current_offset = 0;
  fd.pcontext = p_context;

  /* Keep the returned stateid for later use */
  fd.stateid.seqid =
      resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen.
      OPEN4res_u.resok4.stateid.seqid;
  memcpy((char *)fd.stateid.other,
         resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.
         opopen.OPEN4res_u.resok4.stateid.other, 12);

  /* See if a OPEN_CONFIRM is required */
  if(resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen.
     OPEN4res_u.resok4.rflags & OPEN4_RESULT_CONFIRM)
    {
      fsal_status = FSAL_proxy_open_confirm(&fd);
      if(FSAL_IS_ERROR(fsal_status))
        Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_create);
    }
#ifdef _FSAL_CREATE_CLOSE_FILE
  /* The craeted file is still opened, to preserve the correct seqid for later use, we close it */
  fsal_status = FSAL_close(&fd);
  if(FSAL_IS_ERROR(fsal_status))
    Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_create);
#endif

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);
}                               /* FSAL_create */
Example #10
0
fsal_status_t PROXYFSAL_truncate(fsal_handle_t * file_hdl,       /* IN */
                                 fsal_op_context_t * context,    /* IN */
                                 fsal_size_t length,    /* IN */
                                 fsal_file_t * file_descriptor, /* [IN|OUT] */
                                 fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */
    )
{

  int rc;

  COMPOUND4args argnfs4;
  COMPOUND4res resnfs4;
  nfs_fh4 nfs4fh;
  uint64_t fileid;
  fsal_status_t fsal_status;
  fsal_attrib_list_t open_attrs;
  bitmap4 inbitmap;
  bitmap4 convert_bitmap;
  uint32_t inbitmap_val[2];
  uint32_t bitmap_res[2];
  uint32_t bitmap_set[2];
  uint32_t bitmap_conv_val[2];
  proxyfsal_handle_t * filehandle = (proxyfsal_handle_t *)file_hdl;
  proxyfsal_op_context_t * p_context = (proxyfsal_op_context_t *)context;

#define FSAL_TRUNCATE_NB_OP_ALLOC 3
  nfs_argop4 argoparray[FSAL_TRUNCATE_NB_OP_ALLOC];
  nfs_resop4 resoparray[FSAL_TRUNCATE_NB_OP_ALLOC];

  fsal_attrib_list_t fsal_attr_set;
  fattr4 fattr_set;
  fsal_proxy_internal_fattr_t fattr_internal;
  struct timeval timeout = TIMEOUTRPC;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!filehandle || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate);

  if(filehandle->data.object_type_reminder != FSAL_TYPE_FILE)
    {
      Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_truncate);
    }

  if(file_descriptor == NULL)
    {
      /* Use the stateless version */
      fsal_status = FSAL_proxy_truncate_stateless(file_hdl,
                                                  context, length, object_attributes);
      Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_truncate);
    }

  /* First, we need to get the fileid on a filehandle base */
  fsal_status = FSAL_DigestHandle(context->export_context,
                                  FSAL_DIGEST_FILEID4, file_hdl, (caddr_t) & fileid);
  if(FSAL_IS_ERROR(fsal_status))
    {
      Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_truncate);
    }

  /* Then we have of open the file by fileid */
  open_attrs.asked_attributes = FSAL_ATTRS_POSIX;
  fsal_status = FSAL_open_by_fileid(file_hdl,
                                    fileid,
                                    context, FSAL_O_RDWR, file_descriptor, &open_attrs);
  if(FSAL_IS_ERROR(fsal_status))
    {
      Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_truncate);
    }

  /* Setup results structures */
  argnfs4.argarray.argarray_val = argoparray;
  resnfs4.resarray.resarray_val = resoparray;
  fsal_internal_proxy_setup_fattr(&fattr_internal);
  argnfs4.minorversion = 0;
  /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Truncate" ; */
  argnfs4.tag.utf8string_val = NULL;
  argnfs4.tag.utf8string_len = 0;
  argnfs4.argarray.argarray_len = 0;

  /* Get NFSv4 File handle */
  if(fsal_internal_proxy_extract_fh(&nfs4fh, file_hdl) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate);

  /* Get prepared for truncate */
  fsal_attr_set.asked_attributes = FSAL_ATTR_SIZE;
  fsal_attr_set.filesize = length;

  convert_bitmap.bitmap4_val = bitmap_conv_val;
  convert_bitmap.bitmap4_len = 2;

  fsal_interval_proxy_fsalattr2bitmap4(&fsal_attr_set, &convert_bitmap);

  if(nfs4_FSALattr_To_Fattr(NULL,       /* no exportlist required here */
                            &fsal_attr_set, &fattr_set, NULL,   /* no compound data required here */
                            NULL,       /* No fh here, filehandle is not a settable attribute */
                            &convert_bitmap) == -1)
    Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_truncate);

  inbitmap.bitmap4_val = inbitmap_val;
  inbitmap.bitmap4_len = 2;
  fsal_internal_proxy_create_fattr_bitmap(&inbitmap);

#define FSAL_TRUNCATE_IDX_OP_PUTFH     0
#define FSAL_TRUNCATE_IDX_OP_SETATTR   1
#define FSAL_TRUNCATE_IDX_OP_GETATTR   2
  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh);
  COMPOUNDV4_ARG_ADD_OP_SETATTR(argnfs4, fattr_set);
  COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, inbitmap);

  /* For ATTR_SIZE, stateid is needed */
  argnfs4.argarray.argarray_val[FSAL_TRUNCATE_IDX_OP_SETATTR].nfs_argop4_u.opsetattr.
      stateid.seqid = ((proxyfsal_file_t *)file_descriptor)->stateid.seqid;
  memcpy(argnfs4.argarray.argarray_val[FSAL_TRUNCATE_IDX_OP_SETATTR].nfs_argop4_u.
         opsetattr.stateid.other, ((proxyfsal_file_t *)file_descriptor)->stateid.other, 12);

  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_res;
  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2;

  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val =
      (char *)&fattr_internal;
  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len =
      sizeof(fattr_internal);

  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_SETATTR].nfs_resop4_u.opsetattr.
      attrsset.bitmap4_val = bitmap_set;
  resnfs4.resarray.resarray_val[FSAL_TRUNCATE_IDX_OP_SETATTR].nfs_resop4_u.opsetattr.
      attrsset.bitmap4_len = 2;

  TakeTokenFSCall();

  COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc);
  if(rc != RPC_SUCCESS)
    {
      ReleaseTokenFSCall();

      Return(ERR_FSAL_IO, 0, INDEX_FSAL_truncate);
    }

  ReleaseTokenFSCall();

  if(resnfs4.status != NFS4_OK)
    return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_truncate);

  /* >> interpret error code << */

  /* >> Optionnaly retrieve post op attributes
   * If your filesystem truncate call can't return them,
   * you can proceed like this : <<
   */
  if(object_attributes)
    {
      if(nfs4_Fattr_To_FSAL_attr(object_attributes,
                                 &resnfs4.resarray.
                                 resarray_val[FSAL_TRUNCATE_IDX_OP_GETATTR].nfs_resop4_u.
                                 opgetattr.GETATTR4res_u.resok4.obj_attributes) != NFS4_OK)
        {
          FSAL_CLEAR_MASK(object_attributes->asked_attributes);
          FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);

          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_truncate);
        }

    }

  /* Close the previously opened filedescriptor */
  fsal_status = FSAL_close_by_fileid(file_descriptor, fileid);
  if(FSAL_IS_ERROR(fsal_status))
    {
      Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_truncate);
    }

  /* No error occured */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_truncate);
}