1 /*
2 interface.c -- parted binding glue to libext2resize
3 Copyright (C) 1998-2000, 2007 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_ext3)
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 = (EXT2_SUPER_FEATURE_COMPAT(sb)
50 & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0;
51
52 if (expect_ext3 != is_ext3)
53 return NULL;
54
55 if (version > 0 && group_nr > 0) {
56 PedSector start;
57 PedGeometry probe_geom;
58
59 start = geom->start
60 - group_blocks * group_nr
61 - first_data_block;
62
63 if (start < 0)
64 return NULL;
65 ped_geometry_init (&probe_geom, geom->dev,
66 start, block_count * block_size);
67 return _ext2_generic_probe (&probe_geom, expect_ext3);
68 } else {
69 return ped_geometry_new (geom->dev, geom->start,
70 block_count * block_size);
71 }
72 }
73 return NULL;
74 }
75
76 static PedGeometry*
77 _ext2_probe (PedGeometry* geom)
78 {
79 return _ext2_generic_probe (geom, 0);
80 }
81
82 static PedGeometry*
83 _ext3_probe (PedGeometry* geom)
84 {
85 return _ext2_generic_probe (geom, 1);
86 }
87
88 #ifndef DISCOVER_ONLY
89 static int
90 _ext2_clobber (PedGeometry* geom)
91 {
92 struct ext2_super_block sb;
93
94 if (!ped_geometry_read(geom, &sb, 2, 2))
95 return 0;
96 if (EXT2_SUPER_MAGIC(sb) != EXT2_SUPER_MAGIC_CONST)
97 return 1;
98
99 sb.s_magic = 0;
100 return ped_geometry_write(geom, &sb, 2, 2);
101 }
102
103 static PedFileSystem*
104 _ext2_open (PedGeometry* geom)
105 {
106 PedFileSystem* fs;
107 struct ext2_fs* fs_info;
108 struct ext2_dev_handle* handle;
109
110 fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
111 if (!fs) goto error;
112
113 fs->type = &_ext2_type;
114 fs->geom = ped_geometry_duplicate (geom);
115 fs->checked = 1;
116
117 handle = ext2_make_dev_handle_from_parted_geometry(fs->geom);
118 if (!handle) goto error_free_fs;
119
120 fs_info = (struct ext2_fs*) ext2_open(handle, 0);
121 if (!fs_info) goto error_free_handle;
122
123 fs->type_specific = (void*) fs_info;
124 fs_info->opt_verbose = 0;
125
126 return fs;
127
128 error_free_handle:
129 ext2_destroy_dev_handle(handle);
130 error_free_fs:
131 ped_free(fs);
132 error:
133 return NULL;
134 }
135
136 static PedFileSystem*
137 _ext2_create (PedGeometry* geom, PedTimer* timer)
138 {
139 PedFileSystem* fs;
140 struct ext2_fs* fs_info;
141 struct ext2_dev_handle* handle;
142
143 fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
144 if (!fs) goto error;
145
146 fs->type = &_ext2_type;
147 fs->geom = ped_geometry_duplicate (geom);
148
149 handle = ext2_make_dev_handle_from_parted_geometry(fs->geom);
150 if (!handle) goto error_free_fs;
151
152 fs_info = ext2_mkfs (handle, 0, 0, 0, 0, -1, -1, timer);
153 if (!fs_info) goto error_free_handle;
154
155 fs->type_specific = (void*) fs_info;
156 fs_info->opt_verbose = 0;
157
158 return fs;
159
160 error_free_handle:
161 ext2_destroy_dev_handle(handle);
162 error_free_fs:
163 ped_free(fs);
164 error:
165 return NULL;
166 }
167
168 static int
169 _ext2_close (PedFileSystem *fs)
170 {
171 struct ext2_dev_handle* handle;
172
173 handle = ((struct ext2_fs*)fs->type_specific)->devhandle;
174 ext2_close(fs->type_specific);
175 ext2_destroy_dev_handle(handle);
176
177 ped_free(fs);
178 return 1;
179 }
180
181 static int
182 _ext2_check (PedFileSystem *fs, PedTimer* timer)
183 {
184 ped_exception_throw (PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK,
185 _("The ext2 file system passed a basic check. For a more "
186 "comprehensive check, use the e2fsck program."));
187 return 1;
188 }
189
190 static int
191 _ext2_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
192 {
193 struct ext2_fs* f;
194 PedSector old_length = fs->geom->length;
195
196 PED_ASSERT (fs->geom->dev == geom->dev, return 0);
197
198 if (fs->geom->start != geom->start)
199 {
200 ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
201 PED_EXCEPTION_CANCEL,
202 _("Sorry, can't move the start of ext2 partitions yet!"));
203 return 0;
204 }
205
206 geom->dev->boot_dirty = 1;
207
208 f = (struct ext2_fs *) fs->type_specific;
209
210 /* ensure that the geometry contains the new and old geometry */
211 if (old_length > geom->length) {
212 if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9),
213 timer))
214 goto error;
215
216 fs->geom->length = geom->length;
217 fs->geom->end = fs->geom->start + geom->length - 1;
218 } else {
219 fs->geom->length = geom->length;
220 fs->geom->end = fs->geom->start + geom->length - 1;
221
222 if (!ext2_resize_fs(f, geom->length >> (f->logsize - 9),
223 timer))
224 goto error;
225 }
226 return 1;
227
228 error:
229 return 0;
230 }
231
232 static PedConstraint*
233 _ext2_get_create_constraint (const PedDevice* dev)
234 {
235 PedGeometry full_dev;
236
237 if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
238 return NULL;
239
240 return ped_constraint_new (
241 ped_alignment_any, ped_alignment_any,
242 &full_dev, &full_dev,
243 64, dev->length);
244 }
245
246 static PedConstraint*
247 _ext2_get_resize_constraint (const PedFileSystem* fs)
248 {
249 struct ext2_fs* f = (struct ext2_fs *) fs->type_specific;
250 PedDevice* dev = fs->geom->dev;
251 PedAlignment start_align;
252 PedGeometry start_sector;
253 PedGeometry full_dev;
254 PedSector min_size;
255
256 if (!ped_alignment_init (&start_align, fs->geom->start, 0))
257 return NULL;
258 if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
259 return NULL;
260 if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
261 return NULL;
262 min_size = (EXT2_SUPER_BLOCKS_COUNT(f->sb)
263 - EXT2_SUPER_FREE_BLOCKS_COUNT(f->sb))
264 * (f->blocksize / dev->sector_size);
265
266 return ped_constraint_new (&start_align, ped_alignment_any,
267 &start_sector, &full_dev, min_size,
268 dev->length);
269 }
270 #endif /* !DISCOVER_ONLY */
271
272 static PedFileSystemOps _ext2_ops = {
273 .probe = _ext2_probe,
274 #ifndef DISCOVER_ONLY
275 .clobber = _ext2_clobber,
276 .open = _ext2_open,
277 .create = _ext2_create,
278 .close = _ext2_close,
279 .check = _ext2_check,
280 .resize = _ext2_resize,
281 .copy = NULL,
282 .get_create_constraint = _ext2_get_create_constraint,
283 .get_copy_constraint = NULL,
284 .get_resize_constraint = _ext2_get_resize_constraint
285 #else /* !DISCOVER_ONLY */
286 .clobber = NULL,
287 .open = NULL,
288 .create = NULL,
289 .close = NULL,
290 .check = NULL,
291 .resize = NULL,
292 .copy = NULL,
293 .get_create_constraint = NULL,
294 .get_copy_constraint = NULL,
295 .get_resize_constraint = NULL
296 #endif /* !DISCOVER_ONLY */
297 };
298
299 static PedFileSystemOps _ext3_ops = {
300 .probe = _ext3_probe,
301 #ifndef DISCOVER_ONLY
302 .clobber = _ext2_clobber,
303 .open = _ext2_open,
304 .create = NULL,
305 .close = _ext2_close,
306 .check = _ext2_check,
307 .resize = _ext2_resize,
308 .copy = NULL,
309 .get_create_constraint = _ext2_get_create_constraint,
310 .get_copy_constraint = NULL,
311 .get_resize_constraint = _ext2_get_resize_constraint
312 #else /* !DISCOVER_ONLY */
313 .clobber = NULL,
314 .open = NULL,
315 .create = NULL,
316 .close = NULL,
317 .check = NULL,
318 .resize = NULL,
319 .copy = NULL,
320 .get_create_constraint = NULL,
321 .get_copy_constraint = NULL,
322 .get_resize_constraint = NULL
323 #endif /* !DISCOVER_ONLY */
324 };
325
326 #define EXT23_BLOCK_SIZES ((int[6]){512, 1024, 2048, 4096, 8192, 0})
327
328 static PedFileSystemType _ext2_type = {
329 .next = NULL,
330 .ops = &_ext2_ops,
331 .name = "ext2",
332 .block_sizes = EXT23_BLOCK_SIZES
333 };
334
335 static PedFileSystemType _ext3_type = {
336 .next = NULL,
337 .ops = &_ext3_ops,
338 .name = "ext3",
339 .block_sizes = EXT23_BLOCK_SIZES
340 };
341
342 void ped_file_system_ext2_init ()
343 {
344 ped_file_system_type_register (&_ext2_type);
345 ped_file_system_type_register (&_ext3_type);
346 }
347
348 void ped_file_system_ext2_done ()
349 {
350 ped_file_system_type_unregister (&_ext2_type);
351 ped_file_system_type_unregister (&_ext3_type);
352 }