/* SPDX-License-Identifier: LGPL-3.0-or-later */
/*
 *
 *
 *
 * Copyright CEA/DAM/DIF  (2008)
 * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
 *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
 *
 *
 * 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
 *
 * ---------------------------------------
 */

#ifndef FSAL_LOCAL_FS_H
#define FSAL_LOCAL_FS_H

#include "fsal_api.h"

#if !GSH_CAN_HOST_LOCAL_FS

static inline void release_posix_file_systems(void)
{
}
#ifdef USE_DBUS
static inline void dbus_cache_init(void)
{
}
#endif

struct fsal_filesystem;

#else

/**
 * @brief Public structure for filesystem descriptions
 *
 * This structure is provided along with a general interface to support those
 * FSALs that map into a traditional file system model. Note that
 * fsal_obj_handles do not link to an fsal_filesystem, that linkage is reserved
 * for FSAL's private obj handle if appropriate.
 *
 */

struct fsal_filesystem {
	struct glist_head filesystems; /*< List of file systems */
	struct glist_head children; /*< Child file systems */
	struct glist_head siblings; /*< Entry in list of parent's child
					    file systems */
	struct fsal_filesystem *parent; /*< Parent file system */
	struct fsal_module *fsal; /*< Link back to fsal module */
	struct glist_head exports; /*< List of all the export maps */
	void *private_data; /*< Private data for owning FSAL */
	char *path; /*< Path to root of this file system */
	char *device; /*< Path to block device */
	char *type; /*< fs type */

	unclaim_filesystem_cb unclaim; /*< Call back to unclaim this fs */
	uint32_t pathlen; /*< Length of path */
	uint32_t namelen; /*< Name length from statfs */

	struct avltree_node avl_fsid; /*< AVL indexed by fsid */
	struct avltree_node avl_dev; /*< AVL indexed by dev */
	struct fsal_fsid__ fsid; /*< file system id */
	fsal_dev_t dev; /*< device filesystem is on */
	enum fsid_type fsid_type; /*< type of fsid present */
	bool in_fsid_avl; /*< true if inserted in fsid avl */
	bool in_dev_avl; /*< true if inserted in dev avl */
	int claims[CLAIM_NUM]; /*< number of each type of claim */
	bool trunc_verif; /*< true if the filesystem needs
					    atime/mtime to be truncated to 31
					    bits when storing verifier. */
};

/*
 * Link fsal_filesystems and fsal_exports
 * Supports a many-to-many relationship
 */
struct fsal_filesystem_export_map {
	struct fsal_filesystem_export_map *parent_map;
	struct fsal_export *exp;
	struct fsal_filesystem *fs;
	struct glist_head child_maps;
	struct glist_head on_parent;
	struct glist_head on_exports;
	struct glist_head on_filesystems;
	enum claim_type claim_type;
};

int open_dir_by_path_walk(int first_fd, const char *path, struct stat *stat);

static inline int fsal_fs_compare_fsid(enum fsid_type left_fsid_type,
				       const struct fsal_fsid__ *left_fsid,
				       enum fsid_type right_fsid_type,
				       const struct fsal_fsid__ *right_fsid)
{
	if (left_fsid_type < right_fsid_type)
		return -1;

	if (left_fsid_type > right_fsid_type)
		return 1;

	if (left_fsid->major < right_fsid->major)
		return -1;

	if (left_fsid->major > right_fsid->major)
		return 1;

	/* No need to compare minors as they should be
	 * zeros if the type is FSID_MAJOR_64
	 */
	if (left_fsid_type == FSID_MAJOR_64) {
		assert(right_fsid_type == FSID_MAJOR_64);
		return 0;
	}

	if (left_fsid->minor < right_fsid->minor)
		return -1;

	if (left_fsid->minor > right_fsid->minor)
		return 1;

	return 0;
}

extern pthread_rwlock_t fs_lock;

#define LogFilesystem(cmt, cmt2, fs)                                         \
	LogFullDebug(COMPONENT_FSAL,                                         \
		     "%s%s FS %p %s parent %p %s children? %s siblings? %s " \
		     "FSAL %s exports? %s private %p "                       \
		     "claims ALL %d ROOT %d SUBTREE %d CHILD %d TEMP %d",    \
		     (cmt), (cmt2), (fs), (fs)->path, (fs)->parent,          \
		     (fs)->parent ? (fs)->parent->path : "NONE",             \
		     glist_empty(&(fs)->children) ? "NO" : "YES",            \
		     glist_null(&(fs)->siblings) ? "NO" : "YES",             \
		     (fs)->fsal ? (fs)->fsal->name : "NONE",                 \
		     glist_empty(&(fs)->exports) ? "NO" : "YES",             \
		     (fs)->private_data, (fs)->claims[CLAIM_ALL],            \
		     (fs)->claims[CLAIM_ROOT], (fs)->claims[CLAIM_SUBTREE],  \
		     (fs)->claims[CLAIM_CHILD], (fs)->claims[CLAIM_TEMP])

int populate_posix_file_systems(const char *path);

int resolve_posix_filesystem(const char *path, struct fsal_module *fsal,
			     struct fsal_export *exp,
			     claim_filesystem_cb claimfs,
			     unclaim_filesystem_cb unclaim,
			     struct fsal_filesystem **root_fs);

void release_posix_file_systems(void);

enum release_claims {
	UNCLAIM_WARN,
	UNCLAIM_SKIP,
};

bool release_posix_file_system(struct fsal_filesystem *fs,
			       enum release_claims release_claims);

int re_index_fs_fsid(struct fsal_filesystem *fs, enum fsid_type fsid_type,
		     struct fsal_fsid__ *fsid);

int re_index_fs_dev(struct fsal_filesystem *fs, struct fsal_dev__ *dev);

int change_fsid_type(struct fsal_filesystem *fs, enum fsid_type fsid_type);

struct fsal_filesystem *lookup_fsid_locked(struct fsal_fsid__ *fsid,
					   enum fsid_type fsid_type);
struct fsal_filesystem *lookup_dev_locked(struct fsal_dev__ *dev);
struct fsal_filesystem *lookup_fsid(struct fsal_fsid__ *fsid,
				    enum fsid_type fsid_type);
struct fsal_filesystem *lookup_dev(struct fsal_dev__ *dev);

int claim_posix_filesystems(const char *path, struct fsal_module *fsal,
			    struct fsal_export *exp,
			    claim_filesystem_cb claimfs,
			    unclaim_filesystem_cb unclaim,
			    struct fsal_filesystem **root_fs,
			    struct stat *statbuf);

bool is_filesystem_exported(struct fsal_filesystem *fs,
			    struct fsal_export *exp);

void unclaim_all_export_maps(struct fsal_export *exp);

void get_fs_first_export_ref(struct fsal_filesystem *this,
			     struct gsh_export **gsh_export,
			     struct fsal_export **fsal_export);

#ifdef USE_DBUS
void dbus_cache_init(void);
#endif

#endif /* GSH_CAN_HOST_LOCAL_FS */

#endif /* FSAL_LOCAL_FS_H */
