Exemple #1
0
/**
 * FSAL_setattrs:
 * Set attributes for the object specified by its filehandle.
 *
 * \param filehandle (input):
 *        The handle of the object to get parameters.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param attrib_set (mandatory input):
 *        The attributes to be set for the object.
 *        It defines the attributes that the caller
 *        wants to set and their values.
 * \param object_attributes (optionnal input/output):
 *        The post operation attributes for the object.
 *        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).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t LUSTREFSAL_setattrs(fsal_handle_t * p_filehandle,   /* IN */
                                  fsal_op_context_t * p_context,  /* IN */
                                  fsal_attrib_list_t * p_attrib_set,    /* IN */
                                  fsal_attrib_list_t * p_object_attributes      /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  unsigned int i;
  fsal_status_t status;
  fsal_attrib_list_t attrs;

  fsal_path_t fsalpath;
  struct stat buffstat;

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

  /* local copy of attributes */
  attrs = *p_attrib_set;

  /* First, check that FSAL attributes changes are allowed. */

  /* Is it allowed to change times ? */

  if(!global_fs_info.cansettime)
    {

      if(attrs.asked_attributes
         & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
        {
          /* handled as an unsettable attribute. */
          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
        }
    }

  /* apply umask, if mode attribute is to be changed */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
    {
      attrs.mode &= (~global_fs_info.umask);
    }

  /* convert handle into path */
  status = fsal_internal_Handle2FidPath(p_context, p_filehandle, &fsalpath);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_setattrs);

  /* get current attributes */
  TakeTokenFSCall();
  rc = lstat(fsalpath.path, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc != 0)
    {
      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_setattrs);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
    }

  /***********
   *  CHMOD  *
   ***********/
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
    {

      /* The POSIX chmod call don't affect the symlink object, but
       * the entry it points to. So we must ignore it.
       */
      if(!S_ISLNK(buffstat.st_mode))
        {

          /* For modifying mode, user must be root or the owner */
          if((p_context->credential.user != 0)
             && (p_context->credential.user != buffstat.st_uid))
            {
              LogFullDebug(COMPONENT_FSAL,
                                "Permission denied for CHMOD opeartion: current owner=%d, credential=%d",
                                buffstat.st_uid, p_context->credential.user);
              Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
            }

          TakeTokenFSCall();
          rc = chmod(fsalpath.path, fsal2unix_mode(attrs.mode));
          errsv = errno;
          ReleaseTokenFSCall();

          if(rc)
            {
              Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
            }

        }

    }

  /***********
   *  CHOWN  *
   ***********/
  /* Only root can change uid and A normal user must be in the group he wants to set */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER))
    {

      /* For modifying owner, user must be root or current owner==wanted==client */
      if((p_context->credential.user != 0) &&
         ((p_context->credential.user != buffstat.st_uid) ||
          (p_context->credential.user != attrs.owner)))
        {
          LogFullDebug(COMPONENT_FSAL,
                            "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d",
                            buffstat.st_uid, p_context->credential.user, attrs.owner);
          Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
        }
    }

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP))
    {

      /* For modifying group, user must be root or current owner */
      if((p_context->credential.user != 0)
         && (p_context->credential.user != buffstat.st_uid))
        Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);

      int in_grp = 0;
      /* set in_grp */
      if(p_context->credential.group == attrs.group)
        in_grp = 1;
      else
        for(i = 0; i < p_context->credential.nbgroups; i++)
          {
            if((in_grp = (attrs.group == p_context->credential.alt_groups[i])))
              break;
          }

      /* it must also be in target group */
      if(p_context->credential.user != 0 && !in_grp)
        {
          LogFullDebug(COMPONENT_FSAL,
                            "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d",
                            buffstat.st_gid, p_context->credential.group, attrs.group);

          Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
        }
    }

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
    {
      LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)",
                        fsalpath.path, FSAL_TEST_MASK(attrs.asked_attributes,
                                                      FSAL_ATTR_OWNER) ? (int)attrs.owner
                        : -1, FSAL_TEST_MASK(attrs.asked_attributes,
                                             FSAL_ATTR_GROUP) ? (int)attrs.group : -1);

      TakeTokenFSCall();
      rc = lchown(fsalpath.path,
                  FSAL_TEST_MASK(attrs.asked_attributes,
                                 FSAL_ATTR_OWNER) ? (int)attrs.owner : -1,
                  FSAL_TEST_MASK(attrs.asked_attributes,
                                 FSAL_ATTR_GROUP) ? (int)attrs.group : -1);
      ReleaseTokenFSCall();
      if(rc)
        Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
    }

  /***********
   *  UTIME  *
   ***********/

  /* user must be the owner or have read access to modify 'atime' */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME)
     && (p_context->credential.user != 0)
     && (p_context->credential.user != buffstat.st_uid)
     && ((status = fsal_internal_testAccess(p_context, FSAL_R_OK, &buffstat, NULL)).major
         != ERR_FSAL_NO_ERROR))
    ReturnStatus(status, INDEX_FSAL_setattrs);

  /* user must be the owner or have write access to modify 'mtime' */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME)
     && (p_context->credential.user != 0)
     && (p_context->credential.user != buffstat.st_uid)
     && ((status = fsal_internal_testAccess(p_context, FSAL_W_OK, &buffstat, NULL)).major
         != ERR_FSAL_NO_ERROR))
    ReturnStatus(status, INDEX_FSAL_setattrs);

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME))
    {

      struct utimbuf timebuf;

      timebuf.actime =
          (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs.
           atime.seconds : buffstat.st_atime);
      timebuf.modtime =
          (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs.
           mtime.seconds : buffstat.st_mtime);

      TakeTokenFSCall();
      rc = utime(fsalpath.path, &timebuf);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);

    }

  /* Optionaly fills output attributes. */

  if(p_object_attributes)
    {
      status = LUSTREFSAL_getattrs(p_filehandle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);

}
Exemple #2
0
fsal_status_t ZFSFSAL_rename(fsal_handle_t * old_parentdir_handle, /* IN */
                          fsal_name_t * p_old_name,     /* IN */
                          fsal_handle_t * new_parentdir_handle, /* IN */
                          fsal_name_t * p_new_name,     /* IN */
                          fsal_op_context_t * p_context,        /* IN */
                          fsal_attrib_list_t * src_dir_attributes,      /* [ IN/OUT ] */
                          fsal_attrib_list_t * tgt_dir_attributes       /* [ IN/OUT ] */
    )
{

  int rc;
  creden_t cred;

  /* sanity checks.
   * note : src/tgt_dir_attributes are optional.
   */
  if(!old_parentdir_handle ||
     !new_parentdir_handle || !p_old_name || !p_new_name || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

  /* Hook to prenvet moving thing from or to a snapshot */
  if(((zfsfsal_handle_t *)old_parentdir_handle)->data.i_snap != 0 ||
     ((zfsfsal_handle_t *)new_parentdir_handle)->data.i_snap != 0)
  {
    LogDebug(COMPONENT_FSAL, "Trying to rename an object from/to a snapshot");
    Return(ERR_FSAL_ROFS, 0, INDEX_FSAL_rename);
  }
  cred.uid = p_context->credential.user;
  cred.gid = p_context->credential.group;

  TakeTokenFSCall();

  rc = libzfswrap_rename(((zfsfsal_op_context_t *)p_context)->export_context->p_vfs,
			 &cred,
                         ((zfsfsal_handle_t *)old_parentdir_handle)->data.zfs_handle,
			 p_old_name->name,
                         ((zfsfsal_handle_t *)new_parentdir_handle)->data.zfs_handle,
			 p_new_name->name);

  ReleaseTokenFSCall();

  /* >> interpret the returned error << */
  if(rc)
    Return(posix2fsal_error(rc), 0, INDEX_FSAL_rename);

  /* >> get last parent post op attributes if asked
   * For example : << */

  if(src_dir_attributes)
    {
      fsal_status_t st;

      st = ZFSFSAL_getattrs(old_parentdir_handle, p_context, src_dir_attributes);

      if(FSAL_IS_ERROR(st))
        {
          FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes);
          FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* >> get new parent post op attributes if asked
   * For example : << */

  if(tgt_dir_attributes)
    {
      fsal_status_t st;

      /* optimization when src=tgt : */

      if(!ZFSFSAL_handlecmp(old_parentdir_handle, new_parentdir_handle, &st)
         && src_dir_attributes)
        {

          /* If source dir = target dir, we just copy the attributes.
           * to avoid doing another getattr.
           */

          (*tgt_dir_attributes) = (*src_dir_attributes);

        }
      else
        {

          /* get attributes */
          st = ZFSFSAL_getattrs(new_parentdir_handle, p_context, tgt_dir_attributes);

          if(FSAL_IS_ERROR(st))
            {
              FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes);
              FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
            }

        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename);

}
Exemple #3
0
/**
 * FSAL_symlink:
 * Create a symbolic link.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the link is to be created.
 * \param p_linkname (input):
 *        Name of the link to be created.
 * \param p_linkcontent (input):
 *        Content of the link to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (ignored input):
 *        Mode of the link to be created.
 *        It has no sense in HPSS nor UNIX filesystems.
 * \param link_handle (output):
 *        Pointer to the handle of the created symlink.
 * \param link_attributes (optionnal input/output): 
 *        Attributes of the newly created symlink.
 *        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).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t LUSTREFSAL_symlink(fsal_handle_t * p_parent_directory_handle,       /* IN */
                                 fsal_name_t * p_linkname,      /* IN */
                                 fsal_path_t * p_linkcontent,   /* IN */
                                 fsal_op_context_t * p_context,   /* IN */
                                 fsal_accessmode_t accessmode,  /* IN (ignored) */
                                 fsal_handle_t * p_link_handle,   /* OUT */
                                 fsal_attrib_list_t * p_link_attributes /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  fsal_status_t status;
  fsal_path_t fsalpath;
  struct stat buffstat;
  int setgid_bit = FALSE;

  /* sanity checks.
   * note : link_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context ||
     !p_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);

  /* build the new path and check the permissions on the parent directory */
  status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &fsalpath);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_symlink);

  /* retrieve directory metadata, for checking access */
  TakeTokenFSCall();
  rc = lstat(fsalpath.path, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc)
    {
      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_symlink);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink);
    }

  if(buffstat.st_mode & S_ISGID)
    setgid_bit = TRUE;

  status = fsal_internal_testAccess(p_context, FSAL_W_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_symlink);

  /* build symlink path */

  status = fsal_internal_appendNameToPath(&fsalpath, p_linkname);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_symlink);

  /* create the symlink on the filesystem. */

  TakeTokenFSCall();
  rc = symlink(p_linkcontent->path, fsalpath.path);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink);

  /* Get symlink handle */
  TakeTokenFSCall();
  status = fsal_internal_Path2Handle(p_context, &fsalpath, p_link_handle);
  ReleaseTokenFSCall();
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_lookup);

  /* chown the symlink to the current user/group */

  TakeTokenFSCall();
  rc = lchown(fsalpath.path, p_context->credential.user,
              setgid_bit ? -1 : p_context->credential.group);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink);

  /* get attributes if asked */

  if(p_link_attributes)
    {

      status = LUSTREFSAL_getattrs(p_link_handle, p_context, p_link_attributes);

      /* On error, we set a flag in the returned attributes */

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_link_attributes->asked_attributes);
          FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_symlink);
}
Exemple #4
0
fsal_status_t VFSFSAL_truncate(fsal_handle_t * p_filehandle,       /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            fsal_size_t length, /* IN */
                            fsal_file_t * file_descriptor,      /* Unused in this FSAL */
                            fsal_attrib_list_t * p_object_attributes    /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  int fd;
  fsal_status_t st;

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

  /* get the path of the file and its handle */
  TakeTokenFSCall();
  st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDWR);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(st))
    ReturnStatus(st, INDEX_FSAL_truncate);

  /* Executes the POSIX truncate operation */

  TakeTokenFSCall();
  rc = ftruncate(fd, length);
  errsv = errno;
  ReleaseTokenFSCall();

  close(fd);

  /* convert return code */
  if(rc)
    {
      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_truncate);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_truncate);
    }

  /* Optionally retrieve attributes */
  if(p_object_attributes)
    {

      fsal_status_t st;

      st = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);

      if(FSAL_IS_ERROR(st))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

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

}
Exemple #5
0
/**
 * FSAL_opendir :
 *     Opens a directory for reading its content.
 *
 * \param dir_handle (input)
 *         the handle of the directory to be opened.
 * \param p_context (input)
 *         Permission context for the operation (user, export context...).
 * \param dir_descriptor (output)
 *         pointer to an allocated structure that will receive
 *         directory stream informations, on successfull completion.
 * \param dir_attributes (optional output)
 *         On successfull completion,the structure pointed
 *         by dir_attributes receives the new directory attributes.
 *         Can be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - ERR_FSAL_ACCESS       (user does not have read permission on directory)
 *        - ERR_FSAL_STALE        (dir_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_IO, ...
 */
fsal_status_t FUSEFSAL_opendir(fsal_handle_t * dir_hdl,  /* IN */
                               fsal_op_context_t * p_context,       /* IN */
                               fsal_dir_t * dir_desc,     /* OUT */
                               fsal_attrib_list_t * dir_attributes      /* [ IN/OUT ] */
    )
{
  int rc;
  char object_path[FSAL_MAX_PATH_LEN];
  fusefsal_dir_t * dir_descriptor = (fusefsal_dir_t *)dir_desc;
  fusefsal_handle_t * dir_handle = (fusefsal_handle_t *)dir_hdl;

  /* sanity checks
   * note : dir_attributes is optionnal.
   */
  if(!dir_handle || !p_context || !dir_descriptor)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir);

  /* get the full path for this directory */
  rc = NamespacePath(dir_handle->data.inode, dir_handle->data.device, dir_handle->data.validator,
                     object_path);
  if(rc)
    Return(ERR_FSAL_STALE, rc, INDEX_FSAL_opendir);

  memset(dir_descriptor, 0, sizeof(fsal_dir_t));

  /* set context for the next operation, so it can be retrieved by FS thread */
  fsal_set_thread_context(p_context);

  /* check opendir call */

  if(p_fs_ops->opendir)
    {
      TakeTokenFSCall();
      rc = p_fs_ops->opendir(object_path, &(dir_descriptor->dir_info));
      ReleaseTokenFSCall();

      if(rc)
        Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_opendir);
    }
  else
    {
      /* ignoring opendir */
      memset(&(dir_descriptor->dir_info), 0, sizeof(struct ganefuse_file_info));
    }

  /* fill the dir descriptor structure */
  dir_descriptor->dir_handle = *dir_handle;

  /* backup context */
  dir_descriptor->context = *(fusefsal_op_context_t *)p_context;

  /* optionaly get attributes */
  if(dir_attributes)
    {
      fsal_status_t status;

      status = FUSEFSAL_getattrs(dir_hdl, p_context, dir_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(dir_attributes->asked_attributes);
          FSAL_SET_MASK(dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }
    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir);

}
Exemple #6
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 */
Exemple #7
0
fsal_status_t HPSSFSAL_readdir(hpssfsal_dir_t * dir_descriptor, /* IN */
                               fsal_op_context_t * p_context,       /* IN */
                               hpssfsal_cookie_t start_position,        /* IN */
                               fsal_attrib_mask_t get_attr_mask,        /* IN */
                               fsal_mdsize_t buffersize,        /* IN */
                               fsal_dirent_t * pdirent, /* OUT */
                               hpssfsal_cookie_t * end_position,        /* OUT */
                               fsal_count_t * nb_entries,       /* OUT */
                               fsal_boolean_t * end_of_dir      /* OUT */ )
{
  int rc, returned, i;
  fsal_status_t st;

  fsal_attrib_mask_t handle_attr_mask;
  fsal_count_t current_nb_entries, missing_entries, max_dir_entries;

  /* hpss_ReadRawAttrsHandle arguments. */

  u_signed64 curr_start_position;
  unsigned32 buff_size_in;
  unsigned32 bool_getattr_in;
  unsigned32 bool_eod_out;
  u_signed64 last_offset_out;
  //ns_DirEntry_t outbuff[FSAL_READDIR_SIZE];
  ns_DirEntry_t * outbuff = NULL ;

  /* sanity checks */

  if(!dir_descriptor || !pdirent || !end_position || !nb_entries || !end_of_dir)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  if((outbuff = gsh_calloc(FSAL_READDIR_SIZE, sizeof(ns_DirEntry_t))) == NULL)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  /* handle provides : suppattr, type, fileid */
  /** @todo : does handle provide mounted_on_fileid ? */

  handle_attr_mask = FSAL_ATTR_SUPPATTR | FSAL_ATTR_TYPE | FSAL_ATTR_FILEID;

  /* if the handle cannot provide the requested attributes,
   * we have to retrieve file attributes. */

  if(get_attr_mask & (~handle_attr_mask))
    bool_getattr_in = TRUE;
  else
    bool_getattr_in = FALSE;

  /* init values */

  curr_start_position = start_position.data;
  bool_eod_out = 0;
  current_nb_entries = 0;
  max_dir_entries = (buffersize / sizeof(fsal_dirent_t));

  /* while we haven't filled the output buffer
   * and the end of dir has not been reached :
   */
  while((current_nb_entries < max_dir_entries) && (!bool_eod_out))
    {

      missing_entries = max_dir_entries - current_nb_entries;

      /* If the requested count is smaller than the default FSAL_READDIR_SIZE,
       * we use a smaller output buffer.
       */
      if(missing_entries < FSAL_READDIR_SIZE)
        buff_size_in = missing_entries * sizeof(ns_DirEntry_t);
      else
        buff_size_in = FSAL_READDIR_SIZE * sizeof(ns_DirEntry_t);

      /* call to hpss clapi */

      TakeTokenFSCall();

      rc = HPSSFSAL_ReadRawAttrsHandle(&(dir_descriptor->dir_handle.data.ns_handle),
                                       curr_start_position,
                                       &dir_descriptor->context.credential.hpss_usercred,
                                       buff_size_in,
                                       bool_getattr_in,
                                       ReturnInconsistentDirent,
                                       &bool_eod_out, &last_offset_out, outbuff);

      ReleaseTokenFSCall();

      if(rc < 0)
       {
         gsh_free( outbuff ) ;
         Return(hpss2fsal_error(rc), -rc, INDEX_FSAL_readdir);
       }
      else
        returned = rc;

      /* Fills the fsal dirent list. */

      for(i = 0; i < returned; i++)
        {

          memset( (char *)&(pdirent[current_nb_entries].handle), 0, sizeof( hpssfsal_handle_t ) ) ;
          pdirent[current_nb_entries].handle.data.ns_handle = outbuff[i].ObjHandle;

          pdirent[current_nb_entries].handle.data.obj_type =
              hpss2fsal_type(outbuff[i].ObjHandle.Type);

          st = FSAL_str2name((char *)outbuff[i].Name, HPSS_MAX_FILE_NAME,
                             &pdirent[current_nb_entries].name);

      /** @todo : test returned status */

          pdirent[current_nb_entries].cookie.data = outbuff[i].ObjOffset;

          /* set asked attributes */
          pdirent[current_nb_entries].attributes.asked_attributes = get_attr_mask;

          if(bool_getattr_in)
            {

              /* convert HPSS attributes to fsal attributes */
              st = hpss2fsal_attributes(&outbuff[i].ObjHandle,
                                        &outbuff[i].Attrs,
                                        &pdirent[current_nb_entries].attributes);

              /* on error, we set a special bit in the mask. */
              if(FSAL_IS_ERROR(st))
                {
                  FSAL_CLEAR_MASK(pdirent[current_nb_entries].attributes.
                                  asked_attributes);
                  FSAL_SET_MASK(pdirent[current_nb_entries].attributes.asked_attributes,
                                FSAL_ATTR_RDATTR_ERR);
                }

            }
          else if(get_attr_mask)
            {

              /* extract asked attributes from file handle */
              st = hpssHandle2fsalAttributes(&outbuff[i].ObjHandle,
                                             &pdirent[current_nb_entries].attributes);

              /* on error, we set a special bit in the mask. */
              if(FSAL_IS_ERROR(st))
                {
                  FSAL_CLEAR_MASK(pdirent[current_nb_entries].attributes.
                                  asked_attributes);
                  FSAL_SET_MASK(pdirent[current_nb_entries].attributes.asked_attributes,
                                FSAL_ATTR_RDATTR_ERR);
                }

            }

          /* set the previous' next */
          if(current_nb_entries)
            pdirent[current_nb_entries - 1].nextentry = &(pdirent[current_nb_entries]);

          /* current's next */
          pdirent[current_nb_entries].nextentry = NULL;

          /* increment entries count */
          current_nb_entries++;
          curr_start_position = last_offset_out;
        }

    }

  /* At this point, 2 cases :
   * - the requested count is reached
   * - the end of dir is reached.
   * However, the treatment is the same.
   */

  /* setting output vars. */

  /* if no item was read, the offset keeps the same. */
  end_position->data = (current_nb_entries == 0 ? start_position.data : last_offset_out);

  *nb_entries = current_nb_entries;
  *end_of_dir = (bool_eod_out ? TRUE : FALSE);

  LogDebug(COMPONENT_FSAL, "%s() returned %u entries, end_of_dir=%d", __func__, *nb_entries, *end_of_dir);

  gsh_free( outbuff ) ;
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); /* @todo badly set fsal_log ? */
}
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param extparent (input):
 *        Handle of the parent directory where the file is to be created.
 * \param filename (input):
 *        Pointer to the name of the file to be created.
 * \param context (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 CEPHFSAL_create(fsal_handle_t * extparent,
                              fsal_name_t * filename,
                              fsal_op_context_t * extcontext,
                              fsal_accessmode_t accessmode,
                              fsal_handle_t * object_handle,
                              fsal_attrib_list_t * object_attributes)
{
  int rc;
  mode_t mode;
  struct Fh *fd;
  struct stat st;
  char strname[FSAL_MAX_NAME_LEN];
  cephfsal_handle_t* parent = (cephfsal_handle_t*) extparent;
  cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext;
  struct ceph_mount_info *cmount = context->export_context->cmount;
  int uid = FSAL_OP_CONTEXT_TO_UID(context);
  int gid = FSAL_OP_CONTEXT_TO_GID(context);

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!parent || !context || !object_handle || !filename)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  memset(object_handle, 0, sizeof(cephfsal_handle_t));

  mode = fsal2unix_mode(accessmode);
  mode = mode & ~global_fs_info.umask;

  FSAL_name2str(filename, strname, FSAL_MAX_NAME_LEN);

  TakeTokenFSCall();

  rc = ceph_ll_create(cmount, VINODE(parent), strname,
                      mode, 0, &fd, &st, uid, gid);
  ceph_ll_close(cmount, fd);

  ReleaseTokenFSCall();

  if (rc < 0)
    Return(posix2fsal_error(rc), 0, INDEX_FSAL_create);

  rc = stat2fsal_fh(cmount,
                    &st,
                    (cephfsal_handle_t*) object_handle);

  if (rc < 0)
    Return(posix2fsal_error(rc), 0, INDEX_FSAL_create);

  if(object_attributes)
    {
      fsal_status_t status;
      status = posix2fsal_attributes(&st, object_attributes);
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(object_attributes->asked_attributes);
          FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
          Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);
        }
    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);
}
/**
 *
 * cache_inode_renew_entry: Renews the attributes for an entry.
 *
 * Sets the attributes for an entry located in the cache by its address. Attributes are provided
 * with compliance to the underlying FSAL semantics. Attributes that are set are returned in "*pattr".
 *
 * @param pentry_parent [IN] entry for the parent directory to be managed.
 * @param pattr [OUT] renewed attributes for the entry that we have found.
 * @param pclient [INOUT] ressource allocated by the client for the nfs management.
 * @param pcontext [IN] FSAL credentials
 * @param pstatus [OUT] returned status.
 *
 * @return CACHE_INODE_SUCCESS if operation is a success \n
   @return Other errors shows a FSAL error.
 *
 */
cache_inode_status_t cache_inode_renew_entry(cache_entry_t * pentry,
                                             fsal_attrib_list_t * pattr,
                                             hash_table_t * ht,
                                             cache_inode_client_t * pclient,
                                             fsal_op_context_t * pcontext,
                                             cache_inode_status_t * pstatus)
{
  fsal_handle_t *pfsal_handle = NULL;
  fsal_status_t fsal_status;
  fsal_attrib_list_t object_attributes;
  fsal_path_t link_content;
  time_t current_time = time(NULL);
  time_t entry_time = pentry->internal_md.refresh_time;

  /* If we do nothing (no expiration) then everything is all right */
  *pstatus = CACHE_INODE_SUCCESS;

  if(isFullDebug(COMPONENT_CACHE_INODE))
    {
      char *type;
      char grace[20], grace2[20];
      unsigned int elapsed = (unsigned int)current_time - (unsigned int)entry_time;
      int print = 1;

      cache_inode_expire_to_str(pclient->expire_type_attr, pclient->grace_period_attr, grace);

      switch(pentry->internal_md.type)
        {
          case UNASSIGNED:
            type = "UNASSIGNED";
            break;
          case REGULAR_FILE:
            type = "REGULAR_FILE";
            break;
          case CHARACTER_FILE:
            type = "CHARACTER_FILE";
            break;
          case BLOCK_FILE:
            type = "BLOCK_FILE";
            break;
          case SYMBOLIC_LINK:
            print = 0;
            cache_inode_expire_to_str(pclient->expire_type_link, pclient->grace_period_link, grace2);
            LogDebug(COMPONENT_CACHE_INODE,
                     "Renew Entry test of %p for SYMBOLIC_LINK elapsed time=%u, grace_period_attr=%s, grace_period_link=%s",
                     pentry, elapsed, grace, grace2);
            break;
          case SOCKET_FILE:
            type = "SOCKET_FILE";
            break;
          case FIFO_FILE:
            type = "FIFO_FILE";
            break;
          case DIRECTORY:
            print = 0;
            cache_inode_expire_to_str(pclient->expire_type_dirent, pclient->grace_period_dirent, grace2);
            LogDebug(COMPONENT_CACHE_INODE,
                     "Renew Entry test of %p for DIRECTORY elapsed time=%u, grace_period_attr=%s, grace_period_dirent=%s, has_been_readdir=%u",
                     pentry, elapsed, grace, grace2,
                     pentry->object.dir.has_been_readdir);
            break;
          case FS_JUNCTION:
            type = "FS_JUNCTION";
            break;
          case RECYCLED:
            type = "RECYCLED";
            break;
          default:
            type = "UNKNOWN";
            break;
        }
      if(print)
        {
          LogDebug(COMPONENT_CACHE_INODE,
                   "Renew Entry test of %p for %s elapsed time=%u, grace_period_attr=%s",
                   pentry, type, elapsed, grace);
        }
    }

  /* An entry that is a regular file with an associated File Content Entry won't
   * expire until data exists in File Content Cache, to avoid attributes incoherency */

  /* @todo: BUGAZOMEU: I got serious doubts on the following blocks: possible trouble if using data caching */
  if(pentry->internal_md.type == REGULAR_FILE &&
     pentry->object.file.pentry_content != NULL)
    {
      /* Successfull exit without having nothing to do ... */

      LogDebug(COMPONENT_CACHE_INODE,
               "Entry %p is a REGULAR_FILE with associated data cached %p, no expiration",
               pentry, pentry->object.file.pentry_content);

      *pstatus = CACHE_INODE_SUCCESS;
      return *pstatus;
    }

  LogDebug(COMPONENT_CACHE_INODE,
           "cache_inode_renew_entry use getattr/mtime checking %d, is dir "
	   "beginning %d, has bit in mask %d, has been readdir %d state %d",
           pclient->getattr_dir_invalidation,
           pentry->internal_md.type == DIRECTORY,
           (int) FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME),
	   pentry->object.dir.has_been_readdir,
	   pentry->internal_md.valid_state);
  /* Do we use getattr/mtime checking */
  if(pclient->getattr_dir_invalidation &&
     pentry->internal_md.type == DIRECTORY &&
     FSAL_TEST_MASK(pclient->attrmask, FSAL_ATTR_MTIME) /*&&
     pentry->object.dir.has_been_readdir == CACHE_INODE_YES*/)
    {
      /* This checking is to be done ... */
      LogDebug(COMPONENT_CACHE_INODE,
               "cache_inode_renew_entry testing directory mtime");
      pfsal_handle = &pentry->object.dir.handle;

      /* Call FSAL to get the attributes */
      object_attributes.asked_attributes = pclient->attrmask;

      fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes);

      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          if(fsal_status.major == ERR_FSAL_STALE)
            {
              cache_inode_status_t kill_status;

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                       pentry, __LINE__, fsal_status.major, fsal_status.minor);

              if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
                 CACHE_INODE_SUCCESS)
                LogCrit(COMPONENT_CACHE_INODE,
                        "cache_inode_renew_entry: Could not kill entry %p, status = %u",
                         pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }
          /* stats */
          (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++;

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_renew_entry: returning %d (%s) from FSAL_getattrs for getattr/mtime checking",
                   *pstatus, cache_inode_err_str(*pstatus));
          return *pstatus;
        }

      LogDebug(COMPONENT_CACHE_INODE,
               "cache_inode_renew_entry: Entry=%p, type=%d, Cached Time=%d, FSAL Time=%d",
               pentry, pentry->internal_md.type,
               pentry->object.dir.attributes.mtime.seconds,
               object_attributes.mtime.seconds);

      /* Compare the FSAL mtime and the cached mtime */
      if(pentry->object.dir.attributes.mtime.seconds <
         object_attributes.mtime.seconds)
        {
          /* Cached directory content is obsolete, it must be renewed */
          cache_inode_set_attributes(pentry, &object_attributes);

          /* Return the attributes as set */
          if(pattr != NULL)
            *pattr = object_attributes;

          /* Set the directory content as "to be renewed" */
          /* Next call to cache_inode_readdir will repopulate the dirent array */
          pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED;

          /* Set the refresh time for the cache entry */
          pentry->internal_md.refresh_time = time(NULL);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_renew_entry: cached directory content for entry %p must be renewed, due to getattr mismatch",
                   pentry);

          if(cache_inode_invalidate_all_cached_dirent(pentry, ht, pclient, pstatus)
             != CACHE_INODE_SUCCESS)
            {
              /* Should never happen */
              LogCrit(COMPONENT_CACHE_INODE,
                      "cache_inode_invalidate_all_cached_dirent returned %d (%s)",
                      *pstatus, cache_inode_err_str(*pstatus));
              return *pstatus;
            }

        }                       /* if( pentry->object.dir.attributes.mtime < object_attributes.asked_attributes.mtime ) */
    }

  /* if( pclient->getattr_dir_invalidation && ... */
  /* Check for dir content expiration and/or staleness */
  if(pentry->internal_md.type == DIRECTORY &&
     pclient->expire_type_dirent != CACHE_INODE_EXPIRE_NEVER &&
     pentry->object.dir.has_been_readdir == CACHE_INODE_YES &&
     ((current_time - entry_time >= pclient->grace_period_dirent)
      || (pentry->internal_md.valid_state == STALE)))
    {
      /* Would be better if state was a flag that we could and/or the bits but
       * in any case we need to get rid of stale so we only go through here
       * once.
       */
      if ( pentry->internal_md.valid_state == STALE )
	pentry->internal_md.valid_state = VALID;

      /* stats */
      (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++;

      /* Log */
      LogDebug(COMPONENT_CACHE_INODE,
	       "Case 1: cached directory entries for entry %p must be renewed"
	       " (has been readdir)", pentry);

      if(isFullDebug(COMPONENT_CACHE_INODE))
        {
          char name[1024];
	  struct avltree_node *d_node;
	  cache_inode_dir_entry_t *d_dirent;
	  int i = 0;
	  
	  d_node = avltree_first(&pentry->object.dir.dentries);
      	  do {
              d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t,
					      node_n);
	      if (d_dirent->pentry->internal_md.valid_state == VALID) {
	          FSAL_name2str(&(d_dirent->name), name, 1023);
                  LogDebug(COMPONENT_CACHE_INODE,
                           "cache_inode_renew_entry: Entry %d %s",
                           i, name);
	      }
	      i++;
          } while ((d_node = avltree_next(d_node)));
        }

      /* Do the getattr if it had not being done before */
      if(pfsal_handle == NULL)
        {
          pfsal_handle = &pentry->object.dir.handle;

          /* Call FSAL to get the attributes */
          object_attributes.asked_attributes = pclient->attrmask;

          fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes);

          if(FSAL_IS_ERROR(fsal_status))
            {
              *pstatus = cache_inode_error_convert(fsal_status);

              /* stats */
              (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++;

              if(fsal_status.major == ERR_FSAL_STALE)
                {
                  cache_inode_status_t kill_status;

                  LogEvent(COMPONENT_CACHE_INODE,
                           "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                           pentry, __LINE__,fsal_status.major, fsal_status.minor );

                  if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
                     CACHE_INODE_SUCCESS)
                    LogCrit(COMPONENT_CACHE_INODE,
                            "cache_inode_renew_entry: Could not kill entry %p, status = %u",
                            pentry, kill_status);

                  *pstatus = CACHE_INODE_FSAL_ESTALE;
                }

              LogDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (1)",
                       *pstatus, cache_inode_err_str(*pstatus));
              return *pstatus;
            }
        }

      cache_inode_set_attributes(pentry, &object_attributes);

      /* Return the attributes as set */
      if(pattr != NULL)
        *pattr = object_attributes;

      /* Set the directory content as "to be renewed" */
      /* Next call to cache_inode_readdir will repopulate the dirent array */
      pentry->object.dir.has_been_readdir = CACHE_INODE_RENEW_NEEDED;

      /* Set the refresh time for the cache entry */
      pentry->internal_md.refresh_time = time(NULL);

    }

  /* if( pentry->internal_md.type == DIRECTORY && ... */
  /* if the directory has not been readdir, only update its attributes */
  else if(pentry->internal_md.type == DIRECTORY &&
          pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER &&
          pentry->object.dir.has_been_readdir != CACHE_INODE_YES &&
	  ((current_time - entry_time >= pclient->grace_period_attr) || (pentry->internal_md.valid_state == STALE)))
    {
      /* Would be better if state was a flag that we could and/or the bits but
       * in any case we need to get rid of stale so we only go through here
       * once.
       */
      if ( pentry->internal_md.valid_state == STALE )
         pentry->internal_md.valid_state = VALID;

      /* stats */
      (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++;

      /* Log */
      LogDebug(COMPONENT_CACHE_INODE,
	       "Case 2: cached directory entries for entry %p must be renewed (has not been readdir)",
               pentry);

      if(isFullDebug(COMPONENT_CACHE_INODE))
        {
          char name[1024];
	  struct avltree_node *d_node;
	  cache_inode_dir_entry_t *d_dirent;
	  int i = 0;
	  
	  d_node = avltree_first(&pentry->object.dir.dentries);
      	  do {
              d_dirent = avltree_container_of(d_node, cache_inode_dir_entry_t,
					      node_n);
	      if (d_dirent->pentry->internal_md.valid_state == VALID) {
	          FSAL_name2str(&(d_dirent->name), name, 1023);
                  LogDebug(COMPONENT_CACHE_INODE,
                           "cache_inode_renew_entry: Entry %d %s",
                           i, name);
	      }
	      i++;
          } while ((d_node = avltree_next(d_node)));
        }

      pfsal_handle = &pentry->object.dir.handle;

      /* Call FSAL to get the attributes */
      object_attributes.asked_attributes = pclient->attrmask;

      fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes);

      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          /* stats */
          (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++;

          if(fsal_status.major == ERR_FSAL_STALE)
            {
              cache_inode_status_t kill_status;

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                       pentry, __LINE__,fsal_status.major, fsal_status.minor );

              if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
                 CACHE_INODE_SUCCESS)
                LogCrit(COMPONENT_CACHE_INODE,
                        "cache_inode_renew_entry: Could not kill entry %p, status = %u",
                         pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for directory entries (2)",
                   *pstatus, cache_inode_err_str(*pstatus));
          return *pstatus;
        }

      cache_inode_set_attributes(pentry, &object_attributes);

      /* Return the attributes as set */
      if(pattr != NULL)
        *pattr = object_attributes;

      /* Set the refresh time for the cache entry */
      pentry->internal_md.refresh_time = time(NULL);

    }

  /* else if( pentry->internal_md.type == DIRECTORY && ... */
  /* Check for attributes expiration in other cases */
  else if(pentry->internal_md.type != DIRECTORY &&
          pclient->expire_type_attr != CACHE_INODE_EXPIRE_NEVER &&
	  ((current_time - entry_time >= pclient->grace_period_attr)
	   || (pentry->internal_md.valid_state == STALE)))
    {
      /* Would be better if state was a flag that we could and/or the bits but
       * in any case we need to get rid of stale so we only go through here
       * once.
       */
      if ( pentry->internal_md.valid_state == STALE )
	pentry->internal_md.valid_state = VALID;
      
      /* stats */
      (pclient->stat.func_stats.nb_call[CACHE_INODE_RENEW_ENTRY])++;

      /* Log */
      LogDebug(COMPONENT_CACHE_INODE,
               "Attributes for entry %p must be renewed", pentry);

      switch (pentry->internal_md.type)
        {
        case REGULAR_FILE:
          pfsal_handle = &pentry->object.file.handle;
          break;

        case SYMBOLIC_LINK:
          assert(pentry->object.symlink);
          pfsal_handle = &pentry->object.symlink->handle;
          break;

        case SOCKET_FILE:
        case FIFO_FILE:
        case CHARACTER_FILE:
        case BLOCK_FILE:
          pfsal_handle = &pentry->object.special_obj.handle;
          break;

        case DIRECTORY:
        case FS_JUNCTION:
        case UNASSIGNED:
        case RECYCLED:
          LogCrit(COMPONENT_CACHE_INODE,
                  "WARNING: unknown source pentry type: internal_md.type=%d, line %d in file %s",
                  pentry->internal_md.type, __LINE__, __FILE__);
          *pstatus = CACHE_INODE_BAD_TYPE;
          return *pstatus;
        }

      /* Call FSAL to get the attributes */
      object_attributes.asked_attributes = pclient->attrmask;
#ifdef _USE_MFSL
      fsal_status = FSAL_getattrs_descriptor(&(cache_inode_fd(pentry)->fsal_file), pfsal_handle, pcontext, &object_attributes);
#else
      fsal_status = FSAL_getattrs_descriptor(cache_inode_fd(pentry), pfsal_handle, pcontext, &object_attributes);
#endif
      if(FSAL_IS_ERROR(fsal_status) && fsal_status.major == ERR_FSAL_NOT_OPENED)
        {
          //TODO: LOOKATME !!!!!
          fsal_status = FSAL_getattrs(pfsal_handle, pcontext, &object_attributes);
        }
      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          /* stats */
          (pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY])++;

          if(fsal_status.major == ERR_FSAL_STALE)
            {
              cache_inode_status_t kill_status;

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                       pentry, __LINE__,fsal_status.major, fsal_status.minor );

              if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
                 CACHE_INODE_SUCCESS)
                LogCrit(COMPONENT_CACHE_INODE,
                        "cache_inode_renew_entry: Could not kill entry %p, status = %u",
                        pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_renew_entry returning %d (%s) from FSAL_getattrs for non directories",
                   *pstatus, cache_inode_err_str(*pstatus));
          return *pstatus;
        }

      /* Keep the new attribute in cache */
      cache_inode_set_attributes(pentry, &object_attributes);

      /* Return the attributes as set */
      if(pattr != NULL)
        *pattr = object_attributes;

      /* Set the refresh time for the cache entry */
      pentry->internal_md.refresh_time = time(NULL);

    }

  /* if(  pentry->internal_md.type   != DIR_CONTINUE && ... */
  /* Check for link content expiration */
  if(pentry->internal_md.type == SYMBOLIC_LINK &&
     pclient->expire_type_link != CACHE_INODE_EXPIRE_NEVER &&
     ((current_time - entry_time >= pclient->grace_period_link)
      || (pentry->internal_md.valid_state == STALE)))
    {
      assert(pentry->object.symlink);
      pfsal_handle = &pentry->object.symlink->handle;
      /* Would be better if state was a flag that we could and/or the bits but
       * in any case we need to get rid of stale so we only go through here
       * once.
       */
      if ( pentry->internal_md.valid_state == STALE )
	pentry->internal_md.valid_state = VALID;

      assert(pentry->object.symlink);
      pfsal_handle = &pentry->object.symlink->handle;

      /* Log */
      LogDebug(COMPONENT_CACHE_INODE,
               "cached link content for entry %p must be renewed", pentry);

      FSAL_CLEAR_MASK(object_attributes.asked_attributes);
      FSAL_SET_MASK(object_attributes.asked_attributes, pclient->attrmask);

      if( CACHE_INODE_KEEP_CONTENT( pentry->policy ) )
       {
#ifdef _USE_MFSL
      fsal_status =
          MFSL_readlink(&pentry->mobject, pcontext, &pclient->mfsl_context, &link_content,
                        &object_attributes, NULL);
#else
      fsal_status =
          FSAL_readlink(pfsal_handle, pcontext, &link_content, &object_attributes);
#endif
        }
      else
        { 
          fsal_status.major = ERR_FSAL_NO_ERROR ;
          fsal_status.minor = 0 ;
        }

      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);
          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1;

          if(fsal_status.major == ERR_FSAL_STALE)
            {
              cache_inode_status_t kill_status;

              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Stale FSAL File Handle detected for pentry = %p, line %u, fsal_status=(%u,%u)",
                       pentry, __LINE__,fsal_status.major, fsal_status.minor );

              if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
                 CACHE_INODE_SUCCESS)
                LogCrit(COMPONENT_CACHE_INODE,
                       "cache_inode_renew_entry: Could not kill entry %p, status = %u",
                       pentry, kill_status);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

        }
      else
        {
	  assert(pentry->object.symlink);
          fsal_status = FSAL_pathcpy(&pentry->object.symlink->content, &link_content); /* copy ctor? */
          if(FSAL_IS_ERROR(fsal_status))
            {
              *pstatus = cache_inode_error_convert(fsal_status);
              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_RENEW_ENTRY] += 1;
            }
        }

      /* Set the refresh time for the cache entry */
      pentry->internal_md.refresh_time = time(NULL);

    }

  /* if( pentry->internal_md.type == SYMBOLIC_LINK && ... */
  LogDebug(COMPONENT_CACHE_INODE, "cache_inode_renew_entry returning %d (%s)",
           *pstatus, cache_inode_err_str(*pstatus));
  return *pstatus;
}                               /* cache_inode_renew_entry */
Exemple #10
0
fsal_status_t VFSFSAL_readdir(fsal_dir_t * dir_descriptor,      /* IN */
                              fsal_cookie_t startposition,      /* IN */
                              fsal_attrib_mask_t get_attr_mask, /* IN */
                              fsal_mdsize_t buffersize,         /* IN */
                              fsal_dirent_t * p_pdirent,        /* OUT */
                              fsal_cookie_t * end_position,     /* OUT */
                              fsal_count_t * p_nb_entries,      /* OUT */
                              fsal_boolean_t * p_end_of_dir     /* OUT */
    )
{
  vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t * ) dir_descriptor;
  vfsfsal_cookie_t start_position;
  vfsfsal_cookie_t * p_end_position = (vfsfsal_cookie_t *) end_position;
  fsal_status_t st;
  fsal_count_t max_dir_entries;
  fsal_name_t entry_name;
  char buff[BUF_SIZE];
  struct linux_dirent *dp = NULL;
  int bpos = 0;

  char d_type;
  struct stat buffstat;

  int rc = 0;

  memset(buff, 0, BUF_SIZE);
  memset(&entry_name, 0, sizeof(fsal_name_t));

  /*****************/
  /* sanity checks */
  /*****************/

  if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  max_dir_entries = (buffersize / sizeof(fsal_dirent_t));

  /***************************/
  /* seek into the directory */
  /***************************/
  start_position.data.cookie = *((off_t*) &startposition.data);
  rc = errno = 0;
  lseek(p_dir_descriptor->fd, start_position.data.cookie, SEEK_SET);
  rc = errno;

  if(rc)
    Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir);

  /************************/
  /* browse the directory */
  /************************/

  *p_nb_entries = 0;
  while(*p_nb_entries < max_dir_entries)
    {
    /***********************/
      /* read the next entry */
    /***********************/
      TakeTokenFSCall();
      rc = syscall(SYS_getdents, p_dir_descriptor->fd, buff, BUF_SIZE);
      ReleaseTokenFSCall();
      if(rc < 0)
        {
          rc = errno;
          Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir);
        }
      /* End of directory */
      if(rc == 0)
        {
          *p_end_of_dir = 1;
          break;
        }

    /***********************************/
      /* Get information about the entry */
    /***********************************/

      for(bpos = 0; bpos < rc;)
        {
          dp = (struct linux_dirent *)(buff + bpos);
          d_type = *(buff + bpos + dp->d_reclen - 1);

          bpos += dp->d_reclen;

          if(!(*p_nb_entries < max_dir_entries))
            break;

          /* skip . and .. */
          if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
            continue;

          /* build the full path of the file into "fsalpath */
          if(FSAL_IS_ERROR
             (st =
              FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN,
                            &(p_pdirent[*p_nb_entries].name))))
            ReturnStatus(st, INDEX_FSAL_readdir);


          // TODO: there is a race here, because between handle fetch
          // and open at things might change.  we need to figure out if there
          // is another way to open without the pcontext

          strncpy(entry_name.name, dp->d_name, sizeof(entry_name.name));
          entry_name.len = strlen(entry_name.name);

          /* get object handle */
          TakeTokenFSCall();

          
          if(fstatat(p_dir_descriptor->fd, dp->d_name, &buffstat, AT_SYMLINK_NOFOLLOW) < 0 )
            {
              ReleaseTokenFSCall();
              Return(posix2fsal_error(errno), errno, INDEX_FSAL_readdir);
            }

          st = fsal_internal_get_handle_at( p_dir_descriptor->fd, dp->d_name,
		           				            &p_pdirent[*p_nb_entries].handle) ;
          if(FSAL_IS_ERROR(st))
            {
              ReleaseTokenFSCall();
              ReturnStatus(st, INDEX_FSAL_readdir);
            }
          p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask;

          st = posix2fsal_attributes(&buffstat, &p_pdirent[*p_nb_entries].attributes);
          if(FSAL_IS_ERROR(st))
            {
              ReleaseTokenFSCall();
              FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes);
              FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes,
                            FSAL_ATTR_RDATTR_ERR);
              ReturnStatus(st, INDEX_FSAL_getattrs);
            }

          ReleaseTokenFSCall();

          //p_pdirent[*p_nb_entries].cookie.cookie = dp->d_off;
          ((vfsfsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = dp->d_off;
          p_pdirent[*p_nb_entries].nextentry = NULL;
          if(*p_nb_entries)
            p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]);

          //(*p_end_position) = p_pdirent[*p_nb_entries].cookie;
          memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie,
                 sizeof(vfsfsal_cookie_t));

          (*p_nb_entries)++;

        }                       /* for */
    }                           /* While */

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);

}
Exemple #11
0
/**
 * FSAL_opendir :
 *     Opens a directory for reading its content.
 *
 * \param dir_handle (input)
 *         the handle of the directory to be opened.
 * \param cred (input)
 *         Permission context for the operation (user,...).
 * \param dir_descriptor (output)
 *         pointer to an allocated structure that will receive
 *         directory stream informations, on successfull completion.
 * \param dir_attributes (optional output)
 *         On successfull completion,the structure pointed
 *         by dir_attributes receives the new directory attributes.
 *         May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t VFSFSAL_opendir(fsal_handle_t * p_dir_handle,  /* IN */
                              fsal_op_context_t * p_context, /* IN */
                              fsal_dir_t * dir_desc, /* OUT */
                              fsal_attrib_list_t * p_dir_attributes     /* [ IN/OUT ] */
    )
{
  vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t *) dir_desc;
  int rc, errsv;
  fsal_status_t status;

  struct stat buffstat;

  /* sanity checks
   * note : dir_attributes is optionnal.
   */
  if(!p_dir_handle || !p_context || !p_dir_descriptor)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir);

  /* get the path of the directory */
  TakeTokenFSCall();
  status =
      fsal_internal_handle2fd(p_context, p_dir_handle, &p_dir_descriptor->fd,
                              O_RDONLY | O_DIRECTORY);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_opendir);

  /* get directory metadata */
  TakeTokenFSCall();
  rc = fstat(p_dir_descriptor->fd, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc != 0)
    {
      close(p_dir_descriptor->fd);
      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_opendir);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_opendir);
    }

  /* Test access rights for this directory */
  status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_opendir);

  /* if everything is OK, fills the dir_desc structure : */

  memcpy(&(p_dir_descriptor->context), p_context, sizeof(vfsfsal_op_context_t));
  memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(vfsfsal_handle_t));

  if(p_dir_attributes)
    {
      status = posix2fsal_attributes(&buffstat, p_dir_attributes);
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_dir_attributes->asked_attributes);
          FSAL_SET_MASK(p_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }
    }

  p_dir_descriptor->dir_offset = 0;

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir);

}
Exemple #12
0
fsal_status_t PROXYFSAL_rename(fsal_handle_t * old_parent,       /* IN */
                               fsal_name_t * p_old_name,        /* IN */
                               fsal_handle_t * new_parent,       /* IN */
                               fsal_name_t * p_new_name,        /* IN */
                               fsal_op_context_t *context,      /* IN */
                               fsal_attrib_list_t * src_dir_attributes, /* [ IN/OUT ] */
                               fsal_attrib_list_t * tgt_dir_attributes  /* [ IN/OUT ] */
    )
{

  int rc;

  COMPOUND4args argnfs4;
  COMPOUND4res resnfs4;
  nfs_fh4 nfs4fh_old;
  nfs_fh4 nfs4fh_new;
  bitmap4 bitmap_old;
  uint32_t bitmap_val_old[2];
  bitmap4 bitmap_new;
  uint32_t bitmap_val_new[2];
  component4 oldname;
  char oldnameval[MAXNAMLEN+1];
  component4 newname;
  char newnameval[MAXNAMLEN+1];
  proxyfsal_handle_t * old_parentdir_handle = (proxyfsal_handle_t *)old_parent;
  proxyfsal_handle_t * new_parentdir_handle = (proxyfsal_handle_t *)new_parent;
  proxyfsal_op_context_t * p_context = (proxyfsal_op_context_t *)context;

#define FSAL_RENAME_NB_OP_ALLOC 7
  nfs_argop4 argoparray[FSAL_RENAME_NB_OP_ALLOC];
  nfs_resop4 resoparray[FSAL_RENAME_NB_OP_ALLOC];
  uint32_t bitmap_res_old[2];
  uint32_t bitmap_res_new[2];

  fsal_proxy_internal_fattr_t fattr_internal_new;
  fsal_proxy_internal_fattr_t fattr_internal_old;
  struct timeval timeout = TIMEOUTRPC;

  /* sanity checks.
   * note : src/tgt_dir_attributes are optional.
   */
  if(!old_parentdir_handle ||
     !new_parentdir_handle || !p_old_name || !p_new_name || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

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

  /* Prepare the structures */
  bitmap_old.bitmap4_val = bitmap_val_old;
  bitmap_old.bitmap4_len = 2;

  fsal_internal_proxy_create_fattr_bitmap(&bitmap_old);

  if(fsal_internal_proxy_extract_fh(&nfs4fh_old, old_parent) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

  memset((char *)&oldname, 0, sizeof(component4));
  oldname.utf8string_val = oldnameval;
  oldname.utf8string_len = sizeof(oldnameval);
  if(fsal_internal_proxy_fsal_name_2_utf8(p_old_name, &oldname) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

  bitmap_new.bitmap4_val = bitmap_val_new;
  bitmap_new.bitmap4_len = 2;
  fsal_internal_proxy_create_fattr_bitmap(&bitmap_new);

  if(fsal_internal_proxy_extract_fh(&nfs4fh_new, new_parent) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

  memset((char *)&newname, 0, sizeof(component4));
  newname.utf8string_val = newnameval;
  newname.utf8string_len = sizeof(newnameval);
  if(fsal_internal_proxy_fsal_name_2_utf8(p_new_name, &newname) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

#define FSAL_RENAME_IDX_OP_PUTFH_OLD      0
#define FSAL_RENAME_IDX_OP_SAVEFH         1
#define FSAL_RENAME_IDX_OP_PUTFH_NEW      2
#define FSAL_RENAME_IDX_OP_RENAME         3
#define FSAL_RENAME_IDX_OP_GETATTR_NEW    4
#define FSAL_RENAME_IDX_OP_RESTOREFH      5
#define FSAL_RENAME_IDX_OP_GETATTR_OLD    6

  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_old);
  COMPOUNDV4_ARG_ADD_OP_SAVEFH(argnfs4);
  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_new);
  COMPOUNDV4_ARG_ADD_OP_RENAME(argnfs4, oldname, newname);
  COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap_new);
  COMPOUNDV4_ARG_ADD_OP_RESTOREFH(argnfs4);
  COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap_old);

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

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

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

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

  TakeTokenFSCall();

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

      Return(ERR_FSAL_IO, rc, INDEX_FSAL_rename);
    }

  ReleaseTokenFSCall();

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

  /* >> get last parent post op attributes if asked
   * For example : << */

  if(src_dir_attributes)
    {
      if(nfs4_Fattr_To_FSAL_attr(src_dir_attributes,
                                 &resnfs4.resarray.resarray_val
                                 [FSAL_RENAME_IDX_OP_GETATTR_OLD].nfs_resop4_u.
                                 opgetattr.GETATTR4res_u.resok4.obj_attributes,
                                 ANON_UID, ANON_GID) != NFS4_OK)
        {
          FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes);
          FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);

          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rename);
        }

    }

  /* >> get new parent post op attributes if asked
   * For example : << */

  if(tgt_dir_attributes)
    {
      if(nfs4_Fattr_To_FSAL_attr(tgt_dir_attributes,
                                 &resnfs4.resarray.resarray_val
                                 [FSAL_RENAME_IDX_OP_GETATTR_NEW].nfs_resop4_u.
                                 opgetattr.GETATTR4res_u.resok4.obj_attributes,
                                 ANON_UID, ANON_GID) != NFS4_OK)
        {
          FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes);
          FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);

          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rename);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename);

}
Exemple #13
0
/**
 * PTFSAL_getattrs:
 * Get attributes for the object specified by its filehandle.
 *
 * \param filehandle (input):
 *        The handle of the object to get parameters.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param object_attributes (mandatory input/output):
 *        The retrieved attributes for the object.
 *        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).
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t
PTFSAL_getattrs(fsal_handle_t      * p_filehandle,        /* IN */
                fsal_op_context_t  * p_context,           /* IN */
                fsal_attrib_list_t * p_object_attributes  /* IN/OUT */)
{
  fsal_status_t   st;
  int             stat_rc;
  fsi_stat_struct buffstat;
  ptfsal_op_context_t     * fsi_op_context  = (ptfsal_op_context_t *)p_context;
  ptfsal_export_context_t * fsi_export_context = 
    fsi_op_context->export_context;

#ifdef _USE_NFS4_ACL
  fsal_accessflags_t access_mask = 0;
#endif

  FSI_TRACE(FSI_DEBUG, "Begin-------------------\n");

  /* sanity checks.
   * note : object_attributes is mandatory in PTFSAL_getattrs.
   */
  if (!p_filehandle || !p_context || !p_object_attributes) { 
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs);
  }

  stat_rc = ptfsal_stat_by_handle(p_filehandle, p_context, &buffstat);

  if (stat_rc) {
    Return(ERR_FSAL_INVAL, errno, INDEX_FSAL_getattrs);
  }

  /* convert attributes */

  st = posix2fsal_attributes(&buffstat, p_object_attributes);
  FSI_TRACE(FSI_DEBUG, "Handle type=%d st_mode=%o (octal)", 
            p_object_attributes->type, buffstat.st_mode);

  p_object_attributes->mounted_on_fileid = 
    fsi_export_context->ganesha_export_id;

  if (FSAL_IS_ERROR(st)) {
    FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
    FSAL_SET_MASK(p_object_attributes->asked_attributes, 
                  FSAL_ATTR_RDATTR_ERR);
    ReturnStatus(st, INDEX_FSAL_getattrs);
  }

#ifdef _USE_NFS4_ACL
      /* Check permission to get attributes and ACL. */
      access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy */
                    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_READ_ATTR |
                                       FSAL_ACE_PERM_READ_ACL);

    if (!p_context->export_context->fe_static_fs_info->accesscheck_support) {
      st = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                    p_object_attributes);
    } else {
      st = fsal_internal_access(p_context, p_filehandle, access_mask,
                                p_object_attributes);
    } 
    if (FSAL_IS_ERROR(st)) {
      ReturnStatus(st, INDEX_FSAL_getattrs);
    }
#endif

  FSI_TRACE(FSI_DEBUG, "End-----------------------------\n");
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs);

}
Exemple #14
0
/**
 * PTFSAL_setattrs:
 * Set attributes for the object specified by its filehandle.
 *
 * \param filehandle (input):
 *        The handle of the object to get parameters.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param attrib_set (mandatory input):
 *        The attributes to be set for the object.
 *        It defines the attributes that the caller
 *        wants to set and their values.
 * \param object_attributes (optionnal input/output):
 *        The post operation attributes for the object.
 *        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).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t
PTFSAL_setattrs(fsal_handle_t      * p_filehandle,       /* IN */
                fsal_op_context_t  * p_context,          /* IN */
                fsal_attrib_list_t * p_attrib_set,       /* IN */
                fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */)
{
  unsigned int i;
  fsal_status_t status;

  ptfsal_xstat_t buffxstat;

  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t wanted_attrs, current_attrs;
  mode_t             st_mode_in_cache = 0;
  char               fsi_name[PATH_MAX];
  int                rc;
  int fd;

  FSI_TRACE(FSI_DEBUG, "Begin-----------------------------------------\n");

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if (!p_filehandle || !p_context || !p_attrib_set) {
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);
  }

  /* local copy of attributes */
  wanted_attrs = *p_attrib_set;

  /* First, check that FSAL attributes changes are allowed. */
  if (!global_fs_info.cansettime) {

    if (wanted_attrs.asked_attributes
       & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME 
       | FSAL_ATTR_MTIME)) {
       /* handled as an unsettable attribute. */
       Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
    }
  }

  /* apply umask, if mode attribute is to be changed */
  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) {
    wanted_attrs.mode &= (~global_fs_info.umask);
  }

  /* get current attributes */
  current_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES;
  status = PTFSAL_getattrs(p_filehandle, p_context, &current_attrs);
  if (FSAL_IS_ERROR(status)) {
    FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
    FSAL_SET_MASK(p_object_attributes->asked_attributes, 
                  FSAL_ATTR_RDATTR_ERR);
    ReturnStatus(status, INDEX_FSAL_setattrs);
  }

  /**************
   *  TRUNCATE  *
   **************/

  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_SIZE)) {

      status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY);

      if (FSAL_IS_ERROR(status)) {
        ReturnStatus(status, INDEX_FSAL_setattrs);
      }

      status = PTFSAL_truncate( p_filehandle,
                                p_context,   
                                wanted_attrs.filesize,                
                                &fd,     
                                p_object_attributes);

      if (FSAL_IS_ERROR(status)) {
        ReturnStatus(status, INDEX_FSAL_setattrs);
      }
    
   }
 

  /***********
   *  CHMOD  *
   ***********/
  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) {
    FSI_TRACE(FSI_DEBUG, "Begin chmod------------------\n");
    /* The POSIX chmod call don't affect the symlink object, but
     * the entry it points to. So we must ignore it.
     */
    if (current_attrs.type != FSAL_TYPE_LNK) {

      /* For modifying mode, user must be root or the owner */
      if ((p_context->credential.user != 0)
         && (p_context->credential.user != current_attrs.owner)) {
        FSI_TRACE(FSI_DEBUG,
                  "Permission denied for CHMOD opeartion: " 
                  "current owner=%d, credential=%d",
                  current_attrs.owner, 
                  p_context->credential.user);
        Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
      }

#ifdef _USE_NFS4_ACL
          /* Check permission using ACL. */
          access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
                        FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);

          if (!p_context->export_context->fe_static_fs_info->accesscheck_support)
            status = fsal_internal_testAccess(p_context, access_mask, NULL, 
            &current_attrs);
          else
            status = fsal_internal_access(p_context, p_filehandle, access_mask,
                                          &current_attrs);

          if (FSAL_IS_ERROR(status))
            ReturnStatus(status, INDEX_FSAL_setattrs);
#endif

      /* Fill wanted mode. */
      buffxstat.buffstat.st_mode = fsal2unix_mode(wanted_attrs.mode);
      FSI_TRACE(FSI_DEBUG,
                "current mode = %o, new mode = %o",
                fsal2unix_mode(current_attrs.mode), 
                buffxstat.buffstat.st_mode);

      rc = fsi_get_name_from_handle(p_context, 
                                    p_filehandle->data.handle.f_handle, 
                                    fsi_name,
                                    NULL);
      if (rc < 0) {
        FSI_TRACE(FSI_ERR, 
                  "Failed to convert file handle back to filename" );
        FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s", 
                  p_filehandle->data.handle.f_handle);
        Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs);
      }
      FSI_TRACE(FSI_DEBUG, "Handle to name: %s for handle %s", 
                fsi_name, p_filehandle->data.handle.f_handle);

      rc = ptfsal_chmod(p_context, fsi_name, 
                        buffxstat.buffstat.st_mode);
      if (rc == -1) {
        FSI_TRACE(FSI_ERR, "chmod FAILED");
        Return (ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
      } else {
        st_mode_in_cache = (buffxstat.buffstat.st_mode 
                            | fsal_type2unix(current_attrs.type));
        fsi_update_cache_stat(fsi_name, 
                              st_mode_in_cache, 
                              p_context->export_context->pt_export_id);
        FSI_TRACE(FSI_INFO, 
                  "Chmod SUCCEED with st_mode in cache being %o",
                  st_mode_in_cache);
      }

    }
    FSI_TRACE(FSI_DEBUG, "End chmod-------------------\n");
  }

  /***********
   *  CHOWN  *
   ***********/
  FSI_TRACE(FSI_DEBUG, "Begin chown------------------------------\n");
  /* Only root can change uid and A normal user must be in the group 
   * he wants to set 
   */
  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) {

    /* For modifying owner, user must be root or current 
     * owner==wanted==client 
     */
    if ((p_context->credential.user != 0) &&
       ((p_context->credential.user != current_attrs.owner) ||
       (p_context->credential.user != wanted_attrs.owner))) {
      FSI_TRACE(FSI_DEBUG,
                "Permission denied for CHOWN opeartion: " 
                "current owner=%d, credential=%d, new owner=%d",
                current_attrs.owner, p_context->credential.user, 
                wanted_attrs.owner);
       Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
    }

#ifdef _USE_NFS4_ACL
          /* Check permission using ACL. */
          access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
                        FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER);

        if (!p_context->export_context->fe_static_fs_info->accesscheck_support)
          status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                            &current_attrs);
        else
          status = fsal_internal_access(p_context, p_filehandle, access_mask,
                                        &current_attrs);

          if (FSAL_IS_ERROR(status))
            ReturnStatus(status, INDEX_FSAL_setattrs);
#endif

        }

  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) {

    /* For modifying group, user must be root or current owner */
    if ((p_context->credential.user != 0)
       && (p_context->credential.user != current_attrs.owner)) {
       Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
    }

    int in_grp = 0;
    /* set in_grp */
    if (p_context->credential.group == wanted_attrs.group) {
      in_grp = 1;
    } else {
      for(i = 0; i < p_context->credential.nbgroups; i++) {
        if ((in_grp = (wanted_attrs.group == 
            p_context->credential.alt_groups[i])))
          break;
      }
    }
    /* it must also be in target group */
    if (p_context->credential.user != 0 && !in_grp) {
      FSI_TRACE(FSI_DEBUG,
                "Permission denied for CHOWN operation: " 
                "current group=%d, credential=%d, new group=%d",
                current_attrs.group, p_context->credential.group, 
                wanted_attrs.group);
      Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
    }

#ifdef _USE_NFS4_ACL
      /* Check permission using ACL. */
      access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
                    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER);

      if (!p_context->export_context->fe_static_fs_info->accesscheck_support)
        status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                      &current_attrs);
      else
        status = fsal_internal_access(p_context, p_filehandle, access_mask,
                                      &current_attrs);

      if (FSAL_IS_ERROR(status))
        ReturnStatus(status, INDEX_FSAL_setattrs);
#endif

    }

  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER | 
     FSAL_ATTR_GROUP)) {

    /* Fill wanted owner. */
    if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) {
      buffxstat.buffstat.st_uid = (int)wanted_attrs.owner;
    } else {
      buffxstat.buffstat.st_uid = (int)current_attrs.owner;
    }
    FSI_TRACE(FSI_DEBUG,
              "current uid = %d, new uid = %d",
              current_attrs.owner, buffxstat.buffstat.st_uid);

    /* Fill wanted group. */
    if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) {
      buffxstat.buffstat.st_gid = (int)wanted_attrs.group;
    } else {
      buffxstat.buffstat.st_gid = (int)current_attrs.group;
    }
    FSI_TRACE(FSI_DEBUG,
              "current gid = %d, new gid = %d",
              current_attrs.group, buffxstat.buffstat.st_gid);

    rc = fsi_get_name_from_handle(p_context, 
                                  p_filehandle->data.handle.f_handle, 
                                  fsi_name,
                                  NULL);
    if (rc < 0) {
      FSI_TRACE(FSI_ERR, "Failed to convert file handle back to filename" );
      FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s", 
                p_filehandle->data.handle.f_handle);
      Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs);
    }
   
    FSI_TRACE(FSI_DEBUG, "handle to name: %s for handle %s", 
              fsi_name, p_filehandle->data.handle.f_handle);
    rc = ptfsal_chown(p_context, fsi_name, buffxstat.buffstat.st_uid, 
                      buffxstat.buffstat.st_gid);
    if (rc == -1) {
      FSI_TRACE(FSI_ERR, "chown FAILED");
      Return (ERR_FSAL_PERM, 1, INDEX_FSAL_setattrs);
    } else {
      FSI_TRACE(FSI_INFO, "Chown SUCCEED");
    }
  }
  FSI_TRACE(FSI_DEBUG, "End chown-----------------------------------\n");

  /***********
   *  UTIME  *
   ***********/
  FSI_TRACE(FSI_DEBUG, "Begin UTIME-----------------------------------\n");
  /* user must be the owner or have read access to modify 'atime' */
  access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);

  if (!p_context->export_context->fe_static_fs_info->accesscheck_support) {
    status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                      &current_attrs);
  } else {
    status = fsal_internal_access(p_context, p_filehandle, access_mask,
                                  &current_attrs);
  }

  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)
     && (p_context->credential.user != 0)
     && (p_context->credential.user != current_attrs.owner)
     && (status.major
         != ERR_FSAL_NO_ERROR)) {
    ReturnStatus(status, INDEX_FSAL_setattrs);
  }

  /* user must be the owner or have write access to modify 'mtime' */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);

  if (!p_context->export_context->fe_static_fs_info->accesscheck_support) {
    status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                      &current_attrs);
  } else {
    status = fsal_internal_access(p_context, p_filehandle, access_mask,
                                  &current_attrs);
  }
  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME)
     && (p_context->credential.user != 0)
     && (p_context->credential.user != current_attrs.owner)
     && (status.major
         != ERR_FSAL_NO_ERROR)) {
     ReturnStatus(status, INDEX_FSAL_setattrs);
  }

  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME | 
                    FSAL_ATTR_MTIME)) {

    /* Fill wanted atime. */
    if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)) {
      buffxstat.buffstat.st_atime = (time_t) wanted_attrs.atime.seconds;
      FSI_TRACE(FSI_DEBUG,
                "current atime = %lu, new atime = %lu",
                (unsigned long)current_attrs.atime.seconds, 
                (unsigned long)buffxstat.buffstat.st_atime);
    } else {
      buffxstat.buffstat.st_atime = (time_t) current_attrs.atime.seconds;
    }
    FSI_TRACE(FSI_DEBUG,
              "current atime = %lu, new atime = %lu",
              (unsigned long)current_attrs.atime.seconds,
              (unsigned long)buffxstat.buffstat.st_atime);

    /* Fill wanted mtime. */
    if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME)) {
      buffxstat.buffstat.st_mtime = (time_t) wanted_attrs.mtime.seconds;
    } else {
      buffxstat.buffstat.st_mtime = (time_t) current_attrs.mtime.seconds;
    }
    FSI_TRACE(FSI_DEBUG,
              "current mtime = %lu, new mtime = %lu",
              (unsigned long)current_attrs.mtime.seconds,
              (unsigned long)buffxstat.buffstat.st_mtime);

    rc = fsi_get_name_from_handle(p_context, 
                                  p_filehandle->data.handle.f_handle, 
                                  fsi_name,
                                  NULL);
    if (rc < 0) {
      FSI_TRACE(FSI_ERR, 
                "Failed to convert file handle back to filename "  
                "from cache" );
      FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s",
                p_filehandle->data.handle.f_handle);
      Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs);
    }

    FSI_TRACE(FSI_DEBUG, "Handle to name: %s for handle %s", 
              fsi_name, p_filehandle->data.handle.f_handle); 
   
    rc = ptfsal_ntimes(p_context, fsi_name, buffxstat.buffstat.st_atime, 
                       buffxstat.buffstat.st_mtime);
    if (rc == -1) {
      FSI_TRACE(FSI_ERR, "ntime FAILED");
      Return (ERR_FSAL_PERM, 2, INDEX_FSAL_setattrs);
    } else {
      FSI_TRACE(FSI_INFO, "ntime SUCCEED");
    }

  }
  FSI_TRACE(FSI_DEBUG, "End UTIME------------------------------\n");

#ifdef _USE_NFS4_ACL
   /***********
   *  ACL  *
   ***********/

  if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ACL)) {
    /* Check permission to set ACL. */
    access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy */
                  FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ACL);

    if (!p_context->export_context->fe_static_fs_info->accesscheck_support)
      status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                        &current_attrs);
    else
      status = fsal_internal_access(p_context, p_filehandle, access_mask,
                                      &current_attrs);

    if (FSAL_IS_ERROR(status))
      ReturnStatus(status, INDEX_FSAL_setattrs);

    if (wanted_attrs.acl) {
      LogDebug(COMPONENT_FSAL, "setattr acl = %p", wanted_attrs.acl);

      /* Convert FSAL ACL to PTFS NFS4 ACL and fill the buffer. */
      status = fsal_acl_2_ptfs_acl(wanted_attrs.acl, &buffxstat);

      if (FSAL_IS_ERROR(status))
        ReturnStatus(status, INDEX_FSAL_setattrs);
    } else {
      LogCrit(COMPONENT_FSAL, "setattr acl is NULL");
      Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);
    }
  }
#endif                          /* _USE_NFS4_ACL */


  /* Optionaly fills output attributes. */

  if (p_object_attributes) {
    status = PTFSAL_getattrs(p_filehandle, p_context, p_object_attributes);

    /* on error, we set a special bit in the mask. */
    if (FSAL_IS_ERROR(status)) {
      FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
      FSAL_SET_MASK(p_object_attributes->asked_attributes, 
                    FSAL_ATTR_RDATTR_ERR);
    }

  }
  FSI_TRACE(FSI_DEBUG, "End--------------------------------------------\n");
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);

}
Exemple #15
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_dirname (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory 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 directory.
 * \param object_attributes (optionnal input/output): 
 *        The attributes of the created directory.
 *        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).
 *        May 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_mkdir(proxyfsal_handle_t * parent_directory_handle,     /* IN */
                              fsal_name_t * p_dirname,  /* 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_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];
  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_MKDIR_NB_OP_ALLOC 4
#define FSAL_MKDIR_VAL_BUFFER  1024

  nfs_argop4 argoparray[FSAL_MKDIR_NB_OP_ALLOC];
  nfs_resop4 resoparray[FSAL_MKDIR_NB_OP_ALLOC];

  char fattr_val[FSAL_MKDIR_VAL_BUFFER];
  struct timeval timeout = { 25, 0 };

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

  PRINT_HANDLE("FSAL_mkdir", parent_directory_handle);

  /* 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_MKDIR_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_dirname, &name) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir);

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

  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_mkdir);

#define FSAL_MKDIR_IDX_OP_PUTFH     0
#define FSAL_MKDIR_IDX_OP_MKDIR     1
#define FSAL_MKDIR_IDX_OP_GETFH     2
#define FSAL_MKDIR_IDX_OP_GETATTR   3
  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh);
  COMPOUNDV4_ARG_ADD_OP_MKDIR(argnfs4, name, input_attr);
  COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4);
  COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap);

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

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

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

  resnfs4.resarray.resarray_val[FSAL_MKDIR_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val =
      (char *)&fattr_internal;
  resnfs4.resarray.resarray_val[FSAL_MKDIR_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_mkdir);
    }

  ReleaseTokenFSCall();

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

  /* Use NFSv4 service function to build the FSAL_attr */
  if(nfs4_Fattr_To_FSAL_attr(&attributes,
                             &resnfs4.resarray.resarray_val[FSAL_MKDIR_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_mkdir);

    }

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

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

  PRINT_HANDLE("FSAL_mkdir new obj", object_handle);

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir);

}
cache_entry_t *cache_inode_get_located(cache_inode_fsal_data_t * pfsdata,
                                       cache_entry_t * plocation, 
                                       cache_inode_policy_t policy,
                                       fsal_attrib_list_t * pattr,
                                       hash_table_t * ht,
                                       cache_inode_client_t * pclient,
                                       fsal_op_context_t * pcontext,
                                       cache_inode_status_t * pstatus)
{
  hash_buffer_t key, value;
  cache_entry_t *pentry = NULL;
  fsal_status_t fsal_status;
  cache_inode_create_arg_t create_arg;
  cache_inode_file_type_t type;
  int hrc = 0;
  fsal_attrib_list_t fsal_attributes;
  cache_inode_fsal_data_t *ppoolfsdata = NULL;

  memset(&create_arg, 0, sizeof(create_arg));

  /* Set the return default to CACHE_INODE_SUCCESS */
  *pstatus = CACHE_INODE_SUCCESS;

  /* stats */
  /* cache_invalidate calls this with no context or client */
  if (pclient) {
    pclient->stat.nb_call_total += 1;
    pclient->stat.func_stats.nb_call[CACHE_INODE_GET] += 1;
  }

  /* Turn the input to a hash key */
  if(cache_inode_fsaldata_2_key(&key, pfsdata, pclient))
    {
      *pstatus = CACHE_INODE_UNAPPROPRIATED_KEY;

      /* stats */
      /* cache_invalidate calls this with no context or client */
      if (pclient) {
	pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;
	ppoolfsdata = (cache_inode_fsal_data_t *) key.pdata;
	ReleaseToPool(ppoolfsdata, &pclient->pool_key);
      }
      return NULL;
    }

  switch (hrc = HashTable_Get(ht, &key, &value))
    {
    case HASHTABLE_SUCCESS:
      /* Entry exists in the cache and was found */
      pentry = (cache_entry_t *) value.pdata;

      /* return attributes additionally */
      *pattr = pentry->attributes;

      if ( !pclient ) {
	/* invalidate. Just return it to mark it stale and go on. */
	return( pentry );
      }

      break;

    case HASHTABLE_ERROR_NO_SUCH_KEY:
      if ( !pclient ) {
	/* invalidate. Just return */
	return( NULL );
      }
      /* Cache miss, allocate a new entry */

      /* XXX I do not think this can happen with avl dirent cache */
      if(pfsdata->cookie != DIR_START)
        {
          /* added for sanity check */
          LogDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_get: pfsdata->cookie != DIR_START (=%"PRIu64") on object whose type is %u",
                       pfsdata->cookie,
                       cache_inode_fsal_type_convert(fsal_attributes.type));

          pfsdata->cookie = DIR_START;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          /* redo the call */
          return cache_inode_get(pfsdata, policy, pattr, ht, pclient, pcontext, pstatus);
        }

      /* First, call FSAL to know what the object is */
      fsal_attributes.asked_attributes = pclient->attrmask;
      fsal_status = FSAL_getattrs(&pfsdata->handle, pcontext, &fsal_attributes);
      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_get: cache_inode_status=%u fsal_status=%u,%u ",
                   *pstatus, fsal_status.major, fsal_status.minor);

          if(fsal_status.major == ERR_FSAL_STALE)
            {
              char handle_str[256];

              snprintHandle(handle_str, 256, &pfsdata->handle);
              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_get: Stale FSAL File Handle %s, fsal_status=(%u,%u)",
                       handle_str, fsal_status.major, fsal_status.minor);

              *pstatus = CACHE_INODE_FSAL_ESTALE;
            }

          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* The type has to be set in the attributes */
      if(!FSAL_TEST_MASK(fsal_attributes.supported_attributes, FSAL_ATTR_TYPE))
        {
          *pstatus = CACHE_INODE_FSAL_ERROR;

          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* Get the cache_inode file type */
      type = cache_inode_fsal_type_convert(fsal_attributes.type);

      if(type == SYMBOLIC_LINK)
        {
          if( CACHE_INODE_KEEP_CONTENT( policy ) )
           {
             FSAL_CLEAR_MASK(fsal_attributes.asked_attributes);
             FSAL_SET_MASK(fsal_attributes.asked_attributes, pclient->attrmask);
             fsal_status =
                FSAL_readlink(&pfsdata->handle, pcontext, &create_arg.link_content,
                              &fsal_attributes);
            }
          else
            { 
               fsal_status.major = ERR_FSAL_NO_ERROR ;
               fsal_status.minor = 0 ;
            }

          if(FSAL_IS_ERROR(fsal_status))
            {
              *pstatus = cache_inode_error_convert(fsal_status);

              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

              /* Free this key */
              cache_inode_release_fsaldata_key(&key, pclient);

              if(fsal_status.major == ERR_FSAL_STALE)
                {
                  cache_inode_status_t kill_status;

                  LogEvent(COMPONENT_CACHE_INODE,
                           "cache_inode_get: Stale FSAL File Handle detected for pentry = %p, fsal_status=(%u,%u)",
                           pentry, fsal_status.major, fsal_status.minor);

                  if(cache_inode_kill_entry(pentry, NO_LOCK, ht, pclient, &kill_status) !=
                     CACHE_INODE_SUCCESS)
                    LogCrit(COMPONENT_CACHE_INODE,
                            "cache_inode_get: Could not kill entry %p, status = %u, fsal_status=(%u,%u)",
                            pentry, kill_status, fsal_status.major, fsal_status.minor);

                  *pstatus = CACHE_INODE_FSAL_ESTALE;

                }

              return NULL;
            }
        }

      /* Add the entry to the cache */
      if ( type == 1)
	LogCrit(COMPONENT_CACHE_INODE,"inode get");

      if((pentry = cache_inode_new_entry( pfsdata,
                                          &fsal_attributes, 
                                          type,
                                          policy, 
                                          &create_arg, 
                                          NULL,    /* never used to add a new DIR_CONTINUE within this function */
                                          ht, 
                                          pclient, 
                                          pcontext, 
                                          FALSE,  /* This is a population, not a creation */
                                          pstatus ) ) == NULL )
        {
          /* stats */
          pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

          /* Free this key */
          cache_inode_release_fsaldata_key(&key, pclient);

          return NULL;
        }

      /* Set the returned attributes */
      *pattr = fsal_attributes;

      /* Now, exit the switch/case and returns */
      break;

    default:
      /* This should not happened */
      *pstatus = CACHE_INODE_INVALID_ARGUMENT;
      LogCrit(COMPONENT_CACHE_INODE,
              "cache_inode_get returning CACHE_INODE_INVALID_ARGUMENT - this should not have happened");

      if ( !pclient ) {
        /* invalidate. Just return */
        return( NULL );
      }

      /* stats */
      pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_GET] += 1;

      /* Free this key */
      cache_inode_release_fsaldata_key(&key, pclient);

      return NULL;
      break;
    }

  /* Want to ASSERT pclient at this point */
  *pstatus = CACHE_INODE_SUCCESS;
  
  if (pentry->object.symlink != NULL) {
  	int stop_here;
	stop_here = 1;
	if (stop_here) {
		stop_here = 2;
	}
  }

  /* valid the found entry, if this is not feasable, returns nothing to the client */
  if( plocation != NULL )
   {
     if( plocation != pentry )
      {
        P_w(&pentry->lock);
        if((*pstatus =
           cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient)) != CACHE_INODE_SUCCESS)
          {
            V_w(&pentry->lock);
            pentry = NULL;
          }
        V_w(&pentry->lock);
      }
   }

  /* stats */
  pclient->stat.func_stats.nb_success[CACHE_INODE_GET] += 1;

  /* Free this key */
  cache_inode_release_fsaldata_key(&key, pclient);

  return pentry;
}  /* cache_inode_get_located */
Exemple #17
0
/**
 * FSAL_link:
 * Create a hardlink.
 *
 * \param target_handle (input):
 *        Handle of the target object.
 * \param dir_handle (input):
 *        Pointer to the directory handle where
 *        the hardlink is to be created.
 * \param p_link_name (input):
 *        Pointer to the name of the hardlink to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param attributes (optionnal input/output): 
 *        The post_operation attributes of the linked object.
 *        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).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - ERR_FSAL_STALE        (target_handle or dir_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 attributes->asked_attributes field.
 */
fsal_status_t PROXYFSAL_link(proxyfsal_handle_t * target_handle,        /* IN */
                             proxyfsal_handle_t * dir_handle,   /* IN */
                             fsal_name_t * p_link_name, /* IN */
                             proxyfsal_op_context_t * p_context,        /* IN */
                             fsal_attrib_list_t * attributes    /* [ IN/OUT ] */
    )
{
  int rc;

  COMPOUND4args argnfs4;
  COMPOUND4res resnfs4;
  nfs_fh4 nfs4fh_target;
  nfs_fh4 nfs4fh_dest;
  bitmap4 bitmap;
  uint32_t bitmap_val[2];
  uint32_t bitmap_res[2];
  component4 name;
  char nameval[MAXNAMLEN];

  fsal_proxy_internal_fattr_t fattr_internal;

  struct timeval timeout = { 25, 0 };

  /* sanity checks.
   * note : attributes is optional.
   */
  if(!target_handle || !dir_handle || !p_context || !p_link_name)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link);

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

  if(!global_fs_info.link_support)
    Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link);

#define FSAL_LINK_NB_OP_ALLOC 6
  nfs_argop4 argoparray[FSAL_LINK_NB_OP_ALLOC];
  nfs_resop4 resoparray[FSAL_LINK_NB_OP_ALLOC];

  /* 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: Link" ; */
  argnfs4.tag.utf8string_val = NULL;
  argnfs4.tag.utf8string_len = 0;
  argnfs4.argarray.argarray_len = 0;

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

  if(fsal_internal_proxy_extract_fh(&nfs4fh_target, target_handle) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link);

  if(fsal_internal_proxy_extract_fh(&nfs4fh_dest, dir_handle) == FALSE)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link);

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

#define FSAL_LINK_IDX_OP_PUTFH_TARGET 0
#define FSAL_LINK_IDX_OP_SAVEFH       1
#define FSAL_LINK_IDX_OP_PUTFH_DEST   2
#define FSAL_LINK_IDX_OP_LINK         3
#define FSAL_LINK_IDX_OP_RESTOREFH    4
#define FSAL_LINK_IDX_OP_GETATTR      5
  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_target);
  COMPOUNDV4_ARG_ADD_OP_SAVEFH(argnfs4);
  COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh_dest);
  COMPOUNDV4_ARG_ADD_OP_LINK(argnfs4, name);
  COMPOUNDV4_ARG_ADD_OP_RESTOREFH(argnfs4);
  COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap);

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

  resnfs4.resarray.resarray_val[FSAL_LINK_IDX_OP_GETATTR].nfs_resop4_u.opgetattr.
      GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val =
      (char *)&fattr_internal;
  resnfs4.resarray.resarray_val[FSAL_LINK_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_link);
    }

  ReleaseTokenFSCall();

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

  if(attributes)
    {
      /* Use NFSv4 service function to build the FSAL_attr */
      if(nfs4_Fattr_To_FSAL_attr(attributes,
                                 &resnfs4.resarray.
                                 resarray_val[FSAL_LINK_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_link);
        }
    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link);

}
/*
 * Read the ACL in GlusterFS format and convert it into fsal ACL before
 * storing it in fsalattr
 */
fsal_status_t glusterfs_get_acl(struct glusterfs_export *glfs_export,
				struct glfs_object *glhandle,
				glusterfs_fsal_xstat_t *buffxstat,
				struct attrlist *fsalattr)
{
	fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
	fsal_acl_data_t acldata;
	fsal_acl_status_t aclstatus;
	fsal_ace_t *pace = NULL;
	int e_count = 0, i_count = 0, new_count = 0, new_i_count = 0;

	if (fsalattr->acl != NULL) {
		/* We should never be passed attributes that have an
		 * ACL attached, but just in case some future code
		 * path changes that assumption, let's release the
		 * old ACL properly.
		 */
		int acl_status;

		acl_status = nfs4_acl_release_entry(fsalattr->acl);

		if (acl_status != NFS_V4_ACL_SUCCESS)
			LogCrit(COMPONENT_FSAL,
				"Failed to release old acl, status=%d",
				acl_status);

		fsalattr->acl = NULL;
	}

	if (NFSv4_ACL_SUPPORT) {

		buffxstat->e_acl = glfs_h_acl_get(glfs_export->gl_fs->fs,
						glhandle, ACL_TYPE_ACCESS);

		if (!buffxstat->e_acl) {
			status = gluster2fsal_error(errno);
			return status;
		}

		e_count = ace_count(buffxstat->e_acl);

		if (buffxstat->is_dir) {
			buffxstat->i_acl =
					 glfs_h_acl_get(glfs_export->gl_fs->fs,
						glhandle, ACL_TYPE_DEFAULT);
			i_count = ace_count(buffxstat->i_acl);
		}

		/* Allocating memory for both ALLOW and DENY entries */
		acldata.naces = 2 * (e_count  + i_count);

		LogDebug(COMPONENT_FSAL, "No of aces present in fsal_acl_t = %d"
					, acldata.naces);
		if (!acldata.naces)
			return status;

		FSAL_SET_MASK(buffxstat->attr_valid, XATTR_ACL);

		acldata.aces = (fsal_ace_t *) nfs4_ace_alloc(acldata.naces);
		pace = acldata.aces;

		new_count = posix_acl_2_fsal_acl(buffxstat->e_acl,
					buffxstat->is_dir, false, &pace);
		if (new_count < 0)
			return fsalstat(ERR_FSAL_NO_ACE, -1);

		if (i_count > 0) {
			new_i_count = posix_acl_2_fsal_acl(buffxstat->i_acl,
							true, true, &pace);
			if (new_i_count > 0)
				new_count += new_i_count;
			else
				LogDebug(COMPONENT_FSAL,
				"Inherit acl is not set for this directory");
		}

		/* Reallocating acldata into the required size */
		acldata.aces = (fsal_ace_t *) gsh_realloc(acldata.aces,
				new_count*sizeof(fsal_ace_t));
		acldata.naces = new_count;

		fsalattr->acl = nfs4_acl_new_entry(&acldata, &aclstatus);
		LogDebug(COMPONENT_FSAL, "fsal acl = %p, fsal_acl_status = %u",
				fsalattr->acl, aclstatus);
		if (fsalattr->acl == NULL) {
			LogCrit(COMPONENT_FSAL,
			"failed to create a new acl entry");
			return fsalstat(ERR_FSAL_NOMEM, -1);
		}

		fsalattr->valid_mask |= ATTR_ACL;
	} else {
		/* We were asked for ACL but do not support. */
		status = fsalstat(ERR_FSAL_NOTSUPP, 0);
	}

	return status;

}
Exemple #19
0
fsal_status_t CEPHFSAL_setattrs(fsal_handle_t * exthandle,
                                fsal_op_context_t * extcontext,
                                fsal_attrib_list_t * attrib_set,
                                fsal_attrib_list_t * object_attributes)
{
  cephfsal_handle_t* filehandle = (cephfsal_handle_t*) exthandle;
  cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext;
  struct stat st;
  fsal_attrib_list_t attrs;
  int rc, mask=0;
  int uid = FSAL_OP_CONTEXT_TO_UID(context);
  int gid = FSAL_OP_CONTEXT_TO_GID(context);

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

  /* local copy of attributes */
  attrs = *attrib_set;

  /* First, check that FSAL attributes changes are allowed. */

  /* Is it allowed to change times ? */

  if(!global_fs_info.cansettime)
    {
      if(attrs.asked_attributes &
         (FSAL_ATTR_ATIME |
          FSAL_ATTR_CREATION |
          FSAL_ATTR_CTIME |
          FSAL_ATTR_MTIME))
        {

          /* handled as an unsettable attribute. */
          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
        }

    }

  /* apply umask, if mode attribute is to be changed */

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
    {
      attrs.mode &= (~global_fs_info.umask);
    }

  /* Build flags and struct stat */

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
    {
      mask |= CEPH_SETATTR_MODE;
      st.st_mode = fsal2unix_mode(attrs.mode);
    }
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER))
    {
      mask |= CEPH_SETATTR_UID;
      st.st_uid = attrs.owner;
    }
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP))
    {
      mask |= CEPH_SETATTR_UID;
      st.st_gid = attrs.group;
    }
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME))
    {
      mask |= CEPH_SETATTR_ATIME;
      st.st_atime = attrs.atime.seconds;
    }
  if (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME))
    {
      mask |= CEPH_SETATTR_MTIME;
      st.st_mtime = attrs.mtime.seconds;
    }
  if (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_CTIME))
    {
      mask |= CEPH_SETATTR_CTIME;
      st.st_ctime = attrs.ctime.seconds;
    }

  TakeTokenFSCall();

  rc = ceph_ll_setattr(context->export_context->cmount, VINODE(filehandle),
                       &st, mask, uid, gid);

  ReleaseTokenFSCall();

  if (rc < 0)
    Return(posix2fsal_error(rc), 0, INDEX_FSAL_getattrs);

  if(object_attributes)
    {
      fsal_status_t status;
      status = CEPHFSAL_getattrs(exthandle, extcontext, object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(object_attributes->asked_attributes);
          FSAL_SET_MASK(object_attributes->asked_attributes,
                        FSAL_ATTR_RDATTR_ERR);
        }

    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);
}
Exemple #20
0
fsal_status_t CEPHFSAL_rename(fsal_handle_t * extold_parent,
                              fsal_name_t * old_name,
                              fsal_handle_t * extnew_parent,
                              fsal_name_t * new_name,
                              fsal_op_context_t * extcontext,
                              fsal_attrib_list_t * src_dir_attributes,
                              fsal_attrib_list_t * tgt_dir_attributes)
{
  int rc;
  cephfsal_handle_t* old_parent = (cephfsal_handle_t*) extold_parent;
  cephfsal_handle_t* new_parent = (cephfsal_handle_t*) extnew_parent;
  cephfsal_op_context_t* context = (cephfsal_op_context_t*) extcontext;
  char oldstr[FSAL_MAX_NAME_LEN+1];
  char newstr[FSAL_MAX_NAME_LEN+1];
  int uid = FSAL_OP_CONTEXT_TO_UID(context);
  int gid = FSAL_OP_CONTEXT_TO_GID(context);

  /* sanity checks.
   * note : src/tgt_dir_attributes are optional.
   */
  if(!old_parent || !new_parent || !old_name || !new_name || !context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

  if(src_dir_attributes)
    {
      fsal_status_t status =
        CEPHFSAL_getattrs(extold_parent, extcontext, src_dir_attributes);

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes);
          FSAL_SET_MASK(src_dir_attributes->asked_attributes,
                        FSAL_ATTR_RDATTR_ERR);
        }
    }

  if(tgt_dir_attributes)
    {
      fsal_status_t status;

      /* optimization when src=tgt : */

      if(!CEPHFSAL_handlecmp(extold_parent, extnew_parent, &status)
         && src_dir_attributes)
        {
          /* If source dir = target dir, we just copy the attributes.
           * to avoid doing another getattr.
           */
          (*tgt_dir_attributes) = (*src_dir_attributes);
        }
      else
        {
          status = CEPHFSAL_getattrs(extnew_parent, extcontext,
                                     tgt_dir_attributes);

          if(FSAL_IS_ERROR(status))
            {
              FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes);
              FSAL_SET_MASK(tgt_dir_attributes->asked_attributes,
                            FSAL_ATTR_RDATTR_ERR);
            }
        }
    }

  FSAL_name2str(old_name, oldstr, FSAL_MAX_NAME_LEN);
  FSAL_name2str(new_name, newstr, FSAL_MAX_NAME_LEN);
  rc = ceph_ll_rename(context->export_context->cmount,
                      VINODE(old_parent), oldstr,
                      VINODE(new_parent), newstr,
                      uid, gid);

  if (rc < 0)
    Return(posix2fsal_error(rc), 0, INDEX_FSAL_rename);

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename);
}
Exemple #21
0
/**
 * FSAL_open:
 * Open a regular file for reading/writing its data content.
 *
 * \param filehandle (input):
 *        Handle of the file to be read/modified.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param openflags (input):
 *        Flags that indicates behavior for file opening and access.
 *        This is an inclusive OR of the following values
 *        ( such of them are not compatible) :
 *        - FSAL_O_RDONLY: opening file for reading only.
 *        - FSAL_O_RDWR: opening file for reading and writing.
 *        - FSAL_O_WRONLY: opening file for writting only.
 *        - FSAL_O_APPEND: always write at the end of the file.
 *        - FSAL_O_TRUNC: truncate the file to 0 on opening.
 * \param file_descriptor (output):
 *        The file descriptor to be used for FSAL_read/write operations.
 * \param file_attributes (optionnal input/output):
 *        Post operation attributes.
 *        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).
 *
 * \return Major error codes:
 *      - ERR_FSAL_NO_ERROR     (no error)
 *      - ERR_FSAL_ACCESS       (user doesn't have the permissions for opening the file)
 *      - ERR_FSAL_STALE        (filehandle does not address an existing object)
 *      - ERR_FSAL_INVAL        (filehandle does not address a regular file,
 *                               or open flags are conflicting)
 *      - ERR_FSAL_FAULT        (a NULL pointer was passed as mandatory argument)
 *      - Other error codes can be returned :
 *        ERR_FSAL_IO, ...
 */
fsal_status_t FUSEFSAL_open(fsal_handle_t * file_hdl,     /* IN */
                            fsal_op_context_t * p_context,  /* IN */
                            fsal_openflags_t openflags, /* IN */
                            fsal_file_t * file_desc,  /* OUT */
                            fsal_attrib_list_t * file_attributes        /* [ IN/OUT ] */
    )
{

  int rc = 0;
  char object_path[FSAL_MAX_PATH_LEN];
  int file_info_provided = FALSE;
  fusefsal_handle_t * filehandle = (fusefsal_handle_t *)file_hdl;
  fusefsal_file_t * file_descriptor = (fusefsal_file_t *)file_desc;

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

  /* get the full path for this file */
  rc = NamespacePath(filehandle->data.inode, filehandle->data.device, filehandle->data.validator,
                     object_path);
  if(rc)
    Return(ERR_FSAL_STALE, rc, INDEX_FSAL_open);

  memset(file_descriptor, 0, sizeof(fusefsal_file_t));

  /* set access mode flags */

  file_descriptor->file_info.flags = 0;

  if(openflags & FSAL_O_RDONLY)
    file_descriptor->file_info.flags |= O_RDONLY;
  if(openflags & FSAL_O_WRONLY)
    file_descriptor->file_info.flags |= O_WRONLY;
  if(openflags & FSAL_O_RDWR)
    file_descriptor->file_info.flags |= O_RDWR;

  /* set context for the next operation, so it can be retrieved by FS thread */
  fsal_set_thread_context(p_context);

  /* check open call */

  if(p_fs_ops->open)
    {
      LogFullDebug(COMPONENT_FSAL, "Call to open( %s, %#X )", object_path, file_descriptor->file_info.flags);

      TakeTokenFSCall();
      rc = p_fs_ops->open(object_path, &(file_descriptor->file_info));
      ReleaseTokenFSCall();

      if(rc)
        Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_open);

      file_info_provided = TRUE;

    }
  else
    {
      LogFullDebug(COMPONENT_FSAL, "no open command provided");

      /* ignoring open */
      memset(&(file_descriptor->file_info), 0, sizeof(struct ganefuse_file_info));
    }

  /* check open flags (only FSAL_O_TRUNC and FSAL_O_APPEND are used for FUSE filesystems) */

  if(openflags & FSAL_O_TRUNC)
    {
      if(file_info_provided && p_fs_ops->ftruncate)
        {
          LogFullDebug(COMPONENT_FSAL, "call to ftruncate on file since FSAL_O_TRUNC was set");

          /* ftruncate the file */
          TakeTokenFSCall();
          rc = p_fs_ops->ftruncate(object_path, 0, &(file_descriptor->file_info));
          ReleaseTokenFSCall();

          if(rc)
            Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_open);
        }
      else if(p_fs_ops->truncate)
        {
          LogFullDebug(COMPONENT_FSAL, "call to truncate on file since FSAL_O_TRUNC was set");

          /* truncate the file */
          TakeTokenFSCall();
          rc = p_fs_ops->truncate(object_path, 0);
          ReleaseTokenFSCall();

          if(rc)
            Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_open);
        }
      /* else: ignoring flag */
    }

  if(openflags & FSAL_O_APPEND)
    {
      struct stat stbuf;

      /* In this case, this only solution is to get file attributes */

      if(file_info_provided && p_fs_ops->fgetattr)
        {
          rc = p_fs_ops->fgetattr(object_path, &stbuf, &(file_descriptor->file_info));
        }
      else
        {
          rc = p_fs_ops->getattr(object_path, &stbuf);
        }

      if(rc)
        Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_open);

      file_descriptor->current_offset = stbuf.st_size;
    }
  else
    {
      file_descriptor->current_offset = 0;
    }

  /* fill the file descriptor structure */
  file_descriptor->file_handle = *filehandle;

  /* backup context */
  file_descriptor->context = *(fusefsal_op_context_t *)p_context;

  if(file_info_provided)
    LogFullDebug(COMPONENT_FSAL, "FSAL_open: FH=%"PRId64, file_descriptor->file_info.fh);

  if(file_attributes)
    {
      fsal_status_t status;

      status = FUSEFSAL_getattrs((fsal_handle_t *)filehandle, p_context, file_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(file_attributes->asked_attributes);
          FSAL_SET_MASK(file_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }
    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_open);

}
Exemple #22
0
/**
 * FSAL_readdir :
 *     Read the entries of an opened directory.
 *     
 * \param dir_descriptor (input):
 *        Pointer to the directory descriptor filled by FSAL_opendir.
 * \param start_position (input):
 *        Cookie that indicates the first object to be read during
 *        this readdir operation.
 *        This should be :
 *        - FSAL_READDIR_FROM_BEGINNING for reading the content
 *          of the directory from the beginning.
 *        - The end_position parameter returned by the previous
 *          call to FSAL_readdir.
 * \param get_attr_mask (input)
 *        Specify the set of attributes to be retrieved for directory entries.
 * \param buffersize (input)
 *        The size (in bytes) of the buffer where
 *        the direntries are to be stored.
 * \param pdirent (output)
 *        Adresse of the buffer where the direntries are to be stored.
 * \param end_position (output)
 *        Cookie that indicates the current position in the directory.
 * \param nb_entries (output)
 *        Pointer to the number of entries read during the call.
 * \param end_of_dir (output)
 *        Pointer to a boolean that indicates if the end of dir
 *        has been reached during the call.
 * 
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t LUSTREFSAL_readdir(fsal_dir_t *dir_desc,   /* IN */
                                 fsal_cookie_t start_pos,    /* IN */
                                 fsal_attrib_mask_t get_attr_mask,      /* IN */
                                 fsal_mdsize_t buffersize,      /* IN */
                                 fsal_dirent_t * p_pdirent,     /* OUT */
                                 fsal_cookie_t * p_end_position,  /* OUT */
                                 fsal_count_t * p_nb_entries,   /* OUT */
                                 fsal_boolean_t * p_end_of_dir  /* OUT */
    )
{
  fsal_status_t st;
  fsal_count_t max_dir_entries;
  struct dirent *dp;
  struct dirent dpe;
  fsal_path_t fsalpath;
  int rc;
  lustrefsal_dir_t * p_dir_descriptor = (lustrefsal_dir_t *)dir_desc;
  lustrefsal_cookie_t start_position;

  /*****************/
  /* sanity checks */
  /*****************/

  if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  max_dir_entries = (buffersize / sizeof(fsal_dirent_t));
  start_position.data.cookie = (off_t)start_pos.data;

  /***************************/
  /* seek into the directory */
  /***************************/
  errno = 0;
  if(start_position.data.cookie == 0)
    {
      rewinddir(p_dir_descriptor->p_dir);
      rc = errno;
    }
  else
    {
      seekdir(p_dir_descriptor->p_dir, start_position.data.cookie);
      rc = errno;
    }

  if(rc)
    Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir);

  /************************/
  /* browse the directory */
  /************************/

  *p_nb_entries = 0;
  while(*p_nb_entries < max_dir_entries)
    {
    /***********************/
      /* read the next entry */
    /***********************/
      TakeTokenFSCall();
      rc = readdir_r(p_dir_descriptor->p_dir, &dpe, &dp);
      ReleaseTokenFSCall();
      if(rc)
        {
          rc = errno;
          Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir);
        }
      /* End of directory */
      if(!dp)
        {
          *p_end_of_dir = 1;
          break;
        }

    /***********************************/
      /* Get information about the entry */
    /***********************************/

      /* skip . and .. */
      if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
        continue;

      /* build the full path of the file into "fsalpath */
      if(FSAL_IS_ERROR
         (st =
          FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN, &(p_pdirent[*p_nb_entries].name))))
        ReturnStatus(st, INDEX_FSAL_readdir);

      memcpy(&fsalpath, &(p_dir_descriptor->path), sizeof(fsal_path_t));
      st = fsal_internal_appendNameToPath(&fsalpath, &(p_pdirent[*p_nb_entries].name));
      if(FSAL_IS_ERROR(st))
        ReturnStatus(st, INDEX_FSAL_readdir);

      /* get object handle */
      TakeTokenFSCall();
      st = fsal_internal_Path2Handle((fsal_op_context_t *) &p_dir_descriptor->context, &fsalpath,
                                     &(p_pdirent[*p_nb_entries].handle));
      ReleaseTokenFSCall();

      if(FSAL_IS_ERROR(st))
        ReturnStatus(st, INDEX_FSAL_readdir);

    /************************
     * Fills the attributes *
     ************************/
      p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask;

      st = LUSTREFSAL_getattrs(&(p_pdirent[*p_nb_entries].handle),
                               (fsal_op_context_t *) &p_dir_descriptor->context,
                               &p_pdirent[*p_nb_entries].attributes);
      if(FSAL_IS_ERROR(st))
        {
          FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes);
          FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes,
                        FSAL_ATTR_RDATTR_ERR);
        }

      ((lustrefsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = telldir(p_dir_descriptor->p_dir);
      p_pdirent[*p_nb_entries].nextentry = NULL;
      if(*p_nb_entries)
        p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]);

      memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie,
	     sizeof(lustrefsal_cookie_t));
      (*p_nb_entries)++;
    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);

}
Exemple #23
0
static void fill_dirent(fsal_dirent_t * to_be_filled,
                        fsal_attrib_mask_t getattr_mask,
                        const char *name, const struct stat *stbuf, off_t off)
{
  fsal_status_t status;
  struct stat tmp_statbuff;
  int err = FALSE;
  fusefsal_handle_t *fill_handle = (fusefsal_handle_t *) &to_be_filled->handle;

  if(stbuf)
    {
      if(stbuf->st_ino == 0)
        {
          LogDebug(COMPONENT_FSAL,
                   "WARNING in fill_dirent: Filesystem doesn't provide inode numbers !!!");
        }

      fill_handle->data.inode = stbuf->st_ino;
      fill_handle->data.device = stbuf->st_dev;
      FSAL_str2name(name, strlen(name) + 1, &(to_be_filled->name));
      ((fusefsal_cookie_t *) &to_be_filled->cookie)->data = off;

      /* local copy for non "const" calls */
      tmp_statbuff = *stbuf;

      /* set attributes */
      to_be_filled->attributes.asked_attributes = getattr_mask;
      status = posix2fsal_attributes(&tmp_statbuff, &to_be_filled->attributes);

      LogFullDebug(COMPONENT_FSAL,
           "getattr_mask = %X, recupere = %X, status=%d, inode=%llX.%llu, type=%d, posixmode=%#o, mode=%#o",
           getattr_mask, to_be_filled->attributes.asked_attributes, status.major,
           to_be_filled->attributes.fsid.major, to_be_filled->attributes.fileid,
           to_be_filled->attributes.type, tmp_statbuff.st_mode,
           to_be_filled->attributes.mode);

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(to_be_filled->attributes.asked_attributes);
          /* set getattr error bit in attr mask */
          FSAL_SET_MASK(to_be_filled->attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR);
          err = TRUE;
        }
    }

  /* if any error occured during conversion,
   * or if values seem to be inconsistent,
   * proceed a lookup afterward */

  if(!stbuf
     || (stbuf->st_ino == 0)
     || err
     || to_be_filled->attributes.type == (fsal_nodetype_t) - 1
     || to_be_filled->attributes.mode == 0 || to_be_filled->attributes.numlinks == 0)
    {
      FSAL_CLEAR_MASK(to_be_filled->attributes.asked_attributes);
      /* we only known entry name, we tag it for a later lookup.
       */
      fill_handle->data.inode = INODE_TO_BE_COMPLETED;
      FSAL_str2name(name, strlen(name) + 1, &(to_be_filled->name));
      ((fusefsal_cookie_t *) &to_be_filled->cookie)->data = off;
    }

}                               /* fill_dirent */
Exemple #24
0
/**
 * FSAL_opendir :
 *     Opens a directory for reading its content.
 *     
 * \param dir_handle (input)
 *         the handle of the directory to be opened.
 * \param cred (input)
 *         Permission context for the operation (user,...).
 * \param dir_descriptor (output)
 *         pointer to an allocated structure that will receive
 *         directory stream informations, on successfull completion.
 * \param dir_attributes (optional output)
 *         On successfull completion,the structure pointed
 *         by dir_attributes receives the new directory attributes.
 *         May be NULL.
 * 
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t LUSTREFSAL_opendir(fsal_handle_t * p_dir_handle,    /* IN */
                                 fsal_op_context_t * p_context,   /* IN */
                                 fsal_dir_t *dir_desc,   /* OUT */
                                 fsal_attrib_list_t * p_dir_attributes  /* [ IN/OUT ] */
    )
{
  int rc;
  fsal_status_t status;

  fsal_path_t fsalpath;
  struct stat buffstat;
  lustrefsal_dir_t *p_dir_descriptor = (lustrefsal_dir_t *)dir_desc;

  /* sanity checks
   * note : dir_attributes is optionnal.
   */
  if(!p_dir_handle || !p_context || !p_dir_descriptor)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir);

  /* get the path of the directory */
  status = fsal_internal_Handle2FidPath(p_context, p_dir_handle, &fsalpath);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_opendir);

  /* get directory metadata */
  TakeTokenFSCall();
  rc = lstat(fsalpath.path, &buffstat);
  ReleaseTokenFSCall();

  if(rc != 0)
    {
      rc = errno;
      if(rc == ENOENT)
        Return(ERR_FSAL_STALE, rc, INDEX_FSAL_opendir);
      else
        Return(posix2fsal_error(rc), rc, INDEX_FSAL_opendir);
    }

  /* Test access rights for this directory */
  status = fsal_internal_testAccess(p_context, FSAL_R_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_opendir);

  /* if everything is OK, fills the dir_desc structure : */

  TakeTokenFSCall();
  p_dir_descriptor->p_dir = opendir(fsalpath.path);
  ReleaseTokenFSCall();
  if(!p_dir_descriptor->p_dir)
    Return(posix2fsal_error(errno), errno, INDEX_FSAL_opendir);

  memcpy(&(p_dir_descriptor->context), p_context, sizeof(lustrefsal_op_context_t));
  memcpy(&(p_dir_descriptor->path), &fsalpath, sizeof(fsal_path_t));
  memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(lustrefsal_handle_t));

  if(p_dir_attributes)
    {
      status = posix2fsal_attributes(&buffstat, p_dir_attributes);
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_dir_attributes->asked_attributes);
          FSAL_SET_MASK(p_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }
    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir);

}
Exemple #25
0
fsal_status_t FUSEFSAL_rename(fusefsal_handle_t * old_parentdir_handle, /* IN */
                              fsal_name_t * p_old_name, /* IN */
                              fusefsal_handle_t * new_parentdir_handle, /* IN */
                              fsal_name_t * p_new_name, /* IN */
                              fusefsal_op_context_t * p_context,        /* IN */
                              fsal_attrib_list_t * src_dir_attributes,  /* [ IN/OUT ] */
                              fsal_attrib_list_t * tgt_dir_attributes   /* [ IN/OUT ] */
    )
{

  int rc = 0;
  char src_dir_path[FSAL_MAX_PATH_LEN];
  char tgt_dir_path[FSAL_MAX_PATH_LEN];
  char src_obj_path[FSAL_MAX_PATH_LEN];
  char tgt_obj_path[FSAL_MAX_PATH_LEN];

  /* sanity checks.
   * note : src/tgt_dir_attributes are optional.
   */
  if(!old_parentdir_handle ||
     !new_parentdir_handle || !p_old_name || !p_new_name || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

  if(!p_fs_ops->rename)
    Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_rename);

  /* get full path for parent source handle */
  rc = NamespacePath(old_parentdir_handle->data.inode, old_parentdir_handle->data.device,
                     old_parentdir_handle->data.validator, src_dir_path);
  if(rc)
    Return(ERR_FSAL_STALE, rc, INDEX_FSAL_rename);

  /* get full path for parent target handle */
  rc = NamespacePath(new_parentdir_handle->data.inode, new_parentdir_handle->data.device,
                     new_parentdir_handle->data.validator, tgt_dir_path);
  if(rc)
    Return(ERR_FSAL_STALE, rc, INDEX_FSAL_rename);

  /* build full path for source entry */
  FSAL_internal_append_path(src_obj_path, src_dir_path, p_old_name->name);

  /* build full path for target entry */
  FSAL_internal_append_path(tgt_obj_path, tgt_dir_path, p_new_name->name);

  /* set context for the next operation, so it can be retrieved by FS thread */
  fsal_set_thread_context(p_context);

  TakeTokenFSCall();

  rc = p_fs_ops->rename(src_obj_path, tgt_obj_path);

  ReleaseTokenFSCall();

  /* Regarding FALSE parameter of function fuse2fsal_error:
   * here, if error is ENOENT, we don't know weither the father handle is STALE
   * or if the source entry does not exist.
   * We choose returning ENOENT since the parent exists in the namespace,
   * so it it more likely to exist than the children.
   */
  if(rc)
    Return(fuse2fsal_error(rc, FALSE), rc, INDEX_FSAL_rename);

  /* If operation succeeded, impact the namespace */
  NamespaceRename(old_parentdir_handle->data.inode, old_parentdir_handle->data.device,
                  old_parentdir_handle->data.validator, p_old_name->name,
                  new_parentdir_handle->data.inode, new_parentdir_handle->data.device,
                  new_parentdir_handle->data.validator, p_new_name->name);

  /* Last parent post op attributes if asked */

  if(src_dir_attributes)
    {
      fsal_status_t st;

      st = FUSEFSAL_getattrs(old_parentdir_handle, p_context, src_dir_attributes);

      if(FSAL_IS_ERROR(st))
        {
          FSAL_CLEAR_MASK(src_dir_attributes->asked_attributes);
          FSAL_SET_MASK(src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* New parent post op attributes if asked */

  if(tgt_dir_attributes)
    {
      fsal_status_t st;

      /* optimization when src=tgt : */

      if(!FUSEFSAL_handlecmp(old_parentdir_handle, new_parentdir_handle, &st)
         && src_dir_attributes)
        {

          /* If source dir = target dir, we just copy the attributes.
           * to avoid doing another getattr.
           */

          (*tgt_dir_attributes) = (*src_dir_attributes);

        }
      else
        {

          /* get attributes */
          st = FUSEFSAL_getattrs(new_parentdir_handle, p_context, tgt_dir_attributes);

          if(FSAL_IS_ERROR(st))
            {
              FSAL_CLEAR_MASK(tgt_dir_attributes->asked_attributes);
              FSAL_SET_MASK(tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
            }

        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename);

}
Exemple #26
0
static struct closefd vfs_fsal_open_and_stat(struct fsal_export *exp,
					     struct vfs_fsal_obj_handle *myself,
					     struct stat *stat, int open_flags,
					     fsal_errors_t *fsal_error)
{
	struct fsal_obj_handle *obj_hdl = &myself->obj_handle;
	struct closefd cfd = { .fd = -1, .close_fd = false };
	int retval = 0;
	vfs_file_handle_t *fh = NULL;
	vfs_alloc_handle(fh);
	const char *func = "unknown";
	struct vfs_filesystem *vfs_fs = myself->obj_handle.fs->private;

	switch (obj_hdl->type) {
	case SOCKET_FILE:
	case CHARACTER_FILE:
	case BLOCK_FILE:
		cfd.fd = vfs_open_by_handle(vfs_fs,
					    myself->u.unopenable.dir,
					    O_PATH | O_NOACCESS,
					    fsal_error);
		if (cfd.fd < 0) {
			LogDebug(COMPONENT_FSAL,
				 "Failed with %s open_flags 0x%08x",
				 strerror(-cfd.fd), O_PATH | O_NOACCESS);
			return cfd;
		}
		cfd.close_fd = true;
		retval =
		    fstatat(cfd.fd, myself->u.unopenable.name, stat,
			    AT_SYMLINK_NOFOLLOW);

		func = "fstatat";
		break;
	case REGULAR_FILE:
		if (myself->u.file.openflags == FSAL_O_CLOSED) {
			/* no file open at the moment */
			cfd.fd = vfs_fsal_open(myself, open_flags, fsal_error);
			if (cfd.fd < 0) {
				LogDebug(COMPONENT_FSAL,
					 "Failed with %s open_flags 0x%08x",
					 strerror(-cfd.fd), open_flags);
				return cfd;
			}
			cfd.close_fd = true;
		} else {
			cfd.fd = myself->u.file.fd;
		}
		retval = fstat(cfd.fd, stat);
		func = "fstat";
		break;
	case SYMBOLIC_LINK:
		open_flags |= (O_PATH | O_RDWR | O_NOFOLLOW);
		goto vfos_open;
	case FIFO_FILE:
		open_flags |= O_NONBLOCK;
		/* fall through */
	case DIRECTORY:
	default:
 vfos_open:
		cfd.fd = vfs_fsal_open(myself, open_flags, fsal_error);
		if (cfd.fd < 0) {
			LogDebug(COMPONENT_FSAL,
				 "Failed with %s open_flags 0x%08x",
				 strerror(-cfd.fd), open_flags);
			return cfd;
		}
		cfd.close_fd = true;
		retval = vfs_stat_by_handle(cfd.fd, myself->handle,
					    stat, open_flags);
		func = "vfs_stat_by_handle";
		break;
	}

	if (retval < 0) {
		retval = errno;
		if (cfd.close_fd) {
			int rc;
			rc = close(cfd.fd);
			if (rc < 0) {
				rc = errno;
				LogDebug(COMPONENT_FSAL, "close failed with %s",
					 strerror(rc));
			}
		}
		if (retval == ENOENT)
			retval = ESTALE;
		*fsal_error = posix2fsal_error(retval);
		LogDebug(COMPONENT_FSAL, "%s failed with %s", func,
			 strerror(retval));
		cfd.fd = -retval;
		cfd.close_fd = false;
		return cfd;
	}
	return cfd;
}

static fsal_status_t getattrs(struct fsal_obj_handle *obj_hdl)
{
	struct vfs_fsal_obj_handle *myself;
	struct closefd cfd = { .fd = -1, .close_fd = false };
	struct stat stat;
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	fsal_status_t st;
	int retval = 0;

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	if (obj_hdl->fsal != obj_hdl->fs->fsal) {
		LogDebug(COMPONENT_FSAL,
			 "FSAL %s getattr for handle belonging to FSAL %s, ignoring",
			 obj_hdl->fsal->name,
			 obj_hdl->fs->fsal != NULL
				? obj_hdl->fs->fsal->name
				: "(none)");
		goto out;
	}

	cfd = vfs_fsal_open_and_stat(op_ctx->fsal_export, myself, &stat,
				     O_RDONLY, &fsal_error);
	if (cfd.fd >= 0) {
		st = posix2fsal_attributes(&stat, &obj_hdl->attributes);
		if (cfd.close_fd)
			close(cfd.fd);
		if (FSAL_IS_ERROR(st)) {
			FSAL_CLEAR_MASK(obj_hdl->attributes.mask);
			FSAL_SET_MASK(obj_hdl->attributes.mask,
				      ATTR_RDATTR_ERR);
			fsal_error = st.major;
			retval = st.minor;
		} else {
			obj_hdl->attributes.fsid = obj_hdl->fs->fsid;
		}
	} else {
		LogDebug(COMPONENT_FSAL, "Failed with %s, fsal_error %s",
			 strerror(-cfd.fd),
			 fsal_error ==
			 ERR_FSAL_STALE ? "ERR_FSAL_STALE" : "other");
		if (obj_hdl->type == SYMBOLIC_LINK
		    && cfd.fd == -EPERM) {
			/* You cannot open_by_handle (XFS on linux) a symlink
			 * and it throws an EPERM error for it.
			 * open_by_handle_at does not throw that error for
			 * symlinks so we play a game here.  Since there is
			 * not much we can do with symlinks anyway,
			 * say that we did it but don't actually
			 * do anything.  In this case, return the stat we got
			 * at lookup time.  If you *really* want to tweek things
			 * like owners, get a modern linux kernel...
			 */
			fsal_error = ERR_FSAL_NO_ERROR;
			goto out;
		}
		retval = -cfd.fd;
	}

 out:
	return fsalstat(fsal_error, retval);
}

/*
 * NOTE: this is done under protection of the attributes rwlock
 * in the cache entry.
 */

static fsal_status_t setattrs(struct fsal_obj_handle *obj_hdl,
			      struct attrlist *attrs)
{
	struct vfs_fsal_obj_handle *myself;
	struct closefd cfd = { .fd = -1, .close_fd = false };
	struct stat stat;
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int retval = 0;
	int open_flags = O_RDONLY;

	/* apply umask, if mode attribute is to be changed */
	if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE))
		attrs->mode &= ~op_ctx->fsal_export->exp_ops.
			fs_umask(op_ctx->fsal_export);
	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);
	if (obj_hdl->fsal != obj_hdl->fs->fsal) {
		LogDebug(COMPONENT_FSAL,
			 "FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
			 obj_hdl->fsal->name,
			 obj_hdl->fs->fsal != NULL
				? obj_hdl->fs->fsal->name
				: "(none)");
		retval = EXDEV;
		fsal_error = posix2fsal_error(retval);
		goto hdlerr;
	}

	/* This is yet another "you can't get there from here".  If this object
	 * is a socket (AF_UNIX), an fd on the socket s useless _period_.
	 * If it is for a symlink, without O_PATH, you will get an ELOOP error
	 * and (f)chmod doesn't work for a symlink anyway - not that it matters
	 * because access checking is not done on the symlink but the final
	 * target.
	 * AF_UNIX sockets are also ozone material.  If the socket is already
	 * active listeners et al, you can manipulate the mode etc.  If it is
	 * just sitting there as in you made it with a mknod.
	 * (one of those leaky abstractions...)
	 * or the listener forgot to unlink it, it is lame duck.
	 */

	if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE))
		open_flags = O_RDWR;

	cfd = vfs_fsal_open_and_stat(op_ctx->fsal_export, myself, &stat,
				     open_flags, &fsal_error);

	if (cfd.fd < 0) {
		if (obj_hdl->type == SYMBOLIC_LINK &&
		    cfd.fd == -EPERM) {
			/* You cannot open_by_handle (XFS) a symlink and it
			 * throws an EPERM error for it.  open_by_handle_at
			 * does not throw that error for symlinks so we play a
			 * game here.  Since there is not much we can do with
			 * symlinks anyway, say that we did it
			 * but don't actually do anything.
			 * If you *really* want to tweek things
			 * like owners, get a modern linux kernel...
			 */
			fsal_error = ERR_FSAL_NO_ERROR;
			goto out;
		}
		return fsalstat(fsal_error, cfd.fd);
	}
	/** TRUNCATE **/
	if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) {
		if (obj_hdl->type != REGULAR_FILE) {
			fsal_error = ERR_FSAL_INVAL;
			goto fileerr;
		}
		retval = ftruncate(cfd.fd, attrs->filesize);
		if (retval != 0) {
			/* XXX ESXi volume creation pattern reliably
			 * reaches this point and reliably can successfully
			 * ftruncate on reopen.  I don't know yet if fd if
			 * we failed to handle a previous error, or what.
			 * I don't see a prior failed op in wireshark. */
			if (retval == -1 /* bad fd */) {
				vfs_close(obj_hdl);
				if (cfd.close_fd)
					close(cfd.fd);
				cfd = vfs_fsal_open_and_stat(
							op_ctx->fsal_export,
							     myself, &stat,
							     open_flags,
							     &fsal_error);
				retval = ftruncate(cfd.fd, attrs->filesize);
				if (retval != 0)
					goto fileerr;
			} else
				goto fileerr;
		}
	}

	/** CHMOD **/
	if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) {
		/* The POSIX chmod call doesn't affect the symlink object, but
		 * the entry it points to. So we must ignore it.
		 */
		if (!S_ISLNK(stat.st_mode)) {
			if (vfs_unopenable_type(obj_hdl->type))
				retval = fchmodat(cfd.fd,
						  myself->u.unopenable.name,
						  fsal2unix_mode(attrs->mode),
						  0);
			else
				retval = fchmod(cfd.fd,
						fsal2unix_mode(attrs->mode));

			if (retval != 0)
				goto fileerr;
		}
	}

	/**  CHOWN  **/
	if (FSAL_TEST_MASK(attrs->mask, ATTR_OWNER | ATTR_GROUP)) {
		uid_t user = FSAL_TEST_MASK(attrs->mask, ATTR_OWNER)
		    ? (int)attrs->owner : -1;
		gid_t group = FSAL_TEST_MASK(attrs->mask, ATTR_GROUP)
		    ? (int)attrs->group : -1;

		if (vfs_unopenable_type(obj_hdl->type))
			retval = fchownat(cfd.fd, myself->u.unopenable.name,
					  user, group, AT_SYMLINK_NOFOLLOW);
		else if (obj_hdl->type == SYMBOLIC_LINK)
			retval = fchownat(cfd.fd, "", user, group,
					  AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH);
		else
			retval = fchown(cfd.fd, user, group);

		if (retval)
			goto fileerr;
	}

	/**  UTIME  **/
	if (FSAL_TEST_MASK
	    (attrs->mask,
	     ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SERVER | ATTR_MTIME_SERVER)) {
		struct timespec timebuf[2];

		if (obj_hdl->type == SYMBOLIC_LINK)
			goto out; /* Setting time on symlinks is illegal */
		/* Atime */
		if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME_SERVER)) {
			timebuf[0].tv_sec = 0;
			timebuf[0].tv_nsec = UTIME_NOW;
		} else if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME)) {
			timebuf[0] = attrs->atime;
		} else {
			timebuf[0].tv_sec = 0;
			timebuf[0].tv_nsec = UTIME_OMIT;
		}

		/* Mtime */
		if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME_SERVER)) {
			timebuf[1].tv_sec = 0;
			timebuf[1].tv_nsec = UTIME_NOW;
		} else if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME)) {
			timebuf[1] = attrs->mtime;
		} else {
			timebuf[1].tv_sec = 0;
			timebuf[1].tv_nsec = UTIME_OMIT;
		}
		if (vfs_unopenable_type(obj_hdl->type))
			retval = vfs_utimesat(cfd.fd, myself->u.unopenable.name,
					      timebuf, AT_SYMLINK_NOFOLLOW);
		else
			retval = vfs_utimes(cfd.fd, timebuf);
		if (retval != 0)
			goto fileerr;
	}
	goto out;

 fileerr:
	retval = errno;
	fsal_error = posix2fsal_error(retval);
 out:
	if (cfd.close_fd)
		close(cfd.fd);
 hdlerr:
	return fsalstat(fsal_error, retval);
}

/* file_unlink
 * unlink the named file in the directory
 */

static fsal_status_t file_unlink(struct fsal_obj_handle *dir_hdl,
				 const char *name)
{
	struct vfs_fsal_obj_handle *myself;
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	struct stat stat;
	int fd;
	int retval = 0;

	myself = container_of(dir_hdl, struct vfs_fsal_obj_handle, obj_handle);
	if (dir_hdl->fsal != dir_hdl->fs->fsal) {
		LogDebug(COMPONENT_FSAL,
			 "FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
			 dir_hdl->fsal->name,
			 dir_hdl->fs->fsal != NULL
				? dir_hdl->fs->fsal->name
				: "(none)");
		retval = EXDEV;
		fsal_error = posix2fsal_error(retval);
		goto out;
	}
	fd = vfs_fsal_open(myself, O_PATH | O_NOACCESS, &fsal_error);
	if (fd < 0) {
		retval = -fd;
		goto out;
	}
	retval = fstatat(fd, name, &stat, AT_SYMLINK_NOFOLLOW);
	if (retval < 0) {
		retval = errno;
		LogDebug(COMPONENT_FSAL, "fstatat %s failed %s", name,
			 strerror(retval));
		if (retval == ENOENT)
			fsal_error = ERR_FSAL_STALE;
		else
			fsal_error = posix2fsal_error(retval);
		goto errout;
	}
	fsal_set_credentials(op_ctx->creds);
	retval = unlinkat(fd, name, (S_ISDIR(stat.st_mode)) ? AT_REMOVEDIR : 0);
	if (retval < 0) {
		retval = errno;
		if (retval == ENOENT)
			fsal_error = ERR_FSAL_STALE;
		else
			fsal_error = posix2fsal_error(retval);
	}
	fsal_restore_ganesha_credentials();

 errout:
	close(fd);
 out:
	return fsalstat(fsal_error, retval);
}

/* handle_digest
 * fill in the opaque f/s file handle part.
 * we zero the buffer to length first.  This MAY already be done above
 * at which point, remove memset here because the caller is zeroing
 * the whole struct.
 */

static fsal_status_t handle_digest(const struct fsal_obj_handle *obj_hdl,
				   fsal_digesttype_t output_type,
				   struct gsh_buffdesc *fh_desc)
{
	const struct vfs_fsal_obj_handle *myself;

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	if (obj_hdl->fsal != obj_hdl->fs->fsal) {
		/* Log, but allow digest */
		LogDebug(COMPONENT_FSAL,
			 "FSAL %s operation for handle belonging to FSAL %s",
			 obj_hdl->fsal->name,
			 obj_hdl->fs->fsal != NULL
				? obj_hdl->fs->fsal->name
				: "(none)");
	}

	switch (output_type) {
	case FSAL_DIGEST_NFSV3:
	case FSAL_DIGEST_NFSV4:
		if (fh_desc->len < myself->handle->handle_len) {
			LogMajor(COMPONENT_FSAL,
				 "Space too small for handle.  need %d, have %lu",
				 (int) myself->handle->handle_len,
				 fh_desc->len);
			return fsalstat(ERR_FSAL_TOOSMALL, 0);
		}
		memcpy(fh_desc->addr,
		       myself->handle->handle_data,
		       myself->handle->handle_len);
		break;
	default:
		return fsalstat(ERR_FSAL_SERVERFAULT, 0);
	}

	fh_desc->len = myself->handle->handle_len;
	return fsalstat(ERR_FSAL_NO_ERROR, 0);
}

/**
 * handle_to_key
 * return a handle descriptor into the handle in this object handle
 * @TODO reminder.  make sure things like hash keys don't point here
 * after the handle is released.
 */

static void handle_to_key(struct fsal_obj_handle *obj_hdl,
			  struct gsh_buffdesc *fh_desc)
{
	struct vfs_fsal_obj_handle *myself;

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	fh_desc->addr = myself->handle->handle_data;
	fh_desc->len = myself->handle->handle_len;
}

/*
 * release
 * release our export first so they know we are gone
 */

static void release(struct fsal_obj_handle *obj_hdl)
{
	struct vfs_fsal_obj_handle *myself;
	object_file_type_t type = obj_hdl->type;

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	if (type == REGULAR_FILE) {
		fsal_status_t st = vfs_close(obj_hdl);
		if (FSAL_IS_ERROR(st)) {
			LogCrit(COMPONENT_FSAL,
				"Could not close hdl 0x%p, error %s(%d)",
				obj_hdl, strerror(st.minor), st.minor);
		}
	}

	fsal_obj_handle_fini(obj_hdl);

	if (type == SYMBOLIC_LINK) {
		if (myself->u.symlink.link_content != NULL)
			gsh_free(myself->u.symlink.link_content);
	} else if (vfs_unopenable_type(type)) {
		if (myself->u.unopenable.name != NULL)
			gsh_free(myself->u.unopenable.name);
		if (myself->u.unopenable.dir != NULL)
			gsh_free(myself->u.unopenable.dir);
	}

	gsh_free(myself);
}

void vfs_handle_ops_init(struct fsal_obj_ops *ops)
{
	ops->release = release;
	ops->lookup = lookup;
	ops->readdir = read_dirents;
	ops->create = create;
	ops->mkdir = makedir;
	ops->mknode = makenode;
	ops->symlink = makesymlink;
	ops->readlink = readsymlink;
	ops->test_access = fsal_test_access;
	ops->getattrs = getattrs;
	ops->setattrs = setattrs;
	ops->link = linkfile;
	ops->rename = renamefile;
	ops->unlink = file_unlink;
	ops->open = vfs_open;
	ops->status = vfs_status;
	ops->read = vfs_read;
	ops->write = vfs_write;
	ops->commit = vfs_commit;
	ops->lock_op = vfs_lock_op;
	ops->close = vfs_close;
	ops->lru_cleanup = vfs_lru_cleanup;
	ops->handle_digest = handle_digest;
	ops->handle_to_key = handle_to_key;

	/* xattr related functions */
	ops->list_ext_attrs = vfs_list_ext_attrs;
	ops->getextattr_id_by_name = vfs_getextattr_id_by_name;
	ops->getextattr_value_by_name = vfs_getextattr_value_by_name;
	ops->getextattr_value_by_id = vfs_getextattr_value_by_id;
	ops->setextattr_value = vfs_setextattr_value;
	ops->setextattr_value_by_id = vfs_setextattr_value_by_id;
	ops->getextattr_attrs = vfs_getextattr_attrs;
	ops->remove_extattr_by_id = vfs_remove_extattr_by_id;
	ops->remove_extattr_by_name = vfs_remove_extattr_by_name;

}

/* export methods that create object handles
 */

/* lookup_path
 * modeled on old api except we don't stuff attributes.
 * KISS
 */

fsal_status_t vfs_lookup_path(struct fsal_export *exp_hdl,
			      const char *path, struct fsal_obj_handle **handle)
{
	int dir_fd = -1;
	struct stat stat;
	struct vfs_fsal_obj_handle *hdl;
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int retval = 0;
	struct fsal_filesystem *fs;
	struct fsal_dev__ dev;
	vfs_file_handle_t *fh = NULL;

	vfs_alloc_handle(fh);

	*handle = NULL;	/* poison it */

	dir_fd = open_dir_by_path_walk(-1, path, &stat);

	if (dir_fd < 0) {
		LogCrit(COMPONENT_FSAL,
			"Could not open directory for path %s",
			path);
		retval = -dir_fd;
		goto errout;
	}

	dev = posix2fsal_devt(stat.st_dev);
	fs = lookup_dev(&dev);

	if (fs == NULL) {
		LogInfo(COMPONENT_FSAL,
			"Could not find file system for path %s",
			path);
		retval = ENOENT;
		goto errout;
	}

	if (fs->fsal != exp_hdl->fsal) {
		LogInfo(COMPONENT_FSAL,
			"File system for path %s did not belong to FSAL %s",
			path, exp_hdl->fsal->name);
		retval = EACCES;
		goto errout;
	}

	LogDebug(COMPONENT_FSAL,
		 "filesystem %s for path %s",
		 fs->path, path);

	retval = vfs_fd_to_handle(dir_fd, fs, fh);

	if (retval < 0) {
		retval = errno;
		LogCrit(COMPONENT_FSAL,
			"Could not get handle for path %s, error %s",
			path, strerror(retval));
		goto errout;
	}

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(-1, fh, fs, &stat, NULL, "", exp_hdl);

	if (hdl == NULL) {
		retval = ENOMEM;
		LogCrit(COMPONENT_FSAL,
			"Could not allocate handle for path %s",
			path);
		goto errout;
	}

	close(dir_fd);

	*handle = &hdl->obj_handle;
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 errout:
	if (dir_fd >= 0)
		close(dir_fd);
	fsal_error = posix2fsal_error(retval);
	return fsalstat(fsal_error, retval);
}

fsal_status_t vfs_check_handle(struct fsal_export *exp_hdl,
			       struct gsh_buffdesc *hdl_desc,
			       struct fsal_filesystem **fs,
			       vfs_file_handle_t *fh,
			       bool *dummy)
{
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int retval = 0;
	struct fsal_fsid__ fsid;
	enum fsid_type fsid_type;

	*fs = NULL;

	if (!vfs_valid_handle(hdl_desc))
		return fsalstat(ERR_FSAL_BADHANDLE, 0);

	memcpy(fh->handle_data, hdl_desc->addr, hdl_desc->len);
	fh->handle_len = hdl_desc->len;

	*dummy = vfs_is_dummy_handle(fh);

	retval = vfs_extract_fsid(fh, &fsid_type, &fsid);

	if (retval == 0) {
		*fs = lookup_fsid(&fsid, fsid_type);
		if (*fs == NULL) {
			LogInfo(COMPONENT_FSAL,
				"Could not map "
				"fsid=0x%016"PRIx64".0x%016"PRIx64
				" to filesytem",
				fsid.major, fsid.minor);
			retval = ESTALE;
			fsal_error = posix2fsal_error(retval);
			goto errout;
		}
		if (((*fs)->fsal != exp_hdl->fsal) && !(*dummy)) {
			LogInfo(COMPONENT_FSAL,
				"fsid=0x%016"PRIx64".0x%016"PRIx64
				" in handle not a %s filesystem",
				fsid.major, fsid.minor,
				exp_hdl->fsal->name);
			retval = ESTALE;
			fsal_error = posix2fsal_error(retval);
			goto errout;
		}

		LogDebug(COMPONENT_FSAL,
			 "Found filesystem %s for handle for FSAL %s",
			 (*fs)->path,
			 (*fs)->fsal != NULL ? (*fs)->fsal->name : "(none)");
	} else {
		LogDebug(COMPONENT_FSAL,
			 "Could not map handle to fsid");
		fsal_error = ERR_FSAL_BADHANDLE;
		goto errout;
	}

 errout:
	return fsalstat(fsal_error, retval);
}
Exemple #27
0
fsal_status_t FSAL_setattrs(fsal_handle_t * filehandle, /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            fsal_attrib_list_t * attrib_set,    /* IN */
                            fsal_attrib_list_t * object_attributes      /* [ IN/OUT ] */
    )
{
  GHOSTFS_setattr_mask_t set_mask = 0;
  GHOSTFS_Attrs_t ghost_attrs;
  int rc;

  memset(&ghost_attrs, 0, sizeof(GHOSTFS_Attrs_t));

  /* For logging */
  SetFuncID(INDEX_FSAL_setattrs);

#define SETTABLE_ATTRIBUTES ( FSAL_ATTR_SIZE |\
                              FSAL_ATTR_MODE |\
                              FSAL_ATTR_OWNER |\
                              FSAL_ATTR_GROUP |\
                              FSAL_ATTR_ATIME |\
                              FSAL_ATTR_MTIME )
  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!filehandle || !p_context || !attrib_set)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);

  /* first convert attributes and mask */

  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_SIZE))
    {
      set_mask |= SETATTR_SIZE;
      ghost_attrs.size = attrib_set->filesize;
    }
  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_MODE))
    {
      set_mask |= SETATTR_MODE;
      ghost_attrs.mode = fsal2ghost_mode(attrib_set->mode);
    }

  /* ghostfs does not check chown restrictions,
   * so we check this for it. */

  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_OWNER))
    {

      if(p_context->credential.user != 0)
        Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);

      set_mask |= SETATTR_UID;
      ghost_attrs.uid = attrib_set->owner;
    }

  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_GROUP))
    {
      if(p_context->credential.user != 0)
        Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);

      set_mask |= SETATTR_GID;
      ghost_attrs.gid = attrib_set->group;
    }

  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_ATIME))
    {
      set_mask |= SETATTR_ATIME;
      ghost_attrs.atime = attrib_set->atime.seconds;
    }
  if(FSAL_TEST_MASK(attrib_set->asked_attributes, FSAL_ATTR_MTIME))
    {
      set_mask |= SETATTR_MTIME;
      ghost_attrs.mtime = attrib_set->mtime.seconds;
    }

  if(attrib_set->asked_attributes & ~SETTABLE_ATTRIBUTES)
    {
      LogFullDebug(COMPONENT_FSAL, "FSAL: To be set %llX, Settable %llX",
             (unsigned long long)object_attributes->asked_attributes,
             (unsigned long long)SETTABLE_ATTRIBUTES);

      Return(ERR_FSAL_ATTRNOTSUPP, 0, INDEX_FSAL_setattrs);
    }

  /* appel a setattr */
  rc = GHOSTFS_SetAttrs((GHOSTFS_handle_t) (*filehandle), set_mask, ghost_attrs);

  if(rc)
    Return(ghost2fsal_error(rc), rc, INDEX_FSAL_setattrs);

  if(object_attributes)
    {
      fsal_status_t status = FSAL_getattrs(filehandle, p_context, object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(object_attributes->asked_attributes);
          FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);

}
Exemple #28
0
/**
 * FSAL_open:
 * Open a regular file for reading/writing its data content.
 *
 * \param filehandle (input):
 *        Handle of the file to be read/modified.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param openflags (input):
 *        Flags that indicates behavior for file opening and access.
 *        This is an inclusive OR of the following values
 *        ( such of them are not compatible) : 
 *        - FSAL_O_RDONLY: opening file for reading only.
 *        - FSAL_O_RDWR: opening file for reading and writing.
 *        - FSAL_O_WRONLY: opening file for writting only.
 *        - FSAL_O_APPEND: always write at the end of the file.
 *        - FSAL_O_TRUNC: truncate the file to 0 on opening.
 * \param file_descriptor (output):
 *        The file descriptor to be used for FSAL_read/write operations.
 * \param file_attributes (optionnal input/output):
 *        Post operation attributes.
 *        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).
 *
 * \return Major error codes:
 *      - ERR_FSAL_NO_ERROR: no error.
 *      - Another error code if an error occured during this call.
 */
fsal_status_t POSIXFSAL_open(posixfsal_handle_t * p_filehandle, /* IN */
                             posixfsal_op_context_t * p_context,        /* IN */
                             fsal_openflags_t openflags,        /* IN */
                             posixfsal_file_t * p_file_descriptor,      /* OUT */
                             fsal_attrib_list_t * p_file_attributes     /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  fsal_status_t status;

  fsal_path_t fsalpath;
  struct stat buffstat;
#ifdef _FSAL_POSIX_USE_STREAM
  char posix_flags[4];          /* stores r, r+, w, w+, a, or a+ */
#else
  int posix_flags;
#endif

  /* sanity checks.
   * note : file_attributes is optional.
   */
  if(!p_filehandle || !p_context || !p_file_descriptor)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_open);

  status =
      fsal_internal_getPathFromHandle(p_context, p_filehandle, 0, &fsalpath, &buffstat);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_open);

  status =
      fsal_internal_testAccess(p_context,
                               (openflags & FSAL_O_RDONLY ? FSAL_R_OK : FSAL_W_OK) |
                               FSAL_OWNER_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_open);

  /* convert fsal open flags to posix open flags */
  rc = fsal2posix_openflags(openflags, &posix_flags);

  /* flags conflicts. */
  if(rc)
    {
      LogEvent(COMPONENT_FSAL, "Invalid/conflicting flags : %#X", openflags);
      Return(rc, 0, INDEX_FSAL_open);
    }

  TakeTokenFSCall();
#ifdef _FSAL_POSIX_USE_STREAM
  p_file_descriptor->p_file = fopen(fsalpath.path, posix_flags);
  errsv = errno;
  ReleaseTokenFSCall();

  if(!(p_file_descriptor->p_file))
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_open);
#else
  p_file_descriptor->filefd = open(fsalpath.path, posix_flags);
  errsv = errno;
  ReleaseTokenFSCall();
#endif

  /* set the read-only flag of the file descriptor */
  p_file_descriptor->ro = openflags & FSAL_O_RDONLY;

  /* output attributes */
  if(p_file_attributes)
    {

      status = posix2fsal_attributes(&buffstat, p_file_attributes);

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_file_attributes->asked_attributes);
          FSAL_SET_MASK(p_file_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }
    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_open);

}
Exemple #29
0
/**
 * FSAL_readlink:
 * Read the content of a symbolic link.
 *
 * \param linkhandle (input):
 *        Handle of the link to be read.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param p_link_content (output):
 *        Pointer to an fsal path structure where
 *        the link content is to be stored..
 * \param link_attributes (optionnal input/output): 
 *        The post operation attributes of the symlink link.
 *        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).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t LUSTREFSAL_readlink(fsal_handle_t * p_linkhandle,   /* IN */
                                  fsal_op_context_t * p_context,  /* IN */
                                  fsal_path_t * p_link_content, /* OUT */
                                  fsal_attrib_list_t * p_link_attributes        /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  fsal_status_t status;
  char link_content_out[FSAL_MAX_PATH_LEN];
  fsal_path_t fsalpath;

  /* sanity checks.
   * note : link_attributes is optional.
   */
  if(!p_linkhandle || !p_context || !p_link_content)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readlink);

  status = fsal_internal_Handle2FidPath(p_context, p_linkhandle, &fsalpath);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_readlink);

  memset(link_content_out, 0, FSAL_MAX_PATH_LEN);

  /* Read the link on the filesystem */

  TakeTokenFSCall();
  rc = readlink(fsalpath.path, link_content_out, FSAL_MAX_PATH_LEN);
  errsv = errno;
  ReleaseTokenFSCall();

  /* rc is the length for the symlink content or -1 on error !!! */
  if(rc < 0)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_readlink);

  /* convert char * to fsal_path_t */
  status = FSAL_str2path(link_content_out, FSAL_MAX_PATH_LEN, p_link_content);

  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_readlink);

  /* retrieves object attributes, if asked */

  if(p_link_attributes)
    {

      status = LUSTREFSAL_getattrs(p_linkhandle, p_context, p_link_attributes);

      /* On error, we set a flag in the returned attributes */

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_link_attributes->asked_attributes);
          FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readlink);

}
Exemple #30
0
/**
 * FSAL_readdir :
 *     Read the entries of an opened directory.
 *     
 * \param dir_descriptor (input):
 *        Pointer to the directory descriptor filled by FSAL_opendir.
 * \param start_position (input):
 *        Cookie that indicates the first object to be read during
 *        this readdir operation.
 *        This should be :
 *        - FSAL_READDIR_FROM_BEGINNING for reading the content
 *          of the directory from the beginning.
 *        - The end_position parameter returned by the previous
 *          call to FSAL_readdir.
 * \param get_attr_mask (input)
 *        Specify the set of attributes to be retrieved for directory entries.
 * \param buffersize (input)
 *        The size (in bytes) of the buffer where
 *        the direntries are to be stored.
 * \param pdirent (output)
 *        Adresse of the buffer where the direntries are to be stored.
 * \param end_position (output)
 *        Cookie that indicates the current position in the directory.
 * \param nb_entries (output)
 *        Pointer to the number of entries read during the call.
 * \param end_of_dir (output)
 *        Pointer to a boolean that indicates if the end of dir
 *        has been reached during the call.
 * 
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - ERR_FSAL_FAULT        (a NULL pointer was passed as mandatory argument) 
 *        - Other error codes can be returned :
 *          ERR_FSAL_IO, ...
 */
fsal_status_t SNMPFSAL_readdir(fsal_dir_t * dir_desc, /* IN */
                               fsal_cookie_t start_pos,        /* IN */
                               fsal_attrib_mask_t get_attr_mask,        /* IN */
                               fsal_mdsize_t buffersize,        /* IN */
                               fsal_dirent_t * pdirent, /* OUT */
                               fsal_cookie_t * end_pos,        /* OUT */
                               fsal_count_t * nb_entries,       /* OUT */
                               fsal_boolean_t * end_of_dir      /* OUT */
    )
{
  fsal_count_t max_dir_entries;
  fsal_count_t cur_nb_entries;
  fsal_boolean_t bool_eod;
  snmpfsal_cookie_t last_listed;

  fsal_request_desc_t req_opt;
  netsnmp_variable_list *p_curr_var;
  struct tree *cur_node;
  struct tree *nearest_node;
  int rc;
  snmpfsal_dir_t * dir_descriptor = (snmpfsal_dir_t *)dir_desc;
  snmpfsal_cookie_t start_position;
  snmpfsal_cookie_t * end_position = (snmpfsal_cookie_t *)end_pos;

  /* sanity checks */

  if(!dir_descriptor || !pdirent || !end_position || !nb_entries || !end_of_dir)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir);

  /* The readdir call is a sequence of GET/GETNEXT operations :
   * The first call, is a get on the hypothetic next brother
   * => if it exists, we add it to the dirents, and try to get the next child.
   * => if it doesnt exist, we make a getnext on it. 
   *    then, when a next branch is discovered, the next item to be tested 
   *    is the next hypothetic child.
   */

  /* initial cookie  */

  memcpy(&start_position.data, &start_pos.data, sizeof(snmpfsal_cookie_t));
  if(start_position.data.oid_len == 0)       /* readdir from begginning  */
    {
      FSAL_OID_DUP(&last_listed, dir_descriptor->node_handle.data.oid_tab,
                   dir_descriptor->node_handle.data.oid_len);
      /* first try to get .0 child */
      last_listed.data.oid_tab[last_listed.data.oid_len] = 0;
      last_listed.data.oid_len++;
    }
  else                          /* readdir from another entry */
    {
      FSAL_OID_DUP(&last_listed, start_position.data.oid_tab, start_position.data.oid_len);
    }

  /* calculate the requested dircount */

  max_dir_entries = (buffersize / sizeof(fsal_dirent_t));

  /* init counters and outputs */
  memset(pdirent, 0, buffersize);
  bool_eod = FALSE;
  cur_nb_entries = 0;

  if(max_dir_entries == 0)
    Return(ERR_FSAL_TOOSMALL, 0, INDEX_FSAL_readdir);

  while(!bool_eod && cur_nb_entries < max_dir_entries)
    {
      snmpfsal_handle_t *dir_entry = (snmpfsal_handle_t *) &pdirent[cur_nb_entries].handle;
      snmpfsal_cookie_t *dir_cookie = (snmpfsal_cookie_t *) &pdirent[cur_nb_entries].cookie;

      /* First, we proceed a GET request  */
      req_opt.request_type = SNMP_MSG_GET;

      TakeTokenFSCall();

      rc = IssueSNMPQuery(dir_descriptor->p_context, last_listed.data.oid_tab,
                          last_listed.data.oid_len, &req_opt);

      ReleaseTokenFSCall();

      if(rc != SNMP_ERR_NOERROR && snmp2fsal_error(rc) != ERR_FSAL_NOENT)
        {
          LogDebug(COMPONENT_FSAL,
                   "SNMP GET request failed: error=%d, snmp_errno=%d, errno=%d, msg=%s",
                   rc, snmp_errno, errno, snmp_api_errstring(rc));
          Return(snmp2fsal_error(rc), rc, INDEX_FSAL_readdir);
        }
      else if(snmp2fsal_error(rc) != ERR_FSAL_NOENT)
        {

          p_curr_var = GetNextResponse(dir_descriptor->p_context);

          /* Then test if the object exists  */
          if(p_curr_var != NULL
             && p_curr_var->type != SNMP_NOSUCHOBJECT
             && p_curr_var->type != SNMP_NOSUCHINSTANCE
             && p_curr_var->type != SNMP_ENDOFMIBVIEW)
            {
              FSAL_OID_DUP(dir_entry, p_curr_var->name,
                           p_curr_var->name_length);
              dir_entry->data.object_type_reminder = FSAL_NODETYPE_LEAF;

              /* object cookie is the hypothetic next object at the same level */
              FSAL_OID_DUP(dir_cookie, p_curr_var->name,
                           p_curr_var->name_length);
              FSAL_OID_INC(dir_cookie);

              cur_node =
                  GetMIBNode(dir_descriptor->p_context, dir_entry,
                             FALSE);

              /* build the label */
              rc = snmp_object2name(p_curr_var, cur_node, dir_entry,
                                    &pdirent[cur_nb_entries].name);

              if(rc)
                Return(rc, 0, INDEX_FSAL_readdir);

              /* when a node does not exist, we take its nearest parent's rights */
              if(cur_node == NULL)
                nearest_node =
                    GetMIBNode(dir_descriptor->p_context, dir_entry,
                               TRUE);
              else
                nearest_node = cur_node;

              if(isFullDebug(COMPONENT_FSAL))
                {
                  LogFullDebug(COMPONENT_FSAL,
                               "FOUND A DIRECT CHILD (LEAF) = %s, parent_oid_len=%zu, oid_len=%zu, index=%d",
                               pdirent[cur_nb_entries].name.name, dir_descriptor->node_handle.data.oid_len,
                               p_curr_var->name_length, p_curr_var->index);
                  if(nearest_node)
                    LogFullDebug(COMPONENT_FSAL, "type = %#X, last oid=%ld",
                                 nearest_node->type,
                                 p_curr_var->name[p_curr_var->name_length - 1]);
                }

              /* set entry attributes  */
              if(get_attr_mask)
                {
                  pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask;
                  rc = snmp2fsal_attributes(dir_entry, p_curr_var,
                                            nearest_node,
                                            &pdirent[cur_nb_entries].attributes);

                  if(rc != ERR_FSAL_NO_ERROR)
                    {
                      FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes.
                                      asked_attributes);
                      FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes,
                                    FSAL_ATTR_RDATTR_ERR);
                    }
                }

              /* link entries together */
              pdirent[cur_nb_entries].nextentry = NULL;
              if(cur_nb_entries > 0)
                pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries];

              /* copy hypothetic next entry to cookie and increment nb_entries  */
              FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab,
                           dir_cookie->data.oid_len);
              cur_nb_entries++;

              /* restart a sequence from GET request  */
              continue;
            }
        }

      /* the entry has not been found, we can look for the next child */

      req_opt.request_type = SNMP_MSG_GETNEXT;

      TakeTokenFSCall();

      rc = IssueSNMPQuery(dir_descriptor->p_context, last_listed.data.oid_tab,
                          last_listed.data.oid_len, &req_opt);

      ReleaseTokenFSCall();

      if(rc != SNMP_ERR_NOERROR && snmp2fsal_error(rc) != ERR_FSAL_NOENT)
        {
          LogDebug(COMPONENT_FSAL,
                   "SNMP GETNEXT request failed: error=%d, snmp_errno=%d, errno=%d, msg=%s",
                   rc, snmp_errno, errno, snmp_api_errstring(rc));
          Return(snmp2fsal_error(rc), rc, INDEX_FSAL_readdir);
        }
      else if(snmp2fsal_error(rc) == ERR_FSAL_NOENT)
        {
          bool_eod = TRUE;
          break;
        }

      p_curr_var = GetNextResponse(dir_descriptor->p_context);

      if(p_curr_var == NULL
         || p_curr_var->type == SNMP_NOSUCHOBJECT
         || p_curr_var->type == SNMP_NOSUCHINSTANCE
         || p_curr_var->type == SNMP_ENDOFMIBVIEW)
        {
          bool_eod = TRUE;
          break;
        }

      /* check if the response is under the root (else, end of dir is reached)  */
      if(IsSNMPChild
         (dir_descriptor->node_handle.data.oid_tab, dir_descriptor->node_handle.data.oid_len,
          p_curr_var->name, p_curr_var->name_length))
        {
          /* if the object is exactly 1 level under the dir, we insert it in the list */
          if(p_curr_var->name_length == dir_descriptor->node_handle.data.oid_len + 1)
            {
              FSAL_OID_DUP(dir_entry, p_curr_var->name,
                           p_curr_var->name_length);
              dir_entry->data.object_type_reminder = FSAL_NODETYPE_LEAF;

              /* object cookie is the hypothetic next object */
              FSAL_OID_DUP(dir_cookie, p_curr_var->name,
                           p_curr_var->name_length);
              FSAL_OID_INC(dir_cookie);

              cur_node =
                  GetMIBNode(dir_descriptor->p_context, dir_entry,
                             FALSE);

              /* build the label */
              rc = snmp_object2name(p_curr_var, cur_node, dir_entry,
                                    &pdirent[cur_nb_entries].name);

              if(rc)
                Return(rc, 0, INDEX_FSAL_readdir);

              /* when a node does not exist, we take its nearest parent's rights */
              if(cur_node == NULL)
                nearest_node =
                    GetMIBNode(dir_descriptor->p_context, dir_entry,
                               TRUE);
              else
                nearest_node = cur_node;

              if(isFullDebug(COMPONENT_FSAL))
                {
                  LogFullDebug(COMPONENT_FSAL,
                               "FOUND A DIRECT CHILD (LEAF) = %s, parent_oid_len=%zu, oid_len=%zu, index=%d",
                               pdirent[cur_nb_entries].name.name, dir_descriptor->node_handle.data.oid_len,
                               p_curr_var->name_length, p_curr_var->index);
                  if(nearest_node)
                    LogFullDebug(COMPONENT_FSAL, "type = %#X, last oid=%ld",
                                 nearest_node->type,
                                 p_curr_var->name[p_curr_var->name_length - 1]);
                }

              /* set entry attributes  */
              if(get_attr_mask)
                {
                  pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask;
                  rc = snmp2fsal_attributes(dir_entry, p_curr_var,
                                            nearest_node,
                                            &pdirent[cur_nb_entries].attributes);

                  if(rc != ERR_FSAL_NO_ERROR)
                    {
                      FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes.
                                      asked_attributes);
                      FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes,
                                    FSAL_ATTR_RDATTR_ERR);
                    }
                }

              /* link entries together */
              pdirent[cur_nb_entries].nextentry = NULL;
              if(cur_nb_entries > 0)
                pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries];

              /* copy hypothetic next entry to cookie and increment nb_entries  */
              FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab,
                           dir_cookie->data.oid_len);
              cur_nb_entries++;

              /* restart a sequence from GET request  */
              continue;
            }
          else                  /* directory item */
            {

              /* it the returned subdirectory is "smaller" than the cookie, we skip it
               * and incrment the cookie.
               */
              if(fsal_oid_cmp(p_curr_var->name, last_listed.data.oid_tab, last_listed.data.oid_len)
                 < 0)
                {
                  FSAL_OID_INC(&last_listed);
                  continue;
                }

              /* we found a new subsirectory */

              FSAL_OID_DUP(dir_entry, p_curr_var->name,
                           dir_descriptor->node_handle.data.oid_len + 1);
              dir_entry->data.object_type_reminder = FSAL_NODETYPE_NODE;

              /* object cookie is the next potentiel object at this level */
              FSAL_OID_DUP(dir_cookie,
                           dir_entry->data.oid_tab,
                           dir_entry->data.oid_len);
              FSAL_OID_INC(dir_cookie);

              /* try to get the associated MIB node  */
              cur_node =
                  GetMIBNode(dir_descriptor->p_context, dir_entry,
                             FALSE);

              /* build the label */
              rc = snmp_object2name(NULL, cur_node, dir_entry,
                                    &pdirent[cur_nb_entries].name);

              if(rc)
                Return(rc, 0, INDEX_FSAL_readdir);

              /* when a node does not exist, we take its nearest parent's rights */
              if(cur_node == NULL)
                nearest_node =
                    GetMIBNode(dir_descriptor->p_context, dir_entry,
                               TRUE);
              else
                nearest_node = cur_node;

              LogFullDebug(COMPONENT_FSAL, "FOUND A NEW SUBDIR = %s (%ld) (cookie->%ld)",
                           pdirent[cur_nb_entries].name.name,
                           dir_entry->data.oid_tab[dir_descriptor->node_handle.data.oid_len],
                           dir_cookie->data.oid_tab[dir_cookie->data.oid_len - 1]);

              /* set entry attributes  */
              if(get_attr_mask)
                {
                  pdirent[cur_nb_entries].attributes.asked_attributes = get_attr_mask;
                  rc = snmp2fsal_attributes(dir_entry, NULL,
                                            nearest_node,
                                            &pdirent[cur_nb_entries].attributes);

                  if(rc != ERR_FSAL_NO_ERROR)
                    {
                      FSAL_CLEAR_MASK(pdirent[cur_nb_entries].attributes.
                                      asked_attributes);
                      FSAL_SET_MASK(pdirent[cur_nb_entries].attributes.asked_attributes,
                                    FSAL_ATTR_RDATTR_ERR);
                    }
                }

              /* link entries together */
              pdirent[cur_nb_entries].nextentry = NULL;
              if(cur_nb_entries > 0)
                pdirent[cur_nb_entries - 1].nextentry = &pdirent[cur_nb_entries];

              /* copy last listed item to cookie and increment nb_entries  */
              FSAL_OID_DUP(&last_listed, dir_cookie->data.oid_tab,
                           dir_cookie->data.oid_len);
              cur_nb_entries++;

              /* end of subdir processing */

            }

        }
      else                      /* no more objects in the directory tree */
        {
          bool_eod = TRUE;
          break;
        }

      /* loop until the requested count is reached
       * or the end of dir is reached.
       */
    }

  /* setting output vars : end_position, nb_entries, end_of_dir  */
  *end_of_dir = bool_eod;

  memset(end_position, 0, sizeof(snmpfsal_cookie_t));
  FSAL_OID_DUP(end_position, last_listed.data.oid_tab, last_listed.data.oid_len);

  *nb_entries = cur_nb_entries;

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);

}