jack2 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.

821 lines
21KB

  1. /*
  2. Copyright (C) 2011 David Robillard
  3. Copyright (C) 2013 Paul Davis
  4. Copyright (C) 2019 Filipe Coelho
  5. This program is free software; you can redistribute it and/or modify it
  6. under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 2.1 of the License, or (at
  8. your option) any later version.
  9. This program is distributed in the hope that it will be useful, but WITHOUT
  10. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  12. License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  16. */
  17. #include "JackMetadata.h"
  18. #include "JackClient.h"
  19. #include "JackTools.h"
  20. #include <string.h>
  21. #include <sys/stat.h>
  22. #include <limits.h>
  23. #define JACK_METADATA_PREFIX "http://jackaudio.org/metadata/"
  24. LIB_EXPORT const char* JACK_METADATA_CONNECTED = JACK_METADATA_PREFIX "connected";
  25. LIB_EXPORT const char* JACK_METADATA_EVENT_TYPES = JACK_METADATA_PREFIX "event-types";
  26. LIB_EXPORT const char* JACK_METADATA_HARDWARE = JACK_METADATA_PREFIX "hardware";
  27. LIB_EXPORT const char* JACK_METADATA_ICON_LARGE = JACK_METADATA_PREFIX "icon-large";
  28. LIB_EXPORT const char* JACK_METADATA_ICON_NAME = JACK_METADATA_PREFIX "icon-name";
  29. LIB_EXPORT const char* JACK_METADATA_ICON_SMALL = JACK_METADATA_PREFIX "icon-small";
  30. LIB_EXPORT const char* JACK_METADATA_ORDER = JACK_METADATA_PREFIX "order";
  31. LIB_EXPORT const char* JACK_METADATA_PORT_GROUP = JACK_METADATA_PREFIX "port-group";
  32. LIB_EXPORT const char* JACK_METADATA_PRETTY_NAME = JACK_METADATA_PREFIX "pretty-name";
  33. LIB_EXPORT const char* JACK_METADATA_SIGNAL_TYPE = JACK_METADATA_PREFIX "signal-type";
  34. #undef JACK_METADATA_PREFIX
  35. namespace Jack
  36. {
  37. JackMetadata::JackMetadata(bool isEngine)
  38. #if HAVE_DB
  39. : fDB(NULL), fDBenv(NULL), fIsEngine(isEngine)
  40. #endif
  41. {
  42. PropertyInit();
  43. }
  44. JackMetadata::~JackMetadata()
  45. {
  46. #if HAVE_DB
  47. char dbpath[PATH_MAX + 1];
  48. if (fDB) {
  49. fDB->close (fDB, 0);
  50. fDB = NULL;
  51. }
  52. if (fDBenv) {
  53. fDBenv->close (fDBenv, 0);
  54. fDBenv = NULL;
  55. }
  56. if (fIsEngine)
  57. {
  58. // cleanup after libdb, nasty!
  59. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/metadata.db", fDBFilesDir, JackTools::GetUID());
  60. remove (dbpath);
  61. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/__db.001", fDBFilesDir, JackTools::GetUID());
  62. remove (dbpath);
  63. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/__db.002", fDBFilesDir, JackTools::GetUID());
  64. remove (dbpath);
  65. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/__db.003", fDBFilesDir, JackTools::GetUID());
  66. remove (dbpath);
  67. // remove our custom dir
  68. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d", fDBFilesDir, JackTools::GetUID());
  69. rmdir (dbpath);
  70. }
  71. #endif
  72. }
  73. int JackMetadata::PropertyInit()
  74. {
  75. #if HAVE_DB
  76. int ret;
  77. char dbpath[PATH_MAX + 1];
  78. #ifdef WIN32
  79. ret = GetTempPathA (PATH_MAX, fDBFilesDir);
  80. if ((ret > PATH_MAX) || (ret == 0)) {
  81. jack_error ("cannot get path for temp files");
  82. return -1;
  83. }
  84. #else
  85. strncpy (fDBFilesDir, jack_server_dir, PATH_MAX);
  86. #endif
  87. /* idempotent */
  88. if (fDBenv) {
  89. return 0;
  90. }
  91. if ((ret = db_env_create (&fDBenv, 0)) != 0) {
  92. jack_error ("cannot initialize DB environment: %s\n", db_strerror (ret));
  93. return -1;
  94. }
  95. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d", fDBFilesDir, JackTools::GetUID());
  96. #ifdef WIN32
  97. mkdir (dbpath);
  98. #else
  99. mkdir (dbpath, S_IRWXU | S_IRWXG);
  100. #endif
  101. if ((ret = fDBenv->open (fDBenv, dbpath, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_THREAD, 0)) != 0) {
  102. #if defined(WIN32) || defined(__APPLE__)
  103. // new versions of jack2 are built with HAVE_MIXED_SIZE_ADDRESSING, which induces this error, this is expected
  104. if (ret == DB_VERSION_MISMATCH) {
  105. jack_error ("Failed to open previous DB environment, trying again clean...");
  106. // cleanup old stuff
  107. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/metadata.db", fDBFilesDir, JackTools::GetUID());
  108. remove (dbpath);
  109. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/__db.001", fDBFilesDir, JackTools::GetUID());
  110. remove (dbpath);
  111. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/__db.002", fDBFilesDir, JackTools::GetUID());
  112. remove (dbpath);
  113. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/__db.003", fDBFilesDir, JackTools::GetUID());
  114. remove (dbpath);
  115. // try again fresh
  116. ret = fDBenv->open (fDBenv, dbpath, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_THREAD, 0);
  117. }
  118. if (ret != 0)
  119. #endif
  120. {
  121. jack_error ("Cannot open DB environment: %s", db_strerror (ret));
  122. fDBenv = NULL;
  123. return -1;
  124. }
  125. }
  126. if ((ret = db_create (&fDB, fDBenv, 0)) != 0) {
  127. jack_error ("Cannot initialize metadata DB (%s)", db_strerror (ret));
  128. fDBenv->close (fDBenv, 0);
  129. fDBenv = NULL;
  130. return -1;
  131. }
  132. snprintf (dbpath, sizeof(dbpath), "%s/jack_db-%d/metadata.db", fDBFilesDir, JackTools::GetUID());
  133. if ((ret = fDB->open (fDB, NULL, dbpath, NULL, DB_HASH, DB_CREATE | DB_THREAD, 0666)) != 0) {
  134. jack_error ("Cannot open metadata DB at %s: %s", dbpath, db_strerror (ret));
  135. fDB->close (fDB, 0);
  136. fDB = NULL;
  137. fDBenv->close (fDBenv, 0);
  138. fDBenv = NULL;
  139. return -1;
  140. }
  141. return 0;
  142. #else // !HAVE_DB
  143. return -1;
  144. #endif
  145. }
  146. int JackMetadata::PropertyChangeNotify(JackClient* client, jack_uuid_t subject, const char* key, jack_property_change_t change)
  147. {
  148. /* the engine passes in a NULL client when it removes metadata during port or client removal
  149. */
  150. if (client == NULL) {
  151. return 0;
  152. }
  153. return client->PropertyChangeNotify(subject, key, change);
  154. }
  155. #if HAVE_DB
  156. void JackMetadata::MakeKeyDbt(DBT* dbt, jack_uuid_t subject, const char* key)
  157. {
  158. char ustr[JACK_UUID_STRING_SIZE];
  159. size_t len1, len2;
  160. memset (dbt, 0, sizeof(DBT));
  161. memset (ustr, 0, JACK_UUID_STRING_SIZE);
  162. jack_uuid_unparse (subject, ustr);
  163. len1 = JACK_UUID_STRING_SIZE;
  164. len2 = strlen (key) + 1;
  165. dbt->size = len1 + len2;
  166. dbt->data = malloc (dbt->size);
  167. memcpy (dbt->data, ustr, len1); // copy subject+null
  168. memcpy ((char *)dbt->data + len1, key, len2); // copy key+null
  169. }
  170. #endif
  171. int JackMetadata::SetProperty(JackClient* client, jack_uuid_t subject, const char* key, const char* value, const char* type)
  172. {
  173. #if HAVE_DB
  174. DBT d_key;
  175. DBT data;
  176. int ret;
  177. size_t len1, len2;
  178. jack_property_change_t change;
  179. if (!key || key[0] == '\0') {
  180. jack_error ("empty key string for metadata not allowed");
  181. return -1;
  182. }
  183. if (!value || value[0] == '\0') {
  184. jack_error ("empty value string for metadata not allowed");
  185. return -1;
  186. }
  187. if (PropertyInit()) {
  188. return -1;
  189. }
  190. /* build a key */
  191. MakeKeyDbt(&d_key, subject, key);
  192. /* build data */
  193. memset (&data, 0, sizeof(data));
  194. len1 = strlen (value) + 1;
  195. if (type && type[0] != '\0') {
  196. len2 = strlen (type) + 1;
  197. } else {
  198. len2 = 0;
  199. }
  200. data.size = len1 + len2;
  201. data.data = malloc (data.size);
  202. memcpy (data.data, value, len1);
  203. if (len2) {
  204. memcpy ((char *)data.data + len1, type, len2);
  205. }
  206. if (fDB->exists (fDB, NULL, &d_key, 0) == DB_NOTFOUND) {
  207. change = PropertyCreated;
  208. } else {
  209. change = PropertyChanged;
  210. }
  211. if ((ret = fDB->put (fDB, NULL, &d_key, &data, 0)) != 0) {
  212. char ustr[JACK_UUID_STRING_SIZE];
  213. jack_uuid_unparse (subject, ustr);
  214. jack_error ("Cannot store metadata for %s/%s (%s)", ustr, key, db_strerror (ret));
  215. if (d_key.size > 0) {
  216. free (d_key.data);
  217. }
  218. if (data.size > 0) {
  219. free (data.data);
  220. }
  221. return -1;
  222. }
  223. PropertyChangeNotify(client, subject, key, change);
  224. if (d_key.size > 0) {
  225. free (d_key.data);
  226. }
  227. if (data.size > 0) {
  228. free (data.data);
  229. }
  230. return 0;
  231. #else // !HAVE_DB
  232. return -1;
  233. #endif
  234. }
  235. int JackMetadata::GetProperty(jack_uuid_t subject, const char* key, char** value, char** type)
  236. {
  237. #if HAVE_DB
  238. DBT d_key;
  239. DBT data;
  240. int ret;
  241. size_t len1, len2;
  242. if (key == NULL || key[0] == '\0') {
  243. return -1;
  244. }
  245. if (PropertyInit()) {
  246. return -1;
  247. }
  248. /* build a key */
  249. MakeKeyDbt(&d_key, subject, key);
  250. /* setup data DBT */
  251. memset (&data, 0, sizeof(data));
  252. data.flags = DB_DBT_MALLOC;
  253. if ((ret = fDB->get (fDB, NULL, &d_key, &data, 0)) != 0) {
  254. if (ret != DB_NOTFOUND) {
  255. char ustr[JACK_UUID_STRING_SIZE];
  256. jack_uuid_unparse (subject, ustr);
  257. jack_error ("Cannot retrieve metadata for %s/%s (%s)", ustr, key, db_strerror (ret));
  258. }
  259. if (d_key.size > 0) {
  260. free (d_key.data);
  261. }
  262. if (data.size > 0) {
  263. free (data.data);
  264. }
  265. return -1;
  266. }
  267. /* result must have at least 1 char plus 1 null to be valid
  268. (old rule was:
  269. result must have at least 2 chars plus 2 nulls to be valid
  270. )
  271. */
  272. if (data.size < 2) {
  273. if (d_key.size > 0) {
  274. free (d_key.data);
  275. }
  276. if (data.size > 0) {
  277. free (data.data);
  278. }
  279. return -1;
  280. }
  281. len1 = strlen ((const char*)data.data) + 1;
  282. (*value) = (char*)malloc (len1);
  283. memcpy (*value, data.data, len1);
  284. if (len1 < data.size) {
  285. len2 = strlen ((const char*)data.data + len1) + 1;
  286. (*type) = (char*)malloc (len2);
  287. memcpy (*type, (const char *)data.data + len1, len2);
  288. } else {
  289. /* no type specified, assume default */
  290. *type = NULL;
  291. }
  292. if (d_key.size > 0) {
  293. free (d_key.data);
  294. }
  295. if (data.size > 0) {
  296. free (data.data);
  297. }
  298. return 0;
  299. #else // !HAVE_DB
  300. return -1;
  301. #endif
  302. }
  303. int JackMetadata::GetProperties(jack_uuid_t subject, jack_description_t* desc)
  304. {
  305. #if HAVE_DB
  306. DBT key;
  307. DBT data;
  308. DBC* cursor;
  309. int ret;
  310. size_t len1, len2;
  311. size_t cnt = 0;
  312. char ustr[JACK_UUID_STRING_SIZE];
  313. size_t props_size = 0;
  314. jack_property_t* prop;
  315. desc->properties = NULL;
  316. desc->property_cnt = 0;
  317. memset (ustr, 0, JACK_UUID_STRING_SIZE);
  318. jack_uuid_unparse (subject, ustr);
  319. if (PropertyInit()) {
  320. return -1;
  321. }
  322. if ((ret = fDB->cursor (fDB, 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 (key.size > 0) free(key.data); */
  335. if (data.size > 0) {
  336. free (data.data);
  337. }
  338. continue;
  339. }
  340. if (memcmp (ustr, key.data, JACK_UUID_STRING_SIZE) != 0) {
  341. /* not relevant */
  342. /* if (key.size > 0) free(key.data); */
  343. if (data.size > 0) {
  344. free (data.data);
  345. }
  346. continue;
  347. }
  348. /* result must have at least 1 char plus 1 null to be valid
  349. (old rule was:
  350. result must have at least 2 chars plus 2 nulls to be valid
  351. )
  352. */
  353. if (data.size < 2) {
  354. /* if (key.size > 0) free(key.data); */
  355. if (data.size > 0) {
  356. free (data.data);
  357. }
  358. continue;
  359. }
  360. /* realloc array if necessary */
  361. if (cnt == props_size) {
  362. if (props_size == 0) {
  363. props_size = 8; /* a rough guess at a likely upper bound for the number of properties */
  364. } else {
  365. props_size *= 2;
  366. }
  367. desc->properties = (jack_property_t*)realloc (desc->properties, sizeof(jack_property_t) * props_size);
  368. }
  369. prop = &desc->properties[cnt];
  370. /* store UUID/subject */
  371. jack_uuid_copy (&desc->subject, subject);
  372. /* copy key (without leading UUID as subject */
  373. len1 = key.size - JACK_UUID_STRING_SIZE;
  374. prop->key = (char*)malloc (len1);
  375. memcpy ((char*)prop->key, (const char *)key.data + JACK_UUID_STRING_SIZE, len1);
  376. /* copy data (which contains 1 or 2 null terminated strings, the value
  377. and optionally a MIME type.
  378. */
  379. len1 = strlen ((const char*)data.data) + 1;
  380. prop->data = (char*)malloc (len1);
  381. memcpy ((char*)prop->data, data.data, len1);
  382. if (len1 < data.size) {
  383. len2 = strlen ((const char *)data.data + len1) + 1;
  384. prop->type = (char*)malloc (len2);
  385. memcpy ((char*)prop->type, (const char *)data.data + len1, len2);
  386. } else {
  387. /* no type specified, assume default */
  388. prop->type = NULL;
  389. }
  390. /* if (key.size > 0) free(key.data); */
  391. if (data.size > 0) {
  392. free (data.data);
  393. }
  394. ++cnt;
  395. }
  396. cursor->close (cursor);
  397. desc->property_cnt = cnt;
  398. return cnt;
  399. #else // !HAVE_DB
  400. return -1;
  401. #endif
  402. }
  403. int JackMetadata::GetAllProperties(jack_description_t** descriptions)
  404. {
  405. #if HAVE_DB
  406. DBT key;
  407. DBT data;
  408. DBC* cursor;
  409. int ret;
  410. size_t dcnt = 0;
  411. size_t dsize = 0;
  412. size_t n = 0;
  413. jack_description_t* desc = NULL;
  414. jack_uuid_t uuid = JACK_UUID_EMPTY_INITIALIZER;
  415. jack_description_t* current_desc = NULL;
  416. jack_property_t* current_prop = NULL;
  417. size_t len1, len2;
  418. if (PropertyInit()) {
  419. return -1;
  420. }
  421. if ((ret = fDB->cursor (fDB, NULL, &cursor, 0)) != 0) {
  422. jack_error ("Cannot create cursor for metadata search (%s)", db_strerror (ret));
  423. return -1;
  424. }
  425. memset (&key, 0, sizeof(key));
  426. memset (&data, 0, sizeof(data));
  427. data.flags = DB_DBT_MALLOC;
  428. dsize = 8; /* initial guess at number of descriptions we need */
  429. dcnt = 0;
  430. desc = (jack_description_t*)malloc (dsize * sizeof(jack_description_t));
  431. while ((ret = cursor->get (cursor, &key, &data, DB_NEXT)) == 0) {
  432. /* require 2 extra chars (data+null) for key,
  433. which is composed of UUID str plus a key name
  434. */
  435. if (key.size < JACK_UUID_STRING_SIZE + 2) {
  436. /* if (key.size > 0) free(key.data); */
  437. if (data.size > 0) {
  438. free (data.data);
  439. }
  440. continue;
  441. }
  442. if (jack_uuid_parse ((const char *)key.data, &uuid) != 0) {
  443. continue;
  444. }
  445. /* do we have an existing description for this UUID */
  446. for (n = 0; n < dcnt; ++n) {
  447. if (jack_uuid_compare (uuid, desc[n].subject) == 0) {
  448. break;
  449. }
  450. }
  451. if (n == dcnt) {
  452. /* we do not have an existing description, so grow the array */
  453. if (dcnt == dsize) {
  454. dsize *= 2;
  455. desc = (jack_description_t*)realloc (desc, sizeof(jack_description_t) * dsize);
  456. }
  457. /* initialize */
  458. desc[n].property_size = 0;
  459. desc[n].property_cnt = 0;
  460. desc[n].properties = NULL;
  461. /* set up UUID */
  462. jack_uuid_copy (&desc[n].subject, uuid);
  463. dcnt++;
  464. }
  465. current_desc = &desc[n];
  466. /* see if there is room for the new property or if we need to realloc
  467. */
  468. if (current_desc->property_cnt == current_desc->property_size) {
  469. if (current_desc->property_size == 0) {
  470. current_desc->property_size = 8;
  471. } else {
  472. current_desc->property_size *= 2;
  473. }
  474. current_desc->properties = (jack_property_t*)realloc (current_desc->properties, sizeof(jack_property_t) * current_desc->property_size);
  475. }
  476. current_prop = &current_desc->properties[current_desc->property_cnt++];
  477. /* copy key (without leading UUID) */
  478. len1 = key.size - JACK_UUID_STRING_SIZE;
  479. current_prop->key = (char*)malloc (len1);
  480. memcpy ((char*)current_prop->key, (const char *)key.data + JACK_UUID_STRING_SIZE, len1);
  481. /* copy data (which contains 1 or 2 null terminated strings, the value
  482. and optionally a MIME type.
  483. */
  484. len1 = strlen ((const char *)data.data) + 1;
  485. current_prop->data = (char*)malloc (len1);
  486. memcpy ((char*)current_prop->data, data.data, len1);
  487. if (len1 < data.size) {
  488. len2 = strlen ((const char *)data.data + len1) + 1;
  489. current_prop->type = (char*)malloc (len2);
  490. memcpy ((char*)current_prop->type, (const char *)data.data + len1, len2);
  491. } else {
  492. /* no type specified, assume default */
  493. current_prop->type = NULL;
  494. }
  495. /* if (key.size > 0) free(key.data); */
  496. if (data.size > 0) {
  497. free (data.data);
  498. }
  499. }
  500. cursor->close (cursor);
  501. (*descriptions) = desc;
  502. return dcnt;
  503. #else // !HAVE_DB
  504. return -1;
  505. #endif
  506. }
  507. int JackMetadata::GetDescription(jack_uuid_t subject, jack_description_t* desc)
  508. {
  509. return 0;
  510. }
  511. int JackMetadata::GetAllDescriptions(jack_description_t** descs)
  512. {
  513. return 0;
  514. }
  515. void JackMetadata::FreeDescription(jack_description_t* desc, int free_actual_description_too)
  516. {
  517. uint32_t n;
  518. for (n = 0; n < desc->property_cnt; ++n) {
  519. free ((char*)desc->properties[n].key);
  520. free ((char*)desc->properties[n].data);
  521. if (desc->properties[n].type) {
  522. free ((char*)desc->properties[n].type);
  523. }
  524. }
  525. free (desc->properties);
  526. if (free_actual_description_too) {
  527. free (desc);
  528. }
  529. }
  530. int JackMetadata::RemoveProperty(JackClient* client, jack_uuid_t subject, const char* key)
  531. {
  532. #if HAVE_DB
  533. DBT d_key;
  534. int ret;
  535. if (PropertyInit()) {
  536. return -1;
  537. }
  538. MakeKeyDbt(&d_key, subject, key);
  539. if ((ret = fDB->del (fDB, NULL, &d_key, 0)) != 0) {
  540. jack_error ("Cannot delete key %s (%s)", key, db_strerror (ret));
  541. if (d_key.size > 0) {
  542. free (d_key.data);
  543. }
  544. return -1;
  545. }
  546. PropertyChangeNotify(client, subject, key, PropertyDeleted);
  547. if (d_key.size > 0) {
  548. free (d_key.data);
  549. }
  550. return 0;
  551. #else // !HAVE_DB
  552. return -1;
  553. #endif
  554. }
  555. int JackMetadata::RemoveProperties(JackClient* client, jack_uuid_t subject)
  556. {
  557. #if HAVE_DB
  558. DBT key;
  559. DBT data;
  560. DBC* cursor;
  561. int ret;
  562. char ustr[JACK_UUID_STRING_SIZE];
  563. int retval = 0;
  564. uint32_t cnt = 0;
  565. memset (ustr, 0, JACK_UUID_STRING_SIZE);
  566. jack_uuid_unparse (subject, ustr);
  567. if (PropertyInit() || fDB == NULL) {
  568. return -1;
  569. }
  570. if ((ret = fDB->cursor (fDB, NULL, &cursor, 0)) != 0) {
  571. jack_error ("Cannot create cursor for metadata search (%s)", db_strerror (ret));
  572. return -1;
  573. }
  574. memset (&key, 0, sizeof(key));
  575. memset (&data, 0, sizeof(data));
  576. data.flags = DB_DBT_MALLOC;
  577. while ((ret = cursor->get (cursor, &key, &data, DB_NEXT)) == 0) {
  578. /* require 2 extra chars (data+null) for key,
  579. which is composed of UUID str plus a key name
  580. */
  581. if (key.size < JACK_UUID_STRING_SIZE + 2) {
  582. /* if (key.size > 0) free(key.data); */
  583. if (data.size > 0) {
  584. free (data.data);
  585. }
  586. continue;
  587. }
  588. if (memcmp (ustr, key.data, JACK_UUID_STRING_SIZE) != 0) {
  589. /* not relevant */
  590. /* if (key.size > 0) free(key.data); */
  591. if (data.size > 0) {
  592. free (data.data);
  593. }
  594. continue;
  595. }
  596. if ((ret = cursor->del (cursor, 0)) != 0) {
  597. jack_error ("cannot delete property (%s)", db_strerror (ret));
  598. /* don't return -1 here since this would leave things
  599. even more inconsistent. wait till the cursor is finished
  600. */
  601. retval = -1;
  602. }
  603. cnt++;
  604. /* if (key.size > 0) free(key.data); */
  605. if (data.size > 0) {
  606. free (data.data);
  607. }
  608. }
  609. cursor->close (cursor);
  610. if (cnt) {
  611. PropertyChangeNotify(client, subject, NULL, PropertyDeleted);
  612. }
  613. if (retval) {
  614. return -1;
  615. }
  616. return cnt;
  617. #else // !HAVE_DB
  618. return -1;
  619. #endif
  620. }
  621. int JackMetadata::RemoveAllProperties(JackClient* client)
  622. {
  623. #if HAVE_DB
  624. int ret;
  625. jack_uuid_t empty_uuid = JACK_UUID_EMPTY_INITIALIZER;
  626. if (PropertyInit()) {
  627. return -1;
  628. }
  629. if ((ret = fDB->truncate (fDB, NULL, NULL, 0)) != 0) {
  630. jack_error ("Cannot clear properties (%s)", db_strerror (ret));
  631. return -1;
  632. }
  633. PropertyChangeNotify(client, empty_uuid, NULL, PropertyDeleted);
  634. return 0;
  635. #else // !HAVE_DB
  636. return -1;
  637. #endif
  638. }
  639. } // end of namespace