%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% header /** @file File descriptors, open and close a file, read and write. Portable use of file descriptor. CRT on Windows: Required. */ #ifndef DK4CONF_H_INCLUDED #include "dk4conf.h" #endif #ifndef DK4TYPES_H_INCLUDED #include "dk4types.h" #endif #ifndef DK4ERROR_H_INCLUDED #include "dk4error.h" #endif #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYS_STAT_H #ifndef SYS_STAT_H_INCLUDED #include #define SYS_STAT_H_INCLUDED 1 #endif #endif #if DK4_HAVE_FCNTL_H #ifndef FCNTL_H_INCLUDED #include #define FCNTL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_IO_H #ifndef IO_H_INCLUDED #include #define IO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_WCHAR_H #ifndef WCHAR_H_INCLUDED #include #define WCHAR_H_INCLUDED 1 #endif #endif #if DK4_ON_WINDOWS /** File open flags. */ enum { /** Read only access. */ DK4_O_RDONLY = _O_RDONLY, /** Write only access. */ DK4_O_WRONLY = _O_WRONLY, /** Read and write access. */ DK4_O_RDWR = _O_RDWR, /** Create file if it does not yet exist. */ DK4_O_CREAT = _O_CREAT, /** Combined with DK4_O_CREAT, create error if file already exists. */ DK4_O_EXCL = _O_EXCL, /** Truncate existing file. */ DK4_O_TRUNC = _O_TRUNC, /** Append to existing file. */ DK4_O_APPEND = _O_APPEND, /** Open file in binary mode. */ DK4_O_BINARY = _O_BINARY, }; #else /** File open flags. */ enum { /** Read only access. */ DK4_O_RDONLY = O_RDONLY, /** Write only access. */ DK4_O_WRONLY = O_WRONLY, /** Read and write access. */ DK4_O_RDWR = O_RDWR, /** Create file if it does not yet exist. */ DK4_O_CREAT = O_CREAT, /** Combined with DK4_O_CREAT, create error if file already exists. */ DK4_O_EXCL = O_EXCL, /** Truncate existing file. */ DK4_O_TRUNC = O_TRUNC, /** Append to existing file. */ DK4_O_APPEND = O_APPEND, /** Open file in binary mode. */ DK4_O_BINARY = 0, }; #endif #ifdef __cplusplus extern "C" { #endif /** Open a file, return file descriptor. @param path File name. @param flags Flags how to open the file. @param erp Error report, may be NULL. @return Non-negative file descriptor on success, -1 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if path is NULL, - DK4_E_OPEN_FAILED
with iDetails set to errno value if the open() function indicated an error. */ int dk4fd_c8_open(const char *path, int flags, dk4_er_t *erp); /** Open a file, return file descriptor. @param path File name. @param flags Flags how to open the file. @param erp Error report, may be NULL. @return Non-negative file descriptor on success, -1 on error. Error codes: - DK4_E_NOT_SUPPORTED
if there is no function available to open files by wchar_t file name, - DK4_E_INVALID_ARGUMENTS
if path is NULL, - DK4_E_OPEN_FAILED
with iDetails set to errno value if the open() function indicated an error. */ int dk4fd_wc_open(const wchar_t *path, int flags, dk4_er_t *erp); /** Open a file, return file descriptor. @param path File name. @param flags Flags how to open the file. @param erp Error report, may be NULL. @return Non-negative file descriptor on success, -1 on error. Error codes: - DK4_E_NOT_SUPPORTED
if there is no function available to open files by wchar_t file name, - DK4_E_INVALID_ARGUMENTS
if path is NULL, - DK4_E_OPEN_FAILED
with iDetails set to errno value if the open() function indicated an error. */ int dk4fd_open(const dkChar *path, int flags, dk4_er_t *erp); /** Close file descriptor. @param fd File descriptor to close. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_CLOSE_FAILED
with iDetails set to errno if the close() function indicates an error. */ int dk4fd_close(int fd, dk4_er_t *erp); /** Write data to a file descriptor. @param fd File descriptor. @param buffer Buffer start address. @param sz Size of buffer. @param erp Error report, may be NULL. @return 1 on success (all bytes written), 0 otherwise. Error codes: - DK4_E_INVALID_ARGUMENTS
if buffer is NULL or sz is 0 or sz is too large, - DK4_E_WRITE_FAILED
with mem.nelem set to the number of bytes written if the write attempt failed. */ int dk4fd_write(int fd, const void *buffer, size_t sz, dk4_er_t *erp); /** Read data from a file descriptor. @param fd File descriptor. @param buffer Buffer start address. @param psz Pointer to size variable, in: Size of buffer, out: Number of bytes read. @param erp Error report, may be NULL. @return 1 on success (at least one byte read), 0 otherwise. Error codes: - DK4_E_INVALID_ARGUMENTS
if buffer or psz is NULL or *psz is 0 or *psz is too large, - DK4_E_READ_FAILED
with iDetails set to errno if the read() function indicated an error. */ int dk4fd_read(int fd, void *buffer, size_t *psz, dk4_er_t *erp); #ifdef __cplusplus } #endif %% module #include "dk4fd.h" #if DK4_HAVE_ERRNO_H #ifndef ERRNO_H_INCLUDED #include #define ERRNO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SHARE_H #ifndef SHARE_H_INCLUDED #include #define SHARE_H_INCLUDED 1 #endif #endif $!trace-include int dk4fd_c8_open(const char *path, int flags, dk4_er_t *erp) { int back = -1; if (NULL != path) { #if DK4_ON_WINDOWS #if _MSC_VER >= 1700 int res; if (0 != (res = _sopen_s(&back,path,flags,_SH_DENYNO,(_S_IREAD|_S_IWRITE)))) { if (-1 != back) { _close(back); back = -1; } dk4error_set_idetails(erp, DK4_E_OPEN_FAILED, res); } #else errno = 0; back = _open(path, flags, (_S_IREAD | _S_IWRITE)); if (-1 == back) { dk4error_set_idetails(erp, DK4_E_OPEN_FAILED, errno); } #endif #else errno = 0; back = open(path, flags, 0600); if (-1 == back) { dk4error_set_idetails(erp, DK4_E_OPEN_FAILED, errno); } #endif } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } int dk4fd_wc_open(const wchar_t *path, int flags, dk4_er_t *erp) { int back = -1; if (NULL != path) { #if DK4_ON_WINDOWS #if _MSC_VER >= 1700 int res; if (0 != (res=_wsopen_s(&back,path,flags,_SH_DENYNO,(_S_IREAD|_S_IWRITE)))) { if (-1 != back) { _close(back); back = -1; } dk4error_set_idetails(erp, DK4_E_OPEN_FAILED, res); } #else errno = 0; back = _wopen(path, flags, (_S_IREAD | _S_IWRITE)); if (-1 == back) { dk4error_set_idetails(erp, DK4_E_OPEN_FAILED, errno); } #endif #else dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); #endif } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } int dk4fd_open(const dkChar *path, int flags, dk4_er_t *erp) { #if DK4_CHAR_SIZE > 1 return (dk4fd_wc_open(path, flags, erp)); #else return (dk4fd_c8_open(path, flags, erp)); #endif } int dk4fd_close(int fd, dk4_er_t *erp) { int back = 0; #if DK4_ON_WINDOWS errno = 0; if (0 == _close(fd)) { back = 1; } else { dk4error_set_idetails(erp, DK4_E_CLOSE_FAILED, errno); } #else errno = 0; if (0 == close(fd)) { back = 1; } else { dk4error_set_idetails(erp, DK4_E_CLOSE_FAILED, errno); } #endif return back; } #if !DK4_ON_WINDOWS #ifndef SSIZE_MAX /** Maximum value for ssize_t. */ #define SSIZE_MAX ((SIZE_MAX) / 2U) #endif #endif int dk4fd_write(int fd, const void *buffer, size_t sz, dk4_er_t *erp) { #if DK4_ON_WINDOWS int back = 0; int res; if ((NULL != buffer) && (0 < sz)) { if ((dk4_um_t)INT_MAX >= (dk4_um_t)sz) { errno = 0; res = _write(fd, buffer, (unsigned)sz); if ((unsigned)res == (unsigned)sz) { back = 1; } else { if (0 <= res) { dk4error_set_elsize_nelem(erp, DK4_E_WRITE_FAILED, 1, (size_t)res); } else { dk4error_set_elsize_nelem(erp, DK4_E_WRITE_FAILED, 1, 0); } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; #else ssize_t res; int back = 0; if ((NULL != buffer) && (0 < sz)) { if ((dk4_um_t)SSIZE_MAX >= (dk4_um_t)sz) { errno = 0; res = write(fd, buffer, sz); if ((size_t)res == sz) { back = 1; } else { if (0 <= res) { dk4error_set_elsize_nelem(erp, DK4_E_WRITE_FAILED, 1, res); } else { dk4error_set_elsize_nelem(erp, DK4_E_WRITE_FAILED, 1, 0); } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; #endif } int dk4fd_read(int fd, void *buffer, size_t *psz, dk4_er_t *erp) { #if DK4_ON_WINDOWS int res = 0; /* Result from read operation */ int back = 0; if ((NULL != buffer) && (NULL != psz)) { if (0 < *psz) { if ((dk4_um_t)INT_MAX >= (dk4_um_t)(*psz)) { errno = 0; res = _read(fd, buffer, (unsigned)(*psz)); if (0 < res) { back = 1; *psz = (size_t)res; } else { if (0 > res) { back = 0; *psz = 0; dk4error_set_idetails(erp, DK4_E_READ_FAILED, errno); } else { back = 1; *psz = 0; } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; #else int back = 0; ssize_t res; if ((NULL != buffer) && (NULL != psz)) { if (0 < *psz) { if ((dk4_um_t)SSIZE_MAX >= (dk4_um_t)(*psz)) { errno = 0; res = read(fd, buffer, *psz); if (0 < res) { back = 1; *psz = (size_t)res; } else { if (0 > res) { back = 0; *psz = 0; dk4error_set_idetails(erp, DK4_E_READ_FAILED, errno); } else { back = 1; *psz = 0; } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; #endif }