]>
Commit | Line | Data |
---|---|---|
23a1b987 TT |
1 | /* |
2 | * mk_hugefiles.c -- create huge files | |
3 | */ | |
4 | ||
5 | #define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX in Solaris */ | |
c42de75b | 6 | #define _BSD_SOURCE /* for makedev() and major() */ |
82e48fb1 | 7 | #define _DEFAULT_SOURCE /* since glibc 2.20 _BSD_SOURCE is deprecated */ |
23a1b987 TT |
8 | |
9 | #include "config.h" | |
10 | #include <stdio.h> | |
c42de75b | 11 | #include <stdarg.h> |
23a1b987 TT |
12 | #include <string.h> |
13 | #include <strings.h> | |
14 | #include <fcntl.h> | |
15 | #include <ctype.h> | |
16 | #include <time.h> | |
17 | #ifdef __linux__ | |
18 | #include <sys/utsname.h> | |
19 | #endif | |
20 | #ifdef HAVE_GETOPT_H | |
21 | #include <getopt.h> | |
22 | #else | |
23 | extern char *optarg; | |
24 | extern int optind; | |
25 | #endif | |
26 | #ifdef HAVE_UNISTD_H | |
27 | #include <unistd.h> | |
28 | #endif | |
29 | #ifdef HAVE_STDLIB_H | |
30 | #include <stdlib.h> | |
31 | #endif | |
32 | #ifdef HAVE_ERRNO_H | |
33 | #include <errno.h> | |
34 | #endif | |
0a3d8041 | 35 | #ifdef HAVE_SYS_IOCTL_H |
23a1b987 | 36 | #include <sys/ioctl.h> |
0a3d8041 | 37 | #endif |
23a1b987 TT |
38 | #include <sys/types.h> |
39 | #include <sys/stat.h> | |
3fb715b5 MF |
40 | #ifdef HAVE_SYS_SYSMACROS_H |
41 | #include <sys/sysmacros.h> | |
42 | #endif | |
23a1b987 TT |
43 | #include <libgen.h> |
44 | #include <limits.h> | |
45 | #include <blkid/blkid.h> | |
46 | ||
47 | #include "ext2fs/ext2_fs.h" | |
48 | #include "ext2fs/ext2fsP.h" | |
49 | #include "et/com_err.h" | |
50 | #include "uuid/uuid.h" | |
51 | #include "e2p/e2p.h" | |
52 | #include "ext2fs/ext2fs.h" | |
53 | #include "util.h" | |
1dc16b0b TT |
54 | #include "support/profile.h" |
55 | #include "support/prof_err.h" | |
99ceb8ec | 56 | #include "support/nls-enable.h" |
23a1b987 TT |
57 | #include "mke2fs.h" |
58 | ||
59 | static int uid; | |
60 | static int gid; | |
61 | static blk64_t num_blocks; | |
62 | static blk64_t num_slack; | |
63 | static unsigned long num_files; | |
64 | static blk64_t goal; | |
65 | static char *fn_prefix; | |
66 | static int idx_digits; | |
67 | static char *fn_buf; | |
68 | static char *fn_numbuf; | |
69 | int zero_hugefile = 1; | |
70 | ||
c42de75b TT |
71 | #define SYSFS_PATH_LEN 256 |
72 | typedef char sysfs_path_t[SYSFS_PATH_LEN]; | |
73 | ||
74 | #ifndef HAVE_SNPRINTF | |
75 | /* | |
76 | * We are very careful to avoid needing to worry about buffer | |
77 | * overflows, so we don't really need to use snprintf() except as an | |
78 | * additional safety check. So if snprintf() is not present, it's | |
79 | * safe to fall back to vsprintf(). This provides portability since | |
80 | * vsprintf() is guaranteed by C89, while snprintf() is only | |
81 | * guaranteed by C99 --- which for example, Microsoft Visual Studio | |
82 | * has *still* not bothered to implement. :-/ (Not that I expect | |
83 | * mke2fs to be ported to MS Visual Studio any time soon, but | |
84 | * libext2fs *does* get built on Microsoft platforms, and we might | |
85 | * want to move this into libext2fs some day.) | |
86 | */ | |
87 | static int my_snprintf(char *str, size_t size, const char *format, ...) | |
88 | { | |
89 | va_list ap; | |
90 | int ret; | |
91 | ||
92 | va_start(ap, format); | |
93 | ret = vsprintf(str, format, ap); | |
94 | va_end(ap); | |
95 | return ret; | |
96 | } | |
97 | ||
98 | #define snprintf my_snprintf | |
99 | #endif | |
100 | ||
101 | /* | |
102 | * Fall back to Linux's definitions of makedev and major are needed. | |
103 | * The search_sysfs_block() function is highly unlikely to work on | |
104 | * non-Linux systems anyway. | |
105 | */ | |
106 | #ifndef makedev | |
107 | #define makedev(maj, min) (((maj) << 8) + (min)) | |
108 | #endif | |
109 | ||
110 | static char *search_sysfs_block(dev_t devno, sysfs_path_t ret_path) | |
111 | { | |
112 | struct dirent *de, *p_de; | |
113 | DIR *dir = NULL, *p_dir = NULL; | |
114 | FILE *f; | |
115 | sysfs_path_t path, p_path; | |
116 | unsigned int major, minor; | |
117 | char *ret = ret_path; | |
118 | ||
119 | ret_path[0] = 0; | |
120 | if ((dir = opendir("/sys/block")) == NULL) | |
121 | return NULL; | |
122 | while ((de = readdir(dir)) != NULL) { | |
123 | if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") || | |
124 | strlen(de->d_name) > sizeof(path)-32) | |
125 | continue; | |
126 | snprintf(path, SYSFS_PATH_LEN, | |
127 | "/sys/block/%s/dev", de->d_name); | |
128 | f = fopen(path, "r"); | |
129 | if (f && | |
130 | (fscanf(f, "%u:%u", &major, &minor) == 2)) { | |
131 | fclose(f); f = NULL; | |
132 | if (makedev(major, minor) == devno) { | |
133 | snprintf(ret_path, SYSFS_PATH_LEN, | |
134 | "/sys/block/%s", de->d_name); | |
135 | goto success; | |
136 | } | |
137 | #ifdef major | |
138 | if (major(devno) != major) | |
139 | continue; | |
140 | #endif | |
141 | } | |
142 | if (f) | |
143 | fclose(f); | |
144 | ||
145 | snprintf(path, SYSFS_PATH_LEN, "/sys/block/%s", de->d_name); | |
146 | ||
147 | if (p_dir) | |
148 | closedir(p_dir); | |
149 | if ((p_dir = opendir(path)) == NULL) | |
150 | continue; | |
151 | while ((p_de = readdir(p_dir)) != NULL) { | |
152 | if (!strcmp(p_de->d_name, ".") || | |
153 | !strcmp(p_de->d_name, "..") || | |
154 | (strlen(p_de->d_name) > | |
155 | SYSFS_PATH_LEN - strlen(path) - 32)) | |
156 | continue; | |
157 | snprintf(p_path, SYSFS_PATH_LEN, "%s/%s/dev", | |
158 | path, p_de->d_name); | |
159 | ||
160 | f = fopen(p_path, "r"); | |
161 | if (f && | |
162 | (fscanf(f, "%u:%u", &major, &minor) == 2) && | |
163 | (((major << 8) + minor) == devno)) { | |
164 | fclose(f); | |
165 | snprintf(ret_path, SYSFS_PATH_LEN, "%s/%s", | |
166 | path, p_de->d_name); | |
167 | goto success; | |
168 | } | |
169 | if (f) | |
170 | fclose(f); | |
171 | } | |
172 | } | |
173 | ret = NULL; | |
174 | success: | |
175 | if (dir) | |
176 | closedir(dir); | |
177 | if (p_dir) | |
178 | closedir(p_dir); | |
179 | return ret; | |
180 | } | |
181 | ||
182 | static blk64_t get_partition_start(const char *device_name) | |
183 | { | |
184 | unsigned long long start; | |
185 | sysfs_path_t path; | |
186 | struct stat st; | |
187 | FILE *f; | |
188 | char *cp; | |
189 | int n; | |
190 | ||
191 | if ((stat(device_name, &st) < 0) || !S_ISBLK(st.st_mode)) | |
192 | return 0; | |
193 | ||
194 | cp = search_sysfs_block(st.st_rdev, path); | |
195 | if (!cp) | |
196 | return 0; | |
c3470fcd DW |
197 | if (strlen(path) > SYSFS_PATH_LEN - sizeof("/start")) |
198 | return 0; | |
199 | strcat(path, "/start"); | |
c42de75b TT |
200 | f = fopen(path, "r"); |
201 | if (!f) | |
202 | return 0; | |
203 | n = fscanf(f, "%llu", &start); | |
204 | fclose(f); | |
205 | return (n == 1) ? start : 0; | |
206 | } | |
207 | ||
23a1b987 TT |
208 | static errcode_t create_directory(ext2_filsys fs, char *dir, |
209 | ext2_ino_t *ret_ino) | |
210 | ||
211 | { | |
212 | struct ext2_inode inode; | |
213 | ext2_ino_t ino = EXT2_ROOT_INO; | |
214 | ext2_ino_t newdir; | |
215 | errcode_t retval = 0; | |
216 | char *fn, *cp, *next; | |
217 | ||
218 | fn = malloc(strlen(dir) + 1); | |
219 | if (fn == NULL) | |
220 | return ENOMEM; | |
221 | ||
222 | strcpy(fn, dir); | |
223 | cp = fn; | |
224 | while(1) { | |
225 | next = strchr(cp, '/'); | |
226 | if (next) | |
227 | *next++ = 0; | |
228 | if (*cp) { | |
229 | retval = ext2fs_new_inode(fs, ino, LINUX_S_IFDIR, | |
230 | NULL, &newdir); | |
231 | if (retval) | |
232 | goto errout; | |
233 | ||
234 | retval = ext2fs_mkdir(fs, ino, newdir, cp); | |
235 | if (retval) | |
236 | goto errout; | |
237 | ||
238 | ino = newdir; | |
239 | retval = ext2fs_read_inode(fs, ino, &inode); | |
240 | if (retval) | |
241 | goto errout; | |
242 | ||
243 | inode.i_uid = uid & 0xFFFF; | |
244 | ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff); | |
245 | inode.i_gid = gid & 0xFFFF; | |
246 | ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff); | |
247 | retval = ext2fs_write_inode(fs, ino, &inode); | |
248 | if (retval) | |
249 | goto errout; | |
250 | } | |
251 | if (next == NULL || *next == '\0') | |
252 | break; | |
253 | cp = next; | |
254 | } | |
255 | errout: | |
256 | free(fn); | |
257 | if (retval == 0) | |
258 | *ret_ino = ino; | |
259 | return retval; | |
260 | } | |
261 | ||
262 | static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num, | |
263 | ext2_ino_t dir, unsigned long idx, ext2_ino_t *ino) | |
264 | ||
265 | { | |
266 | errcode_t retval; | |
fff2d127 TT |
267 | blk64_t lblk, bend = 0; |
268 | __u64 size; | |
269 | blk64_t left; | |
270 | blk64_t count = 0; | |
23a1b987 | 271 | struct ext2_inode inode; |
fff2d127 | 272 | ext2_extent_handle_t handle; |
23a1b987 TT |
273 | |
274 | retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino); | |
275 | if (retval) | |
276 | return retval; | |
277 | ||
278 | memset(&inode, 0, sizeof(struct ext2_inode)); | |
279 | inode.i_mode = LINUX_S_IFREG | (0666 & ~fs->umask); | |
280 | inode.i_links_count = 1; | |
281 | inode.i_uid = uid & 0xFFFF; | |
282 | ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff); | |
283 | inode.i_gid = gid & 0xFFFF; | |
284 | ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff); | |
285 | ||
286 | retval = ext2fs_write_new_inode(fs, *ino, &inode); | |
287 | if (retval) | |
288 | return retval; | |
289 | ||
290 | ext2fs_inode_alloc_stats2(fs, *ino, +1, 0); | |
291 | ||
fff2d127 | 292 | retval = ext2fs_extent_open2(fs, *ino, &inode, &handle); |
23a1b987 TT |
293 | if (retval) |
294 | return retval; | |
fff2d127 TT |
295 | |
296 | /* | |
297 | * We don't use ext2fs_fallocate() here because hugefiles are | |
298 | * designed to be physically contiguous (if the block group | |
299 | * descriptors are configured to be in a single block at the | |
300 | * beginning of the file system, by using the | |
301 | * packed_meta_blocks layout), with the extent tree blocks | |
302 | * allocated near the beginning of the file system. | |
303 | */ | |
304 | lblk = 0; | |
305 | left = num ? num : 1; | |
306 | while (left) { | |
307 | blk64_t pblk, end; | |
308 | blk64_t n = left; | |
309 | ||
310 | retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map, | |
311 | goal, ext2fs_blocks_count(fs->super) - 1, &end); | |
312 | if (retval) | |
313 | goto errout; | |
314 | goal = end; | |
315 | ||
316 | retval = ext2fs_find_first_set_block_bitmap2(fs->block_map, goal, | |
317 | ext2fs_blocks_count(fs->super) - 1, &bend); | |
318 | if (retval == ENOENT) { | |
319 | bend = ext2fs_blocks_count(fs->super); | |
320 | if (num == 0) | |
321 | left = 0; | |
322 | } | |
323 | if (!num || bend - goal < left) | |
324 | n = bend - goal; | |
325 | pblk = goal; | |
326 | if (num) | |
327 | left -= n; | |
328 | goal += n; | |
329 | count += n; | |
330 | ext2fs_block_alloc_stats_range(fs, pblk, n, +1); | |
331 | ||
332 | if (zero_hugefile) { | |
333 | blk64_t ret_blk; | |
334 | retval = ext2fs_zero_blocks2(fs, pblk, n, | |
335 | &ret_blk, NULL); | |
336 | ||
337 | if (retval) | |
338 | com_err(program_name, retval, | |
339 | _("while zeroing block %llu " | |
340 | "for hugefile"), ret_blk); | |
341 | } | |
342 | ||
343 | while (n) { | |
344 | blk64_t l = n; | |
345 | struct ext2fs_extent newextent; | |
346 | ||
347 | if (l > EXT_INIT_MAX_LEN) | |
348 | l = EXT_INIT_MAX_LEN; | |
349 | ||
350 | newextent.e_len = l; | |
351 | newextent.e_pblk = pblk; | |
352 | newextent.e_lblk = lblk; | |
353 | newextent.e_flags = 0; | |
354 | ||
355 | retval = ext2fs_extent_insert(handle, | |
356 | EXT2_EXTENT_INSERT_AFTER, &newextent); | |
357 | if (retval) | |
358 | return retval; | |
359 | pblk += l; | |
360 | lblk += l; | |
361 | n -= l; | |
362 | } | |
363 | } | |
364 | ||
365 | retval = ext2fs_read_inode(fs, *ino, &inode); | |
97c607b1 | 366 | if (retval) |
fff2d127 | 367 | goto errout; |
23a1b987 | 368 | |
fff2d127 TT |
369 | retval = ext2fs_iblk_add_blocks(fs, &inode, |
370 | count / EXT2FS_CLUSTER_RATIO(fs)); | |
371 | if (retval) | |
372 | goto errout; | |
373 | size = (__u64) count * fs->blocksize; | |
374 | retval = ext2fs_inode_size_set(fs, &inode, size); | |
375 | if (retval) | |
376 | goto errout; | |
377 | ||
378 | retval = ext2fs_write_new_inode(fs, *ino, &inode); | |
23a1b987 TT |
379 | if (retval) |
380 | goto errout; | |
381 | ||
382 | if (idx_digits) | |
383 | sprintf(fn_numbuf, "%0*lu", idx_digits, idx); | |
384 | else if (num_files > 1) | |
385 | sprintf(fn_numbuf, "%lu", idx); | |
386 | ||
387 | retry: | |
388 | retval = ext2fs_link(fs, dir, fn_buf, *ino, EXT2_FT_REG_FILE); | |
389 | if (retval == EXT2_ET_DIR_NO_SPACE) { | |
390 | retval = ext2fs_expand_dir(fs, dir); | |
391 | if (retval) | |
392 | goto errout; | |
393 | goto retry; | |
394 | } | |
395 | ||
fff2d127 TT |
396 | if (retval) |
397 | goto errout; | |
398 | ||
23a1b987 | 399 | errout: |
fff2d127 TT |
400 | if (handle) |
401 | ext2fs_extent_free(handle); | |
402 | ||
23a1b987 TT |
403 | return retval; |
404 | } | |
405 | ||
406 | static blk64_t calc_overhead(ext2_filsys fs, blk64_t num) | |
407 | { | |
408 | blk64_t e_blocks, e_blocks2, e_blocks3, e_blocks4; | |
409 | int extents_per_block; | |
410 | int extents = (num + EXT_INIT_MAX_LEN - 1) / EXT_INIT_MAX_LEN; | |
411 | ||
412 | if (extents <= 4) | |
413 | return 0; | |
414 | ||
415 | /* | |
416 | * This calculation is due to the fact that we are inefficient | |
417 | * in how handle extent splits when appending to the end of | |
418 | * the extent tree. Sigh. We should fix this so that we can | |
419 | * actually store 340 extents per 4k block, instead of only 170. | |
420 | */ | |
421 | extents_per_block = ((fs->blocksize - | |
422 | sizeof(struct ext3_extent_header)) / | |
423 | sizeof(struct ext3_extent)); | |
424 | extents_per_block = (extents_per_block/ 2) - 1; | |
425 | ||
426 | e_blocks = (extents + extents_per_block - 1) / extents_per_block; | |
427 | e_blocks2 = (e_blocks + extents_per_block - 1) / extents_per_block; | |
428 | e_blocks3 = (e_blocks2 + extents_per_block - 1) / extents_per_block; | |
429 | e_blocks4 = (e_blocks3 + extents_per_block - 1) / extents_per_block; | |
430 | return e_blocks + e_blocks2 + e_blocks3 + e_blocks4; | |
431 | } | |
432 | ||
433 | /* | |
434 | * Find the place where we should start allocating blocks for the huge | |
435 | * files. Leave <slack> free blocks at the beginning of the file | |
436 | * system for things like metadata blocks. | |
437 | */ | |
438 | static blk64_t get_start_block(ext2_filsys fs, blk64_t slack) | |
439 | { | |
440 | errcode_t retval; | |
441 | blk64_t blk = fs->super->s_first_data_block, next; | |
442 | blk64_t last_blk = ext2fs_blocks_count(fs->super) - 1; | |
443 | ||
444 | while (slack) { | |
445 | retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map, | |
446 | blk, last_blk, &blk); | |
447 | if (retval) | |
448 | break; | |
449 | ||
450 | retval = ext2fs_find_first_set_block_bitmap2(fs->block_map, | |
451 | blk, last_blk, &next); | |
452 | if (retval) | |
453 | next = last_blk; | |
23a1b987 TT |
454 | |
455 | if (next - blk > slack) { | |
456 | blk += slack; | |
457 | break; | |
458 | } | |
459 | ||
460 | slack -= (next - blk); | |
461 | blk = next; | |
462 | } | |
463 | return blk; | |
464 | } | |
465 | ||
c42de75b TT |
466 | static blk64_t round_up_align(blk64_t b, unsigned long align, |
467 | blk64_t part_offset) | |
7efd2507 TT |
468 | { |
469 | unsigned long m; | |
470 | ||
471 | if (align == 0) | |
472 | return b; | |
c42de75b TT |
473 | part_offset = part_offset % align; |
474 | m = (b + part_offset) % align; | |
7efd2507 TT |
475 | if (m) |
476 | b += align - m; | |
477 | return b; | |
478 | } | |
479 | ||
c42de75b | 480 | errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name) |
23a1b987 TT |
481 | { |
482 | unsigned long i; | |
483 | ext2_ino_t dir; | |
484 | errcode_t retval; | |
8b90ab2b | 485 | blk64_t fs_blocks, part_offset = 0; |
7efd2507 | 486 | unsigned long align; |
23a1b987 TT |
487 | int d, dsize; |
488 | char *t; | |
489 | ||
490 | if (!get_bool_from_profile(fs_types, "make_hugefiles", 0)) | |
491 | return 0; | |
492 | ||
7889640d | 493 | if (!ext2fs_has_feature_extents(fs->super)) |
fc4f5b22 DW |
494 | return EXT2_ET_EXTENT_NOT_SUPPORTED; |
495 | ||
23a1b987 TT |
496 | uid = get_int_from_profile(fs_types, "hugefiles_uid", 0); |
497 | gid = get_int_from_profile(fs_types, "hugefiles_gid", 0); | |
498 | fs->umask = get_int_from_profile(fs_types, "hugefiles_umask", 077); | |
499 | num_files = get_int_from_profile(fs_types, "num_hugefiles", 0); | |
500 | t = get_string_from_profile(fs_types, "hugefiles_slack", "1M"); | |
501 | num_slack = parse_num_blocks2(t, fs->super->s_log_block_size); | |
502 | free(t); | |
503 | t = get_string_from_profile(fs_types, "hugefiles_size", "0"); | |
504 | num_blocks = parse_num_blocks2(t, fs->super->s_log_block_size); | |
505 | free(t); | |
7efd2507 TT |
506 | t = get_string_from_profile(fs_types, "hugefiles_align", "0"); |
507 | align = parse_num_blocks2(t, fs->super->s_log_block_size); | |
508 | free(t); | |
725502de | 509 | if (get_bool_from_profile(fs_types, "hugefiles_align_disk", 0)) { |
c42de75b TT |
510 | part_offset = get_partition_start(device_name) / |
511 | (fs->blocksize / 512); | |
725502de TT |
512 | if (part_offset % EXT2FS_CLUSTER_RATIO(fs)) { |
513 | fprintf(stderr, | |
514 | _("Partition offset of %llu (%uk) blocks " | |
515 | "not compatible with cluster size %u.\n"), | |
516 | part_offset, fs->blocksize, | |
517 | EXT2_CLUSTER_SIZE(fs->super)); | |
518 | exit(1); | |
519 | } | |
520 | } | |
c42de75b | 521 | num_blocks = round_up_align(num_blocks, align, 0); |
71d920e3 TT |
522 | zero_hugefile = get_bool_from_profile(fs_types, "zero_hugefiles", |
523 | zero_hugefile); | |
23a1b987 TT |
524 | |
525 | t = get_string_from_profile(fs_types, "hugefiles_dir", "/"); | |
526 | retval = create_directory(fs, t, &dir); | |
527 | free(t); | |
528 | if (retval) | |
529 | return retval; | |
530 | ||
531 | fn_prefix = get_string_from_profile(fs_types, "hugefiles_name", | |
532 | "hugefile"); | |
533 | idx_digits = get_int_from_profile(fs_types, "hugefiles_digits", 5); | |
534 | d = int_log10(num_files) + 1; | |
535 | if (idx_digits > d) | |
536 | d = idx_digits; | |
537 | dsize = strlen(fn_prefix) + d + 16; | |
538 | fn_buf = malloc(dsize); | |
539 | if (!fn_buf) { | |
540 | free(fn_prefix); | |
541 | return ENOMEM; | |
542 | } | |
543 | strcpy(fn_buf, fn_prefix); | |
544 | fn_numbuf = fn_buf + strlen(fn_prefix); | |
545 | free(fn_prefix); | |
546 | ||
7efd2507 TT |
547 | fs_blocks = ext2fs_free_blocks_count(fs->super); |
548 | if (fs_blocks < num_slack + align) | |
4f769f4c | 549 | return ENOSPC; |
7efd2507 TT |
550 | fs_blocks -= num_slack + align; |
551 | if (num_blocks && num_blocks > fs_blocks) | |
4f769f4c | 552 | return ENOSPC; |
23a1b987 TT |
553 | if (num_blocks == 0 && num_files == 0) |
554 | num_files = 1; | |
555 | ||
556 | if (num_files == 0 && num_blocks) { | |
557 | num_files = fs_blocks / num_blocks; | |
558 | fs_blocks -= (num_files / 16) + 1; | |
559 | fs_blocks -= calc_overhead(fs, num_blocks) * num_files; | |
560 | num_files = fs_blocks / num_blocks; | |
561 | } | |
562 | ||
563 | if (num_blocks == 0 && num_files > 1) { | |
564 | num_blocks = fs_blocks / num_files; | |
565 | fs_blocks -= (num_files / 16) + 1; | |
566 | fs_blocks -= calc_overhead(fs, num_blocks) * num_files; | |
567 | num_blocks = fs_blocks / num_files; | |
568 | } | |
569 | ||
570 | num_slack += calc_overhead(fs, num_blocks) * num_files; | |
571 | num_slack += (num_files / 16) + 1; /* space for dir entries */ | |
572 | goal = get_start_block(fs, num_slack); | |
c42de75b | 573 | goal = round_up_align(goal, align, part_offset); |
23a1b987 | 574 | |
71d920e3 TT |
575 | if ((num_blocks ? num_blocks : fs_blocks) > |
576 | (0x80000000UL / fs->blocksize)) | |
7889640d | 577 | ext2fs_set_feature_large_file(fs->super); |
71d920e3 | 578 | |
23a1b987 TT |
579 | if (!quiet) { |
580 | if (zero_hugefile && verbose) | |
4d46e6c7 | 581 | printf("%s", _("Huge files will be zero'ed\n")); |
23a1b987 TT |
582 | printf(_("Creating %lu huge file(s) "), num_files); |
583 | if (num_blocks) | |
584 | printf(_("with %llu blocks each"), num_blocks); | |
585 | fputs(": ", stdout); | |
586 | } | |
587 | for (i=0; i < num_files; i++) { | |
588 | ext2_ino_t ino; | |
589 | ||
590 | retval = mk_hugefile(fs, num_blocks, dir, i, &ino); | |
591 | if (retval) { | |
592 | com_err(program_name, retval, | |
593 | _("while creating huge file %lu"), i); | |
594 | goto errout; | |
595 | } | |
596 | } | |
597 | if (!quiet) | |
598 | fputs(_("done\n"), stdout); | |
599 | ||
600 | errout: | |
601 | free(fn_buf); | |
602 | return retval; | |
603 | } |