PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/tags/3_3_0_qa07/device-src/vfs-device.c

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