sqliterk_pager.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /*
  2. * Tencent is pleased to support the open source community by making
  3. * WCDB available.
  4. *
  5. * Copyright (C) 2017 THL A29 Limited, a Tencent company.
  6. * All rights reserved.
  7. *
  8. * Licensed under the BSD 3-Clause License (the "License"); you may not use
  9. * this file except in compliance with the License. You may obtain a copy of
  10. * the License at
  11. *
  12. * https://opensource.org/licenses/BSD-3-Clause
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. #include "sqliterk_pager.h"
  21. #include "SQLiteRepairKit.h"
  22. #include "sqliterk_crypto.h"
  23. #include "sqliterk_os.h"
  24. #include "sqliterk_util.h"
  25. #include <errno.h>
  26. #include <string.h>
  27. static int sqliterkPagerParseHeader(sqliterk_pager *pager, int forcePageSize);
  28. static int sqliterkPageAcquireOne(sqliterk_pager *pager,
  29. int pageno,
  30. sqliterk_page **page,
  31. sqliterk_page_type type);
  32. struct sqliterk_page {
  33. int pageno;
  34. unsigned char *data; // page data
  35. sqliterk_page_type type;
  36. };
  37. int sqliterkPagerOpen(const char *path,
  38. const sqliterk_cipher_conf *cipher,
  39. sqliterk_pager **pager)
  40. {
  41. // Workaround page size cannot be specified for plain-text
  42. // databases. For that case, pass non-null cipher_conf with
  43. // null key and non-zero page size.
  44. int forcePageSize = 0;
  45. if (cipher && !cipher->key) {
  46. forcePageSize = cipher->page_size;
  47. cipher = NULL;
  48. }
  49. if (!pager) {
  50. return SQLITERK_MISUSE;
  51. }
  52. int rc = SQLITERK_OK;
  53. sqliterk_pager *thePager = sqliterkOSMalloc(sizeof(sqliterk_pager));
  54. if (!thePager) {
  55. rc = SQLITERK_NOMEM;
  56. sqliterkOSError(rc, "Not enough memory, required %zu bytes.",
  57. sizeof(sqliterk_pager));
  58. goto sqliterkPagerOpen_Failed;
  59. }
  60. rc = sqliterkOSReadOnlyOpen(path, &thePager->file);
  61. if (rc != SQLITERK_OK) {
  62. goto sqliterkPagerOpen_Failed;
  63. }
  64. if (cipher) {
  65. // Try KDF salt in SQLite file first.
  66. sqliterk_cipher_conf c;
  67. memcpy(&c, cipher, sizeof(c));
  68. c.kdf_salt = NULL;
  69. rc = sqliterkCryptoSetCipher(thePager, thePager->file, &c);
  70. if (rc != SQLITERK_OK)
  71. goto sqliterkPagerOpen_Failed;
  72. // Try parsing header.
  73. sqliterkPagerParseHeader(thePager, 0);
  74. if (thePager->integrity & SQLITERK_INTEGRITY_HEADER) {
  75. // If header is parsed successfully, original KDF salt is also correct.
  76. thePager->integrity |= SQLITERK_INTEGRITY_KDF_SALT;
  77. } else if (cipher->kdf_salt) {
  78. // If anything goes wrong, use KDF salt specified in cipher config.
  79. sqliterkOSWarning(SQLITERK_DAMAGED, "Header cannot be decoded "
  80. "correctly. Trying to apply "
  81. "recovery data.");
  82. rc = sqliterkCryptoSetCipher(thePager, thePager->file, cipher);
  83. if (rc != SQLITERK_OK)
  84. goto sqliterkPagerOpen_Failed;
  85. rc = sqliterkPagerParseHeader(thePager, 0);
  86. if (rc != SQLITERK_OK)
  87. goto sqliterkPagerOpen_Failed;
  88. }
  89. } else {
  90. rc = sqliterkPagerParseHeader(thePager, forcePageSize);
  91. if (rc != SQLITERK_OK)
  92. goto sqliterkPagerOpen_Failed;
  93. // For plain-text databases, just mark KDF salt correct.
  94. if (thePager->integrity & SQLITERK_INTEGRITY_HEADER)
  95. thePager->integrity |= SQLITERK_INTEGRITY_KDF_SALT;
  96. }
  97. if (!(thePager->integrity & SQLITERK_INTEGRITY_HEADER))
  98. sqliterkOSWarning(SQLITERK_DAMAGED, "Header corrupted.");
  99. else
  100. sqliterkOSInfo(SQLITERK_OK, "Header checksum OK.");
  101. int pageCount = thePager->pagecount;
  102. size_t len = sizeof(sqliterk_status) * (pageCount + 1);
  103. thePager->pagesStatus = sqliterkOSMalloc(len);
  104. if (!thePager->pagesStatus) {
  105. rc = SQLITERK_NOMEM;
  106. sqliterkOSError(rc, "Not enough memory, required %zu bytes.", len);
  107. goto sqliterkPagerOpen_Failed;
  108. }
  109. *pager = thePager;
  110. return SQLITERK_OK;
  111. sqliterkPagerOpen_Failed:
  112. if (thePager) {
  113. sqliterkPagerClose(thePager);
  114. }
  115. *pager = NULL;
  116. return rc;
  117. }
  118. // Get the meta from header and set it into pager.
  119. // For further information, see https://www.sqlite.org/fileformat2.html
  120. static int sqliterkPagerParseHeader(sqliterk_pager *pager, int forcePageSize)
  121. {
  122. // For encrypted databases, assume default page size, decode the first
  123. // page, and we have the plain-text header.
  124. if (!pager) {
  125. return SQLITERK_MISUSE;
  126. }
  127. int rc = SQLITERK_OK;
  128. // Overwrite pager page size if forcePageSize is specified.
  129. if (forcePageSize) {
  130. pager->pagesize = forcePageSize;
  131. }
  132. size_t size = pager->codec ? pager->pagesize : 100;
  133. // Read data
  134. unsigned char *buffer = sqliterkOSMalloc(size);
  135. if (!buffer) {
  136. rc = SQLITERK_NOMEM;
  137. sqliterkOSError(rc, "Not enough memory, required %zu bytes.", size);
  138. goto sqliterkPagerParseHeader_End;
  139. }
  140. rc = sqliterkOSRead(pager->file, 0, buffer, &size);
  141. if (rc != SQLITERK_OK) {
  142. if (rc == SQLITERK_SHORT_READ)
  143. sqliterkOSError(rc, "File truncated.");
  144. else
  145. sqliterkOSError(rc, "Cannot read file '%s': %s",
  146. sqliterkOSGetFilePath(pager->file),
  147. strerror(errno));
  148. pager->integrity &= ~SQLITERK_INTEGRITY_HEADER;
  149. goto sqliterkPagerParseHeader_End;
  150. }
  151. pager->integrity |= SQLITERK_INTEGRITY_HEADER;
  152. if (pager->codec) {
  153. rc = sqliterkCryptoDecode(pager->codec, 1, buffer);
  154. if (rc != SQLITERK_OK) {
  155. sqliterkOSWarning(SQLITERK_DAMAGED,
  156. "Failed to decode page 1, header corrupted.");
  157. pager->integrity &= ~SQLITERK_INTEGRITY_HEADER;
  158. }
  159. }
  160. if (pager->integrity & SQLITERK_INTEGRITY_HEADER) {
  161. if (memcmp(buffer, "SQLite format 3\000", 16) == 0) {
  162. //parse pagesize
  163. int pagesize;
  164. sqliterkParseInt(buffer, 16, 2, &pagesize);
  165. if (pager->codec || forcePageSize) {
  166. // Page size is predefined, check whether it matches the header.
  167. if (pagesize != pager->pagesize) {
  168. sqliterkOSWarning(
  169. SQLITERK_DAMAGED,
  170. "Invalid page size: %d expected, %d returned.",
  171. pager->pagesize, pagesize);
  172. pager->integrity &= ~SQLITERK_INTEGRITY_HEADER;
  173. }
  174. } else if (((pagesize - 1) & pagesize) != 0 || pagesize < 512) {
  175. // Page size is not predefined and value in the header is invalid,
  176. // use the default page size.
  177. sqliterkOSWarning(SQLITERK_DAMAGED,
  178. "Page size field is corrupted. Default page "
  179. "size %d is used",
  180. SQLITRK_CONFIG_DEFAULT_PAGESIZE);
  181. pager->pagesize = SQLITRK_CONFIG_DEFAULT_PAGESIZE;
  182. pager->integrity &= ~SQLITERK_INTEGRITY_HEADER;
  183. } else {
  184. // Page size is not predefined and value in the header is valid,
  185. // use the value in header.
  186. pager->pagesize = pagesize;
  187. }
  188. // parse free page count
  189. sqliterkParseInt(buffer, 36, 4, &pager->freepagecount);
  190. // parse reserved bytes
  191. int reservedBytes;
  192. sqliterkParseInt(buffer, 20, 1, &reservedBytes);
  193. if (pager->codec) {
  194. if (reservedBytes != pager->reservedBytes) {
  195. sqliterkOSWarning(SQLITERK_DAMAGED,
  196. "Reserved bytes field doesn't match. %d "
  197. "expected, %d returned.",
  198. pager->reservedBytes, reservedBytes);
  199. pager->integrity &= ~SQLITERK_INTEGRITY_HEADER;
  200. }
  201. } else if (reservedBytes < 0 || reservedBytes > 255) {
  202. sqliterkOSWarning(
  203. SQLITERK_DAMAGED,
  204. "The [reserved bytes] field is corrupted. 0 is used");
  205. pager->reservedBytes = 0;
  206. pager->integrity &= ~SQLITERK_INTEGRITY_HEADER;
  207. } else
  208. pager->reservedBytes = reservedBytes;
  209. } else {
  210. // Header is corrupted. Defaults the config
  211. sqliterkOSWarning(SQLITERK_DAMAGED,
  212. "SQLite format magic corrupted.");
  213. if (!pager->codec) {
  214. pager->pagesize = SQLITRK_CONFIG_DEFAULT_PAGESIZE;
  215. pager->reservedBytes = 0;
  216. }
  217. pager->freepagecount = 0;
  218. pager->integrity &= ~SQLITERK_INTEGRITY_HEADER;
  219. }
  220. }
  221. // Assign page count
  222. size_t filesize;
  223. rc = sqliterkOSFileSize(pager->file, &filesize);
  224. if (rc != SQLITERK_OK) {
  225. sqliterkOSError(rc, "Failed to get size of file '%s': %s",
  226. sqliterkOSGetFilePath(pager->file), strerror(errno));
  227. goto sqliterkPagerParseHeader_End;
  228. }
  229. pager->pagecount =
  230. (int) ((filesize + pager->pagesize - 1) / pager->pagesize);
  231. if (pager->pagecount < 1) {
  232. rc = SQLITERK_DAMAGED;
  233. sqliterkOSError(rc, "File truncated.");
  234. goto sqliterkPagerParseHeader_End;
  235. }
  236. // Check free page
  237. if (pager->freepagecount < 0 || pager->freepagecount > pager->pagecount) {
  238. sqliterkOSWarning(
  239. SQLITERK_DAMAGED,
  240. "The [free page count] field is corrupted. 0 is used");
  241. pager->freepagecount = 0;
  242. pager->integrity &= ~SQLITERK_INTEGRITY_HEADER;
  243. }
  244. // Assign usableSize
  245. pager->usableSize = pager->pagesize - pager->reservedBytes;
  246. sqliterkPagerParseHeader_End:
  247. if (buffer) {
  248. sqliterkOSFree(buffer);
  249. }
  250. return rc;
  251. }
  252. int sqliterkPagerClose(sqliterk_pager *pager)
  253. {
  254. if (!pager) {
  255. return SQLITERK_MISUSE;
  256. }
  257. int rc = SQLITERK_OK;
  258. if (pager->file) {
  259. rc = sqliterkOSClose(pager->file);
  260. pager->file = NULL;
  261. }
  262. if (pager->pagesStatus) {
  263. sqliterkOSFree(pager->pagesStatus);
  264. pager->pagesStatus = NULL;
  265. }
  266. pager->pagesize = 0;
  267. pager->pagecount = 0;
  268. sqliterkCryptoFreeCodec(pager);
  269. sqliterkOSFree(pager);
  270. return rc;
  271. }
  272. int sqliterkPagerGetPageCount(sqliterk_pager *pager)
  273. {
  274. if (!pager) {
  275. return 0;
  276. }
  277. return pager->pagecount;
  278. }
  279. int sqliterkPagerIsPagenoValid(sqliterk_pager *pager, int pageno)
  280. {
  281. if (!pager || pageno < 1 || pageno > pager->pagecount) {
  282. return SQLITERK_MISUSE;
  283. }
  284. return SQLITERK_OK;
  285. }
  286. // Get the page type from file at page [pageno]
  287. int sqliterkPageAcquireType(sqliterk_pager *pager,
  288. int pageno,
  289. sqliterk_page_type *type)
  290. {
  291. // TODO: for encrypted databases, decode the whole page.
  292. // Use sqliterkPageAcquire instead.
  293. if (!pager || sqliterkPagerIsPagenoValid(pager, pageno) != SQLITERK_OK ||
  294. !type) {
  295. return SQLITERK_MISUSE;
  296. }
  297. int rc = SQLITERK_OK;
  298. unsigned char typedata;
  299. size_t typesize = 1;
  300. rc = sqliterkOSRead(pager->file,
  301. sqliterkPagenoHeaderOffset(pageno) +
  302. (pageno - 1) * pager->pagesize,
  303. &typedata, &typesize);
  304. if (rc != SQLITERK_OK) {
  305. goto sqliterkPageAcquireType_Failed;
  306. }
  307. int theType;
  308. sqliterkParseInt(&typedata, 0, 1, &theType);
  309. switch (theType) {
  310. case sqliterk_page_type_interior_index:
  311. case sqliterk_page_type_interior_table:
  312. case sqliterk_page_type_leaf_index:
  313. case sqliterk_page_type_leaf_table:
  314. *type = theType;
  315. break;
  316. default:
  317. *type = sqliterk_page_type_unknown;
  318. break;
  319. }
  320. return SQLITERK_OK;
  321. sqliterkPageAcquireType_Failed:
  322. *type = sqliterk_page_type_unknown;
  323. return rc;
  324. }
  325. // Get whole page data from file at page [pageno] and setup the [page].
  326. int sqliterkPageAcquire(sqliterk_pager *pager, int pageno, sqliterk_page **page)
  327. {
  328. return sqliterkPageAcquireOne(pager, pageno, page,
  329. sqliterk_page_type_unknown);
  330. }
  331. int sqliterkPageAcquireOverflow(sqliterk_pager *pager,
  332. int pageno,
  333. sqliterk_page **page)
  334. {
  335. return sqliterkPageAcquireOne(pager, pageno, page,
  336. sqliterk_page_type_overflow);
  337. }
  338. static int sqliterkPageAcquireOne(sqliterk_pager *pager,
  339. int pageno,
  340. sqliterk_page **page,
  341. sqliterk_page_type type)
  342. {
  343. if (!pager || !page ||
  344. sqliterkPagerIsPagenoValid(pager, pageno) != SQLITERK_OK) {
  345. return SQLITERK_MISUSE;
  346. }
  347. int rc = SQLITERK_OK;
  348. sqliterk_page *thePage = sqliterkOSMalloc(sizeof(sqliterk_page));
  349. if (!thePage) {
  350. rc = SQLITERK_NOMEM;
  351. goto sqliterkPageAcquire_Failed;
  352. }
  353. thePage->pageno = pageno;
  354. thePage->data = sqliterkOSMalloc(pager->pagesize);
  355. if (!thePage->data) {
  356. rc = SQLITERK_NOMEM;
  357. goto sqliterkPageAcquire_Failed;
  358. }
  359. size_t size = pager->pagesize;
  360. rc = sqliterkOSRead(pager->file, (pageno - 1) * pager->pagesize,
  361. thePage->data, &size);
  362. if (rc != SQLITERK_OK) {
  363. goto sqliterkPageAcquire_Failed;
  364. }
  365. // For encrypted databases, decode page.
  366. if (pager->codec) {
  367. rc = sqliterkCryptoDecode(pager->codec, pageno, thePage->data);
  368. if (rc != SQLITERK_OK)
  369. goto sqliterkPageAcquire_Failed;
  370. }
  371. // Check type
  372. if (type == sqliterk_page_type_unknown) {
  373. sqliterkParseInt(thePage->data, sqliterkPageHeaderOffset(thePage), 1,
  374. &type);
  375. switch (type) {
  376. case sqliterk_page_type_interior_index:
  377. case sqliterk_page_type_interior_table:
  378. case sqliterk_page_type_leaf_index:
  379. case sqliterk_page_type_leaf_table:
  380. thePage->type = type;
  381. break;
  382. default:
  383. thePage->type = sqliterk_page_type_unknown;
  384. break;
  385. }
  386. } else {
  387. thePage->type = type;
  388. }
  389. *page = thePage;
  390. return SQLITERK_OK;
  391. sqliterkPageAcquire_Failed:
  392. if (thePage) {
  393. sqliterkPageRelease(thePage);
  394. }
  395. *page = NULL;
  396. return rc;
  397. }
  398. int sqliterkPageRelease(sqliterk_page *page)
  399. {
  400. if (!page) {
  401. return SQLITERK_MISUSE;
  402. }
  403. if (page->data) {
  404. sqliterkOSFree(page->data);
  405. page->data = NULL;
  406. }
  407. sqliterkOSFree(page);
  408. return SQLITERK_OK;
  409. }
  410. // Ahead release the page data to save memory
  411. int sqliterkPageClearData(sqliterk_page *page)
  412. {
  413. if (!page) {
  414. return SQLITERK_MISUSE;
  415. }
  416. if (page->data) {
  417. sqliterkOSFree(page->data);
  418. page->data = NULL;
  419. }
  420. return SQLITERK_OK;
  421. }
  422. const unsigned char *sqliterkPageGetData(sqliterk_page *page)
  423. {
  424. if (!page) {
  425. return NULL;
  426. }
  427. return page->data;
  428. }
  429. int sqliterkPagerGetSize(sqliterk_pager *pager)
  430. {
  431. if (!pager) {
  432. return 0;
  433. }
  434. return pager->pagesize;
  435. }
  436. int sqliterkPagerGetUsableSize(sqliterk_pager *pager)
  437. {
  438. if (!pager) {
  439. return 0;
  440. }
  441. return pager->usableSize;
  442. }
  443. int sqliterkPageGetPageno(sqliterk_page *page)
  444. {
  445. if (!page) {
  446. return 0;
  447. }
  448. return page->pageno;
  449. }
  450. sqliterk_page_type sqliterkPageGetType(sqliterk_page *page)
  451. {
  452. if (!page) {
  453. return sqliterk_page_type_unknown;
  454. }
  455. return page->type;
  456. }
  457. int sqliterkPagenoHeaderOffset(int pageno)
  458. {
  459. if (pageno == 1) {
  460. return 100;
  461. }
  462. return 0;
  463. }
  464. int sqliterkPageHeaderOffset(sqliterk_page *page)
  465. {
  466. if (!page) {
  467. return 0;
  468. }
  469. return sqliterkPagenoHeaderOffset(page->pageno);
  470. }
  471. const char *sqliterkPageGetTypeName(sqliterk_page_type type)
  472. {
  473. char *name;
  474. switch (type) {
  475. case sqliterk_page_type_interior_index:
  476. name = "interior-index btree";
  477. break;
  478. case sqliterk_page_type_interior_table:
  479. name = "interior-table btree";
  480. break;
  481. case sqliterk_page_type_leaf_index:
  482. name = "leaf-index btree";
  483. break;
  484. case sqliterk_page_type_leaf_table:
  485. name = "leaf-table btree";
  486. break;
  487. default:
  488. name = "unknown page";
  489. break;
  490. }
  491. return name;
  492. }
  493. void sqliterkPagerSetStatus(sqliterk_pager *pager,
  494. int pageno,
  495. sqliterk_status status)
  496. {
  497. if (!pager || !pager->pagesStatus ||
  498. sqliterkPagerIsPagenoValid(pager, pageno) != SQLITERK_OK) {
  499. return;
  500. }
  501. pager->pagesStatus[pageno - 1] = status;
  502. if (status == sqliterk_status_checked)
  503. pager->integrity |= SQLITERK_INTEGRITY_DATA;
  504. }
  505. sqliterk_status sqliterkPagerGetStatus(sqliterk_pager *pager, int pageno)
  506. {
  507. if (!pager || !pager->pagesStatus ||
  508. sqliterkPagerIsPagenoValid(pager, pageno) != SQLITERK_OK) {
  509. return sqliterk_status_invalid;
  510. }
  511. return pager->pagesStatus[pageno - 1];
  512. }
  513. int sqliterkPagerGetParsedPageCount(sqliterk_pager *pager)
  514. {
  515. if (!pager || !pager->pagesStatus) {
  516. return 0;
  517. }
  518. int i, count = 0;
  519. for (i = 0; i < pager->pagecount; i++) {
  520. if (pager->pagesStatus[i] == sqliterk_status_checked) {
  521. count++;
  522. }
  523. }
  524. return count;
  525. }
  526. int sqliterkPagerGetValidPageCount(sqliterk_pager *pager)
  527. {
  528. if (!pager) {
  529. return 0;
  530. }
  531. return pager->pagecount - pager->freepagecount;
  532. }
  533. unsigned int sqliterkPagerGetIntegrity(sqliterk_pager *pager)
  534. {
  535. if (!pager) {
  536. return 0;
  537. }
  538. return pager->integrity;
  539. }