ntdb.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /*
  2. Trivial Database 2: fetch, store and misc routines.
  3. Copyright (C) Rusty Russell 2010
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 3 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "private.h"
  16. #ifndef HAVE_LIBREPLACE
  17. #include <stdarg.h>
  18. #endif
  19. static enum NTDB_ERROR update_rec_hdr(struct ntdb_context *ntdb,
  20. ntdb_off_t off,
  21. ntdb_len_t keylen,
  22. ntdb_len_t datalen,
  23. struct ntdb_used_record *rec)
  24. {
  25. uint64_t dataroom = rec_data_length(rec) + rec_extra_padding(rec);
  26. enum NTDB_ERROR ecode;
  27. ecode = set_header(ntdb, rec, NTDB_USED_MAGIC, keylen, datalen,
  28. keylen + dataroom);
  29. if (ecode == NTDB_SUCCESS) {
  30. ecode = ntdb_write_convert(ntdb, off, rec, sizeof(*rec));
  31. }
  32. return ecode;
  33. }
  34. static enum NTDB_ERROR replace_data(struct ntdb_context *ntdb,
  35. struct hash_info *h,
  36. NTDB_DATA key, NTDB_DATA dbuf,
  37. ntdb_off_t old_off, ntdb_len_t old_room,
  38. bool growing)
  39. {
  40. ntdb_off_t new_off;
  41. enum NTDB_ERROR ecode;
  42. /* Allocate a new record. */
  43. new_off = alloc(ntdb, key.dsize, dbuf.dsize, NTDB_USED_MAGIC, growing);
  44. if (NTDB_OFF_IS_ERR(new_off)) {
  45. return NTDB_OFF_TO_ERR(new_off);
  46. }
  47. /* We didn't like the existing one: remove it. */
  48. if (old_off) {
  49. ntdb->stats.frees++;
  50. ecode = add_free_record(ntdb, old_off,
  51. sizeof(struct ntdb_used_record)
  52. + key.dsize + old_room,
  53. NTDB_LOCK_WAIT, true);
  54. if (ecode == NTDB_SUCCESS)
  55. ecode = replace_in_hash(ntdb, h, new_off);
  56. } else {
  57. ecode = add_to_hash(ntdb, h, new_off);
  58. }
  59. if (ecode != NTDB_SUCCESS) {
  60. return ecode;
  61. }
  62. new_off += sizeof(struct ntdb_used_record);
  63. ecode = ntdb->io->twrite(ntdb, new_off, key.dptr, key.dsize);
  64. if (ecode != NTDB_SUCCESS) {
  65. return ecode;
  66. }
  67. new_off += key.dsize;
  68. ecode = ntdb->io->twrite(ntdb, new_off, dbuf.dptr, dbuf.dsize);
  69. if (ecode != NTDB_SUCCESS) {
  70. return ecode;
  71. }
  72. if (ntdb->flags & NTDB_SEQNUM)
  73. ntdb_inc_seqnum(ntdb);
  74. return NTDB_SUCCESS;
  75. }
  76. static enum NTDB_ERROR update_data(struct ntdb_context *ntdb,
  77. ntdb_off_t off,
  78. NTDB_DATA dbuf,
  79. ntdb_len_t extra)
  80. {
  81. enum NTDB_ERROR ecode;
  82. ecode = ntdb->io->twrite(ntdb, off, dbuf.dptr, dbuf.dsize);
  83. if (ecode == NTDB_SUCCESS && extra) {
  84. /* Put a zero in; future versions may append other data. */
  85. ecode = ntdb->io->twrite(ntdb, off + dbuf.dsize, "", 1);
  86. }
  87. if (ntdb->flags & NTDB_SEQNUM)
  88. ntdb_inc_seqnum(ntdb);
  89. return ecode;
  90. }
  91. _PUBLIC_ enum NTDB_ERROR ntdb_store(struct ntdb_context *ntdb,
  92. NTDB_DATA key, NTDB_DATA dbuf, int flag)
  93. {
  94. struct hash_info h;
  95. ntdb_off_t off;
  96. ntdb_len_t old_room = 0;
  97. struct ntdb_used_record rec;
  98. enum NTDB_ERROR ecode;
  99. off = find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL);
  100. if (NTDB_OFF_IS_ERR(off)) {
  101. return NTDB_OFF_TO_ERR(off);
  102. }
  103. /* Now we have lock on this hash bucket. */
  104. if (flag == NTDB_INSERT) {
  105. if (off) {
  106. ecode = NTDB_ERR_EXISTS;
  107. goto out;
  108. }
  109. } else {
  110. if (off) {
  111. old_room = rec_data_length(&rec)
  112. + rec_extra_padding(&rec);
  113. if (old_room >= dbuf.dsize) {
  114. /* Can modify in-place. Easy! */
  115. ecode = update_rec_hdr(ntdb, off,
  116. key.dsize, dbuf.dsize,
  117. &rec);
  118. if (ecode != NTDB_SUCCESS) {
  119. goto out;
  120. }
  121. ecode = update_data(ntdb,
  122. off + sizeof(rec)
  123. + key.dsize, dbuf,
  124. old_room - dbuf.dsize);
  125. if (ecode != NTDB_SUCCESS) {
  126. goto out;
  127. }
  128. ntdb_unlock_hash(ntdb, h.h, F_WRLCK);
  129. return NTDB_SUCCESS;
  130. }
  131. } else {
  132. if (flag == NTDB_MODIFY) {
  133. /* if the record doesn't exist and we
  134. are in NTDB_MODIFY mode then we should fail
  135. the store */
  136. ecode = NTDB_ERR_NOEXIST;
  137. goto out;
  138. }
  139. }
  140. }
  141. /* If we didn't use the old record, this implies we're growing. */
  142. ecode = replace_data(ntdb, &h, key, dbuf, off, old_room, off);
  143. out:
  144. ntdb_unlock_hash(ntdb, h.h, F_WRLCK);
  145. return ecode;
  146. }
  147. _PUBLIC_ enum NTDB_ERROR ntdb_append(struct ntdb_context *ntdb,
  148. NTDB_DATA key, NTDB_DATA dbuf)
  149. {
  150. struct hash_info h;
  151. ntdb_off_t off;
  152. struct ntdb_used_record rec;
  153. ntdb_len_t old_room = 0, old_dlen;
  154. unsigned char *newdata;
  155. NTDB_DATA new_dbuf;
  156. enum NTDB_ERROR ecode;
  157. off = find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL);
  158. if (NTDB_OFF_IS_ERR(off)) {
  159. return NTDB_OFF_TO_ERR(off);
  160. }
  161. if (off) {
  162. old_dlen = rec_data_length(&rec);
  163. old_room = old_dlen + rec_extra_padding(&rec);
  164. /* Fast path: can append in place. */
  165. if (rec_extra_padding(&rec) >= dbuf.dsize) {
  166. ecode = update_rec_hdr(ntdb, off, key.dsize,
  167. old_dlen + dbuf.dsize, &rec);
  168. if (ecode != NTDB_SUCCESS) {
  169. goto out;
  170. }
  171. off += sizeof(rec) + key.dsize + old_dlen;
  172. ecode = update_data(ntdb, off, dbuf,
  173. rec_extra_padding(&rec));
  174. goto out;
  175. }
  176. /* Slow path. */
  177. newdata = ntdb->alloc_fn(ntdb, key.dsize + old_dlen + dbuf.dsize,
  178. ntdb->alloc_data);
  179. if (!newdata) {
  180. ecode = ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
  181. "ntdb_append:"
  182. " failed to allocate %zu bytes",
  183. (size_t)(key.dsize + old_dlen
  184. + dbuf.dsize));
  185. goto out;
  186. }
  187. ecode = ntdb->io->tread(ntdb, off + sizeof(rec) + key.dsize,
  188. newdata, old_dlen);
  189. if (ecode != NTDB_SUCCESS) {
  190. goto out_free_newdata;
  191. }
  192. memcpy(newdata + old_dlen, dbuf.dptr, dbuf.dsize);
  193. new_dbuf.dptr = newdata;
  194. new_dbuf.dsize = old_dlen + dbuf.dsize;
  195. } else {
  196. newdata = NULL;
  197. new_dbuf = dbuf;
  198. }
  199. /* If they're using ntdb_append(), it implies they're growing record. */
  200. ecode = replace_data(ntdb, &h, key, new_dbuf, off, old_room, true);
  201. out_free_newdata:
  202. ntdb->free_fn(newdata, ntdb->alloc_data);
  203. out:
  204. ntdb_unlock_hash(ntdb, h.h, F_WRLCK);
  205. return ecode;
  206. }
  207. _PUBLIC_ enum NTDB_ERROR ntdb_fetch(struct ntdb_context *ntdb, NTDB_DATA key,
  208. NTDB_DATA *data)
  209. {
  210. ntdb_off_t off;
  211. struct ntdb_used_record rec;
  212. struct hash_info h;
  213. enum NTDB_ERROR ecode;
  214. const char *keyp;
  215. off = find_and_lock(ntdb, key, F_RDLCK, &h, &rec, &keyp);
  216. if (NTDB_OFF_IS_ERR(off)) {
  217. return NTDB_OFF_TO_ERR(off);
  218. }
  219. if (!off) {
  220. ecode = NTDB_ERR_NOEXIST;
  221. } else {
  222. data->dsize = rec_data_length(&rec);
  223. data->dptr = ntdb->alloc_fn(ntdb, data->dsize, ntdb->alloc_data);
  224. if (unlikely(!data->dptr)) {
  225. ecode = NTDB_ERR_OOM;
  226. } else {
  227. memcpy(data->dptr, keyp + key.dsize, data->dsize);
  228. ecode = NTDB_SUCCESS;
  229. }
  230. ntdb_access_release(ntdb, keyp);
  231. }
  232. ntdb_unlock_hash(ntdb, h.h, F_RDLCK);
  233. return ecode;
  234. }
  235. _PUBLIC_ bool ntdb_exists(struct ntdb_context *ntdb, NTDB_DATA key)
  236. {
  237. ntdb_off_t off;
  238. struct ntdb_used_record rec;
  239. struct hash_info h;
  240. off = find_and_lock(ntdb, key, F_RDLCK, &h, &rec, NULL);
  241. if (NTDB_OFF_IS_ERR(off)) {
  242. return false;
  243. }
  244. ntdb_unlock_hash(ntdb, h.h, F_RDLCK);
  245. return off ? true : false;
  246. }
  247. _PUBLIC_ enum NTDB_ERROR ntdb_delete(struct ntdb_context *ntdb, NTDB_DATA key)
  248. {
  249. ntdb_off_t off;
  250. struct ntdb_used_record rec;
  251. struct hash_info h;
  252. enum NTDB_ERROR ecode;
  253. off = find_and_lock(ntdb, key, F_WRLCK, &h, &rec, NULL);
  254. if (NTDB_OFF_IS_ERR(off)) {
  255. return NTDB_OFF_TO_ERR(off);
  256. }
  257. if (!off) {
  258. ecode = NTDB_ERR_NOEXIST;
  259. goto unlock;
  260. }
  261. ecode = delete_from_hash(ntdb, &h);
  262. if (ecode != NTDB_SUCCESS) {
  263. goto unlock;
  264. }
  265. /* Free the deleted entry. */
  266. ntdb->stats.frees++;
  267. ecode = add_free_record(ntdb, off,
  268. sizeof(struct ntdb_used_record)
  269. + rec_key_length(&rec)
  270. + rec_data_length(&rec)
  271. + rec_extra_padding(&rec),
  272. NTDB_LOCK_WAIT, true);
  273. if (ntdb->flags & NTDB_SEQNUM)
  274. ntdb_inc_seqnum(ntdb);
  275. unlock:
  276. ntdb_unlock_hash(ntdb, h.h, F_WRLCK);
  277. return ecode;
  278. }
  279. _PUBLIC_ unsigned int ntdb_get_flags(struct ntdb_context *ntdb)
  280. {
  281. return ntdb->flags;
  282. }
  283. static bool inside_transaction(const struct ntdb_context *ntdb)
  284. {
  285. return ntdb->transaction != NULL;
  286. }
  287. static bool readonly_changable(struct ntdb_context *ntdb, const char *caller)
  288. {
  289. if (inside_transaction(ntdb)) {
  290. ntdb_logerr(ntdb, NTDB_ERR_EINVAL, NTDB_LOG_USE_ERROR,
  291. "%s: can't change"
  292. " NTDB_RDONLY inside transaction",
  293. caller);
  294. return false;
  295. }
  296. return true;
  297. }
  298. _PUBLIC_ void ntdb_add_flag(struct ntdb_context *ntdb, unsigned flag)
  299. {
  300. if (ntdb->flags & NTDB_INTERNAL) {
  301. ntdb_logerr(ntdb, NTDB_ERR_EINVAL, NTDB_LOG_USE_ERROR,
  302. "ntdb_add_flag: internal db");
  303. return;
  304. }
  305. switch (flag) {
  306. case NTDB_NOLOCK:
  307. ntdb->flags |= NTDB_NOLOCK;
  308. break;
  309. case NTDB_NOMMAP:
  310. if (ntdb->file->direct_count) {
  311. ntdb_logerr(ntdb, NTDB_ERR_EINVAL, NTDB_LOG_USE_ERROR,
  312. "ntdb_add_flag: Can't get NTDB_NOMMAP from"
  313. " ntdb_parse_record!");
  314. return;
  315. }
  316. ntdb->flags |= NTDB_NOMMAP;
  317. #ifndef HAVE_INCOHERENT_MMAP
  318. ntdb_munmap(ntdb);
  319. #endif
  320. break;
  321. case NTDB_NOSYNC:
  322. ntdb->flags |= NTDB_NOSYNC;
  323. break;
  324. case NTDB_SEQNUM:
  325. ntdb->flags |= NTDB_SEQNUM;
  326. break;
  327. case NTDB_ALLOW_NESTING:
  328. ntdb->flags |= NTDB_ALLOW_NESTING;
  329. break;
  330. case NTDB_RDONLY:
  331. if (readonly_changable(ntdb, "ntdb_add_flag"))
  332. ntdb->flags |= NTDB_RDONLY;
  333. break;
  334. default:
  335. ntdb_logerr(ntdb, NTDB_ERR_EINVAL, NTDB_LOG_USE_ERROR,
  336. "ntdb_add_flag: Unknown flag %u", flag);
  337. }
  338. }
  339. _PUBLIC_ void ntdb_remove_flag(struct ntdb_context *ntdb, unsigned flag)
  340. {
  341. if (ntdb->flags & NTDB_INTERNAL) {
  342. ntdb_logerr(ntdb, NTDB_ERR_EINVAL, NTDB_LOG_USE_ERROR,
  343. "ntdb_remove_flag: internal db");
  344. return;
  345. }
  346. switch (flag) {
  347. case NTDB_NOLOCK:
  348. ntdb->flags &= ~NTDB_NOLOCK;
  349. break;
  350. case NTDB_NOMMAP:
  351. ntdb->flags &= ~NTDB_NOMMAP;
  352. #ifndef HAVE_INCOHERENT_MMAP
  353. /* If mmap incoherent, we were mmaping anyway. */
  354. ntdb_mmap(ntdb);
  355. #endif
  356. break;
  357. case NTDB_NOSYNC:
  358. ntdb->flags &= ~NTDB_NOSYNC;
  359. break;
  360. case NTDB_SEQNUM:
  361. ntdb->flags &= ~NTDB_SEQNUM;
  362. break;
  363. case NTDB_ALLOW_NESTING:
  364. ntdb->flags &= ~NTDB_ALLOW_NESTING;
  365. break;
  366. case NTDB_RDONLY:
  367. if ((ntdb->open_flags & O_ACCMODE) == O_RDONLY) {
  368. ntdb_logerr(ntdb, NTDB_ERR_EINVAL, NTDB_LOG_USE_ERROR,
  369. "ntdb_remove_flag: can't"
  370. " remove NTDB_RDONLY on ntdb"
  371. " opened with O_RDONLY");
  372. break;
  373. }
  374. if (readonly_changable(ntdb, "ntdb_remove_flag"))
  375. ntdb->flags &= ~NTDB_RDONLY;
  376. break;
  377. default:
  378. ntdb_logerr(ntdb, NTDB_ERR_EINVAL, NTDB_LOG_USE_ERROR,
  379. "ntdb_remove_flag: Unknown flag %u",
  380. flag);
  381. }
  382. }
  383. _PUBLIC_ const char *ntdb_errorstr(enum NTDB_ERROR ecode)
  384. {
  385. /* Gcc warns if you miss a case in the switch, so use that. */
  386. switch (NTDB_ERR_TO_OFF(ecode)) {
  387. case NTDB_ERR_TO_OFF(NTDB_SUCCESS): return "Success";
  388. case NTDB_ERR_TO_OFF(NTDB_ERR_CORRUPT): return "Corrupt database";
  389. case NTDB_ERR_TO_OFF(NTDB_ERR_IO): return "IO Error";
  390. case NTDB_ERR_TO_OFF(NTDB_ERR_LOCK): return "Locking error";
  391. case NTDB_ERR_TO_OFF(NTDB_ERR_OOM): return "Out of memory";
  392. case NTDB_ERR_TO_OFF(NTDB_ERR_EXISTS): return "Record exists";
  393. case NTDB_ERR_TO_OFF(NTDB_ERR_EINVAL): return "Invalid parameter";
  394. case NTDB_ERR_TO_OFF(NTDB_ERR_NOEXIST): return "Record does not exist";
  395. case NTDB_ERR_TO_OFF(NTDB_ERR_RDONLY): return "write not permitted";
  396. }
  397. return "Invalid error code";
  398. }
  399. enum NTDB_ERROR COLD ntdb_logerr(struct ntdb_context *ntdb,
  400. enum NTDB_ERROR ecode,
  401. enum ntdb_log_level level,
  402. const char *fmt, ...)
  403. {
  404. char *message;
  405. va_list ap;
  406. size_t len;
  407. /* ntdb_open paths care about errno, so save it. */
  408. int saved_errno = errno;
  409. if (!ntdb->log_fn)
  410. return ecode;
  411. va_start(ap, fmt);
  412. len = vsnprintf(NULL, 0, fmt, ap);
  413. va_end(ap);
  414. message = ntdb->alloc_fn(ntdb, len + 1, ntdb->alloc_data);
  415. if (!message) {
  416. ntdb->log_fn(ntdb, NTDB_LOG_ERROR, NTDB_ERR_OOM,
  417. "out of memory formatting message:", ntdb->log_data);
  418. ntdb->log_fn(ntdb, level, ecode, fmt, ntdb->log_data);
  419. } else {
  420. va_start(ap, fmt);
  421. vsnprintf(message, len+1, fmt, ap);
  422. va_end(ap);
  423. ntdb->log_fn(ntdb, level, ecode, message, ntdb->log_data);
  424. ntdb->free_fn(message, ntdb->alloc_data);
  425. }
  426. errno = saved_errno;
  427. return ecode;
  428. }
  429. _PUBLIC_ enum NTDB_ERROR ntdb_parse_record_(struct ntdb_context *ntdb,
  430. NTDB_DATA key,
  431. enum NTDB_ERROR (*parse)(NTDB_DATA k,
  432. NTDB_DATA d,
  433. void *data),
  434. void *data)
  435. {
  436. ntdb_off_t off;
  437. struct ntdb_used_record rec;
  438. struct hash_info h;
  439. enum NTDB_ERROR ecode;
  440. const char *keyp;
  441. off = find_and_lock(ntdb, key, F_RDLCK, &h, &rec, &keyp);
  442. if (NTDB_OFF_IS_ERR(off)) {
  443. return NTDB_OFF_TO_ERR(off);
  444. }
  445. if (!off) {
  446. ecode = NTDB_ERR_NOEXIST;
  447. } else {
  448. unsigned int old_flags;
  449. NTDB_DATA d = ntdb_mkdata(keyp + key.dsize,
  450. rec_data_length(&rec));
  451. /*
  452. * Make sure they don't try to write db, since they
  453. * have read lock! They can if they've done
  454. * ntdb_lockall(): if it was ntdb_lockall_read, that'll
  455. * stop them doing a write operation anyway.
  456. */
  457. old_flags = ntdb->flags;
  458. if (!ntdb->file->allrecord_lock.count &&
  459. !(ntdb->flags & NTDB_NOLOCK)) {
  460. ntdb->flags |= NTDB_RDONLY;
  461. }
  462. ecode = parse(key, d, data);
  463. ntdb->flags = old_flags;
  464. ntdb_access_release(ntdb, keyp);
  465. }
  466. ntdb_unlock_hash(ntdb, h.h, F_RDLCK);
  467. return ecode;
  468. }
  469. _PUBLIC_ const char *ntdb_name(const struct ntdb_context *ntdb)
  470. {
  471. return ntdb->name;
  472. }
  473. _PUBLIC_ int64_t ntdb_get_seqnum(struct ntdb_context *ntdb)
  474. {
  475. return ntdb_read_off(ntdb, offsetof(struct ntdb_header, seqnum));
  476. }
  477. _PUBLIC_ int ntdb_fd(const struct ntdb_context *ntdb)
  478. {
  479. return ntdb->file->fd;
  480. }
  481. struct traverse_state {
  482. enum NTDB_ERROR error;
  483. struct ntdb_context *dest_db;
  484. };
  485. /*
  486. traverse function for repacking
  487. */
  488. static int repack_traverse(struct ntdb_context *ntdb, NTDB_DATA key, NTDB_DATA data,
  489. struct traverse_state *state)
  490. {
  491. state->error = ntdb_store(state->dest_db, key, data, NTDB_INSERT);
  492. if (state->error != NTDB_SUCCESS) {
  493. return -1;
  494. }
  495. return 0;
  496. }
  497. _PUBLIC_ enum NTDB_ERROR ntdb_repack(struct ntdb_context *ntdb)
  498. {
  499. struct ntdb_context *tmp_db;
  500. struct traverse_state state;
  501. state.error = ntdb_transaction_start(ntdb);
  502. if (state.error != NTDB_SUCCESS) {
  503. return state.error;
  504. }
  505. tmp_db = ntdb_open("tmpdb", NTDB_INTERNAL, O_RDWR|O_CREAT, 0, NULL);
  506. if (tmp_db == NULL) {
  507. state.error = ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
  508. __location__
  509. " Failed to create tmp_db");
  510. ntdb_transaction_cancel(ntdb);
  511. return state.error;
  512. }
  513. state.dest_db = tmp_db;
  514. if (ntdb_traverse(ntdb, repack_traverse, &state) < 0) {
  515. goto fail;
  516. }
  517. state.error = ntdb_wipe_all(ntdb);
  518. if (state.error != NTDB_SUCCESS) {
  519. goto fail;
  520. }
  521. state.dest_db = ntdb;
  522. if (ntdb_traverse(tmp_db, repack_traverse, &state) < 0) {
  523. goto fail;
  524. }
  525. ntdb_close(tmp_db);
  526. return ntdb_transaction_commit(ntdb);
  527. fail:
  528. ntdb_transaction_cancel(ntdb);
  529. ntdb_close(tmp_db);
  530. return state.error;
  531. }