ext/magic/functions.c (286 lines of code) (raw):
#if defined(__cplusplus)
extern "C" {
#endif
#include "functions.h"
int check_fd(int fd);
static int safe_dup(int fd);
static int safe_close(int fd);
static int safe_cloexec(int fd);
int override_error_output(void *data);
int restore_error_output(void *data);
inline int
check_fd(int fd)
{
errno = 0;
if (fd < 0 || (fcntl(fd, F_GETFD) < 0 && errno == EBADF)) {
errno = EBADF;
return -EBADF;
}
return 0;
}
static int
safe_dup(int fd)
{
int new_fd;
int local_errno;
int flags = F_DUPFD;
#if defined(HAVE_F_DUPFD_CLOEXEC)
flags = F_DUPFD_CLOEXEC;
#endif
new_fd = fcntl(fd, flags, fileno(stderr) + 1);
if (new_fd < 0 && errno == EINVAL) {
new_fd = dup(fd);
if (new_fd < 0) {
local_errno = errno;
goto error;
}
}
if (safe_cloexec(new_fd) < 0) {
local_errno = errno;
goto error;
}
return new_fd;
error:
errno = local_errno;
return -1;
}
static int
safe_close(int fd)
{
int rv;
#if defined(HAVE_POSIX_CLOSE_RESTART)
rv = posix_close(fd, 0);
#else
rv = close(fd);
if (rv < 0 && errno == EINTR)
errno = EINPROGRESS;
#endif
return rv;
}
static inline int
safe_cloexec(int fd)
{
int local_errno;
int flags = fcntl(fd, F_GETFD);
if (flags < 0) {
local_errno = errno;
goto error;
}
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
local_errno = errno;
goto error;
}
return 0;
error:
errno = local_errno;
return -1;
}
int
override_error_output(void *data)
{
int local_errno;
mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
save_t *s = data;
#if defined(HAVE_O_CLOEXEC)
mode |= O_CLOEXEC;
#endif
assert(s != NULL && \
"Must be a valid pointer to `save_t' type");
s->file.old_fd = -1;
s->file.new_fd = -1;
s->status = -1;
fflush(stderr);
fgetpos(stderr, &s->file.position);
s->file.old_fd = safe_dup(fileno(stderr));
if (s->file.old_fd < 0) {
local_errno = errno;
goto error;
}
s->file.new_fd = open("/dev/null", O_WRONLY | O_APPEND, mode);
if (s->file.new_fd < 0) {
local_errno = errno;
if (dup2(s->file.old_fd, fileno(stderr)) < 0) {
local_errno = errno;
goto error;
}
safe_close(s->file.old_fd);
goto error;
}
if (safe_cloexec(s->file.new_fd) < 0) {
local_errno = errno;
goto error;
}
if (dup2(s->file.new_fd, fileno(stderr)) < 0) {
local_errno = errno;
goto error;
}
safe_close(s->file.new_fd);
return 0;
error:
s->status = local_errno;
errno = s->status;
return -1;
}
int
restore_error_output(void *data)
{
int local_errno;
save_t *s = data;
assert(s != NULL && \
"Must be a valid pointer to `save_t' type");
if (s->file.old_fd < 0 && s->status != 0)
return -1;
fflush(stderr);
if (dup2(s->file.old_fd, fileno(stderr)) < 0) {
local_errno = errno;
goto error;
}
safe_close(s->file.old_fd);
clearerr(stderr);
fsetpos(stderr, &s->file.position);
if (setvbuf(stderr, NULL, _IONBF, 0) != 0) {
local_errno = errno;
goto error;
}
return 0;
error:
s->status = local_errno;
errno = s->status;
return -1;
}
inline magic_t
magic_open_wrapper(int flags)
{
return magic_open(flags);
}
inline void
magic_close_wrapper(magic_t magic)
{
magic_close(magic);
}
inline const char*
magic_error_wrapper(magic_t magic)
{
return magic_error(magic);
}
inline int
magic_errno_wrapper(magic_t magic)
{
return magic_errno(magic);
}
inline const char*
magic_getpath_wrapper(void)
{
/*
* The second argument translates to same value as the
* FILE_LOAD constant, which when used results in this
* function calling the get_default_magic() internally.
*
* N.B. magic_getpath() also honors the "MAGIC"
* environment variable."
*/
return magic_getpath(NULL, 0);
}
inline int
magic_getparam_wrapper(magic_t magic, int parameter, void *value)
{
return magic_getparam(magic, parameter, value);
}
inline int
magic_setparam_wrapper(magic_t magic, int parameter, const void *value)
{
if (*(const int *)value < 0 || *(const size_t *)value > UINT_MAX) {
errno = EOVERFLOW;
return -EOVERFLOW;
}
if (parameter == MAGIC_PARAM_BYTES_MAX)
return magic_setparam(magic, parameter, value);
if (*(const size_t *)value > USHRT_MAX) {
errno = EOVERFLOW;
return -EOVERFLOW;
}
return magic_setparam(magic, parameter, value);
}
inline int
magic_getflags_wrapper(magic_t magic)
{
#if defined(HAVE_MAGIC_GETFLAGS)
return magic_getflags(magic);
#else
UNUSED(magic);
errno = ENOSYS;
return -ENOSYS;
#endif
}
inline int
magic_setflags_wrapper(magic_t magic, int flags)
{
if (flags < 0 || flags > 0xfffffff) {
errno = EINVAL;
return -EINVAL;
}
#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
if (flags & MAGIC_PRESERVE_ATIME) {
errno = ENOSYS;
return -ENOSYS;
}
#endif
return magic_setflags(magic, flags);
}
inline int
magic_load_wrapper(magic_t magic, const char *magic_file, int flags)
{
int rv;
MAGIC_FUNCTION(magic_load, rv, flags, magic, magic_file);
return rv;
}
inline int
magic_load_buffers_wrapper(magic_t magic, void **buffers, size_t *sizes, size_t count, int flags)
{
int rv;
MAGIC_FUNCTION(magic_load_buffers, rv, flags, magic, buffers, sizes, count);
return rv;
}
inline int
magic_compile_wrapper(magic_t magic, const char *magic_file, int flags)
{
int rv;
MAGIC_FUNCTION(magic_compile, rv, flags, magic, magic_file);
return rv;
}
inline int
magic_check_wrapper(magic_t magic, const char *magic_file, int flags)
{
int rv;
MAGIC_FUNCTION(magic_check, rv, flags, magic, magic_file);
return rv;
}
inline const char*
magic_file_wrapper(magic_t magic, const char* filename, int flags)
{
const char *cstring;
MAGIC_FUNCTION(magic_file, cstring, flags, magic, filename);
return cstring;
}
inline const char*
magic_buffer_wrapper(magic_t magic, const void *buffer, size_t size, int flags)
{
const char *cstring;
MAGIC_FUNCTION(magic_buffer, cstring, flags, magic, buffer, size);
return cstring;
}
inline const char*
magic_descriptor_wrapper(magic_t magic, int fd, int flags)
{
int local_errno;
const char *cstring;
if (check_fd(fd) < 0) {
local_errno = errno;
goto error;
}
MAGIC_FUNCTION(magic_descriptor, cstring, flags, magic, fd);
return cstring;
error:
errno = local_errno;
return NULL;
}
inline int
magic_version_wrapper(void)
{
return magic_version();
}
#if defined(__cplusplus)
}
#endif