/* SPDX-License-Identifier: LGPL-2.1-only */ /* Copyright (C) 2020 Gediminas Jakutis */ #include #include #include #include #include #include #include #include #include #include #include "io.h" #include "defs.h" #include "datagen.h" #include "cache.h" static int stream_open_in(struct stream * const in, const struct settings * const s); static int stream_open_out(struct stream * const in, const struct settings * const s); static int stream_open_special(struct stream * const in); int stream_open(struct stream * const in, const struct settings * const s) { int ret = 0; try(!in || in->fd > 0 || !in->name || !s, err, EINVAL); if (in->out == 1) { ret = stream_open_out(in, s); } else if (!in->out) { ret = stream_open_in(in, s); } else { ret = stream_open_special(in); } err: return ret; } int stream_close(struct stream * const in) { int ret = 0; try(!in || in->fd < 0, early_err, EINVAL); if (!in->out) { goto out; } if (in->name) { char path[PATH_MAX]; struct stat st; snprintf(path, PATH_MAX, "/proc/self/fd/%i", in->fd); if (!stat(in->name, &st)) { if (st.st_mode & S_IFREG) { unlink(in->name); } else { ret = EINVAL; /* TODO: error message */ goto err; } } try(linkat(AT_FDCWD, path, AT_FDCWD, in->name, AT_SYMLINK_FOLLOW), err, errno); } else { ret = EINVAL; goto err; } out: err: close(in->fd); in->fd = -1; early_err: return ret; } static int stream_open_out(struct stream * const in, const struct settings * const s) { struct stat st; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP; char *dname = NULL; char *tmp[2]; int ret = 0; tmp[0] = strdup(in->name); tmp[1] = dirname(tmp[0]); dname = strdup(tmp[1]); free(tmp[0]); try(stat(dname, &st), err, errno); try(!(st.st_mode & S_IFDIR), err, EINVAL); /* TODO: err msg */ if (!stat(in->name, &st)) { try(!(st.st_mode & S_IFREG), err, EINVAL); /* TODO: err msg */ mode = st.st_mode; } in->fd = open(dname, O_TMPFILE | O_WRONLY, mode); try(in->fd < 0, err, errno); /* TODO: err msg */ try(ftruncate(in->fd, s->stride * in->n), err, errno); /* TODO: err msg */ err: free(dname); return ret; } static int stream_open_in(struct stream * const in, const struct settings * const s) { struct stat st; int ret = 0; try(stat(in->name, &st), err, errno); /* TODO: err msg */ try(!(st.st_mode & S_IFREG) || !st.st_size || (st.st_size % s->stride), err, EINVAL); /* TODO: err msg */ in->n = st.st_size / s->stride; in->fd = open(in->name, O_RDONLY | O_NOATIME); try(in->fd < 0, err, errno); /* TODO: err msg */ if (in->cached) { cache_create(in, s); cache_populate(in); } err: return ret; } static int stream_open_special(struct stream * const in) { struct stat st; int ret = 0; try(stat(in->name, &st), err, errno); /* TODO: err msg */ in->fd = open(in->name, O_RDONLY | O_NOATIME); try(in->fd < 0, err, errno); /* TODO: err msg */ err: return ret; }