Imported Upstream version 3.3.3
[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
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
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
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
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
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
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
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
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
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
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
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. */
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
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
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
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. */
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. */
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  */
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. */
531 static void promote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
532 }
533
534 static void demote_volume_lock(VfsDevice * self G_GNUC_UNUSED) {
535 }
536
537 /* A SearchDirectoryFunctor */
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
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
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 */
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. */
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. */
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. */
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.) */
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
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
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
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
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
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
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. */
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
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. */
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
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
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
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
1131 vfs_device_finish_file(Device * dself) {
1132     VfsDevice * self = VFS_DEVICE(dself);
1133
1134     if (device_in_error(self)) return FALSE;
1135
1136     release_file(self);
1137
1138     g_mutex_lock(dself->device_mutex);
1139     dself->in_file = FALSE;
1140     g_mutex_unlock(dself->device_mutex);
1141
1142     return TRUE;
1143 }
1144
1145 /* This function is used for two purposes, rather than one. In
1146  * addition to its documented behavior, we also use it to open the
1147  * volume label for reading at startup. In that second case, we avoid
1148  * FdDevice-related side effects. */
1149 static dumpfile_t *
1150 vfs_device_seek_file (Device * dself, guint requested_file) {
1151     VfsDevice *self = VFS_DEVICE(dself);
1152     int file;
1153     dumpfile_t * rval;
1154     char header_buffer[VFS_DEVICE_LABEL_SIZE];
1155     int header_buffer_size = sizeof(header_buffer);
1156     IoResult result;
1157
1158     if (device_in_error(self)) return NULL;
1159
1160     dself->is_eof = FALSE;
1161     dself->block = 0;
1162     g_mutex_lock(dself->device_mutex);
1163     dself->in_file = FALSE;
1164     dself->bytes_read = 0;
1165     g_mutex_unlock(dself->device_mutex);
1166
1167     release_file(self);
1168
1169     if (requested_file > 0) {
1170         file = get_next_file_number(self, requested_file);
1171     } else {
1172         file = requested_file;
1173     }
1174
1175     if (file < 0) {
1176         /* Did they request one past the end? */
1177         char * tmp_file_name;
1178         tmp_file_name = file_number_to_file_name(self, requested_file - 1);
1179         if (tmp_file_name != NULL) {
1180             free(tmp_file_name);
1181             dself->file = requested_file; /* other attributes are already correct */
1182             return make_tapeend_header();
1183         } else {
1184             device_set_error(dself,
1185                 stralloc(_("Attempt to read past tape-end file")),
1186                 DEVICE_STATUS_SUCCESS);
1187             return NULL;
1188         }
1189     }
1190
1191     if (!open_lock(self, file, FALSE)) {
1192         device_set_error(dself,
1193             stralloc(_("could not acquire lock")),
1194             DEVICE_STATUS_DEVICE_ERROR);
1195         return NULL;
1196     }
1197
1198     self->file_name = file_number_to_file_name(self, file);
1199     if (self->file_name == NULL) {
1200         device_set_error(dself,
1201             vstrallocf(_("File %d not found"), file),
1202             file == 0 ? DEVICE_STATUS_VOLUME_UNLABELED
1203                       : DEVICE_STATUS_VOLUME_ERROR);
1204         release_file(self);
1205         rval = g_new(dumpfile_t, 1);
1206         fh_init(rval);
1207         return rval;
1208     }
1209
1210     self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
1211     if (self->open_file_fd < 0) {
1212         device_set_error(dself,
1213             vstrallocf(_("Couldn't open file %s: %s"), self->file_name, strerror(errno)),
1214             DEVICE_STATUS_DEVICE_ERROR);
1215         amfree(self->file_name);
1216         release_file(self);
1217         return NULL;
1218     }
1219
1220     result = vfs_device_robust_read(self, header_buffer,
1221                                     &header_buffer_size);
1222     if (result != RESULT_SUCCESS) {
1223         device_set_error(dself,
1224             vstrallocf(_("Problem reading Amanda header: %s"), device_error(dself)),
1225             DEVICE_STATUS_VOLUME_ERROR);
1226         release_file(self);
1227         return NULL;
1228     }
1229
1230     rval = g_new(dumpfile_t, 1);
1231     parse_file_header(header_buffer, rval, header_buffer_size);
1232     switch (rval->type) {
1233         case F_DUMPFILE:
1234         case F_CONT_DUMPFILE:
1235         case F_SPLIT_DUMPFILE:
1236             break;
1237
1238         case F_TAPESTART:
1239             /* file 0 should have a TAPESTART header; vfs_device_read_label
1240              * uses this */
1241             if (requested_file == 0)
1242                 break;
1243             /* FALLTHROUGH */
1244
1245         default:
1246             device_set_error(dself,
1247                 stralloc(_("Invalid amanda header while reading file header")),
1248                 DEVICE_STATUS_VOLUME_ERROR);
1249             amfree(rval);
1250             release_file(self);
1251             return NULL;
1252     }
1253
1254     /* update our state */
1255     if (requested_file == 0) {
1256         dself->header_block_size = header_buffer_size;
1257     }
1258     g_mutex_lock(dself->device_mutex);
1259     dself->in_file = TRUE;
1260     g_mutex_unlock(dself->device_mutex);
1261     dself->file = file;
1262
1263     return rval;
1264 }
1265
1266 static gboolean
1267 vfs_device_seek_block (Device * pself, guint64 block) {
1268     VfsDevice * self;
1269     off_t result;
1270
1271     self = VFS_DEVICE(pself);
1272
1273     g_assert(self->open_file_fd >= 0);
1274     g_assert(sizeof(off_t) >= sizeof(guint64));
1275     if (device_in_error(self)) return FALSE;
1276
1277     /* Pretty simple. We figure out the blocksize and use that. */
1278     result = lseek(self->open_file_fd,
1279                    (block) * pself->block_size + VFS_DEVICE_LABEL_SIZE,
1280                    SEEK_SET);
1281
1282     pself->block = block;
1283
1284     if (result == (off_t)(-1)) {
1285         device_set_error(pself,
1286             vstrallocf(_("Error seeking within file: %s"), strerror(errno)),
1287             DEVICE_STATUS_DEVICE_ERROR);
1288         return FALSE;
1289     }
1290
1291     return TRUE;
1292 }
1293
1294 static gboolean try_unlink(const char * file) {
1295     if (unlink(file) < 0) {
1296         return FALSE;
1297     } else {
1298         return TRUE;
1299     }
1300 }
1301
1302 static gboolean
1303 check_at_leom(VfsDevice *self, guint64 size)
1304 {
1305     gboolean recheck = FALSE;
1306     guint64 est_avail_now;
1307     struct fs_usage fsusage;
1308     guint64 block_size = DEVICE(self)->block_size;
1309     guint64 eom_warning_buffer = EOM_EARLY_WARNING_ZONE_BLOCKS * block_size;
1310
1311     if (!self->leom || !self->monitor_free_space)
1312         return FALSE;
1313
1314     /* handle VOLUME_LIMIT */
1315     if (self->enforce_volume_limit && self->volume_limit &&
1316             self->volume_bytes + size + eom_warning_buffer > self->volume_limit) {
1317         return TRUE;
1318     }
1319
1320     /* handle actual filesystem available space, using some heuristics to avoid polling this
1321      * too frequently */
1322     est_avail_now = 0;
1323     if (self->checked_fs_free_bytes >= self->checked_bytes_used + size)
1324         est_avail_now = self->checked_fs_free_bytes - self->checked_bytes_used - size;
1325
1326     /* is it time to check again? */
1327     if (est_avail_now <= block_size * MONITOR_FREE_SPACE_CLOSELY_WITHIN_BLOCKS) {
1328         recheck = TRUE;
1329     } else if (self->checked_bytes_used > MONITOR_FREE_SPACE_EVERY_KB * 1024) {
1330         recheck = TRUE;
1331     } else if (self->checked_fs_free_time + MONITOR_FREE_SPACE_EVERY_SECONDS <= time(NULL)) {
1332         recheck = TRUE;
1333     }
1334
1335     if (!recheck)
1336         return FALSE;
1337
1338     if (get_fs_usage(self->dir_name, NULL, &fsusage) < 0 || fsusage.fsu_bavail_top_bit_set) {
1339         g_warning("Filesystem cannot provide free space: %s; setting MONITOR_FREE_SPACE false",
1340                 fsusage.fsu_bavail_top_bit_set? "no result" : strerror(errno));
1341         self->monitor_free_space = FALSE;
1342         return FALSE;
1343     }
1344
1345     self->checked_fs_free_bytes = fsusage.fsu_bavail * fsusage.fsu_blocksize;
1346     self->checked_bytes_used = 0;
1347     self->checked_fs_free_time = time(NULL);
1348
1349     if (self->checked_fs_free_bytes - size <= eom_warning_buffer) {
1350         g_debug("%s: at LEOM", DEVICE(self)->device_name);
1351         return TRUE;
1352     }
1353
1354     return FALSE;
1355 }
1356
1357 static gboolean
1358 check_at_peom(VfsDevice *self, guint64 size)
1359 {
1360     if (self->enforce_volume_limit && (self->volume_limit > 0)) {
1361         guint64 newtotal = self->volume_bytes + size;
1362         if (newtotal > self->volume_limit) {
1363             return TRUE;
1364         }
1365     }
1366
1367     return FALSE;
1368 }
1369
1370 static gboolean
1371 vfs_device_recycle_file (Device * dself, guint filenum) {
1372     VfsDevice * self = VFS_DEVICE(dself);
1373     struct stat file_status;
1374     off_t file_size;
1375
1376     if (device_in_error(self)) return FALSE;
1377
1378     /* Game Plan:
1379      * 1) Get a write lock on the file in question.
1380      * 2) Unlink the file in question.
1381      * 3) Unlink the lock.
1382      * 4) Release the lock.
1383      * FIXME: Is it OK to unlink the lockfile?
1384      */
1385
1386     self->file_name = file_number_to_file_name(self, filenum);
1387     if (self->file_name == NULL) {
1388         device_set_error(dself,
1389             vstrallocf(_("File %d not found"), filenum),
1390             DEVICE_STATUS_VOLUME_ERROR);
1391         return FALSE;
1392     }
1393
1394     if (!open_lock(self, filenum, FALSE)) {
1395         device_set_error(dself,
1396             stralloc(_("could not acquire lock")),
1397             DEVICE_STATUS_DEVICE_ERROR);
1398         return FALSE;
1399     }
1400
1401     if (0 != stat(self->file_name, &file_status)) {
1402         device_set_error(dself,
1403             vstrallocf(_("Cannot stat file %s (%s), so not removing"),
1404                                     self->file_name, strerror(errno)),
1405             DEVICE_STATUS_VOLUME_ERROR);
1406         return FALSE;
1407     }
1408     file_size = file_status.st_size;
1409
1410     if (!try_unlink(self->file_name)) {
1411         device_set_error(dself,
1412             vstrallocf(_("Unlink of %s failed: %s"), self->file_name, strerror(errno)),
1413             DEVICE_STATUS_VOLUME_ERROR);
1414         release_file(self);
1415         return FALSE;
1416     }
1417
1418     self->volume_bytes -= file_size;
1419     release_file(self);
1420     return TRUE;
1421 }
1422
1423 static gboolean
1424 vfs_device_erase (Device * dself) {
1425     VfsDevice *self = VFS_DEVICE(dself);
1426
1427     if (!open_lock(self, 0, TRUE))
1428         return FALSE;
1429
1430     delete_vfs_files(self);
1431
1432     release_file(self);
1433
1434     dumpfile_free(dself->volume_header);
1435     dself->volume_header = NULL;
1436     device_set_error(dself, g_strdup("Unlabeled volume"),
1437                      DEVICE_STATUS_VOLUME_UNLABELED);
1438
1439     return TRUE;
1440 }
1441
1442 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
1443                                              int *count) {
1444     int fd = self->open_file_fd;
1445     Device *d_self = DEVICE(self);
1446     int want = *count, got = 0;
1447
1448     while (got < want) {
1449         int result;
1450         result = read(fd, buf + got, want - got);
1451         if (result > 0) {
1452             got += result;
1453         } else if (result == 0) {
1454             /* end of file */
1455             if (got == 0) {
1456                 return RESULT_NO_DATA;
1457             } else {
1458                 *count = got;
1459                 return RESULT_SUCCESS;
1460             }
1461         } else if (0
1462 #ifdef EAGAIN
1463                 || errno == EAGAIN
1464 #endif
1465 #ifdef EWOULDBLOCK
1466                 || errno == EWOULDBLOCK
1467 #endif
1468 #ifdef EINTR
1469                 || errno == EINTR
1470 #endif
1471                    ) {
1472             /* Try again. */
1473             continue;
1474         } else {
1475             /* Error occured. */
1476             device_set_error(d_self,
1477                 vstrallocf(_("Error reading fd %d: %s"), fd, strerror(errno)),
1478                 DEVICE_STATUS_VOLUME_ERROR);
1479             *count = got;
1480             return RESULT_ERROR;
1481         }
1482     }
1483
1484     *count = got;
1485     return RESULT_SUCCESS;
1486 }
1487
1488 static IoResult
1489 vfs_device_robust_write(VfsDevice * self,  char *buf, int count) {
1490     int fd = self->open_file_fd;
1491     Device *d_self = DEVICE(self);
1492     int rval = 0;
1493
1494     while (rval < count) {
1495         int result;
1496         result = write(fd, buf + rval, count - rval);
1497         if (result > 0) {
1498             rval += result;
1499             continue;
1500         } else if (0
1501 #ifdef EAGAIN
1502                 || errno == EAGAIN
1503 #endif
1504 #ifdef EWOULDBLOCK
1505                 || errno == EWOULDBLOCK
1506 #endif
1507 #ifdef EINTR
1508                 || errno == EINTR
1509 #endif
1510                    ) {
1511             /* Try again. */
1512             continue;
1513         } else if (0
1514 #ifdef EFBIG
1515                    || errno == EFBIG
1516 #endif
1517 #ifdef ENOSPC
1518                    || errno == ENOSPC
1519 #endif
1520                    ) {
1521             /* We are definitely out of space. */
1522             device_set_error(d_self,
1523                     vstrallocf(_("No space left on device: %s"), strerror(errno)),
1524                     DEVICE_STATUS_VOLUME_ERROR);
1525             return RESULT_NO_SPACE;
1526         } else {
1527             /* Error occured. Note that here we handle EIO as an error. */
1528             device_set_error(d_self,
1529                     vstrallocf(_("Error writing device fd %d: %s"), fd, strerror(errno)),
1530                     DEVICE_STATUS_VOLUME_ERROR);
1531             return RESULT_ERROR;
1532         }
1533     }
1534     return RESULT_SUCCESS;
1535 }
1536
1537 /* TODO: add prop */