]> git.tuebingen.mpg.de Git - paraslash.git/blob - file_write.c
Merge topic branch t/sf_float into pu
[paraslash.git] / file_write.c
1 /* Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file file_write.c simple output plugin for testing purposes */
4
5 #include <regex.h>
6 #include <sys/types.h>
7 #include <lopsub.h>
8
9 #include "write_cmd.lsg.h"
10 #include "para.h"
11 #include "list.h"
12 #include "sched.h"
13 #include "buffer_tree.h"
14 #include "write.h"
15 #include "string.h"
16 #include "fd.h"
17 #include "error.h"
18
19 /** Data specific to the file writer. */
20 struct private_file_write_data {
21         /** The file descriptor of the output file. */
22         int fd;
23 };
24
25 /*
26  * Get a random filename.
27  *
28  * This is by no means a secure way to create temporary files in a hostile
29  * directory like \p /tmp. However, we use it only for creating temp files in
30  * ~/.paraslash, for which it is OK. Result must be freed by the caller.
31  */
32 __must_check __malloc static char *random_filename(void)
33 {
34         srandom(clock_get_realtime(NULL)->tv_usec);
35         return make_message("%s/%08ld", get_confdir(), para_random(99999999));
36 }
37
38 static int prepare_output_file(struct writer_node *wn)
39 {
40         const unsigned flags = O_WRONLY | O_CREAT, mode = S_IRUSR | S_IWUSR;
41         int ret, fd;
42         struct private_file_write_data *pfwd;
43
44
45         if (WRITE_CMD_OPT_GIVEN(FILE, FILENAME, wn->lpr)) {
46                 const char *path = WRITE_CMD_OPT_STRING_VAL(FILE, FILENAME,
47                         wn->lpr);
48                 ret = para_open(path, flags, mode);
49         } else {
50                 char *path = random_filename();
51                 ret = para_open(path, flags, mode);
52                 free(path);
53         }
54         if (ret < 0)
55                 return ret;
56         fd = ret;
57         ret = mark_fd_blocking(fd);
58         if (ret < 0) {
59                 close(fd);
60                 return ret;
61         }
62         pfwd = wn->private_data = zalloc(sizeof(*pfwd));
63         pfwd->fd = fd;
64         return 1;
65 }
66
67 static void file_write_pre_monitor(struct sched *s, void *context)
68 {
69         struct writer_node *wn = context;
70         struct private_file_write_data *pfwd = wn->private_data;
71         int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
72
73         if (ret == 0)
74                 return;
75         if (ret < 0 || !pfwd)
76                 return sched_min_delay(s);
77         sched_monitor_writefd(pfwd->fd, s);
78 }
79
80 static void file_write_close(struct writer_node *wn)
81 {
82         struct private_file_write_data *pfwd = wn->private_data;
83
84         if (!pfwd)
85                 return;
86         close(pfwd->fd);
87         free(pfwd);
88 }
89
90 static int file_write_post_monitor(__a_unused struct sched *s, void *context)
91 {
92         struct writer_node *wn = context;
93         struct private_file_write_data *pfwd = wn->private_data;
94         struct btr_node *btrn = wn->btrn;
95         int ret;
96         char *buf;
97         size_t bytes;
98
99         ret = task_get_notification(wn->task);
100         if (ret < 0)
101                 goto out;
102         ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF);
103         if (ret <= 0)
104                 goto out;
105         if (!pfwd) {
106                 ret = prepare_output_file(wn);
107                 goto out;
108         }
109         if (!sched_write_ok(pfwd->fd, s))
110                 return 0;
111         bytes = btr_next_buffer(btrn, &buf);
112         assert(bytes > 0);
113         //PARA_INFO_LOG("writing %zu\n", bytes);
114         ret = xwrite(pfwd->fd, buf, bytes);
115         if (ret < 0)
116                 goto out;
117         btr_consume(btrn, ret);
118 out:
119         if (ret < 0)
120                 btr_remove_node(&wn->btrn);
121         return ret;
122 }
123
124 /** the init function of the file writer */
125 struct writer lsg_write_cmd_com_file_user_data = {
126         .pre_monitor = file_write_pre_monitor,
127         .post_monitor = file_write_post_monitor,
128         .close = file_write_close,
129 };