// SPDX-License-Identifier: LGPL-3.0-or-later
/*
 * Copyright IBM Corporation, 2012
 *  Contributor: Frank Filz <ffilz@us.ibm.com>
 *
 * --------------------------
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 *
 *
 */

#include "config.h"
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include "log.h"
#include "fsal.h"
#include "nfs_proto_functions.h"
#include "nfs_file_handle.h"
#include "sal_functions.h"
#include "nlm_util.h"
#include "nlm_async.h"

/**
 * @brief Set a share reservation
 *
 * @param[in]  args
 * @param[in]  req
 * @param[out] res
 *
 */

int nlm4_Unshare(nfs_arg_t *args, struct svc_req *req, nfs_res_t *res)
{
	nlm4_shareargs *arg = &args->arg_nlm4_share;
	struct fsal_obj_handle *obj;
	state_status_t state_status = STATE_SUCCESS;
	char buffer[MAXNETOBJ_SZ * 2] = "\0";
	state_nsm_client_t *nsm_client;
	state_nlm_client_t *nlm_client;
	state_owner_t *nlm_owner;
	state_t *nlm_state;
	int rc;

	if (nfs_param.core_param.disable_NLM_SHARE) {
		res->res_nlm4share.stat = NLM4_FAILED;
		LogEvent(COMPONENT_NLM,
			 "NLM4_UNSHARE call detected, failing it");
		return NFS_REQ_OK;
	}

	/* NLM doesn't have a BADHANDLE error, nor can rpc_execute deal with
	 * responding to an NLM_*_MSG call, so we check here if the export is
	 * NULL and if so, handle the response.
	 */
	if (op_ctx->ctx_export == NULL) {
		res->res_nlm4share.stat = NLM4_STALE_FH;
		LogInfo(COMPONENT_NLM, "INVALID HANDLE: NLM4_UNSHARE");
		return NFS_REQ_OK;
	}

	res->res_nlm4share.sequence = 0;

	netobj_to_string(&arg->cookie, buffer, 1024);

	if (isDebug(COMPONENT_NLM)) {
		char str[LEN_FH_STR];
		struct display_buffer dspbuf = { sizeof(str), str, str };
		char oh[MAXNETOBJ_SZ * 2] = "\0";

		display_opaque_bytes(&dspbuf, arg->share.fh.n_bytes,
				     arg->share.fh.n_len);

		netobj_to_string(&arg->share.oh, oh, 1024);

		LogDebug(
			COMPONENT_NLM,
			"REQUEST PROCESSING: Calling NLM4_UNSHARE File Handle V3: Len=%u %s, cookie=%s, reclaim=%s, owner=%s, access=%d, deny=%d",
			arg->share.fh.n_len, str, buffer,
			arg->reclaim ? "yes" : "no", oh, arg->share.access,
			arg->share.mode);
	}

	copy_netobj(&res->res_nlm4share.cookie, &arg->cookie);

	rc = nlm_process_share_parms(req, &arg->share, op_ctx->fsal_export,
				     &obj, CARE_NOT, &nsm_client, &nlm_client,
				     &nlm_owner, &nlm_state);

	if (rc >= 0) {
		/* Present the error back to the client */
		res->res_nlm4share.stat = (nlm4_stats)rc;
		LogDebug(COMPONENT_NLM, "REQUEST RESULT: NLM4_UNSHARE %s",
			 lock_result_str(res->res_nlm4share.stat));
		return NFS_REQ_OK;
	}

	state_status = state_nlm_share(obj, arg->share.access, arg->share.mode,
				       nlm_owner, nlm_state, false, true);

	if (state_status != STATE_SUCCESS) {
		res->res_nlm4share.stat = nlm_convert_state_error(state_status);
	} else {
		res->res_nlm4share.stat = NLM4_GRANTED;
	}

	/* Release the NLM Client and NLM Owner references we have */
	dec_nsm_client_ref(nsm_client);
	dec_nlm_client_ref(nlm_client);
	dec_state_owner_ref(nlm_owner);
	obj->obj_ops->put_ref(obj);
	dec_nlm_state_ref(nlm_state);

	LogDebug(COMPONENT_NLM, "REQUEST RESULT: NLM4_UNSHARE %s",
		 lock_result_str(res->res_nlm4share.stat));

	return NFS_REQ_OK;
}

/**
 * nlm4_Unshare_Free: Frees the result structure allocated for nlm4_Lock
 *
 * Frees the result structure allocated for nlm4_Lock. Does Nothing in fact.
 *
 * @param res        [INOUT]   Pointer to the result structure.
 *
 */
void nlm4_Unshare_Free(nfs_res_t *res)
{
	netobj_free(&res->res_nlm4share.cookie);
}
