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