open.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. /*
  2. Trivial Database 2: opening and closing TDBs
  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. #include <ccan/hash/hash.h>
  17. #include <assert.h>
  18. /* all lock info, to detect double-opens (fcntl file don't nest!) */
  19. static struct tdb_file *files = NULL;
  20. static struct tdb_file *find_file(dev_t device, ino_t ino)
  21. {
  22. struct tdb_file *i;
  23. for (i = files; i; i = i->next) {
  24. if (i->device == device && i->inode == ino) {
  25. i->refcnt++;
  26. break;
  27. }
  28. }
  29. return i;
  30. }
  31. static bool read_all(int fd, void *buf, size_t len)
  32. {
  33. while (len) {
  34. ssize_t ret;
  35. ret = read(fd, buf, len);
  36. if (ret < 0)
  37. return false;
  38. if (ret == 0) {
  39. /* ETOOSHORT? */
  40. errno = EWOULDBLOCK;
  41. return false;
  42. }
  43. buf = (char *)buf + ret;
  44. len -= ret;
  45. }
  46. return true;
  47. }
  48. static uint64_t random_number(struct tdb_context *tdb)
  49. {
  50. int fd;
  51. uint64_t ret = 0;
  52. struct timeval now;
  53. fd = open("/dev/urandom", O_RDONLY);
  54. if (fd >= 0) {
  55. if (read_all(fd, &ret, sizeof(ret))) {
  56. close(fd);
  57. return ret;
  58. }
  59. close(fd);
  60. }
  61. /* FIXME: Untested! Based on Wikipedia protocol description! */
  62. fd = open("/dev/egd-pool", O_RDWR);
  63. if (fd >= 0) {
  64. /* Command is 1, next byte is size we want to read. */
  65. char cmd[2] = { 1, sizeof(uint64_t) };
  66. if (write(fd, cmd, sizeof(cmd)) == sizeof(cmd)) {
  67. char reply[1 + sizeof(uint64_t)];
  68. int r = read(fd, reply, sizeof(reply));
  69. if (r > 1) {
  70. /* Copy at least some bytes. */
  71. memcpy(&ret, reply+1, r - 1);
  72. if (reply[0] == sizeof(uint64_t)
  73. && r == sizeof(reply)) {
  74. close(fd);
  75. return ret;
  76. }
  77. }
  78. }
  79. close(fd);
  80. }
  81. /* Fallback: pid and time. */
  82. gettimeofday(&now, NULL);
  83. ret = getpid() * 100132289ULL + now.tv_sec * 1000000ULL + now.tv_usec;
  84. tdb_logerr(tdb, TDB_SUCCESS, TDB_LOG_WARNING,
  85. "tdb_open: random from getpid and time");
  86. return ret;
  87. }
  88. struct new_database {
  89. struct tdb_header hdr;
  90. struct tdb_freetable ftable;
  91. };
  92. /* initialise a new database */
  93. static enum TDB_ERROR tdb_new_database(struct tdb_context *tdb,
  94. struct tdb_attribute_seed *seed,
  95. struct tdb_header *hdr)
  96. {
  97. /* We make it up in memory, then write it out if not internal */
  98. struct new_database newdb;
  99. unsigned int magic_len;
  100. ssize_t rlen;
  101. enum TDB_ERROR ecode;
  102. /* Fill in the header */
  103. newdb.hdr.version = TDB_VERSION;
  104. if (seed)
  105. newdb.hdr.hash_seed = seed->seed;
  106. else
  107. newdb.hdr.hash_seed = random_number(tdb);
  108. newdb.hdr.hash_test = TDB_HASH_MAGIC;
  109. newdb.hdr.hash_test = tdb->hash_fn(&newdb.hdr.hash_test,
  110. sizeof(newdb.hdr.hash_test),
  111. newdb.hdr.hash_seed,
  112. tdb->hash_data);
  113. newdb.hdr.recovery = 0;
  114. newdb.hdr.features_used = newdb.hdr.features_offered = TDB_FEATURE_MASK;
  115. newdb.hdr.seqnum = 0;
  116. memset(newdb.hdr.reserved, 0, sizeof(newdb.hdr.reserved));
  117. /* Initial hashes are empty. */
  118. memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable));
  119. /* Free is empty. */
  120. newdb.hdr.free_table = offsetof(struct new_database, ftable);
  121. memset(&newdb.ftable, 0, sizeof(newdb.ftable));
  122. ecode = set_header(NULL, &newdb.ftable.hdr, TDB_FTABLE_MAGIC, 0,
  123. sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr),
  124. sizeof(newdb.ftable) - sizeof(newdb.ftable.hdr),
  125. 0);
  126. if (ecode != TDB_SUCCESS) {
  127. return ecode;
  128. }
  129. /* Magic food */
  130. memset(newdb.hdr.magic_food, 0, sizeof(newdb.hdr.magic_food));
  131. strcpy(newdb.hdr.magic_food, TDB_MAGIC_FOOD);
  132. /* This creates an endian-converted database, as if read from disk */
  133. magic_len = sizeof(newdb.hdr.magic_food);
  134. tdb_convert(tdb,
  135. (char *)&newdb.hdr + magic_len, sizeof(newdb) - magic_len);
  136. *hdr = newdb.hdr;
  137. if (tdb->flags & TDB_INTERNAL) {
  138. tdb->file->map_size = sizeof(newdb);
  139. tdb->file->map_ptr = malloc(tdb->file->map_size);
  140. if (!tdb->file->map_ptr) {
  141. return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
  142. "tdb_new_database:"
  143. " failed to allocate");
  144. }
  145. memcpy(tdb->file->map_ptr, &newdb, tdb->file->map_size);
  146. return TDB_SUCCESS;
  147. }
  148. if (lseek(tdb->file->fd, 0, SEEK_SET) == -1) {
  149. return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  150. "tdb_new_database:"
  151. " failed to seek: %s", strerror(errno));
  152. }
  153. if (ftruncate(tdb->file->fd, 0) == -1) {
  154. return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  155. "tdb_new_database:"
  156. " failed to truncate: %s", strerror(errno));
  157. }
  158. rlen = write(tdb->file->fd, &newdb, sizeof(newdb));
  159. if (rlen != sizeof(newdb)) {
  160. if (rlen >= 0)
  161. errno = ENOSPC;
  162. return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  163. "tdb_new_database: %zi writing header: %s",
  164. rlen, strerror(errno));
  165. }
  166. return TDB_SUCCESS;
  167. }
  168. static enum TDB_ERROR tdb_new_file(struct tdb_context *tdb)
  169. {
  170. tdb->file = malloc(sizeof(*tdb->file));
  171. if (!tdb->file)
  172. return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
  173. "tdb_open: cannot alloc tdb_file structure");
  174. tdb->file->num_lockrecs = 0;
  175. tdb->file->lockrecs = NULL;
  176. tdb->file->allrecord_lock.count = 0;
  177. tdb->file->refcnt = 1;
  178. return TDB_SUCCESS;
  179. }
  180. enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb,
  181. const union tdb_attribute *attr)
  182. {
  183. switch (attr->base.attr) {
  184. case TDB_ATTRIBUTE_LOG:
  185. tdb->log_fn = attr->log.fn;
  186. tdb->log_data = attr->log.data;
  187. break;
  188. case TDB_ATTRIBUTE_HASH:
  189. case TDB_ATTRIBUTE_SEED:
  190. case TDB_ATTRIBUTE_OPENHOOK:
  191. return tdb->last_error
  192. = tdb_logerr(tdb, TDB_ERR_EINVAL,
  193. TDB_LOG_USE_ERROR,
  194. "tdb_set_attribute:"
  195. " cannot set %s after opening",
  196. attr->base.attr == TDB_ATTRIBUTE_HASH
  197. ? "TDB_ATTRIBUTE_HASH"
  198. : attr->base.attr == TDB_ATTRIBUTE_SEED
  199. ? "TDB_ATTRIBUTE_SEED"
  200. : "TDB_ATTRIBUTE_OPENHOOK");
  201. case TDB_ATTRIBUTE_STATS:
  202. return tdb->last_error
  203. = tdb_logerr(tdb, TDB_ERR_EINVAL,
  204. TDB_LOG_USE_ERROR,
  205. "tdb_set_attribute:"
  206. " cannot set TDB_ATTRIBUTE_STATS");
  207. case TDB_ATTRIBUTE_FLOCK:
  208. tdb->lock_fn = attr->flock.lock;
  209. tdb->unlock_fn = attr->flock.unlock;
  210. tdb->lock_data = attr->flock.data;
  211. break;
  212. default:
  213. return tdb->last_error
  214. = tdb_logerr(tdb, TDB_ERR_EINVAL,
  215. TDB_LOG_USE_ERROR,
  216. "tdb_set_attribute:"
  217. " unknown attribute type %u",
  218. attr->base.attr);
  219. }
  220. return TDB_SUCCESS;
  221. }
  222. static uint64_t jenkins_hash(const void *key, size_t length, uint64_t seed,
  223. void *unused)
  224. {
  225. uint64_t ret;
  226. /* hash64_stable assumes lower bits are more important; they are a
  227. * slightly better hash. We use the upper bits first, so swap them. */
  228. ret = hash64_stable((const unsigned char *)key, length, seed);
  229. return (ret >> 32) | (ret << 32);
  230. }
  231. enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
  232. union tdb_attribute *attr)
  233. {
  234. switch (attr->base.attr) {
  235. case TDB_ATTRIBUTE_LOG:
  236. if (!tdb->log_fn)
  237. return tdb->last_error = TDB_ERR_NOEXIST;
  238. attr->log.fn = tdb->log_fn;
  239. attr->log.data = tdb->log_data;
  240. break;
  241. case TDB_ATTRIBUTE_HASH:
  242. attr->hash.fn = tdb->hash_fn;
  243. attr->hash.data = tdb->hash_data;
  244. break;
  245. case TDB_ATTRIBUTE_SEED:
  246. attr->seed.seed = tdb->hash_seed;
  247. break;
  248. case TDB_ATTRIBUTE_OPENHOOK:
  249. return tdb->last_error
  250. = tdb_logerr(tdb, TDB_ERR_EINVAL,
  251. TDB_LOG_USE_ERROR,
  252. "tdb_get_attribute:"
  253. " cannot get TDB_ATTRIBUTE_OPENHOOK");
  254. case TDB_ATTRIBUTE_STATS: {
  255. size_t size = attr->stats.size;
  256. if (size > tdb->stats.size)
  257. size = tdb->stats.size;
  258. memcpy(&attr->stats, &tdb->stats, size);
  259. break;
  260. }
  261. case TDB_ATTRIBUTE_FLOCK:
  262. attr->flock.lock = tdb->lock_fn;
  263. attr->flock.unlock = tdb->unlock_fn;
  264. attr->flock.data = tdb->lock_data;
  265. break;
  266. default:
  267. return tdb->last_error
  268. = tdb_logerr(tdb, TDB_ERR_EINVAL,
  269. TDB_LOG_USE_ERROR,
  270. "tdb_get_attribute:"
  271. " unknown attribute type %u",
  272. attr->base.attr);
  273. }
  274. attr->base.next = NULL;
  275. return TDB_SUCCESS;
  276. }
  277. void tdb_unset_attribute(struct tdb_context *tdb,
  278. enum tdb_attribute_type type)
  279. {
  280. switch (type) {
  281. case TDB_ATTRIBUTE_LOG:
  282. tdb->log_fn = NULL;
  283. break;
  284. case TDB_ATTRIBUTE_HASH:
  285. case TDB_ATTRIBUTE_SEED:
  286. case TDB_ATTRIBUTE_OPENHOOK:
  287. tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
  288. "tdb_unset_attribute: cannot unset %s after opening",
  289. type == TDB_ATTRIBUTE_HASH
  290. ? "TDB_ATTRIBUTE_HASH"
  291. : type == TDB_ATTRIBUTE_SEED
  292. ? "TDB_ATTRIBUTE_SEED"
  293. : "TDB_ATTRIBUTE_OPENHOOK");
  294. break;
  295. case TDB_ATTRIBUTE_STATS:
  296. tdb_logerr(tdb, TDB_ERR_EINVAL,
  297. TDB_LOG_USE_ERROR,
  298. "tdb_unset_attribute:"
  299. "cannot unset TDB_ATTRIBUTE_STATS");
  300. break;
  301. case TDB_ATTRIBUTE_FLOCK:
  302. tdb->lock_fn = tdb_fcntl_lock;
  303. tdb->unlock_fn = tdb_fcntl_unlock;
  304. break;
  305. default:
  306. tdb_logerr(tdb, TDB_ERR_EINVAL,
  307. TDB_LOG_USE_ERROR,
  308. "tdb_unset_attribute: unknown attribute type %u",
  309. type);
  310. }
  311. }
  312. struct tdb_context *tdb_open(const char *name, int tdb_flags,
  313. int open_flags, mode_t mode,
  314. union tdb_attribute *attr)
  315. {
  316. struct tdb_context *tdb;
  317. struct stat st;
  318. int saved_errno = 0;
  319. uint64_t hash_test;
  320. unsigned v;
  321. ssize_t rlen;
  322. struct tdb_header hdr;
  323. struct tdb_attribute_seed *seed = NULL;
  324. struct tdb_attribute_openhook *openhook = NULL;
  325. tdb_bool_err berr;
  326. enum TDB_ERROR ecode;
  327. int openlock;
  328. tdb = malloc(sizeof(*tdb) + (name ? strlen(name) + 1 : 0));
  329. if (!tdb) {
  330. /* Can't log this */
  331. errno = ENOMEM;
  332. return NULL;
  333. }
  334. /* Set name immediately for logging functions. */
  335. if (name) {
  336. tdb->name = strcpy((char *)(tdb + 1), name);
  337. } else {
  338. tdb->name = NULL;
  339. }
  340. tdb->direct_access = 0;
  341. tdb->flags = tdb_flags;
  342. tdb->log_fn = NULL;
  343. tdb->transaction = NULL;
  344. tdb->access = NULL;
  345. tdb->last_error = TDB_SUCCESS;
  346. tdb->file = NULL;
  347. tdb->lock_fn = tdb_fcntl_lock;
  348. tdb->unlock_fn = tdb_fcntl_unlock;
  349. tdb->hash_fn = jenkins_hash;
  350. memset(&tdb->stats, 0, sizeof(tdb->stats));
  351. tdb->stats.base.attr = TDB_ATTRIBUTE_STATS;
  352. tdb->stats.size = sizeof(tdb->stats);
  353. tdb_io_init(tdb);
  354. while (attr) {
  355. switch (attr->base.attr) {
  356. case TDB_ATTRIBUTE_HASH:
  357. tdb->hash_fn = attr->hash.fn;
  358. tdb->hash_data = attr->hash.data;
  359. break;
  360. case TDB_ATTRIBUTE_SEED:
  361. seed = &attr->seed;
  362. break;
  363. case TDB_ATTRIBUTE_OPENHOOK:
  364. openhook = &attr->openhook;
  365. break;
  366. default:
  367. /* These are set as normal. */
  368. ecode = tdb_set_attribute(tdb, attr);
  369. if (ecode != TDB_SUCCESS)
  370. goto fail;
  371. }
  372. attr = attr->base.next;
  373. }
  374. if (tdb_flags & ~(TDB_INTERNAL | TDB_NOLOCK | TDB_NOMMAP | TDB_CONVERT
  375. | TDB_NOSYNC | TDB_SEQNUM | TDB_ALLOW_NESTING)) {
  376. ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
  377. "tdb_open: unknown flags %u", tdb_flags);
  378. goto fail;
  379. }
  380. if ((open_flags & O_ACCMODE) == O_WRONLY) {
  381. ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
  382. "tdb_open: can't open tdb %s write-only",
  383. name);
  384. goto fail;
  385. }
  386. if ((open_flags & O_ACCMODE) == O_RDONLY) {
  387. tdb->read_only = true;
  388. tdb->mmap_flags = PROT_READ;
  389. openlock = F_RDLCK;
  390. } else {
  391. tdb->read_only = false;
  392. tdb->mmap_flags = PROT_READ | PROT_WRITE;
  393. openlock = F_WRLCK;
  394. }
  395. /* internal databases don't need any of the rest. */
  396. if (tdb->flags & TDB_INTERNAL) {
  397. tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
  398. ecode = tdb_new_file(tdb);
  399. if (ecode != TDB_SUCCESS) {
  400. goto fail;
  401. }
  402. tdb->file->fd = -1;
  403. ecode = tdb_new_database(tdb, seed, &hdr);
  404. if (ecode != TDB_SUCCESS) {
  405. goto fail;
  406. }
  407. tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed));
  408. tdb->hash_seed = hdr.hash_seed;
  409. tdb_ftable_init(tdb);
  410. return tdb;
  411. }
  412. if (stat(name, &st) != -1)
  413. tdb->file = find_file(st.st_dev, st.st_ino);
  414. if (!tdb->file) {
  415. int fd;
  416. if ((fd = open(name, open_flags, mode)) == -1) {
  417. /* errno set by open(2) */
  418. saved_errno = errno;
  419. tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  420. "tdb_open: could not open file %s: %s",
  421. name, strerror(errno));
  422. goto fail_errno;
  423. }
  424. /* on exec, don't inherit the fd */
  425. v = fcntl(fd, F_GETFD, 0);
  426. fcntl(fd, F_SETFD, v | FD_CLOEXEC);
  427. if (fstat(fd, &st) == -1) {
  428. saved_errno = errno;
  429. tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  430. "tdb_open: could not stat open %s: %s",
  431. name, strerror(errno));
  432. close(fd);
  433. goto fail_errno;
  434. }
  435. ecode = tdb_new_file(tdb);
  436. if (ecode != TDB_SUCCESS) {
  437. close(fd);
  438. goto fail;
  439. }
  440. tdb->file->next = files;
  441. tdb->file->fd = fd;
  442. tdb->file->device = st.st_dev;
  443. tdb->file->inode = st.st_ino;
  444. tdb->file->map_ptr = NULL;
  445. tdb->file->map_size = sizeof(struct tdb_header);
  446. }
  447. /* ensure there is only one process initialising at once */
  448. ecode = tdb_lock_open(tdb, openlock, TDB_LOCK_WAIT|TDB_LOCK_NOCHECK);
  449. if (ecode != TDB_SUCCESS) {
  450. saved_errno = errno;
  451. goto fail_errno;
  452. }
  453. /* call their open hook if they gave us one. */
  454. if (openhook) {
  455. ecode = openhook->fn(tdb->file->fd, openhook->data);
  456. if (ecode != TDB_SUCCESS) {
  457. tdb_logerr(tdb, ecode, TDB_LOG_ERROR,
  458. "tdb_open: open hook failed");
  459. goto fail;
  460. }
  461. open_flags |= O_CREAT;
  462. }
  463. /* If they used O_TRUNC, read will return 0. */
  464. rlen = pread(tdb->file->fd, &hdr, sizeof(hdr), 0);
  465. if (rlen == 0 && (open_flags & O_CREAT)) {
  466. ecode = tdb_new_database(tdb, seed, &hdr);
  467. if (ecode != TDB_SUCCESS) {
  468. goto fail;
  469. }
  470. } else if (rlen < 0) {
  471. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  472. "tdb_open: error %s reading %s",
  473. strerror(errno), name);
  474. goto fail;
  475. } else if (rlen < sizeof(hdr)
  476. || strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) {
  477. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  478. "tdb_open: %s is not a tdb file", name);
  479. goto fail;
  480. }
  481. if (hdr.version != TDB_VERSION) {
  482. if (hdr.version == bswap_64(TDB_VERSION))
  483. tdb->flags |= TDB_CONVERT;
  484. else {
  485. /* wrong version */
  486. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  487. "tdb_open:"
  488. " %s is unknown version 0x%llx",
  489. name, (long long)hdr.version);
  490. goto fail;
  491. }
  492. }
  493. tdb_convert(tdb, &hdr, sizeof(hdr));
  494. tdb->hash_seed = hdr.hash_seed;
  495. hash_test = TDB_HASH_MAGIC;
  496. hash_test = tdb_hash(tdb, &hash_test, sizeof(hash_test));
  497. if (hdr.hash_test != hash_test) {
  498. /* wrong hash variant */
  499. ecode = tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  500. "tdb_open:"
  501. " %s uses a different hash function",
  502. name);
  503. goto fail;
  504. }
  505. /* Clear any features we don't understand. */
  506. if ((open_flags & O_ACCMODE) != O_RDONLY) {
  507. hdr.features_used &= TDB_FEATURE_MASK;
  508. ecode = tdb_write_convert(tdb, offsetof(struct tdb_header,
  509. features_used),
  510. &hdr.features_used,
  511. sizeof(hdr.features_used));
  512. if (ecode != TDB_SUCCESS)
  513. goto fail;
  514. }
  515. tdb_unlock_open(tdb, openlock);
  516. /* This make sure we have current map_size and mmap. */
  517. ecode = tdb->methods->oob(tdb, tdb->file->map_size + 1, true);
  518. if (unlikely(ecode != TDB_SUCCESS))
  519. goto fail;
  520. /* Now it's fully formed, recover if necessary. */
  521. berr = tdb_needs_recovery(tdb);
  522. if (unlikely(berr != false)) {
  523. if (berr < 0) {
  524. ecode = berr;
  525. goto fail;
  526. }
  527. ecode = tdb_lock_and_recover(tdb);
  528. if (ecode != TDB_SUCCESS) {
  529. goto fail;
  530. }
  531. }
  532. ecode = tdb_ftable_init(tdb);
  533. if (ecode != TDB_SUCCESS) {
  534. goto fail;
  535. }
  536. /* Add to linked list if we're new. */
  537. if (tdb->file->refcnt == 1)
  538. files = tdb->file;
  539. return tdb;
  540. fail:
  541. /* Map ecode to some logical errno. */
  542. switch (ecode) {
  543. case TDB_ERR_CORRUPT:
  544. case TDB_ERR_IO:
  545. saved_errno = EIO;
  546. break;
  547. case TDB_ERR_LOCK:
  548. saved_errno = EWOULDBLOCK;
  549. break;
  550. case TDB_ERR_OOM:
  551. saved_errno = ENOMEM;
  552. break;
  553. case TDB_ERR_EINVAL:
  554. saved_errno = EINVAL;
  555. break;
  556. default:
  557. saved_errno = EINVAL;
  558. break;
  559. }
  560. fail_errno:
  561. #ifdef TDB_TRACE
  562. close(tdb->tracefd);
  563. #endif
  564. if (tdb->file) {
  565. tdb_lock_cleanup(tdb);
  566. if (--tdb->file->refcnt == 0) {
  567. assert(tdb->file->num_lockrecs == 0);
  568. if (tdb->file->map_ptr) {
  569. if (tdb->flags & TDB_INTERNAL) {
  570. free(tdb->file->map_ptr);
  571. } else
  572. tdb_munmap(tdb->file);
  573. }
  574. if (close(tdb->file->fd) != 0)
  575. tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
  576. "tdb_open: failed to close tdb fd"
  577. " on error: %s", strerror(errno));
  578. free(tdb->file->lockrecs);
  579. free(tdb->file);
  580. }
  581. }
  582. free(tdb);
  583. errno = saved_errno;
  584. return NULL;
  585. }
  586. int tdb_close(struct tdb_context *tdb)
  587. {
  588. int ret = 0;
  589. tdb_trace(tdb, "tdb_close");
  590. if (tdb->transaction) {
  591. tdb_transaction_cancel(tdb);
  592. }
  593. if (tdb->file->map_ptr) {
  594. if (tdb->flags & TDB_INTERNAL)
  595. free(tdb->file->map_ptr);
  596. else
  597. tdb_munmap(tdb->file);
  598. }
  599. if (tdb->file) {
  600. struct tdb_file **i;
  601. tdb_lock_cleanup(tdb);
  602. if (--tdb->file->refcnt == 0) {
  603. ret = close(tdb->file->fd);
  604. /* Remove from files list */
  605. for (i = &files; *i; i = &(*i)->next) {
  606. if (*i == tdb->file) {
  607. *i = tdb->file->next;
  608. break;
  609. }
  610. }
  611. free(tdb->file->lockrecs);
  612. free(tdb->file);
  613. }
  614. }
  615. #ifdef TDB_TRACE
  616. close(tdb->tracefd);
  617. #endif
  618. free(tdb);
  619. return ret;
  620. }