int ptfsal_closeHandle_attach_to_queues(void)
{
  int rc;

  /* Get IO and non-IO request, response message queue IDs */
  g_closeHandle_req_msgq = msgget(FSI_IPC_CLOSE_HANDLE_REQ_Q_KEY, 0);
  if (g_closeHandle_req_msgq < 0) {
    FSI_TRACE(FSI_FATAL, "error getting close handle Req Msg Q "
              "id %d (errno = %d)", FSI_IPC_CLOSE_HANDLE_REQ_Q_KEY, errno);
    /* cleanup the attach made earlier, nothing to clean up for the queues */
    if ((rc = shmdt(g_shm_at_fsal)) == -1) {
      FSI_TRACE(FSI_FATAL, "shmdt returned rc = %d errno = %d", rc, errno);
    }
    return -1;
  }

  g_closeHandle_rsp_msgq = msgget(FSI_IPC_CLOSE_HANDLE_RSP_Q_KEY, 0);
  if (g_closeHandle_rsp_msgq < 0) {
    FSI_TRACE(FSI_FATAL, "error getting close handle Rsp Msg Q "
              "id %d (errno = %d)", FSI_IPC_CLOSE_HANDLE_RSP_Q_KEY, errno);
    /* cleanup the attach made earlier, nothing to clean up for the queues */
    if ((rc = shmdt(g_shm_at_fsal)) == -1) {
      FSI_TRACE(FSI_FATAL, "shmdt returned rc = %d errno = %d", rc, errno);
    }
    return -1;
  }

  FSI_TRACE(FSI_NOTICE, "Successful attaching to Close Handle req/rsp queues");
  return 0;
}
void ptfsal_close_timedout_handle_bkg(void)
{
  /* This function will find out from out handle table
   * which handle has timed out and close it.  This is
   * used by background polling thread
   * ptfsal_polling_closeHandler_thread()
   */

  int index;
  time_t current_time = time(NULL);
  int close_rc;

  for (index = FSI_CIFS_RESERVED_STREAMS;
       index < g_fsi_handles_fsal->m_count;
       index++) {
    FSI_TRACE(FSI_DEBUG, "Flushing any pending IO for handle %d", index);
    struct msg_t msg;
    int          rc;
    GET_ANY_IO_RESPONSES(index, &rc, &msg);

    // only poll for timed out handles every PTFSAL_POLLING_HANDLE_TIMEOUT_SEC
    // iterations
    if (g_poll_for_timeouts) {
      FSI_TRACE(FSI_INFO, "Last IO time[%ld] handle index [%d]"
                "current_time[%ld] handle state[%d] m_hndl_in_use[%d]",
                g_fsi_handles_fsal->m_handle[index].m_last_io_time, index,
                current_time, g_fsi_handles_fsal->m_handle[index].m_nfs_state,
                g_fsi_handles_fsal->m_handle[index].m_hndl_in_use);

      if (CCL_CAN_CLOSE_HANDLE(index,
			       polling_thread_handle_timeout_sec)) {
        /* We've found timed out handle and we are sending an explicit
         * close to close it out.
         *
         * NOTE: we are putting a mutex around this close.  This mutex
         *       spans across the close_on_open logic and this polling
         *       for close logic.
         *
         *       We are putting a usleep() in the search loop so that we
         *       allow other close_on_open logic to come in
         */
        FSI_TRACE(FSI_NOTICE, "Found timed-out handle[%d]",index);
        close_rc = ptfsal_implicit_close_for_nfs(index, CCL_CLOSE_STYLE_NORMAL);
        if (close_rc == -1) {
          FSI_TRACE(FSI_ERR, "Failed to implicitly close handle[%d]",index);
        } 
        usleep(1000);
      }
    }
  }

  if (g_poll_for_timeouts) {
    g_poll_for_timeouts = false;
  }

  return;
}
int ptfsal_implicit_close_for_nfs(int handle_index_to_close, int close_style)
{
  int rc;
  rc = CCL_IMPLICIT_CLOSE_FOR_NFS(handle_index_to_close, close_style);
  FSI_TRACE(FSI_DEBUG, "Returned rc=%d", rc);
  return rc;
}
Exemple #4
0
/**
 * PTFSAL_getattrs_descriptor:
 * Get attributes for the object specified by its descriptor or by it's 
 * filehandle.
 *
 * \param p_file_descriptor (input):
 *        The file descriptor of the object to get parameters.
 * \param p_filehandle (input):
 *        The handle of the object to get parameters.
 * \param p_context (input):
 *        Authentication context for the operation (user,...).
 * \param p_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_descriptor(
  fsal_file_t        * p_file_descriptor,  /* IN */
  fsal_handle_t      * p_filehandle,       /* IN */
  fsal_op_context_t  * p_context,          /* IN */
  fsal_attrib_list_t * p_object_attributes /* IN/OUT */) 
{
  if (!p_file_descriptor) {
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs_descriptor);
  }
  ptfsal_file_t * p_file_desc = (ptfsal_file_t *)p_file_descriptor;
  FSI_TRACE(FSI_DEBUG, "FSI---File descriptor=%d\n", p_file_desc->fd);
  return PTFSAL_getattrs(p_filehandle, p_context, p_object_attributes);
}
void *ptfsal_closeHandle_listener_thread(void *args)
{
  int rc;
  struct msg_t msg;
  int msg_bytes;
  int close_rc;
  int i;
  struct CommonMsgHdr *msgHdr;
  int handleIdxFound;

  SetNameFunction("PT FSAL CloseOnOpen Handler");

  rc = ptfsal_closeHandle_attach_to_queues();
  if (rc == -1) {
    exit (1);
  }

  while (1) {
    msg_bytes = RCV_MSG_WAIT_BLOCK(g_closeHandle_req_msgq,
                                   &msg,
                                   sizeof(struct CommonMsgHdr),
                                   0);
    if (msg_bytes != -1) {
      close_rc = -1;
      FSI_TRACE(FSI_NOTICE, "Finding oldest handles");
      /* TBD: we need to address a design if we have more than one
              close thread or NFS4 support (that can issue close itself)
              in order to ensure proper locking to the handle table.
              Currently, one close thread model will work since we don't
              shuffle handle around and there is only one place to
              actually close the handle (which is here) in the code */

      handleIdxFound = CCL_FIND_OLDEST_HANDLE();
      if (handleIdxFound != -1) {
        close_rc = ptfsal_implicit_close_for_nfs(handleIdxFound,
                                                 CCL_CLOSE_STYLE_NORMAL);
      }
      /* Send the response back */
      msgHdr = (struct CommonMsgHdr *) &msg.mtext[0];
      msgHdr->transactionRc = close_rc;
      msg_bytes = SEND_MSG(g_closeHandle_rsp_msgq,
                           &msg,
                           sizeof(struct CommonMsgHdr));
    }
  }
}
void *ptfsal_polling_closeHandler_thread(void *args)
{
  SetNameFunction("PT FSAL Polling Close");
  
  g_poll_iterations   = 1;
  g_poll_for_timeouts = false;

  while (1) {
    FSI_TRACE(FSI_DEBUG, "Periodic check for opened handle to close");
    ptfsal_close_timedout_handle_bkg();
    sleep (PTFSAL_POLLING_THREAD_FREQUENCY_SEC);

    if ((g_poll_iterations * PTFSAL_POLLING_THREAD_FREQUENCY_SEC)
        % PTFSAL_POLLING_HANDLE_TIMEOUT_SEC == 0) {
      g_poll_for_timeouts = true;
      g_poll_iterations   = 1;
    } else {
      ++g_poll_iterations;
    }
  }
}
Exemple #7
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_hdl (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param p_context (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param p_object_handle (output):
 *        Pointer to the handle of the created file.
 * \param p_object_attributes (optional input/output):
 *        The attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occurred.
 */
fsal_status_t PTFSAL_create(struct fsal_obj_handle *dir_hdl,	/* IN */
			    const char *p_filename,	/* IN */
			    const struct req_op_context *p_context,	/* IN */
			    uint32_t accessmode,	/* IN */
			    ptfsal_handle_t *p_object_handle,	/* OUT */
			    struct attrlist *p_object_attributes)
{				/* IN/OUT */

	int errsv;
	fsal_status_t status;
	struct pt_fsal_obj_handle *pt_hdl;
	mode_t unix_mode;
	int open_rc;
	ptfsal_handle_t *p_fsi_handle = (ptfsal_handle_t *) p_object_handle;

	FSI_TRACE(FSI_DEBUG, "Begin to create file************************\n");

	/* sanity checks.
	 * note : object_attributes is optional.
	 */
	if (!dir_hdl || !p_context || !p_object_handle || !p_filename)
		return fsalstat(ERR_FSAL_FAULT, 0);

	pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle);

	/* convert fsal mode to unix mode. */
	unix_mode = fsal2unix_mode(accessmode);

	/* Apply umask */
	unix_mode = unix_mode & ~p_context->fsal_export->exp_ops.
			fs_umask(p_context->fsal_export);

	LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

	open_rc =
	    ptfsal_open(pt_hdl, p_filename, p_context, unix_mode,
			p_object_handle);
	if (open_rc < 0) {
		errsv = errno;
		return fsalstat(posix2fsal_error(errsv), errsv);
	}

	FSI_TRACE(FSI_DEBUG, "New Handle = %s",
		  (char *)p_fsi_handle->data.handle.f_handle);

	/* retrieve file attributes */
	if (p_object_attributes) {
		status = PTFSAL_getattrs(p_context->fsal_export, p_context,
					 p_object_handle,
					 p_object_attributes);

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

	}

	FSI_TRACE(FSI_DEBUG, "End to create file************************\n");

	/* OK */
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

}
Exemple #8
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param dir_hdl (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_context (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param p_object_handle (output):
 *        Pointer to the handle of the created directory.
 * \param p_object_attributes (optionnal input/output):
 *        The attributes of the created directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t PTFSAL_mkdir(struct fsal_obj_handle *dir_hdl,	/* IN */
			   const char *p_dirname,	/* IN */
			   const struct req_op_context *p_context,	/* IN */
			   uint32_t accessmode,	/* IN */
			   ptfsal_handle_t *p_object_handle,	/* OUT */
			   struct attrlist *p_object_attributes)
{				/* IN/OUT */

	int rc, errsv;
	int setgid_bit = 0;
	mode_t unix_mode;
	fsal_status_t status;
	struct attrlist parent_dir_attrs;
	char newPath[PATH_MAX];
	struct pt_fsal_obj_handle *pt_hdl;

	FSI_TRACE(FSI_INFO, "MKDIR BEGIN-------------------------\n");

	/* sanity checks.
	 * note : object_attributes is optional.
	 */
	if (!dir_hdl || !p_context || !p_object_handle || !p_dirname)
		return fsalstat(ERR_FSAL_FAULT, 0);

	pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle);

	/* convert FSAL mode to unix mode. */
	unix_mode = fsal2unix_mode(accessmode);

	/* Apply umask */
	unix_mode = unix_mode & ~p_context->fsal_export->exp_ops.
			fs_umask(p_context->fsal_export);

	/* get directory metadata */
	parent_dir_attrs.mask = p_context->fsal_export->exp_ops.
				fs_supported_attrs(p_context->fsal_export);
	status =
	    PTFSAL_getattrs(p_context->fsal_export, p_context, pt_hdl->handle,
			    &parent_dir_attrs);

	if (FSAL_IS_ERROR(status))
		return status;

	/* Check the user can write in the directory, and check the
	 * setgid bit on the directory
	 */

	if (fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID)
		setgid_bit = 1;

	rc = ptfsal_mkdir(pt_hdl, p_dirname, p_context, unix_mode,
			  p_object_handle);
	errsv = errno;
	if (rc)
		return fsalstat(posix2fsal_error(errsv), errsv);

	if (FSAL_IS_ERROR(status))
		return status;

	/* the directory has been created */
	/* chown the dir to the current user/group */

	if (p_context->creds->caller_uid != geteuid()) {
		FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__);
		/* if the setgid_bit was set on the parent directory, do not
		 * change the group of the created file, because it's already
		 * the parentdir's group
		 */

		if (fsi_get_name_from_handle
		    (p_context, p_context->fsal_export, pt_hdl->handle,
		     (char *)newPath, NULL) < 0) {
			FSI_TRACE(FSI_DEBUG,
				  "Failed to get name from handle %s",
				  (char *)p_object_handle->data.handle.
				  f_handle);
			return fsalstat(posix2fsal_error(errsv), errsv);
		}
		rc = ptfsal_chown(p_context, p_context->fsal_export, newPath,
				  p_context->creds->caller_uid,
				  setgid_bit ? -1 : (int)p_context->creds->
				  caller_gid);
		errsv = errno;
		if (rc)
			return fsalstat(posix2fsal_error(errsv), errsv);
	}

	/* retrieve file attributes */
	if (p_object_attributes) {
		FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__);
		status = PTFSAL_getattrs(p_context->fsal_export, p_context,
					 p_object_handle,
					 p_object_attributes);

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

	}
	FSI_TRACE(FSI_INFO, "MKDIR END ------------------\n");
	FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__);
	/* OK */
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

}
Exemple #9
0
fsal_status_t
posix2fsal_attributes(fsi_stat_struct    * p_buffstat,
		      fsal_attrib_list_t * p_fsalattr_out)
{

  fsal_attrib_mask_t supp_attr, unsupp_attr;

  /* sanity checks */
  if(!p_buffstat || !p_fsalattr_out)
    ReturnCode(ERR_FSAL_FAULT, 0);

  FSI_TRACE(FSI_DEBUG, "FSI - posix2fsal_attributes\n");

  /* check that asked attributes are supported */
  supp_attr = global_fs_info.supported_attrs;

  unsupp_attr = (p_fsalattr_out->asked_attributes) & (~supp_attr);
  if(unsupp_attr)
    {
      LogFullDebug(COMPONENT_FSAL, "Unsupported attributes: %#llX",
                        unsupp_attr);
      ReturnCode(ERR_FSAL_ATTRNOTSUPP, 0);
    }

  /* Initialize ACL regardless of whether ACL was asked or not.
   * This is needed to make sure ACL attribute is initialized. */
  p_fsalattr_out->acl = NULL;

  /* Fills the output struct */
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SUPPATTR))
    {
      p_fsalattr_out->supported_attributes = supp_attr;
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_TYPE))
    {
      p_fsalattr_out->type = posix2fsal_type(p_buffstat->st_mode);
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SIZE))
    {
      p_fsalattr_out->filesize = p_buffstat->st_size;
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_FSID))
    {
      p_fsalattr_out->fsid = posix2fsal_fsid(p_buffstat->st_dev);
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_ACL))
    {
      p_fsalattr_out->acl = NULL;
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_FILEID))
    {
      p_fsalattr_out->fileid = (fsal_u64_t) (p_buffstat->st_ino);
    }

  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_MODE))
    {
      p_fsalattr_out->mode = unix2fsal_mode(p_buffstat->st_mode);
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_NUMLINKS))
    {
      p_fsalattr_out->numlinks = p_buffstat->st_nlink;
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_OWNER))
    {
      p_fsalattr_out->owner = p_buffstat->st_uid;
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_GROUP))
    {
      p_fsalattr_out->group = p_buffstat->st_gid;
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_ATIME))
    {
      p_fsalattr_out->atime = posix2fsal_time(p_buffstat->st_atime_sec, 0);
    }

  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_CTIME))
    {
      p_fsalattr_out->ctime = posix2fsal_time(p_buffstat->st_ctime_sec, 0);
    }
  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_MTIME))
    {
      p_fsalattr_out->mtime = posix2fsal_time(p_buffstat->st_mtime_sec, 0);
    }

  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_CHGTIME))
    {
      p_fsalattr_out->chgtime
        = posix2fsal_time(MAX_2(
                            p_buffstat->st_mtime_sec, 
                            p_buffstat->st_ctime_sec), 0);
      p_fsalattr_out->change = (uint64_t) p_fsalattr_out->chgtime.seconds ;
    }

  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_SPACEUSED))
    {
      p_fsalattr_out->spaceused = p_buffstat->st_blocks * S_BLKSIZE;
    }

  if(FSAL_TEST_MASK(p_fsalattr_out->asked_attributes, FSAL_ATTR_RAWDEV))
    {
      p_fsalattr_out->rawdev = posix2fsal_devt(p_buffstat->st_rdev);  
    }

  /* everything has been copied ! */

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}
Exemple #10
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created file.
 * \param object_attributes (optional input/output):
 *        The attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occurred.
 */
fsal_status_t
PTFSAL_create(fsal_handle_t      * p_parent_directory_handle, /* IN */
              fsal_name_t        * p_filename,                /* IN */
              fsal_op_context_t  * p_context,                 /* IN */
              fsal_accessmode_t    accessmode,                /* IN */
              fsal_handle_t      * p_object_handle,           /* OUT */
              fsal_attrib_list_t * p_object_attributes        /* [ IN/OUT ] */)
{

  int errsv;
  int setgid_bit = 0;
  fsal_status_t status;

  mode_t unix_mode;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;
  int open_rc;
  ptfsal_handle_t * p_fsi_handle = (ptfsal_handle_t *)p_object_handle;

  FSI_TRACE(FSI_DEBUG, "Begin to create file************************\n");

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || 
     !p_filename) {
    FSI_TRACE(FSI_DEBUG, "BAD Happen!");
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);
  }

  /* convert fsal mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

  /* retrieve directory metadata */
  parent_dir_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES;
  status = PTFSAL_getattrs(p_parent_directory_handle, p_context, 
                           &parent_dir_attrs);
  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_create);
  }

  /* Check the user can write in the directory, and check the setgid bit 
   * on the directory 
   */

  if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) {
    setgid_bit = 1;
  }

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);

  if(!p_context->export_context->fe_static_fs_info->accesscheck_support) {
    status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                      &parent_dir_attrs);
  } else {
    status = fsal_internal_access(p_context, 
                                  p_parent_directory_handle, 
                                  access_mask,
                                  &parent_dir_attrs);
  }
  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_create);
  }

  // Create the file, return handle
  open_rc = ptfsal_open(p_parent_directory_handle, 
                        p_filename, p_context, unix_mode, p_object_handle);
  if (open_rc < 0) {
     errsv = errno;
     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
  }

  FSI_TRACE(FSI_DEBUG, "New Handle = %s", 
            (char *)p_fsi_handle->data.handle.f_handle);

  /* retrieve file attributes */
  if(p_object_attributes) {
    status = PTFSAL_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);
    }

  }

  FSI_TRACE(FSI_DEBUG, "End to create file************************\n");

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

}
Exemple #11
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_dirname (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created directory.
 * \param object_attributes (optionnal input/output):
 *        The attributes of the created directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t
PTFSAL_mkdir(fsal_handle_t      * p_parent_directory_handle, /* IN */
             fsal_name_t        * p_dirname,                 /* IN */
             fsal_op_context_t  * p_context,                 /* IN */
             fsal_accessmode_t    accessmode,                /* IN */
             fsal_handle_t      * p_object_handle,           /* OUT */
             fsal_attrib_list_t * p_object_attributes        /* [ IN/OUT ] */)
{

  int rc, errsv;
  int setgid_bit = 0;
  mode_t unix_mode;
  fsal_status_t status;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;
  char               newPath[PATH_MAX];

  FSI_TRACE(FSI_INFO,"MKDIR BEGIN-------------------------\n");

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || 
     !p_dirname) {
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir);
  }

  /* convert FSAL mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  /* get directory metadata */
  parent_dir_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES;
  status = PTFSAL_getattrs(p_parent_directory_handle, p_context, 
                           &parent_dir_attrs);
  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_create);
  }

  /* Check the user can write in the directory, and check the 
   * setgid bit on the directory 
   */

  if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) {
    setgid_bit = 1;
  }

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_SUBDIRECTORY);

  if(!p_context->export_context->fe_static_fs_info->accesscheck_support) {
    status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                      &parent_dir_attrs);
  } else {
    status = fsal_internal_access(p_context, p_parent_directory_handle, 
                                  access_mask,
                                  &parent_dir_attrs);
  }
  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_mkdir);
  }

  rc = ptfsal_mkdir(p_parent_directory_handle, p_dirname, 
                    p_context, unix_mode, p_object_handle);
  errsv = errno;
  if(rc) {
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
  }

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

  /* the directory has been created */
  /* chown the dir to the current user/group */

  if(p_context->credential.user != geteuid()) {
    FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__);
    /* if the setgid_bit was set on the parent directory, do not change 
     * the group of the created file, because it's already the parentdir's 
     * group       
     */

    if(fsi_get_name_from_handle(
       p_context, 
       (char *)p_object_handle->data.handle.f_handle, 
       (char *)newPath, NULL) < 0) {
       FSI_TRACE(FSI_DEBUG, "Failed to get name from handle %s", 
                 (char *)p_object_handle->data.handle.f_handle);
       Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
    }  
    rc = ptfsal_chown(p_context, newPath,
                      p_context->credential.user,
                      setgid_bit ? -1 : (int)p_context->credential.group);
    errsv = errno;
    if(rc) {
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
    }
  }

  /* retrieve file attributes */
  if(p_object_attributes) {
    FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__);
    status = PTFSAL_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);
    }

  }
  FSI_TRACE(FSI_INFO,"MKDIR END ------------------\n");
  FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__);
  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir);

}
Exemple #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 PTFSAL_lookup(const struct req_op_context *p_context,
			    struct fsal_obj_handle *parent,
			    const char *p_filename,
			    struct attrlist *p_object_attr,
			    ptfsal_handle_t *fh)
{
	fsal_status_t status;
	int parent_fd;
	struct attrlist *parent_dir_attrs;
	fsi_stat_struct buffstat;
	int rc;
	struct pt_fsal_obj_handle *parent_hdl;

	FSI_TRACE(FSI_DEBUG, "Begin##################################\n");
	if (p_filename != NULL)
		FSI_TRACE(FSI_DEBUG, "FSI - fsal_lookup file [%s]\n",
			  p_filename);

	if (parent != NULL)
		FSI_TRACE(FSI_DEBUG, "FSI - fsal_lookup parent dir\n");

	if (!parent || !p_filename)
		return fsalstat(ERR_FSAL_FAULT, 0);

	parent_hdl =
	    container_of(parent, struct pt_fsal_obj_handle, obj_handle);

	parent_dir_attrs = &parent_hdl->obj_handle.attributes;

	/* get directory metadata */
	parent_dir_attrs->mask = p_context->fsal_export->exp_ops.
			fs_supported_attrs(p_context->fsal_export);
	status =
	    fsal_internal_handle2fd_at(p_context, parent_hdl, &parent_fd,
				       O_RDONLY);

	if (FSAL_IS_ERROR(status))
		return status;

	FSI_TRACE(FSI_DEBUG, "FSI - lookup parent directory type = %d\n",
		  parent_dir_attrs->type);

	/* Be careful about junction crossing, symlinks, hardlinks,... */
	switch (parent_dir_attrs->type) {
	case DIRECTORY:
		/* OK */
		break;

	case REGULAR_FILE:
	case SYMBOLIC_LINK:
		/* not a directory */
		pt_close(parent);
		return fsalstat(ERR_FSAL_NOTDIR, 0);

	default:
		return fsalstat(ERR_FSAL_SERVERFAULT, 0);
	}

	/* get file handle, it it exists */
	/* This might be a race, but it's the best we can currently do */
	rc = ptfsal_stat_by_parent_name(p_context, parent_hdl, p_filename,
					&buffstat);
	if (rc < 0) {
		ptfsal_closedir_fd(p_context, p_context->fsal_export,
				   parent_fd);
		return fsalstat(ERR_FSAL_NOENT, errno);
	}
	memset(fh->data.handle.f_handle, 0, sizeof(fh->data.handle.f_handle));
	memcpy(&fh->data.handle.f_handle, &buffstat.st_persistentHandle.handle,
	       FSI_CCL_PERSISTENT_HANDLE_N_BYTES);
	fh->data.handle.handle_size = FSI_CCL_PERSISTENT_HANDLE_N_BYTES;
	fh->data.handle.handle_key_size = OPENHANDLE_KEY_LEN;
	fh->data.handle.handle_version = OPENHANDLE_VERSION;
	fh->data.handle.handle_type = posix2fsal_type(buffstat.st_mode);

	/* get object attributes */
	if (p_object_attr) {
		p_object_attr->mask = p_context->fsal_export->exp_ops.
				fs_supported_attrs(p_context->fsal_export);
		status = PTFSAL_getattrs(p_context->fsal_export, p_context,
					 fh, p_object_attr);
		if (FSAL_IS_ERROR(status)) {
			FSAL_CLEAR_MASK(p_object_attr->mask);
			FSAL_SET_MASK(p_object_attr->mask, ATTR_RDATTR_ERR);
		}
	}

	ptfsal_closedir_fd(p_context, p_context->fsal_export, parent_fd);

	FSI_TRACE(FSI_DEBUG, "End##################################\n");
	/* lookup complete ! */
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

}
Exemple #13
0
fsal_status_t pt_posix2fsal_attributes(struct stat *p_buffstat,
				    struct attrlist *p_fsalattr_out)
{

	FSI_TRACE(FSI_DEBUG, "FSI - posix2fsal_attributes\n");

	/* sanity checks */
	if (!p_buffstat || !p_fsalattr_out)
		return fsalstat(ERR_FSAL_FAULT, 0);

	/* Initialize ACL regardless of whether ACL was asked or not.
	 * This is needed to make sure ACL attribute is initialized. */
	p_fsalattr_out->acl = NULL;

	/* Fills the output struct

	   supported_attributes is set by the caller.

	   if(FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SUPPATTR))
	      p_fsalattr_out->supported_attributes = PT_SUPPORTED_ATTRIBUTES;
	 */
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_TYPE))
		p_fsalattr_out->type = posix2fsal_type(p_buffstat->st_mode);
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SIZE))
		p_fsalattr_out->filesize = p_buffstat->st_size;
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FSID))
		p_fsalattr_out->fsid = posix2fsal_fsid(p_buffstat->st_dev);
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ACL))
		p_fsalattr_out->acl = NULL;
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FILEID))
		p_fsalattr_out->fileid = (uint64_t) (p_buffstat->st_ino);
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MODE))
		p_fsalattr_out->mode = unix2fsal_mode(p_buffstat->st_mode);
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_NUMLINKS))
		p_fsalattr_out->numlinks = p_buffstat->st_nlink;
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_OWNER))
		p_fsalattr_out->owner = p_buffstat->st_uid;
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_GROUP))
		p_fsalattr_out->group = p_buffstat->st_gid;
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ATIME))
		p_fsalattr_out->atime =
		    posix2fsal_time(p_buffstat->st_atime, 0);
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CTIME))
		p_fsalattr_out->ctime =
		    posix2fsal_time(p_buffstat->st_ctime, 0);
	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MTIME))
		p_fsalattr_out->mtime =
		    posix2fsal_time(p_buffstat->st_mtime, 0);

	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CHGTIME)) {
		p_fsalattr_out->chgtime =
		    posix2fsal_time(MAX
				    (p_buffstat->st_mtime,
				     p_buffstat->st_ctime), 0);
		p_fsalattr_out->change =
		    (uint64_t) p_fsalattr_out->chgtime.tv_sec;
	}

	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SPACEUSED))
		p_fsalattr_out->spaceused = p_buffstat->st_blocks * S_BLKSIZE;

	if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_RAWDEV))
		p_fsalattr_out->rawdev = posix2fsal_devt(p_buffstat->st_rdev);

	/* everything has been copied ! */

	return fsalstat(ERR_FSAL_NO_ERROR, 0);
}
Exemple #14
0
/**
 * PTFSAL_getattrs:
 * Get attributes for the object specified by its filehandle.
 *
 * \param filehandle (input):
 *        The handle of the object to get parameters.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param object_attributes (mandatory input/output):
 *        The retrieved attributes for the object.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t
PTFSAL_getattrs(fsal_handle_t      * p_filehandle,        /* IN */
                fsal_op_context_t  * p_context,           /* IN */
                fsal_attrib_list_t * p_object_attributes  /* IN/OUT */)
{
  fsal_status_t   st;
  int             stat_rc;
  fsi_stat_struct buffstat;
  ptfsal_op_context_t     * fsi_op_context  = (ptfsal_op_context_t *)p_context;
  ptfsal_export_context_t * fsi_export_context = 
    fsi_op_context->export_context;

#ifdef _USE_NFS4_ACL
  fsal_accessflags_t access_mask = 0;
#endif

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

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

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

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

  /* convert attributes */

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

  p_object_attributes->mounted_on_fileid = 
    fsi_export_context->ganesha_export_id;

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

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

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

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

}
Exemple #15
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);

}
/**
 * FSAL_unlink:
 * Remove a filesystem object .
 *
 * \param dir_hdl (input):
 *        Handle of the parent directory of the object to be deleted.
 * \param p_object_name (input):
 *        Name of the object to be removed.
 * \param p_context (input):
 *        Authentication context for the operation (user,...).
 * \param p_parentdir_attributes (optionnal input/output):
 *        Post operation attributes of the parent directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t PTFSAL_unlink(struct fsal_obj_handle *dir_hdl,	/* IN */
			    const char *p_object_name,	/* IN */
			    const struct req_op_context *p_context,	/* IN */
			    struct attrlist *p_parent_attributes)
{				/* IN/OUT */

	fsal_status_t status;
	int rc, errsv;
	fsi_stat_struct buffstat;
	struct pt_fsal_obj_handle *pt_hdl;

	/* sanity checks. */
	if (!dir_hdl || !p_context || !p_object_name)
		return fsalstat(ERR_FSAL_FAULT, 0);

	pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle);

	FSI_TRACE(FSI_DEBUG, "FSI - PTFSAL_unlink [%s] entry\n", p_object_name);

	/* build the child path */

	FSI_TRACE(FSI_DEBUG, "FSI - PTFSAL_unlink [%s] build child path\n",
		  p_object_name);

	/* get file metadata */
	rc = ptfsal_stat_by_parent_name(p_context, pt_hdl, p_object_name,
					&buffstat);
	if (rc) {
		FSI_TRACE(FSI_DEBUG, "FSI - PTFSAL_unlink stat [%s] rc %d\n",
			  p_object_name, rc);
		return fsalstat(posix2fsal_error(errno), errno);
	}

  /******************************
   * DELETE FROM THE FILESYSTEM *
   ******************************/

	/* If the object to delete is a directory, use 'rmdir' to delete
	 * the object else use 'unlink'
	 */
	if (S_ISDIR(buffstat.st_mode)) {
		FSI_TRACE(FSI_DEBUG, "Deleting directory %s", p_object_name);
		rc = ptfsal_rmdir(p_context, pt_hdl, p_object_name);

	} else {
		FSI_TRACE(FSI_DEBUG, "Deleting file %s", p_object_name);
		rc = ptfsal_unlink(p_context, pt_hdl, p_object_name);
	}
	if (rc) {
		errsv = errno;
		return fsalstat(posix2fsal_error(errsv), errsv);
	}

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

	if (p_parent_attributes) {
		status = PTFSAL_getattrs(p_context->fsal_export, p_context,
					pt_hdl->handle, p_parent_attributes);
		if (FSAL_IS_ERROR(status)) {
			FSAL_CLEAR_MASK(p_parent_attributes->mask);
			FSAL_SET_MASK(p_parent_attributes->mask,
				      ATTR_RDATTR_ERR);
		}
	}
	/* OK */
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

}