Esempio n. 1
0
int pnfs_ds_unlink_file(pnfs_client_t * pnfsclient,
                        pnfs_ds_file_t * pfile)
{
  component4 name;
  char nameval[MAXNAMLEN];
  char filename[MAXNAMLEN];
  unsigned int i;
  int rc = 0;

  if(!pnfsclient || !pfile)
    return NFS4ERR_SERVERFAULT;

  name.utf8string_val = nameval;
  name.utf8string_len = 0;
  snprintf(filename, MAXNAMLEN, "%s", pfile->location.str_mds_handle);
  if(str2utf8(filename, &name) == -1)
    return NFS4ERR_SERVERFAULT;

  for(i = 0; i < pnfsclient->nb_ds; i++)
    {
      if((rc =
          pnfs_unlink_ds_partfile(&(pnfsclient->ds_client[i]), name, 
                                  &(pfile->filepart[i]))) != NFS4_OK)
        return rc;
    }

  return NFS4_OK;
}                               /* pnfs_ds_unlink_file */
int fsal_internal_proxy_fsal_path_2_utf8(fsal_path_t * ppath, utf8string * utf8str)
{
  char tmpstr[FSAL_MAX_PATH_LEN];
  fsal_status_t fsal_status;

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

  fsal_status = FSAL_path2str(ppath, tmpstr, FSAL_MAX_NAME_LEN);
  if(fsal_status.major != ERR_FSAL_NO_ERROR)
    return FALSE;

  if(utf8str->utf8string_len == 0)
    {
      if((utf8str->utf8string_val = gsh_malloc(ppath->len)) == NULL)
        return FALSE;
      else
        utf8str->utf8string_len = ppath->len;
    }

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

  return TRUE;
}                               /* fsal_internal_proxy_fsal_path_2_utf8 */
Esempio n. 3
0
int fsal_internal_proxy_fsal_name_2_utf8(fsal_name_t * pname, utf8string * utf8str)
{
  char tmpstr[FSAL_MAX_NAME_LEN];
  fsal_status_t fsal_status;

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

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

  if(utf8str->utf8string_len == 0)
    {
      if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(pname->len,
                                                            "fsal_internal_proxy_fsal_name_2_utf8")) == NULL)
        return FALSE;
      else
        utf8str->utf8string_len = pname->len;
    }

  if(str2utf8(tmpstr, utf8str) == -1)
    return FALSE;
  return TRUE;
}                               /* fsal_internal_proxy_fsal_name_2_utf8 */
Esempio n. 4
0
File: a2c.c Progetto: sacado/arc2c
void PR(){
  pair * p;
  tagged * t;
  obj y = TOS();

  if (AFIX(y))
    printf ("%ld", OBJ2FIX(y));
  else if (ACHAR(y)){
    char * utf8 = cpt2utf8(OBJ2CHAR(y));
    printf ("%s", utf8);
    free(utf8);
  }
  else if (ASYM(y))
    printf ("%s", ((symbol *)y)->value);
  else if (AFLOAT(y))
    printf ("%g", ((flonum*)y)->value);
  else if (ASTR(y))
    printf ("%s", str2utf8 ((string *) y));
  else if (AFN(y))
    printf ("#<procedure>");
  else if (ATBL(y))
    pr_tbl((table *) y);
  else if (ATAG(y)){
    t = (tagged *) y;
    printf ("#3(tagged ");
    PUSH(t->ctype); PR();
    printf (" ");
    TOS() = t->content; PR(); sp--; 
    printf (")");
  }
  else if (APAIR(y)){
    printf ("(");

    while (APAIR(y)){
        p = (pair *) y;
        PUSH(p->car); PR(); sp--;
        y = p->cdr;

        if (APAIR(y))
          printf (" ");
   }

   if (y != SYM2OBJ("nil")){
       PUSH(y);
       printf (" . ");
       PR(); sp--;
    }
    printf (")");
  }
}
Esempio n. 5
0
/**
 *
 * gid2utf8: converts a gid to a utf8 string descriptor.
 *
 * Converts a gid to a utf8 string descriptor.
 *
 * @param gid     [IN]  the input gid
 * @param utf8str [OUT] computed UTF8 string descriptor
 *
 * @return the length of the utf8 buffer if succesfull, -1 if failed
 *
 */
int gid2utf8(gid_t gid, utf8string * utf8str)
{
  char buff[NFS4_MAX_DOMAIN_LEN];
  unsigned int len = 0;

  if(gid2str(gid, buff) == -1)
    return -1;

  len = strlen(buff);

  /* A matching gid was found */
  /* Do the conversion to uft8 format */
  if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(len, "gid2utf8")) == NULL)
    return -1;
  else
    utf8str->utf8string_len = len;

  return str2utf8(buff, utf8str);
}                               /* gid2utf8 */
Esempio n. 6
0
/**
 *
 * uid2utf8: converts a uid to a utf8 string descriptor.
 *
 * Converts a uid to a utf8 string descriptor.
 *
 * @param uid     [IN]  the input uid
 * @param utf8str [OUT] computed UTF8 string descriptor
 *
 * @return the length of the utf8 buffer if succesfull, -1 if failed
 *
 */
int uid2utf8(uid_t uid, utf8string * utf8str)
{
  char buff[NFS4_MAX_DOMAIN_LEN];
  unsigned int len = 0;

  if(uid2str(uid, buff) == -1)
    return -1;

  len = strlen(buff);

  /* A matching uid was found, now do the conversion to utf8 */
  if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(len, "uid2utf8")) == NULL)
    return -1;
  else
    utf8str->utf8string_len = len;

  return str2utf8(buff, utf8str);

}                               /* uid2utf8 */
Esempio n. 7
0
int pnfs_ds_create_file(pnfs_client_t * pnfsclient,
                        pnfs_ds_loc_t * plocation, pnfs_ds_file_t * pfile)
{
  component4 name;
  char nameval[MAXNAMLEN];
  char filename[MAXNAMLEN];
  int rc;
  unsigned int i = 0;

  if(!pnfsclient || !pfile || !plocation)
    return NFS4ERR_SERVERFAULT;

  name.utf8string_val = nameval;
  name.utf8string_len = 0;

  snprintf(filename, MAXNAMLEN, "%s", plocation->str_mds_handle ) ;

  if(str2utf8(filename, &name) == -1)
    return NFS4ERR_SERVERFAULT;

  for(i = 0; i < pnfsclient->nb_ds; i++)
    {

      if((rc = pnfs_create_ds_partfile(&(pnfsclient->ds_client[i]),
                                       name, plocation, &(pfile->filepart[i]))) != NFS4_OK)
        return rc;

    }                           /* for */

  strncpy ( pfile->location.str_mds_handle, plocation->str_mds_handle, MAXNAMLEN ) ;
  
  pfile->allocated = TRUE;
  pfile->stripe = pnfsclient->nb_ds;

  return NFS4_OK;
}                               /* pnfs_ds_create_file */
Esempio n. 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 = 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 */
Esempio n. 9
0
int nfs4_op_readlink(struct nfs_argop4 *op,
                     compound_data_t * data, struct nfs_resop4 *resp)
{
  cache_inode_status_t cache_status;
  fsal_path_t symlink_path;

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

  resp->resop = NFS4_OP_READLINK;
  res_READLINK4.status = NFS4_OK;

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

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

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

  /* You can readlink only on a link ... */
  if(data->current_filetype != SYMBOLIC_LINK)
    {
      /* As said on page 194 of RFC3530, return NFS4ERR_INVAL in this case */
      res_READLINK4.status = NFS4ERR_INVAL;
      return res_READLINK4.status;
    }

  /* Using cache_inode_readlink */
  if(cache_inode_readlink(data->current_entry,
                          &symlink_path,
                          data->ht,
                          data->pclient,
                          data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
    {
      /* Alloc read link */

      if((res_READLINK4.READLINK4res_u.resok4.link.utf8string_val =
          (char *)Mem_Alloc_Label(symlink_path.len, "nfs4_op_readlink")) == NULL)
        {
          res_READLINK4.status = NFS4ERR_INVAL;
          return res_READLINK4.status;
        }

      /* convert the fsal path to a utf8 string */
      if(str2utf8((char *)symlink_path.path, &res_READLINK4.READLINK4res_u.resok4.link)
         == -1)
        {
          res_READLINK4.status = NFS4ERR_INVAL;
          return res_READLINK4.status;
        }

      res_READLINK4.status = NFS4_OK;
      return res_READLINK4.status;
    }

  res_READLINK4.status = nfs4_Errno(cache_status);
  return res_READLINK4.status;
}                               /* nfs4_op_readlink */
Esempio n. 10
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 */
Esempio n. 11
0
/**
 *
 * pnfs_lookup: looks up for a path's component.
 *
 * Looks up for a path's component.
 *
 * @param pnfsclient              [IN]  pointer to the pnfsclient structure (client to the ds).
 * @param parent_directory_handle [IN]  the NFSv4 file handle for the parent directory
 * @param filename                [IN]  the path's component to be looked up
 * @param object_handle           [OUT] the resulting NFSv4 file handle
 *
 * @return NFS4_OK if successful
 * @return a NFSv4 error (positive value) if failed.
 *
 */
int pnfs_lookup(pnfs_ds_client_t * pnfsdsclient, nfs_fh4 * parent_directory_handle,     /* IN */
                char *filename, /* IN */
                nfs_fh4 * object_handle)
{

  int rc;
  nfs_fh4 nfs4fh;
  component4 name;
  char nameval[MAXNAMLEN];
  unsigned int index_getfh = 0;

  COMPOUND4args argnfs4;
  COMPOUND4res resnfs4;
  struct timeval timeout = { 25, 0 };

#define  PNFS_LAYOUTFILE_NB_OP_ALLOC 4
  nfs_argop4 argoparray[PNFS_LAYOUTFILE_NB_OP_ALLOC];
  nfs_resop4 resoparray[PNFS_LAYOUTFILE_NB_OP_ALLOC];
  uint32_t bitmap_res[2];

  char padfilehandle[PNFS_LAYOUTFILE_FILEHANDLE_MAX_LEN];

  /* sanity checks
   * note : object_attributes is optionnal
   *        parent_directory_handle may be null for getting FS root.
   */
  if(!object_handle || !filename || !object_handle)
    return NFS4ERR_INVAL;

  /* Setup results structures */
  argnfs4.argarray.argarray_val = argoparray;
  resnfs4.resarray.resarray_val = resoparray;
  argnfs4.minorversion = 1;
  argnfs4.argarray.argarray_len = 0;

  name.utf8string_val = nameval;
  name.utf8string_len = 0;

  if(!parent_directory_handle)
    {
      /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Lookup Root" ; */
      argnfs4.tag.utf8string_val = NULL;
      argnfs4.tag.utf8string_len = 0;

#define PNFS_LOOKUP_IDX_OP_SEQUENCE       0
#define PNFS_LOOKUP_IDX_OP_PUTROOTFH      1
#define PNFS_LOOKUP_IDX_OP_GETFH_ROOT     2
      COMPOUNDV41_ARG_ADD_OP_SEQUENCE(argnfs4, pnfsdsclient->session,
                                      pnfsdsclient->sequence);
      COMPOUNDV41_ARG_ADD_OP_PUTROOTFH(argnfs4);
      COMPOUNDV41_ARG_ADD_OP_GETFH(argnfs4);

      index_getfh = PNFS_LOOKUP_IDX_OP_GETFH_ROOT;

      resnfs4.resarray.resarray_val[PNFS_LOOKUP_IDX_OP_GETFH_ROOT].nfs_resop4_u.opgetfh.
          GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle;
      resnfs4.resarray.resarray_val[PNFS_LOOKUP_IDX_OP_GETFH_ROOT].nfs_resop4_u.opgetfh.
          GETFH4res_u.resok4.object.nfs_fh4_len = PNFS_LAYOUTFILE_FILEHANDLE_MAX_LEN;
    }
  else                          /* this is a real lookup(parent, name)  */
    {
      /* the filename should not be null */
      if(filename == NULL)
        return NFS4ERR_INVAL;

      if(str2utf8(filename, &name) == -1)
        return NFS4ERR_SERVERFAULT;

      nfs4fh.nfs_fh4_len = parent_directory_handle->nfs_fh4_len;
      nfs4fh.nfs_fh4_val = parent_directory_handle->nfs_fh4_val;

      /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Lookup name" ; */
      argnfs4.tag.utf8string_val = NULL;
      argnfs4.tag.utf8string_len = 0;

#define PNFS_LOOKUP_IDX_OP_SEQUENCE  0
#define PNFS_LOOKUP_IDX_OP_PUTFH     1
#define PNFS_LOOKUP_IDX_OP_LOOKUP    2
#define PNFS_LOOKUP_IDX_OP_GETFH     3
      COMPOUNDV41_ARG_ADD_OP_SEQUENCE(argnfs4, pnfsdsclient->session,
                                      pnfsdsclient->sequence);
      COMPOUNDV41_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh);
      COMPOUNDV41_ARG_ADD_OP_LOOKUP(argnfs4, name);
      COMPOUNDV41_ARG_ADD_OP_GETFH(argnfs4);

      index_getfh = PNFS_LOOKUP_IDX_OP_GETFH;

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

    }

  /* 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 */
    }

  /* Increment the sequence */
  pnfsdsclient->sequence += 1;

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

  object_handle->nfs_fh4_len =
      resnfs4.resarray.resarray_val[index_getfh].nfs_resop4_u.opgetfh.GETFH4res_u.resok4.
      object.nfs_fh4_len;
  memcpy((char *)object_handle->nfs_fh4_val,
         (char *)resnfs4.resarray.resarray_val[index_getfh].nfs_resop4_u.opgetfh.
         GETFH4res_u.resok4.object.nfs_fh4_val,
         resnfs4.resarray.resarray_val[index_getfh].nfs_resop4_u.opgetfh.GETFH4res_u.
         resok4.object.nfs_fh4_len);

  /* lookup complete ! */
  return NFS4_OK;
}