closefs.c revision a917d1ccf49605b3009f4e7225f00b81fc16100b
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 12#include <stdio.h> 13#if HAVE_UNISTD_H 14#include <unistd.h> 15#endif 16#include <time.h> 17#include <string.h> 18 19#if EXT2_FLAT_INCLUDES 20#include "ext2_fs.h" 21#else 22#include <linux/ext2_fs.h> 23#endif 24 25#include "ext2fsP.h" 26 27static int test_root(int a, int b) 28{ 29 if (a == 0) 30 return 1; 31 while (1) { 32 if (a == 1) 33 return 1; 34 if (a % b) 35 return 0; 36 a = a / b; 37 } 38} 39 40int ext2fs_bg_has_super(ext2_filsys fs, int group_block) 41{ 42#ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 43 struct ext2fs_sb *s; 44 45 s = (struct ext2fs_sb *) fs->super; 46 if (!(s->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) 47 return 1; 48 49 if (test_root(group_block, 3) || (test_root(group_block, 5)) || 50 test_root(group_block, 7)) 51 return 1; 52 53 return 0; 54#else 55 return 1; 56#endif 57} 58 59/* 60 * This function forces out the primary superblock. We need to only 61 * write out those fields which we have changed, since if the 62 * filesystem is mounted, it may have changed some of the other 63 * fields. 64 * 65 * It takes as input a superblock which has already been byte swapped 66 * (if necessary). 67 * 68 */ 69static errcode_t write_primary_superblock(ext2_filsys fs, 70 struct ext2_super_block *super) 71{ 72 __u16 *old_super, *new_super; 73 int check_idx, write_idx, size; 74 errcode_t retval; 75 76 if (!fs->io->manager->write_byte || !fs->orig_super) { 77 io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); 78 retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE, 79 super); 80 io_channel_set_blksize(fs->io, fs->blocksize); 81 return retval; 82 } 83 84 old_super = (__u16 *) fs->orig_super; 85 new_super = (__u16 *) super; 86 87 for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) { 88 if (old_super[check_idx] == new_super[check_idx]) 89 continue; 90 write_idx = check_idx; 91 for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++) 92 if (old_super[check_idx] == new_super[check_idx]) 93 break; 94 size = 2 * (check_idx - write_idx); 95#if 0 96 printf("Writing %d bytes starting at %d\n", 97 size, write_idx*2); 98#endif 99 retval = io_channel_write_byte(fs->io, 100 SUPERBLOCK_OFFSET + (2 * write_idx), size, 101 new_super + write_idx); 102 if (retval) 103 return retval; 104 } 105 return 0; 106} 107 108 109/* 110 * Updates the revision to EXT2_DYNAMIC_REV 111 */ 112void ext2fs_update_dynamic_rev(ext2_filsys fs) 113{ 114 struct ext2_super_block *sb = fs->super; 115 116 if (sb->s_rev_level > EXT2_GOOD_OLD_REV) 117 return; 118 119 sb->s_rev_level = EXT2_DYNAMIC_REV; 120 sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; 121 sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; 122 /* s_uuid is handled by e2fsck already */ 123 /* other fields should be left alone */ 124} 125 126errcode_t ext2fs_flush(ext2_filsys fs) 127{ 128 dgrp_t i,j,maxgroup,sgrp; 129 blk_t group_block; 130 errcode_t retval; 131 char *group_ptr; 132 unsigned long fs_state; 133 struct ext2_super_block *super_shadow = 0; 134 struct ext2_group_desc *group_shadow = 0; 135 struct ext2_group_desc *s, *t; 136 struct ext2fs_sb *sb, *sb_shadow; 137 138 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 139 140 fs_state = fs->super->s_state; 141 142 fs->super->s_wtime = time(NULL); 143 sb = (struct ext2fs_sb *) fs->super; 144 sb->s_block_group_nr = 0; 145 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 146 retval = EXT2_ET_NO_MEMORY; 147 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, 148 (void **) &super_shadow); 149 if (retval) 150 goto errout; 151 retval = ext2fs_get_mem((size_t)(fs->blocksize * 152 fs->desc_blocks), 153 (void **) &group_shadow); 154 if (retval) 155 goto errout; 156 memset(group_shadow, 0, (size_t) fs->blocksize * 157 fs->desc_blocks); 158 159 /* swap the superblock */ 160 *super_shadow = *fs->super; 161 ext2fs_swap_super(super_shadow); 162 sb_shadow = (struct ext2fs_sb *) super_shadow; 163 164 /* swap the group descriptors */ 165 for (j=0, s=fs->group_desc, t=group_shadow; 166 j < fs->group_desc_count; j++, t++, s++) { 167 *t = *s; 168 ext2fs_swap_group_desc(t); 169 } 170 } else { 171 super_shadow = fs->super; 172 sb_shadow = (struct ext2fs_sb *) fs->super; 173 group_shadow = fs->group_desc; 174 } 175 176 /* 177 * Write out master superblock. This has to be done 178 * separately, since it is located at a fixed location 179 * (SUPERBLOCK_OFFSET). 180 */ 181 retval = write_primary_superblock(fs, super_shadow); 182 if (retval) 183 goto errout; 184 185 /* 186 * Set the state of the FS to be non-valid. (The state has 187 * already been backed up earlier, and will be restored when 188 * we exit.) 189 */ 190 fs->super->s_state &= ~EXT2_VALID_FS; 191 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 192 *super_shadow = *fs->super; 193 ext2fs_swap_super(super_shadow); 194 } 195 196 /* 197 * Write out the master group descriptors, and the backup 198 * superblocks and group descriptors. 199 */ 200 group_block = fs->super->s_first_data_block; 201 maxgroup = (fs->flags & EXT2_FLAG_MASTER_SB_ONLY) ? 1 : 202 fs->group_desc_count; 203 for (i = 0; i < maxgroup; i++) { 204 if (!ext2fs_bg_has_super(fs, i)) 205 goto next_group; 206 207 sgrp = i; 208 if (sgrp > ((1 << 16) - 1)) 209 sgrp = (1 << 16) - 1; 210 if (fs->flags & EXT2_FLAG_SWAP_BYTES) 211 sb_shadow->s_block_group_nr = ext2fs_swab16(sgrp); 212 else 213 sb->s_block_group_nr = sgrp; 214 215 if (i !=0 ) { 216 retval = io_channel_write_blk(fs->io, group_block, 217 -SUPERBLOCK_SIZE, 218 super_shadow); 219 if (retval) 220 goto errout; 221 } 222 group_ptr = (char *) group_shadow; 223 for (j=0; j < fs->desc_blocks; j++) { 224 retval = io_channel_write_blk(fs->io, 225 group_block+1+j, 1, 226 group_ptr); 227 if (retval) 228 goto errout; 229 group_ptr += fs->blocksize; 230 } 231 next_group: 232 group_block += EXT2_BLOCKS_PER_GROUP(fs->super); 233 } 234 sb->s_block_group_nr = 0; 235 236 /* 237 * If the write_bitmaps() function is present, call it to 238 * flush the bitmaps. This is done this way so that a simple 239 * program that doesn't mess with the bitmaps doesn't need to 240 * drag in the bitmaps.c code. 241 */ 242 if (fs->write_bitmaps) { 243 retval = fs->write_bitmaps(fs); 244 if (retval) 245 goto errout; 246 } 247 248 /* 249 * Flush the blocks out to disk 250 */ 251 retval = io_channel_flush(fs->io); 252errout: 253 fs->super->s_state = fs_state; 254 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 255 if (super_shadow) 256 ext2fs_free_mem((void **) &super_shadow); 257 if (group_shadow) 258 ext2fs_free_mem((void **) &group_shadow); 259 } 260 return retval; 261} 262 263errcode_t ext2fs_close(ext2_filsys fs) 264{ 265 errcode_t retval; 266 267 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 268 269 if (fs->flags & EXT2_FLAG_DIRTY) { 270 retval = ext2fs_flush(fs); 271 if (retval) 272 return retval; 273 } 274 if (fs->write_bitmaps) { 275 retval = fs->write_bitmaps(fs); 276 if (retval) 277 return retval; 278 } 279 ext2fs_free(fs); 280 return 0; 281} 282 283