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