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

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

#
C | 1667 lines | 1287 code | 287 blank | 93 comment | 202 complexity | c10a85f267944ca10bb4c717abd98fcc 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. /* The Device API abstracts device workings, interaction, properties, and
  21. * capabilities from the rest of the Amanda code base. It supports
  22. * pluggable modules for different kinds of devices. */
  23. #include "amanda.h"
  24. #include "conffile.h"
  25. #include <regex.h>
  26. #include "device.h"
  27. #include "queueing.h"
  28. #include "device-queueing.h"
  29. #include "property.h"
  30. #include "timestamp.h"
  31. #include "util.h"
  32. /*
  33. * Prototypes for subclass registration functions
  34. */
  35. void null_device_register (void);
  36. void rait_device_register (void);
  37. #ifdef WANT_S3_DEVICE
  38. void s3_device_register (void);
  39. #endif
  40. #ifdef WANT_TAPE_DEVICE
  41. void tape_device_register (void);
  42. #endif
  43. void vfs_device_register (void);
  44. #ifdef WANT_DVDRW_DEVICE
  45. void dvdrw_device_register (void);
  46. #endif
  47. #ifdef WANT_NDMP_DEVICE
  48. void ndmp_device_register (void);
  49. #endif
  50. /*
  51. * Registration infrastructure
  52. */
  53. static GHashTable* driverList = NULL;
  54. void device_api_init(void) {
  55. glib_init();
  56. device_property_init();
  57. driverList = g_hash_table_new(g_str_hash, g_str_equal);
  58. /* register other types and devices. */
  59. null_device_register();
  60. vfs_device_register();
  61. #ifdef WANT_TAPE_DEVICE
  62. tape_device_register();
  63. #endif
  64. rait_device_register();
  65. #ifdef WANT_S3_DEVICE
  66. s3_device_register();
  67. #endif
  68. #ifdef WANT_DVDRW_DEVICE
  69. dvdrw_device_register();
  70. #endif
  71. #ifdef WANT_NDMP_DEVICE
  72. ndmp_device_register();
  73. #endif
  74. }
  75. void
  76. register_device(
  77. DeviceFactory factory,
  78. const char ** device_prefix_list)
  79. {
  80. char ** tmp;
  81. g_assert(driverList != NULL);
  82. g_assert(factory != NULL);
  83. g_return_if_fail(device_prefix_list != NULL);
  84. g_return_if_fail(*device_prefix_list != NULL);
  85. tmp = (char**)device_prefix_list;
  86. while (*tmp != NULL) {
  87. g_hash_table_insert(driverList, *tmp, (gpointer)factory);
  88. tmp ++;
  89. }
  90. }
  91. static DeviceFactory lookup_device_factory(const char *device_type) {
  92. gpointer key, value;
  93. g_assert(driverList != NULL);
  94. if (g_hash_table_lookup_extended(driverList, device_type, &key, &value)) {
  95. return (DeviceFactory)value;
  96. } else {
  97. return NULL;
  98. }
  99. }
  100. static const GFlagsValue device_status_flags_values[] = {
  101. { DEVICE_STATUS_SUCCESS,
  102. "DEVICE_STATUS_SUCCESS",
  103. "Success" },
  104. { DEVICE_STATUS_DEVICE_ERROR,
  105. "DEVICE_STATUS_DEVICE_ERROR",
  106. "Device error" },
  107. { DEVICE_STATUS_DEVICE_BUSY,
  108. "DEVICE_STATUS_DEVICE_BUSY",
  109. "Device busy" },
  110. { DEVICE_STATUS_VOLUME_MISSING,
  111. "DEVICE_STATUS_VOLUME_MISSING",
  112. "Volume not found" },
  113. { DEVICE_STATUS_VOLUME_UNLABELED,
  114. "DEVICE_STATUS_VOLUME_UNLABELED",
  115. "Volume not labeled" },
  116. { DEVICE_STATUS_VOLUME_ERROR,
  117. "DEVICE_STATUS_VOLUME_ERROR",
  118. "Volume error" },
  119. { 0, NULL, NULL }
  120. };
  121. GType device_status_flags_get_type(void) {
  122. static GType type = 0;
  123. if (G_UNLIKELY(type == 0)) {
  124. type = g_flags_register_static("DeviceStatusFlags",
  125. device_status_flags_values);
  126. }
  127. return type;
  128. }
  129. /* Device class definition starts here. */
  130. struct DevicePrivate_s {
  131. /* hash table mapping ID to SimpleProperty object */
  132. GHashTable * simple_properties;
  133. /* In writing mode, after a short block is written, no additional blocks
  134. * are allowed the file is finished and a new file started. This is only
  135. * used for assertions. */
  136. gboolean wrote_short_block;
  137. /* Holds an error message if the function returned an error. */
  138. char * errmsg;
  139. /* temporary holding place for device_status_error() */
  140. char * statusmsg;
  141. DeviceStatusFlags last_status;
  142. };
  143. /* This holds the default response to a particular property. */
  144. typedef struct {
  145. DeviceProperty *prop;
  146. GValue response;
  147. PropertySurety surety;
  148. PropertySource source;
  149. } SimpleProperty;
  150. #define selfp (self->private)
  151. /* here are local prototypes, so we can make function pointers. */
  152. static void device_init (Device * o);
  153. static void device_class_init (DeviceClass * c);
  154. static void device_base_init (DeviceClass * c);
  155. static void simple_property_free(SimpleProperty *o);
  156. static void default_device_open_device(Device * self, char * device_name,
  157. char * device_type, char * device_node);
  158. static gboolean default_device_configure(Device *self, gboolean use_global_config);
  159. static gboolean default_device_write_from_fd(Device *self,
  160. queue_fd_t *queue_fd);
  161. static gboolean default_device_read_to_fd(Device *self, queue_fd_t *queue_fd);
  162. static gboolean default_device_property_get_ex(Device * self, DevicePropertyId id,
  163. GValue * val,
  164. PropertySurety *surety,
  165. PropertySource *source);
  166. static gboolean default_device_property_set_ex(Device *self,
  167. DevicePropertyId id,
  168. GValue * val,
  169. PropertySurety surety,
  170. PropertySource source);
  171. static void set_properties_from_global_config(Device * device);
  172. static void set_properties_from_device_config(Device * device, device_config_t *dc);
  173. static gboolean property_get_block_size_fn(Device *self,
  174. DevicePropertyBase *base, GValue *val,
  175. PropertySurety *surety, PropertySource *source);
  176. static gboolean property_set_block_size_fn(Device *self,
  177. DevicePropertyBase *base, GValue *val,
  178. PropertySurety surety, PropertySource source);
  179. static gboolean property_get_min_block_size_fn(Device *self,
  180. DevicePropertyBase *base, GValue *val,
  181. PropertySurety *surety, PropertySource *source);
  182. static gboolean property_get_max_block_size_fn(Device *self,
  183. DevicePropertyBase *base, GValue *val,
  184. PropertySurety *surety, PropertySource *source);
  185. static gboolean property_get_canonical_name_fn(Device *self,
  186. DevicePropertyBase *base, GValue *val,
  187. PropertySurety *surety, PropertySource *source);
  188. /* pointer to the class of our parent */
  189. static GObjectClass *parent_class = NULL;
  190. GType
  191. device_get_type (void)
  192. {
  193. static GType type = 0;
  194. if G_UNLIKELY(type == 0) {
  195. static const GTypeInfo info = {
  196. sizeof (DeviceClass),
  197. (GBaseInitFunc) device_base_init,
  198. (GBaseFinalizeFunc) NULL,
  199. (GClassInitFunc) device_class_init,
  200. (GClassFinalizeFunc) NULL,
  201. NULL /* class_data */,
  202. sizeof (Device),
  203. 0 /* n_preallocs */,
  204. (GInstanceInitFunc) device_init,
  205. NULL
  206. };
  207. type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
  208. (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
  209. }
  210. return type;
  211. }
  212. static void device_finalize(GObject *obj_self) {
  213. Device *self G_GNUC_UNUSED = DEVICE (obj_self);
  214. if(G_OBJECT_CLASS(parent_class)->finalize)
  215. (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
  216. /* Here we call device_finish() if it hasn't been done
  217. yet. Subclasses may need to do this same check earlier. */
  218. if (self->access_mode != ACCESS_NULL) {
  219. device_finish(self);
  220. }
  221. amfree(self->device_name);
  222. amfree(self->volume_label);
  223. amfree(self->volume_time);
  224. amfree(self->volume_header);
  225. amfree(selfp->errmsg);
  226. amfree(selfp->statusmsg);
  227. g_hash_table_destroy(selfp->simple_properties);
  228. amfree(self->private);
  229. }
  230. static void
  231. device_init (Device * self)
  232. {
  233. self->private = malloc(sizeof(DevicePrivate));
  234. self->device_name = NULL;
  235. self->access_mode = ACCESS_NULL;
  236. self->is_eof = FALSE;
  237. self->is_eom = FALSE;
  238. self->file = -1;
  239. self->block = 0;
  240. self->in_file = FALSE;
  241. self->volume_label = NULL;
  242. self->volume_time = NULL;
  243. self->status = DEVICE_STATUS_SUCCESS;
  244. self->min_block_size = 1;
  245. self->max_block_size = SIZE_MAX; /* subclasses *really* should choose something smaller */
  246. self->block_size = DISK_BLOCK_BYTES;
  247. selfp->errmsg = NULL;
  248. selfp->statusmsg = NULL;
  249. selfp->last_status = 0;
  250. selfp->simple_properties =
  251. g_hash_table_new_full(g_direct_hash,
  252. g_direct_equal,
  253. NULL,
  254. (GDestroyNotify) simple_property_free);
  255. }
  256. static void
  257. device_class_init (DeviceClass * device_class)
  258. {
  259. GObjectClass *g_object_class = (GObjectClass*) device_class;
  260. parent_class = g_type_class_ref (G_TYPE_OBJECT);
  261. device_class->directtcp_supported = FALSE;
  262. device_class->open_device = default_device_open_device;
  263. device_class->configure = default_device_configure;
  264. device_class->write_from_fd = default_device_write_from_fd;
  265. device_class->read_to_fd = default_device_read_to_fd;
  266. device_class->property_get_ex = default_device_property_get_ex;
  267. device_class->property_set_ex = default_device_property_set_ex;
  268. g_object_class->finalize = device_finalize;
  269. }
  270. static void
  271. device_base_init (DeviceClass * device_class)
  272. {
  273. /* The base_init function is called once each time a child class is
  274. * created, before the class_init functions (even our own) are called. */
  275. device_class->class_properties = g_array_new(FALSE, TRUE, sizeof(DeviceProperty));
  276. device_class->class_properties_list = NULL;
  277. device_class_register_property(device_class, PROPERTY_BLOCK_SIZE,
  278. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  279. property_get_block_size_fn,
  280. property_set_block_size_fn);
  281. device_class_register_property(device_class, PROPERTY_MIN_BLOCK_SIZE,
  282. PROPERTY_ACCESS_GET_MASK,
  283. property_get_min_block_size_fn,
  284. NULL);
  285. device_class_register_property(device_class, PROPERTY_MAX_BLOCK_SIZE,
  286. PROPERTY_ACCESS_GET_MASK,
  287. property_get_max_block_size_fn,
  288. NULL);
  289. device_class_register_property(device_class, PROPERTY_CANONICAL_NAME,
  290. PROPERTY_ACCESS_GET_MASK,
  291. property_get_canonical_name_fn,
  292. NULL);
  293. device_class_register_property(device_class, PROPERTY_CONCURRENCY,
  294. PROPERTY_ACCESS_GET_MASK,
  295. device_simple_property_get_fn,
  296. device_simple_property_set_fn);
  297. device_class_register_property(device_class, PROPERTY_STREAMING,
  298. PROPERTY_ACCESS_GET_MASK,
  299. device_simple_property_get_fn,
  300. device_simple_property_set_fn);
  301. device_class_register_property(device_class, PROPERTY_APPENDABLE,
  302. PROPERTY_ACCESS_GET_MASK,
  303. device_simple_property_get_fn,
  304. device_simple_property_set_fn);
  305. device_class_register_property(device_class, PROPERTY_PARTIAL_DELETION,
  306. PROPERTY_ACCESS_GET_MASK,
  307. device_simple_property_get_fn,
  308. device_simple_property_set_fn);
  309. device_class_register_property(device_class, PROPERTY_FULL_DELETION,
  310. PROPERTY_ACCESS_GET_MASK,
  311. device_simple_property_get_fn,
  312. device_simple_property_set_fn);
  313. device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE,
  314. PROPERTY_ACCESS_GET_MASK,
  315. device_simple_property_get_fn,
  316. device_simple_property_set_fn);
  317. device_class_register_property(device_class, PROPERTY_COMMENT,
  318. PROPERTY_ACCESS_GET_MASK|PROPERTY_ACCESS_SET_MASK,
  319. device_simple_property_get_fn,
  320. device_simple_property_set_fn);
  321. }
  322. static void simple_property_free(SimpleProperty * resp) {
  323. g_value_unset(&(resp->response));
  324. amfree(resp);
  325. }
  326. static char *
  327. regex_message(int result, regex_t *regex) {
  328. char * rval;
  329. size_t size;
  330. size = regerror(result, regex, NULL, 0);
  331. rval = malloc(size);
  332. regerror(result, regex, rval, size);
  333. return rval;
  334. }
  335. static gboolean
  336. handle_device_regex(const char * user_name, char ** driver_name,
  337. char ** device, char **errmsg) {
  338. regex_t regex;
  339. int reg_result;
  340. regmatch_t pmatch[3];
  341. static const char * regex_string = "^([a-z0-9]+):(.*)$";
  342. bzero(&regex, sizeof(regex));
  343. reg_result = regcomp(&regex, regex_string, REG_EXTENDED | REG_ICASE);
  344. if (reg_result != 0) {
  345. char * message = regex_message(reg_result, &regex);
  346. *errmsg = newvstrallocf(*errmsg, "Error compiling regular expression \"%s\": %s\n",
  347. regex_string, message);
  348. amfree(message);
  349. return FALSE;
  350. }
  351. reg_result = regexec(&regex, user_name, 3, pmatch, 0);
  352. if (reg_result != 0 && reg_result != REG_NOMATCH) {
  353. char * message = regex_message(reg_result, &regex);
  354. *errmsg = newvstrallocf(*errmsg,
  355. "Error applying regular expression \"%s\" to string \"%s\": %s\n",
  356. user_name, regex_string, message);
  357. amfree(message);
  358. regfree(&regex);
  359. return FALSE;
  360. } else if (reg_result == REG_NOMATCH) {
  361. #ifdef WANT_TAPE_DEVICE
  362. g_warning(
  363. "\"%s\" uses deprecated device naming convention; \n"
  364. "using \"tape:%s\" instead.\n",
  365. user_name, user_name);
  366. *driver_name = stralloc("tape");
  367. *device = stralloc(user_name);
  368. #else /* !WANT_TAPE_DEVICE */
  369. errmsg = newvstrallocf(errmsg, "\"%s\" is not a valid device name.\n", user_name);
  370. regfree(&regex);
  371. return FALSE;
  372. #endif /* WANT_TAPE_DEVICE */
  373. } else {
  374. *driver_name = find_regex_substring(user_name, pmatch[1]);
  375. *device = find_regex_substring(user_name, pmatch[2]);
  376. }
  377. regfree(&regex);
  378. return TRUE;
  379. }
  380. /* helper function for device_open */
  381. static Device *
  382. make_null_error(char *errmsg, DeviceStatusFlags status)
  383. {
  384. DeviceFactory factory;
  385. Device *device;
  386. factory = lookup_device_factory("null");
  387. g_assert(factory != NULL);
  388. device = factory("null:", "null", "");
  389. device_set_error(device, errmsg, status);
  390. return device;
  391. }
  392. char *
  393. device_unaliased_name(
  394. char *device_name)
  395. {
  396. device_config_t *dc;
  397. char *unaliased_name;
  398. /* look up the unaliased device name in the configuration */
  399. if ((dc = lookup_device_config(device_name))) {
  400. if (!(unaliased_name = device_config_get_tapedev(dc))
  401. || unaliased_name[0] == '\0') {
  402. return NULL;
  403. }
  404. } else {
  405. unaliased_name = device_name;
  406. }
  407. return unaliased_name;
  408. }
  409. Device*
  410. device_open (char * device_name)
  411. {
  412. char *device_type = NULL;
  413. char *device_node = NULL;
  414. char *errmsg = NULL;
  415. char *unaliased_name = NULL;
  416. DeviceFactory factory;
  417. Device *device;
  418. g_assert(device_name != NULL);
  419. if (driverList == NULL) {
  420. g_critical("device_open() called without device_api_init()!");
  421. g_assert_not_reached();
  422. }
  423. if (device_name == NULL)
  424. return make_null_error(stralloc(_("No device name specified")), DEVICE_STATUS_DEVICE_ERROR);
  425. unaliased_name = device_unaliased_name(device_name);
  426. if (!unaliased_name) {
  427. return make_null_error(
  428. vstrallocf(_("Device '%s' has no tapedev"), device_name),
  429. DEVICE_STATUS_DEVICE_ERROR);
  430. }
  431. if (!handle_device_regex(unaliased_name, &device_type, &device_node,
  432. &errmsg)) {
  433. amfree(device_type);
  434. amfree(device_node);
  435. return make_null_error(errmsg, DEVICE_STATUS_DEVICE_ERROR);
  436. }
  437. factory = lookup_device_factory(device_type);
  438. if (factory == NULL) {
  439. Device *nulldev = make_null_error(vstrallocf(_("Device type %s is not known."),
  440. device_type), DEVICE_STATUS_DEVICE_ERROR);
  441. amfree(device_type);
  442. amfree(device_node);
  443. return nulldev;
  444. }
  445. device = factory(device_name, device_type, device_node);
  446. g_assert(device != NULL); /* factories must always return a device */
  447. amfree(device_type);
  448. amfree(device_node);
  449. return device;
  450. }
  451. char *
  452. device_error(Device * self)
  453. {
  454. if (self == NULL) {
  455. return device_error_or_status(self);
  456. } else if (selfp->errmsg) {
  457. return selfp->errmsg;
  458. } else {
  459. return "Unknown Device error";
  460. }
  461. }
  462. char *
  463. device_status_error(Device * self)
  464. {
  465. char **status_strv;
  466. char *statusmsg;
  467. if (self == NULL) {
  468. return device_error_or_status(self);
  469. }
  470. /* reuse a previous statusmsg, if it was for the same status */
  471. if (selfp->statusmsg && selfp->last_status == self->status)
  472. return selfp->statusmsg;
  473. amfree(selfp->statusmsg);
  474. status_strv = g_flags_nick_to_strv(self->status, DEVICE_STATUS_FLAGS_TYPE);
  475. g_assert(g_strv_length(status_strv) > 0);
  476. if (g_strv_length(status_strv) == 1) {
  477. statusmsg = stralloc(*status_strv);
  478. } else {
  479. char * status_list = g_english_strjoinv(status_strv, "or");
  480. statusmsg = g_strdup_printf("one of %s", status_list);
  481. amfree(status_list);
  482. }
  483. g_strfreev(status_strv);
  484. selfp->statusmsg = statusmsg;
  485. selfp->last_status = self->status;
  486. return statusmsg;
  487. }
  488. char *
  489. device_error_or_status(Device * self)
  490. {
  491. if (self == NULL) {
  492. return "Device is NULL";
  493. } else if (selfp->errmsg) {
  494. return selfp->errmsg;
  495. } else {
  496. return device_status_error(self);
  497. }
  498. }
  499. void
  500. device_set_error(Device *self, char *errmsg, DeviceStatusFlags new_flags)
  501. {
  502. char **flags_strv;
  503. char *flags_str;
  504. char *device_name;
  505. if (!self) {
  506. g_warning("device_set_error called with a NULL device: '%s'", errmsg? errmsg:"(NULL)");
  507. amfree(errmsg);
  508. return;
  509. }
  510. device_name = self->device_name? self->device_name : "(unknown device)";
  511. if (errmsg && (!selfp->errmsg || strcmp(errmsg, selfp->errmsg) != 0))
  512. g_debug("Device %s error = '%s'", device_name, errmsg);
  513. amfree(selfp->errmsg);
  514. selfp->errmsg = errmsg;
  515. if (new_flags != DEVICE_STATUS_SUCCESS) {
  516. flags_strv = g_flags_name_to_strv(new_flags, DEVICE_STATUS_FLAGS_TYPE);
  517. g_assert(g_strv_length(flags_strv) > 0);
  518. flags_str = g_english_strjoinv(flags_strv, "and");
  519. g_debug("Device %s setting status flag(s): %s", device_name, flags_str);
  520. amfree(flags_str);
  521. g_strfreev(flags_strv);
  522. }
  523. self->status = new_flags;
  524. }
  525. char * device_build_amanda_header(Device * self, const dumpfile_t * info,
  526. size_t *size) {
  527. return build_header(info, size, self->block_size);
  528. }
  529. dumpfile_t * make_tapestart_header(Device * self, char * label,
  530. char * timestamp) {
  531. dumpfile_t * rval;
  532. GValue val;
  533. bzero(&val, sizeof(val));
  534. g_assert(label != NULL);
  535. rval = malloc(sizeof(*rval));
  536. fh_init(rval);
  537. rval->type = F_TAPESTART;
  538. if (device_property_get(self, PROPERTY_BLOCK_SIZE, &val)) {
  539. rval->blocksize = g_value_get_int(&val);
  540. g_value_unset(&val);
  541. }
  542. amfree(self->volume_time);
  543. if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  544. self->volume_time = get_proper_stamp_from_time(time(NULL));
  545. } else {
  546. self->volume_time = g_strdup(timestamp);
  547. }
  548. strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
  549. strncpy(rval->name, label, sizeof(rval->name));
  550. return rval;
  551. }
  552. dumpfile_t * make_tapeend_header(void) {
  553. dumpfile_t * rval;
  554. char * timestamp;
  555. rval = malloc(sizeof(*rval));
  556. rval->type = F_TAPEEND;
  557. timestamp = get_timestamp_from_time(time(NULL));
  558. strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
  559. amfree(timestamp);
  560. return rval;
  561. }
  562. /* Try setting the blocksize on a device. Check results, fallback, and
  563. * set error status for problems. */
  564. static gboolean
  565. try_set_blocksize(Device * device, guint blocksize) {
  566. GValue val;
  567. gboolean success;
  568. bzero(&val, sizeof(val));
  569. g_value_init(&val, G_TYPE_INT);
  570. g_value_set_int(&val, blocksize);
  571. success = device_property_set(device, PROPERTY_BLOCK_SIZE, &val);
  572. g_value_unset(&val);
  573. if (!success) {
  574. device_set_error(device,
  575. vstrallocf(_("Setting BLOCK_SIZE to %u "
  576. "not supported for device %s.\n"),
  577. blocksize, device->device_name),
  578. DEVICE_STATUS_DEVICE_ERROR);
  579. }
  580. return success;
  581. }
  582. /* A GHFunc (callback for g_hash_table_foreach) */
  583. static void set_device_property(gpointer key_p, gpointer value_p,
  584. gpointer user_data_p) {
  585. char * property_s = key_p;
  586. property_t * property = value_p;
  587. Device * device = user_data_p;
  588. const DevicePropertyBase* property_base;
  589. GValue property_value;
  590. char * value;
  591. g_return_if_fail(IS_DEVICE(device));
  592. g_return_if_fail(property_s != NULL);
  593. g_return_if_fail(property != NULL);
  594. g_return_if_fail(property->values != NULL);
  595. /* don't continue beating on a device that's already erroring */
  596. if (device_in_error(device)) return;
  597. property_base = device_property_get_by_name(property_s);
  598. if (property_base == NULL) {
  599. /* Nonexistant property name. */
  600. device_set_error(device,
  601. vstrallocf(_("unknown device property name '%s'"), property_s),
  602. DEVICE_STATUS_DEVICE_ERROR);
  603. return;
  604. }
  605. if (g_slist_length(property->values) > 1) {
  606. device_set_error(device,
  607. vstrallocf(_("multiple values for device property '%s'"), property_s),
  608. DEVICE_STATUS_DEVICE_ERROR);
  609. return;
  610. }
  611. bzero(&property_value, sizeof(property_value));
  612. g_value_init(&property_value, property_base->type);
  613. value = property->values->data;
  614. if (!g_value_set_from_string(&property_value, value)) {
  615. /* Value type could not be interpreted. */
  616. device_set_error(device,
  617. vstrallocf(_("Could not parse property value '%s' for property '%s' (property type %s)"),
  618. value, property_base->name, g_type_name(property_base->type)),
  619. DEVICE_STATUS_DEVICE_ERROR);
  620. return;
  621. } else {
  622. g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
  623. }
  624. if (!device_property_set(device, property_base->ID, &property_value)) {
  625. /* Device rejects property. */
  626. if (!device_in_error(device)) {
  627. device_set_error(device,
  628. vstrallocf(_("Could not set property '%s' to '%s' on %s"),
  629. property_base->name, value, device->device_name),
  630. DEVICE_STATUS_DEVICE_ERROR);
  631. }
  632. return;
  633. }
  634. }
  635. /* Set up properties based on various taper-related configuration parameters
  636. * and from the tapetype.
  637. */
  638. static void
  639. set_properties_from_global_config(Device * device) {
  640. char * tapetype_name = getconf_str(CNF_TAPETYPE);
  641. if (tapetype_name != NULL) {
  642. tapetype_t * tapetype = lookup_tapetype(tapetype_name);
  643. if (tapetype != NULL) {
  644. GValue val;
  645. guint64 length;
  646. guint blocksize_kb;
  647. gboolean success;
  648. bzero(&val, sizeof(GValue));
  649. if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
  650. length = tapetype_get_length(tapetype);
  651. g_value_init(&val, G_TYPE_UINT64);
  652. g_value_set_uint64(&val, length * 1024);
  653. /* If this fails, it's not really an error. */
  654. device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
  655. g_value_unset(&val);
  656. }
  657. if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
  658. blocksize_kb = tapetype_get_readblocksize(tapetype);
  659. g_value_init(&val, G_TYPE_UINT);
  660. g_value_set_uint(&val, blocksize_kb * 1024);
  661. success = device_property_set(device,
  662. PROPERTY_READ_BLOCK_SIZE,
  663. &val);
  664. g_value_unset(&val);
  665. if (!success) {
  666. /* a non-fatal error */
  667. g_warning("Setting READ_BLOCK_SIZE to %ju not supported for device %s.",
  668. 1024*(uintmax_t)blocksize_kb, device->device_name);
  669. }
  670. }
  671. if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
  672. blocksize_kb = tapetype_get_blocksize(tapetype);
  673. /* TODO: handle errors */
  674. (void)try_set_blocksize(device, blocksize_kb * 1024);
  675. }
  676. }
  677. }
  678. g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
  679. set_device_property, device);
  680. }
  681. /* Set properties specified within a device definition */
  682. static void
  683. set_properties_from_device_config(Device * device, device_config_t *dc) {
  684. g_hash_table_foreach(device_config_get_property(dc),
  685. set_device_property, device);
  686. }
  687. static gboolean
  688. default_device_configure(Device *self, gboolean use_global_config)
  689. {
  690. device_config_t *dc;
  691. if (device_in_error(self))
  692. return FALSE;
  693. if (use_global_config)
  694. set_properties_from_global_config(self);
  695. if (device_in_error(self))
  696. return FALSE;
  697. if ((dc = lookup_device_config(self->device_name)))
  698. set_properties_from_device_config(self, dc);
  699. return !device_in_error(self);
  700. }
  701. void device_clear_volume_details(Device * device) {
  702. if (device == NULL || device->access_mode != ACCESS_NULL) {
  703. return;
  704. }
  705. amfree(device->volume_label);
  706. amfree(device->volume_time);
  707. }
  708. /* Here we put default implementations of virtual functions. Since
  709. this class is virtual, many of these functions offer at best
  710. incomplete functionality. But they do offer the useful commonality
  711. that all devices can expect to need. */
  712. static void default_device_open_device(Device * self, char * device_name,
  713. char * device_type G_GNUC_UNUSED, char * device_node G_GNUC_UNUSED) {
  714. /* Set the device_name property */
  715. self->device_name = stralloc(device_name);
  716. }
  717. static gboolean
  718. property_get_block_size_fn(
  719. Device *self,
  720. DevicePropertyBase *base G_GNUC_UNUSED,
  721. GValue *val,
  722. PropertySurety *surety,
  723. PropertySource *source)
  724. {
  725. g_value_unset_init(val, G_TYPE_INT);
  726. g_assert(self->block_size < G_MAXINT); /* gsize -> gint */
  727. g_value_set_int(val, (gint)self->block_size);
  728. if (surety)
  729. *surety = self->block_size_surety;
  730. if (source)
  731. *source = self->block_size_source;
  732. return TRUE;
  733. }
  734. static gboolean
  735. property_set_block_size_fn(
  736. Device *self,
  737. DevicePropertyBase *base G_GNUC_UNUSED,
  738. GValue *val,
  739. PropertySurety surety,
  740. PropertySource source)
  741. {
  742. gint block_size = g_value_get_int(val);
  743. g_assert(block_size >= 0); /* int -> gsize (unsigned) */
  744. if ((gsize)block_size < self->min_block_size
  745. || (gsize)block_size > self->max_block_size)
  746. return FALSE;
  747. self->block_size = block_size;
  748. self->block_size_surety = surety;
  749. self->block_size_source = source;
  750. return TRUE;
  751. }
  752. static gboolean
  753. property_get_min_block_size_fn(
  754. Device *self,
  755. DevicePropertyBase *base G_GNUC_UNUSED,
  756. GValue *val,
  757. PropertySurety *surety,
  758. PropertySource *source)
  759. {
  760. g_value_unset_init(val, G_TYPE_UINT);
  761. g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
  762. g_value_set_uint(val, (guint)self->min_block_size);
  763. if (surety)
  764. *surety = PROPERTY_SURETY_GOOD;
  765. if (source)
  766. *source = PROPERTY_SOURCE_DEFAULT;
  767. return TRUE;
  768. }
  769. static gboolean
  770. property_get_max_block_size_fn(
  771. Device *self,
  772. DevicePropertyBase *base G_GNUC_UNUSED,
  773. GValue *val,
  774. PropertySurety *surety,
  775. PropertySource *source)
  776. {
  777. g_value_unset_init(val, G_TYPE_UINT);
  778. g_assert(self->block_size < G_MAXUINT); /* gsize -> guint */
  779. g_value_set_uint(val, (guint)self->max_block_size);
  780. if (surety)
  781. *surety = PROPERTY_SURETY_GOOD;
  782. if (source)
  783. *source = PROPERTY_SOURCE_DEFAULT;
  784. return TRUE;
  785. }
  786. static gboolean
  787. property_get_canonical_name_fn(
  788. Device *self,
  789. DevicePropertyBase *base G_GNUC_UNUSED,
  790. GValue *val,
  791. PropertySurety *surety,
  792. PropertySource *source)
  793. {
  794. g_value_unset_init(val, G_TYPE_STRING);
  795. g_value_set_string(val, self->device_name);
  796. if (surety)
  797. *surety = PROPERTY_SURETY_GOOD;
  798. if (source)
  799. *source = PROPERTY_SOURCE_DEFAULT;
  800. return TRUE;
  801. }
  802. /* util function */
  803. static PropertyPhaseFlags
  804. state_to_phase(
  805. Device *self)
  806. {
  807. if (self->access_mode == ACCESS_NULL) {
  808. return PROPERTY_PHASE_BEFORE_START;
  809. } else if (IS_WRITABLE_ACCESS_MODE(self->access_mode)) {
  810. if (self->in_file) {
  811. return PROPERTY_PHASE_INSIDE_FILE_WRITE;
  812. } else {
  813. return PROPERTY_PHASE_BETWEEN_FILE_WRITE;
  814. }
  815. } else { /* read mode */
  816. if (self->in_file) {
  817. return PROPERTY_PHASE_INSIDE_FILE_READ;
  818. } else {
  819. return PROPERTY_PHASE_BETWEEN_FILE_READ;
  820. }
  821. }
  822. }
  823. /* This default implementation serves up static responses, and
  824. implements a few default responses based on values from the Device
  825. struct. */
  826. static gboolean
  827. default_device_property_get_ex(
  828. Device * self,
  829. DevicePropertyId id,
  830. GValue * val,
  831. PropertySurety *surety,
  832. PropertySource *source)
  833. {
  834. DeviceProperty *prop;
  835. GArray *class_properties;
  836. PropertyPhaseFlags cur_phase;
  837. /* Most of this function's job is to sanity-check everything, then
  838. * call the relevant getter. */
  839. class_properties = DEVICE_GET_CLASS(self)->class_properties;
  840. if (id >= class_properties->len)
  841. return FALSE;
  842. prop = &g_array_index(class_properties, DeviceProperty, id);
  843. if (prop->base == NULL)
  844. return FALSE;
  845. if (val || surety || source) {
  846. /* check the phase */
  847. cur_phase = state_to_phase(self);
  848. if (!(prop->access & cur_phase))
  849. return FALSE;
  850. if (prop->getter == NULL)
  851. return FALSE;
  852. if (!prop->getter(self, prop->base, val, surety, source))
  853. return FALSE;
  854. }
  855. return TRUE;
  856. }
  857. static gboolean
  858. default_device_property_set_ex(
  859. Device *self,
  860. DevicePropertyId id,
  861. GValue * val,
  862. PropertySurety surety,
  863. PropertySource source)
  864. {
  865. DeviceProperty *prop;
  866. GArray *class_properties;
  867. PropertyPhaseFlags cur_phase;
  868. /* Most of this function's job is to sanity-check everything, then
  869. * call the relevant setter. */
  870. if (device_in_error(self))
  871. return FALSE;
  872. class_properties = DEVICE_GET_CLASS(self)->class_properties;
  873. if (id >= class_properties->len)
  874. return FALSE;
  875. prop = &g_array_index(class_properties, DeviceProperty, id);
  876. if (prop->base == NULL)
  877. return FALSE;
  878. /* check that the type matches */
  879. if (!G_VALUE_HOLDS(val, prop->base->type))
  880. return FALSE;
  881. /* check the phase */
  882. cur_phase = state_to_phase(self) << PROPERTY_PHASE_SHIFT;
  883. if (!(prop->access & cur_phase))
  884. return FALSE;
  885. if (prop->setter == NULL)
  886. return FALSE;
  887. if (!prop->setter(self, prop->base, val, surety, source))
  888. return FALSE;
  889. return TRUE;
  890. }
  891. const GSList *
  892. device_property_get_list (Device * self)
  893. {
  894. g_assert(IS_DEVICE(self));
  895. return DEVICE_GET_CLASS(self)->class_properties_list;
  896. }
  897. static gboolean
  898. default_device_read_to_fd(Device *self, queue_fd_t *queue_fd) {
  899. GValue val;
  900. StreamingRequirement streaming_mode;
  901. if (device_in_error(self)) return FALSE;
  902. /* Get the device's parameters */
  903. bzero(&val, sizeof(val));
  904. if (!device_property_get(self, PROPERTY_STREAMING, &val)
  905. || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
  906. streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
  907. } else {
  908. streaming_mode = g_value_get_enum(&val);
  909. }
  910. return QUEUE_SUCCESS ==
  911. do_consumer_producer_queue_full(
  912. device_read_producer,
  913. self,
  914. fd_write_consumer,
  915. queue_fd,
  916. self->block_size,
  917. DEFAULT_MAX_BUFFER_MEMORY,
  918. streaming_mode);
  919. }
  920. static gboolean
  921. default_device_write_from_fd(Device *self, queue_fd_t *queue_fd) {
  922. GValue val;
  923. StreamingRequirement streaming_mode;
  924. if (device_in_error(self)) return FALSE;
  925. /* Get the device's parameters */
  926. bzero(&val, sizeof(val));
  927. if (!device_property_get(self, PROPERTY_STREAMING, &val)
  928. || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
  929. streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
  930. } else {
  931. streaming_mode = g_value_get_enum(&val);
  932. }
  933. return QUEUE_SUCCESS ==
  934. do_consumer_producer_queue_full(
  935. fd_read_producer,
  936. queue_fd,
  937. device_write_consumer,
  938. self,
  939. self->block_size,
  940. DEFAULT_MAX_BUFFER_MEMORY,
  941. streaming_mode);
  942. }
  943. /* XXX WARNING XXX
  944. * All the functions below this comment are stub functions that do nothing
  945. * but implement the virtual function table. Call these functions and they
  946. * will do what you expect vis-a-vis virtual functions. But don't put code
  947. * in them beyond error checking and VFT lookup. */
  948. void
  949. device_open_device (Device * self, char * device_name,
  950. char * device_type, char * device_node)
  951. {
  952. DeviceClass *klass;
  953. g_assert(IS_DEVICE(self));
  954. g_assert(device_name != NULL);
  955. klass = DEVICE_GET_CLASS(self);
  956. g_assert(klass->open_device);
  957. (klass->open_device)(self, device_name, device_type, device_node);
  958. }
  959. DeviceStatusFlags device_read_label(Device * self) {
  960. DeviceClass * klass;
  961. g_assert(self != NULL);
  962. g_assert(IS_DEVICE(self));
  963. g_assert(self->access_mode == ACCESS_NULL);
  964. klass = DEVICE_GET_CLASS(self);
  965. g_assert(klass->read_label);
  966. return (klass->read_label)(self);
  967. }
  968. gboolean
  969. device_finish (Device * self) {
  970. DeviceClass *klass;
  971. g_assert(IS_DEVICE (self));
  972. klass = DEVICE_GET_CLASS(self);
  973. g_assert(klass->finish);
  974. return (klass->finish)(self);
  975. }
  976. gboolean
  977. device_configure (Device * self, gboolean use_global_config)
  978. {
  979. DeviceClass *klass;
  980. g_assert(IS_DEVICE (self));
  981. g_assert(self->access_mode == ACCESS_NULL);
  982. klass = DEVICE_GET_CLASS(self);
  983. if(klass->configure) {
  984. return (klass->configure)(self, use_global_config);
  985. } else {
  986. device_set_error(self,
  987. stralloc(_("Unimplemented method")),
  988. DEVICE_STATUS_DEVICE_ERROR);
  989. return FALSE;
  990. }
  991. }
  992. gboolean
  993. device_start (Device * self, DeviceAccessMode mode,
  994. char * label, char * timestamp)
  995. {
  996. DeviceClass *klass;
  997. char * local_timestamp = NULL;
  998. gboolean rv;
  999. g_assert(IS_DEVICE (self));
  1000. g_assert(mode != ACCESS_NULL);
  1001. g_assert(mode != ACCESS_WRITE || label != NULL);
  1002. klass = DEVICE_GET_CLASS(self);
  1003. g_assert(klass->start);
  1004. /* For a good combination of synchronization and public simplicity,
  1005. this stub function does not require a timestamp, but the actual
  1006. implementation function does. We generate the timestamp here with
  1007. time(). */
  1008. if (mode == ACCESS_WRITE &&
  1009. get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  1010. local_timestamp = timestamp =
  1011. get_proper_stamp_from_time(time(NULL));
  1012. }
  1013. rv = (klass->start)(self, mode, label, timestamp);
  1014. amfree(local_timestamp);
  1015. return rv;
  1016. }
  1017. gboolean
  1018. device_write_block (Device * self, guint size, gpointer block)
  1019. {
  1020. DeviceClass *klass;
  1021. g_assert(IS_DEVICE (self));
  1022. g_assert(size > 0);
  1023. /* these are all things that the caller should take care to
  1024. * guarantee, so we just assert them here */
  1025. g_assert(size <= self->block_size);
  1026. g_assert(self->in_file);
  1027. g_assert(!selfp->wrote_short_block);
  1028. g_assert(block != NULL);
  1029. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  1030. if (size < self->block_size)
  1031. selfp->wrote_short_block = TRUE;
  1032. klass = DEVICE_GET_CLASS(self);
  1033. g_assert(klass->write_block);
  1034. return (*klass->write_block)(self,size, block);
  1035. }
  1036. gboolean
  1037. device_write_from_fd (Device * self, queue_fd_t * queue_fd)
  1038. {
  1039. DeviceClass *klass;
  1040. g_assert(IS_DEVICE (self));
  1041. g_assert(queue_fd->fd >= 0);
  1042. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  1043. klass = DEVICE_GET_CLASS(self);
  1044. g_assert(klass->write_from_fd);
  1045. return (klass->write_from_fd)(self,queue_fd);
  1046. }
  1047. gboolean
  1048. device_start_file (Device * self, dumpfile_t * jobInfo) {
  1049. DeviceClass * klass;
  1050. g_assert(IS_DEVICE (self));
  1051. g_assert(!(self->in_file));
  1052. g_assert(jobInfo != NULL);
  1053. selfp->wrote_short_block = FALSE;
  1054. klass = DEVICE_GET_CLASS(self);
  1055. g_assert(klass->start_file);
  1056. return (klass->start_file)(self, jobInfo );
  1057. }
  1058. gboolean
  1059. device_finish_file (Device * self)
  1060. {
  1061. DeviceClass *klass;
  1062. g_assert(IS_DEVICE (self));
  1063. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  1064. g_assert(self->in_file);
  1065. klass = DEVICE_GET_CLASS(self);
  1066. g_assert(klass->finish_file);
  1067. return (klass->finish_file)(self);
  1068. }
  1069. dumpfile_t*
  1070. device_seek_file (Device * self, guint file)
  1071. {
  1072. DeviceClass *klass;
  1073. g_assert(IS_DEVICE (self));
  1074. g_assert(self->access_mode == ACCESS_READ);
  1075. klass = DEVICE_GET_CLASS(self);
  1076. g_assert(klass->seek_file);
  1077. return (klass->seek_file)(self,file);
  1078. }
  1079. gboolean
  1080. device_seek_block (Device * self, guint64 block)
  1081. {
  1082. DeviceClass *klass;
  1083. g_assert(IS_DEVICE (self));
  1084. g_assert(self->access_mode == ACCESS_READ);
  1085. g_assert(self->in_file);
  1086. klass = DEVICE_GET_CLASS(self);
  1087. g_assert(klass->seek_block);
  1088. return (klass->seek_block)(self,block);
  1089. }
  1090. int
  1091. device_read_block (Device * self, gpointer buffer, int * size)
  1092. {
  1093. DeviceClass *klass;
  1094. g_assert(IS_DEVICE (self));
  1095. g_assert(size != NULL);
  1096. g_assert(self->access_mode == ACCESS_READ);
  1097. if (*size != 0) {
  1098. g_assert(buffer != NULL);
  1099. }
  1100. klass = DEVICE_GET_CLASS(self);
  1101. g_assert(klass->read_block);
  1102. return (klass->read_block)(self,buffer,size);
  1103. }
  1104. gboolean
  1105. device_read_to_fd (Device * self, queue_fd_t *queue_fd)
  1106. {
  1107. DeviceClass *klass;
  1108. g_assert(IS_DEVICE (self));
  1109. g_assert(queue_fd->fd >= 0);
  1110. g_assert(self->access_mode == ACCESS_READ);
  1111. klass = DEVICE_GET_CLASS(self);
  1112. g_assert(klass->read_to_fd);
  1113. return (klass->read_to_fd)(self,queue_fd);
  1114. }
  1115. gboolean
  1116. device_property_get_ex(
  1117. Device * self,
  1118. DevicePropertyId id,
  1119. GValue * val,
  1120. PropertySurety *surety,
  1121. PropertySource *source)
  1122. {
  1123. DeviceClass *klass;
  1124. g_assert(IS_DEVICE (self));
  1125. g_assert(device_property_get_by_id(id) != NULL);
  1126. klass = DEVICE_GET_CLASS(self);
  1127. g_assert(klass->property_get_ex);
  1128. return (klass->property_get_ex)(self, id, val, surety, source);
  1129. }
  1130. gboolean
  1131. device_property_set_ex(
  1132. Device * self,
  1133. DevicePropertyId id,
  1134. GValue * val,
  1135. PropertySurety surety,
  1136. PropertySource source)
  1137. {
  1138. DeviceClass *klass;
  1139. g_assert(IS_DEVICE (self));
  1140. klass = DEVICE_GET_CLASS(self);
  1141. g_assert(klass->property_set_ex);
  1142. return (klass->property_set_ex)(self, id, val, surety, source);
  1143. }
  1144. gboolean
  1145. device_recycle_file (Device * self, guint filenum)
  1146. {
  1147. DeviceClass *klass;
  1148. g_assert(self != NULL);
  1149. g_assert(IS_DEVICE (self));
  1150. g_assert(self->access_mode == ACCESS_APPEND);
  1151. g_assert(!self->in_file);
  1152. klass = DEVICE_GET_CLASS(self);
  1153. g_assert(klass->recycle_file);
  1154. return (klass->recycle_file)(self,filenum);
  1155. }
  1156. gboolean
  1157. device_erase (Device * self)
  1158. {
  1159. DeviceClass *klass;
  1160. g_assert(IS_DEVICE (self));
  1161. g_assert(self->access_mode == ACCESS_NULL);
  1162. g_assert(!self->in_file);
  1163. klass = DEVICE_GET_CLASS(self);
  1164. if(klass->erase) {
  1165. return (klass->erase)(self);
  1166. } else {
  1167. device_set_error(self,
  1168. stralloc(_("Unimplemented method")),
  1169. DEVICE_STATUS_DEVICE_ERROR);
  1170. return FALSE;
  1171. }
  1172. }
  1173. gboolean
  1174. device_eject (Device * self)
  1175. {
  1176. DeviceClass *klass;
  1177. g_assert(IS_DEVICE (self));
  1178. g_assert(self->access_mode == ACCESS_NULL);
  1179. g_assert(!self->in_file);
  1180. klass = DEVICE_GET_CLASS(self);
  1181. if (klass->eject) {
  1182. return (klass->eject)(self);
  1183. } else {
  1184. return TRUE;
  1185. }
  1186. }
  1187. gboolean
  1188. device_listen(
  1189. Device *self,
  1190. gboolean for_writing,
  1191. DirectTCPAddr **addrs)
  1192. {
  1193. DeviceClass *klass;
  1194. klass = DEVICE_GET_CLASS(self);
  1195. if(klass->listen) {
  1196. return (klass->listen)(self, for_writing, addrs);
  1197. } else {
  1198. device_set_error(self,
  1199. stralloc(_("Unimplemented method")),
  1200. DEVICE_STATUS_DEVICE_ERROR);
  1201. return FALSE;
  1202. }
  1203. }
  1204. gboolean
  1205. device_accept(
  1206. Device *self,
  1207. DirectTCPConnection **conn,
  1208. ProlongProc prolong,
  1209. gpointer prolong_data)
  1210. {
  1211. DeviceClass *klass;
  1212. klass = DEVICE_GET_CLASS(self);
  1213. if(klass->accept) {
  1214. return (klass->accept)(self, conn, prolong, prolong_data);
  1215. } else {
  1216. device_set_error(self,
  1217. stralloc(_("Unimplemented method")),
  1218. DEVICE_STATUS_DEVICE_ERROR);
  1219. return FALSE;
  1220. }
  1221. }
  1222. gboolean
  1223. device_write_from_connection(
  1224. Device *self,
  1225. guint64 size,
  1226. guint64 *actual_size)
  1227. {
  1228. DeviceClass *klass;
  1229. klass = DEVICE_GET_CLASS(self);
  1230. g_assert(self->in_file);
  1231. g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode));
  1232. if(klass->write_from_connection) {
  1233. return (klass->write_from_connection)(self, size, actual_size);
  1234. } else {
  1235. device_set_error(self,
  1236. stralloc(_("Unimplemented method")),
  1237. DEVICE_STATUS_DEVICE_ERROR);
  1238. return FALSE;
  1239. }
  1240. }
  1241. gboolean
  1242. device_read_to_connection(
  1243. Device *self,
  1244. guint64 size,
  1245. guint64 *actual_size)
  1246. {
  1247. DeviceClass *klass;
  1248. g_assert(self->in_file);
  1249. g_assert(self->access_mode == ACCESS_READ);
  1250. klass = DEVICE_GET_CLASS(self);
  1251. if(klass->read_to_connection) {
  1252. return (klass->read_to_connection)(self, size, actual_size);
  1253. } else {
  1254. device_set_error(self,
  1255. stralloc(_("Unimplemented method")),
  1256. DEVICE_STATUS_DEVICE_ERROR);
  1257. return FALSE;
  1258. }
  1259. }
  1260. gboolean
  1261. device_use_connection(
  1262. Device *self,
  1263. DirectTCPConnection *conn)
  1264. {
  1265. DeviceClass *klass;
  1266. g_assert(self->access_mode == ACCESS_NULL);
  1267. klass = DEVICE_GET_CLASS(self);
  1268. if(klass->use_connection) {
  1269. return (klass->use_connection)(self, conn);
  1270. } else {
  1271. device_set_error(self,
  1272. stralloc(_("Unimplemented method")),
  1273. DEVICE_STATUS_DEVICE_ERROR);
  1274. return FALSE;
  1275. }
  1276. }
  1277. /* Property handling */
  1278. void
  1279. device_class_register_property(
  1280. DeviceClass *klass,
  1281. DevicePropertyId id,
  1282. PropertyAccessFlags access,
  1283. PropertyGetFn getter,
  1284. PropertySetFn setter)
  1285. {
  1286. DevicePropertyBase *base;
  1287. DeviceProperty *prop;
  1288. GSList *proplist;
  1289. guint i;
  1290. g_assert(klass != NULL);
  1291. base = device_property_get_by_id(id);
  1292. g_assert(base != NULL);
  1293. if (klass->class_properties->len <= id) {
  1294. g_array_set_size(klass->class_properties, id+1);
  1295. }
  1296. prop = &g_array_index(klass->class_properties, DeviceProperty, id);
  1297. prop->base = base;
  1298. prop->access = access;
  1299. prop->getter = getter;
  1300. prop->setter = setter;
  1301. /* completely rewrite the list of prop pointers, as they may have changed,
  1302. * or we may have replaced an existing property*/
  1303. if (klass->class_properties_list) {
  1304. g_slist_free(klass->class_properties_list);
  1305. }
  1306. proplist = NULL;
  1307. for (i = 0; i < klass->class_properties->len; i++) {
  1308. prop = &g_array_index(klass->class_properties, DeviceProperty, i);
  1309. if (!prop->base)
  1310. continue;
  1311. proplist = g_slist_prepend(proplist, prop);
  1312. }
  1313. klass->class_properties_list = proplist;
  1314. }
  1315. gboolean
  1316. device_set_simple_property(
  1317. Device *self,
  1318. DevicePropertyId id,
  1319. GValue *val,
  1320. PropertySurety surety,
  1321. PropertySource source)
  1322. {
  1323. SimpleProperty *simp;
  1324. DeviceProperty *prop;
  1325. prop = &g_array_index(DEVICE_GET_CLASS(self)->class_properties,
  1326. DeviceProperty, id);
  1327. /* these assertions should already be checked, but let's be sure */
  1328. g_assert(prop->base != NULL); /* prop must be registered with device */
  1329. g_assert(G_VALUE_HOLDS(val, prop->base->type));
  1330. simp = g_new0(SimpleProperty, 1);
  1331. simp->prop = prop;
  1332. g_value_unset_copy(val, &(simp->response));
  1333. simp->surety = surety;
  1334. simp->source = source;
  1335. g_hash_table_insert(selfp->simple_properties,
  1336. GINT_TO_POINTER(id),
  1337. simp);
  1338. return TRUE;
  1339. }
  1340. gboolean
  1341. device_simple_property_set_fn(
  1342. Device *self,
  1343. DevicePropertyBase *base,
  1344. GValue *val,
  1345. PropertySurety surety,
  1346. PropertySource source)
  1347. {
  1348. return device_set_simple_property(self, base->ID, val, surety, source);
  1349. }
  1350. gboolean
  1351. device_get_simple_property(
  1352. Device *self,
  1353. DevicePropertyId id,
  1354. GValue *val,
  1355. PropertySurety *surety,
  1356. PropertySource *source)
  1357. {
  1358. SimpleProperty *simp =
  1359. g_hash_table_lookup(selfp->simple_properties,
  1360. GINT_TO_POINTER(id));
  1361. if (!simp)
  1362. return FALSE;
  1363. if (val)
  1364. g_value_unset_copy(&(simp->response), val);
  1365. if (surety)
  1366. *surety = simp->surety;
  1367. if (source)
  1368. *source = simp->source;
  1369. return TRUE;
  1370. }
  1371. gboolean
  1372. device_simple_property_get_fn(
  1373. Device *self,
  1374. DevicePropertyBase *base,
  1375. GValue *val,
  1376. PropertySurety *surety,
  1377. PropertySource *source)
  1378. {
  1379. return device_get_simple_property(self, base->ID, val, surety, source);
  1380. }