PageRenderTime 55ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/tags/amanda260p2/device-src/vfs-device.c

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