Whamcloud - gitweb
libext2fs: remove unnecessary casts to ext2fs_generic_bitmap
[tools/e2fsprogs.git] / lib / ext2fs / gen_bitmap64.c
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
13 #include <stdio.h>
14 #include <string.h>
15 #if HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 #include <fcntl.h>
19 #include <time.h>
20 #include <errno.h>
21 #if HAVE_SYS_STAT_H
22 #include <sys/stat.h>
23 #endif
24 #if HAVE_SYS_TYPES_H
25 #include <sys/types.h>
26 #endif
27
28 #include "ext2_fs.h"
29 #include "ext2fsP.h"
30 #include "bmap64.h"
31
32 /*
33  * Design of 64-bit bitmaps
34  *
35  * In order maintain ABI compatibility with programs that don't
36  * understand about 64-bit blocks/inodes,
37  * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap()
38  * will create old-style bitmaps unless the application passes the
39  * flag EXT2_FLAG_64BITS to ext2fs_open().  If this flag is
40  * passed, then we know the application has been recompiled, so we can
41  * use the new-style bitmaps.  If it is not passed, we have to return
42  * an error if trying to open a filesystem which needs 64-bit bitmaps.
43  *
44  * The new bitmaps use a new set of structure magic numbers, so that
45  * both the old-style and new-style interfaces can identify which
46  * version of the data structure was used.  Both the old-style and
47  * new-style interfaces will support either type of bitmap, although
48  * of course 64-bit operation will only be possible when both the
49  * new-style interface and the new-style bitmap are used.
50  *
51  * For example, the new bitmap interfaces will check the structure
52  * magic numbers and so will be able to detect old-stype bitmap.  If
53  * they see an old-style bitmap, they will pass it to the gen_bitmap.c
54  * functions for handling.  The same will be true for the old
55  * interfaces as well.
56  *
57  * The new-style interfaces will have several different back-end
58  * implementations, so we can support different encodings that are
59  * appropriate for different applications.  In general the default
60  * should be whatever makes sense, and what the application/library
61  * will use.  However, e2fsck may need specialized implementations for
62  * its own uses.  For example, when doing parent directory pointer
63  * loop detections in pass 3, the bitmap will *always* be sparse, so
64  * e2fsck can request an encoding which is optimized for that.
65  */
66
67 static void warn_bitmap(ext2fs_generic_bitmap bitmap,
68                         int code, __u64 arg)
69 {
70 #ifndef OMIT_COM_ERR
71         if (bitmap->description)
72                 com_err(0, bitmap->base_error_code+code,
73                         "#%llu for %s", arg, bitmap->description);
74         else
75                 com_err(0, bitmap->base_error_code + code, "#%llu", arg);
76 #endif
77 }
78
79
80 errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
81                                     int type, __u64 start, __u64 end,
82                                     __u64 real_end,
83                                     const char *descr,
84                                     ext2fs_generic_bitmap *ret)
85 {
86         ext2fs_generic_bitmap   bitmap;
87         struct ext2_bitmap_ops  *ops;
88         errcode_t retval;
89
90         switch (type) {
91         case EXT2FS_BMAP64_BITARRAY:
92                 ops = &ext2fs_blkmap64_bitarray;
93                 break;
94         default:
95                 return EINVAL;
96         }
97
98         retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
99                                 &bitmap);
100         if (retval)
101                 return retval;
102
103         /* XXX factor out, repeated in copy_bmap */
104         bitmap->magic = magic;
105         bitmap->fs = fs;
106         bitmap->start = start;
107         bitmap->end = end;
108         bitmap->real_end = real_end;
109         bitmap->bitmap_ops = ops;
110         switch (magic) {
111         case EXT2_ET_MAGIC_INODE_BITMAP64:
112                 bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
113                 break;
114         case EXT2_ET_MAGIC_BLOCK_BITMAP64:
115                 bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
116                 break;
117         default:
118                 bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
119         }
120         if (descr) {
121                 retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
122                 if (retval) {
123                         ext2fs_free_mem(&bitmap);
124                         return retval;
125                 }
126                 strcpy(bitmap->description, descr);
127         } else
128                 bitmap->description = 0;
129
130         retval = bitmap->bitmap_ops->new_bmap(fs, bitmap);
131         if (retval) {
132                 ext2fs_free_mem(&bitmap);
133                 ext2fs_free_mem(&bitmap->description);
134                 return retval;
135         }
136
137         *ret = bitmap;
138         return 0;
139 }
140
141 void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap)
142 {
143         if (!bmap)
144                 return;
145
146         if (EXT2FS_IS_32_BITMAP(bmap)) {
147                 ext2fs_free_generic_bitmap(bmap);
148                 return;
149         }
150
151         if (!EXT2FS_IS_64_BITMAP(bmap))
152                 return;
153
154         bmap->bitmap_ops->free_bmap(bmap);
155
156         if (bmap->description) {
157                 ext2fs_free_mem(&bmap->description);
158                 bmap->description = 0;
159         }
160         bmap->magic = 0;
161 }
162
163 errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src,
164                                    ext2fs_generic_bitmap *dest)
165 {
166         char *descr, *new_descr;
167         ext2fs_generic_bitmap   new_bmap;
168         errcode_t retval;
169
170         if (!src)
171                 return EINVAL;
172
173         if (EXT2FS_IS_32_BITMAP(src))
174                 return ext2fs_copy_generic_bitmap(src, dest);
175
176         if (!EXT2FS_IS_64_BITMAP(src))
177                 return EINVAL;
178
179         /* Allocate a new bitmap struct */
180         retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
181                                 &new_bmap);
182         if (retval)
183                 return retval;
184
185         /* Copy all the high-level parts over */
186         new_bmap->magic = src->magic;
187         new_bmap->fs = src->fs;
188         new_bmap->start = src->start;
189         new_bmap->end = src->end;
190         new_bmap->real_end = src->real_end;
191         new_bmap->bitmap_ops = src->bitmap_ops;
192         new_bmap->base_error_code = src->base_error_code;
193
194         descr = src->description;
195         if (descr) {
196                 retval = ext2fs_get_mem(strlen(descr)+1, &new_descr);
197                 if (retval) {
198                         ext2fs_free_mem(&new_bmap);
199                         return retval;
200                 }
201                 strcpy(new_descr, descr);
202                 new_bmap->description = new_descr;
203         }
204
205         retval = src->bitmap_ops->copy_bmap(src, new_bmap);
206         if (retval) {
207                 ext2fs_free_mem(&new_bmap->description);
208                 ext2fs_free_mem(&new_bmap);
209                 return retval;
210         }
211
212         *dest = new_bmap;
213
214         return 0;
215 }
216
217 errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap,
218                                      __u64 new_end,
219                                      __u64 new_real_end)
220 {
221         if (!bmap)
222                 return EINVAL;
223
224         if (EXT2FS_IS_32_BITMAP(bmap))
225                 return ext2fs_resize_generic_bitmap(bmap->magic, new_end,
226                                                     new_real_end, bmap);
227
228         if (!EXT2FS_IS_64_BITMAP(bmap))
229                 return EINVAL;
230
231         return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
232 }
233
234 errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap,
235                                         errcode_t neq,
236                                         __u64 end, __u64 *oend)
237 {
238         if (!bitmap)
239                 return EINVAL;
240
241         if (EXT2FS_IS_32_BITMAP(bitmap)) {
242                 ext2_ino_t tmp_oend;
243                 int retval;
244
245                 retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic,
246                                                          neq, end, &tmp_oend);
247                 if (oend)
248                         *oend = tmp_oend;
249                 return retval;
250         }
251
252         if (!EXT2FS_IS_64_BITMAP(bitmap))
253                 return EINVAL;
254
255         if (end > bitmap->real_end)
256                 return neq;
257         if (oend)
258                 *oend = bitmap->end;
259         bitmap->end = end;
260         return 0;
261 }
262
263 __u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap)
264 {
265         if (!bitmap)
266                 return EINVAL;
267
268         if (EXT2FS_IS_32_BITMAP(bitmap))
269                 return ext2fs_get_generic_bitmap_start(bitmap);
270
271         if (!EXT2FS_IS_64_BITMAP(bitmap))
272                 return EINVAL;
273
274         return bitmap->start;
275 }
276
277 __u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap)
278 {
279         if (!bitmap)
280                 return EINVAL;
281
282         if (EXT2FS_IS_32_BITMAP(bitmap))
283                 return ext2fs_get_generic_bitmap_end(bitmap);
284
285         if (!EXT2FS_IS_64_BITMAP(bitmap))
286                 return EINVAL;
287
288         return bitmap->end;
289 }
290
291 void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap)
292 {
293         if (EXT2FS_IS_32_BITMAP(bitmap))
294                 ext2fs_clear_generic_bitmap(bitmap);
295
296         bitmap->bitmap_ops->clear_bmap (bitmap);
297 }
298
299 int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap,
300                              __u64 arg)
301 {
302         if (!bitmap)
303                 return 0;
304
305         if (EXT2FS_IS_32_BITMAP(bitmap)) {
306                 if (arg & ~0xffffffffULL) {
307                         ext2fs_warn_bitmap2(bitmap,
308                                             EXT2FS_MARK_ERROR, 0xffffffff);
309                         return 0;
310                 }
311                 return ext2fs_mark_generic_bitmap(bitmap, arg);
312         }
313
314         if (!EXT2FS_IS_64_BITMAP(bitmap))
315                 return 0;
316
317         if ((arg < bitmap->start) || (arg > bitmap->end)) {
318                 warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
319                 return 0;
320         }
321
322         return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
323 }
324
325 int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap,
326                                __u64 arg)
327 {
328         if (!bitmap)
329                 return 0;
330
331         if (EXT2FS_IS_32_BITMAP(bitmap)) {
332                 if (arg & ~0xffffffffULL) {
333                         ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR,
334                                             0xffffffff);
335                         return 0;
336                 }
337                 return ext2fs_unmark_generic_bitmap(bitmap, arg);
338         }
339
340         if (!EXT2FS_IS_64_BITMAP(bitmap))
341                 return 0;
342
343         if ((arg < bitmap->start) || (arg > bitmap->end)) {
344                 warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
345                 return 0;
346         }
347
348         return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
349 }
350
351 int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap,
352                              __u64 arg)
353 {
354         if (!bitmap)
355                 return 0;
356
357         if (EXT2FS_IS_32_BITMAP(bitmap)) {
358                 if (arg & ~0xffffffffULL) {
359                         ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR,
360                                             0xffffffff);
361                         return 0;
362                 }
363                 return ext2fs_test_generic_bitmap(bitmap, arg);
364         }
365
366         if (!EXT2FS_IS_64_BITMAP(bitmap))
367                 return 0;
368
369         if ((arg < bitmap->start) || (arg > bitmap->end)) {
370                 warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
371                 return 0;
372         }
373
374         return bitmap->bitmap_ops->test_bmap(bitmap, arg);
375 }
376
377 errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap,
378                                         __u64 start, unsigned int num,
379                                         void *in)
380 {
381         if (!bmap)
382                 return EINVAL;
383
384         if (EXT2FS_IS_32_BITMAP(bmap)) {
385                 if ((start+num) & ~0xffffffffULL) {
386                         ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR,
387                                             0xffffffff);
388                         return EINVAL;
389                 }
390                 return ext2fs_set_generic_bitmap_range(bmap, bmap->magic,
391                                                        start, num, in);
392         }
393
394         if (!EXT2FS_IS_64_BITMAP(bmap))
395                 return EINVAL;
396
397         return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
398 }
399
400 errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap,
401                                         __u64 start, unsigned int num,
402                                         void *out)
403 {
404         if (!bmap)
405                 return EINVAL;
406
407         if (EXT2FS_IS_32_BITMAP(bmap)) {
408                 if ((start+num) & ~0xffffffffULL) {
409                         ext2fs_warn_bitmap2(bmap,
410                                             EXT2FS_UNMARK_ERROR, 0xffffffff);
411                         return EINVAL;
412                 }
413                 return ext2fs_get_generic_bitmap_range(bmap, bmap->magic,
414                                                        start, num, out);
415         }
416
417         if (!EXT2FS_IS_64_BITMAP(bmap))
418                 return EINVAL;
419
420         return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
421 }
422
423 errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
424                                       ext2fs_generic_bitmap bm1,
425                                       ext2fs_generic_bitmap bm2)
426 {
427         blk64_t i;
428
429         if (!bm1 || !bm2)
430                 return EINVAL;
431         if (bm1->magic != bm2->magic)
432                 return EINVAL;
433
434         /* Now we know both bitmaps have the same magic */
435         if (EXT2FS_IS_32_BITMAP(bm1))
436                 return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2);
437
438         if (!EXT2FS_IS_64_BITMAP(bm1))
439                 return EINVAL;
440
441         if ((bm1->start != bm2->start) ||
442             (bm1->end != bm2->end))
443                 return neq;
444
445         for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
446                 if (ext2fs_test_generic_bmap(bm1, i) !=
447                     ext2fs_test_generic_bmap(bm2, i))
448                         return neq;
449
450         return 0;
451 }
452
453 void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap)
454 {
455         __u64   start, num;
456
457         if (EXT2FS_IS_32_BITMAP(bmap)) {
458                 ext2fs_set_generic_bitmap_padding(bmap);
459                 return;
460         }
461
462         start = bmap->end + 1;
463         num = bmap->real_end - bmap->end;
464         bmap->bitmap_ops->mark_bmap_extent(bmap, start, num);
465         /* XXX ought to warn on error */
466 }
467
468 int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap,
469                                     blk64_t block, unsigned int num)
470 {
471         if (!bmap)
472                 return EINVAL;
473
474         if (num == 1)
475                 return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap)
476                                                  bmap, block);
477
478         if (EXT2FS_IS_32_BITMAP(bmap)) {
479                 if ((block+num) & ~0xffffffffULL) {
480                         ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
481                                             EXT2FS_UNMARK_ERROR, 0xffffffff);
482                         return EINVAL;
483                 }
484                 return ext2fs_test_block_bitmap_range(
485                         (ext2fs_generic_bitmap) bmap, block, num);
486         }
487
488         if (!EXT2FS_IS_64_BITMAP(bmap))
489                 return EINVAL;
490
491         return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
492 }
493
494 void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap,
495                                      blk64_t block, unsigned int num)
496 {
497         if (!bmap)
498                 return;
499
500         if (EXT2FS_IS_32_BITMAP(bmap)) {
501                 if ((block+num) & ~0xffffffffULL) {
502                         ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
503                                             EXT2FS_UNMARK_ERROR, 0xffffffff);
504                         return;
505                 }
506                 ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
507                                                block, num);
508         }
509
510         if (!EXT2FS_IS_64_BITMAP(bmap))
511                 return;
512
513         if ((block < bmap->start) || (block+num-1 > bmap->end)) {
514                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
515                                    bmap->description);
516                 return;
517         }
518
519         bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
520 }
521
522 void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap,
523                                        blk64_t block, unsigned int num)
524 {
525         if (!bmap)
526                 return;
527
528         if (EXT2FS_IS_32_BITMAP(bmap)) {
529                 if ((block+num) & ~0xffffffffULL) {
530                         ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
531                                             EXT2FS_UNMARK_ERROR, 0xffffffff);
532                         return;
533                 }
534                 ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
535                                                  block, num);
536         }
537
538         if (!EXT2FS_IS_64_BITMAP(bmap))
539                 return;
540
541         if ((block < bmap->start) || (block+num-1 > bmap->end)) {
542                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
543                                    bmap->description);
544                 return;
545         }
546
547         bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
548 }
549
550 int ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func)
551 {
552 #ifndef OMIT_COM_ERR
553         if (bitmap && bitmap->description)
554                 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
555                         "called %s with 64-bit bitmap for %s", func,
556                         bitmap->description);
557         else
558                 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
559                         "called %s with 64-bit bitmap", func);
560 #endif
561 }