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