Beispiel #1
0
/**
 * FSAL_access :
 * Tests whether the user or entity identified by its cred
 * can access the object identified by object_handle,
 * as indicated by the access_type parameters.
 *
 * \param object_handle (input):
 *        The handle of the object to test permissions on.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param access_type (input):
 *        Indicates the permissions to test.
 *        This is an inclusive OR of the permissions
 *        to be checked for the user identified by cred.
 *        Permissions constants are :
 *        - FSAL_R_OK : test for read permission
 *        - FSAL_W_OK : test for write permission
 *        - FSAL_X_OK : test for exec permission
 *        - FSAL_F_OK : test for file existence
 * \param object_attributes (optional 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_access(fsal_handle_t * p_object_handle,  /* IN */
                                fsal_op_context_t * p_context,    /* IN */
                                fsal_accessflags_t access_type, /* IN */
                                fsal_attrib_list_t * p_object_attributes        /* [ IN/OUT ] */
    )
{

  fsal_status_t status;

  /* sanity checks.
   * note : object_attributes is optionnal in FSAL_getattrs.
   */
  if(!p_object_handle || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_access);

  /* 
   * If an error occures during getattr operation,
   * it is returned, even though the access operation succeeded.
   */

  if(p_object_attributes)
    {

      FSAL_SET_MASK(p_object_attributes->asked_attributes,
                    FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ACL | FSAL_ATTR_MODE);
      status = LUSTREFSAL_getattrs(p_object_handle, 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(status.major, status.minor, INDEX_FSAL_access);
        }

      status =
          fsal_internal_testAccess(p_context, access_type, NULL, p_object_attributes);

    }
  else
    {                           /* p_object_attributes is NULL */
      fsal_attrib_list_t attrs;

      FSAL_CLEAR_MASK(attrs.asked_attributes);
      FSAL_SET_MASK(attrs.asked_attributes,
                    FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ACL | FSAL_ATTR_MODE);

      status = LUSTREFSAL_getattrs(p_object_handle, p_context, &attrs);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        Return(status.major, status.minor, INDEX_FSAL_access);

      status = fsal_internal_testAccess(p_context, access_type, NULL, &attrs);
    }

  Return(status.major, status.minor, INDEX_FSAL_access);

}
Beispiel #2
0
fsal_status_t WRAP_LUSTREFSAL_getattrs(fsal_handle_t * p_filehandle,    /* IN */
                                       fsal_op_context_t * p_context,   /* IN */
                                       fsal_attrib_list_t *
                                       p_object_attributes /* IN/OUT */ )
{
    return LUSTREFSAL_getattrs((lustrefsal_handle_t *) p_filehandle,
                               (lustrefsal_op_context_t *) p_context, p_object_attributes);
}
Beispiel #3
0
fsal_status_t LUSTREFSAL_lookupPath(fsal_path_t * p_path,       /* IN */
                                    fsal_op_context_t * p_context,        /* IN */
                                    fsal_handle_t * object_handle,        /* OUT */
                                    fsal_attrib_list_t * p_object_attributes    /* [ IN/OUT ] */
    )
{
  fsal_status_t status;

  /* sanity checks
   * note : object_attributes is optionnal.
   */

  if(!object_handle || !p_context || !p_path)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookupPath);

  /* test whether the path begins with a slash */

  if(p_path->path[0] != '/')
    Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_lookupPath);

  /* directly call the lookup function */

  status = fsal_internal_Path2Handle(p_context, p_path, object_handle);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_lookupPath);

  /* get object attributes */
  if(p_object_attributes)
    {
      status = LUSTREFSAL_getattrs(object_handle, p_context, p_object_attributes);
      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_lookupPath);

}
Beispiel #4
0
fsal_status_t LUSTREFSAL_unlink(fsal_handle_t * p_parent_directory_handle,        /* IN */
                                fsal_name_t * p_object_name,    /* IN */
                                fsal_op_context_t * p_context,    /* IN */
                                fsal_attrib_list_t * p_parent_directory_attributes      /* [IN/OUT ] */
    )
{

  fsal_status_t status;
  int rc, errsv;
  struct stat buffstat, buffstat_parent;
  fsal_path_t fsalpath;

  /* sanity checks. */
  if(!p_parent_directory_handle || !p_context || !p_object_name)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink);

  /* build the FID path */
  status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &fsalpath);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_unlink);

  /* get directory metadata */
  TakeTokenFSCall();
  rc = lstat(fsalpath.path, &buffstat_parent);
  errsv = errno;
  ReleaseTokenFSCall();
  if(rc)
    {
      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_unlink);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink);
    }

  /* build the child path */
  status = fsal_internal_appendNameToPath(&fsalpath, p_object_name);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_unlink);

  /* get file metadata */
  TakeTokenFSCall();
  rc = lstat(fsalpath.path, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();
  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink);

  /* check access rights */

  /* Sticky bit on the directory => the user who wants to delete the file must own it or its parent dir */
  if((buffstat_parent.st_mode & S_ISVTX)
     && buffstat_parent.st_uid != p_context->credential.user
     && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0)
    {
      Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_unlink);
    }

  /* client must be able to lookup the parent directory and modify it */
  status =
      fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_parent, NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_unlink);

  /******************************
   * DELETE FROM THE FILESYSTEM *
   ******************************/
  TakeTokenFSCall();
  /* If the object to delete is a directory, use 'rmdir' to delete the object, else use 'unlink' */
  rc = (S_ISDIR(buffstat.st_mode)) ? rmdir(fsalpath.path) : unlink(fsalpath.path);
  errsv = errno;
  ReleaseTokenFSCall();
  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink);

  /***********************
   * FILL THE ATTRIBUTES *
   ***********************/

  if(p_parent_directory_attributes)
    {
      status =
          LUSTREFSAL_getattrs(p_parent_directory_handle, p_context,
                              p_parent_directory_attributes);
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_parent_directory_attributes->asked_attributes);
          FSAL_SET_MASK(p_parent_directory_attributes->asked_attributes,
                        FSAL_ATTR_RDATTR_ERR);
        }
    }
  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_unlink);

}
Beispiel #5
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_op_context_t * p_context,       /* 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));
  memcpy( (char *)& start_position.data.cookie, (char *)&start_pos.data, sizeof( off_t ) ) ;

  /***************************/
  /* 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);

}
Beispiel #6
0
fsal_status_t LUSTREFSAL_rename(lustrefsal_handle_t * p_old_parentdir_handle,   /* IN */
                                fsal_name_t * p_old_name,       /* IN */
                                lustrefsal_handle_t * p_new_parentdir_handle,   /* IN */
                                fsal_name_t * p_new_name,       /* IN */
                                lustrefsal_op_context_t * p_context,    /* IN */
                                fsal_attrib_list_t * p_src_dir_attributes,      /* [ IN/OUT ] */
                                fsal_attrib_list_t * p_tgt_dir_attributes       /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  fsal_status_t status;
  struct stat old_parent_buffstat, new_parent_buffstat, buffstat;
  fsal_path_t old_fsalpath, new_fsalpath;
  int src_equal_tgt = FALSE;

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

  /* Get directory access path by fid */

  status = fsal_internal_Handle2FidPath(p_context, p_old_parentdir_handle, &old_fsalpath);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_rename);

  /* retrieve directory metadata for checking access rights */

  TakeTokenFSCall();
  rc = lstat(old_fsalpath.path, &old_parent_buffstat);
  errsv = errno;
  ReleaseTokenFSCall();

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

  /* optimisation : don't do the job twice if source dir = dest dir  */
  if(!LUSTREFSAL_handlecmp(p_old_parentdir_handle, p_new_parentdir_handle, &status))
    {
      FSAL_pathcpy(&new_fsalpath, &old_fsalpath);
      src_equal_tgt = TRUE;
      new_parent_buffstat = old_parent_buffstat;
    }
  else
    {
      status =
          fsal_internal_Handle2FidPath(p_context, p_new_parentdir_handle, &new_fsalpath);
      if(FSAL_IS_ERROR(status))
        ReturnStatus(status, INDEX_FSAL_rename);

      /* retrieve destination attrs */
      TakeTokenFSCall();
      rc = lstat(new_fsalpath.path, &new_parent_buffstat);
      errsv = errno;
      ReleaseTokenFSCall();

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

    }

  /* check access rights */

  status =
      fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &old_parent_buffstat,
                               NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_rename);

  if(!src_equal_tgt)
    {
      status =
          fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &new_parent_buffstat,
                                   NULL);
      if(FSAL_IS_ERROR(status))
        ReturnStatus(status, INDEX_FSAL_rename);
    }

  /* build file paths */

  status = fsal_internal_appendNameToPath(&old_fsalpath, p_old_name);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_rename);
  status = fsal_internal_appendNameToPath(&new_fsalpath, p_new_name);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_rename);

  TakeTokenFSCall();
  rc = lstat(old_fsalpath.path, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();
  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename);

  /* Check sticky bits */

  /* Sticky bit on the source directory => the user who wants to delete the file must own it or its parent dir */
  if((old_parent_buffstat.st_mode & S_ISVTX)
     && old_parent_buffstat.st_uid != p_context->credential.user
     && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0)
    Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename);

  /* Sticky bit on the target directory => the user who wants to create the file must own it or its parent dir */
  if(new_parent_buffstat.st_mode & S_ISVTX)
    {
      TakeTokenFSCall();
      rc = lstat(new_fsalpath.path, &buffstat);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        {
          if(errsv != ENOENT)
            Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename);
        }
      else if(new_parent_buffstat.st_uid != p_context->credential.user
              && buffstat.st_uid != p_context->credential.user
              && p_context->credential.user != 0)
        Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename);
    }

  /*************************************
   * Rename the file on the filesystem *
   *************************************/
  TakeTokenFSCall();
  rc = rename(old_fsalpath.path, new_fsalpath.path);
  errsv = errno;
  ReleaseTokenFSCall();

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

  /***********************
   * Fill the attributes *
   ***********************/

  if(p_src_dir_attributes)
    {

      status =
          LUSTREFSAL_getattrs(p_old_parentdir_handle, p_context, p_src_dir_attributes);

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

    }

  if(p_tgt_dir_attributes)
    {

      status =
          LUSTREFSAL_getattrs(p_new_parentdir_handle, p_context, p_tgt_dir_attributes);

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

    }

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

}
fsal_status_t LUSTREFSAL_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;
  fsal_path_t fsalpath;
  fsal_status_t st;
  int no_trunc = 0;

  /* 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 */
  st = fsal_internal_Handle2FidPath(p_context, p_filehandle, &fsalpath);
  if(FSAL_IS_ERROR(st))
    ReturnStatus(st, INDEX_FSAL_truncate);

#ifdef _SHOOK
    /* If the file is not online:
     * - if truncate(0) => call tuncate(0), then "shook restore_trunc"
     * - if truncate(>0) => call "shook restore", then truncate
     */
    shook_state state;
    rc = shook_get_status(fsalpath.path, &state, FALSE);
    if (rc)
    {
        LogEvent(COMPONENT_FSAL, "Error retrieving shook status of %s: %s",
                 fsalpath.path, strerror(-rc));
        if (rc)
            Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate);
    }
    else if (state != SS_ONLINE)
    {
        if (length == 0)
        {
            LogInfo(COMPONENT_FSAL, "File is offline: calling shook restore_trunc");

            /* first truncate the file, them call the shook_svr to clear
             * the 'released' flag */

            TakeTokenFSCall();
            rc = truncate(fsalpath.path, 0);
            errsv = errno;
            ReleaseTokenFSCall();

            if (rc == 0)
            {
                /* use a short timeout of 2s */
                rc = shook_server_call(SA_RESTORE_TRUNC, ((lustrefsal_op_context_t *)p_context)->export_context->fsname,
                                       &((lustrefsal_handle_t *)p_filehandle)->data.fid, 2);
                if (rc)
                    Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate);
                else {
                    /* check that file is online, else operation is still
                     * in progress: return err jukebox */
                    rc = shook_get_status(fsalpath.path, &state, FALSE);
                    if (rc)
                    {
                        LogEvent(COMPONENT_FSAL, "Error retrieving shook status of %s: %s",
                                 fsalpath.path, strerror(-rc));
                        if (rc)
                            Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate);
                    }
                    else if (state != SS_ONLINE)
                        Return(ERR_FSAL_DELAY, -rc, INDEX_FSAL_truncate);
                    /* OK */
                }
                /* file is already truncated, no need to truncate again */
                no_trunc = 1;
            }
            else
            {
                  if(errsv == ENOENT)
                    Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_truncate);
                  else
                    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_truncate);
            }
        }
        else /* length > 0 */
        {
            /* trigger restore. Give it a chance to retrieve the file in less than a second.
             * Else, it returns ETIME that is converted in ERR_DELAY */
            rc = shook_server_call(SA_RESTORE, ((lustrefsal_op_context_t *)p_context)->export_context->fsname,
                                   &((lustrefsal_handle_t *)p_filehandle)->data.fid, 1);
            if (rc)
                Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate);
            else {
                /* check that file is online, else operation is still
                 * in progress: return err jukebox */
                rc = shook_get_status(fsalpath.path, &state, FALSE);
                if (rc)
                {
                    LogEvent(COMPONENT_FSAL, "Error retrieving shook status of %s: %s",
                             fsalpath.path, strerror(-rc));
                    if (rc)
                        Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate);
                }
                else if (state != SS_ONLINE)
                    Return(ERR_FSAL_DELAY, -rc, INDEX_FSAL_truncate);
                /* OK */
            }

            /* if rc = 0, file can be opened */
        }
    }
    /* else file is on line */
#endif

  /* Executes the POSIX truncate operation */

  if (!no_trunc)
  {
    TakeTokenFSCall();
    rc = truncate(fsalpath.path, length);
    errsv = errno;
    ReleaseTokenFSCall();
  }

  /* 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 = LUSTREFSAL_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);

}
Beispiel #8
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);

}
Beispiel #9
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);
}
Beispiel #10
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);

}
Beispiel #11
0
/**
 * FSAL_lookup :
 * Looks up for an object into a directory.
 *
 * Note : if parent handle and filename are NULL,
 *        this retrieves root's handle.
 *
 * \param parent_directory_handle (input)
 *        Handle of the parent directory to search the object in.
 * \param filename (input)
 *        The name of the object to find.
 * \param p_context (input)
 *        Authentication context for the operation (user,...).
 * \param object_handle (output)
 *        The handle of the object corresponding to filename.
 * \param object_attributes (optional input/output)
 *        Pointer to the attributes of the object we found.
 *        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).
 *        It can be NULL (increases performances).
 *
 * \return - ERR_FSAL_NO_ERROR, if no error.
 *         - Another error code else.
 *          
 */
fsal_status_t LUSTREFSAL_lookup(fsal_handle_t * p_parent_directory_handle,        /* IN */
                                fsal_name_t * p_filename,       /* IN */
                                fsal_op_context_t * p_context,    /* IN */
                                fsal_handle_t * p_object_handle,  /* OUT */
                                fsal_attrib_list_t * p_object_attributes        /* [ IN/OUT ] */
    )
{
  int rc, errsv;
  fsal_status_t status;
  struct stat buffstat;
  fsal_path_t pathfsal;

  /* sanity checks
   * note : object_attributes is optionnal
   *        parent_directory_handle may be null for getting FS root.
   */
  if(!p_object_handle || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup);

  /* filename AND parent handle are NULL => lookup "/" */
  if((p_parent_directory_handle && !p_filename)
     || (!p_parent_directory_handle && p_filename))
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup);

  /* get information about root */
  if(!p_parent_directory_handle)
    {
      /* get handle for the mount point  */
      FSAL_str2path(((lustrefsal_op_context_t *)p_context)->export_context->mount_point,
                    ((lustrefsal_op_context_t *)p_context)->export_context->mnt_len, &pathfsal);
      TakeTokenFSCall();
      status = fsal_internal_Path2Handle(p_context, &pathfsal, p_object_handle);
      ReleaseTokenFSCall();

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

      /* get attributes, if asked */
      if(p_object_attributes)
        {
          status = LUSTREFSAL_getattrs(p_object_handle, p_context, p_object_attributes);
          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);
            }
        }
      /* Done */
      Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup);
    }

  /* retrieve directory attributes */

  status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &pathfsal);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_lookup);

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

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

  /* Be careful about junction crossing, symlinks, hardlinks,... */
  switch (posix2fsal_type(buffstat.st_mode))
    {
    case FSAL_TYPE_DIR:
      // OK
      break;

    case FSAL_TYPE_JUNCTION:
      // This is a junction
      Return(ERR_FSAL_XDEV, 0, INDEX_FSAL_lookup);

    case FSAL_TYPE_FILE:
    case FSAL_TYPE_LNK:
    case FSAL_TYPE_XATTR:
      // not a directory 
      Return(ERR_FSAL_NOTDIR, 0, INDEX_FSAL_lookup);

    default:
      Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_lookup);
    }

  LogFullDebug(COMPONENT_FSAL, "lookup of %s/%s\n",
          pathfsal.path, p_filename->name);

  /* check rights to enter into the directory */
  status = fsal_internal_testAccess(p_context, FSAL_X_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_lookup);

  status = fsal_internal_appendNameToPath(&pathfsal, p_filename);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_lookup);

  /* get file handle, it it exists */
  TakeTokenFSCall();
  status = fsal_internal_Path2Handle(p_context, &pathfsal, p_object_handle);
  ReleaseTokenFSCall();
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_lookup);

  /* get object attributes */
  if(p_object_attributes)
    {
      status = LUSTREFSAL_getattrs(p_object_handle, p_context, p_object_attributes);
      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);
        }
    }

  /* lookup complete ! */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup);

}