blob: 1a615f323a7a0529b9b1fccc965bdfee3da63427 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * closefs.c --- close an ext2 filesystem
3 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * 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%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 */
11
12#include <stdio.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000013#if HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000014#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000015#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000016#include <time.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000017#include <string.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000018
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000019#if EXT2_FLAT_INCLUDES
20#include "ext2_fs.h"
21#else
Theodore Ts'o3839e651997-04-26 13:21:57 +000022#include <linux/ext2_fs.h>
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000023#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000024
Theodore Ts'o21c84b71997-04-29 16:15:03 +000025#include "ext2fsP.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000026
Theodore Ts'o521e3681997-04-29 17:48:10 +000027static 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
Theodore Ts'o3839e651997-04-26 13:21:57 +000059errcode_t ext2fs_flush(ext2_filsys fs)
60{
Theodore Ts'o30c42611998-06-30 05:33:11 +000061 dgrp_t i,j,maxgroup,sgrp;
Theodore Ts'o3cb6c501997-08-11 20:29:22 +000062 blk_t group_block;
Theodore Ts'o3839e651997-04-26 13:21:57 +000063 errcode_t retval;
64 char *group_ptr;
Theodore Ts'of3db3561997-04-26 13:34:30 +000065 unsigned long fs_state;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000066 struct ext2_super_block *super_shadow = 0;
67 struct ext2_group_desc *group_shadow = 0;
68 struct ext2_group_desc *s, *t;
Theodore Ts'o30c42611998-06-30 05:33:11 +000069 struct ext2fs_sb *sb, *sb_shadow;
Theodore Ts'o3839e651997-04-26 13:21:57 +000070
Theodore Ts'of3db3561997-04-26 13:34:30 +000071 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
72
Theodore Ts'o50e1e101997-04-26 13:58:21 +000073 fs_state = fs->super->s_state;
74
75 fs->super->s_wtime = time(NULL);
Theodore Ts'o30c42611998-06-30 05:33:11 +000076 sb = (struct ext2fs_sb *) fs->super;
77 sb->s_block_group_nr = 0;
Theodore Ts'o5c576471997-04-29 15:29:49 +000078 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +000079 retval = EXT2_ET_NO_MEMORY;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000080 retval = ext2fs_get_mem(SUPERBLOCK_SIZE,
81 (void **) &super_shadow);
82 if (retval)
Theodore Ts'o50e1e101997-04-26 13:58:21 +000083 goto errout;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000084 retval = ext2fs_get_mem((size_t)(fs->blocksize *
85 fs->desc_blocks),
86 (void **) &group_shadow);
87 if (retval)
Theodore Ts'o50e1e101997-04-26 13:58:21 +000088 goto errout;
Theodore Ts'o3cb6c501997-08-11 20:29:22 +000089 memset(group_shadow, 0, (size_t) fs->blocksize *
90 fs->desc_blocks);
Theodore Ts'o50e1e101997-04-26 13:58:21 +000091
92 /* swap the superblock */
93 *super_shadow = *fs->super;
94 ext2fs_swap_super(super_shadow);
Theodore Ts'o30c42611998-06-30 05:33:11 +000095 sb_shadow = (struct ext2fs_sb *) super_shadow;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000096
97 /* swap the group descriptors */
98 for (j=0, s=fs->group_desc, t=group_shadow;
99 j < fs->group_desc_count; j++, t++, s++) {
100 *t = *s;
101 ext2fs_swap_group_desc(t);
102 }
103 } else {
104 super_shadow = fs->super;
Theodore Ts'o30c42611998-06-30 05:33:11 +0000105 sb_shadow = (struct ext2fs_sb *) fs->super;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000106 group_shadow = fs->group_desc;
107 }
108
Theodore Ts'o3839e651997-04-26 13:21:57 +0000109 /*
110 * Write out master superblock. This has to be done
111 * separately, since it is located at a fixed location
112 * (SUPERBLOCK_OFFSET).
113 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000114 io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000115 retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
116 super_shadow);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000117 if (retval)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000118 goto errout;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000119 io_channel_set_blksize(fs->io, fs->blocksize);
120
121 /*
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000122 * Set the state of the FS to be non-valid. (The state has
123 * already been backed up earlier, and will be restored when
124 * we exit.)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000125 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000126 fs->super->s_state &= ~EXT2_VALID_FS;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000127 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000128 *super_shadow = *fs->super;
129 ext2fs_swap_super(super_shadow);
130 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000131
132 /*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000133 * Write out the master group descriptors, and the backup
134 * superblocks and group descriptors.
135 */
136 group_block = fs->super->s_first_data_block;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000137 maxgroup = (fs->flags & EXT2_FLAG_MASTER_SB_ONLY) ? 1 :
138 fs->group_desc_count;
139 for (i = 0; i < maxgroup; i++) {
Theodore Ts'o521e3681997-04-29 17:48:10 +0000140 if (!ext2fs_bg_has_super(fs, i))
141 goto next_group;
142
Theodore Ts'o30c42611998-06-30 05:33:11 +0000143 sgrp = i;
144 if (sgrp > ((1 << 16) - 1))
145 sgrp = (1 << 16) - 1;
146 if (fs->flags & EXT2_FLAG_SWAP_BYTES)
147 sb_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
148 else
149 sb->s_block_group_nr = sgrp;
150
Theodore Ts'o3839e651997-04-26 13:21:57 +0000151 if (i !=0 ) {
152 retval = io_channel_write_blk(fs->io, group_block,
153 -SUPERBLOCK_SIZE,
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000154 super_shadow);
155 if (retval)
156 goto errout;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000157 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000158 group_ptr = (char *) group_shadow;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000159 for (j=0; j < fs->desc_blocks; j++) {
160 retval = io_channel_write_blk(fs->io,
161 group_block+1+j, 1,
162 group_ptr);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000163 if (retval)
164 goto errout;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000165 group_ptr += fs->blocksize;
166 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000167 next_group:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000168 group_block += EXT2_BLOCKS_PER_GROUP(fs->super);
169 }
Theodore Ts'o30c42611998-06-30 05:33:11 +0000170 sb->s_block_group_nr = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000171
172 /*
173 * If the write_bitmaps() function is present, call it to
174 * flush the bitmaps. This is done this way so that a simple
175 * program that doesn't mess with the bitmaps doesn't need to
176 * drag in the bitmaps.c code.
177 */
178 if (fs->write_bitmaps) {
179 retval = fs->write_bitmaps(fs);
180 if (retval)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000181 goto errout;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000182 }
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000183
184 /*
185 * Flush the blocks out to disk
186 */
187 retval = io_channel_flush(fs->io);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000188errout:
189 fs->super->s_state = fs_state;
Theodore Ts'o5c576471997-04-29 15:29:49 +0000190 if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000191 if (super_shadow)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000192 ext2fs_free_mem((void **) &super_shadow);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000193 if (group_shadow)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000194 ext2fs_free_mem((void **) &group_shadow);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000195 }
196 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000197}
198
199errcode_t ext2fs_close(ext2_filsys fs)
200{
201 errcode_t retval;
202
Theodore Ts'of3db3561997-04-26 13:34:30 +0000203 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
204
Theodore Ts'o3839e651997-04-26 13:21:57 +0000205 if (fs->flags & EXT2_FLAG_DIRTY) {
206 retval = ext2fs_flush(fs);
207 if (retval)
208 return retval;
209 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000210 if (fs->write_bitmaps) {
211 retval = fs->write_bitmaps(fs);
212 if (retval)
213 return retval;
214 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000215 ext2fs_free(fs);
216 return 0;
217}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000218