rizin/librz/io/p/io_default.c
2022-04-17 15:08:08 +02:00

224 lines
5.9 KiB
C

// SPDX-FileCopyrightText: 2008-2020 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_userconf.h>
#include <rz_io.h>
#include <rz_lib.h>
#include <stdio.h>
typedef struct rz_io_mmo_t {
char *filename;
int mode;
int perm;
bool nocache;
ut8 modified;
RzBuffer *buf;
} RzIOMMapFileObj;
static int iowhence2buf(int whence) {
switch (whence) {
case RZ_BUF_CUR:
return RZ_IO_SEEK_CUR;
case RZ_BUF_SET:
return RZ_IO_SEEK_SET;
case RZ_BUF_END:
return RZ_IO_SEEK_END;
default:
rz_warn_if_reached();
return -1;
}
}
static ut64 rz_io_def_mmap_seek(RzIO *io, RzIOMMapFileObj *mmo, ut64 offset, int whence) {
rz_return_val_if_fail(io && mmo, UT64_MAX);
// NOTE: io->off should not be set here and code outside RzIO should not
// rely on it to get the current seek. They should use `rz_io_seek` instead.
// Keep it here until all use cases of io->off are converted.
io->off = rz_buf_seek(mmo->buf, offset, iowhence2buf(whence));
return io->off;
}
static void rz_io_def_mmap_free(RzIOMMapFileObj *mmo) {
if (!mmo) {
return;
}
free(mmo->filename);
rz_buf_free(mmo->buf);
free(mmo);
}
static void disable_fd_cache(int fd) {
#if F_NOCACHE
fcntl(fd, F_NOCACHE, 1);
#elif O_DIRECT
int open_flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, open_flags | O_DIRECT);
#endif
}
RzIOMMapFileObj *rz_io_def_mmap_create_new_file(RzIO *io, const char *filename, int perm, int mode) {
rz_return_val_if_fail(io && filename, NULL);
RzIOMMapFileObj *mmo = RZ_NEW0(RzIOMMapFileObj);
if (!mmo) {
return NULL;
}
if (rz_str_startswith(filename, "file://")) {
filename += strlen("file://");
}
mmo->nocache = rz_str_startswith(filename, "nocache://");
if (mmo->nocache) {
filename += strlen("nocache://");
}
mmo->filename = strdup(filename);
mmo->perm = rz_sys_open_perms(perm);
mmo->mode = mode;
if (!mmo->nocache) {
mmo->buf = rz_buf_new_mmap(mmo->filename, mmo->perm, mmo->mode);
}
if (!mmo->buf) {
mmo->buf = rz_buf_new_file(mmo->filename, mmo->perm, mmo->mode);
if (!mmo->buf) {
rz_io_def_mmap_free(mmo);
return NULL;
}
if (mmo->nocache) {
disable_fd_cache(mmo->buf->fd);
}
}
return mmo;
}
static int rz_io_def_mmap_close(RzIODesc *fd) {
rz_return_val_if_fail(fd && fd->data, -1);
rz_io_def_mmap_free((RzIOMMapFileObj *)fd->data);
fd->data = NULL;
return 0;
}
static bool rz_io_def_mmap_check_default(const char *filename) {
rz_return_val_if_fail(filename && *filename, false);
if (rz_str_startswith(filename, "file://")) {
filename += strlen("file://");
}
const char *peekaboo = (!strncmp(filename, "nocache://", 10))
? NULL
: strstr(filename, "://");
return (!peekaboo || (peekaboo - filename) > 10);
}
static int rz_io_def_mmap_read(RzIO *io, RzIODesc *fd, ut8 *buf, int count) {
rz_return_val_if_fail(fd && fd->data && buf, -1);
RzIOMMapFileObj *mmo = (RzIOMMapFileObj *)fd->data;
rz_return_val_if_fail(mmo && mmo->buf, -1);
return (int)rz_buf_read(mmo->buf, buf, count);
}
static int rz_io_def_mmap_write(RzIO *io, RzIODesc *fd, const ut8 *buf, int count) {
rz_return_val_if_fail(io && fd && fd->data && buf, -1);
RzIOMMapFileObj *mmo = (RzIOMMapFileObj *)fd->data;
rz_return_val_if_fail(mmo && mmo->buf, -1);
return (int)rz_buf_write(mmo->buf, buf, count);
}
static RzIODesc *rz_io_def_mmap_open(RzIO *io, const char *file, int perm, int mode) {
rz_return_val_if_fail(io && file, NULL);
RzIOMMapFileObj *mmo = rz_io_def_mmap_create_new_file(io, file, perm, mode);
if (!mmo) {
return NULL;
}
RzIODesc *d = rz_io_desc_new(io, &rz_io_plugin_default, mmo->filename, perm, mode, mmo);
if (!d->name) {
d->name = strdup(mmo->filename);
}
return d;
}
static ut64 rz_io_def_mmap_lseek(RzIO *io, RzIODesc *fd, ut64 offset, int whence) {
rz_return_val_if_fail(fd && fd->data, UT64_MAX);
return rz_io_def_mmap_seek(io, (RzIOMMapFileObj *)fd->data, offset, whence);
}
static int rz_io_def_mmap_truncate(RzIOMMapFileObj *mmo, ut64 size) {
return rz_buf_resize(mmo->buf, size);
}
static bool __plugin_open_default(RzIO *io, const char *file, bool many) {
return rz_io_def_mmap_check_default(file);
}
// default open should permit opening
static RzIODesc *__open_default(RzIO *io, const char *file, int perm, int mode) {
if (rz_io_def_mmap_check_default(file)) {
return rz_io_def_mmap_open(io, file, perm, mode);
}
return NULL;
}
static int __read(RzIO *io, RzIODesc *fd, ut8 *buf, int len) {
return rz_io_def_mmap_read(io, fd, buf, len);
}
static int __write(RzIO *io, RzIODesc *fd, const ut8 *buf, int len) {
return rz_io_def_mmap_write(io, fd, buf, len);
}
static ut64 __lseek(RzIO *io, RzIODesc *fd, ut64 offset, int whence) {
return rz_io_def_mmap_lseek(io, fd, offset, whence);
}
static int __close(RzIODesc *fd) {
return rz_io_def_mmap_close(fd);
}
static bool __resize(RzIO *io, RzIODesc *fd, ut64 size) {
rz_return_val_if_fail(io && fd && fd->data, false);
RzIOMMapFileObj *mmo = fd->data;
if (!(mmo->perm & RZ_PERM_W)) {
return false;
}
return rz_io_def_mmap_truncate(mmo, size);
}
#if __UNIX__
static bool __is_blockdevice(RzIODesc *desc) {
rz_return_val_if_fail(desc && desc->data, false);
RzIOMMapFileObj *mmo = desc->data;
struct stat buf;
if (stat(mmo->filename, &buf) == -1) {
return false;
}
return ((buf.st_mode & S_IFBLK) == S_IFBLK);
}
#endif
static ut8 *io_default_get_buf(RzIODesc *desc, ut64 *size) {
rz_return_val_if_fail(desc && size, NULL);
RzIOMMapFileObj *mmo = desc->data;
return rz_buf_data(mmo->buf, size);
}
RzIOPlugin rz_io_plugin_default = {
.name = "default",
.desc = "Open local files",
.license = "LGPL3",
.uris = "file://,nocache://",
.open = __open_default,
.close = __close,
.read = __read,
.check = __plugin_open_default,
.lseek = __lseek,
.write = __write,
.resize = __resize,
#if __UNIX__
.is_blockdevice = __is_blockdevice,
#endif
.get_buf = io_default_get_buf
};
#ifndef RZ_PLUGIN_INCORE
RZ_API RzLibStruct rizin_plugin = {
.type = RZ_LIB_TYPE_IO,
.data = &rz_io_plugin_default,
.version = RZ_VERSION
};
#endif