/*
 * Portions of this file Copyright 1999-2005 University of Chicago
 * Portions of this file Copyright 1999-2005 The University of Southern California.
 *
 * This file or a portion of this file is licensed under the
 * terms of the Globus Toolkit Public License, found at
 * http://www.globus.org/toolkit/download/license.html.
 * If you redistribute this file, with or without
 * modifications, you must include this notice in the file.
 */

#ifndef GLOBUS_XIO_FILE_DRIVER_INCLUDE
#define GLOBUS_XIO_FILE_DRIVER_INCLUDE
/**
 * @file
 * Header file for XIO File Driver
 */
#include "globus_xio_system.h"

/**
 * @defgroup file_driver Globus XIO File Driver
 * The File I/O driver.
 */

/**
 * @defgroup file_driver_instance Opening/Closing
 * @ingroup file_driver
 * 
 * An XIO handle with the file driver can be created with
 * @ref globus_xio_handle_create()
 * 
 * If there is no handle set on the attr passed to the 
 * @ref globus_xio_open() call, it performs the equivalent of an
 * open() call.  In this case, the contact string must contain
 * either a pathname or one of stdin://, stdout://, or stderr://.  If a
 * pathname is used, that path is opened.  If one of the schemes are used
 * the corresponding stdio handle is used (retrieved with fileno()).
 * 
 * In either of the above cases, it is most efficient to call the blocking
 * version of globus_xio_open().  It is also safe to call within a locked
 * critical section.
 * 
 * When the XIO handle is closed, the file driver will destroy its internal
 * resources and close the fd (unless this fd was set on an attr or converted
 * from one of the stdio handles).
 */
 
/**
 * @defgroup file_driver_io Reading/Writing
 * @ingroup file_driver
 * 
 * Both the @ref globus_xio_register_read() and
 * @ref globus_xio_register_write() calls follow similar semantics as described
 * below.
 * 
 * If the waitforbytes parameter is greater than zero, the io will happen
 * asynchronously and be completed when at least waitforbytes has been
 * read/written.
 * 
 * If the waitforbytes parameter is equal to zero, one of the following
 * alternative behaviors occur:
 * 
 * If the length of the buffer is > 0 the read or write happens synchronously.
 * If the user is using one of the blocking xio calls, no internal callback
 * will occur.
 * 
 * If the length of the buffer is also 0, the call behaves like an asynchronous
 * notification of data ready to be either read or written. ie, an
 * asynchronous select().
 * 
 * In any case, when an error or EOF occurs before the waitforbytes request
 * has been met, the outgoing nbytes is set to the amount of data actually
 * read/written before the error or EOF occurred.
 */
 
/**
 * @defgroup file_driver_envs Env Variables
 * @ingroup file_driver
 * 
 * The file driver uses the following environment variables
 * - GLOBUS_XIO_FILE_DEBUG Available if using a debug build. See globus_debug.h
 *      for format.  The File driver defines the levels TRACE for all function
 *      call tracing and INFO for write buffer sizes
 * - GLOBUS_XIO_SYSTEM_DEBUG Available if using a debug build.
 *      See globus_debug.h for format. The File driver uses globus_xio_system
 *      (along with the TCP and UDP drivers) which defines the following
 *      levels: TRACE for all function call tracing, DATA for data read and
 *      written counts, INFO for some special events, and RAW which dumps the
 *      raw buffers actually read or written. This can contain binary data, 
 *      so be careful when you enable it.
 */

/**
 * @defgroup file_driver_cntls Attributes and Cntls
 * @ingroup file_driver
 * 
 * File driver specific attrs and cntls.
 * 
 * @see globus_xio_attr_cntl()
 * @see globus_xio_handle_cntl()
 */
/**
 * @defgroup file_driver_types Types
 * @ingroup file_driver
 */
/**
 * @defgroup file_driver_errors Error Types
 * @ingroup file_driver
 * 
 * The File driver is very close to the system code, so most errors
 * reported by it are converted from the system errno. A few of the exceptions
 * are GLOBUS_XIO_ERROR_EOF, GLOBUS_XIO_ERROR_COMMAND,
 * GLOBUS_XIO_ERROR_CONTACT_STRING, and GLOBUS_XIO_ERROR_CANCELED
 * 
 * @see globus_error_errno_match()
 */

/**
 * Invalid handle type
 * @ingroup file_driver_types
 * @hideinitializer
 * @see GLOBUS_XIO_FILE_SET_HANDLE
 */
#define GLOBUS_XIO_FILE_INVALID_HANDLE GLOBUS_XIO_SYSTEM_INVALID_HANDLE

/** doxygen varargs filter stuff
 * GlobusVarArgDefine(
 *      attr, globus_result_t, globus_xio_attr_cntl, attr, driver)
 * GlobusVarArgDefine(
 *      handle, globus_result_t, globus_xio_handle_cntl, handle, driver)
 */

/**
 * File driver specific cntls
 * @ingroup file_driver_cntls
 */
typedef enum
{
    /** GlobusVarArgEnum(attr)
     * Set the file create mode.
     * @ingroup file_driver_cntls
     * Use this to set the permissions a non-existent file is created with,
     * The default mode is 0644.
     * 
     * @param mode
     *      A bitwise OR of all the modes desired
     * 
     * @see globus_xio_file_mode_t
     */
    /* int                              mode */
    GLOBUS_XIO_FILE_SET_MODE,
    
    /** GlobusVarArgEnum(attr)
     * Get the file create mode.
     * @ingroup file_driver_cntls
     * 
     * @param mode_out
     *      The current mode will be stored here.
     */
    /* int *                            mode_out */
    GLOBUS_XIO_FILE_GET_MODE,
    
    /** GlobusVarArgEnum(attr)
     * Set the file open flags.
     * @ingroup file_driver_cntls
     * The default flags specify to create the file if it doesn't exist,
     * open it for reading and writing, and interpret it as a binary file.
     * 
     * @param flags
     *      A bitwise OR of all the flags desired
     * 
     * @see globus_xio_file_flag_t
     */
    /* int                              flags */
    GLOBUS_XIO_FILE_SET_FLAGS,
    
    /** GlobusVarArgEnum(attr)
     * Get the file open flags.
     * @ingroup file_driver_cntls
     * 
     * @param flags_out
     *      The current flags will be stored here.
     */
    /* int *                            flags_out */
    GLOBUS_XIO_FILE_GET_FLAGS,
    
    /** GlobusVarArgEnum(attr)
     * Set the file truncate offset.
     * @ingroup file_driver_cntls
     * Use this in conjunction with the @ref GLOBUS_XIO_FILE_TRUNC flag
     * to truncate a file to a non-zero offset. If the file was larger
     * than offset bytes, the extra data is lost.  If the file was shorter or
     * non-existent, it is extended and the extended part reads as zeros.
     * (default is 0)
     * 
     * @param offset
     *      The desired size of the file.
     */
    /* globus_off_t                     offset */
    GLOBUS_XIO_FILE_SET_TRUNC_OFFSET,
    
    /** GlobusVarArgEnum(attr)
     * Get the file truncate offset.
     * @ingroup file_driver_cntls
     * 
     * @param offset_out
     *      The offset will be stored here.
     */
    /* globus_off_t *                   offset_out */
    GLOBUS_XIO_FILE_GET_TRUNC_OFFSET,
    
    /** GlobusVarArgEnum(attr)
     * Set the file handle to use.
     * @ingroup file_driver_cntls
     * Do not open a new file, use this preopened handle instead.
     * 
     * @param handle
     *      Use this handle (fd or HANDLE) for the file.
     *      Note:  close() will not be called on this handle.
     */
    /* globus_xio_system_handle_t       handle */
    GLOBUS_XIO_FILE_SET_HANDLE,
    
    /** GlobusVarArgEnum(attr, handle)
     * Get the file handle in use or in attr.
     * @ingroup file_driver_cntls
     * 
     * @param handle_out
     *      The file handle (fd or HANDLE) will be stored here. If none is set,
     *      GLOBUS_XIO_TCP_INVALID_HANDLE will be set.
     */
    /* globus_xio_system_handle_t *     handle_out */
    GLOBUS_XIO_FILE_GET_HANDLE,
    
    /** GlobusVarArgEnum(handle)
     * Reposition read/write file offset.
     * @ingroup file_driver_cntls
     * 
     * @param in_out_offset
     *      Specify the desired offset (according to whence).  On success,
     *      the actual file offset will be stored here.
     * 
     * @param whence
     *      Specify how offset should be interpreted.
     * 
     * @see globus_xio_file_whence_t
     * @see GLOBUS_XIO_SEEK
     */
    /* globus_off_t *                   in_out_offset,
     * globus_xio_file_whence_t         whence */
    GLOBUS_XIO_FILE_SEEK
} globus_xio_file_attr_cmd_t;

/**
 * File driver open flags
 * @ingroup file_driver_types
 * @hideinitializer
 * OR together all the flags you want
 * @see GLOBUS_XIO_FILE_SET_FLAGS
 */
typedef enum
{
    /** Create a new file if it doesn't exist (default) */
    GLOBUS_XIO_FILE_CREAT               = O_CREAT,
    /** Fail if file already exists */
    GLOBUS_XIO_FILE_EXCL                = O_EXCL,
    /** Open for read only */
    GLOBUS_XIO_FILE_RDONLY              = O_RDONLY,
    /** Open for write only */
    GLOBUS_XIO_FILE_WRONLY              = O_WRONLY,
    /** Open for reading and writing (default) */
    GLOBUS_XIO_FILE_RDWR                = O_RDWR,
    /** Truncate file @see GLOBUS_XIO_FILE_SET_TRUNC_OFFSET */
    GLOBUS_XIO_FILE_TRUNC               = O_TRUNC,
    /** Open file for appending */
    GLOBUS_XIO_FILE_APPEND              = O_APPEND,
#ifdef TARGET_ARCH_CYGWIN
    GLOBUS_XIO_FILE_BINARY              = O_BINARY,
    GLOBUS_XIO_FILE_TEXT                = O_TEXT
#else
    /** File is binary (default) */
    GLOBUS_XIO_FILE_BINARY              = 0,
    /** File is text */
    GLOBUS_XIO_FILE_TEXT                = 0
#endif
} globus_xio_file_flag_t;

/**
 * File driver create mode
 * @ingroup file_driver_types
 * @hideinitializer
 * OR these modes together to get the mode you want.
 * @see GLOBUS_XIO_FILE_SET_MODE
 */
typedef enum
{
    /** User read, write, and execute */
    GLOBUS_XIO_FILE_IRWXU               = S_IRWXU,
    /** User read */
    GLOBUS_XIO_FILE_IRUSR               = S_IRUSR,
    /** User write */
    GLOBUS_XIO_FILE_IWUSR               = S_IWUSR,
    /** User execute */
    GLOBUS_XIO_FILE_IXUSR               = S_IXUSR,
    /** Others read, write, and execute */
    GLOBUS_XIO_FILE_IRWXO               = S_IRWXO,
    /** Others read */
    GLOBUS_XIO_FILE_IROTH               = S_IROTH,
    /** Others write */
    GLOBUS_XIO_FILE_IWOTH               = S_IWOTH,
    /** Others execute */
    GLOBUS_XIO_FILE_IXOTH               = S_IXOTH,
    /** Group read, write, and execute */
    GLOBUS_XIO_FILE_IRWXG               = S_IRWXG,
    /** Group read */
    GLOBUS_XIO_FILE_IRGRP               = S_IRGRP,
    /** Group write */
    GLOBUS_XIO_FILE_IWGRP               = S_IWGRP,
    /** Group execute */
    GLOBUS_XIO_FILE_IXGRP               = S_IXGRP
} globus_xio_file_mode_t;

/**
 * File driver seek options
 * @ingroup file_driver_types
 * @hideinitializer
 * @see GLOBUS_XIO_FILE_SEEK
 */
typedef enum
{
    /** set the file pointer at the specified offset */
    GLOBUS_XIO_FILE_SEEK_SET            = SEEK_SET,
    /** set the file pointer at current position + offset */
    GLOBUS_XIO_FILE_SEEK_CUR            = SEEK_CUR,
    /** set the file pointer at size of file + offest */ 
    GLOBUS_XIO_FILE_SEEK_END            = SEEK_END
} globus_xio_file_whence_t;

#endif
