tdb.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. #include "private.h"
  2. #include <ccan/tdb2/tdb2.h>
  3. #include <assert.h>
  4. #include <stdarg.h>
  5. /* The null return. */
  6. struct tdb_data tdb_null = { .dptr = NULL, .dsize = 0 };
  7. /* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
  8. static struct tdb_context *tdbs = NULL;
  9. static bool tdb_already_open(dev_t device, ino_t ino)
  10. {
  11. struct tdb_context *i;
  12. for (i = tdbs; i; i = i->next) {
  13. if (i->device == device && i->inode == ino) {
  14. return true;
  15. }
  16. }
  17. return false;
  18. }
  19. static bool read_all(int fd, void *buf, size_t len)
  20. {
  21. while (len) {
  22. ssize_t ret;
  23. ret = read(fd, buf, len);
  24. if (ret < 0)
  25. return false;
  26. if (ret == 0) {
  27. /* ETOOSHORT? */
  28. errno = EWOULDBLOCK;
  29. return false;
  30. }
  31. buf = (char *)buf + ret;
  32. len -= ret;
  33. }
  34. return true;
  35. }
  36. static uint64_t random_number(struct tdb_context *tdb)
  37. {
  38. int fd;
  39. uint64_t ret = 0;
  40. struct timeval now;
  41. fd = open("/dev/urandom", O_RDONLY);
  42. if (fd >= 0) {
  43. if (read_all(fd, &ret, sizeof(ret))) {
  44. close(fd);
  45. return ret;
  46. }
  47. close(fd);
  48. }
  49. /* FIXME: Untested! Based on Wikipedia protocol description! */
  50. fd = open("/dev/egd-pool", O_RDWR);
  51. if (fd >= 0) {
  52. /* Command is 1, next byte is size we want to read. */
  53. char cmd[2] = { 1, sizeof(uint64_t) };
  54. if (write(fd, cmd, sizeof(cmd)) == sizeof(cmd)) {
  55. char reply[1 + sizeof(uint64_t)];
  56. int r = read(fd, reply, sizeof(reply));
  57. if (r > 1) {
  58. /* Copy at least some bytes. */
  59. memcpy(&ret, reply+1, r - 1);
  60. if (reply[0] == sizeof(uint64_t)
  61. && r == sizeof(reply)) {
  62. close(fd);
  63. return ret;
  64. }
  65. }
  66. }
  67. close(fd);
  68. }
  69. /* Fallback: pid and time. */
  70. gettimeofday(&now, NULL);
  71. ret = getpid() * 100132289ULL + now.tv_sec * 1000000ULL + now.tv_usec;
  72. tdb_logerr(tdb, TDB_SUCCESS, TDB_LOG_WARNING,
  73. "tdb_open: random from getpid and time");
  74. return ret;
  75. }
  76. struct new_database {
  77. struct tdb_header hdr;
  78. struct tdb_freetable ftable;
  79. };
  80. /* initialise a new database */
  81. static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb,
  82. struct tdb_attribute_seed *seed,
  83. struct tdb_header *hdr)
  84. {
  85. /* We make it up in memory, then write it out if not internal */
  86. struct new_database newdb;
  87. unsigned int magic_len;
  88. ssize_t rlen;
  89. enum TDB_ERROR ecode;
  90. /* Fill in the header */
  91. newdb.hdr.version = TDB_VERSION;
  92. if (seed)
  93. newdb.hdr.hash_seed = seed->seed;
  94. else
  95. newdb.hdr.hash_seed = random_number(tdb);
  96. newdb.hdr.hash_test = TDB_HASH_MAGIC;
  97. newdb.hdr.hash_test = tdb->khash(&newdb.hdr.hash_test,
  98. sizeof(newdb.hdr.hash_test),
  99. newdb.hdr.hash_seed,
  100. tdb->hash_priv);
  101. newdb.hdr.recovery = 0;
  102. memset(newdb.hdr.reserved, 0, sizeof(newdb.hdr.reserved));
  103. /* Initial hashes are empty. */
  104. memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable));
  105. /* Free is empty. */
  106. newdb.hdr.free_table = offsetof(struct new_database, ftable);
  107. memset(&newdb.ftable, 0, sizeof(newdb.ftable));
  108. ecode = set_header(NULL, &newdb.ftable.hdr, TDB_FTABLE_MAGIC, 0,
  109. sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr),
  110. sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr),
  111. 0);
  112. if (ecode != TDB_SUCCESS) {
  113. return ecode;
  114. }
  115. /* Magic food */
  116. memset(newdb.hdr.magic_food, 0, sizeof(newdb.hdr.magic_food));
  117. strcpy(newdb.hdr.magic_food, TDB_MAGIC_FOOD);
  118. /* This creates an endian-converted database, as if read from disk */
  119. magic_len = sizeof(newdb.hdr.magic_food);
  120. tdb_convert(tdb,
  121. (char *)&newdb.hdr + magic_len, sizeof(newdb) - magic_len);
  122. *hdr = newdb.hdr;
  123. if (tdb->flags & TDB_INTERNAL) {
  124. tdb->map_size = sizeof(newdb);
  125. tdb->map_ptr = malloc(tdb->map_size);
  126. if (!tdb->map_ptr) {
  127. return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
  128. "tdb_new_database:"
  129. " failed to allocate");
  130. }
  131. memcpy(tdb->map_ptr, &newdb, tdb->map_size);
  132. return TDB_SUCCESS;
  133. }
  134. if (lseek(tdb->fd, 0, SEEK_SET) == -1) {
  135. return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  136. "tdb_new_database:"
  137. " failed to seek: %s", strerror(errno));
  138. }
  139. if (ftruncate(tdb->fd, 0) == -1) {
  140. return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  141. "tdb_new_database:"
  142. " failed to truncate: %s", strerror(errno));
  143. }
  144. rlen = write(tdb->fd, &newdb, sizeof(newdb));
  145. if (rlen != sizeof(newdb)) {
  146. if (rlen >= 0)
  147. errno = ENOSPC;
  148. return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  149. "tdb_new_database: %zi writing header: %s",
  150. rlen, strerror(errno));
  151. }
  152. return TDB_SUCCESS;
  153. }
  154. struct tdb_context *tdb_open(const char *name, int tdb_flags,
  155. int open_flags, mode_t mode,
  156. union tdb_attribute *attr)
  157. {
  158. struct tdb_context *tdb;
  159. struct stat st;
  160. int saved_errno = 0;
  161. uint64_t hash_test;
  162. unsigned v;
  163. ssize_t rlen;
  164. struct tdb_header hdr;
  165. struct tdb_attribute_seed *seed = NULL;
  166. tdb_bool_err berr;
  167. enum TDB_ERROR ecode;
  168. tdb = malloc(sizeof(*tdb));
  169. if (!tdb) {
  170. /* Can't log this */
  171. errno = ENOMEM;
  172. return NULL;
  173. }
  174. tdb->name = NULL;
  175. tdb->map_ptr = NULL;
  176. tdb->direct_access = 0;
  177. tdb->fd = -1;
  178. tdb->map_size = sizeof(struct tdb_header);
  179. tdb->flags = tdb_flags;
  180. tdb->logfn = NULL;
  181. tdb->transaction = NULL;
  182. tdb->stats = NULL;
  183. tdb->access = NULL;
  184. tdb_hash_init(tdb);
  185. tdb_io_init(tdb);
  186. tdb_lock_init(tdb);
  187. while (attr) {
  188. switch (attr->base.attr) {
  189. case TDB_ATTRIBUTE_LOG:
  190. tdb->logfn = attr->log.log_fn;
  191. tdb->log_private = attr->log.log_private;
  192. break;
  193. case TDB_ATTRIBUTE_HASH:
  194. tdb->khash = attr->hash.hash_fn;
  195. tdb->hash_priv = attr->hash.hash_private;
  196. break;
  197. case TDB_ATTRIBUTE_SEED:
  198. seed = &attr->seed;
  199. break;
  200. case TDB_ATTRIBUTE_STATS:
  201. tdb->stats = &attr->stats;
  202. /* They have stats we don't know about? Tell them. */
  203. if (tdb->stats->size > sizeof(attr->stats))
  204. tdb->stats->size = sizeof(attr->stats);
  205. break;
  206. default:
  207. ecode = tdb_logerr(tdb, TDB_ERR_EINVAL,
  208. TDB_LOG_USE_ERROR,
  209. "tdb_open:"
  210. " unknown attribute type %u",
  211. attr->base.attr);
  212. goto fail;
  213. }
  214. attr = attr->base.next;
  215. }
  216. if ((open_flags & O_ACCMODE) == O_WRONLY) {
  217. ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
  218. "tdb_open: can't open tdb %s write-only",
  219. name);
  220. goto fail;
  221. }
  222. if ((open_flags & O_ACCMODE) == O_RDONLY) {
  223. tdb->read_only = true;
  224. tdb->mmap_flags = PROT_READ;
  225. } else {
  226. tdb->read_only = false;
  227. tdb->mmap_flags = PROT_READ | PROT_WRITE;
  228. }
  229. /* internal databases don't need any of the rest. */
  230. if (tdb->flags & TDB_INTERNAL) {
  231. tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
  232. ecode = tdb_new_database(tdb, seed, &hdr);
  233. if (ecode != TDB_SUCCESS) {
  234. goto fail;
  235. }
  236. tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed));
  237. tdb->hash_seed = hdr.hash_seed;
  238. tdb_ftable_init(tdb);
  239. return tdb;
  240. }
  241. if ((tdb->fd = open(name, open_flags, mode)) == -1) {
  242. /* errno set by open(2) */
  243. saved_errno = errno;
  244. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  245. "tdb_open: could not open file %s: %s",
  246. name, strerror(errno));
  247. goto fail;
  248. }
  249. /* on exec, don't inherit the fd */
  250. v = fcntl(tdb->fd, F_GETFD, 0);
  251. fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC);
  252. /* ensure there is only one process initialising at once */
  253. ecode = tdb_lock_open(tdb, TDB_LOCK_WAIT|TDB_LOCK_NOCHECK);
  254. if (ecode != TDB_SUCCESS) {
  255. goto fail;
  256. }
  257. /* If they used O_TRUNC, read will return 0. */
  258. rlen = read(tdb->fd, &hdr, sizeof(hdr));
  259. if (rlen == 0 && (open_flags & O_CREAT)) {
  260. ecode = tdb_new_database(tdb, seed, &hdr);
  261. if (ecode != TDB_SUCCESS) {
  262. goto fail;
  263. }
  264. } else if (rlen < 0) {
  265. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  266. "tdb_open: error %s reading %s",
  267. strerror(errno), name);
  268. goto fail;
  269. } else if (rlen < sizeof(hdr)
  270. || strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) {
  271. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  272. "tdb_open: %s is not a tdb file", name);
  273. goto fail;
  274. }
  275. if (hdr.version != TDB_VERSION) {
  276. if (hdr.version == bswap_64(TDB_VERSION))
  277. tdb->flags |= TDB_CONVERT;
  278. else {
  279. /* wrong version */
  280. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  281. "tdb_open:"
  282. " %s is unknown version 0x%llx",
  283. name, (long long)hdr.version);
  284. goto fail;
  285. }
  286. }
  287. tdb_convert(tdb, &hdr, sizeof(hdr));
  288. tdb->hash_seed = hdr.hash_seed;
  289. hash_test = TDB_HASH_MAGIC;
  290. hash_test = tdb_hash(tdb, &hash_test, sizeof(hash_test));
  291. if (hdr.hash_test != hash_test) {
  292. /* wrong hash variant */
  293. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  294. "tdb_open:"
  295. " %s uses a different hash function",
  296. name);
  297. goto fail;
  298. }
  299. if (fstat(tdb->fd, &st) == -1) {
  300. saved_errno = errno;
  301. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  302. "tdb_open: could not stat open %s: %s",
  303. name, strerror(errno));
  304. goto fail;
  305. }
  306. /* Is it already in the open list? If so, fail. */
  307. if (tdb_already_open(st.st_dev, st.st_ino)) {
  308. /* FIXME */
  309. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_USE_ERROR,
  310. "tdb_open: %s (%d,%d) is already open"
  311. " in this process",
  312. name, (int)st.st_dev, (int)st.st_ino);
  313. goto fail;
  314. }
  315. tdb->name = strdup(name);
  316. if (!tdb->name) {
  317. ecode = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
  318. "tdb_open: failed to allocate name");
  319. goto fail;
  320. }
  321. tdb->device = st.st_dev;
  322. tdb->inode = st.st_ino;
  323. tdb_unlock_open(tdb);
  324. /* This make sure we have current map_size and mmap. */
  325. tdb->methods->oob(tdb, tdb->map_size + 1, true);
  326. /* Now it's fully formed, recover if necessary. */
  327. berr = tdb_needs_recovery(tdb);
  328. if (unlikely(berr != false)) {
  329. if (berr < 0) {
  330. ecode = berr;
  331. goto fail;
  332. }
  333. ecode = tdb_lock_and_recover(tdb);
  334. if (ecode != TDB_SUCCESS) {
  335. goto fail;
  336. }
  337. }
  338. ecode = tdb_ftable_init(tdb);
  339. if (ecode != TDB_SUCCESS) {
  340. goto fail;
  341. }
  342. tdb->next = tdbs;
  343. tdbs = tdb;
  344. return tdb;
  345. fail:
  346. /* Map ecode to some logical errno. */
  347. if (!saved_errno) {
  348. switch (ecode) {
  349. case TDB_ERR_CORRUPT:
  350. case TDB_ERR_IO:
  351. saved_errno = EIO;
  352. break;
  353. case TDB_ERR_LOCK:
  354. saved_errno = EWOULDBLOCK;
  355. break;
  356. case TDB_ERR_OOM:
  357. saved_errno = ENOMEM;
  358. break;
  359. case TDB_ERR_EINVAL:
  360. saved_errno = EINVAL;
  361. break;
  362. default:
  363. saved_errno = EINVAL;
  364. break;
  365. }
  366. }
  367. #ifdef TDB_TRACE
  368. close(tdb->tracefd);
  369. #endif
  370. if (tdb->map_ptr) {
  371. if (tdb->flags & TDB_INTERNAL) {
  372. free(tdb->map_ptr);
  373. } else
  374. tdb_munmap(tdb);
  375. }
  376. free(tdb->lockrecs);
  377. free((char *)tdb->name);
  378. if (tdb->fd != -1)
  379. if (close(tdb->fd) != 0)
  380. tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  381. "tdb_open: failed to close tdb->fd"
  382. " on error: %s", strerror(errno));
  383. free(tdb);
  384. errno = saved_errno;
  385. return NULL;
  386. }
  387. static enum TDB_ERROR update_rec_hdr(struct tdb_context *tdb,
  388. tdb_off_t off,
  389. tdb_len_t keylen,
  390. tdb_len_t datalen,
  391. struct tdb_used_record *rec,
  392. uint64_t h)
  393. {
  394. uint64_t dataroom = rec_data_length(rec) + rec_extra_padding(rec);
  395. enum TDB_ERROR ecode;
  396. ecode = set_header(tdb, rec, TDB_USED_MAGIC, keylen, datalen,
  397. keylen + dataroom, h);
  398. if (ecode == TDB_SUCCESS) {
  399. ecode = tdb_write_convert(tdb, off, rec, sizeof(*rec));
  400. }
  401. return ecode;
  402. }
  403. static enum TDB_ERROR replace_data(struct tdb_context *tdb,
  404. struct hash_info *h,
  405. struct tdb_data key, struct tdb_data dbuf,
  406. tdb_off_t old_off, tdb_len_t old_room,
  407. bool growing)
  408. {
  409. tdb_off_t new_off;
  410. enum TDB_ERROR ecode;
  411. /* Allocate a new record. */
  412. new_off = alloc(tdb, key.dsize, dbuf.dsize, h->h, TDB_USED_MAGIC,
  413. growing);
  414. if (TDB_OFF_IS_ERR(new_off)) {
  415. return new_off;
  416. }
  417. /* We didn't like the existing one: remove it. */
  418. if (old_off) {
  419. add_stat(tdb, frees, 1);
  420. ecode = add_free_record(tdb, old_off,
  421. sizeof(struct tdb_used_record)
  422. + key.dsize + old_room);
  423. if (ecode == TDB_SUCCESS)
  424. ecode = replace_in_hash(tdb, h, new_off);
  425. } else {
  426. ecode = add_to_hash(tdb, h, new_off);
  427. }
  428. if (ecode != TDB_SUCCESS) {
  429. return ecode;
  430. }
  431. new_off += sizeof(struct tdb_used_record);
  432. ecode = tdb->methods->twrite(tdb, new_off, key.dptr, key.dsize);
  433. if (ecode != TDB_SUCCESS) {
  434. return ecode;
  435. }
  436. new_off += key.dsize;
  437. ecode = tdb->methods->twrite(tdb, new_off, dbuf.dptr, dbuf.dsize);
  438. if (ecode != TDB_SUCCESS) {
  439. return ecode;
  440. }
  441. /* FIXME: tdb_increment_seqnum(tdb); */
  442. return TDB_SUCCESS;
  443. }
  444. enum TDB_ERROR tdb_store(struct tdb_context *tdb,
  445. struct tdb_data key, struct tdb_data dbuf, int flag)
  446. {
  447. struct hash_info h;
  448. tdb_off_t off;
  449. tdb_len_t old_room = 0;
  450. struct tdb_used_record rec;
  451. enum TDB_ERROR ecode;
  452. off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
  453. if (TDB_OFF_IS_ERR(off)) {
  454. return off;
  455. }
  456. /* Now we have lock on this hash bucket. */
  457. if (flag == TDB_INSERT) {
  458. if (off) {
  459. ecode = TDB_ERR_EXISTS;
  460. goto out;
  461. }
  462. } else {
  463. if (off) {
  464. old_room = rec_data_length(&rec)
  465. + rec_extra_padding(&rec);
  466. if (old_room >= dbuf.dsize) {
  467. /* Can modify in-place. Easy! */
  468. ecode = update_rec_hdr(tdb, off,
  469. key.dsize, dbuf.dsize,
  470. &rec, h.h);
  471. if (ecode != TDB_SUCCESS) {
  472. goto out;
  473. }
  474. ecode = tdb->methods->twrite(tdb,
  475. off + sizeof(rec)
  476. + key.dsize,
  477. dbuf.dptr,
  478. dbuf.dsize);
  479. if (ecode != TDB_SUCCESS) {
  480. goto out;
  481. }
  482. tdb_unlock_hashes(tdb, h.hlock_start,
  483. h.hlock_range, F_WRLCK);
  484. return TDB_SUCCESS;
  485. }
  486. } else {
  487. if (flag == TDB_MODIFY) {
  488. /* if the record doesn't exist and we
  489. are in TDB_MODIFY mode then we should fail
  490. the store */
  491. ecode = TDB_ERR_NOEXIST;
  492. goto out;
  493. }
  494. }
  495. }
  496. /* If we didn't use the old record, this implies we're growing. */
  497. ecode = replace_data(tdb, &h, key, dbuf, off, old_room, off);
  498. out:
  499. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
  500. return ecode;
  501. }
  502. enum TDB_ERROR tdb_append(struct tdb_context *tdb,
  503. struct tdb_data key, struct tdb_data dbuf)
  504. {
  505. struct hash_info h;
  506. tdb_off_t off;
  507. struct tdb_used_record rec;
  508. tdb_len_t old_room = 0, old_dlen;
  509. unsigned char *newdata;
  510. struct tdb_data new_dbuf;
  511. enum TDB_ERROR ecode;
  512. off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
  513. if (TDB_OFF_IS_ERR(off)) {
  514. return off;
  515. }
  516. if (off) {
  517. old_dlen = rec_data_length(&rec);
  518. old_room = old_dlen + rec_extra_padding(&rec);
  519. /* Fast path: can append in place. */
  520. if (rec_extra_padding(&rec) >= dbuf.dsize) {
  521. ecode = update_rec_hdr(tdb, off, key.dsize,
  522. old_dlen + dbuf.dsize, &rec,
  523. h.h);
  524. if (ecode != TDB_SUCCESS) {
  525. goto out;
  526. }
  527. off += sizeof(rec) + key.dsize + old_dlen;
  528. ecode = tdb->methods->twrite(tdb, off, dbuf.dptr,
  529. dbuf.dsize);
  530. goto out;
  531. }
  532. /* Slow path. */
  533. newdata = malloc(key.dsize + old_dlen + dbuf.dsize);
  534. if (!newdata) {
  535. ecode = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
  536. "tdb_append:"
  537. " failed to allocate %zu bytes",
  538. (size_t)(key.dsize + old_dlen
  539. + dbuf.dsize));
  540. goto out;
  541. }
  542. ecode = tdb->methods->tread(tdb, off + sizeof(rec) + key.dsize,
  543. newdata, old_dlen);
  544. if (ecode != TDB_SUCCESS) {
  545. goto out_free_newdata;
  546. }
  547. memcpy(newdata + old_dlen, dbuf.dptr, dbuf.dsize);
  548. new_dbuf.dptr = newdata;
  549. new_dbuf.dsize = old_dlen + dbuf.dsize;
  550. } else {
  551. newdata = NULL;
  552. new_dbuf = dbuf;
  553. }
  554. /* If they're using tdb_append(), it implies they're growing record. */
  555. ecode = replace_data(tdb, &h, key, new_dbuf, off, old_room, true);
  556. out_free_newdata:
  557. free(newdata);
  558. out:
  559. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
  560. return ecode;
  561. }
  562. enum TDB_ERROR tdb_fetch(struct tdb_context *tdb, struct tdb_data key,
  563. struct tdb_data *data)
  564. {
  565. tdb_off_t off;
  566. struct tdb_used_record rec;
  567. struct hash_info h;
  568. enum TDB_ERROR ecode;
  569. off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL);
  570. if (TDB_OFF_IS_ERR(off)) {
  571. return off;
  572. }
  573. if (!off) {
  574. ecode = TDB_ERR_NOEXIST;
  575. } else {
  576. data->dsize = rec_data_length(&rec);
  577. data->dptr = tdb_alloc_read(tdb, off + sizeof(rec) + key.dsize,
  578. data->dsize);
  579. if (TDB_PTR_IS_ERR(data->dptr)) {
  580. ecode = TDB_PTR_ERR(data->dptr);
  581. } else
  582. ecode = TDB_SUCCESS;
  583. }
  584. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK);
  585. return ecode;
  586. }
  587. enum TDB_ERROR tdb_delete(struct tdb_context *tdb, struct tdb_data key)
  588. {
  589. tdb_off_t off;
  590. struct tdb_used_record rec;
  591. struct hash_info h;
  592. enum TDB_ERROR ecode;
  593. off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
  594. if (TDB_OFF_IS_ERR(off)) {
  595. return off;
  596. }
  597. if (!off) {
  598. ecode = TDB_ERR_NOEXIST;
  599. goto unlock;
  600. }
  601. ecode = delete_from_hash(tdb, &h);
  602. if (ecode != TDB_SUCCESS) {
  603. goto unlock;
  604. }
  605. /* Free the deleted entry. */
  606. add_stat(tdb, frees, 1);
  607. ecode = add_free_record(tdb, off,
  608. sizeof(struct tdb_used_record)
  609. + rec_key_length(&rec)
  610. + rec_data_length(&rec)
  611. + rec_extra_padding(&rec));
  612. unlock:
  613. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
  614. return ecode;
  615. }
  616. int tdb_close(struct tdb_context *tdb)
  617. {
  618. struct tdb_context **i;
  619. int ret = 0;
  620. tdb_trace(tdb, "tdb_close");
  621. if (tdb->transaction) {
  622. tdb_transaction_cancel(tdb);
  623. }
  624. if (tdb->map_ptr) {
  625. if (tdb->flags & TDB_INTERNAL)
  626. free(tdb->map_ptr);
  627. else
  628. tdb_munmap(tdb);
  629. }
  630. free((char *)tdb->name);
  631. if (tdb->fd != -1) {
  632. ret = close(tdb->fd);
  633. tdb->fd = -1;
  634. }
  635. free(tdb->lockrecs);
  636. /* Remove from contexts list */
  637. for (i = &tdbs; *i; i = &(*i)->next) {
  638. if (*i == tdb) {
  639. *i = tdb->next;
  640. break;
  641. }
  642. }
  643. #ifdef TDB_TRACE
  644. close(tdb->tracefd);
  645. #endif
  646. free(tdb);
  647. return ret;
  648. }
  649. const char *tdb_errorstr(enum TDB_ERROR ecode)
  650. {
  651. /* Gcc warns if you miss a case in the switch, so use that. */
  652. switch (ecode) {
  653. case TDB_SUCCESS: return "Success";
  654. case TDB_ERR_CORRUPT: return "Corrupt database";
  655. case TDB_ERR_IO: return "IO Error";
  656. case TDB_ERR_LOCK: return "Locking error";
  657. case TDB_ERR_OOM: return "Out of memory";
  658. case TDB_ERR_EXISTS: return "Record exists";
  659. case TDB_ERR_EINVAL: return "Invalid parameter";
  660. case TDB_ERR_NOEXIST: return "Record does not exist";
  661. case TDB_ERR_RDONLY: return "write not permitted";
  662. }
  663. return "Invalid error code";
  664. }
  665. enum TDB_ERROR COLD tdb_logerr(struct tdb_context *tdb,
  666. enum TDB_ERROR ecode,
  667. enum tdb_log_level level,
  668. const char *fmt, ...)
  669. {
  670. char *message;
  671. va_list ap;
  672. size_t len;
  673. /* tdb_open paths care about errno, so save it. */
  674. int saved_errno = errno;
  675. if (!tdb->logfn)
  676. return ecode;
  677. /* FIXME: Doesn't assume asprintf. */
  678. va_start(ap, fmt);
  679. len = vsnprintf(NULL, 0, fmt, ap);
  680. va_end(ap);
  681. message = malloc(len + 1);
  682. if (!message) {
  683. tdb->logfn(tdb, TDB_LOG_ERROR, tdb->log_private,
  684. "out of memory formatting message:");
  685. tdb->logfn(tdb, level, tdb->log_private, fmt);
  686. return ecode;
  687. }
  688. va_start(ap, fmt);
  689. len = vsprintf(message, fmt, ap);
  690. va_end(ap);
  691. tdb->logfn(tdb, level, tdb->log_private, message);
  692. free(message);
  693. errno = saved_errno;
  694. return ecode;
  695. }