Whamcloud - gitweb
Many files:
[tools/e2fsprogs.git] / lib / ext2fs / closefs.c
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 #include <unistd.h>
14 #include <stdlib.h>
15 #include <time.h>
16 #include <string.h>
17 #ifdef HAVE_ERRNO_H
18 #include <errno.h>
19 #endif
20
21 #include <linux/ext2_fs.h>
22
23 #include "ext2fsP.h"
24
25 static int test_root(int a, int b)
26 {
27         if (a == 0)
28                 return 1;
29         while (1) {
30                 if (a == 1)
31                         return 1;
32                 if (a % b)
33                         return 0;
34                 a = a / b;
35         }
36 }
37
38 int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
39 {
40 #ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
41         struct ext2fs_sb        *s;
42
43         s = (struct ext2fs_sb *) fs->super;
44         if (!(s->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
45                 return 1;
46
47         if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
48             test_root(group_block, 7))
49                 return 1;
50         
51         return 0;
52 #else
53         return 1;
54 #endif
55 }
56
57 errcode_t ext2fs_flush(ext2_filsys fs)
58 {
59         int             i,j,maxgroup;
60         int             group_block;
61         errcode_t       retval;
62         char            *group_ptr;
63         unsigned long   fs_state;
64         struct ext2_super_block *super_shadow = 0;
65         struct ext2_group_desc *group_shadow = 0;
66         struct ext2_group_desc *s, *t;
67         
68         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
69
70         fs_state = fs->super->s_state;
71
72         fs->super->s_wtime = time(NULL);
73         if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
74                 retval = ENOMEM;
75                 if (!(super_shadow = malloc(SUPERBLOCK_SIZE)))
76                         goto errout;
77                 if (!(group_shadow = malloc(fs->blocksize*fs->desc_blocks)))
78                         goto errout;
79                 memset(group_shadow, 0, fs->blocksize*fs->desc_blocks);
80
81                 /* swap the superblock */
82                 *super_shadow = *fs->super;
83                 ext2fs_swap_super(super_shadow);
84
85                 /* swap the group descriptors */
86                 for (j=0, s=fs->group_desc, t=group_shadow;
87                      j < fs->group_desc_count; j++, t++, s++) {
88                         *t = *s;
89                         ext2fs_swap_group_desc(t);
90                 }
91         } else {
92                 super_shadow = fs->super;
93                 group_shadow = fs->group_desc;
94         }
95         
96         /*
97          * Write out master superblock.  This has to be done
98          * separately, since it is located at a fixed location
99          * (SUPERBLOCK_OFFSET).
100          */
101         io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
102         retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
103                                       super_shadow);
104         if (retval)
105                 goto errout;
106         io_channel_set_blksize(fs->io, fs->blocksize);
107
108         /*
109          * Set the state of the FS to be non-valid.  (The state has
110          * already been backed up earlier, and will be restored when
111          * we exit.)
112          */
113         fs->super->s_state &= ~EXT2_VALID_FS;
114         if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
115                 *super_shadow = *fs->super;
116                 ext2fs_swap_super(super_shadow);
117         }
118
119         /*
120          * Write out the master group descriptors, and the backup
121          * superblocks and group descriptors.
122          */
123         group_block = fs->super->s_first_data_block;
124         maxgroup = (fs->flags & EXT2_FLAG_MASTER_SB_ONLY) ? 1 :
125                 fs->group_desc_count;
126         for (i = 0; i < maxgroup; i++) {
127                 if (!ext2fs_bg_has_super(fs, i))
128                         goto next_group;
129
130                 if (i !=0 ) {
131                         retval = io_channel_write_blk(fs->io, group_block,
132                                                       -SUPERBLOCK_SIZE,
133                                                       super_shadow);
134                         if (retval)
135                                 goto errout;
136                 }
137                 group_ptr = (char *) group_shadow;
138                 for (j=0; j < fs->desc_blocks; j++) {
139                         retval = io_channel_write_blk(fs->io,
140                                                       group_block+1+j, 1,
141                                                       group_ptr);
142                         if (retval)
143                                 goto errout;
144                         group_ptr += fs->blocksize;
145                 }
146         next_group:
147                 group_block += EXT2_BLOCKS_PER_GROUP(fs->super);
148         }
149
150         /*
151          * If the write_bitmaps() function is present, call it to
152          * flush the bitmaps.  This is done this way so that a simple
153          * program that doesn't mess with the bitmaps doesn't need to
154          * drag in the bitmaps.c code.
155          */
156         if (fs->write_bitmaps) {
157                 retval = fs->write_bitmaps(fs);
158                 if (retval)
159                         goto errout;
160         }
161         retval = 0;
162 errout:
163         fs->super->s_state = fs_state;
164         if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
165                 if (super_shadow)
166                         free(super_shadow);
167                 if (group_shadow)
168                         free(group_shadow);
169         }
170         return retval;
171 }
172
173 errcode_t ext2fs_close(ext2_filsys fs)
174 {
175         errcode_t       retval;
176         
177         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
178
179         if (fs->flags & EXT2_FLAG_DIRTY) {
180                 retval = ext2fs_flush(fs);
181                 if (retval)
182                         return retval;
183         }
184         if (fs->write_bitmaps) {
185                 retval = fs->write_bitmaps(fs);
186                 if (retval)
187                         return retval;
188         }
189         ext2fs_free(fs);
190         return 0;
191 }
192
193 /*
194  * This procedure frees a badblocks list.
195  */
196 void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
197 {
198         if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
199                 return;
200
201         if (bb->list)
202                 free(bb->list);
203         bb->list = 0;
204         free(bb);
205 }
206
207 /*
208  * Close a directory block list
209  */
210 void ext2fs_free_dblist(ext2_dblist dblist)
211 {
212         if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST))
213                 return;
214
215         if (dblist->list)
216                 free(dblist->list);
217         dblist->list = 0;
218         if (dblist->fs && dblist->fs->dblist == dblist)
219                 dblist->fs->dblist = 0;
220         dblist->magic = 0;
221         free(dblist);
222 }