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