Exemplo n.º 1
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);

}
Exemplo n.º 2
0
fsal_status_t XFSFSAL_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 */
    )
{
  xfsfsal_dir_t * p_dir_descriptor = (xfsfsal_dir_t * ) dir_descriptor;
  xfsfsal_cookie_t start_position;
  xfsfsal_cookie_t * p_end_position = (xfsfsal_cookie_t *) end_position;
  fsal_status_t st;
  fsal_count_t max_dir_entries;
  char buff[BUF_SIZE];
  struct linux_dirent *dp = NULL;
  int bpos = 0;
  int tmpfd = 0;

  char d_type;
  struct stat buffstat;

  int errsv = 0, rc = 0;

  memset(buff, 0, BUF_SIZE);

  /*****************/
  /* 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;
  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.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 = 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);
                                                    /** @todo not used for the moment. Waiting for information on symlink management */
          bpos += dp->d_reclen;

          /* LogFullDebug(COMPONENT_FSAL, "\tino=%8ld|%8lx off=%d|%x reclen=%d|%x name=%s|%d", dp->d_ino, dp->d_ino, (int)dp->d_off, (int)dp->d_off, 
             dp->d_reclen, dp->d_reclen, dp->d_name, (int)dp->d_name[0]  ) ; */

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

          d_type = DT_UNKNOWN;
          if((tmpfd =
              openat(p_dir_descriptor->fd, dp->d_name, O_RDONLY | O_NOFOLLOW, 0600)) < 0)
            {
              if(errno != ELOOP)        /* ( p_dir_descriptor->fd, dp->d_name) is not a symlink */
                Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_readdir);
              else
                d_type = DT_LNK;
            }

          /* get object handle */
          TakeTokenFSCall();
          if(d_type != DT_LNK)
            {
              st = fsal_internal_fd2handle((fsal_op_context_t *)&(p_dir_descriptor->context),
					   tmpfd, &(p_pdirent[*p_nb_entries].handle));
              close(tmpfd);
            }
          else
            {
              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_inum2handle(&p_dir_descriptor->context,
                                             buffstat.st_ino, &(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();

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

    /************************
     * Fills the attributes *
     ************************/
          if(d_type != DT_LNK)
            {
              p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask;

              st = XFSFSAL_getattrs((xfsfsal_handle_t
                                     *) (&(p_pdirent[*p_nb_entries].handle)),
                                    (xfsfsal_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);
                }
            }
          //p_pdirent[*p_nb_entries].cookie.cookie = dp->d_off;
          ((xfsfsal_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(xfsfsal_cookie_t));

          (*p_nb_entries)++;

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

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir);

}
Exemplo n.º 3
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);

}
Exemplo n.º 4
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);
}
Exemplo n.º 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_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);

}
Exemplo n.º 6
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);

}
Exemplo n.º 7
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);

}
Exemplo n.º 8
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);

}
Exemplo n.º 9
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);

}
Exemplo n.º 10
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);

}
Exemplo n.º 11
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);

}
Exemplo n.º 12
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);

}
Exemplo n.º 13
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 XFSFSAL_open(xfsfsal_handle_t * p_filehandle,     /* IN */
                           xfsfsal_op_context_t * p_context,    /* IN */
                           fsal_openflags_t openflags,  /* IN */
                           xfsfsal_file_t * p_file_descriptor,  /* OUT */
                           fsal_attrib_list_t * p_file_attributes       /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  fsal_status_t status;

  int fd = 0 ;
  struct stat buffstat;
  int posix_flags = 0;

  /* sanity checks.
   * note : file_attributes is optional.
   */
  if(!p_filehandle || !p_context || !p_file_descriptor)
    Return(ERR_FSAL_FAULT, 0, 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();
  status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, posix_flags);
  ReleaseTokenFSCall();

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

  /* retrieve file attributes for checking access rights */

  TakeTokenFSCall();
  rc = fstat(fd, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc)
    {
      close(fd);

      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_open);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_open);
    }

#if 0
  /* No required, the open would have failed if not permitted */
  status =
      fsal_internal_testAccess(p_context,
                               openflags & FSAL_O_RDONLY ? FSAL_R_OK : FSAL_W_OK,
                               &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_open);
    }
#endif

  TakeTokenFSCall();
  p_file_descriptor->fd = fd;
  errsv = errno;
  ReleaseTokenFSCall();

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

}