PageRenderTime 69ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

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

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