99c88937af6e5c2fbaa5a23119c8560af0b02863
[debian/amanda] / server-src / taper-port-source.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 2005-2008 Zmanda Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #define selfp (self->_priv)
21
22 #include "taper-port-source.h"
23
24 /* here are local prototypes */
25 static void taper_port_source_class_init (TaperPortSourceClass * c);
26 static ssize_t taper_port_source_read (TaperSource * pself, void * buf,
27                                        size_t count);
28 static void taper_port_source_init (TaperPortSource * self);
29 static gboolean taper_port_source_is_partial(TaperSource * self);
30 static int taper_port_source_predict_parts(TaperSource * pself);
31 static dumpfile_t * taper_port_source_get_first_header(TaperSource * pself);
32
33
34 /* pointer to the class of our parent */
35 static TaperSourceClass *parent_class = NULL;
36
37 GType
38 taper_port_source_get_type (void)
39 {
40     static GType type = 0;
41     
42     if G_UNLIKELY(type == 0) {
43         static const GTypeInfo info = {
44             sizeof (TaperPortSourceClass),
45             (GBaseInitFunc) NULL,
46             (GBaseFinalizeFunc) NULL,
47             (GClassInitFunc) taper_port_source_class_init,
48             (GClassFinalizeFunc) NULL,
49             NULL /* class_data */,
50             sizeof (TaperPortSource),
51             0 /* n_preallocs */,
52             (GInstanceInitFunc) taper_port_source_init,
53             NULL
54         };
55         
56         type = g_type_register_static (TAPER_SOURCE_TYPE, "TaperPortSource",
57                                        &info, (GTypeFlags)0);
58     }
59     
60     return type;
61 }
62
63 static void taper_port_source_finalize(GObject * obj_self) {
64     TaperPortSource *self = TAPER_PORT_SOURCE(obj_self);
65     if (self->socket_fd >= 0) {
66         aclose(self->socket_fd);
67     }
68     
69     G_OBJECT_CLASS (parent_class)->finalize (obj_self);
70 }
71
72 static void taper_port_source_class_init (TaperPortSourceClass * c) {
73     TaperSourceClass *taper_source_class = (TaperSourceClass *)c;
74     GObjectClass *g_object_class = (GObjectClass*)c;
75     
76     parent_class = g_type_class_ref (TAPER_SOURCE_TYPE);
77
78     taper_source_class->read = taper_port_source_read;
79     taper_source_class->is_partial = taper_port_source_is_partial;
80     taper_source_class->get_first_header = taper_port_source_get_first_header;
81     taper_source_class->predict_parts = taper_port_source_predict_parts;
82
83     g_object_class->finalize = taper_port_source_finalize;
84 }
85
86 /* Check if the header has been read; if not, read and parse it. */
87 static void check_first_header(TaperPortSource * self) {
88     TaperSource * pself = (TaperSource*)self;
89     char buf[DISK_BLOCK_BYTES];
90     size_t result;
91     dumpfile_t * rval;
92     
93     if (G_LIKELY(pself->first_header != NULL)) {
94         return;
95     }
96     
97     result = full_read(self->socket_fd, buf, DISK_BLOCK_BYTES);
98     if (result != DISK_BLOCK_BYTES) {
99         return;
100     }
101     rval = malloc(sizeof(dumpfile_t));
102     parse_file_header(buf, rval, DISK_BLOCK_BYTES);
103     pself->first_header = rval;
104 }
105
106 static int taper_port_source_predict_parts(TaperSource * pself) {
107     TaperPortSource * self = TAPER_PORT_SOURCE(pself);
108     g_return_val_if_fail(self != NULL, -1);
109
110     return 1;
111 }
112
113 static dumpfile_t * taper_port_source_get_first_header(TaperSource * pself) {
114     TaperPortSource * self = TAPER_PORT_SOURCE(pself);
115     g_return_val_if_fail(self != NULL, NULL);
116
117     check_first_header(self);
118     
119     if (parent_class->get_first_header) {
120         return (parent_class->get_first_header)(pself);
121     } else {
122         return NULL;
123     }
124 }
125
126 static void taper_port_source_init (TaperPortSource * self) {
127     /* Subclasses may do as they please, but if we are the final word,
128        then there will be no rewinding. */
129     if (G_TYPE_FROM_INSTANCE(self) == TAPER_TYPE_PORT_SOURCE) {
130         TAPER_SOURCE(self)->max_part_size = 0;
131     }
132     self->socket_fd = -1;
133 }
134
135 static ssize_t taper_port_source_read (TaperSource * pself, void * buf,
136                                        size_t count) {
137     TaperPortSource * self = (TaperPortSource*)pself;
138     int read_result;
139     g_return_val_if_fail (self != NULL, -1);
140     g_return_val_if_fail (TAPER_IS_PORT_SOURCE (pself), -1);
141     g_return_val_if_fail (buf != NULL, -1);
142     g_return_val_if_fail (count > 0, -1);
143     
144     check_first_header(self);
145
146     for (;;) {
147         read_result = read(self->socket_fd, buf, count);
148         if (read_result > 0) {
149             return read_result;
150         } else if (read_result == 0) {
151             pself->end_of_data = TRUE;
152             aclose(self->socket_fd);
153             return 0;
154         } else if (0
155 #ifdef EAGAIN
156                    || errno == EAGAIN
157 #endif
158 #ifdef EWOULDBLOCK
159                    || errno == EWOULDBLOCK
160 #endif
161 #ifdef EINTR
162                    || errno == EINTR
163 #endif
164                    ) {
165             /* Try again. */
166             continue;
167         } else {
168             /* Error occured. */
169             return read_result;
170         }
171     }
172     
173     g_assert_not_reached();
174 }
175
176 static gboolean
177 taper_port_source_is_partial(TaperSource * pself) {
178     struct cmdargs *cmdargs;
179     gboolean result;
180     TaperPortSource * self = (TaperPortSource*)pself;
181
182     if (self->socket_fd >= 0)
183         return FALSE;
184
185     /* Query DRIVER about partial dump. */
186     putresult(DUMPER_STATUS, "%s\n", pself->driver_handle);
187     cmdargs = getcmd();
188     if (cmdargs->cmd == FAILED) {
189         result = TRUE;
190     } else if (cmdargs->cmd == DONE) {
191         result = FALSE;
192     } else {
193         error("Driver gave invalid response "
194               "to query DUMPER-STATUS.\n");
195         g_assert_not_reached();
196     }
197
198     free_cmdargs(cmdargs);
199     return result;
200 }