open.c 19 KB

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