/*
* %CopyrightBegin%
*
* Copyright Ericsson 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* %CopyrightEnd%
*/
typedef int posix_errno_t;
enum efile_modes_t {
EFILE_MODE_READ = (1 << 0),
EFILE_MODE_WRITE = (1 << 1), /* Implies truncating file when used alone. */
EFILE_MODE_APPEND = (1 << 2),
EFILE_MODE_EXCLUSIVE = (1 << 3),
EFILE_MODE_SYNC = (1 << 4),
EFILE_MODE_SKIP_TYPE_CHECK = (1 << 5), /* Special for device files on Unix. */
EFILE_MODE_NO_TRUNCATE = (1 << 6), /* Special for reopening on VxWorks. */
EFILE_MODE_READ_WRITE = EFILE_MODE_READ | EFILE_MODE_WRITE
};
enum efile_access_t {
EFILE_ACCESS_NONE = 0,
EFILE_ACCESS_READ = 1,
EFILE_ACCESS_WRITE = 2,
EFILE_ACCESS_READ_WRITE = EFILE_ACCESS_READ | EFILE_ACCESS_WRITE
};
enum efile_seek_t {
EFILE_SEEK_BOF,
EFILE_SEEK_CUR,
EFILE_SEEK_EOF
};
enum efile_filetype_t {
EFILE_FILETYPE_DEVICE,
EFILE_FILETYPE_DIRECTORY,
EFILE_FILETYPE_REGULAR,
EFILE_FILETYPE_SYMLINK,
EFILE_FILETYPE_OTHER
};
enum efile_advise_t {
EFILE_ADVISE_NORMAL,
EFILE_ADVISE_RANDOM,
EFILE_ADVISE_SEQUENTIAL,
EFILE_ADVISE_WILL_NEED,
EFILE_ADVISE_DONT_NEED,
EFILE_ADVISE_NO_REUSE
};
enum efile_state_t {
EFILE_STATE_IDLE = 0,
EFILE_STATE_BUSY = 1,
EFILE_STATE_CLOSE_PENDING = 2,
EFILE_STATE_CLOSED = 3
};
typedef struct {
Sint64 size; /* Size of file */
Uint32 type; /* Type of file -- one of EFILE_FILETYPE_*. */
Uint32 access; /* Access to file -- one of EFILE_ACCESS_*. */
Uint32 mode; /* Access permissions -- bit field. */
Uint32 links; /* Number of links to file. */
Uint32 major_device; /* Major device or file system. */
Uint32 minor_device; /* Minor device (for devices). */
Uint32 inode; /* Inode number. */
Uint32 uid; /* User id of owner. */
Uint32 gid; /* Group id of owner. */
Sint64 a_time; /* Last time the file was accessed. */
Sint64 m_time; /* Last time the file was modified. */
Sint64 c_time; /* Windows: creation time, Unix: last inode
* change. */
} efile_fileinfo_t;
/* The smallest value that can be converted freely between universal, local,
* and POSIX time, as required by read_file_info/2. Corresponds to
* {{1902,1,1},{0,0,0}} */
#define EFILE_MIN_FILETIME -2145916800
/* Initializes an efile_data_t; must be used in efile_open on success. */
#define EFILE_INIT_RESOURCE(__d, __modes) do { \
erts_atomic32_init_acqb(&(__d)->state, EFILE_STATE_IDLE); \
(__d)->posix_errno = 0; \
(__d)->modes = __modes; \
} while(0)
typedef struct {
erts_atomic32_t state;
posix_errno_t posix_errno;
enum efile_modes_t modes;
ErlNifMonitor monitor;
} efile_data_t;
typedef ErlNifBinary efile_path_t;
/* @brief Translates the given "raw name" into the format expected by the APIs
* used by the underlying implementation. The result is transient and does not
* need to be released.
*
* This may change the structure of the path and its results should never be
* passed on to the user. Refer to the OS-specific implementation for details.
*
* @param path The term to translate; it must have been encoded with
* prim_file:internal_native2name for compatibility reasons. */
posix_errno_t efile_marshal_path(ErlNifEnv *env, ERL_NIF_TERM path, efile_path_t *result);
/* @brief Returns the underlying handle as an implementation-defined term.
*
* This is an internal function intended to support tests and tricky
* operations like sendfile(2). */
ERL_NIF_TERM efile_get_handle(ErlNifEnv *env, efile_data_t *d);
/* @brief Read until EOF or the given iovec has been filled.
*
* @return -1 on failure, or the number of bytes read on success. The return
* value will be 0 if no bytes could be read before EOF or the end of the
* iovec. */
Sint64 efile_readv(efile_data_t *d, SysIOVec *iov, int iovlen);
/* @brief Write the entirety of the given iovec.
*
* @return -1 on failure, or the number of bytes written on success. "Partial"
* failures will be reported with -1 and not the number of bytes we managed to
* write to disk before the failure. */
Sint64 efile_writev(efile_data_t *d, SysIOVec *iov, int iovlen);
/* @brief As \c efile_readv, but starting from a file offset. */
Sint64 efile_preadv(efile_data_t *d, Sint64 offset, SysIOVec *iov, int iovlen);
/* @brief As \c efile_writev, but starting from a file offset. */
Sint64 efile_pwritev(efile_data_t *d, Sint64 offset, SysIOVec *iov, int iovlen);
int efile_seek(efile_data_t *d, enum efile_seek_t seek, Sint64 offset, Sint64 *new_position);
int efile_sync(efile_data_t *d, int data_only);
int efile_advise(efile_data_t *d, Sint64 offset, Sint64 length, enum efile_advise_t advise);
int efile_allocate(efile_data_t *d, Sint64 offset, Sint64 length);
int efile_truncate(efile_data_t *d);
posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes,
ErlNifResourceType *nif_type, efile_data_t **d);
/** @brief Closes a file. The file must have entered the CLOSED state prior to
* calling this to prevent double close.
*
* Note that the file is completely invalid after this point, so the error code
* is provided in \c error rather than d->posix_errno. */
int efile_close(efile_data_t *d, posix_errno_t *error);
/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
posix_errno_t efile_read_info(const efile_path_t *path, int follow_link, efile_fileinfo_t *result);
/** @brief Sets the file times to the given values. Refer to efile_fileinfo_t
* for a description of each. */
posix_errno_t efile_set_time(const efile_path_t *path, Sint64 a_time, Sint64 m_time, Sint64 c_time);
/** @brief On Unix, this sets the file permissions according to the docs for
* file:write_file_info/2. On Windows it uses the "owner write permission" flag
* to toggle whether the file is read-only or not. */
posix_errno_t efile_set_permissions(const efile_path_t *path, Uint32 permissions);
/** @brief On Unix, this will set the owner/group to the given values. It will
* do nothing on other platforms. */
posix_errno_t efile_set_owner(const efile_path_t *path, Sint32 owner, Sint32 group);
/** @brief Resolves the final path of the given link. */
posix_errno_t efile_read_link(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result);
/** @brief Lists the contents of the given directory.
* @param result [out] A list of all the directory/file names contained in the
* given directory. */
posix_errno_t efile_list_dir(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result);
/** @brief Changes the name of an existing file or directory, from old_path
* to new_path.
*
* If old_path and new_path refer to the same file or directory, it does
* nothing and returns success. Otherwise if new_path already exists, it will
* be deleted and replaced by src subject to the following conditions:
*
* If old_path is a directory, new_path may be an empty directory.
* If old_path is a file, new_path may be a file.
*
* Neither of these are guaranteed to be atomic. In any other situation where
* new_path already exists, the rename will fail.
*
* Some possible error codes:
*
* - EACCES: Either paths or one of their parent directories can't be read
* and/or written.
* - EEXIST: new_path is a non-empty directory.
* - EINVAL: old_path is a root directory or new_path is a subdirectory
* of new_path.
* - EISDIR: new_path is a directory, but old_path is not.
* - ENOTDIR: old_path is a directory, but new_path is not.
* - ENOENT: old_path doesn't exist, or either path is "".
* - EXDEV: The paths are on different filesystems.
*
* The implementation of rename may allow cross-filesystem renames,
* but the caller should be prepared to emulate it with copy and
* delete if errno is EXDEV. */
posix_errno_t efile_rename(const efile_path_t *old_path, const efile_path_t *new_path);
posix_errno_t efile_make_hard_link(const efile_path_t *existing_path, const efile_path_t *new_path);
posix_errno_t efile_make_soft_link(const efile_path_t *existing_path, const efile_path_t *new_path);
posix_errno_t efile_make_dir(const efile_path_t *path);
posix_errno_t efile_del_file(const efile_path_t *path);
posix_errno_t efile_del_dir(const efile_path_t *path);
posix_errno_t efile_get_cwd(ErlNifEnv *env, ERL_NIF_TERM *result);
posix_errno_t efile_set_cwd(const efile_path_t *path);
/** @brief A Windows-specific function for returning the working directory of a
* given device.
*
* @param device_index The drive index; 1 for A, 2 for B, etc.
* @param result [out] The working directory of the given device
*/
posix_errno_t efile_get_device_cwd(ErlNifEnv *env, int device_index, ERL_NIF_TERM *result);
/** @brief A Windows-specific function for returning the 8.3-name of a given
* file or directory. */
posix_errno_t efile_altname(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result);