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  */
ext2fs_group_of_blk2(ext2_filsys fs,blk64_t blk)19 dgrp_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  */
ext2fs_group_first_block2(ext2_filsys fs,dgrp_t group)28 blk64_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  */
ext2fs_group_last_block2(ext2_filsys fs,dgrp_t group)37 blk64_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 number of blocks in a group
47  */
ext2fs_group_blocks_count(ext2_filsys fs,dgrp_t group)48 int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group)
49 {
50 	int num_blocks;
51 
52 	if (group == fs->group_desc_count - 1) {
53 		num_blocks = (ext2fs_blocks_count(fs->super) -
54 				fs->super->s_first_data_block) %
55 			      fs->super->s_blocks_per_group;
56 		if (!num_blocks)
57 			num_blocks = fs->super->s_blocks_per_group;
58 	} else
59 		num_blocks = fs->super->s_blocks_per_group;
60 
61 	return num_blocks;
62 }
63 
64 /*
65  * Return the inode data block count
66  */
ext2fs_inode_data_blocks2(ext2_filsys fs,struct ext2_inode * inode)67 blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
68 					struct ext2_inode *inode)
69 {
70 	return (inode->i_blocks |
71 		((fs->super->s_feature_ro_compat &
72 		  EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ?
73 		 (__u64) inode->osd2.linux2.l_i_blocks_hi << 32 : 0)) -
74 		(inode->i_file_acl ? fs->blocksize >> 9 : 0);
75 }
76 
77 /*
78  * Return the inode i_blocks count
79  */
ext2fs_inode_i_blocks(ext2_filsys fs,struct ext2_inode * inode)80 blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
81 					struct ext2_inode *inode)
82 {
83 	return (inode->i_blocks |
84 		((fs->super->s_feature_ro_compat &
85 		  EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ?
86 		 (__u64)inode->osd2.linux2.l_i_blocks_hi << 32 : 0));
87 }
88 
89 /*
90  * Return the fs block count
91  */
ext2fs_blocks_count(struct ext2_super_block * super)92 blk64_t ext2fs_blocks_count(struct ext2_super_block *super)
93 {
94 	return super->s_blocks_count |
95 		(super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT ?
96 		(__u64) super->s_blocks_count_hi << 32 : 0);
97 }
98 
99 /*
100  * Set the fs block count
101  */
ext2fs_blocks_count_set(struct ext2_super_block * super,blk64_t blk)102 void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
103 {
104 	super->s_blocks_count = blk;
105 	if (super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
106 		super->s_blocks_count_hi = (__u64) blk >> 32;
107 }
108 
109 /*
110  * Add to the current fs block count
111  */
ext2fs_blocks_count_add(struct ext2_super_block * super,blk64_t blk)112 void ext2fs_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
113 {
114 	blk64_t tmp;
115 	tmp = ext2fs_blocks_count(super) + blk;
116 	ext2fs_blocks_count_set(super, tmp);
117 }
118 
119 /*
120  * Return the fs reserved block count
121  */
ext2fs_r_blocks_count(struct ext2_super_block * super)122 blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super)
123 {
124 	return super->s_r_blocks_count |
125 		(super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT ?
126 		(__u64) super->s_r_blocks_count_hi << 32 : 0);
127 }
128 
129 /*
130  * Set the fs reserved block count
131  */
ext2fs_r_blocks_count_set(struct ext2_super_block * super,blk64_t blk)132 void ext2fs_r_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
133 {
134 	super->s_r_blocks_count = blk;
135 	if (super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
136 		super->s_r_blocks_count_hi = (__u64) blk >> 32;
137 }
138 
139 /*
140  * Add to the current reserved fs block count
141  */
ext2fs_r_blocks_count_add(struct ext2_super_block * super,blk64_t blk)142 void ext2fs_r_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
143 {
144 	blk64_t tmp;
145 	tmp = ext2fs_r_blocks_count(super) + blk;
146 	ext2fs_r_blocks_count_set(super, tmp);
147 }
148 
149 /*
150  * Return the fs free block count
151  */
ext2fs_free_blocks_count(struct ext2_super_block * super)152 blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super)
153 {
154 	return super->s_free_blocks_count |
155 		(super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT ?
156 		(__u64) super->s_free_blocks_hi << 32 : 0);
157 }
158 
159 /*
160  * Set the fs free block count
161  */
ext2fs_free_blocks_count_set(struct ext2_super_block * super,blk64_t blk)162 void ext2fs_free_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
163 {
164 	super->s_free_blocks_count = blk;
165 	if (super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
166 		super->s_free_blocks_hi = (__u64) blk >> 32;
167 }
168 
169 /*
170  * Add to the current free fs block count
171  */
ext2fs_free_blocks_count_add(struct ext2_super_block * super,blk64_t blk)172 void ext2fs_free_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
173 {
174 	blk64_t tmp;
175 	tmp = ext2fs_free_blocks_count(super) + blk;
176 	ext2fs_free_blocks_count_set(super, tmp);
177 }
178 
179 /*
180  * Get a pointer to a block group descriptor.  We need the explicit
181  * pointer to the group desc for code that swaps block group
182  * descriptors before writing them out, as it wants to make a copy and
183  * do the swap there.
184  */
ext2fs_group_desc(ext2_filsys fs,struct opaque_ext2_group_desc * gdp,dgrp_t group)185 struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
186 					  struct opaque_ext2_group_desc *gdp,
187 					  dgrp_t group)
188 {
189 	return (struct ext2_group_desc *)((char *)gdp +
190 					  group * EXT2_DESC_SIZE(fs->super));
191 }
192 
193 /* Do the same but as an ext4 group desc for internal use here */
ext4fs_group_desc(ext2_filsys fs,struct opaque_ext2_group_desc * gdp,dgrp_t group)194 static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs,
195 					  struct opaque_ext2_group_desc *gdp,
196 					  dgrp_t group)
197 {
198 	return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group);
199 }
200 
201 /*
202  * Return the block bitmap block of a group
203  */
ext2fs_block_bitmap_loc(ext2_filsys fs,dgrp_t group)204 blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group)
205 {
206 	struct ext4_group_desc *gdp;
207 
208 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
209 	return gdp->bg_block_bitmap |
210 		(fs->super->s_feature_incompat
211 		 & EXT4_FEATURE_INCOMPAT_64BIT ?
212 		 (__u64)gdp->bg_block_bitmap_hi << 32 : 0);
213 }
214 
215 /*
216  * Set the block bitmap block of a group
217  */
ext2fs_block_bitmap_loc_set(ext2_filsys fs,dgrp_t group,blk64_t blk)218 void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
219 {
220 	struct ext4_group_desc *gdp;
221 
222 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
223 	gdp->bg_block_bitmap = blk;
224 	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
225 		gdp->bg_block_bitmap_hi = (__u64) blk >> 32;
226 }
227 
228 /*
229  * Return the inode bitmap block of a group
230  */
ext2fs_inode_bitmap_loc(ext2_filsys fs,dgrp_t group)231 blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group)
232 {
233 	struct ext4_group_desc *gdp;
234 
235 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
236 	return gdp->bg_inode_bitmap |
237 		(fs->super->s_feature_incompat
238 		 & EXT4_FEATURE_INCOMPAT_64BIT ?
239 		 (__u64) gdp->bg_inode_bitmap_hi << 32 : 0);
240 }
241 
242 /*
243  * Set the inode bitmap block of a group
244  */
ext2fs_inode_bitmap_loc_set(ext2_filsys fs,dgrp_t group,blk64_t blk)245 void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
246 {
247 	struct ext4_group_desc *gdp;
248 
249 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
250 	gdp->bg_inode_bitmap = blk;
251 	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
252 		gdp->bg_inode_bitmap_hi = (__u64) blk >> 32;
253 }
254 
255 /*
256  * Return the inode table block of a group
257  */
ext2fs_inode_table_loc(ext2_filsys fs,dgrp_t group)258 blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group)
259 {
260 	struct ext4_group_desc *gdp;
261 
262 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
263 	return gdp->bg_inode_table |
264 		(fs->super->s_feature_incompat
265 		 & EXT4_FEATURE_INCOMPAT_64BIT ?
266 		 (__u64) gdp->bg_inode_table_hi << 32 : 0);
267 }
268 
269 /*
270  * Set the inode table block of a group
271  */
ext2fs_inode_table_loc_set(ext2_filsys fs,dgrp_t group,blk64_t blk)272 void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
273 {
274 	struct ext4_group_desc *gdp;
275 
276 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
277 	gdp->bg_inode_table = blk;
278 	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
279 		gdp->bg_inode_table_hi = (__u64) blk >> 32;
280 }
281 
282 /*
283  * Return the free blocks count of a group
284  */
ext2fs_bg_free_blocks_count(ext2_filsys fs,dgrp_t group)285 __u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group)
286 {
287 	struct ext4_group_desc *gdp;
288 
289 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
290 	return gdp->bg_free_blocks_count |
291 		(fs->super->s_feature_incompat
292 		 & EXT4_FEATURE_INCOMPAT_64BIT ?
293 		 (__u32) gdp->bg_free_blocks_count_hi << 16 : 0);
294 }
295 
296 /*
297  * Set the free blocks count of a group
298  */
ext2fs_bg_free_blocks_count_set(ext2_filsys fs,dgrp_t group,__u32 n)299 void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
300 {
301 	struct ext4_group_desc *gdp;
302 
303 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
304 	gdp->bg_free_blocks_count = n;
305 
306 	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
307 		gdp->bg_free_blocks_count_hi = (__u32) n >> 16;
308 }
309 
310 /*
311  * Return the free inodes count of a group
312  */
ext2fs_bg_free_inodes_count(ext2_filsys fs,dgrp_t group)313 __u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group)
314 {
315 	struct ext4_group_desc *gdp;
316 
317 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
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 /*
325  * Set the free inodes count of a group
326  */
ext2fs_bg_free_inodes_count_set(ext2_filsys fs,dgrp_t group,__u32 n)327 void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
328 {
329 	struct ext4_group_desc *gdp;
330 
331 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
332 	gdp->bg_free_inodes_count = n;
333 	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
334 		gdp->bg_free_inodes_count_hi = (__u32) n >> 16;
335 }
336 
337 /*
338  * Return the used dirs count of a group
339  */
ext2fs_bg_used_dirs_count(ext2_filsys fs,dgrp_t group)340 __u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group)
341 {
342 	struct ext4_group_desc *gdp;
343 
344 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
345 	return gdp->bg_used_dirs_count |
346 		(fs->super->s_feature_incompat
347 		 & EXT4_FEATURE_INCOMPAT_64BIT ?
348 		 (__u32) gdp->bg_used_dirs_count_hi << 16 : 0);
349 }
350 
351 /*
352  * Set the used dirs count of a group
353  */
ext2fs_bg_used_dirs_count_set(ext2_filsys fs,dgrp_t group,__u32 n)354 void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
355 {
356 	struct ext4_group_desc *gdp;
357 
358 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
359 	gdp->bg_used_dirs_count = n;
360 	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
361 		gdp->bg_used_dirs_count_hi = (__u32) n >> 16;
362 }
363 
364 /*
365  * Return the unused inodes count of a group
366  */
ext2fs_bg_itable_unused(ext2_filsys fs,dgrp_t group)367 __u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group)
368 {
369 	struct ext4_group_desc *gdp;
370 
371 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
372 	return gdp->bg_itable_unused |
373 		(fs->super->s_feature_incompat
374 		 & EXT4_FEATURE_INCOMPAT_64BIT ?
375 		 (__u32) gdp->bg_itable_unused_hi << 16 : 0);
376 }
377 
378 /*
379  * Set the unused inodes count of a group
380  */
ext2fs_bg_itable_unused_set(ext2_filsys fs,dgrp_t group,__u32 n)381 void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, __u32 n)
382 {
383 	struct ext4_group_desc *gdp;
384 
385 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
386 	gdp->bg_itable_unused = n;
387 	if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
388 		gdp->bg_itable_unused_hi = (__u32) n >> 16;
389 }
390 
391 /*
392  * Get the flags for this block group
393  */
ext2fs_bg_flags(ext2_filsys fs,dgrp_t group)394 __u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group)
395 {
396 	struct ext4_group_desc *gdp;
397 
398 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
399 	return gdp->bg_flags;
400 }
401 
402 /*
403  * Zero out the flags for this block group
404  */
ext2fs_bg_flags_zap(ext2_filsys fs,dgrp_t group)405 void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group)
406 {
407 	struct ext4_group_desc *gdp;
408 
409 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
410 	gdp->bg_flags = 0;
411 	return;
412 }
413 
414 /*
415  * Get the value of a particular flag for this block group
416  */
ext2fs_bg_flags_test(ext2_filsys fs,dgrp_t group,__u16 bg_flag)417 int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag)
418 {
419 	struct ext4_group_desc *gdp;
420 
421 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
422 	return gdp->bg_flags & bg_flag;
423 }
424 
425 /*
426  * Set a flag or set of flags for this block group
427  */
ext2fs_bg_flags_set(ext2_filsys fs,dgrp_t group,__u16 bg_flags)428 void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
429 {
430 	struct ext4_group_desc *gdp;
431 
432 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
433 	gdp->bg_flags |= bg_flags;
434 	return;
435 }
436 
437 /*
438  * Clear a flag or set of flags for this block group
439  */
ext2fs_bg_flags_clear(ext2_filsys fs,dgrp_t group,__u16 bg_flags)440 void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
441 {
442 	struct ext4_group_desc *gdp;
443 
444 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
445 	gdp->bg_flags &= ~bg_flags;
446 	return;
447 }
448 
449 /*
450  * Get the checksum for this block group
451  */
ext2fs_bg_checksum(ext2_filsys fs,dgrp_t group)452 __u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group)
453 {
454 	struct ext4_group_desc *gdp;
455 
456 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
457 	return gdp->bg_checksum;
458 }
459 
460 /*
461  * Set the checksum for this block group to a previously calculated value
462  */
ext2fs_bg_checksum_set(ext2_filsys fs,dgrp_t group,__u16 checksum)463 void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum)
464 {
465 	struct ext4_group_desc *gdp;
466 
467 	gdp = ext4fs_group_desc(fs, fs->group_desc, group);
468 	gdp->bg_checksum = checksum;
469 	return;
470 }
471 
472 /*
473  * Get the acl block of a file
474  */
ext2fs_file_acl_block(ext2_filsys fs,const struct ext2_inode * inode)475 blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode)
476 {
477 	blk64_t	blk = inode->i_file_acl;
478 
479 	if (fs && fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
480 		blk |= ((__u64) inode->osd2.linux2.l_i_file_acl_high) << 32;
481 	return blk;
482 }
483 
484 /*
485  * Set the acl block of a file
486  */
ext2fs_file_acl_block_set(ext2_filsys fs,struct ext2_inode * inode,blk64_t blk)487 void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode,
488 			       blk64_t blk)
489 {
490 	inode->i_file_acl = blk;
491 	if (fs && fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
492 		inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32;
493 }
494 
495