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 Theodore Ts'o.  This file may be redistributed
5  * under the terms of the GNU Public License.
6  */
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <time.h>
12 #include <string.h>
13 #ifdef HAVE_ERRNO_H
14 #include <errno.h>
15 #endif
16
17 #include <linux/ext2_fs.h>
18
19 #include "ext2fs.h"
20
21 errcode_t ext2fs_flush(ext2_filsys fs)
22 {
23         int             i,j,maxgroup;
24         int             group_block;
25         errcode_t       retval;
26         char            *group_ptr;
27         unsigned long   fs_state;
28         struct ext2_super_block *super_shadow = 0;
29         struct ext2_group_desc *group_shadow = 0;
30         struct ext2_group_desc *s, *t;
31         
32         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
33
34         fs_state = fs->super->s_state;
35
36         fs->super->s_wtime = time(NULL);
37         if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
38                 retval = ENOMEM;
39                 if (!(super_shadow = malloc(SUPERBLOCK_SIZE)))
40                         goto errout;
41                 if (!(group_shadow = malloc(fs->blocksize*fs->desc_blocks)))
42                         goto errout;
43                 memset(group_shadow, 0, fs->blocksize*fs->desc_blocks);
44
45                 /* swap the superblock */
46                 *super_shadow = *fs->super;
47                 ext2fs_swap_super(super_shadow);
48
49                 /* swap the group descriptors */
50                 for (j=0, s=fs->group_desc, t=group_shadow;
51                      j < fs->group_desc_count; j++, t++, s++) {
52                         *t = *s;
53                         ext2fs_swap_group_desc(t);
54                 }
55         } else {
56                 super_shadow = fs->super;
57                 group_shadow = fs->group_desc;
58         }
59         
60         /*
61          * Write out master superblock.  This has to be done
62          * separately, since it is located at a fixed location
63          * (SUPERBLOCK_OFFSET).
64          */
65         io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
66         retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
67                                       super_shadow);
68         if (retval)
69                 goto errout;
70         io_channel_set_blksize(fs->io, fs->blocksize);
71
72         /*
73          * Set the state of the FS to be non-valid.  (The state has
74          * already been backed up earlier, and will be restored when
75          * we exit.)
76          */
77         fs->super->s_state &= ~EXT2_VALID_FS;
78         if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
79                 *super_shadow = *fs->super;
80                 ext2fs_swap_super(super_shadow);
81         }
82
83         /*
84          * Write out the master group descriptors, and the backup
85          * superblocks and group descriptors.
86          */
87         group_block = fs->super->s_first_data_block;
88         maxgroup = (fs->flags & EXT2_FLAG_MASTER_SB_ONLY) ? 1 :
89                 fs->group_desc_count;
90         for (i = 0; i < maxgroup; i++) {
91                 if (i !=0 ) {
92                         retval = io_channel_write_blk(fs->io, group_block,
93                                                       -SUPERBLOCK_SIZE,
94                                                       super_shadow);
95                         if (retval)
96                                 goto errout;
97                 }
98                 group_ptr = (char *) group_shadow;
99                 for (j=0; j < fs->desc_blocks; j++) {
100                         retval = io_channel_write_blk(fs->io,
101                                                       group_block+1+j, 1,
102                                                       group_ptr);
103                         if (retval)
104                                 goto errout;
105                         group_ptr += fs->blocksize;
106                 }
107                 group_block += EXT2_BLOCKS_PER_GROUP(fs->super);
108         }
109
110         /*
111          * If the write_bitmaps() function is present, call it to
112          * flush the bitmaps.  This is done this way so that a simple
113          * program that doesn't mess with the bitmaps doesn't need to
114          * drag in the bitmaps.c code.
115          */
116         if (fs->write_bitmaps) {
117                 retval = fs->write_bitmaps(fs);
118                 if (retval)
119                         goto errout;
120         }
121
122         retval = 0;
123 errout:
124         fs->super->s_state = fs_state;
125         if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
126                 if (super_shadow)
127                         free(super_shadow);
128                 if (group_shadow)
129                         free(group_shadow);
130         }
131         return retval;
132 }
133
134 errcode_t ext2fs_close(ext2_filsys fs)
135 {
136         errcode_t       retval;
137         
138         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
139
140         if (fs->flags & EXT2_FLAG_DIRTY) {
141                 retval = ext2fs_flush(fs);
142                 if (retval)
143                         return retval;
144         }
145         ext2fs_free(fs);
146         return 0;
147 }