closefs.c revision 5df55d7f847e29d23227592a0bb23daad1a61500
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * closefs.c --- close an ext2 filesystem 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * %Begin-Header% 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * This file may be redistributed under the terms of the GNU Public 8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * License. 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * %End-Header% 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <stdio.h> 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if HAVE_UNISTD_H 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <unistd.h> 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <time.h> 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include <string.h> 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "ext2_fs.h" 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "ext2fsP.h" 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic int test_root(int a, int b) 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (a == 0) 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 1; 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com while (1) { 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (a == 1) 288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 1; 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (a % b) 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com a = a / b; 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint ext2fs_bg_has_super(ext2_filsys fs, int group_block) 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!(fs->super->s_feature_ro_compat & 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) 39d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com return 1; 40d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (test_root(group_block, 3) || (test_root(group_block, 5)) || 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com test_root(group_block, 7)) 438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 1; 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * This function forces out the primary superblock. We need to only 508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * write out those fields which we have changed, since if the 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * filesystem is mounted, it may have changed some of the other 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * fields. 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * It takes as input a superblock which has already been byte swapped 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * (if necessary). 568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * 578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic errcode_t write_primary_superblock(ext2_filsys fs, 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com struct ext2_super_block *super) 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com __u16 *old_super, *new_super; 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int check_idx, write_idx, size; 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com errcode_t retval; 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!fs->io->manager->write_byte || !fs->orig_super) { 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE, 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com super); 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com io_channel_set_blksize(fs->io, fs->blocksize); 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return retval; 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com old_super = (__u16 *) fs->orig_super; 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com new_super = (__u16 *) super; 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) { 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (old_super[check_idx] == new_super[check_idx]) 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com continue; 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com write_idx = check_idx; 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++) 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (old_super[check_idx] == new_super[check_idx]) 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size = 2 * (check_idx - write_idx); 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com printf("Writing %d bytes starting at %d\n", 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size, write_idx*2); 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com retval = io_channel_write_byte(fs->io, 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SUPERBLOCK_OFFSET + (2 * write_idx), size, 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com new_super + write_idx); 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (retval) 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return retval; 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Updates the revision to EXT2_DYNAMIC_REV 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid ext2fs_update_dynamic_rev(ext2_filsys fs) 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com struct ext2_super_block *sb = fs->super; 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (sb->s_rev_level > EXT2_GOOD_OLD_REV) 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sb->s_rev_level = EXT2_DYNAMIC_REV; 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /* s_uuid is handled by e2fsck already */ 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /* other fields should be left alone */ 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comerrcode_t ext2fs_flush(ext2_filsys fs) 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dgrp_t i,j,maxgroup,sgrp; 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blk_t group_block; 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com errcode_t retval; 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com char *group_ptr; 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com unsigned long fs_state; 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com struct ext2_super_block *super_shadow = 0; 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com struct ext2_group_desc *group_shadow = 0; 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com struct ext2_group_desc *s, *t; 1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fs_state = fs->super->s_state; 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fs->super->s_wtime = time(NULL); 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fs->super->s_block_group_nr = 0; 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef EXT2FS_ENABLE_SWAPFS 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com retval = EXT2_ET_NO_MEMORY; 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com retval = ext2fs_get_mem(SUPERBLOCK_SIZE, 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com (void **) &super_shadow); 1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (retval) 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com goto errout; 1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com retval = ext2fs_get_mem((size_t)(fs->blocksize * 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fs->desc_blocks), 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com (void **) &group_shadow); 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (retval) 143 goto errout; 144 memset(group_shadow, 0, (size_t) fs->blocksize * 145 fs->desc_blocks); 146 147 /* swap the superblock */ 148 *super_shadow = *fs->super; 149 ext2fs_swap_super(super_shadow); 150 151 /* swap the group descriptors */ 152 for (j=0, s=fs->group_desc, t=group_shadow; 153 j < fs->group_desc_count; j++, t++, s++) { 154 *t = *s; 155 ext2fs_swap_group_desc(t); 156 } 157 } else { 158 super_shadow = fs->super; 159 group_shadow = fs->group_desc; 160 } 161#else 162 super_shadow = fs->super; 163 group_shadow = fs->group_desc; 164#endif 165 166 /* 167 * Write out master superblock. This has to be done 168 * separately, since it is located at a fixed location 169 * (SUPERBLOCK_OFFSET). 170 */ 171 retval = write_primary_superblock(fs, super_shadow); 172 if (retval) 173 goto errout; 174 175 /* 176 * If this is an external journal device, don't write out the 177 * block group descriptors or any of the backup superblocks 178 */ 179 if (fs->super->s_feature_incompat & 180 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { 181 retval = 0; 182 goto errout; 183 } 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#ifdef EXT2FS_ENABLE_SWAPFS 192 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 193 *super_shadow = *fs->super; 194 ext2fs_swap_super(super_shadow); 195 } 196#endif 197 198 /* 199 * Write out the master group descriptors, and the backup 200 * superblocks and group descriptors. 201 */ 202 group_block = fs->super->s_first_data_block; 203 maxgroup = (fs->flags & EXT2_FLAG_MASTER_SB_ONLY) ? 1 : 204 fs->group_desc_count; 205 for (i = 0; i < maxgroup; i++) { 206 if (!ext2fs_bg_has_super(fs, i)) 207 goto next_group; 208 209 sgrp = i; 210 if (sgrp > ((1 << 16) - 1)) 211 sgrp = (1 << 16) - 1; 212#ifdef EXT2FS_ENABLE_SWAPFS 213 if (fs->flags & EXT2_FLAG_SWAP_BYTES) 214 super_shadow->s_block_group_nr = ext2fs_swab16(sgrp); 215 else 216#endif 217 fs->super->s_block_group_nr = sgrp; 218 219 if (i !=0 ) { 220 retval = io_channel_write_blk(fs->io, group_block, 221 -SUPERBLOCK_SIZE, 222 super_shadow); 223 if (retval) 224 goto errout; 225 } 226 if (fs->flags & EXT2_FLAG_SUPER_ONLY) 227 goto next_group; 228 group_ptr = (char *) group_shadow; 229 for (j=0; j < fs->desc_blocks; j++) { 230 retval = io_channel_write_blk(fs->io, 231 group_block+1+j, 1, 232 group_ptr); 233 if (retval) 234 goto errout; 235 group_ptr += fs->blocksize; 236 } 237 next_group: 238 group_block += EXT2_BLOCKS_PER_GROUP(fs->super); 239 } 240 fs->super->s_block_group_nr = 0; 241 242 /* 243 * If the write_bitmaps() function is present, call it to 244 * flush the bitmaps. This is done this way so that a simple 245 * program that doesn't mess with the bitmaps doesn't need to 246 * drag in the bitmaps.c code. 247 */ 248 if (fs->write_bitmaps) { 249 retval = fs->write_bitmaps(fs); 250 if (retval) 251 goto errout; 252 } 253 254 /* 255 * Flush the blocks out to disk 256 */ 257 retval = io_channel_flush(fs->io); 258errout: 259 fs->super->s_state = fs_state; 260 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 261 if (super_shadow) 262 ext2fs_free_mem((void **) &super_shadow); 263 if (group_shadow) 264 ext2fs_free_mem((void **) &group_shadow); 265 } 266 return retval; 267} 268 269errcode_t ext2fs_close(ext2_filsys fs) 270{ 271 errcode_t retval; 272 273 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 274 275 if (fs->flags & EXT2_FLAG_DIRTY) { 276 retval = ext2fs_flush(fs); 277 if (retval) 278 return retval; 279 } 280 if (fs->write_bitmaps) { 281 retval = fs->write_bitmaps(fs); 282 if (retval) 283 return retval; 284 } 285 ext2fs_free(fs); 286 return 0; 287} 288 289