jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

479 lines
13KB

  1. /*
  2. Copyright (C) 2013 Paul Davis
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2.1 of the License, or (at
  6. your option) any later version.
  7. This program is distributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  9. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  10. License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include <string.h>
  16. #include <db.h>
  17. #include <limits.h>
  18. #include <jack/metadata.h>
  19. #include <jack/uuid.h>
  20. #include "internal.h"
  21. static DB* db = NULL;
  22. static int
  23. jack_property_init (const char* server_name)
  24. {
  25. int ret;
  26. char dbpath[PATH_MAX+1];
  27. char server_dir[PATH_MAX+1];
  28. /* idempotent */
  29. if (db) {
  30. return 0;
  31. }
  32. if ((ret = db_create (&db, NULL, 0)) != 0) {
  33. jack_error ("Cannot initialize metadata DB (%s)", db_strerror (ret));
  34. return -1;
  35. }
  36. snprintf (dbpath, sizeof (dbpath), "%s/%s", jack_server_dir (server_name, server_dir), "metadata.db");
  37. if ((ret = db->open (db, NULL, dbpath, NULL, DB_HASH, DB_CREATE|DB_THREAD, 0666)) != 0) {
  38. jack_error ("Cannot open metadata DB at %s: %s", dbpath, db_strerror (ret));
  39. db->close (db, 0);
  40. db = NULL;
  41. return -1;
  42. }
  43. return 0;
  44. }
  45. static void jack_properties_uninit () __attribute__ ((destructor));
  46. void
  47. jack_properties_uninit ()
  48. {
  49. if (db) {
  50. db->close (db, 0);
  51. db = NULL;
  52. }
  53. }
  54. void
  55. jack_free_description(jack_description_t* desc)
  56. {
  57. return;
  58. }
  59. static void
  60. make_key_dbt (DBT* dbt, jack_uuid_t subject, const char* key)
  61. {
  62. char ustr[JACK_UUID_STRING_SIZE];
  63. size_t len1, len2;
  64. memset(dbt, 0, sizeof(DBT));
  65. jack_uuid_unparse (subject, ustr);
  66. len1 = JACK_UUID_STRING_SIZE;
  67. len2 = strlen (key) + 1;
  68. dbt->size = len1 + len2;
  69. dbt->data = malloc (dbt->size);
  70. memcpy (dbt->data, ustr, len1); // copy subject+null
  71. memcpy (dbt->data + len1, key, len2); // copy key+null
  72. }
  73. int
  74. jack_set_property (jack_client_t* client,
  75. jack_uuid_t subject,
  76. const char* key,
  77. const char* value,
  78. const char* type)
  79. {
  80. DBT d_key;
  81. DBT data;
  82. int ret;
  83. size_t len1, len2;
  84. if (jack_property_init (NULL)) {
  85. return -1;
  86. }
  87. /* build a key */
  88. make_key_dbt (&d_key, subject, key);
  89. /* build data */
  90. memset(&data, 0, sizeof(data));
  91. len1 = strlen(value) + 1;
  92. if (type && type[0] != '\0') {
  93. len2 = strlen(type) + 1;
  94. } else {
  95. len2 = 0;
  96. }
  97. data.size = len1 + len2;
  98. data.data = malloc (data.size);
  99. memcpy (data.data, value, len1);
  100. if (len2) {
  101. memcpy (data.data + len1, type, len2);
  102. }
  103. if ((ret = db->put (db, NULL, &d_key, &data, 0)) != 0) {
  104. char ustr[JACK_UUID_STRING_SIZE];
  105. jack_uuid_unparse (subject, ustr);
  106. jack_error ("Cannot store metadata for %s/%s (%s)", ustr, key, db_strerror (ret));
  107. return -1;
  108. }
  109. return 0;
  110. }
  111. int
  112. jack_get_property (jack_uuid_t subject,
  113. const char* key,
  114. char** value,
  115. char** type)
  116. {
  117. DBT d_key;
  118. DBT data;
  119. int ret;
  120. size_t len1, len2;
  121. if (key == NULL || key[0] == '\0') {
  122. return -1;
  123. }
  124. if (jack_property_init (NULL)) {
  125. return -1;
  126. }
  127. /* build a key */
  128. make_key_dbt (&d_key, subject, key);
  129. /* setup data DBT */
  130. memset(&data, 0, sizeof(data));
  131. data.flags = DB_DBT_MALLOC;
  132. if ((ret = db->get (db, NULL, &d_key, &data, 0)) != 0) {
  133. if (ret != DB_NOTFOUND) {
  134. char ustr[JACK_UUID_STRING_SIZE];
  135. jack_uuid_unparse (subject, ustr);
  136. jack_error ("Cannot metadata for %s/%s (%s)", ustr, key, db_strerror (ret));
  137. }
  138. return -1;
  139. }
  140. /* result must have at least 2 chars plus 2 nulls to be valid
  141. */
  142. if (data.size < 4) {
  143. if (data.size > 0) {
  144. free (data.data);
  145. }
  146. return -1;
  147. }
  148. len1 = strlen (data.data) + 1;
  149. (*value) = (char *) malloc (len1);
  150. memcpy (*value, data.data, len1);
  151. if (len1 < data.size) {
  152. len2 = strlen (data.data+len1) + 1;
  153. (*type) = (char *) malloc (len2);
  154. memcpy (*type, data.data+len1, len2);
  155. } else {
  156. /* no type specified, assume default */
  157. *type = NULL;
  158. }
  159. if (data.size) {
  160. free (data.data);
  161. }
  162. return 0;
  163. }
  164. int
  165. jack_get_properties (jack_uuid_t subject,
  166. jack_description_t* desc)
  167. {
  168. DBT key;
  169. DBT data;
  170. DBC* cursor;
  171. int ret;
  172. size_t len1, len2;
  173. size_t cnt = 0;
  174. char ustr[JACK_UUID_STRING_SIZE];
  175. size_t props_size = 0;
  176. jack_property_t* prop;
  177. desc->properties = NULL;
  178. jack_uuid_unparse (subject, ustr);
  179. if (jack_property_init (NULL)) {
  180. return -1;
  181. }
  182. if ((ret = db->cursor (db, NULL, &cursor, 0)) != 0) {
  183. jack_error ("Cannot create cursor for metadata search (%s)", db_strerror (ret));
  184. return -1;
  185. }
  186. memset(&key, 0, sizeof(key));
  187. memset(&data, 0, sizeof(data));
  188. data.flags = DB_DBT_MALLOC;
  189. while ((ret = cursor->get(cursor, &key, &data, DB_NEXT)) == 0) {
  190. /* require 2 extra chars (data+null) for key,
  191. which is composed of UUID str plus a key name
  192. */
  193. if (key.size < JACK_UUID_STRING_SIZE + 2) {
  194. if (data.size > 0) {
  195. free (data.data);
  196. }
  197. continue;
  198. }
  199. if (memcmp (ustr, key.data, JACK_UUID_STRING_SIZE) != 0) {
  200. /* not relevant */
  201. if (data.size > 0) {
  202. free (data.data);
  203. }
  204. continue;
  205. }
  206. /* result must have at least 2 chars plus 2 nulls to be valid
  207. */
  208. if (data.size < 4) {
  209. if (data.size > 0) {
  210. free (data.data);
  211. }
  212. continue;
  213. }
  214. /* realloc array if necessary */
  215. if (cnt == props_size) {
  216. if (props_size == 0) {
  217. props_size = 8;
  218. } else {
  219. props_size *= 2;
  220. }
  221. desc->properties = (jack_property_t*) realloc (desc->properties, sizeof (jack_property_t) * props_size);
  222. }
  223. prop = &desc->properties[cnt];
  224. /* store UUID/subject */
  225. jack_uuid_copy (desc->subject, subject);
  226. /* copy key (without leading UUID as subject */
  227. len1 = key.size - JACK_UUID_STRING_SIZE;
  228. prop->key = malloc (key.size);
  229. memcpy ((char*) prop->key, key.data + JACK_UUID_STRING_SIZE, len1);
  230. /* copy data */
  231. len1 = strlen (data.data) + 1;
  232. prop->data = (char *) malloc (len1);
  233. memcpy ((char*) prop->data, data.data, len1);
  234. if (len1 < data.size) {
  235. len2 = strlen (data.data+len1) + 1;
  236. prop->type= (char *) malloc (len2);
  237. memcpy ((char*) prop->type, data.data+len1, len2);
  238. } else {
  239. /* no type specified, assume default */
  240. prop->type = NULL;
  241. }
  242. if (data.size) {
  243. free (data.data);
  244. }
  245. ++cnt;
  246. }
  247. cursor->close (cursor);
  248. return cnt;
  249. }
  250. int
  251. jack_get_all_properties (jack_description_t** desc)
  252. {
  253. DBT key;
  254. DBT data;
  255. DBC* cursor;
  256. int ret;
  257. size_t cnt = 0;
  258. if (jack_property_init (NULL)) {
  259. return -1;
  260. }
  261. if ((ret = db->cursor (db, NULL, &cursor, 0)) != 0) {
  262. jack_error ("Cannot create cursor for metadata search (%s)", db_strerror (ret));
  263. return -1;
  264. }
  265. memset(&key, 0, sizeof(key));
  266. memset(&data, 0, sizeof(data));
  267. data.flags = DB_DBT_MALLOC;
  268. while ((ret = cursor->get(cursor, &key, &data, DB_NEXT)) == 0) {
  269. if (data.size) {
  270. free (data.data);
  271. }
  272. ++cnt;
  273. }
  274. cursor->close (cursor);
  275. return cnt;
  276. }
  277. int
  278. jack_get_description (jack_uuid_t subject,
  279. jack_description_t* desc)
  280. {
  281. return 0;
  282. }
  283. int
  284. jack_get_all_descriptions (jack_description_t** descs)
  285. {
  286. return 0;
  287. }
  288. int jack_set_property_change_callback (jack_client_t* client,
  289. JackPropertyChangeCallback callback,
  290. void *arg)
  291. {
  292. return 0;
  293. }
  294. int
  295. jack_remove_property (jack_client_t* client, jack_uuid_t subject, const char* key)
  296. {
  297. DBT d_key;
  298. int ret;
  299. if (jack_property_init (NULL)) {
  300. return -1;
  301. }
  302. make_key_dbt (&d_key, subject, key);
  303. if ((ret = db->del (db, NULL, &d_key, 0)) != 0) {
  304. jack_error ("Cannot delete key %s (%s)", key, db_strerror (ret));
  305. return -1;
  306. }
  307. return 0;
  308. }
  309. int
  310. jack_remove_properties (jack_client_t* client, jack_uuid_t subject)
  311. {
  312. DBT key;
  313. DBT data;
  314. DBC* cursor;
  315. int ret;
  316. char ustr[JACK_UUID_STRING_SIZE];
  317. int retval = 0;
  318. jack_uuid_unparse (subject, ustr);
  319. if (jack_property_init (NULL)) {
  320. return -1;
  321. }
  322. if ((ret = db->cursor (db, NULL, &cursor, 0)) != 0) {
  323. jack_error ("Cannot create cursor for metadata search (%s)", db_strerror (ret));
  324. return -1;
  325. }
  326. memset(&key, 0, sizeof(key));
  327. memset(&data, 0, sizeof(data));
  328. data.flags = DB_DBT_MALLOC;
  329. while ((ret = cursor->get(cursor, &key, &data, DB_NEXT)) == 0) {
  330. /* require 2 extra chars (data+null) for key,
  331. which is composed of UUID str plus a key name
  332. */
  333. if (key.size < JACK_UUID_STRING_SIZE + 2) {
  334. if (data.size > 0) {
  335. free (data.data);
  336. }
  337. continue;
  338. }
  339. if (memcmp (ustr, key.data, JACK_UUID_STRING_SIZE) != 0) {
  340. /* not relevant */
  341. if (data.size > 0) {
  342. free (data.data);
  343. }
  344. continue;
  345. }
  346. if ((ret = cursor->del (cursor, 0)) != 0) {
  347. jack_error ("cannot delete property (%s)", db_strerror (ret));
  348. /* don't return -1 here since this would leave things
  349. even more inconsistent. wait till the cursor is finished
  350. */
  351. retval = -1;
  352. }
  353. }
  354. cursor->close (cursor);
  355. return retval;
  356. }
  357. int
  358. jack_remove_all_properties (jack_client_t* client)
  359. {
  360. int ret;
  361. if (jack_property_init (NULL)) {
  362. return -1;
  363. }
  364. if ((ret = db->truncate (db, NULL, NULL, 0)) != 0) {
  365. jack_error ("Cannot clear properties (%s)", db_strerror (ret));
  366. return -1;
  367. }
  368. return 0;
  369. }