ext4_write.c 26 KB

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