#include <glib.h>
#include <blockdev/utils.h>


#ifndef BD_LOOP_API
#define BD_LOOP_API

GQuark  bd_loop_error_quark (void);


#define BD_LOOP_ERROR bd_loop_error_quark ()
typedef enum {
    BD_LOOP_ERROR_TECH_UNAVAIL,
    BD_LOOP_ERROR_FAIL,
    BD_LOOP_ERROR_DEVICE,
} BDLoopError;

typedef enum {
    BD_LOOP_TECH_LOOP = 0,
} BDLoopTech;

typedef enum {
    BD_LOOP_TECH_MODE_CREATE  = 1 << 0,
    BD_LOOP_TECH_MODE_DESTROY = 1 << 1,
    BD_LOOP_TECH_MODE_MODIFY  = 1 << 2,
    BD_LOOP_TECH_MODE_QUERY   = 1 << 3,
} BDLoopTechMode;

/**
 * bd_loop_is_tech_avail:
 * @tech: the queried tech
 * @mode: a bit mask of queried modes of operation (#BDLoopTechMode) for @tech
 * @error: (out) (optional): place to store error (details about why the @tech-@mode combination is not available)
 *
 * Returns: whether the @tech-@mode combination is available -- supported by the
 *          plugin implementation and having all the runtime dependencies available
 */
gboolean  bd_loop_is_tech_avail (BDLoopTech tech, guint64 mode, GError **error);


#define BD_LOOP_TYPE_INFO (bd_loop_info_get_type ())
GType  bd_loop_info_get_type ();


typedef struct BDLoopInfo {
    gchar *backing_file;
    guint64 offset;
    gboolean autoclear;
    gboolean direct_io;
    gboolean part_scan;
    gboolean read_only;
} BDLoopInfo;

/**
 * BDLoopInfo:
 * @backing_file: backing file for the give loop device;
 * @offset: offset of the start of the device (in @backing_file);
 * @autoclear: whether the autoclear flag is set or not;
 * @direct_io: whether direct IO is enabled or not;
 * @part_scan: whether the partition scan is enforced or not;
 * @read_only: whether the device is read-only or not;
 */
/**
 * bd_loop_info_free: (skip)
 * @info: (nullable): %BDLoopInfo to free
 *
 * Frees @info.
 */
void  bd_loop_info_free (BDLoopInfo *info);


/**
 * bd_loop_info_copy: (skip)
 * @info: (nullable): %BDLoopInfo to copy
 *
 * Creates a new copy of @info.
 */
BDLoopInfo* bd_loop_info_copy (BDLoopInfo *info);



/**
 * bd_loop_info:
 * @loop: name of the loop device to get information about (e.g. "loop0")
 * @error: (out) (optional): place to store error (if any)
 *
 * Returns: (transfer full): information about the @loop device or %NULL in case of error
 *
 * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
 */
BDLoopInfo* bd_loop_info (const gchar *loop, GError **error);


/**
 * bd_loop_get_loop_name:
 * @file: path of the backing file to get loop name for
 * @error: (out) (optional): place to store error (if any)
 *
 * Returns: (transfer full): name of the loop device associated with the given
 * @file or %NULL if failed to determine
 *
 * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_QUERY
 */
gchar* bd_loop_get_loop_name (const gchar *file, GError **error);


/**
 * bd_loop_setup:
 * @file: file to setup as a loop device
 * @offset: offset of the start of the device (in @file)
 * @size: maximum size of the device (or 0 to leave unspecified)
 * @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE)
 * @part_scan: whether to enforce partition scan on the newly created device or not
 * @sector_size: logical sector size for the loop device in bytes (or 0 for default)
 * @loop_name: (optional) (out): if not %NULL, it is used to store the name of the loop device
 * @error: (out) (optional): place to store error (if any)
 *
 * Returns: whether the @file was successfully setup as a loop device or not
 *
 * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE
 */
gboolean  bd_loop_setup (const gchar *file, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, guint64 sector_size, const gchar **loop_name, GError **error);


/**
 * bd_loop_setup_from_fd:
 * @fd: file descriptor for a file to setup as a new loop device
 * @offset: offset of the start of the device (in file given by @fd)
 * @size: maximum size of the device (or 0 to leave unspecified)
 * @read_only: whether to setup as read-only (%TRUE) or read-write (%FALSE)
 * @part_scan: whether to enforce partition scan on the newly created device or not
 * @sector_size: logical sector size for the loop device in bytes (or 0 for default)
 * @loop_name: (optional) (out): if not %NULL, it is used to store the name of the loop device
 * @error: (out) (optional): place to store error (if any)
 *
 * Returns: whether a new loop device was successfully setup for @fd or not
 *
 * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_CREATE
 */
gboolean  bd_loop_setup_from_fd (gint fd, guint64 offset, guint64 size, gboolean read_only, gboolean part_scan, guint64 sector_size, const gchar **loop_name, GError **error);


/**
 * bd_loop_teardown:
 * @loop: path or name of the loop device to tear down
 * @error: (out) (optional): place to store error (if any)
 *
 * Returns: whether the @loop device was successfully torn down or not
 *
 * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_DESTROY
 */
gboolean  bd_loop_teardown (const gchar *loop, GError **error);


/**
 * bd_loop_set_autoclear:
 * @loop: path or name of the loop device
 * @autoclear: whether to set or unset the autoclear flag
 * @error: (out) (optional): place to store error (if any)
 *
 * Returns: whether the autoclear flag was successfully set on the @loop device or not
 *
 * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_MODIFY
 */
gboolean  bd_loop_set_autoclear (const gchar *loop, gboolean autoclear, GError **error);


/**
 * bd_loop_set_capacity:
 * @loop: path or name of the loop device
 * @error: (out) (optional): place to store error (if any)
 *
 * Force the loop driver to reread the size of the file associated with the
 * specified @loop device.
 *
 * Returns: whether the LOOP_SET_CAPACITY ioctl was successfully issued or not.
 *
 * Tech category: %BD_LOOP_TECH_LOOP-%BD_LOOP_TECH_MODE_MODIFY
 */
gboolean  bd_loop_set_capacity (const gchar *loop, GError **error);


#endif  /* BD_LOOP_API */
