/*
   Copyright (c) 2013 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 _CHANGELOG_MISC_H
#define _CHANGELOG_MISC_H

#include <glusterfs/glusterfs.h>
#include <glusterfs/common-utils.h>

#define CHANGELOG_MAX_TYPE 4
#define CHANGELOG_FILE_NAME "CHANGELOG"
#define HTIME_FILE_NAME "HTIME"
#define CSNAP_FILE_NAME "CHANGELOG.SNAP"
#define HTIME_KEY "trusted.glusterfs.htime"
#define HTIME_CURRENT "trusted.glusterfs.current_htime"
#define HTIME_INITIAL_VALUE "0:0"

#define CHANGELOG_VERSION_MAJOR 1
#define CHANGELOG_VERSION_MINOR 2

#define CHANGELOG_UNIX_SOCK DEFAULT_VAR_RUN_DIRECTORY "/changelog-%s.sock"
#define CHANGELOG_TMP_UNIX_SOCK DEFAULT_VAR_RUN_DIRECTORY "/.%s%lu.sock"

/**
 * header starts with the version and the format of the changelog.
 * 'version' not much of a use now.
 */
#define CHANGELOG_HEADER                                                       \
    "GlusterFS Changelog | version: v%d.%d | encoding : %d\n"

#define CHANGELOG_MAKE_SOCKET_PATH(brick_path, sockpath, len)                  \
    do {                                                                       \
        char xxh64[GF_XXH64_DIGEST_LENGTH * 2 + 1] = {                         \
            0,                                                                 \
        };                                                                     \
        gf_xxh64_wrapper((unsigned char *)brick_path, strlen(brick_path),      \
                         GF_XXHSUM64_DEFAULT_SEED, xxh64);                     \
        (void)snprintf(sockpath, len, CHANGELOG_UNIX_SOCK, xxh64);             \
    } while (0)

#define CHANGELOG_MAKE_TMP_SOCKET_PATH(brick_path, sockpath, len)              \
    do {                                                                       \
        unsigned long pid = 0;                                                 \
        char xxh64[GF_XXH64_DIGEST_LENGTH * 2 + 1] = {                         \
            0,                                                                 \
        };                                                                     \
        pid = (unsigned long)getpid();                                         \
        gf_xxh64_wrapper((unsigned char *)brick_path, strlen(brick_path),      \
                         GF_XXHSUM64_DEFAULT_SEED, xxh64);                     \
        (void)snprintf(sockpath, len, CHANGELOG_TMP_UNIX_SOCK, xxh64, pid);    \
    } while (0)

/**
 * ... used by libgfchangelog.
 */
#define CHANGELOG_GET_HEADER_INFO(fd, buffer, len, enc, maj, min, elen)        \
    do {                                                                       \
        FILE *fp;                                                              \
        int fd_dup;                                                            \
                                                                               \
        enc = -1;                                                              \
        maj = -1;                                                              \
        min = -1;                                                              \
        fd_dup = dup(fd);                                                      \
                                                                               \
        if (fd_dup != -1) {                                                    \
            fp = fdopen(fd_dup, "r");                                          \
            if (fp) {                                                          \
                if (fgets(buffer, len, fp)) {                                  \
                    elen = strlen(buffer);                                     \
                    sscanf(buffer, CHANGELOG_HEADER, &maj, &min, &enc);        \
                }                                                              \
                fclose(fp);                                                    \
            } else {                                                           \
                sys_close(fd_dup);                                             \
            }                                                                  \
        }                                                                      \
    } while (0)

#define CHANGELOG_FILL_HTIME_DIR(changelog_dir, path)                          \
    do {                                                                       \
        snprintf(path, sizeof(path), "%s/htime", changelog_dir);               \
    } while (0)

#define CHANGELOG_FILL_CSNAP_DIR(changelog_dir, path)                          \
    do {                                                                       \
        snprintf(path, sizeof(path), "%s/csnap", changelog_dir);               \
    } while (0)
/**
 * everything after 'CHANGELOG_TYPE_METADATA_XATTR' are internal types
 * (ie. none of the fops trigger this type of event), hence
 * CHANGELOG_MAX_TYPE = 4
 */
typedef enum {
    CHANGELOG_TYPE_DATA = 0,
    CHANGELOG_TYPE_METADATA,
    CHANGELOG_TYPE_ENTRY,
    CHANGELOG_TYPE_METADATA_XATTR,
    CHANGELOG_TYPE_ROLLOVER,
    CHANGELOG_TYPE_FSYNC,
} changelog_log_type;

/* operation modes - RT for now */
typedef enum {
    CHANGELOG_MODE_RT = 0,
} changelog_mode_t;

/* encoder types */

typedef enum {
    CHANGELOG_ENCODE_MIN = 0,
    CHANGELOG_ENCODE_BINARY,
    CHANGELOG_ENCODE_ASCII,
    CHANGELOG_ENCODE_MAX,
} changelog_encoder_t;

#define CHANGELOG_VALID_ENCODING(enc)                                          \
    (enc > CHANGELOG_ENCODE_MIN && enc < CHANGELOG_ENCODE_MAX)

#define CHANGELOG_TYPE_IS_ENTRY(type) (type == CHANGELOG_TYPE_ENTRY)
#define CHANGELOG_TYPE_IS_ROLLOVER(type) (type == CHANGELOG_TYPE_ROLLOVER)
#define CHANGELOG_TYPE_IS_FSYNC(type) (type == CHANGELOG_TYPE_FSYNC)

#endif /* _CHANGELOG_MISC_H */
