]>
Commit | Line | Data |
---|---|---|
69365c68 TT |
1 | /* |
2 | * gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and | |
3 | * block bitmaps. | |
4 | * | |
5 | * Copyright (C) 2007, 2008 Theodore Ts'o. | |
6 | * | |
7 | * %Begin-Header% | |
8 | * This file may be redistributed under the terms of the GNU Public | |
9 | * License. | |
10 | * %End-Header% | |
11 | */ | |
12 | ||
d1154eb4 | 13 | #include "config.h" |
69365c68 TT |
14 | #include <stdio.h> |
15 | #include <string.h> | |
16 | #if HAVE_UNISTD_H | |
17 | #include <unistd.h> | |
18 | #endif | |
19 | #include <fcntl.h> | |
20 | #include <time.h> | |
21 | #include <errno.h> | |
22 | #if HAVE_SYS_STAT_H | |
23 | #include <sys/stat.h> | |
24 | #endif | |
25 | #if HAVE_SYS_TYPES_H | |
26 | #include <sys/types.h> | |
27 | #endif | |
b96365f8 MF |
28 | #ifdef HAVE_SYS_TIME_H |
29 | #include <sys/time.h> | |
30 | #endif | |
69365c68 TT |
31 | |
32 | #include "ext2_fs.h" | |
33 | #include "ext2fsP.h" | |
34 | #include "bmap64.h" | |
35 | ||
36 | /* | |
37 | * Design of 64-bit bitmaps | |
38 | * | |
39 | * In order maintain ABI compatibility with programs that don't | |
40 | * understand about 64-bit blocks/inodes, | |
41 | * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap() | |
42 | * will create old-style bitmaps unless the application passes the | |
43 | * flag EXT2_FLAG_64BITS to ext2fs_open(). If this flag is | |
44 | * passed, then we know the application has been recompiled, so we can | |
45 | * use the new-style bitmaps. If it is not passed, we have to return | |
46 | * an error if trying to open a filesystem which needs 64-bit bitmaps. | |
47 | * | |
48 | * The new bitmaps use a new set of structure magic numbers, so that | |
49 | * both the old-style and new-style interfaces can identify which | |
50 | * version of the data structure was used. Both the old-style and | |
51 | * new-style interfaces will support either type of bitmap, although | |
52 | * of course 64-bit operation will only be possible when both the | |
53 | * new-style interface and the new-style bitmap are used. | |
54 | * | |
55 | * For example, the new bitmap interfaces will check the structure | |
56 | * magic numbers and so will be able to detect old-stype bitmap. If | |
57 | * they see an old-style bitmap, they will pass it to the gen_bitmap.c | |
58 | * functions for handling. The same will be true for the old | |
59 | * interfaces as well. | |
60 | * | |
61 | * The new-style interfaces will have several different back-end | |
62 | * implementations, so we can support different encodings that are | |
63 | * appropriate for different applications. In general the default | |
64 | * should be whatever makes sense, and what the application/library | |
65 | * will use. However, e2fsck may need specialized implementations for | |
66 | * its own uses. For example, when doing parent directory pointer | |
67 | * loop detections in pass 3, the bitmap will *always* be sparse, so | |
68 | * e2fsck can request an encoding which is optimized for that. | |
69 | */ | |
70 | ||
83d9ffcc | 71 | static void warn_bitmap(ext2fs_generic_bitmap_64 bitmap, |
69365c68 TT |
72 | int code, __u64 arg) |
73 | { | |
74 | #ifndef OMIT_COM_ERR | |
75 | if (bitmap->description) | |
76 | com_err(0, bitmap->base_error_code+code, | |
77 | "#%llu for %s", arg, bitmap->description); | |
78 | else | |
79 | com_err(0, bitmap->base_error_code + code, "#%llu", arg); | |
80 | #endif | |
81 | } | |
82 | ||
1625bf42 | 83 | #ifdef ENABLE_BMAP_STATS_OPS |
9288e3be LC |
84 | #define INC_STAT(map, name) map->stats.name |
85 | #else | |
86 | #define INC_STAT(map, name) ;; | |
87 | #endif | |
88 | ||
69365c68 TT |
89 | |
90 | errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, | |
91 | int type, __u64 start, __u64 end, | |
92 | __u64 real_end, | |
93 | const char *descr, | |
94 | ext2fs_generic_bitmap *ret) | |
95 | { | |
83d9ffcc | 96 | ext2fs_generic_bitmap_64 bitmap; |
69365c68 | 97 | struct ext2_bitmap_ops *ops; |
d182831a | 98 | ext2_ino_t num_dirs; |
69365c68 TT |
99 | errcode_t retval; |
100 | ||
67861e5b TT |
101 | if (!type) |
102 | type = EXT2FS_BMAP64_BITARRAY; | |
103 | ||
69365c68 TT |
104 | switch (type) { |
105 | case EXT2FS_BMAP64_BITARRAY: | |
106 | ops = &ext2fs_blkmap64_bitarray; | |
107 | break; | |
c1359d91 LC |
108 | case EXT2FS_BMAP64_RBTREE: |
109 | ops = &ext2fs_blkmap64_rbtree; | |
110 | break; | |
d182831a TT |
111 | case EXT2FS_BMAP64_AUTODIR: |
112 | retval = ext2fs_get_num_dirs(fs, &num_dirs); | |
113 | if (retval || num_dirs > (fs->super->s_inodes_count / 320)) | |
114 | ops = &ext2fs_blkmap64_bitarray; | |
115 | else | |
116 | ops = &ext2fs_blkmap64_rbtree; | |
117 | break; | |
69365c68 TT |
118 | default: |
119 | return EINVAL; | |
120 | } | |
121 | ||
83d9ffcc | 122 | retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64), |
9288e3be | 123 | &bitmap); |
69365c68 TT |
124 | if (retval) |
125 | return retval; | |
126 | ||
1625bf42 | 127 | #ifdef ENABLE_BMAP_STATS |
9288e3be LC |
128 | if (gettimeofday(&bitmap->stats.created, |
129 | (struct timezone *) NULL) == -1) { | |
130 | perror("gettimeofday"); | |
6a26b38a | 131 | ext2fs_free_mem(&bitmap); |
9288e3be LC |
132 | return 1; |
133 | } | |
134 | bitmap->stats.type = type; | |
135 | #endif | |
136 | ||
69365c68 TT |
137 | /* XXX factor out, repeated in copy_bmap */ |
138 | bitmap->magic = magic; | |
139 | bitmap->fs = fs; | |
140 | bitmap->start = start; | |
141 | bitmap->end = end; | |
142 | bitmap->real_end = real_end; | |
143 | bitmap->bitmap_ops = ops; | |
94968e74 | 144 | bitmap->cluster_bits = 0; |
69365c68 TT |
145 | switch (magic) { |
146 | case EXT2_ET_MAGIC_INODE_BITMAP64: | |
147 | bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; | |
148 | break; | |
149 | case EXT2_ET_MAGIC_BLOCK_BITMAP64: | |
150 | bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; | |
94968e74 | 151 | bitmap->cluster_bits = fs->cluster_ratio_bits; |
69365c68 TT |
152 | break; |
153 | default: | |
154 | bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; | |
155 | } | |
156 | if (descr) { | |
157 | retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); | |
158 | if (retval) { | |
159 | ext2fs_free_mem(&bitmap); | |
160 | return retval; | |
161 | } | |
162 | strcpy(bitmap->description, descr); | |
163 | } else | |
164 | bitmap->description = 0; | |
165 | ||
166 | retval = bitmap->bitmap_ops->new_bmap(fs, bitmap); | |
167 | if (retval) { | |
69365c68 | 168 | ext2fs_free_mem(&bitmap->description); |
ba7cb5d9 | 169 | ext2fs_free_mem(&bitmap); |
69365c68 TT |
170 | return retval; |
171 | } | |
172 | ||
83d9ffcc | 173 | *ret = (ext2fs_generic_bitmap) bitmap; |
69365c68 TT |
174 | return 0; |
175 | } | |
176 | ||
1625bf42 | 177 | #ifdef ENABLE_BMAP_STATS |
83d9ffcc | 178 | static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap_64 bitmap) |
9288e3be LC |
179 | { |
180 | struct ext2_bmap_statistics *stats = &bitmap->stats; | |
1625bf42 | 181 | #ifdef ENABLE_BMAP_STATS_OPS |
9288e3be LC |
182 | float mark_seq_perc = 0.0, test_seq_perc = 0.0; |
183 | float mark_back_perc = 0.0, test_back_perc = 0.0; | |
e64e6761 | 184 | #endif |
9288e3be LC |
185 | double inuse; |
186 | struct timeval now; | |
187 | ||
1625bf42 | 188 | #ifdef ENABLE_BMAP_STATS_OPS |
9288e3be LC |
189 | if (stats->test_count) { |
190 | test_seq_perc = ((float)stats->test_seq / | |
191 | stats->test_count) * 100; | |
192 | test_back_perc = ((float)stats->test_back / | |
193 | stats->test_count) * 100; | |
194 | } | |
195 | ||
196 | if (stats->mark_count) { | |
197 | mark_seq_perc = ((float)stats->mark_seq / | |
198 | stats->mark_count) * 100; | |
199 | mark_back_perc = ((float)stats->mark_back / | |
200 | stats->mark_count) * 100; | |
201 | } | |
202 | #endif | |
203 | ||
204 | if (gettimeofday(&now, (struct timezone *) NULL) == -1) { | |
205 | perror("gettimeofday"); | |
206 | return; | |
207 | } | |
208 | ||
209 | inuse = (double) now.tv_sec + \ | |
210 | (((double) now.tv_usec) * 0.000001); | |
211 | inuse -= (double) stats->created.tv_sec + \ | |
212 | (((double) stats->created.tv_usec) * 0.000001); | |
213 | ||
214 | fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description, | |
215 | stats->type); | |
216 | fprintf(stderr, "=================================================\n"); | |
1625bf42 | 217 | #ifdef ENABLE_BMAP_STATS_OPS |
9288e3be LC |
218 | fprintf(stderr, "%16llu bits long\n", |
219 | bitmap->real_end - bitmap->start); | |
220 | fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n", | |
221 | stats->copy_count, stats->resize_count); | |
222 | fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n", | |
223 | stats->mark_count, stats->unmark_count); | |
224 | fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n", | |
225 | stats->test_count, stats->mark_ext_count); | |
226 | fprintf(stderr, "%16lu unmark_bmap_extent\n" | |
227 | "%16lu test_clear_bmap_extent\n", | |
228 | stats->unmark_ext_count, stats->test_ext_count); | |
229 | fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n", | |
230 | stats->set_range_count, stats->get_range_count); | |
231 | fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n", | |
232 | stats->clear_count, stats->test_seq, test_seq_perc); | |
233 | fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n" | |
234 | "%16llu bits tested backwards (%.2f%%)\n", | |
235 | stats->mark_seq, mark_seq_perc, | |
236 | stats->test_back, test_back_perc); | |
237 | fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n" | |
238 | "%16.2f seconds in use\n", | |
239 | stats->mark_back, mark_back_perc, inuse); | |
1625bf42 | 240 | #endif /* ENABLE_BMAP_STATS_OPS */ |
9288e3be LC |
241 | } |
242 | #endif | |
243 | ||
83d9ffcc | 244 | void ext2fs_free_generic_bmap(ext2fs_generic_bitmap gen_bmap) |
69365c68 | 245 | { |
83d9ffcc TT |
246 | ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
247 | ||
69365c68 TT |
248 | if (!bmap) |
249 | return; | |
250 | ||
251 | if (EXT2FS_IS_32_BITMAP(bmap)) { | |
83d9ffcc | 252 | ext2fs_free_generic_bitmap(gen_bmap); |
69365c68 TT |
253 | return; |
254 | } | |
255 | ||
256 | if (!EXT2FS_IS_64_BITMAP(bmap)) | |
257 | return; | |
258 | ||
1625bf42 | 259 | #ifdef ENABLE_BMAP_STATS |
9288e3be LC |
260 | if (getenv("E2FSPROGS_BITMAP_STATS")) { |
261 | ext2fs_print_bmap_statistics(bmap); | |
262 | bmap->bitmap_ops->print_stats(bmap); | |
263 | } | |
264 | #endif | |
265 | ||
69365c68 TT |
266 | bmap->bitmap_ops->free_bmap(bmap); |
267 | ||
268 | if (bmap->description) { | |
269 | ext2fs_free_mem(&bmap->description); | |
270 | bmap->description = 0; | |
271 | } | |
272 | bmap->magic = 0; | |
5fff9754 | 273 | ext2fs_free_mem(&bmap); |
69365c68 TT |
274 | } |
275 | ||
83d9ffcc | 276 | errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src, |
69365c68 TT |
277 | ext2fs_generic_bitmap *dest) |
278 | { | |
83d9ffcc | 279 | ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64) gen_src; |
69365c68 | 280 | char *descr, *new_descr; |
83d9ffcc | 281 | ext2fs_generic_bitmap_64 new_bmap; |
69365c68 TT |
282 | errcode_t retval; |
283 | ||
284 | if (!src) | |
285 | return EINVAL; | |
286 | ||
287 | if (EXT2FS_IS_32_BITMAP(src)) | |
83d9ffcc | 288 | return ext2fs_copy_generic_bitmap(gen_src, dest); |
69365c68 TT |
289 | |
290 | if (!EXT2FS_IS_64_BITMAP(src)) | |
291 | return EINVAL; | |
292 | ||
293 | /* Allocate a new bitmap struct */ | |
83d9ffcc | 294 | retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64), |
9288e3be | 295 | &new_bmap); |
69365c68 TT |
296 | if (retval) |
297 | return retval; | |
298 | ||
9288e3be | 299 | |
1625bf42 | 300 | #ifdef ENABLE_BMAP_STATS_OPS |
9288e3be LC |
301 | src->stats.copy_count++; |
302 | #endif | |
1625bf42 | 303 | #ifdef ENABLE_BMAP_STATS |
9288e3be LC |
304 | if (gettimeofday(&new_bmap->stats.created, |
305 | (struct timezone *) NULL) == -1) { | |
306 | perror("gettimeofday"); | |
6a26b38a | 307 | ext2fs_free_mem(&new_bmap); |
9288e3be LC |
308 | return 1; |
309 | } | |
310 | new_bmap->stats.type = src->stats.type; | |
311 | #endif | |
312 | ||
69365c68 TT |
313 | /* Copy all the high-level parts over */ |
314 | new_bmap->magic = src->magic; | |
315 | new_bmap->fs = src->fs; | |
316 | new_bmap->start = src->start; | |
317 | new_bmap->end = src->end; | |
318 | new_bmap->real_end = src->real_end; | |
319 | new_bmap->bitmap_ops = src->bitmap_ops; | |
320 | new_bmap->base_error_code = src->base_error_code; | |
9c79612f | 321 | new_bmap->cluster_bits = src->cluster_bits; |
69365c68 TT |
322 | |
323 | descr = src->description; | |
324 | if (descr) { | |
4a61d17c | 325 | retval = ext2fs_get_mem(strlen(descr)+10, &new_descr); |
69365c68 TT |
326 | if (retval) { |
327 | ext2fs_free_mem(&new_bmap); | |
328 | return retval; | |
329 | } | |
c4111cd7 TT |
330 | strcpy(new_descr, "copy of "); |
331 | strcat(new_descr, descr); | |
69365c68 TT |
332 | new_bmap->description = new_descr; |
333 | } | |
334 | ||
335 | retval = src->bitmap_ops->copy_bmap(src, new_bmap); | |
336 | if (retval) { | |
337 | ext2fs_free_mem(&new_bmap->description); | |
338 | ext2fs_free_mem(&new_bmap); | |
339 | return retval; | |
340 | } | |
341 | ||
83d9ffcc | 342 | *dest = (ext2fs_generic_bitmap) new_bmap; |
69365c68 TT |
343 | |
344 | return 0; | |
345 | } | |
346 | ||
83d9ffcc | 347 | errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap, |
69365c68 TT |
348 | __u64 new_end, |
349 | __u64 new_real_end) | |
350 | { | |
83d9ffcc TT |
351 | ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
352 | ||
69365c68 TT |
353 | if (!bmap) |
354 | return EINVAL; | |
355 | ||
877d1dc0 | 356 | if (EXT2FS_IS_32_BITMAP(bmap)) |
83d9ffcc TT |
357 | return ext2fs_resize_generic_bitmap(gen_bmap->magic, new_end, |
358 | new_real_end, gen_bmap); | |
69365c68 TT |
359 | |
360 | if (!EXT2FS_IS_64_BITMAP(bmap)) | |
361 | return EINVAL; | |
362 | ||
9288e3be LC |
363 | INC_STAT(bmap, resize_count); |
364 | ||
69365c68 TT |
365 | return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end); |
366 | } | |
367 | ||
83d9ffcc | 368 | errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap, |
69365c68 TT |
369 | errcode_t neq, |
370 | __u64 end, __u64 *oend) | |
371 | { | |
83d9ffcc TT |
372 | ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap; |
373 | ||
69365c68 TT |
374 | if (!bitmap) |
375 | return EINVAL; | |
376 | ||
377 | if (EXT2FS_IS_32_BITMAP(bitmap)) { | |
378 | ext2_ino_t tmp_oend; | |
379 | int retval; | |
380 | ||
83d9ffcc TT |
381 | retval = ext2fs_fudge_generic_bitmap_end(gen_bitmap, |
382 | bitmap->magic, | |
877d1dc0 | 383 | neq, end, &tmp_oend); |
69365c68 TT |
384 | if (oend) |
385 | *oend = tmp_oend; | |
386 | return retval; | |
387 | } | |
388 | ||
389 | if (!EXT2FS_IS_64_BITMAP(bitmap)) | |
390 | return EINVAL; | |
391 | ||
392 | if (end > bitmap->real_end) | |
393 | return neq; | |
394 | if (oend) | |
395 | *oend = bitmap->end; | |
396 | bitmap->end = end; | |
397 | return 0; | |
398 | } | |
399 | ||
83d9ffcc | 400 | __u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap gen_bitmap) |
69365c68 | 401 | { |
83d9ffcc TT |
402 | ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap; |
403 | ||
69365c68 TT |
404 | if (!bitmap) |
405 | return EINVAL; | |
406 | ||
877d1dc0 | 407 | if (EXT2FS_IS_32_BITMAP(bitmap)) |
83d9ffcc | 408 | return ext2fs_get_generic_bitmap_start(gen_bitmap); |
69365c68 TT |
409 | |
410 | if (!EXT2FS_IS_64_BITMAP(bitmap)) | |
411 | return EINVAL; | |
412 | ||
413 | return bitmap->start; | |
414 | } | |
415 | ||
83d9ffcc | 416 | __u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap) |
69365c68 | 417 | { |
83d9ffcc TT |
418 | ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap; |
419 | ||
69365c68 TT |
420 | if (!bitmap) |
421 | return EINVAL; | |
422 | ||
877d1dc0 | 423 | if (EXT2FS_IS_32_BITMAP(bitmap)) |
83d9ffcc | 424 | return ext2fs_get_generic_bitmap_end(gen_bitmap); |
69365c68 TT |
425 | |
426 | if (!EXT2FS_IS_64_BITMAP(bitmap)) | |
427 | return EINVAL; | |
428 | ||
429 | return bitmap->end; | |
430 | } | |
431 | ||
83d9ffcc | 432 | void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap gen_bitmap) |
69365c68 | 433 | { |
83d9ffcc TT |
434 | ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap; |
435 | ||
877d1dc0 | 436 | if (EXT2FS_IS_32_BITMAP(bitmap)) |
83d9ffcc | 437 | ext2fs_clear_generic_bitmap(gen_bitmap); |
ba37bb70 | 438 | else |
83d9ffcc | 439 | bitmap->bitmap_ops->clear_bmap(bitmap); |
69365c68 TT |
440 | } |
441 | ||
83d9ffcc | 442 | int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap gen_bitmap, |
69365c68 TT |
443 | __u64 arg) |
444 | { | |
83d9ffcc TT |
445 | ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap; |
446 | ||
69365c68 TT |
447 | if (!bitmap) |
448 | return 0; | |
449 | ||
450 | if (EXT2FS_IS_32_BITMAP(bitmap)) { | |
451 | if (arg & ~0xffffffffULL) { | |
83d9ffcc | 452 | ext2fs_warn_bitmap2(gen_bitmap, |
69365c68 TT |
453 | EXT2FS_MARK_ERROR, 0xffffffff); |
454 | return 0; | |
455 | } | |
83d9ffcc | 456 | return ext2fs_mark_generic_bitmap(gen_bitmap, arg); |
69365c68 TT |
457 | } |
458 | ||
459 | if (!EXT2FS_IS_64_BITMAP(bitmap)) | |
460 | return 0; | |
461 | ||
94968e74 TT |
462 | arg >>= bitmap->cluster_bits; |
463 | ||
1625bf42 | 464 | #ifdef ENABLE_BMAP_STATS_OPS |
9288e3be LC |
465 | if (arg == bitmap->stats.last_marked + 1) |
466 | bitmap->stats.mark_seq++; | |
467 | if (arg < bitmap->stats.last_marked) | |
468 | bitmap->stats.mark_back++; | |
469 | bitmap->stats.last_marked = arg; | |
470 | bitmap->stats.mark_count++; | |
471 | #endif | |
472 | ||
69365c68 TT |
473 | if ((arg < bitmap->start) || (arg > bitmap->end)) { |
474 | warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); | |
475 | return 0; | |
476 | } | |
477 | ||
478 | return bitmap->bitmap_ops->mark_bmap(bitmap, arg); | |
479 | } | |
480 | ||
83d9ffcc | 481 | int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap gen_bitmap, |
69365c68 TT |
482 | __u64 arg) |
483 | { | |
83d9ffcc TT |
484 | ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap; |
485 | ||
69365c68 TT |
486 | if (!bitmap) |
487 | return 0; | |
488 | ||
489 | if (EXT2FS_IS_32_BITMAP(bitmap)) { | |
490 | if (arg & ~0xffffffffULL) { | |
83d9ffcc | 491 | ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_UNMARK_ERROR, |
877d1dc0 | 492 | 0xffffffff); |
69365c68 TT |
493 | return 0; |
494 | } | |
83d9ffcc | 495 | return ext2fs_unmark_generic_bitmap(gen_bitmap, arg); |
69365c68 TT |
496 | } |
497 | ||
498 | if (!EXT2FS_IS_64_BITMAP(bitmap)) | |
499 | return 0; | |
500 | ||
94968e74 TT |
501 | arg >>= bitmap->cluster_bits; |
502 | ||
9288e3be LC |
503 | INC_STAT(bitmap, unmark_count); |
504 | ||
69365c68 TT |
505 | if ((arg < bitmap->start) || (arg > bitmap->end)) { |
506 | warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); | |
507 | return 0; | |
508 | } | |
509 | ||
510 | return bitmap->bitmap_ops->unmark_bmap(bitmap, arg); | |
511 | } | |
512 | ||
83d9ffcc | 513 | int ext2fs_test_generic_bmap(ext2fs_generic_bitmap gen_bitmap, |
69365c68 TT |
514 | __u64 arg) |
515 | { | |
83d9ffcc | 516 | ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap; |
69365c68 TT |
517 | if (!bitmap) |
518 | return 0; | |
519 | ||
520 | if (EXT2FS_IS_32_BITMAP(bitmap)) { | |
521 | if (arg & ~0xffffffffULL) { | |
83d9ffcc | 522 | ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR, |
877d1dc0 | 523 | 0xffffffff); |
69365c68 TT |
524 | return 0; |
525 | } | |
83d9ffcc | 526 | return ext2fs_test_generic_bitmap(gen_bitmap, arg); |
69365c68 TT |
527 | } |
528 | ||
529 | if (!EXT2FS_IS_64_BITMAP(bitmap)) | |
530 | return 0; | |
531 | ||
94968e74 TT |
532 | arg >>= bitmap->cluster_bits; |
533 | ||
1625bf42 | 534 | #ifdef ENABLE_BMAP_STATS_OPS |
9288e3be LC |
535 | bitmap->stats.test_count++; |
536 | if (arg == bitmap->stats.last_tested + 1) | |
537 | bitmap->stats.test_seq++; | |
538 | if (arg < bitmap->stats.last_tested) | |
539 | bitmap->stats.test_back++; | |
540 | bitmap->stats.last_tested = arg; | |
541 | #endif | |
542 | ||
69365c68 TT |
543 | if ((arg < bitmap->start) || (arg > bitmap->end)) { |
544 | warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); | |
545 | return 0; | |
546 | } | |
547 | ||
548 | return bitmap->bitmap_ops->test_bmap(bitmap, arg); | |
549 | } | |
550 | ||
83d9ffcc | 551 | errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap gen_bmap, |
69365c68 TT |
552 | __u64 start, unsigned int num, |
553 | void *in) | |
554 | { | |
83d9ffcc TT |
555 | ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
556 | ||
69365c68 TT |
557 | if (!bmap) |
558 | return EINVAL; | |
559 | ||
560 | if (EXT2FS_IS_32_BITMAP(bmap)) { | |
15749d7d | 561 | if ((start+num-1) & ~0xffffffffULL) { |
83d9ffcc | 562 | ext2fs_warn_bitmap2(gen_bmap, EXT2FS_UNMARK_ERROR, |
877d1dc0 | 563 | 0xffffffff); |
69365c68 TT |
564 | return EINVAL; |
565 | } | |
83d9ffcc | 566 | return ext2fs_set_generic_bitmap_range(gen_bmap, bmap->magic, |
877d1dc0 | 567 | start, num, in); |
69365c68 TT |
568 | } |
569 | ||
570 | if (!EXT2FS_IS_64_BITMAP(bmap)) | |
571 | return EINVAL; | |
572 | ||
9288e3be LC |
573 | INC_STAT(bmap, set_range_count); |
574 | ||
69365c68 TT |
575 | return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in); |
576 | } | |
577 | ||
83d9ffcc | 578 | errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap gen_bmap, |
69365c68 TT |
579 | __u64 start, unsigned int num, |
580 | void *out) | |
581 | { | |
83d9ffcc TT |
582 | ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
583 | ||
69365c68 TT |
584 | if (!bmap) |
585 | return EINVAL; | |
586 | ||
587 | if (EXT2FS_IS_32_BITMAP(bmap)) { | |
15749d7d | 588 | if ((start+num-1) & ~0xffffffffULL) { |
83d9ffcc | 589 | ext2fs_warn_bitmap2(gen_bmap, |
69365c68 TT |
590 | EXT2FS_UNMARK_ERROR, 0xffffffff); |
591 | return EINVAL; | |
592 | } | |
83d9ffcc | 593 | return ext2fs_get_generic_bitmap_range(gen_bmap, bmap->magic, |
877d1dc0 | 594 | start, num, out); |
69365c68 TT |
595 | } |
596 | ||
597 | if (!EXT2FS_IS_64_BITMAP(bmap)) | |
598 | return EINVAL; | |
599 | ||
9288e3be LC |
600 | INC_STAT(bmap, get_range_count); |
601 | ||
69365c68 TT |
602 | return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out); |
603 | } | |
604 | ||
605 | errcode_t ext2fs_compare_generic_bmap(errcode_t neq, | |
83d9ffcc TT |
606 | ext2fs_generic_bitmap gen_bm1, |
607 | ext2fs_generic_bitmap gen_bm2) | |
69365c68 | 608 | { |
83d9ffcc TT |
609 | ext2fs_generic_bitmap_64 bm1 = (ext2fs_generic_bitmap_64) gen_bm1; |
610 | ext2fs_generic_bitmap_64 bm2 = (ext2fs_generic_bitmap_64) gen_bm2; | |
69365c68 TT |
611 | blk64_t i; |
612 | ||
613 | if (!bm1 || !bm2) | |
614 | return EINVAL; | |
615 | if (bm1->magic != bm2->magic) | |
616 | return EINVAL; | |
617 | ||
618 | /* Now we know both bitmaps have the same magic */ | |
619 | if (EXT2FS_IS_32_BITMAP(bm1)) | |
83d9ffcc TT |
620 | return ext2fs_compare_generic_bitmap(bm1->magic, neq, |
621 | gen_bm1, gen_bm2); | |
69365c68 TT |
622 | |
623 | if (!EXT2FS_IS_64_BITMAP(bm1)) | |
624 | return EINVAL; | |
625 | ||
626 | if ((bm1->start != bm2->start) || | |
627 | (bm1->end != bm2->end)) | |
628 | return neq; | |
629 | ||
630 | for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) | |
83d9ffcc TT |
631 | if (ext2fs_test_generic_bmap(gen_bm1, i) != |
632 | ext2fs_test_generic_bmap(gen_bm2, i)) | |
69365c68 TT |
633 | return neq; |
634 | ||
635 | return 0; | |
636 | } | |
637 | ||
83d9ffcc | 638 | void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap gen_bmap) |
69365c68 | 639 | { |
83d9ffcc | 640 | ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
69365c68 TT |
641 | __u64 start, num; |
642 | ||
643 | if (EXT2FS_IS_32_BITMAP(bmap)) { | |
83d9ffcc | 644 | ext2fs_set_generic_bitmap_padding(gen_bmap); |
69365c68 TT |
645 | return; |
646 | } | |
647 | ||
648 | start = bmap->end + 1; | |
649 | num = bmap->real_end - bmap->end; | |
650 | bmap->bitmap_ops->mark_bmap_extent(bmap, start, num); | |
651 | /* XXX ought to warn on error */ | |
652 | } | |
653 | ||
83d9ffcc | 654 | int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap, |
69365c68 TT |
655 | blk64_t block, unsigned int num) |
656 | { | |
83d9ffcc | 657 | ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
3e1816b8 TT |
658 | __u64 end = block + num; |
659 | ||
69365c68 TT |
660 | if (!bmap) |
661 | return EINVAL; | |
662 | ||
663 | if (num == 1) | |
664 | return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap) | |
665 | bmap, block); | |
666 | ||
667 | if (EXT2FS_IS_32_BITMAP(bmap)) { | |
92c55949 TT |
668 | if ((block & ~0xffffffffULL) || |
669 | ((block+num-1) & ~0xffffffffULL)) { | |
69365c68 TT |
670 | ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, |
671 | EXT2FS_UNMARK_ERROR, 0xffffffff); | |
672 | return EINVAL; | |
673 | } | |
674 | return ext2fs_test_block_bitmap_range( | |
675 | (ext2fs_generic_bitmap) bmap, block, num); | |
676 | } | |
677 | ||
678 | if (!EXT2FS_IS_64_BITMAP(bmap)) | |
679 | return EINVAL; | |
680 | ||
9288e3be LC |
681 | INC_STAT(bmap, test_ext_count); |
682 | ||
3e1816b8 TT |
683 | /* convert to clusters if necessary */ |
684 | block >>= bmap->cluster_bits; | |
685 | end += (1 << bmap->cluster_bits) - 1; | |
686 | end >>= bmap->cluster_bits; | |
687 | num = end - block; | |
688 | ||
92c55949 TT |
689 | if ((block < bmap->start) || (block > bmap->end) || |
690 | (block+num-1 > bmap->end)) { | |
3e1816b8 TT |
691 | ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block, |
692 | bmap->description); | |
0d89e5ac | 693 | return EINVAL; |
3e1816b8 TT |
694 | } |
695 | ||
69365c68 TT |
696 | return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num); |
697 | } | |
698 | ||
83d9ffcc | 699 | void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap, |
69365c68 TT |
700 | blk64_t block, unsigned int num) |
701 | { | |
83d9ffcc | 702 | ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
3e1816b8 TT |
703 | __u64 end = block + num; |
704 | ||
69365c68 TT |
705 | if (!bmap) |
706 | return; | |
707 | ||
708 | if (EXT2FS_IS_32_BITMAP(bmap)) { | |
92c55949 TT |
709 | if ((block & ~0xffffffffULL) || |
710 | ((block+num-1) & ~0xffffffffULL)) { | |
69365c68 TT |
711 | ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, |
712 | EXT2FS_UNMARK_ERROR, 0xffffffff); | |
713 | return; | |
714 | } | |
715 | ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap, | |
716 | block, num); | |
717 | } | |
718 | ||
719 | if (!EXT2FS_IS_64_BITMAP(bmap)) | |
720 | return; | |
721 | ||
9288e3be LC |
722 | INC_STAT(bmap, mark_ext_count); |
723 | ||
3e1816b8 TT |
724 | /* convert to clusters if necessary */ |
725 | block >>= bmap->cluster_bits; | |
726 | end += (1 << bmap->cluster_bits) - 1; | |
727 | end >>= bmap->cluster_bits; | |
728 | num = end - block; | |
729 | ||
92c55949 TT |
730 | if ((block < bmap->start) || (block > bmap->end) || |
731 | (block+num-1 > bmap->end)) { | |
69365c68 TT |
732 | ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, |
733 | bmap->description); | |
734 | return; | |
735 | } | |
736 | ||
737 | bmap->bitmap_ops->mark_bmap_extent(bmap, block, num); | |
738 | } | |
739 | ||
83d9ffcc | 740 | void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap, |
69365c68 TT |
741 | blk64_t block, unsigned int num) |
742 | { | |
83d9ffcc | 743 | ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
3e1816b8 TT |
744 | __u64 end = block + num; |
745 | ||
69365c68 TT |
746 | if (!bmap) |
747 | return; | |
748 | ||
749 | if (EXT2FS_IS_32_BITMAP(bmap)) { | |
92c55949 TT |
750 | if ((block & ~0xffffffffULL) || |
751 | ((block+num-1) & ~0xffffffffULL)) { | |
69365c68 TT |
752 | ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, |
753 | EXT2FS_UNMARK_ERROR, 0xffffffff); | |
754 | return; | |
755 | } | |
756 | ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap, | |
757 | block, num); | |
758 | } | |
759 | ||
760 | if (!EXT2FS_IS_64_BITMAP(bmap)) | |
761 | return; | |
762 | ||
9288e3be LC |
763 | INC_STAT(bmap, unmark_ext_count); |
764 | ||
3e1816b8 TT |
765 | /* convert to clusters if necessary */ |
766 | block >>= bmap->cluster_bits; | |
767 | end += (1 << bmap->cluster_bits) - 1; | |
768 | end >>= bmap->cluster_bits; | |
769 | num = end - block; | |
770 | ||
92c55949 TT |
771 | if ((block < bmap->start) || (block > bmap->end) || |
772 | (block+num-1 > bmap->end)) { | |
69365c68 TT |
773 | ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, |
774 | bmap->description); | |
775 | return; | |
776 | } | |
777 | ||
778 | bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num); | |
779 | } | |
c21cde99 | 780 | |
83d9ffcc | 781 | void ext2fs_warn_bitmap32(ext2fs_generic_bitmap gen_bitmap, const char *func) |
c21cde99 | 782 | { |
83d9ffcc TT |
783 | ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap; |
784 | ||
c21cde99 TT |
785 | #ifndef OMIT_COM_ERR |
786 | if (bitmap && bitmap->description) | |
787 | com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, | |
788 | "called %s with 64-bit bitmap for %s", func, | |
789 | bitmap->description); | |
790 | else | |
791 | com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, | |
792 | "called %s with 64-bit bitmap", func); | |
793 | #endif | |
794 | } | |
94968e74 TT |
795 | |
796 | errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, | |
797 | ext2fs_block_bitmap *bitmap) | |
798 | { | |
83d9ffcc TT |
799 | ext2fs_generic_bitmap_64 bmap, cmap; |
800 | ext2fs_block_bitmap gen_bmap = *bitmap, gen_cmap; | |
94968e74 | 801 | errcode_t retval; |
bd828b0d | 802 | blk64_t i, next, b_end, c_end; |
94968e74 | 803 | |
83d9ffcc TT |
804 | bmap = (ext2fs_generic_bitmap_64) gen_bmap; |
805 | if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(gen_bmap)) | |
94968e74 TT |
806 | return 0; /* Nothing to do */ |
807 | ||
808 | retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap", | |
83d9ffcc | 809 | &gen_cmap); |
94968e74 TT |
810 | if (retval) |
811 | return retval; | |
812 | ||
83d9ffcc | 813 | cmap = (ext2fs_generic_bitmap_64) gen_cmap; |
94968e74 TT |
814 | i = bmap->start; |
815 | b_end = bmap->end; | |
816 | bmap->end = bmap->real_end; | |
817 | c_end = cmap->end; | |
818 | cmap->end = cmap->real_end; | |
94968e74 | 819 | while (i < bmap->real_end) { |
bd828b0d LD |
820 | retval = ext2fs_find_first_set_block_bitmap2(gen_bmap, |
821 | i, bmap->real_end, &next); | |
822 | if (retval) | |
823 | break; | |
824 | ext2fs_mark_block_bitmap2(gen_cmap, next); | |
825 | i = EXT2FS_C2B(fs, EXT2FS_B2C(fs, next) + 1); | |
94968e74 TT |
826 | } |
827 | bmap->end = b_end; | |
828 | cmap->end = c_end; | |
83d9ffcc TT |
829 | ext2fs_free_block_bitmap(gen_bmap); |
830 | *bitmap = (ext2fs_block_bitmap) cmap; | |
94968e74 TT |
831 | return 0; |
832 | } | |
c1a1e7fc SL |
833 | |
834 | errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap, | |
835 | __u64 start, __u64 end, __u64 *out) | |
836 | { | |
83d9ffcc | 837 | ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap; |
36021974 TT |
838 | __u64 cstart, cend, cout; |
839 | errcode_t retval; | |
c1a1e7fc | 840 | |
664c3326 TT |
841 | if (!bitmap) |
842 | return EINVAL; | |
c1a1e7fc | 843 | |
664c3326 TT |
844 | if (EXT2FS_IS_32_BITMAP(bitmap)) { |
845 | blk_t blk = 0; | |
664c3326 TT |
846 | |
847 | if (((start) & ~0xffffffffULL) || | |
848 | ((end) & ~0xffffffffULL)) { | |
849 | ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); | |
850 | return EINVAL; | |
851 | } | |
852 | ||
853 | retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start, | |
854 | end, &blk); | |
855 | if (retval == 0) | |
856 | *out = blk; | |
857 | return retval; | |
858 | } | |
859 | ||
860 | if (!EXT2FS_IS_64_BITMAP(bitmap)) | |
c1a1e7fc SL |
861 | return EINVAL; |
862 | ||
83d9ffcc TT |
863 | cstart = start >> bmap64->cluster_bits; |
864 | cend = end >> bmap64->cluster_bits; | |
664c3326 | 865 | |
83d9ffcc TT |
866 | if (cstart < bmap64->start || cend > bmap64->end || start > end) { |
867 | warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start); | |
c1a1e7fc SL |
868 | return EINVAL; |
869 | } | |
870 | ||
83d9ffcc TT |
871 | if (bmap64->bitmap_ops->find_first_zero) { |
872 | retval = bmap64->bitmap_ops->find_first_zero(bmap64, cstart, | |
36021974 TT |
873 | cend, &cout); |
874 | if (retval) | |
875 | return retval; | |
876 | found: | |
83d9ffcc | 877 | cout <<= bmap64->cluster_bits; |
36021974 TT |
878 | *out = (cout >= start) ? cout : start; |
879 | return 0; | |
c1a1e7fc SL |
880 | } |
881 | ||
36021974 | 882 | for (cout = cstart; cout <= cend; cout++) |
83d9ffcc | 883 | if (!bmap64->bitmap_ops->test_bmap(bmap64, cout)) |
36021974 TT |
884 | goto found; |
885 | ||
c1a1e7fc SL |
886 | return ENOENT; |
887 | } | |
dff0b6a3 TT |
888 | |
889 | errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap, | |
890 | __u64 start, __u64 end, __u64 *out) | |
891 | { | |
83d9ffcc | 892 | ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap; |
36021974 TT |
893 | __u64 cstart, cend, cout; |
894 | errcode_t retval; | |
dff0b6a3 TT |
895 | |
896 | if (!bitmap) | |
897 | return EINVAL; | |
898 | ||
dff0b6a3 TT |
899 | if (EXT2FS_IS_32_BITMAP(bitmap)) { |
900 | blk_t blk = 0; | |
dff0b6a3 TT |
901 | |
902 | if (((start) & ~0xffffffffULL) || | |
903 | ((end) & ~0xffffffffULL)) { | |
904 | ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); | |
905 | return EINVAL; | |
c1a1e7fc | 906 | } |
dff0b6a3 TT |
907 | |
908 | retval = ext2fs_find_first_set_generic_bitmap(bitmap, start, | |
909 | end, &blk); | |
910 | if (retval == 0) | |
911 | *out = blk; | |
912 | return retval; | |
c1a1e7fc SL |
913 | } |
914 | ||
dff0b6a3 TT |
915 | if (!EXT2FS_IS_64_BITMAP(bitmap)) |
916 | return EINVAL; | |
917 | ||
83d9ffcc TT |
918 | cstart = start >> bmap64->cluster_bits; |
919 | cend = end >> bmap64->cluster_bits; | |
dff0b6a3 | 920 | |
83d9ffcc TT |
921 | if (cstart < bmap64->start || cend > bmap64->end || start > end) { |
922 | warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start); | |
dff0b6a3 TT |
923 | return EINVAL; |
924 | } | |
925 | ||
83d9ffcc TT |
926 | if (bmap64->bitmap_ops->find_first_set) { |
927 | retval = bmap64->bitmap_ops->find_first_set(bmap64, cstart, | |
36021974 TT |
928 | cend, &cout); |
929 | if (retval) | |
930 | return retval; | |
931 | found: | |
83d9ffcc | 932 | cout <<= bmap64->cluster_bits; |
36021974 TT |
933 | *out = (cout >= start) ? cout : start; |
934 | return 0; | |
dff0b6a3 TT |
935 | } |
936 | ||
36021974 | 937 | for (cout = cstart; cout <= cend; cout++) |
83d9ffcc | 938 | if (bmap64->bitmap_ops->test_bmap(bmap64, cout)) |
36021974 TT |
939 | goto found; |
940 | ||
c1a1e7fc SL |
941 | return ENOENT; |
942 | } | |
59037c53 LD |
943 | |
944 | errcode_t ext2fs_count_used_clusters(ext2_filsys fs, blk64_t start, | |
945 | blk64_t end, blk64_t *out) | |
946 | { | |
947 | blk64_t next; | |
948 | blk64_t tot_set = 0; | |
949 | errcode_t retval; | |
950 | ||
951 | while (start < end) { | |
952 | retval = ext2fs_find_first_set_block_bitmap2(fs->block_map, | |
953 | start, end, &next); | |
954 | if (retval) { | |
955 | if (retval == ENOENT) | |
956 | retval = 0; | |
957 | break; | |
958 | } | |
959 | start = next; | |
960 | ||
961 | retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map, | |
962 | start, end, &next); | |
963 | if (retval == 0) { | |
964 | tot_set += next - start; | |
965 | start = next + 1; | |
966 | } else if (retval == ENOENT) { | |
967 | retval = 0; | |
968 | tot_set += end - start + 1; | |
969 | break; | |
970 | } else | |
971 | break; | |
972 | } | |
973 | ||
974 | if (!retval) | |
975 | *out = EXT2FS_NUM_B2C(fs, tot_set); | |
976 | return retval; | |
977 | } |