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