blknum.c revision cd65a24e756b8f6770a5961fd94c67eb00dd7baa
1/*
2 * blknum.c --- Functions to handle blk64_t and high/low 64-bit block
3 * number.
4 *
5 * Copyright IBM Corporation, 2007
6 * Author Jose R. Santos <jrs@us.ibm.com>
7 *
8 * %Begin-Header%
9 * This file may be redistributed under the terms of the GNU Public
10 * License.
11 * %End-Header%
12 */
13
14#include "ext2fs.h"
15
16/*
17 * Return the group # of a block
18 */
19dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t blk)
20{
21	return (blk - fs->super->s_first_data_block) /
22		fs->super->s_blocks_per_group;
23}
24
25/*
26 * Return the first block (inclusive) in a group
27 */
28blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group)
29{
30	return fs->super->s_first_data_block +
31		((blk64_t)group * fs->super->s_blocks_per_group);
32}
33
34/*
35 * Return the last block (inclusive) in a group
36 */
37blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group)
38{
39	return (group == fs->group_desc_count - 1 ?
40		ext2fs_blocks_count(fs->super) - 1 :
41		ext2fs_group_first_block2(fs, group) +
42			(fs->super->s_blocks_per_group - 1));
43}
44
45/*
46 * Return the inode data block count
47 */
48blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
49					struct ext2_inode *inode)
50{
51	return (inode->i_blocks |
52		((fs->super->s_feature_incompat &
53		  EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ?
54		 (__u64) inode->osd2.linux2.l_i_blocks_hi << 32 : 0)) -
55		(inode->i_file_acl ? fs->blocksize >> 9 : 0);
56}
57
58/*
59 * Return the inode i_blocks count
60 */
61blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
62					struct ext2_inode *inode)
63{
64	return (inode->i_blocks |
65		((fs->super->s_feature_incompat &
66		  EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ?
67		 (__u64)inode->osd2.linux2.l_i_blocks_hi << 32 : 0));
68}
69
70/*
71 * Return the fs block count
72 */
73blk64_t ext2fs_blocks_count(struct ext2_super_block *super)
74{
75	return super->s_blocks_count |
76		(super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT ?
77		(__u64) super->s_blocks_count_hi << 32 : 0);
78}
79
80/*
81 * Set the fs block count
82 */
83void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
84{
85	super->s_blocks_count = blk;
86	if (super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
87		super->s_blocks_count_hi = (__u64) blk >> 32;
88}
89
90/*
91 * Add to the current fs block count
92 */
93void ext2fs_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
94{
95	blk64_t tmp;
96	tmp = ext2fs_blocks_count(super) + blk;
97	ext2fs_blocks_count_set(super, tmp);
98}
99
100/*
101 * Return the fs reserved block count
102 */
103blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super)
104{
105	return super->s_r_blocks_count |
106		(super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT ?
107		(__u64) super->s_r_blocks_count_hi << 32 : 0);
108}
109
110/*
111 * Set the fs reserved block count
112 */
113void ext2fs_r_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
114{
115	super->s_r_blocks_count = blk;
116	if (super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
117		super->s_r_blocks_count_hi = (__u64) blk >> 32;
118}
119
120/*
121 * Add to the current reserved fs block count
122 */
123void ext2fs_r_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
124{
125	blk64_t tmp;
126	tmp = ext2fs_r_blocks_count(super) + blk;
127	ext2fs_r_blocks_count_set(super, tmp);
128}
129
130/*
131 * Return the fs free block count
132 */
133blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super)
134{
135	return super->s_free_blocks_count |
136		(super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT ?
137		(__u64) super->s_free_blocks_hi << 32 : 0);
138}
139
140/*
141 * Set the fs free block count
142 */
143void ext2fs_free_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
144{
145	super->s_free_blocks_count = blk;
146	if (super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
147		super->s_free_blocks_hi = (__u64) blk >> 32;
148}
149
150/*
151 * Add to the current free fs block count
152 */
153void ext2fs_free_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
154{
155	blk64_t tmp;
156	tmp = ext2fs_free_blocks_count(super) + blk;
157	ext2fs_free_blocks_count_set(super, tmp);
158}
159
160/*
161 * Get a pointer to a block group descriptor.  We need the explicit
162 * pointer to the group desc for code that swaps block group
163 * descriptors before writing them out, as it wants to make a copy and
164 * do the swap there.
165 */
166struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
167					  struct ext2_group_desc *gdp,
168					  dgrp_t group)
169{
170	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT)
171		return (struct ext2_group_desc *)
172			((struct ext4_group_desc *) gdp + group);
173	else
174		return (struct ext2_group_desc *) gdp + group;
175}
176
177/*
178 * Return the block bitmap block of a group
179 */
180blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group)
181{
182	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
183		struct ext4_group_desc *gdp;
184		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
185
186		return gdp->bg_block_bitmap |
187			(fs->super->s_feature_incompat
188			 & EXT4_FEATURE_INCOMPAT_64BIT ?
189			 (__u64) gdp->bg_block_bitmap_hi << 32 : 0);
190	}
191
192	return fs->group_desc[group].bg_block_bitmap;
193}
194
195/*
196 * Set the block bitmap block of a group
197 */
198void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
199{
200	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
201		struct ext4_group_desc *gdp;
202		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
203		gdp->bg_block_bitmap = blk;
204		if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
205			gdp->bg_block_bitmap_hi = (__u64) blk >> 32;
206	} else
207		fs->group_desc[group].bg_block_bitmap = blk;
208}
209
210/*
211 * Return the inode bitmap block of a group
212 */
213blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group)
214{
215	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
216		struct ext4_group_desc *gdp;
217		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
218
219		return gdp->bg_inode_bitmap |
220			(fs->super->s_feature_incompat
221			 & EXT4_FEATURE_INCOMPAT_64BIT ?
222			 (__u64) gdp->bg_inode_bitmap_hi << 32 : 0);
223	}
224
225	return fs->group_desc[group].bg_inode_bitmap;
226}
227
228/*
229 * Set the inode bitmap block of a group
230 */
231void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
232{
233	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
234		struct ext4_group_desc *gdp;
235		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
236		gdp->bg_inode_bitmap = blk;
237		if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
238			gdp->bg_inode_bitmap_hi = (__u64) blk >> 32;
239	} else
240		fs->group_desc[group].bg_inode_bitmap = blk;
241}
242
243/*
244 * Return the inode table block of a group
245 */
246blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group)
247{
248	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
249		struct ext4_group_desc *gdp;
250		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
251
252		return gdp->bg_inode_table |
253			(fs->super->s_feature_incompat
254			 & EXT4_FEATURE_INCOMPAT_64BIT ?
255			 (__u64) gdp->bg_inode_table_hi << 32 : 0);
256	}
257
258	return fs->group_desc[group].bg_inode_table;
259}
260
261/*
262 * Set the inode table block of a group
263 */
264void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
265{
266	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
267		struct ext4_group_desc *gdp;
268		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
269		gdp->bg_inode_table = blk;
270		if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
271			gdp->bg_inode_table_hi = (__u64) blk >> 32;
272	} else
273		fs->group_desc[group].bg_inode_table = blk;
274}
275
276/*
277 * Return the free blocks count of a group
278 */
279__u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group)
280{
281	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
282		struct ext4_group_desc *gdp;
283		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
284
285		return gdp->bg_free_blocks_count |
286			(fs->super->s_feature_incompat
287			 & EXT4_FEATURE_INCOMPAT_64BIT ?
288			 (__u32) gdp->bg_free_blocks_count_hi << 16 : 0);
289	}
290
291	return fs->group_desc[group].bg_free_blocks_count;
292}
293
294/*
295 * Set the free blocks count of a group
296 */
297void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
298{
299	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
300		struct ext4_group_desc *gdp;
301		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
302		gdp->bg_free_blocks_count = n;
303		if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
304			gdp->bg_free_blocks_count_hi = (__u32) n >> 16;
305	} else
306		fs->group_desc[group].bg_free_blocks_count = n;
307}
308
309/*
310 * Return the free inodes count of a group
311 */
312__u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group)
313{
314	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
315		struct ext4_group_desc *gdp;
316		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
317
318		return gdp->bg_free_inodes_count |
319			(fs->super->s_feature_incompat
320			 & EXT4_FEATURE_INCOMPAT_64BIT ?
321			 (__u32) gdp->bg_free_inodes_count_hi << 16 : 0);
322	}
323
324	return fs->group_desc[group].bg_free_inodes_count;
325}
326
327/*
328 * Set the free inodes count of a group
329 */
330void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
331{
332	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
333		struct ext4_group_desc *gdp;
334		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
335		gdp->bg_free_inodes_count = n;
336		if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
337			gdp->bg_free_inodes_count_hi = (__u32) n >> 16;
338	} else
339		fs->group_desc[group].bg_free_inodes_count = n;
340}
341
342/*
343 * Return the used dirs count of a group
344 */
345__u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group)
346{
347	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
348		struct ext4_group_desc *gdp;
349		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
350
351		return gdp->bg_used_dirs_count |
352			(fs->super->s_feature_incompat
353			 & EXT4_FEATURE_INCOMPAT_64BIT ?
354			 (__u32) gdp->bg_used_dirs_count_hi << 16 : 0);
355	}
356
357	return fs->group_desc[group].bg_used_dirs_count;
358}
359
360/*
361 * Set the used dirs count of a group
362 */
363void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
364{
365	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
366		struct ext4_group_desc *gdp;
367		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
368		gdp->bg_used_dirs_count = n;
369		if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
370			gdp->bg_used_dirs_count_hi = (__u32) n >> 16;
371	} else
372		fs->group_desc[group].bg_used_dirs_count = n;
373}
374
375/*
376 * Return the unused inodes count of a group
377 */
378__u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group)
379{
380	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
381		struct ext4_group_desc *gdp;
382		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
383
384		return gdp->bg_itable_unused |
385			(fs->super->s_feature_incompat
386			 & EXT4_FEATURE_INCOMPAT_64BIT ?
387			 (__u32) gdp->bg_itable_unused_hi << 16 : 0);
388	}
389
390	return fs->group_desc[group].bg_itable_unused;
391}
392
393/*
394 * Set the unused inodes count of a group
395 */
396void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, __u32 n)
397{
398	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
399		struct ext4_group_desc *gdp;
400		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
401		gdp->bg_itable_unused = n;
402		if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
403			gdp->bg_itable_unused_hi = (__u32) n >> 16;
404	} else
405		fs->group_desc[group].bg_itable_unused = n;
406}
407
408/*
409 * Get the flags for this block group
410 */
411__u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group)
412{
413	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
414		struct ext4_group_desc *gdp;
415		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
416
417		return gdp->bg_flags;
418	}
419
420	return fs->group_desc[group].bg_flags;
421}
422
423/*
424 * Zero out the flags for this block group
425 */
426void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group)
427{
428	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
429		struct ext4_group_desc *gdp;
430		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
431
432		gdp->bg_flags = 0;
433		return;
434	}
435
436	fs->group_desc[group].bg_flags = 0;
437}
438
439/*
440 * Get the value of a particular flag for this block group
441 */
442int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag)
443{
444	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
445		struct ext4_group_desc *gdp;
446		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
447
448		return gdp->bg_flags & bg_flag;
449	}
450
451	return fs->group_desc[group].bg_flags & bg_flag;
452}
453
454/*
455 * Set a flag or set of flags for this block group
456 */
457void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
458{
459	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
460		struct ext4_group_desc *gdp;
461		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
462
463		gdp->bg_flags |= bg_flags;
464		return;
465	}
466
467	fs->group_desc[group].bg_flags |= bg_flags;
468}
469
470/*
471 * Clear a flag or set of flags for this block group
472 */
473void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
474{
475	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
476		struct ext4_group_desc *gdp;
477		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
478
479		gdp->bg_flags &= ~bg_flags;
480		return;
481	}
482
483	fs->group_desc[group].bg_flags &= ~bg_flags;
484}
485
486/*
487 * Get the checksum for this block group
488 */
489__u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group)
490{
491	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
492		struct ext4_group_desc *gdp;
493		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
494
495		return gdp->bg_checksum;
496	}
497
498	return fs->group_desc[group].bg_checksum;
499}
500
501/*
502 * Set the checksum for this block group to a previously calculated value
503 */
504void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum)
505{
506	if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT) {
507		struct ext4_group_desc *gdp;
508		gdp = (struct ext4_group_desc *) (fs->group_desc) + group;
509
510		gdp->bg_checksum = checksum;
511		return;
512	}
513
514	fs->group_desc[group].bg_checksum = checksum;
515}
516
517/*
518 * Get the acl block of a file
519 *
520 * XXX Ignoring 64-bit file system flag - most places where this is
521 * called don't have access to the fs struct, and the high bits should
522 * be 0 in the non-64-bit case anyway.
523 */
524blk64_t ext2fs_file_acl_block(const struct ext2_inode *inode)
525{
526	return (inode->i_file_acl |
527		(__u64) inode->osd2.linux2.l_i_file_acl_high << 32);
528}
529
530/*
531 * Set the acl block of a file
532 */
533void ext2fs_file_acl_block_set(struct ext2_inode *inode, blk64_t blk)
534{
535	inode->i_file_acl = blk;
536	inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32;
537}
538
539