1 /*
2  * Copyright (c) 2007-2013 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  *
18  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  */
21 
22 #include "amanda.h"
23 #include <string.h> /* memset() */
24 #include "fsusage.h"
25 #include "util.h"
26 #include <regex.h>
27 
28 #include "vfs-device.h"
29 
30 /* This regex will match all VfsDevice files in a directory. We use it
31    for cleanup and verification. Note that this regex does NOT match
32    the volume label. */
33 #define VFS_DEVICE_FILE_REGEX "^[0-9]+[\\.-]"
34 
35 /* The name of the volume lockfile. Should be the same as that
36    generated by lockfile_name(0). */
37 #define VOLUME_LOCKFILE_NAME "00000-lock"
38 
39 #define VFS_DEVICE_MIN_BLOCK_SIZE (1)
40 #define VFS_DEVICE_MAX_BLOCK_SIZE (INT_MAX)
41 #define VFS_DEVICE_DEFAULT_BLOCK_SIZE (DISK_BLOCK_BYTES)
42 #define VFS_DEVICE_LABEL_SIZE (32768)
43 
44 /* Allow comfortable room for another block and a header before PEOM */
45 #define EOM_EARLY_WARNING_ZONE_BLOCKS 4
46 
47 /* Constants for free-space monitoring */
48 #define MONITOR_FREE_SPACE_EVERY_SECONDS 5
49 #define MONITOR_FREE_SPACE_EVERY_KB 102400
50 #define MONITOR_FREE_SPACE_CLOSELY_WITHIN_BLOCKS 128
51 
52 /* This looks dangerous, but is actually modified by the umask. */
53 #define VFS_DEVICE_CREAT_MODE 0666
54 
55 /* Possible (abstracted) results from a system I/O operation. */
56 typedef enum {
57     RESULT_SUCCESS,
58     RESULT_ERROR,        /* Undefined error. */
59     RESULT_NO_DATA,      /* End of File, while reading */
60     RESULT_NO_SPACE,     /* Out of space. Sometimes we don't know if
61                             it was this or I/O error, but this is the
62                             preferred explanation. */
63     RESULT_MAX
64 } IoResult;
65 
66 void vfs_device_register(void);
67 
68 /* here are local prototypes */
69 static void vfs_device_init (VfsDevice * o);
70 static void vfs_device_class_init (VfsDeviceClass * c);
71 static void vfs_device_base_init (VfsDeviceClass * c);
72 static void vfs_device_finalize (GObject * o);
73 
74 static gboolean vfs_device_start(Device * pself, DeviceAccessMode mode,
75                                  char * label, char * timestamp);
76 static gboolean vfs_device_finish (Device * pself);
77 static void vfs_device_open_device (Device * pself, char * device_name,
78 				char * device_type, char * device_node);
79 static gboolean vfs_device_start_file (Device * pself, dumpfile_t * ji);
80 static gboolean vfs_device_finish_file (Device * dself);
81 static dumpfile_t * vfs_device_seek_file (Device * self, guint file);
82 static gboolean vfs_device_seek_block (Device * self, guint64 block);
83 static gboolean vfs_device_recycle_file (Device * pself, guint filenum);
84 static gboolean vfs_device_erase (Device * pself);
85 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node);
86 static DeviceStatusFlags vfs_device_read_label(Device * dself);
87 static gboolean vfs_device_write_block(Device * self, guint size, gpointer data);
88 static int vfs_device_read_block(Device * self, gpointer data, int * size_req);
89 static IoResult vfs_device_robust_write(VfsDevice * self,  char *buf,
90                                               int count);
91 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
92                                              int *count);
93 
94 /* Various helper functions. */
95 static void release_file(VfsDevice * self);
96 static gboolean check_is_dir(VfsDevice * self, const char * name);
97 static char * file_number_to_file_name(VfsDevice * self, guint file);
98 static gboolean file_number_to_file_name_functor(const char * filename,
99                                                  gpointer datap);
100 static gboolean vfs_device_set_max_volume_usage_fn(Device *p_self,
101 			    DevicePropertyBase *base, GValue *val,
102 			    PropertySurety surety, PropertySource source);
103 static gboolean vfs_device_set_enforce_max_volume_usage_fn(Device *p_self,
104 			    DevicePropertyBase *base, GValue *val,
105 			    PropertySurety surety, PropertySource source);
106 static gboolean property_get_monitor_free_space_fn(Device *p_self,
107 			    DevicePropertyBase *base, GValue *val,
108 			    PropertySurety *surety, PropertySource *source);
109 static gboolean property_set_monitor_free_space_fn(Device *p_self,
110 			    DevicePropertyBase *base, GValue *val,
111 			    PropertySurety surety, PropertySource source);
112 static gboolean property_set_leom_fn(Device *p_self,
113 			    DevicePropertyBase *base, GValue *val,
114 			    PropertySurety surety, PropertySource source);
115 //static char* lockfile_name(VfsDevice * self, guint file);
116 static gboolean open_lock(VfsDevice * self, int file, gboolean exclusive);
117 static void promote_volume_lock(VfsDevice * self);
118 static void demote_volume_lock(VfsDevice * self);
119 static gboolean delete_vfs_files_functor(const char * filename,
120                                          gpointer self);
121 static gboolean check_dir_empty_functor(const char * filename,
122                                         gpointer self);
123 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
124                                         char * timestamp);
125 static int search_vfs_directory(VfsDevice *self, const char * regex,
126 			SearchDirectoryFunctor functor, gpointer user_data);
127 static gint get_last_file_number(VfsDevice * self);
128 static gboolean get_last_file_number_functor(const char * filename,
129                                              gpointer datap);
130 static char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji);
131 static gboolean try_unlink(const char * file);
132 
133 /* return TRUE if the device is going to hit ENOSPC "soon" - this is used to
134  * detect LEOM as represented by actually running out of space on the
135  * underlying filesystem.  Size is the size of the buffer that is about to
136  * be written. */
137 static gboolean check_at_leom(VfsDevice *self, guint64 size);
138 /* Similar, but for PEOM */
139 static gboolean check_at_peom(VfsDevice *self, guint64 size);
140 
141 /* pointer to the classes of our parents */
142 static DeviceClass *parent_class = NULL;
143 
144 /* device-specific properties */
145 DevicePropertyBase device_property_monitor_free_space;
146 #define PROPERTY_MONITOR_FREE_SPACE (device_property_monitor_free_space.ID)
147 
vfs_device_register(void)148 void vfs_device_register(void) {
149     static const char * device_prefix_list[] = { "file", NULL };
150 
151     device_property_fill_and_register(&device_property_monitor_free_space,
152                                       G_TYPE_BOOLEAN, "monitor_free_space",
153       "Should VFS device monitor the filesystem's available free space?");
154 
155     register_device(vfs_device_factory, device_prefix_list);
156 }
157 
158 GType
vfs_device_get_type(void)159 vfs_device_get_type (void)
160 {
161     static GType type = 0;
162 
163     if G_UNLIKELY(type == 0) {
164         static const GTypeInfo info = {
165             sizeof (VfsDeviceClass),
166             (GBaseInitFunc) vfs_device_base_init,
167             (GBaseFinalizeFunc) NULL,
168             (GClassInitFunc) vfs_device_class_init,
169             (GClassFinalizeFunc) NULL,
170             NULL /* class_data */,
171             sizeof (VfsDevice),
172             0 /* n_preallocs */,
173             (GInstanceInitFunc) vfs_device_init,
174             NULL
175         };
176 
177         type = g_type_register_static (TYPE_DEVICE, "VfsDevice",
178                                        &info, (GTypeFlags)0);
179     }
180 
181     return type;
182 }
183 
184 static void
vfs_device_init(VfsDevice * self)185 vfs_device_init (VfsDevice * self) {
186     Device * dself = DEVICE(self);
187     GValue response;
188 
189     self->dir_name = self->file_name = NULL;
190     self->open_file_fd = -1;
191     self->volume_bytes = 0;
192     self->volume_limit = 0;
193     self->leom = TRUE;
194     self->enforce_volume_limit = TRUE;
195 
196     self->monitor_free_space = TRUE;
197     self->checked_fs_free_bytes = G_MAXUINT64;
198     self->checked_fs_free_time = 0;
199     self->checked_fs_free_bytes = G_MAXUINT64;
200 
201     /* Register Properties */
202     bzero(&response, sizeof(response));
203 
204     g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
205     g_value_set_enum(&response, CONCURRENCY_PARADIGM_RANDOM_ACCESS);
206     device_set_simple_property(dself, PROPERTY_CONCURRENCY,
207 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
208     g_value_unset(&response);
209 
210     g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
211     g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
212     device_set_simple_property(dself, PROPERTY_STREAMING,
213 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
214     g_value_unset(&response);
215 
216     g_value_init(&response, G_TYPE_BOOLEAN);
217     g_value_set_boolean(&response, TRUE);
218     device_set_simple_property(dself, PROPERTY_APPENDABLE,
219 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
220     g_value_unset(&response);
221 
222     g_value_init(&response, G_TYPE_BOOLEAN);
223     g_value_set_boolean(&response, TRUE);
224     device_set_simple_property(dself, PROPERTY_PARTIAL_DELETION,
225 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
226     g_value_unset(&response);
227 
228     g_value_init(&response, G_TYPE_BOOLEAN);
229     g_value_set_boolean(&response, TRUE);
230     device_set_simple_property(dself, PROPERTY_FULL_DELETION,
231 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
232     g_value_unset(&response);
233 
234     g_value_init(&response, G_TYPE_BOOLEAN);
235     g_value_set_boolean(&response, TRUE);
236     device_set_simple_property(dself, PROPERTY_LEOM,
237 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
238     g_value_unset(&response);
239 
240     g_value_init(&response, G_TYPE_BOOLEAN);
241     g_value_set_boolean(&response, TRUE);
242     device_set_simple_property(dself, PROPERTY_ENFORCE_MAX_VOLUME_USAGE,
243 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
244     g_value_unset(&response);
245 
246     g_value_init(&response, G_TYPE_BOOLEAN);
247     g_value_set_boolean(&response, FALSE);
248     device_set_simple_property(dself, PROPERTY_COMPRESSION,
249 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
250     g_value_unset(&response);
251 
252     g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
253     g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
254     device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE,
255 	    &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
256     g_value_unset(&response);
257 }
258 
259 static void
vfs_device_class_init(VfsDeviceClass * c)260 vfs_device_class_init (VfsDeviceClass * c)
261 {
262     GObjectClass *g_object_class = (GObjectClass*) c;
263     DeviceClass *device_class = DEVICE_CLASS(c);
264 
265     parent_class = g_type_class_ref(TYPE_DEVICE);
266 
267     device_class->open_device = vfs_device_open_device;
268     device_class->start = vfs_device_start;
269     device_class->start_file = vfs_device_start_file;
270     device_class->read_label = vfs_device_read_label;
271     device_class->write_block = vfs_device_write_block;
272     device_class->read_block = vfs_device_read_block;
273     device_class->finish_file = vfs_device_finish_file;
274     device_class->seek_file = vfs_device_seek_file;
275     device_class->seek_block = vfs_device_seek_block;
276     device_class->recycle_file = vfs_device_recycle_file;
277     device_class->erase = vfs_device_erase;
278     device_class->finish = vfs_device_finish;
279 
280     g_object_class->finalize = vfs_device_finalize;
281 }
282 
283 static void
vfs_device_base_init(VfsDeviceClass * c)284 vfs_device_base_init (VfsDeviceClass * c)
285 {
286     DeviceClass *device_class = (DeviceClass *)c;
287 
288     device_class_register_property(device_class, PROPERTY_MONITOR_FREE_SPACE,
289 	    PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK,
290 	    property_get_monitor_free_space_fn,
291 	    property_set_monitor_free_space_fn);
292 
293     device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE,
294 	    (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
295 			(~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE),
296 	    device_simple_property_get_fn,
297 	    vfs_device_set_max_volume_usage_fn);
298 
299     device_class_register_property(device_class, PROPERTY_ENFORCE_MAX_VOLUME_USAGE,
300             (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
301                         (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE),
302             device_simple_property_get_fn,
303             vfs_device_set_enforce_max_volume_usage_fn);
304 
305     device_class_register_property(device_class, PROPERTY_COMPRESSION,
306 	    PROPERTY_ACCESS_GET_MASK,
307 	    device_simple_property_get_fn,
308 	    NULL);
309 
310     /* add the ability to set LEOM to FALSE, for testing purposes */
311     device_class_register_property(device_class, PROPERTY_LEOM,
312 	    PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
313 	    device_simple_property_get_fn,
314 	    property_set_leom_fn);
315 }
316 
317 static gboolean
vfs_device_set_max_volume_usage_fn(Device * p_self,DevicePropertyBase * base,GValue * val,PropertySurety surety,PropertySource source)318 vfs_device_set_max_volume_usage_fn(Device *p_self,
319     DevicePropertyBase *base, GValue *val,
320     PropertySurety surety, PropertySource source)
321 {
322     VfsDevice *self = VFS_DEVICE(p_self);
323 
324     self->volume_limit = g_value_get_uint64(val);
325 
326     return device_simple_property_set_fn(p_self, base, val, surety, source);
327 }
328 
329 static gboolean
vfs_device_set_enforce_max_volume_usage_fn(Device * p_self,DevicePropertyBase * base,GValue * val,PropertySurety surety,PropertySource source)330 vfs_device_set_enforce_max_volume_usage_fn(Device *p_self,
331     DevicePropertyBase *base, GValue *val,
332     PropertySurety surety, PropertySource source)
333 {
334     VfsDevice *self = VFS_DEVICE(p_self);
335 
336     self->enforce_volume_limit = g_value_get_boolean(val);
337 
338     return device_simple_property_set_fn(p_self, base, val, surety, source);
339 }
340 
341 static gboolean
property_get_monitor_free_space_fn(Device * p_self,DevicePropertyBase * base G_GNUC_UNUSED,GValue * val,PropertySurety * surety,PropertySource * source)342 property_get_monitor_free_space_fn(Device *p_self, DevicePropertyBase *base G_GNUC_UNUSED,
343     GValue *val, PropertySurety *surety, PropertySource *source)
344 {
345     VfsDevice *self = VFS_DEVICE(p_self);
346 
347     g_value_unset_init(val, G_TYPE_BOOLEAN);
348     g_value_set_boolean(val, self->monitor_free_space);
349 
350     if (surety)
351 	*surety = PROPERTY_SURETY_GOOD;
352 
353     if (source)
354 	*source = PROPERTY_SOURCE_DEFAULT;
355 
356     return TRUE;
357 }
358 
359 
360 static gboolean
property_set_monitor_free_space_fn(Device * p_self,DevicePropertyBase * base,GValue * val,PropertySurety surety,PropertySource source)361 property_set_monitor_free_space_fn(Device *p_self,
362     DevicePropertyBase *base, GValue *val,
363     PropertySurety surety, PropertySource source)
364 {
365     VfsDevice *self = VFS_DEVICE(p_self);
366 
367     self->monitor_free_space = g_value_get_boolean(val);
368 
369     return device_simple_property_set_fn(p_self, base, val, surety, source);
370 }
371 
372 static gboolean
property_set_leom_fn(Device * p_self,DevicePropertyBase * base,GValue * val,PropertySurety surety,PropertySource source)373 property_set_leom_fn(Device *p_self,
374     DevicePropertyBase *base, GValue *val,
375     PropertySurety surety, PropertySource source)
376 {
377     VfsDevice *self = VFS_DEVICE(p_self);
378 
379     self->leom = g_value_get_boolean(val);
380 
381     return device_simple_property_set_fn(p_self, base, val, surety, source);
382 }
383 
384 /* Drops everything associated with the volume file: Its name and fd. */
release_file(VfsDevice * self)385 void release_file(VfsDevice * self) {
386     /* Doesn't hurt. */
387     if (self->open_file_fd != -1)
388 	robust_close(self->open_file_fd);
389     amfree(self->file_name);
390 
391     self->open_file_fd = -1;
392 }
393 
vfs_device_finalize(GObject * obj_self)394 static void vfs_device_finalize(GObject * obj_self) {
395     VfsDevice *self = VFS_DEVICE (obj_self);
396     Device * d_self = (Device*)self;
397 
398     if (d_self->access_mode != ACCESS_NULL) {
399         device_finish(d_self);
400     }
401 
402     if(G_OBJECT_CLASS(parent_class)->finalize)
403         (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
404 
405     amfree(self->dir_name);
406 
407     release_file(self);
408 }
409 
vfs_device_factory(char * device_name,char * device_type,char * device_node)410 static Device * vfs_device_factory(char * device_name, char * device_type, char * device_node) {
411     Device * rval;
412     g_assert(0 == strcmp(device_type, "file"));
413     rval = DEVICE(g_object_new(TYPE_VFS_DEVICE, NULL));
414     device_open_device(rval, device_name, device_type, device_node);
415     return rval;
416 }
417 
check_is_dir(VfsDevice * self,const char * name)418 static gboolean check_is_dir(VfsDevice * self, const char * name) {
419     Device *dself = DEVICE(self);
420     struct stat dir_status;
421 
422     if (stat(name, &dir_status) < 0) {
423 #ifdef EINTR
424         if (errno == EINTR) {
425             return check_is_dir(self, name);
426         }
427 #endif /* EINTR */
428 	device_set_error(dself,
429 	    vstrallocf(_("Error checking directory %s: %s"), name, strerror(errno)),
430 	    DEVICE_STATUS_DEVICE_ERROR);
431         return FALSE;
432     } else if (!S_ISDIR(dir_status.st_mode)) {
433 	device_set_error(dself,
434 		    vstrallocf(_("VFS Device path %s is not a directory"), name),
435 		    DEVICE_STATUS_DEVICE_ERROR);
436         return FALSE;
437     } else {
438         return TRUE;
439     }
440 }
441 
442 typedef struct {
443     VfsDevice * self;
444     int count;
445     char * result;
446 } fnfn_data;
447 
448 /* A SearchDirectoryFunctor. */
file_number_to_file_name_functor(const char * filename,gpointer datap)449 static gboolean file_number_to_file_name_functor(const char * filename,
450                                                  gpointer datap) {
451     char * result_tmp;
452     struct stat file_status;
453     fnfn_data *data = (fnfn_data*)datap;
454 
455     result_tmp = vstralloc(data->self->dir_name, "/", filename, NULL);
456 
457     /* Just to be thorough, let's check that it's a real
458        file. */
459     if (0 != stat(result_tmp, &file_status)) {
460 	g_warning(_("Cannot stat file %s (%s), ignoring it"), result_tmp, strerror(errno));
461     } else if (!S_ISREG(file_status.st_mode)) {
462 	g_warning(_("%s is not a regular file, ignoring it"), result_tmp);
463     } else {
464         data->count ++;
465         if (data->result == NULL) {
466             data->result = result_tmp;
467             result_tmp = NULL;
468         }
469     }
470     amfree(result_tmp);
471     return TRUE;
472 }
473 
474 /* This function finds the filename for a given file number. We search
475  * for a filesystem file matching the regex /^0*$device_file\./; if
476  * there is more than one such file we make a warning and take an
477  * arbitrary one. */
file_number_to_file_name(VfsDevice * self,guint device_file)478 static char * file_number_to_file_name(VfsDevice * self, guint device_file) {
479     char * regex;
480     fnfn_data data;
481 
482     data.self = self;
483     data.count = 0;
484     data.result = NULL;
485 
486     regex = g_strdup_printf("^0*%u\\.", device_file);
487 
488     search_vfs_directory(self, regex,
489                          file_number_to_file_name_functor, &data);
490 
491     amfree(regex);
492 
493     if (data.count == 0) {
494         g_assert(data.result == NULL);
495         return NULL;
496     } else if (data.count > 1) {
497 	g_warning("Found multiple names for file number %d, choosing file %s",
498                 device_file, data.result);
499         return data.result;
500     } else {
501         g_assert(data.result != NULL);
502         return data.result;
503     }
504     g_assert_not_reached();
505 }
506 
507 /* This function returns the dynamically-allocated lockfile name for a
508    given file number. */
509 /*
510 static char * lockfile_name(VfsDevice * self, guint number) {
511     return g_strdup_printf("%s/%05d-lock", self->dir_name, number);
512 }
513 */
514 
515 /* Does what you expect. If the lock already exists, it is released
516  * and regained, in case the mode is changing.
517  * The file field has several options:
518  * - file > 0: Open a lock on a real volume file.
519  * - file = 0: Open the volume lock as a volume file (for setup).
520  * - file < 0: Open the volume lock as a volume lock (persistantly).
521  */
open_lock(G_GNUC_UNUSED VfsDevice * self,G_GNUC_UNUSED int file,G_GNUC_UNUSED gboolean exclusive)522 static gboolean open_lock(G_GNUC_UNUSED VfsDevice * self,
523 			  G_GNUC_UNUSED int file,
524 			  G_GNUC_UNUSED gboolean exclusive) {
525 
526     /* At the moment, file locking is horribly broken. */
527     return TRUE;
528 }
529 
530 /* For now, does it the bad way. */
promote_volume_lock(VfsDevice * self G_GNUC_UNUSED)531 static void promote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
532 }
533 
demote_volume_lock(VfsDevice * self G_GNUC_UNUSED)534 static void demote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
535 }
536 
537 /* A SearchDirectoryFunctor */
update_volume_size_functor(const char * filename,gpointer user_data)538 static gboolean update_volume_size_functor(const char * filename,
539                                            gpointer user_data) {
540     char * full_filename;
541     struct stat stat_buf;
542     VfsDevice * self = VFS_DEVICE(user_data);
543 
544     full_filename = vstralloc(self->dir_name, "/", filename, NULL);
545 
546     if (stat(full_filename, &stat_buf) < 0) {
547         /* Log it and keep going. */
548 	g_warning(_("Couldn't stat file %s: %s"), full_filename, strerror(errno));
549         amfree(full_filename);
550         return TRUE;
551     }
552 
553     amfree(full_filename);
554     self->volume_bytes += stat_buf.st_size;
555 
556     return TRUE;
557 }
558 
update_volume_size(VfsDevice * self)559 static void update_volume_size(VfsDevice * self) {
560 
561     self->volume_bytes = 0;
562     search_vfs_directory(self, "^[0-9]+\\.",
563                          update_volume_size_functor, self);
564 
565 }
566 
567 static void
vfs_device_open_device(Device * pself,char * device_name,char * device_type,char * device_node)568 vfs_device_open_device (Device * pself, char * device_name, char * device_type, char * device_node) {
569     VfsDevice * self;
570     self = VFS_DEVICE(pself);
571 
572     pself->min_block_size = VFS_DEVICE_MIN_BLOCK_SIZE;
573     pself->max_block_size = VFS_DEVICE_MAX_BLOCK_SIZE;
574     pself->block_size = VFS_DEVICE_DEFAULT_BLOCK_SIZE;
575 
576     /* We don't have to free this ourselves; it will be freed by
577      * vfs_device_finalize whether we succeed here or not. */
578     self->dir_name = g_strconcat(device_node, "/data/", NULL);
579 
580     if (parent_class->open_device) {
581         parent_class->open_device(pself, device_name, device_type, device_node);
582     }
583 }
584 
585 /* A SearchDirectoryFunctor */
delete_vfs_files_functor(const char * filename,gpointer user_data)586 static gboolean delete_vfs_files_functor(const char * filename,
587                                          gpointer user_data) {
588     VfsDevice * self;
589     char * path_name;
590 
591     self = VFS_DEVICE(user_data);
592 
593     /* Skip the volume lock. */
594     if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
595         return TRUE;
596 
597     path_name = vstralloc(self->dir_name, "/", filename, NULL);
598     if (unlink(path_name) != 0) {
599 	g_warning(_("Error unlinking %s: %s"), path_name, strerror(errno));
600     }
601     amfree(path_name);
602     return TRUE;
603 }
604 
605 /* delete_vfs_files deletes all VfsDevice files in the directory except the
606    volume lockfile. */
delete_vfs_files(VfsDevice * self)607 void delete_vfs_files(VfsDevice * self) {
608     g_assert(self != NULL);
609 
610     /* This function assumes that the volume is locked! */
611     search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
612                          delete_vfs_files_functor, self);
613 }
614 
615 /* This is a functor suitable for search_directory. It simply prints a
616    warning. It also dodges the volume lockfile. */
check_dir_empty_functor(const char * filename,gpointer user_data)617 static gboolean check_dir_empty_functor(const char * filename,
618                                         gpointer user_data) {
619     VfsDevice * self = VFS_DEVICE(user_data);
620     char * path_name;
621 
622     if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
623         return TRUE;
624 
625     path_name = vstralloc(self->dir_name, "/", filename, NULL);
626 
627     g_warning(_("Found spurious storage file %s"), path_name);
628 
629     amfree(path_name);
630     return TRUE;
631 }
632 
633 /* This function is used to write volume and dump headers. */
write_amanda_header(VfsDevice * self,const dumpfile_t * header)634 static gboolean write_amanda_header(VfsDevice * self,
635                                     const dumpfile_t * header) {
636     char * label_buffer;
637     IoResult result;
638     Device *d_self = DEVICE(self);
639 
640     g_assert(header != NULL);
641 
642     label_buffer = device_build_amanda_header(d_self, header, NULL);
643     if (!label_buffer) {
644         amfree(label_buffer);
645 	device_set_error(d_self,
646 	    stralloc(_("Amanda file header won't fit in a single block!")),
647 	    DEVICE_STATUS_DEVICE_ERROR);
648         return FALSE;
649     }
650 
651     result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE);
652     /* vfs_device_robust_write sets error status if necessary */
653     amfree(label_buffer);
654     return (result == RESULT_SUCCESS);
655 }
656 
657 /* clear_and_label will erase the contents of the directory, and write
658  * this label in its place. This function assumes we already have a volume
659  * label write lock in place (e.g., promote_lock() has been called.) */
clear_and_prepare_label(VfsDevice * self,char * label,char * timestamp)660 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
661                                         char * timestamp) {
662     dumpfile_t * label_header;
663     Device *d_self = DEVICE(self);
664 
665     release_file(self);
666 
667     /* Delete any extant data, except our volume lock. */
668     delete_vfs_files(self);
669 
670     /* Print warnings about any remaining files. */
671     search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
672                          check_dir_empty_functor, self);
673 
674     self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);
675 
676     self->open_file_fd = robust_open(self->file_name,
677                                      O_CREAT | O_EXCL | O_WRONLY,
678                                      VFS_DEVICE_CREAT_MODE);
679     if (self->open_file_fd < 0) {
680 	device_set_error(d_self,
681 	    vstrallocf(_("Can't open file %s: %s"), self->file_name, strerror(errno)),
682 	    DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
683         return FALSE;
684     }
685 
686     label_header = make_tapestart_header(DEVICE(self), label, timestamp);
687     if (!write_amanda_header(self, label_header)) {
688 	/* write_amanda_header sets error status if necessary */
689         dumpfile_free(label_header);
690         return FALSE;
691     }
692     dumpfile_free(d_self->volume_header);
693     d_self->header_block_size = VFS_DEVICE_LABEL_SIZE;
694     d_self->volume_header = label_header;
695     self->volume_bytes = VFS_DEVICE_LABEL_SIZE;
696     return TRUE;
697 }
698 
699 /* Just like search_directory, but returns -1 in the event of an error */
700 static int
search_vfs_directory(VfsDevice * self,const char * regex,SearchDirectoryFunctor functor,gpointer user_data)701 search_vfs_directory(
702     VfsDevice *self,
703     const char * regex,
704     SearchDirectoryFunctor functor,
705     gpointer user_data)
706 {
707     Device *dself = DEVICE(self);
708     DIR *dir_handle;
709     int result = -1;
710 
711     dir_handle = opendir(self->dir_name);
712     if (dir_handle == NULL) {
713 	device_set_error(dself,
714 		vstrallocf(_("Couldn't open device %s (directory %s) for reading: %s"),
715 			dself->device_name, self->dir_name, strerror(errno)),
716 		DEVICE_STATUS_DEVICE_ERROR);
717         goto error;
718     }
719 
720     /* TODO: is this the right moment to acquire a lock?? */
721 
722     result = search_directory(dir_handle, regex, functor, user_data);
723 
724 error:
725     if (dir_handle)
726 	closedir(dir_handle);
727     return result;
728 }
729 
vfs_device_read_label(Device * dself)730 static DeviceStatusFlags vfs_device_read_label(Device * dself) {
731     VfsDevice * self = VFS_DEVICE(dself);
732     dumpfile_t * amanda_header;
733 
734     g_assert(self != NULL);
735 
736     if (!check_is_dir(self, self->dir_name)) {
737 	/* error message set by check_is_dir */
738         return dself->status;
739     }
740 
741     amfree(dself->volume_label);
742     amfree(dself->volume_time);
743     dumpfile_free(dself->volume_header);
744     dself->volume_header = NULL;
745 
746     if (device_in_error(dself)) return dself->status;
747 
748     amanda_header = dself->volume_header = vfs_device_seek_file(dself, 0);
749     release_file(self);
750     if (amanda_header == NULL) {
751         /* This means an error occured getting locks or opening the header
752          * file. */
753 	device_set_error(dself,
754 		stralloc("Error loading device header -- unlabeled volume?"),
755 		  DEVICE_STATUS_DEVICE_ERROR
756 		| DEVICE_STATUS_VOLUME_ERROR
757 		| DEVICE_STATUS_VOLUME_UNLABELED);
758 	return dself->status;
759     }
760 
761     /* close the fd we just opened */
762     vfs_device_finish_file(dself);
763 
764     if (amanda_header->type != F_TAPESTART &&
765 	amanda_header->type != F_EMPTY) {
766         /* This is an error, and should not happen. */
767 	device_set_error(dself,
768 		stralloc(_("Got a bad volume label")),
769 		DEVICE_STATUS_VOLUME_ERROR);
770         amfree(amanda_header);
771         return dself->status;
772     }
773 
774     /* self->volume_header is already set */
775 
776     if (amanda_header->type == F_TAPESTART) {
777 	dself->volume_label = g_strdup(amanda_header->name);
778 	dself->volume_time = g_strdup(amanda_header->datestamp);
779 	device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
780     }
781 
782     update_volume_size(self);
783 
784     return dself->status;
785 }
786 
vfs_device_write_block(Device * pself,guint size,gpointer data)787 static gboolean vfs_device_write_block(Device * pself, guint size, gpointer data) {
788     VfsDevice * self = VFS_DEVICE(pself);
789     IoResult result;
790 
791     if (device_in_error(self)) return FALSE;
792 
793     g_assert(self->open_file_fd >= 0);
794 
795     if (check_at_leom(self, size))
796 	pself->is_eom = TRUE;
797 
798     if (check_at_peom(self, size)) {
799 	/* check_at_peom() only checks against MAX_VOLUME_USAGE limit */
800 	pself->is_eom = TRUE;
801 	device_set_error(pself,
802 	    stralloc(_("No space left on device: more than MAX_VOLUME_USAGE bytes written")),
803 	    DEVICE_STATUS_VOLUME_ERROR);
804 	return FALSE;
805     }
806 
807     result = vfs_device_robust_write(self, data, size);
808     if (result != RESULT_SUCCESS) {
809 	/* vfs_device_robust_write set error status appropriately */
810         return FALSE;
811     }
812 
813     self->volume_bytes += size;
814     self->checked_bytes_used += size;
815     pself->block ++;
816     g_mutex_lock(pself->device_mutex);
817     pself->bytes_written += size;
818     g_mutex_unlock(pself->device_mutex);
819 
820     return TRUE;
821 }
822 
823 static int
vfs_device_read_block(Device * pself,gpointer data,int * size_req)824 vfs_device_read_block(Device * pself, gpointer data, int * size_req) {
825     VfsDevice * self;
826     int size;
827     IoResult result;
828 
829     self = VFS_DEVICE(pself);
830 
831     if (device_in_error(self)) return -1;
832 
833     if (data == NULL || (gsize)*size_req < pself->block_size) {
834         /* Just a size query. */
835 	g_assert(pself->block_size < INT_MAX);
836         *size_req = (int)pself->block_size;
837         return 0;
838     }
839 
840     size = pself->block_size;
841     result = vfs_device_robust_read(self, data, &size);
842     switch (result) {
843     case RESULT_SUCCESS:
844         *size_req = size;
845 	g_mutex_lock(pself->device_mutex);
846 	pself->bytes_read += size;
847 	g_mutex_unlock(pself->device_mutex);
848 	pself->block++;
849         return size;
850     case RESULT_NO_DATA:
851         pself->is_eof = TRUE;
852 	g_mutex_lock(pself->device_mutex);
853         pself->in_file = FALSE;
854 	g_mutex_unlock(pself->device_mutex);
855 	device_set_error(pself,
856 	    stralloc(_("EOF")),
857 	    DEVICE_STATUS_SUCCESS);
858         return -1;
859     default:
860 	device_set_error(pself,
861 	    vstrallocf(_("Error reading from data file: %s"), strerror(errno)),
862 	    DEVICE_STATUS_DEVICE_ERROR);
863         return -1;
864     }
865 
866     g_assert_not_reached();
867 }
868 
869 static gboolean
vfs_device_start(Device * dself,DeviceAccessMode mode,char * label,char * timestamp)870 vfs_device_start(Device * dself,
871                                  DeviceAccessMode mode, char * label,
872                                  char * timestamp) {
873     VfsDevice * self = VFS_DEVICE(dself);
874 
875     if (!check_is_dir(self, self->dir_name)) {
876 	/* error message set by check_is_dir */
877         return FALSE;
878     }
879 
880     g_mutex_lock(dself->device_mutex);
881     dself->in_file = FALSE;
882     g_mutex_unlock(dself->device_mutex);
883 
884     if (mode == ACCESS_WRITE) {
885         promote_volume_lock(self);
886         if (!clear_and_prepare_label(self, label, timestamp)) {
887 	    /* clear_and_prepare_label sets error status if necessary */
888             demote_volume_lock(self);
889             return FALSE;
890         }
891 
892         dself->volume_label = newstralloc(dself->volume_label, label);
893         dself->volume_time = newstralloc(dself->volume_time, timestamp);
894 
895 	/* unset the VOLUME_UNLABELED flag, if it was set */
896 	device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
897 
898         demote_volume_lock(self);
899         dself->access_mode = mode;
900     } else {
901 	if (dself->volume_label == NULL && device_read_label(dself) != DEVICE_STATUS_SUCCESS) {
902 	    /* device_read_label already set our error message */
903             return FALSE;
904 	} else {
905             dself->access_mode = mode;
906         }
907     }
908 
909     release_file(self);
910 
911     return TRUE;
912 }
913 
914 static gboolean
vfs_device_finish(Device * pself)915 vfs_device_finish (Device * pself) {
916     VfsDevice * self;
917     self = VFS_DEVICE(pself);
918 
919     release_file(self);
920 
921     pself->access_mode = ACCESS_NULL;
922     g_mutex_lock(pself->device_mutex);
923     pself->in_file = FALSE;
924     g_mutex_unlock(pself->device_mutex);
925 
926     if (device_in_error(self)) return FALSE;
927 
928     return TRUE;
929 }
930 
931 typedef struct {
932     VfsDevice * self;
933     int rval;
934 } glfn_data;
935 
936 /* A SearchDirectoryFunctor. */
get_last_file_number_functor(const char * filename,gpointer datap)937 static gboolean get_last_file_number_functor(const char * filename,
938                                              gpointer datap) {
939     guint64 file;
940     glfn_data * data = (glfn_data*)datap;
941 
942     file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
943     if (file > G_MAXINT) {
944 	g_warning(_("Super-large device file %s found, ignoring"), filename);
945         return TRUE;
946     }
947     /* This condition is needlessly complex due to sign issues. */
948     if (data->rval < 0 || ((guint)data->rval) < file) {
949         data->rval = file;
950     }
951     return TRUE;
952 }
953 
954 static gint
get_last_file_number(VfsDevice * self)955 get_last_file_number(VfsDevice * self) {
956     glfn_data data;
957     int count;
958     Device *d_self = DEVICE(self);
959     data.self = self;
960     data.rval = -1;
961 
962     count = search_vfs_directory(self, "^[0-9]+\\.",
963                                  get_last_file_number_functor, &data);
964 
965     if (count <= 0) {
966         /* Somebody deleted something important while we weren't looking. */
967 	device_set_error(d_self,
968 	    stralloc(_("Error identifying VFS device contents!")),
969 	    DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
970         return -1;
971     } else {
972         g_assert(data.rval >= 0);
973     }
974 
975     return data.rval;
976 }
977 
978 typedef struct {
979     VfsDevice * self;
980     guint request;
981     int best_found;
982 } gnfn_data;
983 
984 /* A SearchDirectoryFunctor. */
get_next_file_number_functor(const char * filename,gpointer datap)985 static gboolean get_next_file_number_functor(const char * filename,
986                                              gpointer datap) {
987     guint file;
988     gnfn_data * data = (gnfn_data*)datap;
989 
990     file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
991     if (file > G_MAXINT) {
992 	g_warning(_("Super-large device file %s found, ignoring"), filename);
993         return TRUE;
994     }
995     /* This condition is needlessly complex due to sign issues. */
996     if (file >= data->request &&
997         (data->best_found < 0 || file < (guint)data->best_found)) {
998         data->best_found = file;
999     }
1000     return TRUE;
1001 }
1002 
1003 /* Returns the file number equal to or greater than the given requested
1004  * file number. */
1005 static gint
get_next_file_number(VfsDevice * self,guint request)1006 get_next_file_number(VfsDevice * self, guint request) {
1007     gnfn_data data;
1008     int count;
1009     Device *d_self = DEVICE(self);
1010     data.self = self;
1011     data.request = request;
1012     data.best_found = -1;
1013 
1014     count = search_vfs_directory(self, "^[0-9]+\\.",
1015                                  get_next_file_number_functor, &data);
1016 
1017     if (count <= 0) {
1018         /* Somebody deleted something important while we weren't looking. */
1019 	device_set_error(d_self,
1020 	    stralloc(_("Error identifying VFS device contents!")),
1021 	    DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1022         return -1;
1023     }
1024 
1025     /* Could be -1. */
1026     return data.best_found;
1027 }
1028 
1029 /* Finds the file number, acquires a lock, and returns the new file name. */
1030 static
make_new_file_name(VfsDevice * self,const dumpfile_t * ji)1031 char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) {
1032     char * rval;
1033     char *base, *sanitary_base;
1034     int fileno;
1035 
1036     for (;;) {
1037         fileno = 1 + get_last_file_number(self);
1038         if (fileno <= 0)
1039             return NULL;
1040 
1041         if (open_lock(self, fileno, TRUE)) {
1042             break;
1043         } else {
1044             continue;
1045         }
1046     }
1047 
1048     /* record that we're at this filenum now */
1049     DEVICE(self)->file = fileno;
1050 
1051     base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk,
1052                            ji->dumplevel);
1053     sanitary_base = sanitise_filename(base);
1054     amfree(base);
1055     rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base);
1056     amfree(sanitary_base);
1057     return rval;
1058 }
1059 
1060 static gboolean
vfs_device_start_file(Device * dself,dumpfile_t * ji)1061 vfs_device_start_file (Device * dself, dumpfile_t * ji) {
1062     VfsDevice * self = VFS_DEVICE(dself);
1063 
1064     dself->is_eom = FALSE;
1065 
1066     if (device_in_error(self)) return FALSE;
1067 
1068     /* set the blocksize in the header to 32k, since the VFS header is always
1069      * 32k regardless of the block_size setting */
1070     ji->blocksize = 32768;
1071 
1072     if (check_at_leom(self, VFS_DEVICE_LABEL_SIZE))
1073 	dself->is_eom = TRUE;
1074 
1075     if (check_at_peom(self, VFS_DEVICE_LABEL_SIZE)) {
1076 	/* check_at_peom() only checks against MAX_VOLUME_USAGE limit */
1077 	dself->is_eom = TRUE;
1078 	device_set_error(dself,
1079 		stralloc(_("No space left on device: more than MAX_VOLUME_USAGE bytes written")),
1080 		DEVICE_STATUS_DEVICE_ERROR);
1081 	return FALSE;
1082     }
1083 
1084     /* The basic idea here is thus:
1085        1) Try to get a lock on the next filenumber.
1086        2) If that fails, update our idea of "next filenumber" and try again.
1087        3) Then open the file itself.
1088        4) Write the label.
1089        5) Chain up. */
1090 
1091     self->file_name = make_new_file_name(self, ji);
1092     if (self->file_name == NULL) {
1093 	device_set_error(dself,
1094 		stralloc(_("Could not create header filename")),
1095 		DEVICE_STATUS_DEVICE_ERROR);
1096         return FALSE;
1097     }
1098 
1099     self->open_file_fd = robust_open(self->file_name,
1100                                      O_CREAT | O_EXCL | O_RDWR,
1101                                      VFS_DEVICE_CREAT_MODE);
1102     if (self->open_file_fd < 0) {
1103 	device_set_error(dself,
1104 		vstrallocf(_("Can't create file %s: %s"), self->file_name, strerror(errno)),
1105 		DEVICE_STATUS_DEVICE_ERROR);
1106         release_file(self);
1107         return FALSE;
1108     }
1109 
1110 
1111     if (!write_amanda_header(self, ji)) {
1112 	/* write_amanda_header sets error status if necessary */
1113         release_file(self);
1114         return FALSE;
1115     }
1116 
1117     /* handle some accounting business */
1118     self->volume_bytes += VFS_DEVICE_LABEL_SIZE;
1119     self->checked_bytes_used += VFS_DEVICE_LABEL_SIZE;
1120     dself->block = 0;
1121     g_mutex_lock(dself->device_mutex);
1122     dself->in_file = TRUE;
1123     dself->bytes_written = 0;
1124     g_mutex_unlock(dself->device_mutex);
1125     /* make_new_file_name set pself->file for us */
1126 
1127     return TRUE;
1128 }
1129 
1130 static gboolean
vfs_device_finish_file(Device * dself)1131 vfs_device_finish_file(Device * dself) {
1132     VfsDevice * self = VFS_DEVICE(dself);
1133 
1134     if (!dself->in_file)
1135 	return TRUE;
1136 
1137     g_mutex_lock(dself->device_mutex);
1138     dself->in_file = FALSE;
1139     g_mutex_unlock(dself->device_mutex);
1140 
1141     release_file(self);
1142 
1143     if (device_in_error(self)) return FALSE;
1144 
1145     return TRUE;
1146 }
1147 
1148 /* This function is used for two purposes, rather than one. In
1149  * addition to its documented behavior, we also use it to open the
1150  * volume label for reading at startup. In that second case, we avoid
1151  * FdDevice-related side effects. */
1152 static dumpfile_t *
vfs_device_seek_file(Device * dself,guint requested_file)1153 vfs_device_seek_file (Device * dself, guint requested_file) {
1154     VfsDevice *self = VFS_DEVICE(dself);
1155     int file;
1156     dumpfile_t * rval;
1157     char header_buffer[VFS_DEVICE_LABEL_SIZE];
1158     int header_buffer_size = sizeof(header_buffer);
1159     IoResult result;
1160 
1161     if (device_in_error(self)) return NULL;
1162 
1163     dself->is_eof = FALSE;
1164     dself->block = 0;
1165     g_mutex_lock(dself->device_mutex);
1166     dself->in_file = FALSE;
1167     dself->bytes_read = 0;
1168     g_mutex_unlock(dself->device_mutex);
1169 
1170     release_file(self);
1171 
1172     if (requested_file > 0) {
1173         file = get_next_file_number(self, requested_file);
1174     } else {
1175         file = requested_file;
1176     }
1177 
1178     if (file < 0) {
1179         /* Did they request one past the end? */
1180         char * tmp_file_name;
1181         tmp_file_name = file_number_to_file_name(self, requested_file - 1);
1182         if (tmp_file_name != NULL) {
1183             free(tmp_file_name);
1184 	    dself->file = requested_file; /* other attributes are already correct */
1185             return make_tapeend_header();
1186         } else {
1187 	    device_set_error(dself,
1188 		stralloc(_("Attempt to read past tape-end file")),
1189 		DEVICE_STATUS_SUCCESS);
1190             return NULL;
1191         }
1192     }
1193 
1194     if (!open_lock(self, file, FALSE)) {
1195 	device_set_error(dself,
1196 	    stralloc(_("could not acquire lock")),
1197 	    DEVICE_STATUS_DEVICE_ERROR);
1198         return NULL;
1199     }
1200 
1201     self->file_name = file_number_to_file_name(self, file);
1202     if (self->file_name == NULL) {
1203 	device_set_error(dself,
1204 	    vstrallocf(_("File %d not found"), file),
1205 	    file == 0 ? DEVICE_STATUS_VOLUME_UNLABELED
1206 		      : DEVICE_STATUS_VOLUME_ERROR);
1207         release_file(self);
1208 	rval = g_new(dumpfile_t, 1);
1209 	fh_init(rval);
1210         return rval;
1211     }
1212 
1213     self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
1214     if (self->open_file_fd < 0) {
1215 	device_set_error(dself,
1216 	    vstrallocf(_("Couldn't open file %s: %s"), self->file_name, strerror(errno)),
1217 	    DEVICE_STATUS_DEVICE_ERROR);
1218         amfree(self->file_name);
1219         release_file(self);
1220         return NULL;
1221     }
1222 
1223     result = vfs_device_robust_read(self, header_buffer,
1224                                     &header_buffer_size);
1225     if (result != RESULT_SUCCESS) {
1226 	device_set_error(dself,
1227 	    vstrallocf(_("Problem reading Amanda header: %s"), device_error(dself)),
1228 	    DEVICE_STATUS_VOLUME_ERROR);
1229         release_file(self);
1230         return NULL;
1231     }
1232 
1233     rval = g_new(dumpfile_t, 1);
1234     parse_file_header(header_buffer, rval, header_buffer_size);
1235     switch (rval->type) {
1236         case F_DUMPFILE:
1237         case F_CONT_DUMPFILE:
1238         case F_SPLIT_DUMPFILE:
1239 	    break;
1240 
1241 	case F_TAPESTART:
1242 	    /* file 0 should have a TAPESTART header; vfs_device_read_label
1243 	     * uses this */
1244 	    if (requested_file == 0)
1245 		break;
1246 	    /* FALLTHROUGH */
1247 
1248         default:
1249 	    device_set_error(dself,
1250 		stralloc(_("Invalid amanda header while reading file header")),
1251 		DEVICE_STATUS_VOLUME_ERROR);
1252             amfree(rval);
1253             release_file(self);
1254             return NULL;
1255     }
1256 
1257     /* update our state */
1258     if (requested_file == 0) {
1259 	dself->header_block_size = header_buffer_size;
1260     }
1261     g_mutex_lock(dself->device_mutex);
1262     dself->in_file = TRUE;
1263     g_mutex_unlock(dself->device_mutex);
1264     dself->file = file;
1265 
1266     return rval;
1267 }
1268 
1269 static gboolean
vfs_device_seek_block(Device * pself,guint64 block)1270 vfs_device_seek_block (Device * pself, guint64 block) {
1271     VfsDevice * self;
1272     off_t result;
1273 
1274     self = VFS_DEVICE(pself);
1275 
1276     g_assert(self->open_file_fd >= 0);
1277     g_assert(sizeof(off_t) >= sizeof(guint64));
1278     if (device_in_error(self)) return FALSE;
1279 
1280     /* Pretty simple. We figure out the blocksize and use that. */
1281     result = lseek(self->open_file_fd,
1282                    (block) * pself->block_size + VFS_DEVICE_LABEL_SIZE,
1283                    SEEK_SET);
1284 
1285     pself->block = block;
1286 
1287     if (result == (off_t)(-1)) {
1288 	device_set_error(pself,
1289 	    vstrallocf(_("Error seeking within file: %s"), strerror(errno)),
1290 	    DEVICE_STATUS_DEVICE_ERROR);
1291 	return FALSE;
1292     }
1293 
1294     return TRUE;
1295 }
1296 
try_unlink(const char * file)1297 static gboolean try_unlink(const char * file) {
1298     if (unlink(file) < 0) {
1299         return FALSE;
1300     } else {
1301         return TRUE;
1302     }
1303 }
1304 
1305 static gboolean
check_at_leom(VfsDevice * self,guint64 size)1306 check_at_leom(VfsDevice *self, guint64 size)
1307 {
1308     gboolean recheck = FALSE;
1309     guint64 est_avail_now;
1310     struct fs_usage fsusage;
1311     guint64 block_size = DEVICE(self)->block_size;
1312     guint64 eom_warning_buffer = EOM_EARLY_WARNING_ZONE_BLOCKS * block_size;
1313 
1314     if (!self->leom || !self->monitor_free_space)
1315 	return FALSE;
1316 
1317     /* handle VOLUME_LIMIT */
1318     if (self->enforce_volume_limit && self->volume_limit &&
1319 	    self->volume_bytes + size + eom_warning_buffer > self->volume_limit) {
1320 	return TRUE;
1321     }
1322 
1323     /* handle actual filesystem available space, using some heuristics to avoid polling this
1324      * too frequently */
1325     est_avail_now = 0;
1326     if (self->checked_fs_free_bytes >= self->checked_bytes_used + size)
1327 	est_avail_now = self->checked_fs_free_bytes - self->checked_bytes_used - size;
1328 
1329     /* is it time to check again? */
1330     if (est_avail_now <= block_size * MONITOR_FREE_SPACE_CLOSELY_WITHIN_BLOCKS) {
1331 	recheck = TRUE;
1332     } else if (self->checked_bytes_used > MONITOR_FREE_SPACE_EVERY_KB * 1024) {
1333 	recheck = TRUE;
1334     } else if (self->checked_fs_free_time + MONITOR_FREE_SPACE_EVERY_SECONDS <= time(NULL)) {
1335 	recheck = TRUE;
1336     }
1337 
1338     if (!recheck)
1339 	return FALSE;
1340 
1341     if (get_fs_usage(self->dir_name, NULL, &fsusage) < 0 || fsusage.fsu_bavail_top_bit_set) {
1342 	g_warning("Filesystem cannot provide free space: %s; setting MONITOR_FREE_SPACE false",
1343 		fsusage.fsu_bavail_top_bit_set? "no result" : strerror(errno));
1344 	self->monitor_free_space = FALSE;
1345 	return FALSE;
1346     }
1347 
1348     self->checked_fs_free_bytes = fsusage.fsu_bavail * fsusage.fsu_blocksize;
1349     self->checked_bytes_used = 0;
1350     self->checked_fs_free_time = time(NULL);
1351 
1352     if (self->checked_fs_free_bytes - size <= eom_warning_buffer) {
1353 	g_debug("%s: at LEOM", DEVICE(self)->device_name);
1354 	return TRUE;
1355     }
1356 
1357     return FALSE;
1358 }
1359 
1360 static gboolean
check_at_peom(VfsDevice * self,guint64 size)1361 check_at_peom(VfsDevice *self, guint64 size)
1362 {
1363     if (self->enforce_volume_limit && (self->volume_limit > 0)) {
1364 	guint64 newtotal = self->volume_bytes + size;
1365         if (newtotal > self->volume_limit) {
1366 	    return TRUE;
1367 	}
1368     }
1369 
1370     return FALSE;
1371 }
1372 
1373 static gboolean
vfs_device_recycle_file(Device * dself,guint filenum)1374 vfs_device_recycle_file (Device * dself, guint filenum) {
1375     VfsDevice * self = VFS_DEVICE(dself);
1376     struct stat file_status;
1377     off_t file_size;
1378 
1379     if (device_in_error(self)) return FALSE;
1380 
1381     /* Game Plan:
1382      * 1) Get a write lock on the file in question.
1383      * 2) Unlink the file in question.
1384      * 3) Unlink the lock.
1385      * 4) Release the lock.
1386      * FIXME: Is it OK to unlink the lockfile?
1387      */
1388 
1389     self->file_name = file_number_to_file_name(self, filenum);
1390     if (self->file_name == NULL) {
1391 	device_set_error(dself,
1392 	    vstrallocf(_("File %d not found"), filenum),
1393 	    DEVICE_STATUS_VOLUME_ERROR);
1394         return FALSE;
1395     }
1396 
1397     if (!open_lock(self, filenum, FALSE)) {
1398 	device_set_error(dself,
1399 	    stralloc(_("could not acquire lock")),
1400 	    DEVICE_STATUS_DEVICE_ERROR);
1401         return FALSE;
1402     }
1403 
1404     if (0 != stat(self->file_name, &file_status)) {
1405 	device_set_error(dself,
1406 	    vstrallocf(_("Cannot stat file %s (%s), so not removing"),
1407 				    self->file_name, strerror(errno)),
1408 	    DEVICE_STATUS_VOLUME_ERROR);
1409         return FALSE;
1410     }
1411     file_size = file_status.st_size;
1412 
1413     if (!try_unlink(self->file_name)) {
1414 	device_set_error(dself,
1415 	    vstrallocf(_("Unlink of %s failed: %s"), self->file_name, strerror(errno)),
1416 	    DEVICE_STATUS_VOLUME_ERROR);
1417         release_file(self);
1418         return FALSE;
1419     }
1420 
1421     self->volume_bytes -= file_size;
1422     release_file(self);
1423     return TRUE;
1424 }
1425 
1426 static gboolean
vfs_device_erase(Device * dself)1427 vfs_device_erase (Device * dself) {
1428     VfsDevice *self = VFS_DEVICE(dself);
1429 
1430     if (!open_lock(self, 0, TRUE))
1431         return FALSE;
1432 
1433     delete_vfs_files(self);
1434 
1435     release_file(self);
1436 
1437     dumpfile_free(dself->volume_header);
1438     dself->volume_header = NULL;
1439     device_set_error(dself, g_strdup("Unlabeled volume"),
1440 		     DEVICE_STATUS_VOLUME_UNLABELED);
1441 
1442     return TRUE;
1443 }
1444 
vfs_device_robust_read(VfsDevice * self,char * buf,int * count)1445 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
1446                                              int *count) {
1447     int fd = self->open_file_fd;
1448     Device *d_self = DEVICE(self);
1449     int want = *count, got = 0;
1450 
1451     while (got < want) {
1452         int result;
1453         result = read(fd, buf + got, want - got);
1454         if (result > 0) {
1455             got += result;
1456         } else if (result == 0) {
1457             /* end of file */
1458             if (got == 0) {
1459                 return RESULT_NO_DATA;
1460             } else {
1461                 *count = got;
1462                 return RESULT_SUCCESS;
1463             }
1464         } else if (0
1465 #ifdef EAGAIN
1466                 || errno == EAGAIN
1467 #endif
1468 #ifdef EWOULDBLOCK
1469                 || errno == EWOULDBLOCK
1470 #endif
1471 #ifdef EINTR
1472                 || errno == EINTR
1473 #endif
1474                    ) {
1475             /* Try again. */
1476             continue;
1477         } else {
1478             /* Error occured. */
1479 	    device_set_error(d_self,
1480 		vstrallocf(_("Error reading fd %d: %s"), fd, strerror(errno)),
1481 		DEVICE_STATUS_VOLUME_ERROR);
1482             *count = got;
1483             return RESULT_ERROR;
1484         }
1485     }
1486 
1487     *count = got;
1488     return RESULT_SUCCESS;
1489 }
1490 
1491 static IoResult
vfs_device_robust_write(VfsDevice * self,char * buf,int count)1492 vfs_device_robust_write(VfsDevice * self,  char *buf, int count) {
1493     int fd = self->open_file_fd;
1494     Device *d_self = DEVICE(self);
1495     int rval = 0;
1496 
1497     while (rval < count) {
1498         int result;
1499         result = write(fd, buf + rval, count - rval);
1500         if (result > 0) {
1501             rval += result;
1502             continue;
1503         } else if (0
1504 #ifdef EAGAIN
1505                 || errno == EAGAIN
1506 #endif
1507 #ifdef EWOULDBLOCK
1508                 || errno == EWOULDBLOCK
1509 #endif
1510 #ifdef EINTR
1511                 || errno == EINTR
1512 #endif
1513                    ) {
1514             /* Try again. */
1515             continue;
1516         } else if (0
1517 #ifdef EFBIG
1518                    || errno == EFBIG
1519 #endif
1520 #ifdef ENOSPC
1521                    || errno == ENOSPC
1522 #endif
1523                    ) {
1524             /* We are definitely out of space. */
1525 	    device_set_error(d_self,
1526 		    vstrallocf(_("No space left on device: %s"), strerror(errno)),
1527 		    DEVICE_STATUS_VOLUME_ERROR);
1528             return RESULT_NO_SPACE;
1529         } else {
1530             /* Error occured. Note that here we handle EIO as an error. */
1531 	    device_set_error(d_self,
1532 		    vstrallocf(_("Error writing device fd %d: %s"), fd, strerror(errno)),
1533 		    DEVICE_STATUS_VOLUME_ERROR);
1534             return RESULT_ERROR;
1535         }
1536     }
1537     return RESULT_SUCCESS;
1538 }
1539 
1540 /* TODO: add prop */
1541