closefs.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * closefs.c --- close an ext2 filesystem
  3. *
  4. * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
  5. *
  6. * %Begin-Header%
  7. * This file may be redistributed under the terms of the GNU Public
  8. * License.
  9. * %End-Header%
  10. */
  11. #include <stdio.h>
  12. #if HAVE_UNISTD_H
  13. #include <unistd.h>
  14. #endif
  15. #include <time.h>
  16. #include <string.h>
  17. #include "ext2_fs.h"
  18. #include "ext2fsP.h"
  19. static int test_root(int a, int b)
  20. {
  21. if (a == 0)
  22. return 1;
  23. while (1) {
  24. if (a == 1)
  25. return 1;
  26. if (a % b)
  27. return 0;
  28. a = a / b;
  29. }
  30. }
  31. int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
  32. {
  33. if (!(fs->super->s_feature_ro_compat &
  34. EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
  35. return 1;
  36. if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
  37. test_root(group_block, 7))
  38. return 1;
  39. return 0;
  40. }
  41. int ext2fs_super_and_bgd_loc(ext2_filsys fs,
  42. dgrp_t group,
  43. blk_t *ret_super_blk,
  44. blk_t *ret_old_desc_blk,
  45. blk_t *ret_new_desc_blk,
  46. int *ret_meta_bg)
  47. {
  48. blk_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
  49. unsigned int meta_bg, meta_bg_size;
  50. int numblocks, has_super;
  51. int old_desc_blocks;
  52. group_block = fs->super->s_first_data_block +
  53. (group * fs->super->s_blocks_per_group);
  54. if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
  55. old_desc_blocks = fs->super->s_first_meta_bg;
  56. else
  57. old_desc_blocks =
  58. fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
  59. if (group == fs->group_desc_count-1) {
  60. numblocks = (fs->super->s_blocks_count -
  61. fs->super->s_first_data_block) %
  62. fs->super->s_blocks_per_group;
  63. if (!numblocks)
  64. numblocks = fs->super->s_blocks_per_group;
  65. } else
  66. numblocks = fs->super->s_blocks_per_group;
  67. has_super = ext2fs_bg_has_super(fs, group);
  68. if (has_super) {
  69. super_blk = group_block;
  70. numblocks--;
  71. }
  72. meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
  73. meta_bg = group / meta_bg_size;
  74. if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
  75. (meta_bg < fs->super->s_first_meta_bg)) {
  76. if (has_super) {
  77. old_desc_blk = group_block + 1;
  78. numblocks -= old_desc_blocks;
  79. }
  80. } else {
  81. if (((group % meta_bg_size) == 0) ||
  82. ((group % meta_bg_size) == 1) ||
  83. ((group % meta_bg_size) == (meta_bg_size-1))) {
  84. if (has_super)
  85. has_super = 1;
  86. new_desc_blk = group_block + has_super;
  87. numblocks--;
  88. }
  89. }
  90. numblocks -= 2 + fs->inode_blocks_per_group;
  91. if (ret_super_blk)
  92. *ret_super_blk = super_blk;
  93. if (ret_old_desc_blk)
  94. *ret_old_desc_blk = old_desc_blk;
  95. if (ret_new_desc_blk)
  96. *ret_new_desc_blk = new_desc_blk;
  97. if (ret_meta_bg)
  98. *ret_meta_bg = meta_bg;
  99. return (numblocks);
  100. }
  101. /*
  102. * This function forces out the primary superblock. We need to only
  103. * write out those fields which we have changed, since if the
  104. * filesystem is mounted, it may have changed some of the other
  105. * fields.
  106. *
  107. * It takes as input a superblock which has already been byte swapped
  108. * (if necessary).
  109. *
  110. */
  111. static errcode_t write_primary_superblock(ext2_filsys fs,
  112. struct ext2_super_block *super)
  113. {
  114. __u16 *old_super, *new_super;
  115. int check_idx, write_idx, size;
  116. errcode_t retval;
  117. if (!fs->io->manager->write_byte || !fs->orig_super) {
  118. io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
  119. retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
  120. super);
  121. io_channel_set_blksize(fs->io, fs->blocksize);
  122. return retval;
  123. }
  124. old_super = (__u16 *) fs->orig_super;
  125. new_super = (__u16 *) super;
  126. for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) {
  127. if (old_super[check_idx] == new_super[check_idx])
  128. continue;
  129. write_idx = check_idx;
  130. for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++)
  131. if (old_super[check_idx] == new_super[check_idx])
  132. break;
  133. size = 2 * (check_idx - write_idx);
  134. #if 0
  135. printf("Writing %d bytes starting at %d\n",
  136. size, write_idx*2);
  137. #endif
  138. retval = io_channel_write_byte(fs->io,
  139. SUPERBLOCK_OFFSET + (2 * write_idx), size,
  140. new_super + write_idx);
  141. if (retval)
  142. return retval;
  143. }
  144. memcpy(fs->orig_super, super, SUPERBLOCK_SIZE);
  145. return 0;
  146. }
  147. /*
  148. * Updates the revision to EXT2_DYNAMIC_REV
  149. */
  150. void ext2fs_update_dynamic_rev(ext2_filsys fs)
  151. {
  152. struct ext2_super_block *sb = fs->super;
  153. if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
  154. return;
  155. sb->s_rev_level = EXT2_DYNAMIC_REV;
  156. sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
  157. sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
  158. /* s_uuid is handled by e2fsck already */
  159. /* other fields should be left alone */
  160. }
  161. static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
  162. blk_t group_block,
  163. struct ext2_super_block *super_shadow)
  164. {
  165. dgrp_t sgrp = group;
  166. if (sgrp > ((1 << 16) - 1))
  167. sgrp = (1 << 16) - 1;
  168. #ifdef EXT2FS_ENABLE_SWAPFS
  169. if (fs->flags & EXT2_FLAG_SWAP_BYTES)
  170. super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
  171. else
  172. #endif
  173. fs->super->s_block_group_nr = sgrp;
  174. return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE,
  175. super_shadow);
  176. }
  177. errcode_t ext2fs_flush(ext2_filsys fs)
  178. {
  179. dgrp_t i;
  180. blk_t group_block;
  181. errcode_t retval;
  182. unsigned long fs_state;
  183. struct ext2_super_block *super_shadow = 0;
  184. struct ext2_group_desc *group_shadow = 0;
  185. char *group_ptr;
  186. int old_desc_blocks;
  187. #ifdef EXT2FS_ENABLE_SWAPFS
  188. dgrp_t j;
  189. struct ext2_group_desc *s, *t;
  190. #endif
  191. EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  192. fs_state = fs->super->s_state;
  193. fs->super->s_wtime = time(NULL);
  194. fs->super->s_block_group_nr = 0;
  195. #ifdef EXT2FS_ENABLE_SWAPFS
  196. if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
  197. retval = EXT2_ET_NO_MEMORY;
  198. retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
  199. if (retval)
  200. goto errout;
  201. retval = ext2fs_get_mem((size_t)(fs->blocksize *
  202. fs->desc_blocks),
  203. &group_shadow);
  204. if (retval)
  205. goto errout;
  206. memset(group_shadow, 0, (size_t) fs->blocksize *
  207. fs->desc_blocks);
  208. /* swap the group descriptors */
  209. for (j=0, s=fs->group_desc, t=group_shadow;
  210. j < fs->group_desc_count; j++, t++, s++) {
  211. *t = *s;
  212. ext2fs_swap_group_desc(t);
  213. }
  214. } else {
  215. super_shadow = fs->super;
  216. group_shadow = fs->group_desc;
  217. }
  218. #else
  219. super_shadow = fs->super;
  220. group_shadow = fs->group_desc;
  221. #endif
  222. /*
  223. * If this is an external journal device, don't write out the
  224. * block group descriptors or any of the backup superblocks
  225. */
  226. if (fs->super->s_feature_incompat &
  227. EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
  228. goto write_primary_superblock_only;
  229. /*
  230. * Set the state of the FS to be non-valid. (The state has
  231. * already been backed up earlier, and will be restored after
  232. * we write out the backup superblocks.)
  233. */
  234. fs->super->s_state &= ~EXT2_VALID_FS;
  235. #ifdef EXT2FS_ENABLE_SWAPFS
  236. if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
  237. *super_shadow = *fs->super;
  238. ext2fs_swap_super(super_shadow);
  239. }
  240. #endif
  241. /*
  242. * Write out the master group descriptors, and the backup
  243. * superblocks and group descriptors.
  244. */
  245. group_block = fs->super->s_first_data_block;
  246. group_ptr = (char *) group_shadow;
  247. if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
  248. old_desc_blocks = fs->super->s_first_meta_bg;
  249. else
  250. old_desc_blocks = fs->desc_blocks;
  251. for (i = 0; i < fs->group_desc_count; i++) {
  252. blk_t super_blk, old_desc_blk, new_desc_blk;
  253. int meta_bg;
  254. ext2fs_super_and_bgd_loc(fs, i, &super_blk, &old_desc_blk,
  255. &new_desc_blk, &meta_bg);
  256. if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) {
  257. retval = write_backup_super(fs, i, super_blk,
  258. super_shadow);
  259. if (retval)
  260. goto errout;
  261. }
  262. if (fs->flags & EXT2_FLAG_SUPER_ONLY)
  263. continue;
  264. if ((old_desc_blk) &&
  265. (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) {
  266. retval = io_channel_write_blk(fs->io,
  267. old_desc_blk, old_desc_blocks, group_ptr);
  268. if (retval)
  269. goto errout;
  270. }
  271. if (new_desc_blk) {
  272. retval = io_channel_write_blk(fs->io, new_desc_blk,
  273. 1, group_ptr + (meta_bg*fs->blocksize));
  274. if (retval)
  275. goto errout;
  276. }
  277. }
  278. fs->super->s_block_group_nr = 0;
  279. fs->super->s_state = fs_state;
  280. #ifdef EXT2FS_ENABLE_SWAPFS
  281. if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
  282. *super_shadow = *fs->super;
  283. ext2fs_swap_super(super_shadow);
  284. }
  285. #endif
  286. /*
  287. * If the write_bitmaps() function is present, call it to
  288. * flush the bitmaps. This is done this way so that a simple
  289. * program that doesn't mess with the bitmaps doesn't need to
  290. * drag in the bitmaps.c code.
  291. */
  292. if (fs->write_bitmaps) {
  293. retval = fs->write_bitmaps(fs);
  294. if (retval)
  295. goto errout;
  296. }
  297. write_primary_superblock_only:
  298. /*
  299. * Write out master superblock. This has to be done
  300. * separately, since it is located at a fixed location
  301. * (SUPERBLOCK_OFFSET). We flush all other pending changes
  302. * out to disk first, just to avoid a race condition with an
  303. * insy-tinsy window....
  304. */
  305. retval = io_channel_flush(fs->io);
  306. retval = write_primary_superblock(fs, super_shadow);
  307. if (retval)
  308. goto errout;
  309. fs->flags &= ~EXT2_FLAG_DIRTY;
  310. retval = io_channel_flush(fs->io);
  311. errout:
  312. fs->super->s_state = fs_state;
  313. if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
  314. if (super_shadow)
  315. ext2fs_free_mem(&super_shadow);
  316. if (group_shadow)
  317. ext2fs_free_mem(&group_shadow);
  318. }
  319. return retval;
  320. }
  321. errcode_t ext2fs_close(ext2_filsys fs)
  322. {
  323. errcode_t retval;
  324. EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  325. if (fs->flags & EXT2_FLAG_DIRTY) {
  326. retval = ext2fs_flush(fs);
  327. if (retval)
  328. return retval;
  329. }
  330. if (fs->write_bitmaps) {
  331. retval = fs->write_bitmaps(fs);
  332. if (retval)
  333. return retval;
  334. }
  335. ext2fs_free(fs);
  336. return 0;
  337. }