/*
   Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
   This file is part of GlusterFS.

   This file is licensed to you under your choice of the GNU Lesser
   General Public License, version 3 or any later version (LGPLv3 or
   later), or the GNU General Public License, version 2 (GPLv2), in all
   cases as published by the Free Software Foundation.
*/
#ifndef __META_H__
#define __META_H__

#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif

#include "strfd.h"

#define DEFAULT_META_DIR_NAME ".meta"

#define META_ROOT_GFID "ba926388-bb9c-4eec-ad60-79dba4cc083a"

#define IS_META_ROOT_GFID(g) (strcmp (uuid_utoa(g), META_ROOT_GFID) == 0)

typedef int (*meta_hook_t) (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata);

typedef struct {
	dict_t *xdata;
} meta_local_t;

typedef struct {
	char *meta_dir_name;
} meta_priv_t;

struct meta_dirent {
	const char *name;
	ia_type_t type;
	meta_hook_t hook;
};

#define DOT_DOTDOT { .name = ".", .type = IA_IFDIR }, { .name = "..", .type = IA_IFDIR }

struct meta_ops {
	struct meta_dirent *fixed_dirents;
	int (*dir_fill) (xlator_t *this, inode_t *dir, struct meta_dirent **entries);
	int (*file_fill) (xlator_t *this, inode_t *file, strfd_t *strfd);
	int (*iatt_fill) (xlator_t *this, inode_t *inode, struct iatt *iatt);
	int (*link_fill) (xlator_t *this, inode_t *inode, strfd_t *strfd);
	int (*file_write) (xlator_t *this, fd_t *fd, struct iovec *iov, int count);
	struct xlator_fops fops;
	struct xlator_cbks cbks;
};

typedef struct {
	char *data;
	struct meta_dirent *dirents;
	size_t size;
} meta_fd_t;


#define COUNT(arr) (sizeof(arr)/sizeof(arr[0]))

#define META_HOOK(loc) (__is_root_gfid (loc->pargfid) && !strcmp (loc->name, META_PRIV(THIS)->meta_dir_name))

#define META_PRIV(t) ((meta_priv_t *)(t->private))

#define META_STACK_UNWIND(fop, frame, params ...)		\
        do {                                                    \
                meta_local_t *__local = NULL;			\
                xlator_t    *__this = NULL;                     \
                if (frame) {                                    \
                        __local = frame->local;                 \
                        __this = frame->this;                   \
                        frame->local = NULL;                    \
                }                                               \
                STACK_UNWIND_STRICT (fop, frame, params);       \
                if (__local) {                                  \
                        meta_local_cleanup (__local, __this);	\
                }                                               \
        } while (0)


#define META_FOP(i, fop, fr, t, params ...) {	\
	struct xlator_fops *_fops = NULL;	\
						\
	_fops = meta_fops_get (i, t);		\
						\
	_fops->fop (fr, t, params);		\
	} while (0)


void meta_iatt_fill (struct iatt *iatt, inode_t *inode, ia_type_t type);

int meta_inode_discover (call_frame_t *frame, xlator_t *this, loc_t *loc,
			 dict_t *xdata);

int meta_ops_set (inode_t *inode, xlator_t *this, struct meta_ops *ops);

struct xlator_fops *meta_fops_get (inode_t *inode, xlator_t *this);
struct xlator_cbks *meta_cbks_get (inode_t *inode, xlator_t *this);
struct meta_ops *meta_ops_get (inode_t *inode, xlator_t *this);

int meta_ctx_set (inode_t *inode, xlator_t *this, void *ctx);

void *meta_ctx_get (inode_t *inode, xlator_t *this);


void meta_local_cleanup (meta_local_t *local, xlator_t *this);

struct xlator_fops *meta_defaults_init (struct xlator_fops *fops);

meta_fd_t *meta_fd_get (fd_t *fd, xlator_t *this);

int meta_fd_release (fd_t *fd, xlator_t *this);

dict_t *meta_direct_io_mode (dict_t *xdata, call_frame_t *frame);

meta_local_t *meta_local (call_frame_t *frame);

int meta_file_fill (xlator_t *this, fd_t *fd);

int meta_dir_fill (xlator_t *this, fd_t *fd);

int fixed_dirents_len (struct meta_dirent *dirents);
#endif /* __META_H__ */
