Imported Upstream version 3.3.0
[debian/amanda] / device-src / vfs-device.c
1 /*
2  * Copyright (c) 2007, 2008, 2009, 2010, 2011 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     Device * d_self;
589     char * path_name;
590
591     self = VFS_DEVICE(user_data);
592     d_self = DEVICE(self);
593
594     /* Skip the volume lock. */
595     if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
596         return TRUE;
597
598     path_name = vstralloc(self->dir_name, "/", filename, NULL);
599     if (unlink(path_name) != 0) {
600         g_warning(_("Error unlinking %s: %s"), path_name, strerror(errno));
601     }
602     amfree(path_name);
603     return TRUE;
604 }
605
606 /* delete_vfs_files deletes all VfsDevice files in the directory except the
607    volume lockfile. */
608 void delete_vfs_files(VfsDevice * self) {
609     g_assert(self != NULL);
610
611     /* This function assumes that the volume is locked! */
612     search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
613                          delete_vfs_files_functor, self);
614 }
615
616 /* This is a functor suitable for search_directory. It simply prints a
617    warning. It also dodges the volume lockfile. */
618 static gboolean check_dir_empty_functor(const char * filename,
619                                         gpointer user_data) {
620     VfsDevice * self = VFS_DEVICE(user_data);
621     char * path_name;
622
623     if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0)
624         return TRUE;
625
626     path_name = vstralloc(self->dir_name, "/", filename, NULL);
627
628     g_warning(_("Found spurious storage file %s"), path_name);
629
630     amfree(path_name);
631     return TRUE;
632 }
633
634 /* This function is used to write volume and dump headers. */
635 static gboolean write_amanda_header(VfsDevice * self,
636                                     const dumpfile_t * header) {
637     char * label_buffer;
638     IoResult result;
639     Device *d_self = DEVICE(self);
640
641     g_assert(header != NULL);
642
643     label_buffer = device_build_amanda_header(d_self, header, NULL);
644     if (!label_buffer) {
645         amfree(label_buffer);
646         device_set_error(d_self,
647             stralloc(_("Amanda file header won't fit in a single block!")),
648             DEVICE_STATUS_DEVICE_ERROR);
649         return FALSE;
650     }
651
652     result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE);
653     /* vfs_device_robust_write sets error status if necessary */
654     amfree(label_buffer);
655     return (result == RESULT_SUCCESS);
656 }
657
658 /* clear_and_label will erase the contents of the directory, and write
659  * this label in its place. This function assumes we already have a volume
660  * label write lock in place (e.g., promote_lock() has been called.) */
661 static gboolean clear_and_prepare_label(VfsDevice * self, char * label,
662                                         char * timestamp) {
663     dumpfile_t * label_header;
664     Device *d_self = DEVICE(self);
665
666     release_file(self);
667
668     /* Delete any extant data, except our volume lock. */
669     delete_vfs_files(self);
670
671     /* Print warnings about any remaining files. */
672     search_vfs_directory(self, VFS_DEVICE_FILE_REGEX,
673                          check_dir_empty_functor, self);
674
675     self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label);
676
677     self->open_file_fd = robust_open(self->file_name,
678                                      O_CREAT | O_EXCL | O_WRONLY,
679                                      VFS_DEVICE_CREAT_MODE);
680     if (self->open_file_fd < 0) {
681         device_set_error(d_self,
682             vstrallocf(_("Can't open file %s: %s"), self->file_name, strerror(errno)),
683             DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
684         return FALSE;
685     }
686
687     label_header = make_tapestart_header(DEVICE(self), label, timestamp);
688     if (!write_amanda_header(self, label_header)) {
689         /* write_amanda_header sets error status if necessary */
690         dumpfile_free(label_header);
691         return FALSE;
692     }
693     dumpfile_free(d_self->volume_header);
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         pself->is_eom = TRUE;
800         device_set_error(pself,
801             stralloc(_("No space left on device")),
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
816     return TRUE;
817 }
818
819 static int
820 vfs_device_read_block(Device * pself, gpointer data, int * size_req) {
821     VfsDevice * self;
822     int size;
823     IoResult result;
824
825     self = VFS_DEVICE(pself);
826
827     if (device_in_error(self)) return -1;
828
829     if (data == NULL || (gsize)*size_req < pself->block_size) {
830         /* Just a size query. */
831         g_assert(pself->block_size < INT_MAX);
832         *size_req = (int)pself->block_size;
833         return 0;
834     }
835
836     size = pself->block_size;
837     result = vfs_device_robust_read(self, data, &size);
838     switch (result) {
839     case RESULT_SUCCESS:
840         *size_req = size;
841         pself->block++;
842         return size;
843     case RESULT_NO_DATA:
844         pself->is_eof = TRUE;
845         pself->in_file = FALSE;
846         device_set_error(pself,
847             stralloc(_("EOF")),
848             DEVICE_STATUS_SUCCESS);
849         return -1;
850     default:
851         device_set_error(pself,
852             vstrallocf(_("Error reading from data file: %s"), strerror(errno)),
853             DEVICE_STATUS_DEVICE_ERROR);
854         return -1;
855     }
856
857     g_assert_not_reached();
858 }
859
860 static gboolean
861 vfs_device_start(Device * dself,
862                                  DeviceAccessMode mode, char * label,
863                                  char * timestamp) {
864     VfsDevice * self = VFS_DEVICE(dself);
865
866     if (!check_is_dir(self, self->dir_name)) {
867         /* error message set by check_is_dir */
868         return FALSE;
869     }
870
871     dself->in_file = FALSE;
872
873     if (mode == ACCESS_WRITE) {
874         promote_volume_lock(self);
875         if (!clear_and_prepare_label(self, label, timestamp)) {
876             /* clear_and_prepare_label sets error status if necessary */
877             demote_volume_lock(self);
878             return FALSE;
879         }
880
881         dself->volume_label = newstralloc(dself->volume_label, label);
882         dself->volume_time = newstralloc(dself->volume_time, timestamp);
883
884         /* unset the VOLUME_UNLABELED flag, if it was set */
885         device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
886
887         demote_volume_lock(self);
888         dself->access_mode = mode;
889     } else {
890         if (dself->volume_label == NULL && device_read_label(dself) != DEVICE_STATUS_SUCCESS) {
891             /* device_read_label already set our error message */
892             return FALSE;
893         } else {
894             dself->access_mode = mode;
895         }
896     }
897
898     release_file(self);
899
900     return TRUE;
901 }
902
903 static gboolean
904 vfs_device_finish (Device * pself) {
905     VfsDevice * self;
906     self = VFS_DEVICE(pself);
907
908     release_file(self);
909
910     pself->access_mode = ACCESS_NULL;
911     pself->in_file = FALSE;
912
913     if (device_in_error(self)) return FALSE;
914
915     return TRUE;
916 }
917
918 typedef struct {
919     VfsDevice * self;
920     int rval;
921 } glfn_data;
922
923 /* A SearchDirectoryFunctor. */
924 static gboolean get_last_file_number_functor(const char * filename,
925                                              gpointer datap) {
926     guint64 file;
927     glfn_data * data = (glfn_data*)datap;
928
929     file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
930     if (file > G_MAXINT) {
931         g_warning(_("Super-large device file %s found, ignoring"), filename);
932         return TRUE;
933     }
934     /* This condition is needlessly complex due to sign issues. */
935     if (data->rval < 0 || ((guint)data->rval) < file) {
936         data->rval = file;
937     }
938     return TRUE;
939 }
940
941 static gint
942 get_last_file_number(VfsDevice * self) {
943     glfn_data data;
944     int count;
945     Device *d_self = DEVICE(self);
946     data.self = self;
947     data.rval = -1;
948
949     count = search_vfs_directory(self, "^[0-9]+\\.",
950                                  get_last_file_number_functor, &data);
951
952     if (count <= 0) {
953         /* Somebody deleted something important while we weren't looking. */
954         device_set_error(d_self,
955             stralloc(_("Error identifying VFS device contents!")),
956             DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
957         return -1;
958     } else {
959         g_assert(data.rval >= 0);
960     }
961
962     return data.rval;
963 }
964
965 typedef struct {
966     VfsDevice * self;
967     guint request;
968     int best_found;
969 } gnfn_data;
970
971 /* A SearchDirectoryFunctor. */
972 static gboolean get_next_file_number_functor(const char * filename,
973                                              gpointer datap) {
974     guint file;
975     gnfn_data * data = (gnfn_data*)datap;
976
977     file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */
978     if (file > G_MAXINT) {
979         g_warning(_("Super-large device file %s found, ignoring"), filename);
980         return TRUE;
981     }
982     /* This condition is needlessly complex due to sign issues. */
983     if (file >= data->request &&
984         (data->best_found < 0 || file < (guint)data->best_found)) {
985         data->best_found = file;
986     }
987     return TRUE;
988 }
989
990 /* Returns the file number equal to or greater than the given requested
991  * file number. */
992 static gint
993 get_next_file_number(VfsDevice * self, guint request) {
994     gnfn_data data;
995     int count;
996     Device *d_self = DEVICE(self);
997     data.self = self;
998     data.request = request;
999     data.best_found = -1;
1000
1001     count = search_vfs_directory(self, "^[0-9]+\\.",
1002                                  get_next_file_number_functor, &data);
1003
1004     if (count <= 0) {
1005         /* Somebody deleted something important while we weren't looking. */
1006         device_set_error(d_self,
1007             stralloc(_("Error identifying VFS device contents!")),
1008             DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1009         return -1;
1010     }
1011
1012     /* Could be -1. */
1013     return data.best_found;
1014 }
1015
1016 /* Finds the file number, acquires a lock, and returns the new file name. */
1017 static
1018 char * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) {
1019     char * rval;
1020     char *base, *sanitary_base;
1021     int fileno;
1022
1023     for (;;) {
1024         fileno = 1 + get_last_file_number(self);
1025         if (fileno <= 0)
1026             return NULL;
1027
1028         if (open_lock(self, fileno, TRUE)) {
1029             break;
1030         } else {
1031             continue;
1032         }
1033     }
1034
1035     /* record that we're at this filenum now */
1036     DEVICE(self)->file = fileno;
1037
1038     base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk,
1039                            ji->dumplevel);
1040     sanitary_base = sanitise_filename(base);
1041     amfree(base);
1042     rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base);
1043     amfree(sanitary_base);
1044     return rval;
1045 }
1046
1047 static gboolean
1048 vfs_device_start_file (Device * dself, dumpfile_t * ji) {
1049     VfsDevice * self = VFS_DEVICE(dself);
1050
1051     dself->is_eom = FALSE;
1052
1053     if (device_in_error(self)) return FALSE;
1054
1055     /* set the blocksize in the header to 32k, since the VFS header is always
1056      * 32k regardless of the block_size setting */
1057     ji->blocksize = 32768;
1058
1059     if (check_at_leom(self, VFS_DEVICE_LABEL_SIZE))
1060         dself->is_eom = TRUE;
1061
1062     if (check_at_peom(self, VFS_DEVICE_LABEL_SIZE)) {
1063         dself->is_eom = TRUE;
1064         device_set_error(dself,
1065                 stralloc(_("No space left on device")),
1066                 DEVICE_STATUS_DEVICE_ERROR);
1067         return FALSE;
1068     }
1069
1070     /* The basic idea here is thus:
1071        1) Try to get a lock on the next filenumber.
1072        2) If that fails, update our idea of "next filenumber" and try again.
1073        3) Then open the file itself.
1074        4) Write the label.
1075        5) Chain up. */
1076
1077     self->file_name = make_new_file_name(self, ji);
1078     if (self->file_name == NULL) {
1079         device_set_error(dself,
1080                 stralloc(_("Could not create header filename")),
1081                 DEVICE_STATUS_DEVICE_ERROR);
1082         return FALSE;
1083     }
1084
1085     self->open_file_fd = robust_open(self->file_name,
1086                                      O_CREAT | O_EXCL | O_RDWR,
1087                                      VFS_DEVICE_CREAT_MODE);
1088     if (self->open_file_fd < 0) {
1089         device_set_error(dself,
1090                 vstrallocf(_("Can't create file %s: %s"), self->file_name, strerror(errno)),
1091                 DEVICE_STATUS_DEVICE_ERROR);
1092         release_file(self);
1093         return FALSE;
1094     }
1095
1096
1097     if (!write_amanda_header(self, ji)) {
1098         /* write_amanda_header sets error status if necessary */
1099         release_file(self);
1100         return FALSE;
1101     }
1102
1103     /* handle some accounting business */
1104     self->volume_bytes += VFS_DEVICE_LABEL_SIZE;
1105     self->checked_bytes_used += VFS_DEVICE_LABEL_SIZE;
1106     dself->in_file = TRUE;
1107     dself->block = 0;
1108     /* make_new_file_name set pself->file for us */
1109
1110     return TRUE;
1111 }
1112
1113 static gboolean
1114 vfs_device_finish_file(Device * dself) {
1115     VfsDevice * self = VFS_DEVICE(dself);
1116
1117     if (device_in_error(self)) return FALSE;
1118
1119     release_file(self);
1120
1121     dself->in_file = FALSE;
1122
1123     return TRUE;
1124 }
1125
1126 /* This function is used for two purposes, rather than one. In
1127  * addition to its documented behavior, we also use it to open the
1128  * volume label for reading at startup. In that second case, we avoid
1129  * FdDevice-related side effects. */
1130 static dumpfile_t *
1131 vfs_device_seek_file (Device * dself, guint requested_file) {
1132     VfsDevice *self = VFS_DEVICE(dself);
1133     int file;
1134     dumpfile_t * rval;
1135     char header_buffer[VFS_DEVICE_LABEL_SIZE];
1136     int header_buffer_size = sizeof(header_buffer);
1137     IoResult result;
1138
1139     if (device_in_error(self)) return NULL;
1140
1141     dself->in_file = FALSE;
1142     dself->is_eof = FALSE;
1143     dself->block = 0;
1144
1145     release_file(self);
1146
1147     if (requested_file > 0) {
1148         file = get_next_file_number(self, requested_file);
1149     } else {
1150         file = requested_file;
1151     }
1152
1153     if (file < 0) {
1154         /* Did they request one past the end? */
1155         char * tmp_file_name;
1156         tmp_file_name = file_number_to_file_name(self, requested_file - 1);
1157         if (tmp_file_name != NULL) {
1158             free(tmp_file_name);
1159             dself->file = requested_file; /* other attributes are already correct */
1160             return make_tapeend_header();
1161         } else {
1162             device_set_error(dself,
1163                 stralloc(_("Attempt to read past tape-end file")),
1164                 DEVICE_STATUS_SUCCESS);
1165             return NULL;
1166         }
1167     }
1168
1169     if (!open_lock(self, file, FALSE)) {
1170         device_set_error(dself,
1171             stralloc(_("could not acquire lock")),
1172             DEVICE_STATUS_DEVICE_ERROR);
1173         return NULL;
1174     }
1175
1176     self->file_name = file_number_to_file_name(self, file);
1177     if (self->file_name == NULL) {
1178         device_set_error(dself,
1179             vstrallocf(_("File %d not found"), file),
1180             file == 0 ? DEVICE_STATUS_VOLUME_UNLABELED
1181                       : DEVICE_STATUS_VOLUME_ERROR);
1182         release_file(self);
1183         rval = g_new(dumpfile_t, 1);
1184         fh_init(rval);
1185         return rval;
1186     }
1187
1188     self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0);
1189     if (self->open_file_fd < 0) {
1190         device_set_error(dself,
1191             vstrallocf(_("Couldn't open file %s: %s"), self->file_name, strerror(errno)),
1192             DEVICE_STATUS_DEVICE_ERROR);
1193         amfree(self->file_name);
1194         release_file(self);
1195         return NULL;
1196     }
1197
1198     result = vfs_device_robust_read(self, header_buffer,
1199                                     &header_buffer_size);
1200     if (result != RESULT_SUCCESS) {
1201         device_set_error(dself,
1202             vstrallocf(_("Problem reading Amanda header: %s"), device_error(dself)),
1203             DEVICE_STATUS_VOLUME_ERROR);
1204         release_file(self);
1205         return NULL;
1206     }
1207
1208     rval = g_new(dumpfile_t, 1);
1209     parse_file_header(header_buffer, rval, header_buffer_size);
1210     switch (rval->type) {
1211         case F_DUMPFILE:
1212         case F_CONT_DUMPFILE:
1213         case F_SPLIT_DUMPFILE:
1214             break;
1215
1216         case F_TAPESTART:
1217             /* file 0 should have a TAPESTART header; vfs_device_read_label
1218              * uses this */
1219             if (requested_file == 0)
1220                 break;
1221             /* FALLTHROUGH */
1222
1223         default:
1224             device_set_error(dself,
1225                 stralloc(_("Invalid amanda header while reading file header")),
1226                 DEVICE_STATUS_VOLUME_ERROR);
1227             amfree(rval);
1228             release_file(self);
1229             return NULL;
1230     }
1231
1232     /* update our state */
1233     dself->in_file = TRUE;
1234     dself->file = file;
1235
1236     return rval;
1237 }
1238
1239 static gboolean
1240 vfs_device_seek_block (Device * pself, guint64 block) {
1241     VfsDevice * self;
1242     off_t result;
1243
1244     self = VFS_DEVICE(pself);
1245
1246     g_assert(self->open_file_fd >= 0);
1247     g_assert(sizeof(off_t) >= sizeof(guint64));
1248     if (device_in_error(self)) return FALSE;
1249
1250     /* Pretty simple. We figure out the blocksize and use that. */
1251     result = lseek(self->open_file_fd,
1252                    (block) * pself->block_size + VFS_DEVICE_LABEL_SIZE,
1253                    SEEK_SET);
1254
1255     pself->block = block;
1256
1257     if (result == (off_t)(-1)) {
1258         device_set_error(pself,
1259             vstrallocf(_("Error seeking within file: %s"), strerror(errno)),
1260             DEVICE_STATUS_DEVICE_ERROR);
1261         return FALSE;
1262     }
1263
1264     return TRUE;
1265 }
1266
1267 static gboolean try_unlink(const char * file) {
1268     if (unlink(file) < 0) {
1269         return FALSE;
1270     } else {
1271         return TRUE;
1272     }
1273 }
1274
1275 static gboolean
1276 check_at_leom(VfsDevice *self, guint64 size)
1277 {
1278     gboolean recheck = FALSE;
1279     guint64 est_avail_now;
1280     struct fs_usage fsusage;
1281     guint64 block_size = DEVICE(self)->block_size;
1282     guint64 eom_warning_buffer = EOM_EARLY_WARNING_ZONE_BLOCKS * block_size;
1283
1284     if (!self->leom || !self->monitor_free_space)
1285         return FALSE;
1286
1287     /* handle VOLUME_LIMIT */
1288     if (self->enforce_volume_limit && self->volume_limit &&
1289             self->volume_bytes + size + eom_warning_buffer > self->volume_limit) {
1290         return TRUE;
1291     }
1292
1293     /* handle actual filesystem available space, using some heuristics to avoid polling this
1294      * too frequently */
1295     est_avail_now = 0;
1296     if (self->checked_fs_free_bytes >= self->checked_bytes_used + size)
1297         est_avail_now = self->checked_fs_free_bytes - self->checked_bytes_used - size;
1298
1299     /* is it time to check again? */
1300     if (est_avail_now <= block_size * MONITOR_FREE_SPACE_CLOSELY_WITHIN_BLOCKS) {
1301         recheck = TRUE;
1302     } else if (self->checked_bytes_used > MONITOR_FREE_SPACE_EVERY_KB * 1024) {
1303         recheck = TRUE;
1304     } else if (self->checked_fs_free_time + MONITOR_FREE_SPACE_EVERY_SECONDS <= time(NULL)) {
1305         recheck = TRUE;
1306     }
1307
1308     if (!recheck)
1309         return FALSE;
1310
1311     if (get_fs_usage(self->dir_name, NULL, &fsusage) < 0 || fsusage.fsu_bavail_top_bit_set) {
1312         g_warning("Filesystem cannot provide free space: %s; setting MONITOR_FREE_SPACE false",
1313                 fsusage.fsu_bavail_top_bit_set? "no result" : strerror(errno));
1314         self->monitor_free_space = FALSE;
1315         return FALSE;
1316     }
1317
1318     self->checked_fs_free_bytes = fsusage.fsu_bavail * fsusage.fsu_blocksize;
1319     self->checked_bytes_used = 0;
1320     self->checked_fs_free_time = time(NULL);
1321
1322     if (self->checked_fs_free_bytes - size <= eom_warning_buffer) {
1323         g_debug("%s: at LEOM", DEVICE(self)->device_name);
1324         return TRUE;
1325     }
1326
1327     return FALSE;
1328 }
1329
1330 static gboolean
1331 check_at_peom(VfsDevice *self, guint64 size)
1332 {
1333     if (self->enforce_volume_limit && (self->volume_limit > 0)) {
1334         guint64 newtotal = self->volume_bytes + size;
1335         if (newtotal > self->volume_limit) {
1336             return TRUE;
1337         }
1338     }
1339
1340     return FALSE;
1341 }
1342
1343 static gboolean
1344 vfs_device_recycle_file (Device * dself, guint filenum) {
1345     VfsDevice * self = VFS_DEVICE(dself);
1346     struct stat file_status;
1347     off_t file_size;
1348
1349     if (device_in_error(self)) return FALSE;
1350
1351     /* Game Plan:
1352      * 1) Get a write lock on the file in question.
1353      * 2) Unlink the file in question.
1354      * 3) Unlink the lock.
1355      * 4) Release the lock.
1356      * FIXME: Is it OK to unlink the lockfile?
1357      */
1358
1359     self->file_name = file_number_to_file_name(self, filenum);
1360     if (self->file_name == NULL) {
1361         device_set_error(dself,
1362             vstrallocf(_("File %d not found"), filenum),
1363             DEVICE_STATUS_VOLUME_ERROR);
1364         return FALSE;
1365     }
1366
1367     if (!open_lock(self, filenum, FALSE)) {
1368         device_set_error(dself,
1369             stralloc(_("could not acquire lock")),
1370             DEVICE_STATUS_DEVICE_ERROR);
1371         return FALSE;
1372     }
1373
1374     if (0 != stat(self->file_name, &file_status)) {
1375         device_set_error(dself,
1376             vstrallocf(_("Cannot stat file %s (%s), so not removing"),
1377                                     self->file_name, strerror(errno)),
1378             DEVICE_STATUS_VOLUME_ERROR);
1379         return FALSE;
1380     }
1381     file_size = file_status.st_size;
1382
1383     if (!try_unlink(self->file_name)) {
1384         device_set_error(dself,
1385             vstrallocf(_("Unlink of %s failed: %s"), self->file_name, strerror(errno)),
1386             DEVICE_STATUS_VOLUME_ERROR);
1387         release_file(self);
1388         return FALSE;
1389     }
1390
1391     self->volume_bytes -= file_size;
1392     release_file(self);
1393     return TRUE;
1394 }
1395
1396 static gboolean
1397 vfs_device_erase (Device * dself) {
1398     VfsDevice *self = VFS_DEVICE(dself);
1399
1400     if (!open_lock(self, 0, TRUE))
1401         return FALSE;
1402
1403     delete_vfs_files(self);
1404
1405     release_file(self);
1406
1407     return TRUE;
1408 }
1409
1410 static IoResult vfs_device_robust_read(VfsDevice * self, char *buf,
1411                                              int *count) {
1412     int fd = self->open_file_fd;
1413     Device *d_self = DEVICE(self);
1414     int want = *count, got = 0;
1415
1416     while (got < want) {
1417         int result;
1418         result = read(fd, buf + got, want - got);
1419         if (result > 0) {
1420             got += result;
1421         } else if (result == 0) {
1422             /* end of file */
1423             if (got == 0) {
1424                 return RESULT_NO_DATA;
1425             } else {
1426                 *count = got;
1427                 return RESULT_SUCCESS;
1428             }
1429         } else if (0
1430 #ifdef EAGAIN
1431                 || errno == EAGAIN
1432 #endif
1433 #ifdef EWOULDBLOCK
1434                 || errno == EWOULDBLOCK
1435 #endif
1436 #ifdef EINTR
1437                 || errno == EINTR
1438 #endif
1439                    ) {
1440             /* Try again. */
1441             continue;
1442         } else {
1443             /* Error occured. */
1444             device_set_error(d_self,
1445                 vstrallocf(_("Error reading fd %d: %s"), fd, strerror(errno)),
1446                 DEVICE_STATUS_VOLUME_ERROR);
1447             *count = got;
1448             return RESULT_ERROR;
1449         }
1450     }
1451
1452     *count = got;
1453     return RESULT_SUCCESS;
1454 }
1455
1456 static IoResult
1457 vfs_device_robust_write(VfsDevice * self,  char *buf, int count) {
1458     int fd = self->open_file_fd;
1459     Device *d_self = DEVICE(self);
1460     int rval = 0;
1461
1462     while (rval < count) {
1463         int result;
1464         result = write(fd, buf + rval, count - rval);
1465         if (result > 0) {
1466             rval += result;
1467             continue;
1468         } else if (0
1469 #ifdef EAGAIN
1470                 || errno == EAGAIN
1471 #endif
1472 #ifdef EWOULDBLOCK
1473                 || errno == EWOULDBLOCK
1474 #endif
1475 #ifdef EINTR
1476                 || errno == EINTR
1477 #endif
1478                    ) {
1479             /* Try again. */
1480             continue;
1481         } else if (0
1482 #ifdef EFBIG
1483                    || errno == EFBIG
1484 #endif
1485 #ifdef ENOSPC
1486                    || errno == ENOSPC
1487 #endif
1488                    ) {
1489             /* We are definitely out of space. */
1490             device_set_error(d_self,
1491                     vstrallocf(_("No space left on device: %s"), strerror(errno)),
1492                     DEVICE_STATUS_VOLUME_ERROR);
1493             return RESULT_NO_SPACE;
1494         } else {
1495             /* Error occured. Note that here we handle EIO as an error. */
1496             device_set_error(d_self,
1497                     vstrallocf(_("Error writing device fd %d: %s"), fd, strerror(errno)),
1498                     DEVICE_STATUS_VOLUME_ERROR);
1499             return RESULT_ERROR;
1500         }
1501     }
1502     return RESULT_SUCCESS;
1503 }
1504
1505 /* TODO: add prop */