Line data Source code
1 : /* progress.c - emit progress status lines
2 : * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 : #include <stdio.h>
22 : #include <assert.h>
23 :
24 : #include "gpg.h"
25 : #include "iobuf.h"
26 : #include "filter.h"
27 : #include "status.h"
28 : #include "util.h"
29 : #include "options.h"
30 :
31 : /* Create a new context for use with the progress filter. We need to
32 : allocate such contexts on the heap because there is no guarantee
33 : that at the end of a function the filter has already been popped
34 : off. In general this will happen but with malformed packets it is
35 : possible that a filter has not yet reached the end-of-stream when
36 : the function has done all processing. Checking in each function
37 : that end-of-stream has been reached would be to cumbersome.
38 :
39 : What we also do is to shortcut the progress handler by having this
40 : function return NULL if progress information has not been
41 : requested.
42 : */
43 : progress_filter_context_t *
44 594 : new_progress_context (void)
45 : {
46 : progress_filter_context_t *pfx;
47 :
48 594 : if (!opt.enable_progress_filter)
49 594 : return NULL;
50 :
51 0 : if (!is_status_enabled ())
52 0 : return NULL;
53 :
54 0 : pfx = xcalloc (1, sizeof *pfx);
55 0 : pfx->refcount = 1;
56 :
57 0 : return pfx;
58 : }
59 :
60 : /* Release a progress filter context. Passing NULL is explicitly
61 : allowed and a no-op. */
62 : void
63 590 : release_progress_context (progress_filter_context_t *pfx)
64 : {
65 590 : if (!pfx)
66 590 : return;
67 0 : assert (pfx->refcount);
68 0 : if ( --pfx->refcount )
69 0 : return;
70 0 : xfree (pfx->what);
71 0 : xfree (pfx);
72 : }
73 :
74 :
75 : /****************
76 : * The filter is used to report progress to the user.
77 : */
78 : static int
79 0 : progress_filter (void *opaque, int control,
80 : IOBUF a, byte *buf, size_t *ret_len)
81 : {
82 0 : int rc = 0;
83 0 : progress_filter_context_t *pfx = opaque;
84 :
85 0 : if (control == IOBUFCTRL_INIT)
86 : {
87 : char buffer[50];
88 :
89 0 : pfx->last = 0;
90 0 : pfx->offset = 0;
91 0 : pfx->last_time = make_timestamp ();
92 :
93 0 : sprintf (buffer, "%.20s ? %lu %lu",
94 0 : pfx->what? pfx->what : "?",
95 : pfx->offset,
96 : pfx->total);
97 0 : write_status_text (STATUS_PROGRESS, buffer);
98 : }
99 0 : else if (control == IOBUFCTRL_UNDERFLOW)
100 : {
101 0 : u32 timestamp = make_timestamp ();
102 0 : int len = iobuf_read (a, buf, *ret_len);
103 :
104 0 : if (len >= 0)
105 : {
106 0 : pfx->offset += len;
107 0 : *ret_len = len;
108 : }
109 : else
110 : {
111 0 : *ret_len = 0;
112 0 : rc = -1;
113 : }
114 0 : if ((len == -1 && pfx->offset != pfx->last)
115 0 : || timestamp - pfx->last_time > 0)
116 : {
117 : char buffer[50];
118 :
119 0 : sprintf (buffer, "%.20s ? %lu %lu",
120 0 : pfx->what? pfx->what : "?",
121 : pfx->offset,
122 : pfx->total);
123 0 : write_status_text (STATUS_PROGRESS, buffer);
124 :
125 0 : pfx->last = pfx->offset;
126 0 : pfx->last_time = timestamp;
127 : }
128 : }
129 0 : else if (control == IOBUFCTRL_FREE)
130 : {
131 0 : release_progress_context (pfx);
132 : }
133 0 : else if (control == IOBUFCTRL_DESC)
134 0 : *(char**)buf = "progress_filter";
135 0 : return rc;
136 : }
137 :
138 : void
139 590 : handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name)
140 : {
141 590 : off_t filesize = 0;
142 :
143 590 : if (!pfx)
144 1180 : return;
145 :
146 0 : assert (opt.enable_progress_filter);
147 0 : assert (is_status_enabled ());
148 :
149 0 : if ( !iobuf_is_pipe_filename (name) && *name )
150 0 : filesize = iobuf_get_filelength (inp, NULL);
151 0 : else if (opt.set_filesize)
152 0 : filesize = opt.set_filesize;
153 :
154 : /* register the progress filter */
155 0 : pfx->what = xstrdup (name ? name : "stdin");
156 0 : pfx->total = filesize;
157 0 : pfx->refcount++;
158 0 : iobuf_push_filter (inp, progress_filter, pfx);
159 : }
|