More file scaffolding.

This commit is contained in:
Ian Gulliver
2016-03-02 14:23:58 -08:00
parent 3e5ca27fdf
commit 58177c93a6
2 changed files with 92 additions and 9 deletions

View File

@@ -123,9 +123,11 @@ void exec_new(char *command, struct flow *flow, void *passthrough) {
(*flow->ref_count)++; (*flow->ref_count)++;
struct exec *exec = malloc(sizeof(*exec)); struct exec *exec = malloc(sizeof(*exec));
assert(exec);
exec->peer.fd = -1; exec->peer.fd = -1;
uuid_gen(exec->id); uuid_gen(exec->id);
exec->command = strdup(command); exec->command = strdup(command);
assert(exec->command);
exec->flow = flow; exec->flow = flow;
exec->passthrough = passthrough; exec->passthrough = passthrough;

View File

@@ -1,23 +1,104 @@
#include <stdlib.h> #include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "flow.h" #include "flow.h"
#include "list.h"
#include "peer.h"
#include "receive.h" #include "receive.h"
#include "send.h" #include "send.h"
#include "uuid.h"
#include "file.h" #include "file.h"
static void file_open_new(char *path, struct flow *flow, void *passthrough, int flags) { struct file {
int fd = open(path, flags | O_CLOEXEC, S_IRUSR | S_IWUSR); struct peer peer;
uint8_t id[UUID_LEN];
char *path;
int flags;
struct flow *flow;
void *passthrough;
bool retry;
struct list_head file_list;
};
static struct list_head file_head = LIST_HEAD_INIT(file_head);
static bool file_should_retry(int fd, struct file *file) {
// We want to retry most files, except if we're reading from a regular file
if (!file->flags & O_RDONLY) {
return true;
}
// Questionable heuristic time. We're going to test if the kernel driver for
// this fd supports polling. If it does, we assume that we have a character
// device, named pipe, or something else that is likely to give us different
// data if we read it again.
int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
assert(epoll_fd >= 0);
struct epoll_event ev = {
.events = 0,
.data = {
.ptr = NULL,
},
};
int res = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
assert(!close(epoll_fd));
return (res == 0);
}
static void file_del(struct file *file) {
(*file->flow->ref_count)--;
list_del(&file->file_list);
free(file->path);
free(file);
}
static void file_handle_close(struct peer *peer) {
struct file *file = (struct file *) peer;
file_del(file);
}
static void file_open(struct file *file) {
int fd = open(file->path, file->flags | O_CLOEXEC, S_IRUSR | S_IWUSR);
if (fd == -1) { if (fd == -1) {
// TODO: log error; retry? // TODO: log error; retry?
return; return;
} }
file_fd_new(fd, flow, passthrough);
file->retry = file_should_retry(fd, file);
file->peer.event_handler = file_handle_close;
file->flow->new(fd, file->passthrough, (struct peer *) file);
// TODO: log error; retry?
flow_hello(fd, file->flow, file->passthrough);
} }
static void file_new(char *path, int flags, struct flow *flow, void *passthrough) {
(*flow->ref_count)++;
struct file *file = malloc(sizeof(*file));
assert(file);
file->peer.fd = -1;
uuid_gen(file->id);
file->path = strdup(path);
assert(file->path);
file->flags = flags;
file->flow = flow;
file->passthrough = passthrough;
list_add(&file->file_list, &file_head);
file_open(file);
}
// TODO: this code probably belongs elsewhere
void file_fd_new(int fd, struct flow *flow, void *passthrough) { void file_fd_new(int fd, struct flow *flow, void *passthrough) {
flow->new(fd, passthrough, NULL); flow->new(fd, passthrough, NULL);
// TODO: log error; retry? // TODO: log error; retry?
@@ -25,13 +106,13 @@ void file_fd_new(int fd, struct flow *flow, void *passthrough) {
} }
void file_read_new(char *path, struct flow *flow, void *passthrough) { void file_read_new(char *path, struct flow *flow, void *passthrough) {
file_open_new(path, flow, passthrough, O_RDONLY); file_new(path, O_RDONLY, flow, passthrough);
} }
void file_write_new(char *path, struct flow *flow, void *passthrough) { void file_write_new(char *path, struct flow *flow, void *passthrough) {
file_open_new(path, flow, passthrough, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC); file_new(path, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, flow, passthrough);
} }
void file_append_new(char *path, struct flow *flow, void *passthrough) { void file_append_new(char *path, struct flow *flow, void *passthrough) {
file_open_new(path, flow, passthrough, O_WRONLY | O_CREAT | O_NOFOLLOW); file_new(path, O_WRONLY | O_CREAT | O_NOFOLLOW, flow, passthrough);
} }