gen_bitmap64.c revision ba7cb5d9d7a9415ccb611e781a3832be7259622f
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
67static 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
80errcode_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->description);
133		ext2fs_free_mem(&bitmap);
134		return retval;
135	}
136
137	*ret = bitmap;
138	return 0;
139}
140
141void 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
163errcode_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
217errcode_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
234errcode_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
291void 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
299int 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
325int 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
351int 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
377errcode_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
400errcode_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
423errcode_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
453void 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
468int 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
494void 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
522void 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
550int 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}
562