Shorten copyright notice.
[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 char *result, *home = para_homedir();
35
36 srandom(clock_get_realtime(NULL)->tv_usec);
37 result = make_message("%s/.paraslash/%08ld", home,
38 para_random(99999999));
39 free(home);
40 return result;
41 }
42
43 static int prepare_output_file(struct writer_node *wn)
44 {
45 const unsigned flags = O_WRONLY | O_CREAT, mode = S_IRUSR | S_IWUSR;
46 int ret, fd;
47 struct private_file_write_data *pfwd;
48
49
50 if (WRITE_CMD_OPT_GIVEN(FILE, FILENAME, wn->lpr)) {
51 const char *path = WRITE_CMD_OPT_STRING_VAL(FILE, FILENAME,
52 wn->lpr);
53 ret = para_open(path, flags, mode);
54 } else {
55 char *path = random_filename();
56 ret = para_open(path, flags, mode);
57 free(path);
58 }
59 if (ret < 0)
60 return ret;
61 fd = ret;
62 ret = mark_fd_blocking(fd);
63 if (ret < 0) {
64 close(fd);
65 return ret;
66 }
67 pfwd = wn->private_data = para_calloc(sizeof(*pfwd));
68 pfwd->fd = fd;
69 return 1;
70 }
71
72 static void file_write_pre_select(struct sched *s, void *context)
73 {
74 struct writer_node *wn = context;
75 struct private_file_write_data *pfwd = wn->private_data;
76 int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
77
78 if (ret == 0)
79 return;
80 if (ret < 0 || !pfwd)
81 return sched_min_delay(s);
82 para_fd_set(pfwd->fd, &s->wfds, &s->max_fileno);
83 }
84
85 static void file_write_close(struct writer_node *wn)
86 {
87 struct private_file_write_data *pfwd = wn->private_data;
88
89 if (!pfwd)
90 return;
91 close(pfwd->fd);
92 free(pfwd);
93 }
94
95 static int file_write_post_select(__a_unused struct sched *s, void *context)
96 {
97 struct writer_node *wn = context;
98 struct private_file_write_data *pfwd = wn->private_data;
99 struct btr_node *btrn = wn->btrn;
100 int ret;
101 char *buf;
102 size_t bytes;
103
104 ret = task_get_notification(wn->task);
105 if (ret < 0)
106 goto out;
107 ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF);
108 if (ret <= 0)
109 goto out;
110 if (!pfwd) {
111 ret = prepare_output_file(wn);
112 goto out;
113 }
114 if (!FD_ISSET(pfwd->fd, &s->wfds))
115 return 0;
116 bytes = btr_next_buffer(btrn, &buf);
117 assert(bytes > 0);
118 //PARA_INFO_LOG("writing %zu\n", bytes);
119 ret = xwrite(pfwd->fd, buf, bytes);
120 if (ret < 0)
121 goto out;
122 btr_consume(btrn, ret);
123 out:
124 if (ret < 0)
125 btr_remove_node(&wn->btrn);
126 return ret;
127 }
128
129 /** the init function of the file writer */
130 struct writer lsg_write_cmd_com_file_user_data = {
131 .pre_select = file_write_pre_select,
132 .post_select = file_write_post_select,
133 .close = file_write_close,
134 };