gen_bitmap64.c revision 5fff975431e02c2b746b023d3c5e6755e910eaa9
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	ext2fs_free_mem(&bmap);
162}
163
164errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src,
165				   ext2fs_generic_bitmap *dest)
166{
167	char *descr, *new_descr;
168	ext2fs_generic_bitmap	new_bmap;
169	errcode_t retval;
170
171	if (!src)
172		return EINVAL;
173
174	if (EXT2FS_IS_32_BITMAP(src))
175		return ext2fs_copy_generic_bitmap(src, dest);
176
177	if (!EXT2FS_IS_64_BITMAP(src))
178		return EINVAL;
179
180	/* Allocate a new bitmap struct */
181	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
182				&new_bmap);
183	if (retval)
184		return retval;
185
186	/* Copy all the high-level parts over */
187	new_bmap->magic = src->magic;
188	new_bmap->fs = src->fs;
189	new_bmap->start = src->start;
190	new_bmap->end = src->end;
191	new_bmap->real_end = src->real_end;
192	new_bmap->bitmap_ops = src->bitmap_ops;
193	new_bmap->base_error_code = src->base_error_code;
194
195	descr = src->description;
196	if (descr) {
197		retval = ext2fs_get_mem(strlen(descr)+1, &new_descr);
198		if (retval) {
199			ext2fs_free_mem(&new_bmap);
200			return retval;
201		}
202		strcpy(new_descr, descr);
203		new_bmap->description = new_descr;
204	}
205
206	retval = src->bitmap_ops->copy_bmap(src, new_bmap);
207	if (retval) {
208		ext2fs_free_mem(&new_bmap->description);
209		ext2fs_free_mem(&new_bmap);
210		return retval;
211	}
212
213	*dest = new_bmap;
214
215	return 0;
216}
217
218errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap,
219				     __u64 new_end,
220				     __u64 new_real_end)
221{
222	if (!bmap)
223		return EINVAL;
224
225	if (EXT2FS_IS_32_BITMAP(bmap))
226		return ext2fs_resize_generic_bitmap(bmap->magic, new_end,
227						    new_real_end, bmap);
228
229	if (!EXT2FS_IS_64_BITMAP(bmap))
230		return EINVAL;
231
232	return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
233}
234
235errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap,
236					errcode_t neq,
237					__u64 end, __u64 *oend)
238{
239	if (!bitmap)
240		return EINVAL;
241
242	if (EXT2FS_IS_32_BITMAP(bitmap)) {
243		ext2_ino_t tmp_oend;
244		int retval;
245
246		retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic,
247							 neq, end, &tmp_oend);
248		if (oend)
249			*oend = tmp_oend;
250		return retval;
251	}
252
253	if (!EXT2FS_IS_64_BITMAP(bitmap))
254		return EINVAL;
255
256	if (end > bitmap->real_end)
257		return neq;
258	if (oend)
259		*oend = bitmap->end;
260	bitmap->end = end;
261	return 0;
262}
263
264__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap)
265{
266	if (!bitmap)
267		return EINVAL;
268
269	if (EXT2FS_IS_32_BITMAP(bitmap))
270		return ext2fs_get_generic_bitmap_start(bitmap);
271
272	if (!EXT2FS_IS_64_BITMAP(bitmap))
273		return EINVAL;
274
275	return bitmap->start;
276}
277
278__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap)
279{
280	if (!bitmap)
281		return EINVAL;
282
283	if (EXT2FS_IS_32_BITMAP(bitmap))
284		return ext2fs_get_generic_bitmap_end(bitmap);
285
286	if (!EXT2FS_IS_64_BITMAP(bitmap))
287		return EINVAL;
288
289	return bitmap->end;
290}
291
292void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap)
293{
294	if (EXT2FS_IS_32_BITMAP(bitmap))
295		ext2fs_clear_generic_bitmap(bitmap);
296
297	bitmap->bitmap_ops->clear_bmap (bitmap);
298}
299
300int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap,
301			     __u64 arg)
302{
303	if (!bitmap)
304		return 0;
305
306	if (EXT2FS_IS_32_BITMAP(bitmap)) {
307		if (arg & ~0xffffffffULL) {
308			ext2fs_warn_bitmap2(bitmap,
309					    EXT2FS_MARK_ERROR, 0xffffffff);
310			return 0;
311		}
312		return ext2fs_mark_generic_bitmap(bitmap, arg);
313	}
314
315	if (!EXT2FS_IS_64_BITMAP(bitmap))
316		return 0;
317
318	if ((arg < bitmap->start) || (arg > bitmap->end)) {
319		warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
320		return 0;
321	}
322
323	return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
324}
325
326int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap,
327			       __u64 arg)
328{
329	if (!bitmap)
330		return 0;
331
332	if (EXT2FS_IS_32_BITMAP(bitmap)) {
333		if (arg & ~0xffffffffULL) {
334			ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR,
335					    0xffffffff);
336			return 0;
337		}
338		return ext2fs_unmark_generic_bitmap(bitmap, arg);
339	}
340
341	if (!EXT2FS_IS_64_BITMAP(bitmap))
342		return 0;
343
344	if ((arg < bitmap->start) || (arg > bitmap->end)) {
345		warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
346		return 0;
347	}
348
349	return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
350}
351
352int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap,
353			     __u64 arg)
354{
355	if (!bitmap)
356		return 0;
357
358	if (EXT2FS_IS_32_BITMAP(bitmap)) {
359		if (arg & ~0xffffffffULL) {
360			ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR,
361					    0xffffffff);
362			return 0;
363		}
364		return ext2fs_test_generic_bitmap(bitmap, arg);
365	}
366
367	if (!EXT2FS_IS_64_BITMAP(bitmap))
368		return 0;
369
370	if ((arg < bitmap->start) || (arg > bitmap->end)) {
371		warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
372		return 0;
373	}
374
375	return bitmap->bitmap_ops->test_bmap(bitmap, arg);
376}
377
378errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap,
379					__u64 start, unsigned int num,
380					void *in)
381{
382	if (!bmap)
383		return EINVAL;
384
385	if (EXT2FS_IS_32_BITMAP(bmap)) {
386		if ((start+num) & ~0xffffffffULL) {
387			ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR,
388					    0xffffffff);
389			return EINVAL;
390		}
391		return ext2fs_set_generic_bitmap_range(bmap, bmap->magic,
392						       start, num, in);
393	}
394
395	if (!EXT2FS_IS_64_BITMAP(bmap))
396		return EINVAL;
397
398	return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
399}
400
401errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap,
402					__u64 start, unsigned int num,
403					void *out)
404{
405	if (!bmap)
406		return EINVAL;
407
408	if (EXT2FS_IS_32_BITMAP(bmap)) {
409		if ((start+num) & ~0xffffffffULL) {
410			ext2fs_warn_bitmap2(bmap,
411					    EXT2FS_UNMARK_ERROR, 0xffffffff);
412			return EINVAL;
413		}
414		return ext2fs_get_generic_bitmap_range(bmap, bmap->magic,
415						       start, num, out);
416	}
417
418	if (!EXT2FS_IS_64_BITMAP(bmap))
419		return EINVAL;
420
421	return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
422}
423
424errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
425				      ext2fs_generic_bitmap bm1,
426				      ext2fs_generic_bitmap bm2)
427{
428	blk64_t	i;
429
430	if (!bm1 || !bm2)
431		return EINVAL;
432	if (bm1->magic != bm2->magic)
433		return EINVAL;
434
435	/* Now we know both bitmaps have the same magic */
436	if (EXT2FS_IS_32_BITMAP(bm1))
437		return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2);
438
439	if (!EXT2FS_IS_64_BITMAP(bm1))
440		return EINVAL;
441
442	if ((bm1->start != bm2->start) ||
443	    (bm1->end != bm2->end))
444		return neq;
445
446	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
447		if (ext2fs_test_generic_bmap(bm1, i) !=
448		    ext2fs_test_generic_bmap(bm2, i))
449			return neq;
450
451	return 0;
452}
453
454void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap)
455{
456	__u64	start, num;
457
458	if (EXT2FS_IS_32_BITMAP(bmap)) {
459		ext2fs_set_generic_bitmap_padding(bmap);
460		return;
461	}
462
463	start = bmap->end + 1;
464	num = bmap->real_end - bmap->end;
465	bmap->bitmap_ops->mark_bmap_extent(bmap, start, num);
466	/* XXX ought to warn on error */
467}
468
469int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap,
470				    blk64_t block, unsigned int num)
471{
472	if (!bmap)
473		return EINVAL;
474
475	if (num == 1)
476		return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap)
477						 bmap, block);
478
479	if (EXT2FS_IS_32_BITMAP(bmap)) {
480		if ((block+num) & ~0xffffffffULL) {
481			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
482					    EXT2FS_UNMARK_ERROR, 0xffffffff);
483			return EINVAL;
484		}
485		return ext2fs_test_block_bitmap_range(
486			(ext2fs_generic_bitmap) bmap, block, num);
487	}
488
489	if (!EXT2FS_IS_64_BITMAP(bmap))
490		return EINVAL;
491
492	return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
493}
494
495void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap,
496				     blk64_t block, unsigned int num)
497{
498	if (!bmap)
499		return;
500
501	if (EXT2FS_IS_32_BITMAP(bmap)) {
502		if ((block+num) & ~0xffffffffULL) {
503			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
504					    EXT2FS_UNMARK_ERROR, 0xffffffff);
505			return;
506		}
507		ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
508					       block, num);
509	}
510
511	if (!EXT2FS_IS_64_BITMAP(bmap))
512		return;
513
514	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
515		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
516				   bmap->description);
517		return;
518	}
519
520	bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
521}
522
523void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap,
524				       blk64_t block, unsigned int num)
525{
526	if (!bmap)
527		return;
528
529	if (EXT2FS_IS_32_BITMAP(bmap)) {
530		if ((block+num) & ~0xffffffffULL) {
531			ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
532					    EXT2FS_UNMARK_ERROR, 0xffffffff);
533			return;
534		}
535		ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
536						 block, num);
537	}
538
539	if (!EXT2FS_IS_64_BITMAP(bmap))
540		return;
541
542	if ((block < bmap->start) || (block+num-1 > bmap->end)) {
543		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
544				   bmap->description);
545		return;
546	}
547
548	bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
549}
550
551int ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func)
552{
553#ifndef OMIT_COM_ERR
554	if (bitmap && bitmap->description)
555		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
556			"called %s with 64-bit bitmap for %s", func,
557			bitmap->description);
558	else
559		com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
560			"called %s with 64-bit bitmap", func);
561#endif
562}
563