ext4fs.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  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. * This program is free software; you can redistribute it and/or modify
  22. * it under the terms of the GNU General Public License as published by
  23. * the Free Software Foundation; either version 2 of the License, or
  24. * (at your option) any later version.
  25. *
  26. * This program is distributed in the hope that it will be useful,
  27. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. * GNU General Public License for more details.
  30. *
  31. * You should have received a copy of the GNU General Public License
  32. * along with this program; if not, write to the Free Software
  33. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  34. */
  35. #include <common.h>
  36. #include <malloc.h>
  37. #include <ext_common.h>
  38. #include <ext4fs.h>
  39. #include <linux/stat.h>
  40. #include <linux/time.h>
  41. #include <asm/byteorder.h>
  42. #include "ext4_common.h"
  43. int ext4fs_symlinknest;
  44. block_dev_desc_t *ext4_dev_desc;
  45. struct ext_filesystem *get_fs(void)
  46. {
  47. if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL)
  48. printf("Invalid Input Arguments %s\n", __func__);
  49. return ext4_dev_desc->priv;
  50. }
  51. int init_fs(block_dev_desc_t *dev_desc)
  52. {
  53. struct ext_filesystem *fs;
  54. if (dev_desc == NULL) {
  55. printf("Invalid Input Arguments %s\n", __func__);
  56. return -EINVAL;
  57. }
  58. fs = zalloc(sizeof(struct ext_filesystem));
  59. if (fs == NULL) {
  60. printf("malloc failed: %s\n", __func__);
  61. return -ENOMEM;
  62. }
  63. fs->dev_desc = dev_desc;
  64. dev_desc->priv = fs;
  65. return 0;
  66. }
  67. void deinit_fs(block_dev_desc_t *dev_desc)
  68. {
  69. if (dev_desc == NULL) {
  70. printf("Invalid Input Arguments %s\n", __func__);
  71. return;
  72. }
  73. free(dev_desc->priv);
  74. dev_desc->priv = NULL;
  75. }
  76. void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
  77. {
  78. if ((node != &ext4fs_root->diropen) && (node != currroot))
  79. free(node);
  80. }
  81. /*
  82. * Taken from openmoko-kernel mailing list: By Andy green
  83. * Optimized read file API : collects and defers contiguous sector
  84. * reads into one potentially more efficient larger sequential read action
  85. */
  86. int ext4fs_read_file(struct ext2fs_node *node, int pos,
  87. unsigned int len, char *buf)
  88. {
  89. int i;
  90. int blockcnt;
  91. int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
  92. int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
  93. unsigned int filesize = __le32_to_cpu(node->inode.size);
  94. int previous_block_number = -1;
  95. int delayed_start = 0;
  96. int delayed_extent = 0;
  97. int delayed_skipfirst = 0;
  98. int delayed_next = 0;
  99. char *delayed_buf = NULL;
  100. short status;
  101. /* Adjust len so it we can't read past the end of the file. */
  102. if (len > filesize)
  103. len = filesize;
  104. blockcnt = ((len + pos) + blocksize - 1) / blocksize;
  105. for (i = pos / blocksize; i < blockcnt; i++) {
  106. int blknr;
  107. int blockoff = pos % blocksize;
  108. int blockend = blocksize;
  109. int skipfirst = 0;
  110. blknr = read_allocated_block(&(node->inode), i);
  111. if (blknr < 0)
  112. return -1;
  113. blknr = blknr << log2blocksize;
  114. /* Last block. */
  115. if (i == blockcnt - 1) {
  116. blockend = (len + pos) % blocksize;
  117. /* The last portion is exactly blocksize. */
  118. if (!blockend)
  119. blockend = blocksize;
  120. }
  121. /* First block. */
  122. if (i == pos / blocksize) {
  123. skipfirst = blockoff;
  124. blockend -= skipfirst;
  125. }
  126. if (blknr) {
  127. int status;
  128. if (previous_block_number != -1) {
  129. if (delayed_next == blknr) {
  130. delayed_extent += blockend;
  131. delayed_next += blockend >> SECTOR_BITS;
  132. } else { /* spill */
  133. status = ext4fs_devread(delayed_start,
  134. delayed_skipfirst,
  135. delayed_extent,
  136. delayed_buf);
  137. if (status == 0)
  138. return -1;
  139. previous_block_number = blknr;
  140. delayed_start = blknr;
  141. delayed_extent = blockend;
  142. delayed_skipfirst = skipfirst;
  143. delayed_buf = buf;
  144. delayed_next = blknr +
  145. (blockend >> SECTOR_BITS);
  146. }
  147. } else {
  148. previous_block_number = blknr;
  149. delayed_start = blknr;
  150. delayed_extent = blockend;
  151. delayed_skipfirst = skipfirst;
  152. delayed_buf = buf;
  153. delayed_next = blknr +
  154. (blockend >> SECTOR_BITS);
  155. }
  156. } else {
  157. if (previous_block_number != -1) {
  158. /* spill */
  159. status = ext4fs_devread(delayed_start,
  160. delayed_skipfirst,
  161. delayed_extent,
  162. delayed_buf);
  163. if (status == 0)
  164. return -1;
  165. previous_block_number = -1;
  166. }
  167. memset(buf, 0, blocksize - skipfirst);
  168. }
  169. buf += blocksize - skipfirst;
  170. }
  171. if (previous_block_number != -1) {
  172. /* spill */
  173. status = ext4fs_devread(delayed_start,
  174. delayed_skipfirst, delayed_extent,
  175. delayed_buf);
  176. if (status == 0)
  177. return -1;
  178. previous_block_number = -1;
  179. }
  180. return len;
  181. }
  182. int ext4fs_ls(const char *dirname)
  183. {
  184. struct ext2fs_node *dirnode;
  185. int status;
  186. if (dirname == NULL)
  187. return 0;
  188. status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
  189. FILETYPE_DIRECTORY);
  190. if (status != 1) {
  191. printf("** Can not find directory. **\n");
  192. return 1;
  193. }
  194. ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
  195. ext4fs_free_node(dirnode, &ext4fs_root->diropen);
  196. return 0;
  197. }
  198. int ext4fs_read(char *buf, unsigned len)
  199. {
  200. if (ext4fs_root == NULL || ext4fs_file == NULL)
  201. return 0;
  202. return ext4fs_read_file(ext4fs_file, 0, len, buf);
  203. }
  204. #if defined(CONFIG_CMD_EXT4_WRITE)
  205. static void ext4fs_update(void)
  206. {
  207. short i;
  208. ext4fs_update_journal();
  209. struct ext_filesystem *fs = get_fs();
  210. /* update super block */
  211. put_ext4((uint64_t)(SUPERBLOCK_SIZE),
  212. (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
  213. /* update block groups */
  214. for (i = 0; i < fs->no_blkgrp; i++) {
  215. fs->gd[i].bg_checksum = ext4fs_checksum_update(i);
  216. put_ext4((uint64_t)(fs->gd[i].block_id * fs->blksz),
  217. fs->blk_bmaps[i], fs->blksz);
  218. }
  219. /* update inode table groups */
  220. for (i = 0; i < fs->no_blkgrp; i++) {
  221. put_ext4((uint64_t) (fs->gd[i].inode_id * fs->blksz),
  222. fs->inode_bmaps[i], fs->blksz);
  223. }
  224. /* update the block group descriptor table */
  225. put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz),
  226. (struct ext2_block_group *)fs->gdtable,
  227. (fs->blksz * fs->no_blk_pergdt));
  228. ext4fs_dump_metadata();
  229. gindex = 0;
  230. gd_index = 0;
  231. }
  232. int ext4fs_get_bgdtable(void)
  233. {
  234. int status;
  235. int grp_desc_size;
  236. struct ext_filesystem *fs = get_fs();
  237. grp_desc_size = sizeof(struct ext2_block_group);
  238. fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
  239. if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
  240. fs->no_blk_pergdt++;
  241. /* allocate memory for gdtable */
  242. fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
  243. if (!fs->gdtable)
  244. return -ENOMEM;
  245. /* read the group descriptor table */
  246. status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0,
  247. fs->blksz * fs->no_blk_pergdt, fs->gdtable);
  248. if (status == 0)
  249. goto fail;
  250. if (ext4fs_log_gdt(fs->gdtable)) {
  251. printf("Error in ext4fs_log_gdt\n");
  252. return -1;
  253. }
  254. return 0;
  255. fail:
  256. free(fs->gdtable);
  257. fs->gdtable = NULL;
  258. return -1;
  259. }
  260. static void delete_single_indirect_block(struct ext2_inode *inode)
  261. {
  262. struct ext2_block_group *gd = NULL;
  263. static int prev_bg_bmap_idx = -1;
  264. long int blknr;
  265. int remainder;
  266. int bg_idx;
  267. int status;
  268. unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
  269. struct ext_filesystem *fs = get_fs();
  270. char *journal_buffer = zalloc(fs->blksz);
  271. if (!journal_buffer) {
  272. printf("No memory\n");
  273. return;
  274. }
  275. /* get block group descriptor table */
  276. gd = (struct ext2_block_group *)fs->gdtable;
  277. /* deleting the single indirect block associated with inode */
  278. if (inode->b.blocks.indir_block != 0) {
  279. debug("SIPB releasing %u\n", inode->b.blocks.indir_block);
  280. blknr = inode->b.blocks.indir_block;
  281. if (fs->blksz != 1024) {
  282. bg_idx = blknr / blk_per_grp;
  283. } else {
  284. bg_idx = blknr / blk_per_grp;
  285. remainder = blknr % blk_per_grp;
  286. if (!remainder)
  287. bg_idx--;
  288. }
  289. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
  290. gd[bg_idx].free_blocks++;
  291. fs->sb->free_blocks++;
  292. /* journal backup */
  293. if (prev_bg_bmap_idx != bg_idx) {
  294. status =
  295. ext4fs_devread(gd[bg_idx].block_id *
  296. fs->sect_perblk, 0, fs->blksz,
  297. journal_buffer);
  298. if (status == 0)
  299. goto fail;
  300. if (ext4fs_log_journal
  301. (journal_buffer, gd[bg_idx].block_id))
  302. goto fail;
  303. prev_bg_bmap_idx = bg_idx;
  304. }
  305. }
  306. fail:
  307. free(journal_buffer);
  308. }
  309. static void delete_double_indirect_block(struct ext2_inode *inode)
  310. {
  311. int i;
  312. short status;
  313. static int prev_bg_bmap_idx = -1;
  314. long int blknr;
  315. int remainder;
  316. int bg_idx;
  317. unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
  318. unsigned int *di_buffer = NULL;
  319. unsigned int *DIB_start_addr = NULL;
  320. struct ext2_block_group *gd = NULL;
  321. struct ext_filesystem *fs = get_fs();
  322. char *journal_buffer = zalloc(fs->blksz);
  323. if (!journal_buffer) {
  324. printf("No memory\n");
  325. return;
  326. }
  327. /* get the block group descriptor table */
  328. gd = (struct ext2_block_group *)fs->gdtable;
  329. if (inode->b.blocks.double_indir_block != 0) {
  330. di_buffer = zalloc(fs->blksz);
  331. if (!di_buffer) {
  332. printf("No memory\n");
  333. return;
  334. }
  335. DIB_start_addr = (unsigned int *)di_buffer;
  336. blknr = inode->b.blocks.double_indir_block;
  337. status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
  338. (char *)di_buffer);
  339. for (i = 0; i < fs->blksz / sizeof(int); i++) {
  340. if (*di_buffer == 0)
  341. break;
  342. debug("DICB releasing %u\n", *di_buffer);
  343. if (fs->blksz != 1024) {
  344. bg_idx = (*di_buffer) / blk_per_grp;
  345. } else {
  346. bg_idx = (*di_buffer) / blk_per_grp;
  347. remainder = (*di_buffer) % blk_per_grp;
  348. if (!remainder)
  349. bg_idx--;
  350. }
  351. ext4fs_reset_block_bmap(*di_buffer,
  352. fs->blk_bmaps[bg_idx], bg_idx);
  353. di_buffer++;
  354. gd[bg_idx].free_blocks++;
  355. fs->sb->free_blocks++;
  356. /* journal backup */
  357. if (prev_bg_bmap_idx != bg_idx) {
  358. status = ext4fs_devread(gd[bg_idx].block_id
  359. * fs->sect_perblk, 0,
  360. fs->blksz,
  361. journal_buffer);
  362. if (status == 0)
  363. goto fail;
  364. if (ext4fs_log_journal(journal_buffer,
  365. gd[bg_idx].block_id))
  366. goto fail;
  367. prev_bg_bmap_idx = bg_idx;
  368. }
  369. }
  370. /* removing the parent double indirect block */
  371. blknr = inode->b.blocks.double_indir_block;
  372. if (fs->blksz != 1024) {
  373. bg_idx = blknr / blk_per_grp;
  374. } else {
  375. bg_idx = blknr / blk_per_grp;
  376. remainder = blknr % blk_per_grp;
  377. if (!remainder)
  378. bg_idx--;
  379. }
  380. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
  381. gd[bg_idx].free_blocks++;
  382. fs->sb->free_blocks++;
  383. /* journal backup */
  384. if (prev_bg_bmap_idx != bg_idx) {
  385. memset(journal_buffer, '\0', fs->blksz);
  386. status = ext4fs_devread(gd[bg_idx].block_id *
  387. fs->sect_perblk, 0, fs->blksz,
  388. journal_buffer);
  389. if (status == 0)
  390. goto fail;
  391. if (ext4fs_log_journal(journal_buffer,
  392. gd[bg_idx].block_id))
  393. goto fail;
  394. prev_bg_bmap_idx = bg_idx;
  395. }
  396. debug("DIPB releasing %ld\n", blknr);
  397. }
  398. fail:
  399. free(DIB_start_addr);
  400. free(journal_buffer);
  401. }
  402. static void delete_triple_indirect_block(struct ext2_inode *inode)
  403. {
  404. int i, j;
  405. short status;
  406. static int prev_bg_bmap_idx = -1;
  407. long int blknr;
  408. int remainder;
  409. int bg_idx;
  410. unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
  411. unsigned int *tigp_buffer = NULL;
  412. unsigned int *tib_start_addr = NULL;
  413. unsigned int *tip_buffer = NULL;
  414. unsigned int *tipb_start_addr = NULL;
  415. struct ext2_block_group *gd = NULL;
  416. struct ext_filesystem *fs = get_fs();
  417. char *journal_buffer = zalloc(fs->blksz);
  418. if (!journal_buffer) {
  419. printf("No memory\n");
  420. return;
  421. }
  422. /* get block group descriptor table */
  423. gd = (struct ext2_block_group *)fs->gdtable;
  424. if (inode->b.blocks.triple_indir_block != 0) {
  425. tigp_buffer = zalloc(fs->blksz);
  426. if (!tigp_buffer) {
  427. printf("No memory\n");
  428. return;
  429. }
  430. tib_start_addr = (unsigned int *)tigp_buffer;
  431. blknr = inode->b.blocks.triple_indir_block;
  432. status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
  433. (char *)tigp_buffer);
  434. for (i = 0; i < fs->blksz / sizeof(int); i++) {
  435. if (*tigp_buffer == 0)
  436. break;
  437. debug("tigp buffer releasing %u\n", *tigp_buffer);
  438. tip_buffer = zalloc(fs->blksz);
  439. if (!tip_buffer)
  440. goto fail;
  441. tipb_start_addr = (unsigned int *)tip_buffer;
  442. status = ext4fs_devread((*tigp_buffer) *
  443. fs->sect_perblk, 0, fs->blksz,
  444. (char *)tip_buffer);
  445. for (j = 0; j < fs->blksz / sizeof(int); j++) {
  446. if (*tip_buffer == 0)
  447. break;
  448. if (fs->blksz != 1024) {
  449. bg_idx = (*tip_buffer) / blk_per_grp;
  450. } else {
  451. bg_idx = (*tip_buffer) / blk_per_grp;
  452. remainder = (*tip_buffer) % blk_per_grp;
  453. if (!remainder)
  454. bg_idx--;
  455. }
  456. ext4fs_reset_block_bmap(*tip_buffer,
  457. fs->blk_bmaps[bg_idx],
  458. bg_idx);
  459. tip_buffer++;
  460. gd[bg_idx].free_blocks++;
  461. fs->sb->free_blocks++;
  462. /* journal backup */
  463. if (prev_bg_bmap_idx != bg_idx) {
  464. status =
  465. ext4fs_devread(gd[bg_idx].block_id *
  466. fs->sect_perblk, 0,
  467. fs->blksz,
  468. journal_buffer);
  469. if (status == 0)
  470. goto fail;
  471. if (ext4fs_log_journal(journal_buffer,
  472. gd[bg_idx].
  473. block_id))
  474. goto fail;
  475. prev_bg_bmap_idx = bg_idx;
  476. }
  477. }
  478. free(tipb_start_addr);
  479. tipb_start_addr = NULL;
  480. /*
  481. * removing the grand parent blocks
  482. * which is connected to inode
  483. */
  484. if (fs->blksz != 1024) {
  485. bg_idx = (*tigp_buffer) / blk_per_grp;
  486. } else {
  487. bg_idx = (*tigp_buffer) / blk_per_grp;
  488. remainder = (*tigp_buffer) % blk_per_grp;
  489. if (!remainder)
  490. bg_idx--;
  491. }
  492. ext4fs_reset_block_bmap(*tigp_buffer,
  493. fs->blk_bmaps[bg_idx], bg_idx);
  494. tigp_buffer++;
  495. gd[bg_idx].free_blocks++;
  496. fs->sb->free_blocks++;
  497. /* journal backup */
  498. if (prev_bg_bmap_idx != bg_idx) {
  499. memset(journal_buffer, '\0', fs->blksz);
  500. status =
  501. ext4fs_devread(gd[bg_idx].block_id *
  502. fs->sect_perblk, 0,
  503. fs->blksz, journal_buffer);
  504. if (status == 0)
  505. goto fail;
  506. if (ext4fs_log_journal(journal_buffer,
  507. gd[bg_idx].block_id))
  508. goto fail;
  509. prev_bg_bmap_idx = bg_idx;
  510. }
  511. }
  512. /* removing the grand parent triple indirect block */
  513. blknr = inode->b.blocks.triple_indir_block;
  514. if (fs->blksz != 1024) {
  515. bg_idx = blknr / blk_per_grp;
  516. } else {
  517. bg_idx = blknr / blk_per_grp;
  518. remainder = blknr % blk_per_grp;
  519. if (!remainder)
  520. bg_idx--;
  521. }
  522. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
  523. gd[bg_idx].free_blocks++;
  524. fs->sb->free_blocks++;
  525. /* journal backup */
  526. if (prev_bg_bmap_idx != bg_idx) {
  527. memset(journal_buffer, '\0', fs->blksz);
  528. status = ext4fs_devread(gd[bg_idx].block_id *
  529. fs->sect_perblk, 0, fs->blksz,
  530. journal_buffer);
  531. if (status == 0)
  532. goto fail;
  533. if (ext4fs_log_journal(journal_buffer,
  534. gd[bg_idx].block_id))
  535. goto fail;
  536. prev_bg_bmap_idx = bg_idx;
  537. }
  538. debug("tigp buffer itself releasing %ld\n", blknr);
  539. }
  540. fail:
  541. free(tib_start_addr);
  542. free(tipb_start_addr);
  543. free(journal_buffer);
  544. }
  545. static int ext4fs_delete_file(int inodeno)
  546. {
  547. struct ext2_inode inode;
  548. short status;
  549. int i;
  550. int remainder;
  551. long int blknr;
  552. int bg_idx;
  553. int ibmap_idx;
  554. char *read_buffer = NULL;
  555. char *start_block_address = NULL;
  556. unsigned int no_blocks;
  557. static int prev_bg_bmap_idx = -1;
  558. unsigned int inodes_per_block;
  559. long int blkno;
  560. unsigned int blkoff;
  561. unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
  562. unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
  563. struct ext2_inode *inode_buffer = NULL;
  564. struct ext2_block_group *gd = NULL;
  565. struct ext_filesystem *fs = get_fs();
  566. char *journal_buffer = zalloc(fs->blksz);
  567. if (!journal_buffer)
  568. return -ENOMEM;
  569. /* get the block group descriptor table */
  570. gd = (struct ext2_block_group *)fs->gdtable;
  571. status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
  572. if (status == 0)
  573. goto fail;
  574. /* read the block no allocated to a file */
  575. no_blocks = inode.size / fs->blksz;
  576. if (inode.size % fs->blksz)
  577. no_blocks++;
  578. if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
  579. struct ext2fs_node *node_inode =
  580. zalloc(sizeof(struct ext2fs_node));
  581. if (!node_inode)
  582. goto fail;
  583. node_inode->data = ext4fs_root;
  584. node_inode->ino = inodeno;
  585. node_inode->inode_read = 0;
  586. memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
  587. for (i = 0; i < no_blocks; i++) {
  588. blknr = read_allocated_block(&(node_inode->inode), i);
  589. if (fs->blksz != 1024) {
  590. bg_idx = blknr / blk_per_grp;
  591. } else {
  592. bg_idx = blknr / blk_per_grp;
  593. remainder = blknr % blk_per_grp;
  594. if (!remainder)
  595. bg_idx--;
  596. }
  597. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
  598. bg_idx);
  599. debug("EXT4_EXTENTS Block releasing %ld: %d\n",
  600. blknr, bg_idx);
  601. gd[bg_idx].free_blocks++;
  602. fs->sb->free_blocks++;
  603. /* journal backup */
  604. if (prev_bg_bmap_idx != bg_idx) {
  605. status =
  606. ext4fs_devread(gd[bg_idx].block_id *
  607. fs->sect_perblk, 0,
  608. fs->blksz, journal_buffer);
  609. if (status == 0)
  610. goto fail;
  611. if (ext4fs_log_journal(journal_buffer,
  612. gd[bg_idx].block_id))
  613. goto fail;
  614. prev_bg_bmap_idx = bg_idx;
  615. }
  616. }
  617. if (node_inode) {
  618. free(node_inode);
  619. node_inode = NULL;
  620. }
  621. } else {
  622. delete_single_indirect_block(&inode);
  623. delete_double_indirect_block(&inode);
  624. delete_triple_indirect_block(&inode);
  625. /* read the block no allocated to a file */
  626. no_blocks = inode.size / fs->blksz;
  627. if (inode.size % fs->blksz)
  628. no_blocks++;
  629. for (i = 0; i < no_blocks; i++) {
  630. blknr = read_allocated_block(&inode, i);
  631. if (fs->blksz != 1024) {
  632. bg_idx = blknr / blk_per_grp;
  633. } else {
  634. bg_idx = blknr / blk_per_grp;
  635. remainder = blknr % blk_per_grp;
  636. if (!remainder)
  637. bg_idx--;
  638. }
  639. ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
  640. bg_idx);
  641. debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
  642. gd[bg_idx].free_blocks++;
  643. fs->sb->free_blocks++;
  644. /* journal backup */
  645. if (prev_bg_bmap_idx != bg_idx) {
  646. memset(journal_buffer, '\0', fs->blksz);
  647. status = ext4fs_devread(gd[bg_idx].block_id
  648. * fs->sect_perblk,
  649. 0, fs->blksz,
  650. journal_buffer);
  651. if (status == 0)
  652. goto fail;
  653. if (ext4fs_log_journal(journal_buffer,
  654. gd[bg_idx].block_id))
  655. goto fail;
  656. prev_bg_bmap_idx = bg_idx;
  657. }
  658. }
  659. }
  660. /* from the inode no to blockno */
  661. inodes_per_block = fs->blksz / fs->inodesz;
  662. ibmap_idx = inodeno / inode_per_grp;
  663. /* get the block no */
  664. inodeno--;
  665. blkno = __le32_to_cpu(gd[ibmap_idx].inode_table_id) +
  666. (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block;
  667. /* get the offset of the inode */
  668. blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
  669. /* read the block no containing the inode */
  670. read_buffer = zalloc(fs->blksz);
  671. if (!read_buffer)
  672. goto fail;
  673. start_block_address = read_buffer;
  674. status = ext4fs_devread(blkno * fs->sect_perblk,
  675. 0, fs->blksz, read_buffer);
  676. if (status == 0)
  677. goto fail;
  678. if (ext4fs_log_journal(read_buffer, blkno))
  679. goto fail;
  680. read_buffer = read_buffer + blkoff;
  681. inode_buffer = (struct ext2_inode *)read_buffer;
  682. memset(inode_buffer, '\0', sizeof(struct ext2_inode));
  683. /* write the inode to original position in inode table */
  684. if (ext4fs_put_metadata(start_block_address, blkno))
  685. goto fail;
  686. /* update the respective inode bitmaps */
  687. inodeno++;
  688. ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
  689. gd[ibmap_idx].free_inodes++;
  690. fs->sb->free_inodes++;
  691. /* journal backup */
  692. memset(journal_buffer, '\0', fs->blksz);
  693. status = ext4fs_devread(gd[ibmap_idx].inode_id *
  694. fs->sect_perblk, 0, fs->blksz, journal_buffer);
  695. if (status == 0)
  696. goto fail;
  697. if (ext4fs_log_journal(journal_buffer, gd[ibmap_idx].inode_id))
  698. goto fail;
  699. ext4fs_update();
  700. ext4fs_deinit();
  701. if (ext4fs_init() != 0) {
  702. printf("error in File System init\n");
  703. goto fail;
  704. }
  705. free(start_block_address);
  706. free(journal_buffer);
  707. return 0;
  708. fail:
  709. free(start_block_address);
  710. free(journal_buffer);
  711. return -1;
  712. }
  713. int ext4fs_init(void)
  714. {
  715. short status;
  716. int i;
  717. unsigned int real_free_blocks = 0;
  718. struct ext_filesystem *fs = get_fs();
  719. /* populate fs */
  720. fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
  721. fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
  722. fs->sect_perblk = fs->blksz / SECTOR_SIZE;
  723. /* get the superblock */
  724. fs->sb = zalloc(SUPERBLOCK_SIZE);
  725. if (!fs->sb)
  726. return -ENOMEM;
  727. if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
  728. (char *)fs->sb))
  729. goto fail;
  730. /* init journal */
  731. if (ext4fs_init_journal())
  732. goto fail;
  733. /* get total no of blockgroups */
  734. fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
  735. (ext4fs_root->sblock.total_blocks -
  736. ext4fs_root->sblock.first_data_block),
  737. ext4fs_root->sblock.blocks_per_group);
  738. /* get the block group descriptor table */
  739. fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
  740. if (ext4fs_get_bgdtable() == -1) {
  741. printf("Error in getting the block group descriptor table\n");
  742. goto fail;
  743. }
  744. fs->gd = (struct ext2_block_group *)fs->gdtable;
  745. /* load all the available bitmap block of the partition */
  746. fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
  747. if (!fs->blk_bmaps)
  748. goto fail;
  749. for (i = 0; i < fs->no_blkgrp; i++) {
  750. fs->blk_bmaps[i] = zalloc(fs->blksz);
  751. if (!fs->blk_bmaps[i])
  752. goto fail;
  753. }
  754. for (i = 0; i < fs->no_blkgrp; i++) {
  755. status =
  756. ext4fs_devread(fs->gd[i].block_id * fs->sect_perblk, 0,
  757. fs->blksz, (char *)fs->blk_bmaps[i]);
  758. if (status == 0)
  759. goto fail;
  760. }
  761. /* load all the available inode bitmap of the partition */
  762. fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
  763. if (!fs->inode_bmaps)
  764. goto fail;
  765. for (i = 0; i < fs->no_blkgrp; i++) {
  766. fs->inode_bmaps[i] = zalloc(fs->blksz);
  767. if (!fs->inode_bmaps[i])
  768. goto fail;
  769. }
  770. for (i = 0; i < fs->no_blkgrp; i++) {
  771. status = ext4fs_devread(fs->gd[i].inode_id * fs->sect_perblk,
  772. 0, fs->blksz,
  773. (char *)fs->inode_bmaps[i]);
  774. if (status == 0)
  775. goto fail;
  776. }
  777. /*
  778. * check filesystem consistency with free blocks of file system
  779. * some time we observed that superblock freeblocks does not match
  780. * with the blockgroups freeblocks when improper
  781. * reboot of a linux kernel
  782. */
  783. for (i = 0; i < fs->no_blkgrp; i++)
  784. real_free_blocks = real_free_blocks + fs->gd[i].free_blocks;
  785. if (real_free_blocks != fs->sb->free_blocks)
  786. fs->sb->free_blocks = real_free_blocks;
  787. return 0;
  788. fail:
  789. ext4fs_deinit();
  790. return -1;
  791. }
  792. void ext4fs_deinit(void)
  793. {
  794. int i;
  795. struct ext2_inode inode_journal;
  796. struct journal_superblock_t *jsb;
  797. long int blknr;
  798. struct ext_filesystem *fs = get_fs();
  799. /* free journal */
  800. char *temp_buff = zalloc(fs->blksz);
  801. if (temp_buff) {
  802. ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
  803. &inode_journal);
  804. blknr = read_allocated_block(&inode_journal,
  805. EXT2_JOURNAL_SUPERBLOCK);
  806. ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
  807. temp_buff);
  808. jsb = (struct journal_superblock_t *)temp_buff;
  809. jsb->s_start = cpu_to_be32(0);
  810. put_ext4((uint64_t) (blknr * fs->blksz),
  811. (struct journal_superblock_t *)temp_buff, fs->blksz);
  812. free(temp_buff);
  813. }
  814. ext4fs_free_journal();
  815. /* get the superblock */
  816. ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb);
  817. fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
  818. put_ext4((uint64_t)(SUPERBLOCK_SIZE),
  819. (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
  820. free(fs->sb);
  821. fs->sb = NULL;
  822. if (fs->blk_bmaps) {
  823. for (i = 0; i < fs->no_blkgrp; i++) {
  824. free(fs->blk_bmaps[i]);
  825. fs->blk_bmaps[i] = NULL;
  826. }
  827. free(fs->blk_bmaps);
  828. fs->blk_bmaps = NULL;
  829. }
  830. if (fs->inode_bmaps) {
  831. for (i = 0; i < fs->no_blkgrp; i++) {
  832. free(fs->inode_bmaps[i]);
  833. fs->inode_bmaps[i] = NULL;
  834. }
  835. free(fs->inode_bmaps);
  836. fs->inode_bmaps = NULL;
  837. }
  838. free(fs->gdtable);
  839. fs->gdtable = NULL;
  840. fs->gd = NULL;
  841. /*
  842. * reinitiliazed the global inode and
  843. * block bitmap first execution check variables
  844. */
  845. fs->first_pass_ibmap = 0;
  846. fs->first_pass_bbmap = 0;
  847. fs->curr_inode_no = 0;
  848. fs->curr_blkno = 0;
  849. }
  850. static int ext4fs_write_file(struct ext2_inode *file_inode,
  851. int pos, unsigned int len, char *buf)
  852. {
  853. int i;
  854. int blockcnt;
  855. int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
  856. unsigned int filesize = __le32_to_cpu(file_inode->size);
  857. struct ext_filesystem *fs = get_fs();
  858. int previous_block_number = -1;
  859. int delayed_start = 0;
  860. int delayed_extent = 0;
  861. int delayed_skipfirst = 0;
  862. int delayed_next = 0;
  863. char *delayed_buf = NULL;
  864. /* Adjust len so it we can't read past the end of the file. */
  865. if (len > filesize)
  866. len = filesize;
  867. blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
  868. for (i = pos / fs->blksz; i < blockcnt; i++) {
  869. long int blknr;
  870. int blockend = fs->blksz;
  871. int skipfirst = 0;
  872. blknr = read_allocated_block(file_inode, i);
  873. if (blknr < 0)
  874. return -1;
  875. blknr = blknr << log2blocksize;
  876. if (blknr) {
  877. if (previous_block_number != -1) {
  878. if (delayed_next == blknr) {
  879. delayed_extent += blockend;
  880. delayed_next += blockend >> SECTOR_BITS;
  881. } else { /* spill */
  882. put_ext4((uint64_t) (delayed_start *
  883. SECTOR_SIZE),
  884. delayed_buf,
  885. (uint32_t) delayed_extent);
  886. previous_block_number = blknr;
  887. delayed_start = blknr;
  888. delayed_extent = blockend;
  889. delayed_skipfirst = skipfirst;
  890. delayed_buf = buf;
  891. delayed_next = blknr +
  892. (blockend >> SECTOR_BITS);
  893. }
  894. } else {
  895. previous_block_number = blknr;
  896. delayed_start = blknr;
  897. delayed_extent = blockend;
  898. delayed_skipfirst = skipfirst;
  899. delayed_buf = buf;
  900. delayed_next = blknr +
  901. (blockend >> SECTOR_BITS);
  902. }
  903. } else {
  904. if (previous_block_number != -1) {
  905. /* spill */
  906. put_ext4((uint64_t) (delayed_start *
  907. SECTOR_SIZE), delayed_buf,
  908. (uint32_t) delayed_extent);
  909. previous_block_number = -1;
  910. }
  911. memset(buf, 0, fs->blksz - skipfirst);
  912. }
  913. buf += fs->blksz - skipfirst;
  914. }
  915. if (previous_block_number != -1) {
  916. /* spill */
  917. put_ext4((uint64_t) (delayed_start * SECTOR_SIZE),
  918. delayed_buf, (uint32_t) delayed_extent);
  919. previous_block_number = -1;
  920. }
  921. return len;
  922. }
  923. int ext4fs_write(const char *fname, unsigned char *buffer,
  924. unsigned long sizebytes)
  925. {
  926. int ret = 0;
  927. struct ext2_inode *file_inode = NULL;
  928. unsigned char *inode_buffer = NULL;
  929. int parent_inodeno;
  930. int inodeno;
  931. time_t timestamp = 0;
  932. uint64_t bytes_reqd_for_file;
  933. unsigned int blks_reqd_for_file;
  934. unsigned int blocks_remaining;
  935. int existing_file_inodeno;
  936. char filename[256];
  937. char *temp_ptr = NULL;
  938. long int itable_blkno;
  939. long int parent_itable_blkno;
  940. long int blkoff;
  941. struct ext2_sblock *sblock = &(ext4fs_root->sblock);
  942. unsigned int inodes_per_block;
  943. unsigned int ibmap_idx;
  944. struct ext_filesystem *fs = get_fs();
  945. g_parent_inode = zalloc(sizeof(struct ext2_inode));
  946. if (!g_parent_inode)
  947. goto fail;
  948. if (ext4fs_init() != 0) {
  949. printf("error in File System init\n");
  950. return -1;
  951. }
  952. inodes_per_block = fs->blksz / fs->inodesz;
  953. parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
  954. if (parent_inodeno == -1)
  955. goto fail;
  956. if (ext4fs_iget(parent_inodeno, g_parent_inode))
  957. goto fail;
  958. /* check if the filename is already present in root */
  959. existing_file_inodeno = ext4fs_filename_check(filename);
  960. if (existing_file_inodeno != -1) {
  961. ret = ext4fs_delete_file(existing_file_inodeno);
  962. fs->first_pass_bbmap = 0;
  963. fs->curr_blkno = 0;
  964. fs->first_pass_ibmap = 0;
  965. fs->curr_inode_no = 0;
  966. if (ret)
  967. goto fail;
  968. }
  969. /* calucalate how many blocks required */
  970. bytes_reqd_for_file = sizebytes;
  971. blks_reqd_for_file = bytes_reqd_for_file / fs->blksz;
  972. if (bytes_reqd_for_file % fs->blksz != 0) {
  973. blks_reqd_for_file++;
  974. debug("total bytes for a file %u\n", blks_reqd_for_file);
  975. }
  976. blocks_remaining = blks_reqd_for_file;
  977. /* test for available space in partition */
  978. if (fs->sb->free_blocks < blks_reqd_for_file) {
  979. printf("Not enough space on partition !!!\n");
  980. goto fail;
  981. }
  982. ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
  983. /* prepare file inode */
  984. inode_buffer = zalloc(fs->inodesz);
  985. if (!inode_buffer)
  986. goto fail;
  987. file_inode = (struct ext2_inode *)inode_buffer;
  988. file_inode->mode = S_IFREG | S_IRWXU |
  989. S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
  990. /* ToDo: Update correct time */
  991. file_inode->mtime = timestamp;
  992. file_inode->atime = timestamp;
  993. file_inode->ctime = timestamp;
  994. file_inode->nlinks = 1;
  995. file_inode->size = sizebytes;
  996. /* Allocate data blocks */
  997. ext4fs_allocate_blocks(file_inode, blocks_remaining,
  998. &blks_reqd_for_file);
  999. file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
  1000. temp_ptr = zalloc(fs->blksz);
  1001. if (!temp_ptr)
  1002. goto fail;
  1003. ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
  1004. inodeno--;
  1005. itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].inode_table_id) +
  1006. (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
  1007. inodes_per_block;
  1008. blkoff = (inodeno % inodes_per_block) * fs->inodesz;
  1009. ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
  1010. if (ext4fs_log_journal(temp_ptr, itable_blkno))
  1011. goto fail;
  1012. memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
  1013. if (ext4fs_put_metadata(temp_ptr, itable_blkno))
  1014. goto fail;
  1015. /* copy the file content into data blocks */
  1016. if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
  1017. printf("Error in copying content\n");
  1018. goto fail;
  1019. }
  1020. ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
  1021. parent_inodeno--;
  1022. parent_itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].inode_table_id) +
  1023. (parent_inodeno %
  1024. __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
  1025. blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
  1026. if (parent_itable_blkno != itable_blkno) {
  1027. memset(temp_ptr, '\0', fs->blksz);
  1028. ext4fs_devread(parent_itable_blkno * fs->sect_perblk,
  1029. 0, fs->blksz, temp_ptr);
  1030. if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
  1031. goto fail;
  1032. memcpy(temp_ptr + blkoff, g_parent_inode,
  1033. sizeof(struct ext2_inode));
  1034. if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
  1035. goto fail;
  1036. free(temp_ptr);
  1037. } else {
  1038. /*
  1039. * If parent and child fall in same inode table block
  1040. * both should be kept in 1 buffer
  1041. */
  1042. memcpy(temp_ptr + blkoff, g_parent_inode,
  1043. sizeof(struct ext2_inode));
  1044. gd_index--;
  1045. if (ext4fs_put_metadata(temp_ptr, itable_blkno))
  1046. goto fail;
  1047. free(temp_ptr);
  1048. }
  1049. ext4fs_update();
  1050. ext4fs_deinit();
  1051. fs->first_pass_bbmap = 0;
  1052. fs->curr_blkno = 0;
  1053. fs->first_pass_ibmap = 0;
  1054. fs->curr_inode_no = 0;
  1055. free(inode_buffer);
  1056. free(g_parent_inode);
  1057. g_parent_inode = NULL;
  1058. return 0;
  1059. fail:
  1060. ext4fs_deinit();
  1061. free(inode_buffer);
  1062. free(g_parent_inode);
  1063. g_parent_inode = NULL;
  1064. return -1;
  1065. }
  1066. #endif