closefs.c revision 4cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3
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 <stdlib.h>
17#include <time.h>
18#include <string.h>
19#ifdef HAVE_ERRNO_H
20#include <errno.h>
21#endif
22
23#include <linux/ext2_fs.h>
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
59errcode_t ext2fs_flush(ext2_filsys fs)
60{
61	int		i,j,maxgroup;
62	int		group_block;
63	errcode_t	retval;
64	char		*group_ptr;
65	unsigned long	fs_state;
66	struct ext2_super_block *super_shadow = 0;
67	struct ext2_group_desc *group_shadow = 0;
68	struct ext2_group_desc *s, *t;
69
70	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
71
72	fs_state = fs->super->s_state;
73
74	fs->super->s_wtime = time(NULL);
75	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
76		retval = ENOMEM;
77		if (!(super_shadow = malloc(SUPERBLOCK_SIZE)))
78			goto errout;
79		if (!(group_shadow = malloc(fs->blocksize*fs->desc_blocks)))
80			goto errout;
81		memset(group_shadow, 0, fs->blocksize*fs->desc_blocks);
82
83		/* swap the superblock */
84		*super_shadow = *fs->super;
85		ext2fs_swap_super(super_shadow);
86
87		/* swap the group descriptors */
88		for (j=0, s=fs->group_desc, t=group_shadow;
89		     j < fs->group_desc_count; j++, t++, s++) {
90			*t = *s;
91			ext2fs_swap_group_desc(t);
92		}
93	} else {
94		super_shadow = fs->super;
95		group_shadow = fs->group_desc;
96	}
97
98	/*
99	 * Write out master superblock.  This has to be done
100	 * separately, since it is located at a fixed location
101	 * (SUPERBLOCK_OFFSET).
102	 */
103	io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
104	retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
105				      super_shadow);
106	if (retval)
107		goto errout;
108	io_channel_set_blksize(fs->io, fs->blocksize);
109
110	/*
111	 * Set the state of the FS to be non-valid.  (The state has
112	 * already been backed up earlier, and will be restored when
113	 * we exit.)
114	 */
115	fs->super->s_state &= ~EXT2_VALID_FS;
116	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
117		*super_shadow = *fs->super;
118		ext2fs_swap_super(super_shadow);
119	}
120
121	/*
122	 * Write out the master group descriptors, and the backup
123	 * superblocks and group descriptors.
124	 */
125	group_block = fs->super->s_first_data_block;
126	maxgroup = (fs->flags & EXT2_FLAG_MASTER_SB_ONLY) ? 1 :
127		fs->group_desc_count;
128	for (i = 0; i < maxgroup; i++) {
129		if (!ext2fs_bg_has_super(fs, i))
130			goto next_group;
131
132		if (i !=0 ) {
133			retval = io_channel_write_blk(fs->io, group_block,
134						      -SUPERBLOCK_SIZE,
135						      super_shadow);
136			if (retval)
137				goto errout;
138		}
139		group_ptr = (char *) group_shadow;
140		for (j=0; j < fs->desc_blocks; j++) {
141			retval = io_channel_write_blk(fs->io,
142						      group_block+1+j, 1,
143						      group_ptr);
144			if (retval)
145				goto errout;
146			group_ptr += fs->blocksize;
147		}
148	next_group:
149		group_block += EXT2_BLOCKS_PER_GROUP(fs->super);
150	}
151
152	/*
153	 * If the write_bitmaps() function is present, call it to
154	 * flush the bitmaps.  This is done this way so that a simple
155	 * program that doesn't mess with the bitmaps doesn't need to
156	 * drag in the bitmaps.c code.
157	 */
158	if (fs->write_bitmaps) {
159		retval = fs->write_bitmaps(fs);
160		if (retval)
161			goto errout;
162	}
163	retval = 0;
164errout:
165	fs->super->s_state = fs_state;
166	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
167		if (super_shadow)
168			free(super_shadow);
169		if (group_shadow)
170			free(group_shadow);
171	}
172	return retval;
173}
174
175errcode_t ext2fs_close(ext2_filsys fs)
176{
177	errcode_t	retval;
178
179	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
180
181	if (fs->flags & EXT2_FLAG_DIRTY) {
182		retval = ext2fs_flush(fs);
183		if (retval)
184			return retval;
185	}
186	if (fs->write_bitmaps) {
187		retval = fs->write_bitmaps(fs);
188		if (retval)
189			return retval;
190	}
191	ext2fs_free(fs);
192	return 0;
193}
194
195