OSDN Git Service

Differentiate between Ext4 and Ext3 file systems.
[android-x86/external-parted.git] / libparted / fs / ext2 / interface.c
1 /*
2     interface.c -- parted binding glue to libext2resize
3     Copyright (C) 1998-2000, 2007, 2009 Free Software Foundation, Inc.
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /* VERSION: libext2resize 1.1.6 (by Lennert)
20  * merged 1.1.11 changes (by Andrew)
21  */
22
23 #include <config.h>
24
25 #include <parted/parted.h>
26 #include "ext2.h"
27 #include "parted_io.h"
28
29 static PedFileSystemType _ext2_type;
30 static PedFileSystemType _ext3_type;
31
32 struct ext2_dev_handle* ext2_make_dev_handle_from_parted_geometry(PedGeometry* geom);
33
34 static PedGeometry*
35 _ext2_generic_probe (PedGeometry* geom, int expect_ext_ver)
36 {
37         struct ext2_super_block sb;
38
39         if (!ped_geometry_read(geom, &sb, 2, 2))
40                 return NULL;
41
42         if (EXT2_SUPER_MAGIC(sb) == EXT2_SUPER_MAGIC_CONST) {
43                 PedSector block_size = 1 << (EXT2_SUPER_LOG_BLOCK_SIZE(sb) + 1);
44                 PedSector block_count = EXT2_SUPER_BLOCKS_COUNT(sb);
45                 PedSector group_blocks = EXT2_SUPER_BLOCKS_PER_GROUP(sb);
46                 PedSector group_nr = EXT2_SUPER_BLOCK_GROUP_NR(sb);
47                 PedSector first_data_block = EXT2_SUPER_FIRST_DATA_BLOCK(sb);
48                 int version = EXT2_SUPER_REV_LEVEL(sb);
49                 int is_ext3 = 0;
50                 int is_ext4 = 0;
51
52                 is_ext3 = (EXT2_SUPER_FEATURE_COMPAT (sb)
53                            & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0;
54                 if (is_ext3) {
55                         is_ext4 = ((EXT2_SUPER_FEATURE_RO_COMPAT (sb)
56                                     & EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
57                                    || (EXT2_SUPER_FEATURE_RO_COMPAT (sb)
58                                        & EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
59                                    || (EXT2_SUPER_FEATURE_INCOMPAT (sb)
60                                        & EXT4_FEATURE_INCOMPAT_EXTENTS)
61                                    || (EXT2_SUPER_FEATURE_INCOMPAT (sb)
62                                        & EXT4_FEATURE_INCOMPAT_64BIT));
63                         if (is_ext4)
64                                 is_ext3 = 0;
65                 }
66
67                 if (expect_ext_ver == 2 && (is_ext3 || is_ext4))
68                         return NULL;
69                 if (expect_ext_ver == 3 && !is_ext3)
70                         return NULL;
71                 else if (expect_ext_ver == 4 && !is_ext4)
72                         return NULL;
73
74                 if (version > 0 && group_nr > 0) {
75                         PedSector start;
76                         PedGeometry probe_geom;
77
78                         start = geom->start
79                                         - group_blocks * group_nr
80                                         - first_data_block;
81
82                         if (start < 0)
83                                 return NULL;
84                         ped_geometry_init (&probe_geom, geom->dev,
85                                            start, block_count * block_size);
86                         return _ext2_generic_probe (&probe_geom,
87                                                     expect_ext_ver);
88                 } else {
89                         return ped_geometry_new (geom->dev, geom->start,
90                                                  block_count * block_size);
91                 }
92         }
93         return NULL;
94 }
95
96 static PedGeometry*
97 _ext2_probe (PedGeometry* geom)
98 {
99         return _ext2_generic_probe (geom, 2);
100 }
101
102 static PedGeometry*
103 _ext3_probe (PedGeometry* geom)
104 {
105         return _ext2_generic_probe (geom, 3);
106 }
107
108 static PedGeometry*
109 _ext4_probe (PedGeometry* geom)
110 {
111         return _ext2_generic_probe (geom, 4);
112 }
113
114 #ifndef DISCOVER_ONLY
115 static int
116 _ext2_clobber (PedGeometry* geom)
117 {
118         struct ext2_super_block sb;
119
120         if (!ped_geometry_read(geom, &sb, 2, 2))
121                 return 0;
122         if (EXT2_SUPER_MAGIC(sb) != EXT2_SUPER_MAGIC_CONST)
123                 return 1;
124
125         sb.s_magic = 0;
126         return ped_geometry_write(geom, &sb, 2, 2);
127 }
128
129 static PedFileSystem*
130 _ext2_open (PedGeometry* geom)
131 {
132         PedFileSystem*          fs;
133         struct ext2_fs*         fs_info;
134         struct ext2_dev_handle* handle;
135
136         fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
137         if (!fs) goto error;
138
139         fs->type = &_ext2_type;
140         fs->geom = ped_geometry_duplicate (geom);
141         fs->checked = 1;
142
143         handle = ext2_make_dev_handle_from_parted_geometry(fs->geom);
144         if (!handle) goto error_free_fs;
145
146         fs_info = (struct ext2_fs*) ext2_open(handle, 0);
147         if (!fs_info) goto error_free_handle;
148
149         fs->type_specific = (void*) fs_info;
150         fs_info->opt_verbose = 0;
151
152         return fs;
153
154 error_free_handle:
155         ext2_destroy_dev_handle(handle);
156 error_free_fs:
157         free(fs);
158 error:
159         return NULL;
160 }
161
162 static PedFileSystem*
163 _ext2_create (PedGeometry* geom, PedTimer* timer)
164 {
165         PedFileSystem*          fs;
166         struct ext2_fs*         fs_info;
167         struct ext2_dev_handle* handle;
168
169         fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
170         if (!fs) goto error;
171
172         fs->type = &_ext2_type;
173         fs->geom = ped_geometry_duplicate (geom);
174
175         handle = ext2_make_dev_handle_from_parted_geometry(fs->geom);
176         if (!handle) goto error_free_fs;
177
178         fs_info = ext2_mkfs (handle, 0, 0, 0, 0, -1, -1, timer);
179         if (!fs_info) goto error_free_handle;
180
181         fs->type_specific = (void*) fs_info;
182         fs_info->opt_verbose = 0;
183
184         return fs;
185
186 error_free_handle:
187         ext2_destroy_dev_handle(handle);
188 error_free_fs:
189         free(fs);
190 error:
191         return NULL;
192 }
193
194 static int
195 _ext2_close (PedFileSystem *fs)
196 {
197         struct ext2_dev_handle* handle;
198
199         handle = ((struct ext2_fs*)fs->type_specific)->devhandle;
200         ext2_close(fs->type_specific);
201         ext2_destroy_dev_handle(handle);
202
203         free(fs);
204         return 1;
205 }
206
207 static int
208 _ext2_check (PedFileSystem *fs, PedTimer* timer)
209 {
210         ped_exception_throw (PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK,
211                 _("The ext2 file system passed a basic check.  For a more "
212                   "comprehensive check, use the e2fsck program."));
213         return 1;
214 }
215
216 static int
217 _ext2_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
218 {
219         struct ext2_fs* f;
220         PedSector       old_length = fs->geom->length;
221
222         PED_ASSERT (fs->geom->dev == geom->dev, return 0);
223
224         if (fs->geom->start != geom->start)
225         {
226                 ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
227                       PED_EXCEPTION_CANCEL,
228                       _("Sorry, can't move the start of ext2 partitions yet!"));
229                 return 0;
230         }
231
232         geom->dev->boot_dirty = 1;
233
234         f = (struct ext2_fs *) fs->type_specific;
235
236 /* ensure that the geometry contains the new and old geometry */
237         if (old_length > geom->length) {
238                 if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9),
239                                     timer))
240                         goto error;
241
242                 fs->geom->length = geom->length;
243                 fs->geom->end = fs->geom->start + geom->length - 1;
244         } else {
245                 fs->geom->length = geom->length;
246                 fs->geom->end = fs->geom->start + geom->length - 1;
247
248                 if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9),
249                                     timer))
250                         goto error;
251         }
252         return 1;
253
254 error:
255         return 0;
256 }
257
258 static PedConstraint*
259 _ext2_get_create_constraint (const PedDevice* dev)
260 {
261         PedGeometry     full_dev;
262
263         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
264                 return NULL;
265
266         return ped_constraint_new (
267                         ped_alignment_any, ped_alignment_any,
268                         &full_dev, &full_dev,
269                         64, dev->length);
270 }
271
272 static PedConstraint*
273 _ext2_get_resize_constraint (const PedFileSystem* fs)
274 {
275         struct ext2_fs* f = (struct ext2_fs *) fs->type_specific;
276         PedDevice*      dev = fs->geom->dev;
277         PedAlignment    start_align;
278         PedGeometry     start_sector;
279         PedGeometry     full_dev;
280         PedSector       min_size;
281
282         if (!ped_alignment_init (&start_align, fs->geom->start, 0))
283                 return NULL;
284         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
285                 return NULL;
286         if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
287                 return NULL;
288         min_size = (EXT2_SUPER_BLOCKS_COUNT(f->sb)
289                         - EXT2_SUPER_FREE_BLOCKS_COUNT(f->sb))
290                    * (f->blocksize / dev->sector_size);
291
292         return ped_constraint_new (&start_align, ped_alignment_any,
293                                    &start_sector, &full_dev, min_size,
294                                    dev->length);
295 }
296 #endif /* !DISCOVER_ONLY */
297
298 static PedFileSystemOps _ext2_ops = {
299         probe:          _ext2_probe,
300 #ifndef DISCOVER_ONLY
301         clobber:        _ext2_clobber,
302         open:           _ext2_open,
303         create:         _ext2_create,
304         close:          _ext2_close,
305         check:          _ext2_check,
306         resize:         _ext2_resize,
307         copy:           NULL,
308         get_create_constraint:  _ext2_get_create_constraint,
309         get_copy_constraint:    NULL,
310         get_resize_constraint:  _ext2_get_resize_constraint
311 #else /* !DISCOVER_ONLY */
312         clobber:        NULL,
313         open:           NULL,
314         create:         NULL,
315         close:          NULL,
316         check:          NULL,
317         resize:         NULL,
318         copy:           NULL,
319         get_create_constraint:  NULL,
320         get_copy_constraint:    NULL,
321         get_resize_constraint:  NULL
322 #endif /* !DISCOVER_ONLY */
323 };
324
325 static PedFileSystemOps _ext3_ops = {
326         probe:          _ext3_probe,
327 #ifndef DISCOVER_ONLY
328         clobber:        _ext2_clobber,
329         open:           _ext2_open,
330         create:         NULL,
331         close:          _ext2_close,
332         check:          _ext2_check,
333         resize:         _ext2_resize,
334         copy:           NULL,
335         get_create_constraint:  _ext2_get_create_constraint,
336         get_copy_constraint:    NULL,
337         get_resize_constraint:  _ext2_get_resize_constraint
338 #else /* !DISCOVER_ONLY */
339         clobber:        NULL,
340         open:           NULL,
341         create:         NULL,
342         close:          NULL,
343         check:          NULL,
344         resize:         NULL,
345         copy:           NULL,
346         get_create_constraint:  NULL,
347         get_copy_constraint:    NULL,
348         get_resize_constraint:  NULL
349 #endif /* !DISCOVER_ONLY */
350 };
351
352 static PedFileSystemOps _ext4_ops = {
353         probe:          _ext4_probe,
354         clobber:        NULL,
355         open:           NULL,
356         create:         NULL,
357         close:          NULL,
358         check:          NULL,
359         resize:         NULL,
360         copy:           NULL,
361         get_create_constraint:  NULL,
362         get_copy_constraint:    NULL,
363         get_resize_constraint:  NULL
364 };
365
366 #define EXT23_BLOCK_SIZES ((int[6]){512, 1024, 2048, 4096, 8192, 0})
367
368 static PedFileSystemType _ext2_type = {
369        next:             NULL,
370        ops:              &_ext2_ops,
371        name:             "ext2",
372        block_sizes:      EXT23_BLOCK_SIZES
373 };
374
375 static PedFileSystemType _ext3_type = {
376        next:             NULL,
377        ops:              &_ext3_ops,
378        name:             "ext3",
379        block_sizes:      EXT23_BLOCK_SIZES
380 };
381
382 static PedFileSystemType _ext4_type = {
383        next:             NULL,
384        ops:              &_ext4_ops,
385        name:             "ext4",
386        block_sizes:      EXT23_BLOCK_SIZES
387 };
388
389 void ped_file_system_ext2_init ()
390 {
391         ped_file_system_type_register (&_ext2_type);
392         ped_file_system_type_register (&_ext3_type);
393         ped_file_system_type_register (&_ext4_type);
394 }
395
396 void ped_file_system_ext2_done ()
397 {
398         ped_file_system_type_unregister (&_ext2_type);
399         ped_file_system_type_unregister (&_ext3_type);
400         ped_file_system_type_unregister (&_ext4_type);
401 }