]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * main.c --- ext2 resizer main program | |
3 | * | |
4 | * Copyright (C) 1997, 1998 by Theodore Ts'o and | |
5 | * PowerQuest, Inc. | |
6 | * | |
7 | * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 by Theodore Ts'o | |
8 | * | |
9 | * %Begin-Header% | |
10 | * This file may be redistributed under the terms of the GNU Public | |
11 | * License. | |
12 | * %End-Header% | |
13 | */ | |
14 | ||
15 | #ifndef _LARGEFILE_SOURCE | |
16 | #define _LARGEFILE_SOURCE | |
17 | #endif | |
18 | #ifndef _LARGEFILE64_SOURCE | |
19 | #define _LARGEFILE64_SOURCE | |
20 | #endif | |
21 | ||
22 | #include "config.h" | |
23 | #ifdef HAVE_GETOPT_H | |
24 | #include <getopt.h> | |
25 | #else | |
26 | extern char *optarg; | |
27 | extern int optind; | |
28 | #endif | |
29 | #include <unistd.h> | |
30 | #ifdef HAVE_STDLIB_H | |
31 | #include <stdlib.h> | |
32 | #endif | |
33 | #include <sys/types.h> | |
34 | #include <sys/stat.h> | |
35 | #include <fcntl.h> | |
36 | #include <libgen.h> | |
37 | ||
38 | #include "e2p/e2p.h" | |
39 | ||
40 | #include "resize2fs.h" | |
41 | ||
42 | #include "../version.h" | |
43 | ||
44 | char *program_name; | |
45 | static char *device_name, *io_options; | |
46 | ||
47 | static void usage (char *prog) | |
48 | { | |
49 | fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] " | |
50 | "[-p] device [-b|-s|new_size] [-S RAID-stride] " | |
51 | "[-z undo_file]\n\n"), | |
52 | prog ? prog : "resize2fs"); | |
53 | ||
54 | exit (1); | |
55 | } | |
56 | ||
57 | static errcode_t resize_progress_func(ext2_resize_t rfs, int pass, | |
58 | unsigned long cur, unsigned long max) | |
59 | { | |
60 | ext2_sim_progmeter progress; | |
61 | const char *label; | |
62 | errcode_t retval; | |
63 | ||
64 | progress = (ext2_sim_progmeter) rfs->prog_data; | |
65 | if (max == 0) | |
66 | return 0; | |
67 | if (cur == 0) { | |
68 | if (progress) | |
69 | ext2fs_progress_close(progress); | |
70 | progress = 0; | |
71 | switch (pass) { | |
72 | case E2_RSZ_EXTEND_ITABLE_PASS: | |
73 | label = _("Extending the inode table"); | |
74 | break; | |
75 | case E2_RSZ_BLOCK_RELOC_PASS: | |
76 | label = _("Relocating blocks"); | |
77 | break; | |
78 | case E2_RSZ_INODE_SCAN_PASS: | |
79 | label = _("Scanning inode table"); | |
80 | break; | |
81 | case E2_RSZ_INODE_REF_UPD_PASS: | |
82 | label = _("Updating inode references"); | |
83 | break; | |
84 | case E2_RSZ_MOVE_ITABLE_PASS: | |
85 | label = _("Moving inode table"); | |
86 | break; | |
87 | default: | |
88 | label = _("Unknown pass?!?"); | |
89 | break; | |
90 | } | |
91 | printf(_("Begin pass %d (max = %lu)\n"), pass, max); | |
92 | retval = ext2fs_progress_init(&progress, label, 30, | |
93 | 40, max, 0); | |
94 | if (retval) | |
95 | progress = 0; | |
96 | rfs->prog_data = (void *) progress; | |
97 | } | |
98 | if (progress) | |
99 | ext2fs_progress_update(progress, cur); | |
100 | if (cur >= max) { | |
101 | if (progress) | |
102 | ext2fs_progress_close(progress); | |
103 | progress = 0; | |
104 | rfs->prog_data = 0; | |
105 | } | |
106 | return 0; | |
107 | } | |
108 | ||
109 | static void determine_fs_stride(ext2_filsys fs) | |
110 | { | |
111 | unsigned int group; | |
112 | unsigned long long sum; | |
113 | unsigned int has_sb, prev_has_sb = 0, num; | |
114 | unsigned int flexbg_size = 1U << fs->super->s_log_groups_per_flex; | |
115 | int i_stride, b_stride; | |
116 | ||
117 | if (fs->stride) | |
118 | return; | |
119 | num = 0; sum = 0; | |
120 | for (group = 0; group < fs->group_desc_count; group++) { | |
121 | has_sb = ext2fs_bg_has_super(fs, group); | |
122 | if (group == 0 || has_sb != prev_has_sb) | |
123 | goto next; | |
124 | b_stride = ext2fs_block_bitmap_loc(fs, group) - | |
125 | ext2fs_block_bitmap_loc(fs, group - 1) - | |
126 | fs->super->s_blocks_per_group; | |
127 | i_stride = ext2fs_inode_bitmap_loc(fs, group) - | |
128 | ext2fs_inode_bitmap_loc(fs, group - 1) - | |
129 | fs->super->s_blocks_per_group; | |
130 | if (b_stride != i_stride || | |
131 | b_stride < 0 || | |
132 | (flexbg_size > 1 && (group % flexbg_size == 0))) | |
133 | goto next; | |
134 | ||
135 | /* printf("group %d has stride %d\n", group, b_stride); */ | |
136 | sum += b_stride; | |
137 | num++; | |
138 | ||
139 | next: | |
140 | prev_has_sb = has_sb; | |
141 | } | |
142 | ||
143 | if (fs->group_desc_count > 12 && num < 3) | |
144 | sum = 0; | |
145 | ||
146 | if (num) | |
147 | fs->stride = sum / num; | |
148 | else | |
149 | fs->stride = 0; | |
150 | ||
151 | fs->super->s_raid_stride = fs->stride; | |
152 | ext2fs_mark_super_dirty(fs); | |
153 | ||
154 | #if 0 | |
155 | if (fs->stride) | |
156 | printf("Using RAID stride of %d\n", fs->stride); | |
157 | #endif | |
158 | } | |
159 | ||
160 | static void bigalloc_check(ext2_filsys fs, int force) | |
161 | { | |
162 | if (!force && ext2fs_has_feature_bigalloc(fs->super)) { | |
163 | fprintf(stderr, "%s", _("\nResizing bigalloc file systems has " | |
164 | "not been fully tested. Proceed at\n" | |
165 | "your own risk! Use the force option " | |
166 | "if you want to go ahead anyway.\n\n")); | |
167 | exit(1); | |
168 | } | |
169 | } | |
170 | ||
171 | static int resize2fs_setup_tdb(const char *device, char *undo_file, | |
172 | io_manager *io_ptr) | |
173 | { | |
174 | errcode_t retval = ENOMEM; | |
175 | const char *tdb_dir = NULL; | |
176 | char *tdb_file = NULL; | |
177 | char *dev_name, *tmp_name; | |
178 | ||
179 | /* (re)open a specific undo file */ | |
180 | if (undo_file && undo_file[0] != 0) { | |
181 | retval = set_undo_io_backing_manager(*io_ptr); | |
182 | if (retval) | |
183 | goto err; | |
184 | *io_ptr = undo_io_manager; | |
185 | retval = set_undo_io_backup_file(undo_file); | |
186 | if (retval) | |
187 | goto err; | |
188 | printf(_("Overwriting existing filesystem; this can be undone " | |
189 | "using the command:\n" | |
190 | " e2undo %s %s\n\n"), | |
191 | undo_file, device); | |
192 | return retval; | |
193 | } | |
194 | ||
195 | /* | |
196 | * Configuration via a conf file would be | |
197 | * nice | |
198 | */ | |
199 | tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); | |
200 | if (!tdb_dir) | |
201 | tdb_dir = "/var/lib/e2fsprogs"; | |
202 | ||
203 | if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || | |
204 | access(tdb_dir, W_OK)) | |
205 | return 0; | |
206 | ||
207 | tmp_name = strdup(device); | |
208 | if (!tmp_name) | |
209 | goto errout; | |
210 | dev_name = basename(tmp_name); | |
211 | tdb_file = malloc(strlen(tdb_dir) + 11 + strlen(dev_name) + 7 + 1); | |
212 | if (!tdb_file) { | |
213 | free(tmp_name); | |
214 | goto errout; | |
215 | } | |
216 | sprintf(tdb_file, "%s/resize2fs-%s.e2undo", tdb_dir, dev_name); | |
217 | free(tmp_name); | |
218 | ||
219 | if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { | |
220 | retval = errno; | |
221 | com_err(program_name, retval, | |
222 | _("while trying to delete %s"), tdb_file); | |
223 | goto errout; | |
224 | } | |
225 | ||
226 | retval = set_undo_io_backing_manager(*io_ptr); | |
227 | if (retval) | |
228 | goto errout; | |
229 | *io_ptr = undo_io_manager; | |
230 | retval = set_undo_io_backup_file(tdb_file); | |
231 | if (retval) | |
232 | goto errout; | |
233 | printf(_("Overwriting existing filesystem; this can be undone " | |
234 | "using the command:\n" | |
235 | " e2undo %s %s\n\n"), tdb_file, device); | |
236 | ||
237 | free(tdb_file); | |
238 | return 0; | |
239 | errout: | |
240 | free(tdb_file); | |
241 | err: | |
242 | com_err(program_name, retval, "%s", | |
243 | _("while trying to setup undo file\n")); | |
244 | return retval; | |
245 | } | |
246 | ||
247 | int main (int argc, char ** argv) | |
248 | { | |
249 | errcode_t retval; | |
250 | ext2_filsys fs; | |
251 | int c; | |
252 | int flags = 0; | |
253 | int flush = 0; | |
254 | int force = 0; | |
255 | int io_flags = 0; | |
256 | int force_min_size = 0; | |
257 | int print_min_size = 0; | |
258 | int fd, ret; | |
259 | int open_flags = O_RDWR; | |
260 | blk64_t new_size = 0; | |
261 | blk64_t max_size = 0; | |
262 | blk64_t min_size = 0; | |
263 | io_manager io_ptr; | |
264 | char *new_size_str = 0; | |
265 | int use_stride = -1; | |
266 | ext2fs_struct_stat st_buf; | |
267 | __s64 new_file_size; | |
268 | unsigned int sys_page_size = 4096; | |
269 | unsigned int blocksize; | |
270 | long sysval; | |
271 | int len, mount_flags; | |
272 | char *mtpt, *undo_file = NULL; | |
273 | ||
274 | #ifdef ENABLE_NLS | |
275 | setlocale(LC_MESSAGES, ""); | |
276 | setlocale(LC_CTYPE, ""); | |
277 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); | |
278 | textdomain(NLS_CAT_NAME); | |
279 | set_com_err_gettext(gettext); | |
280 | #endif | |
281 | ||
282 | add_error_table(&et_ext2_error_table); | |
283 | ||
284 | fprintf (stderr, "resize2fs %s (%s)\n", | |
285 | E2FSPROGS_VERSION, E2FSPROGS_DATE); | |
286 | if (argc && *argv) | |
287 | program_name = *argv; | |
288 | else | |
289 | usage(NULL); | |
290 | ||
291 | while ((c = getopt(argc, argv, "d:fFhMPpS:bsz:")) != EOF) { | |
292 | switch (c) { | |
293 | case 'h': | |
294 | usage(program_name); | |
295 | break; | |
296 | case 'f': | |
297 | force = 1; | |
298 | break; | |
299 | case 'F': | |
300 | flush = 1; | |
301 | break; | |
302 | case 'M': | |
303 | force_min_size = 1; | |
304 | break; | |
305 | case 'P': | |
306 | print_min_size = 1; | |
307 | break; | |
308 | case 'd': | |
309 | flags |= atoi(optarg); | |
310 | break; | |
311 | case 'p': | |
312 | flags |= RESIZE_PERCENT_COMPLETE; | |
313 | break; | |
314 | case 'S': | |
315 | use_stride = atoi(optarg); | |
316 | break; | |
317 | case 'b': | |
318 | flags |= RESIZE_ENABLE_64BIT; | |
319 | break; | |
320 | case 's': | |
321 | flags |= RESIZE_DISABLE_64BIT; | |
322 | break; | |
323 | case 'z': | |
324 | undo_file = optarg; | |
325 | break; | |
326 | default: | |
327 | usage(program_name); | |
328 | } | |
329 | } | |
330 | if (optind == argc) | |
331 | usage(program_name); | |
332 | ||
333 | device_name = argv[optind++]; | |
334 | if (optind < argc) | |
335 | new_size_str = argv[optind++]; | |
336 | if (optind < argc) | |
337 | usage(program_name); | |
338 | ||
339 | io_options = strchr(device_name, '?'); | |
340 | if (io_options) | |
341 | *io_options++ = 0; | |
342 | ||
343 | /* | |
344 | * Figure out whether or not the device is mounted, and if it is | |
345 | * where it is mounted. | |
346 | */ | |
347 | len=80; | |
348 | while (1) { | |
349 | mtpt = malloc(len); | |
350 | if (!mtpt) | |
351 | return ENOMEM; | |
352 | mtpt[len-1] = 0; | |
353 | retval = ext2fs_check_mount_point(device_name, &mount_flags, | |
354 | mtpt, len); | |
355 | if (retval) { | |
356 | com_err("ext2fs_check_mount_point", retval, | |
357 | _("while determining whether %s is mounted."), | |
358 | device_name); | |
359 | exit(1); | |
360 | } | |
361 | if (!(mount_flags & EXT2_MF_MOUNTED) || (mtpt[len-1] == 0)) | |
362 | break; | |
363 | free(mtpt); | |
364 | len = 2 * len; | |
365 | } | |
366 | ||
367 | if (print_min_size) | |
368 | open_flags = O_RDONLY; | |
369 | ||
370 | fd = ext2fs_open_file(device_name, open_flags, 0); | |
371 | if (fd < 0) { | |
372 | com_err("open", errno, _("while opening %s"), | |
373 | device_name); | |
374 | exit(1); | |
375 | } | |
376 | ||
377 | ret = ext2fs_fstat(fd, &st_buf); | |
378 | if (ret < 0) { | |
379 | com_err("open", errno, | |
380 | _("while getting stat information for %s"), | |
381 | device_name); | |
382 | exit(1); | |
383 | } | |
384 | ||
385 | if (flush) { | |
386 | retval = ext2fs_sync_device(fd, 1); | |
387 | if (retval) { | |
388 | com_err(argv[0], retval, | |
389 | _("while trying to flush %s"), | |
390 | device_name); | |
391 | exit(1); | |
392 | } | |
393 | } | |
394 | ||
395 | if (!S_ISREG(st_buf.st_mode )) { | |
396 | close(fd); | |
397 | fd = -1; | |
398 | } | |
399 | ||
400 | #ifdef CONFIG_TESTIO_DEBUG | |
401 | if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { | |
402 | io_ptr = test_io_manager; | |
403 | test_io_backing_manager = unix_io_manager; | |
404 | } else | |
405 | #endif | |
406 | io_ptr = unix_io_manager; | |
407 | ||
408 | if (!(mount_flags & EXT2_MF_MOUNTED) && !print_min_size) | |
409 | io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE; | |
410 | if (mount_flags & EXT2_MF_MOUNTED) | |
411 | io_flags |= EXT2_FLAG_DIRECT_IO; | |
412 | ||
413 | io_flags |= EXT2_FLAG_64BITS | EXT2_FLAG_THREADS; | |
414 | if (undo_file) { | |
415 | retval = resize2fs_setup_tdb(device_name, undo_file, &io_ptr); | |
416 | if (retval) | |
417 | exit(1); | |
418 | } | |
419 | retval = ext2fs_open2(device_name, io_options, io_flags, | |
420 | 0, 0, io_ptr, &fs); | |
421 | if (retval) { | |
422 | com_err(program_name, retval, _("while trying to open %s"), | |
423 | device_name); | |
424 | printf("%s", _("Couldn't find valid filesystem superblock.\n")); | |
425 | exit (1); | |
426 | } | |
427 | fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; | |
428 | ||
429 | /* | |
430 | * Before acting on an unmounted filesystem, make sure it's ok, | |
431 | * unless the user is forcing it. | |
432 | * | |
433 | * We do ERROR and VALID checks even if we're only printing the | |
434 | * minimum size, because traversal of a badly damaged filesystem | |
435 | * can cause issues as well. We don't require it to be fscked after | |
436 | * the last mount time in this case, though, as this is a bit less | |
437 | * risky. | |
438 | */ | |
439 | if (!force && !(mount_flags & EXT2_MF_MOUNTED)) { | |
440 | int checkit = 0; | |
441 | ||
442 | if (fs->super->s_state & EXT2_ERROR_FS) | |
443 | checkit = 1; | |
444 | ||
445 | if ((fs->super->s_state & EXT2_VALID_FS) == 0) | |
446 | checkit = 1; | |
447 | ||
448 | if ((fs->super->s_lastcheck < fs->super->s_mtime) && | |
449 | !print_min_size) | |
450 | checkit = 1; | |
451 | ||
452 | if ((ext2fs_free_blocks_count(fs->super) > | |
453 | ext2fs_blocks_count(fs->super)) || | |
454 | (fs->super->s_free_inodes_count > fs->super->s_inodes_count)) | |
455 | checkit = 1; | |
456 | ||
457 | if ((fs->super->s_last_orphan != 0) || | |
458 | ext2fs_has_feature_journal_needs_recovery(fs->super)) | |
459 | checkit = 1; | |
460 | ||
461 | if (checkit) { | |
462 | fprintf(stderr, | |
463 | _("Please run 'e2fsck -f %s' first.\n\n"), | |
464 | device_name); | |
465 | goto errout; | |
466 | } | |
467 | } | |
468 | ||
469 | /* | |
470 | * Check for compatibility with the feature sets. We need to | |
471 | * be more stringent than ext2fs_open(). | |
472 | */ | |
473 | if (fs->super->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) { | |
474 | com_err(program_name, EXT2_ET_UNSUPP_FEATURE, | |
475 | "(%s)", device_name); | |
476 | goto errout; | |
477 | } | |
478 | ||
479 | min_size = calculate_minimum_resize_size(fs, flags); | |
480 | ||
481 | if (print_min_size) { | |
482 | printf(_("Estimated minimum size of the filesystem: %llu\n"), | |
483 | (unsigned long long) min_size); | |
484 | success_exit: | |
485 | (void) ext2fs_close_free(&fs); | |
486 | remove_error_table(&et_ext2_error_table); | |
487 | exit(0); | |
488 | } | |
489 | ||
490 | /* Determine the system page size if possible */ | |
491 | #ifdef HAVE_SYSCONF | |
492 | #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE)) | |
493 | #define _SC_PAGESIZE _SC_PAGE_SIZE | |
494 | #endif | |
495 | #ifdef _SC_PAGESIZE | |
496 | sysval = sysconf(_SC_PAGESIZE); | |
497 | if (sysval > 0) | |
498 | sys_page_size = sysval; | |
499 | #endif /* _SC_PAGESIZE */ | |
500 | #endif /* HAVE_SYSCONF */ | |
501 | ||
502 | /* | |
503 | * Get the size of the containing partition, and use this for | |
504 | * defaults and for making sure the new filesystem doesn't | |
505 | * exceed the partition size. | |
506 | */ | |
507 | blocksize = fs->blocksize; | |
508 | retval = ext2fs_get_device_size2(device_name, blocksize, | |
509 | &max_size); | |
510 | if (retval) { | |
511 | com_err(program_name, retval, "%s", | |
512 | _("while trying to determine filesystem size")); | |
513 | goto errout; | |
514 | } | |
515 | if (force_min_size) | |
516 | new_size = min_size; | |
517 | else if (new_size_str) { | |
518 | new_size = parse_num_blocks2(new_size_str, | |
519 | fs->super->s_log_block_size); | |
520 | if (new_size == 0) { | |
521 | com_err(program_name, 0, | |
522 | _("Invalid new size: %s\n"), new_size_str); | |
523 | goto errout; | |
524 | } | |
525 | } else { | |
526 | new_size = max_size; | |
527 | /* Round down to an even multiple of a pagesize */ | |
528 | if (sys_page_size > blocksize) | |
529 | new_size &= ~((blk64_t)((sys_page_size / blocksize)-1)); | |
530 | } | |
531 | /* If changing 64bit, don't change the filesystem size. */ | |
532 | if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) { | |
533 | new_size = ext2fs_blocks_count(fs->super); | |
534 | } | |
535 | if (!ext2fs_has_feature_64bit(fs->super)) { | |
536 | /* Take 16T down to 2^32-1 blocks */ | |
537 | if (new_size == (1ULL << 32)) | |
538 | new_size--; | |
539 | else if (new_size > (1ULL << 32)) { | |
540 | com_err(program_name, 0, "%s", | |
541 | _("New size too large to be " | |
542 | "expressed in 32 bits\n")); | |
543 | goto errout; | |
544 | } | |
545 | } | |
546 | ||
547 | /* If using cluster allocations, trim down to a cluster boundary */ | |
548 | if (ext2fs_has_feature_bigalloc(fs->super)) { | |
549 | new_size &= ~((blk64_t)(1ULL << fs->cluster_ratio_bits) - 1); | |
550 | } | |
551 | ||
552 | if (!ext2fs_has_feature_meta_bg(fs->super)) { | |
553 | dgrp_t new_group_desc_count; | |
554 | unsigned long new_desc_blocks; | |
555 | ||
556 | new_group_desc_count = ext2fs_div64_ceil(new_size - | |
557 | fs->super->s_first_data_block, | |
558 | EXT2_BLOCKS_PER_GROUP(fs->super)); | |
559 | new_desc_blocks = ext2fs_div_ceil(new_group_desc_count, | |
560 | EXT2_DESC_PER_BLOCK(fs->super)); | |
561 | if ((new_desc_blocks + fs->super->s_first_data_block) > | |
562 | EXT2_BLOCKS_PER_GROUP(fs->super)) { | |
563 | com_err(program_name, 0, | |
564 | _("New size results in too many block group " | |
565 | "descriptors.\n")); | |
566 | goto errout; | |
567 | } | |
568 | } | |
569 | ||
570 | if (!force && new_size < min_size) { | |
571 | com_err(program_name, 0, | |
572 | _("New size smaller than minimum (%llu)\n"), | |
573 | (unsigned long long) min_size); | |
574 | goto errout; | |
575 | } | |
576 | if (use_stride >= 0) { | |
577 | if (use_stride >= (int) fs->super->s_blocks_per_group) { | |
578 | com_err(program_name, 0, "%s", | |
579 | _("Invalid stride length")); | |
580 | goto errout; | |
581 | } | |
582 | fs->stride = fs->super->s_raid_stride = use_stride; | |
583 | ext2fs_mark_super_dirty(fs); | |
584 | } else | |
585 | determine_fs_stride(fs); | |
586 | ||
587 | /* | |
588 | * If we are resizing a plain file, and it's not big enough, | |
589 | * automatically extend it in a sparse fashion by writing the | |
590 | * last requested block. | |
591 | */ | |
592 | new_file_size = ((__u64) new_size) * blocksize; | |
593 | if ((__u64) new_file_size > | |
594 | (((__u64) 1) << (sizeof(st_buf.st_size)*8 - 1)) - 1) | |
595 | fd = -1; | |
596 | if ((new_file_size > st_buf.st_size) && | |
597 | (fd > 0)) { | |
598 | if ((ext2fs_llseek(fd, new_file_size-1, SEEK_SET) >= 0) && | |
599 | (write(fd, "0", 1) == 1)) | |
600 | max_size = new_size; | |
601 | } | |
602 | if (!force && (new_size > max_size)) { | |
603 | fprintf(stderr, _("The containing partition (or device)" | |
604 | " is only %llu (%dk) blocks.\nYou requested a new size" | |
605 | " of %llu blocks.\n\n"), (unsigned long long) max_size, | |
606 | blocksize / 1024, (unsigned long long) new_size); | |
607 | goto errout; | |
608 | } | |
609 | if ((flags & RESIZE_DISABLE_64BIT) && (flags & RESIZE_ENABLE_64BIT)) { | |
610 | fprintf(stderr, _("Cannot set and unset 64bit feature.\n")); | |
611 | goto errout; | |
612 | } else if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) { | |
613 | if (new_size >= (1ULL << 32)) { | |
614 | fprintf(stderr, _("Cannot change the 64bit feature " | |
615 | "on a filesystem that is larger than " | |
616 | "2^32 blocks.\n")); | |
617 | goto errout; | |
618 | } | |
619 | if (mount_flags & EXT2_MF_MOUNTED) { | |
620 | fprintf(stderr, _("Cannot change the 64bit feature " | |
621 | "while the filesystem is mounted.\n")); | |
622 | goto errout; | |
623 | } | |
624 | if (flags & RESIZE_ENABLE_64BIT && | |
625 | !ext2fs_has_feature_extents(fs->super)) { | |
626 | fprintf(stderr, _("Please enable the extents feature " | |
627 | "with tune2fs before enabling the 64bit " | |
628 | "feature.\n")); | |
629 | goto errout; | |
630 | } | |
631 | } else { | |
632 | adjust_new_size(fs, &new_size); | |
633 | if (new_size == ext2fs_blocks_count(fs->super)) { | |
634 | fprintf(stderr, _("The filesystem is already " | |
635 | "%llu (%dk) blocks long. " | |
636 | "Nothing to do!\n\n"), | |
637 | (unsigned long long) new_size, | |
638 | blocksize / 1024); | |
639 | goto success_exit; | |
640 | } | |
641 | } | |
642 | if ((flags & RESIZE_ENABLE_64BIT) && | |
643 | ext2fs_has_feature_64bit(fs->super)) { | |
644 | fprintf(stderr, _("The filesystem is already 64-bit.\n")); | |
645 | goto success_exit; | |
646 | } | |
647 | if ((flags & RESIZE_DISABLE_64BIT) && | |
648 | !ext2fs_has_feature_64bit(fs->super)) { | |
649 | fprintf(stderr, _("The filesystem is already 32-bit.\n")); | |
650 | goto success_exit; | |
651 | } | |
652 | if (new_size < ext2fs_blocks_count(fs->super) && | |
653 | ext2fs_has_feature_stable_inodes(fs->super)) { | |
654 | fprintf(stderr, _("Cannot shrink this filesystem " | |
655 | "because it has the stable_inodes feature flag.\n")); | |
656 | goto errout; | |
657 | } | |
658 | if (mount_flags & EXT2_MF_MOUNTED) { | |
659 | retval = online_resize_fs(fs, mtpt, &new_size, flags); | |
660 | } else { | |
661 | bigalloc_check(fs, force); | |
662 | if (flags & RESIZE_ENABLE_64BIT) | |
663 | printf(_("Converting the filesystem to 64-bit.\n")); | |
664 | else if (flags & RESIZE_DISABLE_64BIT) | |
665 | printf(_("Converting the filesystem to 32-bit.\n")); | |
666 | else | |
667 | printf(_("Resizing the filesystem on " | |
668 | "%s to %llu (%dk) blocks.\n"), | |
669 | device_name, (unsigned long long) new_size, | |
670 | blocksize / 1024); | |
671 | retval = resize_fs(fs, &new_size, flags, | |
672 | ((flags & RESIZE_PERCENT_COMPLETE) ? | |
673 | resize_progress_func : 0)); | |
674 | } | |
675 | free(mtpt); | |
676 | if (retval) { | |
677 | com_err(program_name, retval, _("while trying to resize %s"), | |
678 | device_name); | |
679 | fprintf(stderr, | |
680 | _("Please run 'e2fsck -fy %s' to fix the filesystem\n" | |
681 | "after the aborted resize operation.\n"), | |
682 | device_name); | |
683 | goto errout; | |
684 | } | |
685 | printf(_("The filesystem on %s is now %llu (%dk) blocks long.\n\n"), | |
686 | device_name, (unsigned long long) new_size, blocksize / 1024); | |
687 | ||
688 | if ((st_buf.st_size > new_file_size) && | |
689 | (fd > 0)) { | |
690 | #ifdef HAVE_FTRUNCATE64 | |
691 | retval = ftruncate64(fd, new_file_size); | |
692 | #else | |
693 | retval = 0; | |
694 | /* Only truncate if new_file_size doesn't overflow off_t */ | |
695 | if (((off_t) new_file_size) == new_file_size) | |
696 | retval = ftruncate(fd, (off_t) new_file_size); | |
697 | #endif | |
698 | if (retval) | |
699 | com_err(program_name, retval, | |
700 | _("while trying to truncate %s"), | |
701 | device_name); | |
702 | } | |
703 | if (fd > 0) | |
704 | close(fd); | |
705 | remove_error_table(&et_ext2_error_table); | |
706 | return 0; | |
707 | errout: | |
708 | (void) ext2fs_close_free(&fs); | |
709 | remove_error_table(&et_ext2_error_table); | |
710 | return 1; | |
711 | } |