ext4_write.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. /*
  2. * (C) Copyright 2011 - 2012 Samsung Electronics
  3. * EXT4 filesystem implementation in Uboot by
  4. * Uma Shankar <uma.shankar@samsung.com>
  5. * Manjunatha C Achar <a.manjunatha@samsung.com>
  6. *
  7. * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
  8. * Ext4 read optimization taken from Open-Moko
  9. * Qi bootloader
  10. *
  11. * (C) Copyright 2004
  12. * esd gmbh <www.esd-electronics.com>
  13. * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
  14. *
  15. * based on code from grub2 fs/ext2.c and fs/fshelp.c by
  16. * GRUB -- GRand Unified Bootloader
  17. * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
  18. *
  19. * ext4write : Based on generic ext4 protocol.
  20. *
  21. * SPDX-License-Identifier: GPL-2.0+
  22. */
  23. #include <common.h>
  24. #include <linux/stat.h>
  25. #include <div64.h>
  26. #include "ext4_common.h"
  27. static void ext4fs_update(void)
  28. {
  29. short i;
  30. ext4fs_update_journal();
  31. struct ext_filesystem *fs = get_fs();
  32. /* update super block */
  33. put_ext4((uint64_t)(SUPERBLOCK_SIZE),
  34. (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
  35. /* update block groups */
  36. for (i = 0; i < fs->no_blkgrp; i++) {
  37. fs->bgd[i].bg_checksum = ext4fs_checksum_update(i);
  38. put_ext4((uint64_t)((uint64_t)fs->bgd[i].block_id * (uint64_t)fs->blksz),
  39. fs->blk_bmaps[i], fs->blksz);
  40. }
  41. /* update inode table groups */
  42. for (i = 0; i < fs->no_blkgrp; i++) {
  43. put_ext4((uint64_t) ((uint64_t)fs->bgd[i].inode_id * (uint64_t)fs->blksz),
  44. fs->inode_bmaps[i], fs->blksz);
  45. }
  46. /* update the block group descriptor table */
  47. put_ext4((uint64_t)((uint64_t)fs->gdtable_blkno * (uint64_t)fs->blksz),
  48. (struct ext2_block_group *)fs->gdtable,
  49. (fs->blksz * fs->no_blk_pergdt));
  50. ext4fs_dump_metadata();
  51. gindex = 0;
  52. gd_index = 0;
  53. }
  54. int ext4fs_get_bgdtable(void)
  55. {
  56. int status;
  57. int grp_desc_size;
  58. struct ext_filesystem *fs = get_fs();
  59. grp_desc_size = sizeof(struct ext2_block_group);
  60. fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
  61. if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
  62. fs->no_blk_pergdt++;
  63. /* allocate memory for gdtable */
  64. fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
  65. if (!fs->gdtable)
  66. return -ENOMEM;
  67. /* read the group descriptor table */
  68. status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk,
  69. 0, fs->blksz * fs->no_blk_pergdt, fs->gdtable);
  70. if (status == 0)
  71. goto fail;
  72. if (ext4fs_log_gdt(fs->gdtable)) {
  73. printf("Error in ext4fs_log_gdt\n");
  74. return -1;
  75. }
  76. return 0;
  77. fail:
  78. free(fs->gdtable);
  79. fs->gdtable = NULL;
  80. return -1;
  81. }
  82. static void delete_single_indirect_block(struct ext2_inode *inode)
  83. {
  84. struct ext2_block_group *bgd = NULL;
  85. static int prev_bg_bmap_idx = -1;
  86. long int blknr;
  87. int remainder;
  88. int bg_idx;
  89. int status;
  90. unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
  91. struct ext_filesystem *fs = get_fs();
  92. char *journal_buffer = zalloc(fs->blksz);
  93. if (!journal_buffer) {
  94. printf("No memory\n");
  95. return;
  96. }
  97. /* get block group descriptor table */
  98. bgd = (struct ext2_block_group *)fs->gdtable;
  99. /* deleting the single indirect block associated with inode */
  100. if (inode->b.blocks.indir_block != 0) {
  101. debug("SIPB releasing %u\n", inode->b.blocks.indir_block);
  102. blknr = inode->b.blocks.indir_block;
  103. if (fs->blksz != 1024) {
  104. bg_idx = blknr / blk_per_grp;
  105. } else {
  106. bg_idx = blknr / blk_per_grp;
  107. remainder = blknr % blk_per_grp;
  108. if (!remainder)
  109. bg_idx--;
  110. }
  111. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
  112. bgd[bg_idx].free_blocks++;
  113. fs->sb->free_blocks++;
  114. /* journal backup */
  115. if (prev_bg_bmap_idx != bg_idx) {
  116. status =
  117. ext4fs_devread((lbaint_t)bgd[bg_idx].block_id *
  118. fs->sect_perblk, 0, fs->blksz,
  119. journal_buffer);
  120. if (status == 0)
  121. goto fail;
  122. if (ext4fs_log_journal
  123. (journal_buffer, bgd[bg_idx].block_id))
  124. goto fail;
  125. prev_bg_bmap_idx = bg_idx;
  126. }
  127. }
  128. fail:
  129. free(journal_buffer);
  130. }
  131. static void delete_double_indirect_block(struct ext2_inode *inode)
  132. {
  133. int i;
  134. short status;
  135. static int prev_bg_bmap_idx = -1;
  136. long int blknr;
  137. int remainder;
  138. int bg_idx;
  139. unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
  140. unsigned int *di_buffer = NULL;
  141. unsigned int *DIB_start_addr = NULL;
  142. struct ext2_block_group *bgd = NULL;
  143. struct ext_filesystem *fs = get_fs();
  144. char *journal_buffer = zalloc(fs->blksz);
  145. if (!journal_buffer) {
  146. printf("No memory\n");
  147. return;
  148. }
  149. /* get the block group descriptor table */
  150. bgd = (struct ext2_block_group *)fs->gdtable;
  151. if (inode->b.blocks.double_indir_block != 0) {
  152. di_buffer = zalloc(fs->blksz);
  153. if (!di_buffer) {
  154. printf("No memory\n");
  155. return;
  156. }
  157. DIB_start_addr = (unsigned int *)di_buffer;
  158. blknr = inode->b.blocks.double_indir_block;
  159. status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
  160. fs->blksz, (char *)di_buffer);
  161. for (i = 0; i < fs->blksz / sizeof(int); i++) {
  162. if (*di_buffer == 0)
  163. break;
  164. debug("DICB releasing %u\n", *di_buffer);
  165. if (fs->blksz != 1024) {
  166. bg_idx = (*di_buffer) / blk_per_grp;
  167. } else {
  168. bg_idx = (*di_buffer) / blk_per_grp;
  169. remainder = (*di_buffer) % blk_per_grp;
  170. if (!remainder)
  171. bg_idx--;
  172. }
  173. ext4fs_reset_block_bmap(*di_buffer,
  174. fs->blk_bmaps[bg_idx], bg_idx);
  175. di_buffer++;
  176. bgd[bg_idx].free_blocks++;
  177. fs->sb->free_blocks++;
  178. /* journal backup */
  179. if (prev_bg_bmap_idx != bg_idx) {
  180. status = ext4fs_devread((lbaint_t)
  181. bgd[bg_idx].block_id
  182. * fs->sect_perblk, 0,
  183. fs->blksz,
  184. journal_buffer);
  185. if (status == 0)
  186. goto fail;
  187. if (ext4fs_log_journal(journal_buffer,
  188. bgd[bg_idx].block_id))
  189. goto fail;
  190. prev_bg_bmap_idx = bg_idx;
  191. }
  192. }
  193. /* removing the parent double indirect block */
  194. blknr = inode->b.blocks.double_indir_block;
  195. if (fs->blksz != 1024) {
  196. bg_idx = blknr / blk_per_grp;
  197. } else {
  198. bg_idx = blknr / blk_per_grp;
  199. remainder = blknr % blk_per_grp;
  200. if (!remainder)
  201. bg_idx--;
  202. }
  203. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
  204. bgd[bg_idx].free_blocks++;
  205. fs->sb->free_blocks++;
  206. /* journal backup */
  207. if (prev_bg_bmap_idx != bg_idx) {
  208. memset(journal_buffer, '\0', fs->blksz);
  209. status = ext4fs_devread((lbaint_t)bgd[bg_idx].block_id *
  210. fs->sect_perblk, 0, fs->blksz,
  211. journal_buffer);
  212. if (status == 0)
  213. goto fail;
  214. if (ext4fs_log_journal(journal_buffer,
  215. bgd[bg_idx].block_id))
  216. goto fail;
  217. prev_bg_bmap_idx = bg_idx;
  218. }
  219. debug("DIPB releasing %ld\n", blknr);
  220. }
  221. fail:
  222. free(DIB_start_addr);
  223. free(journal_buffer);
  224. }
  225. static void delete_triple_indirect_block(struct ext2_inode *inode)
  226. {
  227. int i, j;
  228. short status;
  229. static int prev_bg_bmap_idx = -1;
  230. long int blknr;
  231. int remainder;
  232. int bg_idx;
  233. unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
  234. unsigned int *tigp_buffer = NULL;
  235. unsigned int *tib_start_addr = NULL;
  236. unsigned int *tip_buffer = NULL;
  237. unsigned int *tipb_start_addr = NULL;
  238. struct ext2_block_group *bgd = NULL;
  239. struct ext_filesystem *fs = get_fs();
  240. char *journal_buffer = zalloc(fs->blksz);
  241. if (!journal_buffer) {
  242. printf("No memory\n");
  243. return;
  244. }
  245. /* get block group descriptor table */
  246. bgd = (struct ext2_block_group *)fs->gdtable;
  247. if (inode->b.blocks.triple_indir_block != 0) {
  248. tigp_buffer = zalloc(fs->blksz);
  249. if (!tigp_buffer) {
  250. printf("No memory\n");
  251. return;
  252. }
  253. tib_start_addr = (unsigned int *)tigp_buffer;
  254. blknr = inode->b.blocks.triple_indir_block;
  255. status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
  256. fs->blksz, (char *)tigp_buffer);
  257. for (i = 0; i < fs->blksz / sizeof(int); i++) {
  258. if (*tigp_buffer == 0)
  259. break;
  260. debug("tigp buffer releasing %u\n", *tigp_buffer);
  261. tip_buffer = zalloc(fs->blksz);
  262. if (!tip_buffer)
  263. goto fail;
  264. tipb_start_addr = (unsigned int *)tip_buffer;
  265. status = ext4fs_devread((lbaint_t)(*tigp_buffer) *
  266. fs->sect_perblk, 0, fs->blksz,
  267. (char *)tip_buffer);
  268. for (j = 0; j < fs->blksz / sizeof(int); j++) {
  269. if (*tip_buffer == 0)
  270. break;
  271. if (fs->blksz != 1024) {
  272. bg_idx = (*tip_buffer) / blk_per_grp;
  273. } else {
  274. bg_idx = (*tip_buffer) / blk_per_grp;
  275. remainder = (*tip_buffer) % blk_per_grp;
  276. if (!remainder)
  277. bg_idx--;
  278. }
  279. ext4fs_reset_block_bmap(*tip_buffer,
  280. fs->blk_bmaps[bg_idx],
  281. bg_idx);
  282. tip_buffer++;
  283. bgd[bg_idx].free_blocks++;
  284. fs->sb->free_blocks++;
  285. /* journal backup */
  286. if (prev_bg_bmap_idx != bg_idx) {
  287. status =
  288. ext4fs_devread(
  289. (lbaint_t)
  290. bgd[bg_idx].block_id *
  291. fs->sect_perblk, 0,
  292. fs->blksz,
  293. journal_buffer);
  294. if (status == 0)
  295. goto fail;
  296. if (ext4fs_log_journal(journal_buffer,
  297. bgd[bg_idx].
  298. block_id))
  299. goto fail;
  300. prev_bg_bmap_idx = bg_idx;
  301. }
  302. }
  303. free(tipb_start_addr);
  304. tipb_start_addr = NULL;
  305. /*
  306. * removing the grand parent blocks
  307. * which is connected to inode
  308. */
  309. if (fs->blksz != 1024) {
  310. bg_idx = (*tigp_buffer) / blk_per_grp;
  311. } else {
  312. bg_idx = (*tigp_buffer) / blk_per_grp;
  313. remainder = (*tigp_buffer) % blk_per_grp;
  314. if (!remainder)
  315. bg_idx--;
  316. }
  317. ext4fs_reset_block_bmap(*tigp_buffer,
  318. fs->blk_bmaps[bg_idx], bg_idx);
  319. tigp_buffer++;
  320. bgd[bg_idx].free_blocks++;
  321. fs->sb->free_blocks++;
  322. /* journal backup */
  323. if (prev_bg_bmap_idx != bg_idx) {
  324. memset(journal_buffer, '\0', fs->blksz);
  325. status =
  326. ext4fs_devread((lbaint_t)
  327. bgd[bg_idx].block_id *
  328. fs->sect_perblk, 0,
  329. fs->blksz, journal_buffer);
  330. if (status == 0)
  331. goto fail;
  332. if (ext4fs_log_journal(journal_buffer,
  333. bgd[bg_idx].block_id))
  334. goto fail;
  335. prev_bg_bmap_idx = bg_idx;
  336. }
  337. }
  338. /* removing the grand parent triple indirect block */
  339. blknr = inode->b.blocks.triple_indir_block;
  340. if (fs->blksz != 1024) {
  341. bg_idx = blknr / blk_per_grp;
  342. } else {
  343. bg_idx = blknr / blk_per_grp;
  344. remainder = blknr % blk_per_grp;
  345. if (!remainder)
  346. bg_idx--;
  347. }
  348. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
  349. bgd[bg_idx].free_blocks++;
  350. fs->sb->free_blocks++;
  351. /* journal backup */
  352. if (prev_bg_bmap_idx != bg_idx) {
  353. memset(journal_buffer, '\0', fs->blksz);
  354. status = ext4fs_devread((lbaint_t)bgd[bg_idx].block_id *
  355. fs->sect_perblk, 0, fs->blksz,
  356. journal_buffer);
  357. if (status == 0)
  358. goto fail;
  359. if (ext4fs_log_journal(journal_buffer,
  360. bgd[bg_idx].block_id))
  361. goto fail;
  362. prev_bg_bmap_idx = bg_idx;
  363. }
  364. debug("tigp buffer itself releasing %ld\n", blknr);
  365. }
  366. fail:
  367. free(tib_start_addr);
  368. free(tipb_start_addr);
  369. free(journal_buffer);
  370. }
  371. static int ext4fs_delete_file(int inodeno)
  372. {
  373. struct ext2_inode inode;
  374. short status;
  375. int i;
  376. int remainder;
  377. long int blknr;
  378. int bg_idx;
  379. int ibmap_idx;
  380. char *read_buffer = NULL;
  381. char *start_block_address = NULL;
  382. unsigned int no_blocks;
  383. static int prev_bg_bmap_idx = -1;
  384. unsigned int inodes_per_block;
  385. long int blkno;
  386. unsigned int blkoff;
  387. unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
  388. unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
  389. struct ext2_inode *inode_buffer = NULL;
  390. struct ext2_block_group *bgd = NULL;
  391. struct ext_filesystem *fs = get_fs();
  392. char *journal_buffer = zalloc(fs->blksz);
  393. if (!journal_buffer)
  394. return -ENOMEM;
  395. /* get the block group descriptor table */
  396. bgd = (struct ext2_block_group *)fs->gdtable;
  397. status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
  398. if (status == 0)
  399. goto fail;
  400. /* read the block no allocated to a file */
  401. no_blocks = inode.size / fs->blksz;
  402. if (inode.size % fs->blksz)
  403. no_blocks++;
  404. if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
  405. struct ext2fs_node *node_inode =
  406. zalloc(sizeof(struct ext2fs_node));
  407. if (!node_inode)
  408. goto fail;
  409. node_inode->data = ext4fs_root;
  410. node_inode->ino = inodeno;
  411. node_inode->inode_read = 0;
  412. memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
  413. for (i = 0; i < no_blocks; i++) {
  414. blknr = read_allocated_block(&(node_inode->inode), i);
  415. if (fs->blksz != 1024) {
  416. bg_idx = blknr / blk_per_grp;
  417. } else {
  418. bg_idx = blknr / blk_per_grp;
  419. remainder = blknr % blk_per_grp;
  420. if (!remainder)
  421. bg_idx--;
  422. }
  423. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
  424. bg_idx);
  425. debug("EXT4_EXTENTS Block releasing %ld: %d\n",
  426. blknr, bg_idx);
  427. bgd[bg_idx].free_blocks++;
  428. fs->sb->free_blocks++;
  429. /* journal backup */
  430. if (prev_bg_bmap_idx != bg_idx) {
  431. status =
  432. ext4fs_devread((lbaint_t)
  433. bgd[bg_idx].block_id *
  434. fs->sect_perblk, 0,
  435. fs->blksz, journal_buffer);
  436. if (status == 0)
  437. goto fail;
  438. if (ext4fs_log_journal(journal_buffer,
  439. bgd[bg_idx].block_id))
  440. goto fail;
  441. prev_bg_bmap_idx = bg_idx;
  442. }
  443. }
  444. if (node_inode) {
  445. free(node_inode);
  446. node_inode = NULL;
  447. }
  448. } else {
  449. delete_single_indirect_block(&inode);
  450. delete_double_indirect_block(&inode);
  451. delete_triple_indirect_block(&inode);
  452. /* read the block no allocated to a file */
  453. no_blocks = inode.size / fs->blksz;
  454. if (inode.size % fs->blksz)
  455. no_blocks++;
  456. for (i = 0; i < no_blocks; i++) {
  457. blknr = read_allocated_block(&inode, i);
  458. if (fs->blksz != 1024) {
  459. bg_idx = blknr / blk_per_grp;
  460. } else {
  461. bg_idx = blknr / blk_per_grp;
  462. remainder = blknr % blk_per_grp;
  463. if (!remainder)
  464. bg_idx--;
  465. }
  466. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
  467. bg_idx);
  468. debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
  469. bgd[bg_idx].free_blocks++;
  470. fs->sb->free_blocks++;
  471. /* journal backup */
  472. if (prev_bg_bmap_idx != bg_idx) {
  473. memset(journal_buffer, '\0', fs->blksz);
  474. status = ext4fs_devread((lbaint_t)
  475. bgd[bg_idx].block_id
  476. * fs->sect_perblk,
  477. 0, fs->blksz,
  478. journal_buffer);
  479. if (status == 0)
  480. goto fail;
  481. if (ext4fs_log_journal(journal_buffer,
  482. bgd[bg_idx].block_id))
  483. goto fail;
  484. prev_bg_bmap_idx = bg_idx;
  485. }
  486. }
  487. }
  488. /* from the inode no to blockno */
  489. inodes_per_block = fs->blksz / fs->inodesz;
  490. ibmap_idx = inodeno / inode_per_grp;
  491. /* get the block no */
  492. inodeno--;
  493. blkno = __le32_to_cpu(bgd[ibmap_idx].inode_table_id) +
  494. (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block;
  495. /* get the offset of the inode */
  496. blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
  497. /* read the block no containing the inode */
  498. read_buffer = zalloc(fs->blksz);
  499. if (!read_buffer)
  500. goto fail;
  501. start_block_address = read_buffer;
  502. status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk,
  503. 0, fs->blksz, read_buffer);
  504. if (status == 0)
  505. goto fail;
  506. if (ext4fs_log_journal(read_buffer, blkno))
  507. goto fail;
  508. read_buffer = read_buffer + blkoff;
  509. inode_buffer = (struct ext2_inode *)read_buffer;
  510. memset(inode_buffer, '\0', sizeof(struct ext2_inode));
  511. /* write the inode to original position in inode table */
  512. if (ext4fs_put_metadata(start_block_address, blkno))
  513. goto fail;
  514. /* update the respective inode bitmaps */
  515. inodeno++;
  516. ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
  517. bgd[ibmap_idx].free_inodes++;
  518. fs->sb->free_inodes++;
  519. /* journal backup */
  520. memset(journal_buffer, '\0', fs->blksz);
  521. status = ext4fs_devread((lbaint_t)bgd[ibmap_idx].inode_id *
  522. fs->sect_perblk, 0, fs->blksz, journal_buffer);
  523. if (status == 0)
  524. goto fail;
  525. if (ext4fs_log_journal(journal_buffer, bgd[ibmap_idx].inode_id))
  526. goto fail;
  527. ext4fs_update();
  528. ext4fs_deinit();
  529. if (ext4fs_init() != 0) {
  530. printf("error in File System init\n");
  531. goto fail;
  532. }
  533. free(start_block_address);
  534. free(journal_buffer);
  535. return 0;
  536. fail:
  537. free(start_block_address);
  538. free(journal_buffer);
  539. return -1;
  540. }
  541. int ext4fs_init(void)
  542. {
  543. short status;
  544. int i;
  545. unsigned int real_free_blocks = 0;
  546. struct ext_filesystem *fs = get_fs();
  547. /* populate fs */
  548. fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
  549. fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
  550. fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
  551. /* get the superblock */
  552. fs->sb = zalloc(SUPERBLOCK_SIZE);
  553. if (!fs->sb)
  554. return -ENOMEM;
  555. if (!ext4_read_superblock((char *)fs->sb))
  556. goto fail;
  557. /* init journal */
  558. if (ext4fs_init_journal())
  559. goto fail;
  560. /* get total no of blockgroups */
  561. fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
  562. (ext4fs_root->sblock.total_blocks -
  563. ext4fs_root->sblock.first_data_block),
  564. ext4fs_root->sblock.blocks_per_group);
  565. /* get the block group descriptor table */
  566. fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
  567. if (ext4fs_get_bgdtable() == -1) {
  568. printf("Error in getting the block group descriptor table\n");
  569. goto fail;
  570. }
  571. fs->bgd = (struct ext2_block_group *)fs->gdtable;
  572. /* load all the available bitmap block of the partition */
  573. fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
  574. if (!fs->blk_bmaps)
  575. goto fail;
  576. for (i = 0; i < fs->no_blkgrp; i++) {
  577. fs->blk_bmaps[i] = zalloc(fs->blksz);
  578. if (!fs->blk_bmaps[i])
  579. goto fail;
  580. }
  581. for (i = 0; i < fs->no_blkgrp; i++) {
  582. status =
  583. ext4fs_devread((lbaint_t)fs->bgd[i].block_id *
  584. fs->sect_perblk, 0,
  585. fs->blksz, (char *)fs->blk_bmaps[i]);
  586. if (status == 0)
  587. goto fail;
  588. }
  589. /* load all the available inode bitmap of the partition */
  590. fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
  591. if (!fs->inode_bmaps)
  592. goto fail;
  593. for (i = 0; i < fs->no_blkgrp; i++) {
  594. fs->inode_bmaps[i] = zalloc(fs->blksz);
  595. if (!fs->inode_bmaps[i])
  596. goto fail;
  597. }
  598. for (i = 0; i < fs->no_blkgrp; i++) {
  599. status = ext4fs_devread((lbaint_t)fs->bgd[i].inode_id *
  600. fs->sect_perblk,
  601. 0, fs->blksz,
  602. (char *)fs->inode_bmaps[i]);
  603. if (status == 0)
  604. goto fail;
  605. }
  606. /*
  607. * check filesystem consistency with free blocks of file system
  608. * some time we observed that superblock freeblocks does not match
  609. * with the blockgroups freeblocks when improper
  610. * reboot of a linux kernel
  611. */
  612. for (i = 0; i < fs->no_blkgrp; i++)
  613. real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks;
  614. if (real_free_blocks != fs->sb->free_blocks)
  615. fs->sb->free_blocks = real_free_blocks;
  616. return 0;
  617. fail:
  618. ext4fs_deinit();
  619. return -1;
  620. }
  621. void ext4fs_deinit(void)
  622. {
  623. int i;
  624. struct ext2_inode inode_journal;
  625. struct journal_superblock_t *jsb;
  626. long int blknr;
  627. struct ext_filesystem *fs = get_fs();
  628. /* free journal */
  629. char *temp_buff = zalloc(fs->blksz);
  630. if (temp_buff) {
  631. ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
  632. &inode_journal);
  633. blknr = read_allocated_block(&inode_journal,
  634. EXT2_JOURNAL_SUPERBLOCK);
  635. ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
  636. temp_buff);
  637. jsb = (struct journal_superblock_t *)temp_buff;
  638. jsb->s_start = cpu_to_be32(0);
  639. put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
  640. (struct journal_superblock_t *)temp_buff, fs->blksz);
  641. free(temp_buff);
  642. }
  643. ext4fs_free_journal();
  644. /* get the superblock */
  645. ext4_read_superblock((char *)fs->sb);
  646. fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
  647. put_ext4((uint64_t)(SUPERBLOCK_SIZE),
  648. (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
  649. free(fs->sb);
  650. fs->sb = NULL;
  651. if (fs->blk_bmaps) {
  652. for (i = 0; i < fs->no_blkgrp; i++) {
  653. free(fs->blk_bmaps[i]);
  654. fs->blk_bmaps[i] = NULL;
  655. }
  656. free(fs->blk_bmaps);
  657. fs->blk_bmaps = NULL;
  658. }
  659. if (fs->inode_bmaps) {
  660. for (i = 0; i < fs->no_blkgrp; i++) {
  661. free(fs->inode_bmaps[i]);
  662. fs->inode_bmaps[i] = NULL;
  663. }
  664. free(fs->inode_bmaps);
  665. fs->inode_bmaps = NULL;
  666. }
  667. free(fs->gdtable);
  668. fs->gdtable = NULL;
  669. fs->bgd = NULL;
  670. /*
  671. * reinitiliazed the global inode and
  672. * block bitmap first execution check variables
  673. */
  674. fs->first_pass_ibmap = 0;
  675. fs->first_pass_bbmap = 0;
  676. fs->curr_inode_no = 0;
  677. fs->curr_blkno = 0;
  678. }
  679. static int ext4fs_write_file(struct ext2_inode *file_inode,
  680. int pos, unsigned int len, char *buf)
  681. {
  682. int i;
  683. int blockcnt;
  684. unsigned int filesize = __le32_to_cpu(file_inode->size);
  685. struct ext_filesystem *fs = get_fs();
  686. int log2blksz = fs->dev_desc->log2blksz;
  687. int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
  688. int previous_block_number = -1;
  689. int delayed_start = 0;
  690. int delayed_extent = 0;
  691. int delayed_next = 0;
  692. char *delayed_buf = NULL;
  693. /* Adjust len so it we can't read past the end of the file. */
  694. if (len > filesize)
  695. len = filesize;
  696. blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
  697. for (i = pos / fs->blksz; i < blockcnt; i++) {
  698. long int blknr;
  699. int blockend = fs->blksz;
  700. int skipfirst = 0;
  701. blknr = read_allocated_block(file_inode, i);
  702. if (blknr < 0)
  703. return -1;
  704. blknr = blknr << log2_fs_blocksize;
  705. if (blknr) {
  706. if (previous_block_number != -1) {
  707. if (delayed_next == blknr) {
  708. delayed_extent += blockend;
  709. delayed_next += blockend >> log2blksz;
  710. } else { /* spill */
  711. put_ext4((uint64_t)
  712. ((uint64_t)delayed_start << log2blksz),
  713. delayed_buf,
  714. (uint32_t) delayed_extent);
  715. previous_block_number = blknr;
  716. delayed_start = blknr;
  717. delayed_extent = blockend;
  718. delayed_buf = buf;
  719. delayed_next = blknr +
  720. (blockend >> log2blksz);
  721. }
  722. } else {
  723. previous_block_number = blknr;
  724. delayed_start = blknr;
  725. delayed_extent = blockend;
  726. delayed_buf = buf;
  727. delayed_next = blknr +
  728. (blockend >> log2blksz);
  729. }
  730. } else {
  731. if (previous_block_number != -1) {
  732. /* spill */
  733. put_ext4((uint64_t) ((uint64_t)delayed_start <<
  734. log2blksz),
  735. delayed_buf,
  736. (uint32_t) delayed_extent);
  737. previous_block_number = -1;
  738. }
  739. memset(buf, 0, fs->blksz - skipfirst);
  740. }
  741. buf += fs->blksz - skipfirst;
  742. }
  743. if (previous_block_number != -1) {
  744. /* spill */
  745. put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz),
  746. delayed_buf, (uint32_t) delayed_extent);
  747. previous_block_number = -1;
  748. }
  749. return len;
  750. }
  751. int ext4fs_write(const char *fname, unsigned char *buffer,
  752. unsigned long sizebytes)
  753. {
  754. int ret = 0;
  755. struct ext2_inode *file_inode = NULL;
  756. unsigned char *inode_buffer = NULL;
  757. int parent_inodeno;
  758. int inodeno;
  759. time_t timestamp = 0;
  760. uint64_t bytes_reqd_for_file;
  761. unsigned int blks_reqd_for_file;
  762. unsigned int blocks_remaining;
  763. int existing_file_inodeno;
  764. char *temp_ptr = NULL;
  765. long int itable_blkno;
  766. long int parent_itable_blkno;
  767. long int blkoff;
  768. struct ext2_sblock *sblock = &(ext4fs_root->sblock);
  769. unsigned int inodes_per_block;
  770. unsigned int ibmap_idx;
  771. struct ext_filesystem *fs = get_fs();
  772. ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
  773. memset(filename, 0x00, sizeof(filename));
  774. g_parent_inode = zalloc(sizeof(struct ext2_inode));
  775. if (!g_parent_inode)
  776. goto fail;
  777. if (ext4fs_init() != 0) {
  778. printf("error in File System init\n");
  779. return -1;
  780. }
  781. inodes_per_block = fs->blksz / fs->inodesz;
  782. parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
  783. if (parent_inodeno == -1)
  784. goto fail;
  785. if (ext4fs_iget(parent_inodeno, g_parent_inode))
  786. goto fail;
  787. /* check if the filename is already present in root */
  788. existing_file_inodeno = ext4fs_filename_check(filename);
  789. if (existing_file_inodeno != -1) {
  790. ret = ext4fs_delete_file(existing_file_inodeno);
  791. fs->first_pass_bbmap = 0;
  792. fs->curr_blkno = 0;
  793. fs->first_pass_ibmap = 0;
  794. fs->curr_inode_no = 0;
  795. if (ret)
  796. goto fail;
  797. }
  798. /* calucalate how many blocks required */
  799. bytes_reqd_for_file = sizebytes;
  800. blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
  801. if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
  802. blks_reqd_for_file++;
  803. debug("total bytes for a file %u\n", blks_reqd_for_file);
  804. }
  805. blocks_remaining = blks_reqd_for_file;
  806. /* test for available space in partition */
  807. if (fs->sb->free_blocks < blks_reqd_for_file) {
  808. printf("Not enough space on partition !!!\n");
  809. goto fail;
  810. }
  811. ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
  812. /* prepare file inode */
  813. inode_buffer = zalloc(fs->inodesz);
  814. if (!inode_buffer)
  815. goto fail;
  816. file_inode = (struct ext2_inode *)inode_buffer;
  817. file_inode->mode = S_IFREG | S_IRWXU |
  818. S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
  819. /* ToDo: Update correct time */
  820. file_inode->mtime = timestamp;
  821. file_inode->atime = timestamp;
  822. file_inode->ctime = timestamp;
  823. file_inode->nlinks = 1;
  824. file_inode->size = sizebytes;
  825. /* Allocate data blocks */
  826. ext4fs_allocate_blocks(file_inode, blocks_remaining,
  827. &blks_reqd_for_file);
  828. file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) >>
  829. fs->dev_desc->log2blksz;
  830. temp_ptr = zalloc(fs->blksz);
  831. if (!temp_ptr)
  832. goto fail;
  833. ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
  834. inodeno--;
  835. itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
  836. (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
  837. inodes_per_block;
  838. blkoff = (inodeno % inodes_per_block) * fs->inodesz;
  839. ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
  840. temp_ptr);
  841. if (ext4fs_log_journal(temp_ptr, itable_blkno))
  842. goto fail;
  843. memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
  844. if (ext4fs_put_metadata(temp_ptr, itable_blkno))
  845. goto fail;
  846. /* copy the file content into data blocks */
  847. if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
  848. printf("Error in copying content\n");
  849. goto fail;
  850. }
  851. ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
  852. parent_inodeno--;
  853. parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
  854. (parent_inodeno %
  855. __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
  856. blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
  857. if (parent_itable_blkno != itable_blkno) {
  858. memset(temp_ptr, '\0', fs->blksz);
  859. ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk,
  860. 0, fs->blksz, temp_ptr);
  861. if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
  862. goto fail;
  863. memcpy(temp_ptr + blkoff, g_parent_inode,
  864. sizeof(struct ext2_inode));
  865. if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
  866. goto fail;
  867. free(temp_ptr);
  868. } else {
  869. /*
  870. * If parent and child fall in same inode table block
  871. * both should be kept in 1 buffer
  872. */
  873. memcpy(temp_ptr + blkoff, g_parent_inode,
  874. sizeof(struct ext2_inode));
  875. gd_index--;
  876. if (ext4fs_put_metadata(temp_ptr, itable_blkno))
  877. goto fail;
  878. free(temp_ptr);
  879. }
  880. ext4fs_update();
  881. ext4fs_deinit();
  882. fs->first_pass_bbmap = 0;
  883. fs->curr_blkno = 0;
  884. fs->first_pass_ibmap = 0;
  885. fs->curr_inode_no = 0;
  886. free(inode_buffer);
  887. free(g_parent_inode);
  888. g_parent_inode = NULL;
  889. return 0;
  890. fail:
  891. ext4fs_deinit();
  892. free(inode_buffer);
  893. free(g_parent_inode);
  894. g_parent_inode = NULL;
  895. return -1;
  896. }