PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

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

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