4 * Copyright (C) 1997 Russell King
7 #include <linux/errno.h>
9 #include <linux/adfs_fs.h>
11 static inline unsigned int
12 adfs_convert_map_to_sector (const struct super_block
*sb
, unsigned int mapoff
)
14 if (sb
->u
.adfs_sb
.s_map2blk
>= 0)
15 mapoff
<<= sb
->u
.adfs_sb
.s_map2blk
;
17 mapoff
>>= -sb
->u
.adfs_sb
.s_map2blk
;
21 static inline unsigned int
22 adfs_convert_sector_to_map (const struct super_block
*sb
, unsigned int secoff
)
24 if (sb
->u
.adfs_sb
.s_map2blk
>= 0)
25 secoff
>>= sb
->u
.adfs_sb
.s_map2blk
;
27 secoff
<<= -sb
->u
.adfs_sb
.s_map2blk
;
31 static int lookup_zone (struct super_block
*sb
, int zone
, int frag_id
, int *offset
)
33 unsigned int mapptr
, idlen
, mapsize
;
36 map
= ((unsigned long *)sb
->u
.adfs_sb
.s_map
[zone
]->b_data
) + 1;
38 mapptr
= zone
== 0 ? (ADFS_DR_SIZE
<< 3) : 0;
39 idlen
= sb
->u
.adfs_sb
.s_idlen
;
40 mapsize
= sb
->u
.adfs_sb
.s_zonesize
;
47 v2
= map
[(mapptr
>>5)+1];
49 v1
= (v1
>> (mapptr
& 31)) | (v2
<< (32 - (mapptr
& 31)));
53 v2
= map
[mapptr
>> 5] >> (mapptr
& 31);
55 mapptr
= (mapptr
+ 32) & ~31;
56 for (; (v2
= map
[mapptr
>> 5]) == 0 && mapptr
< mapsize
; mapptr
+= 32);
58 for (; (v2
& 255) == 0; v2
>>= 8, mapptr
+= 8);
59 for (; (v2
& 1) == 0; v2
>>= 1, mapptr
+= 1);
62 if ((v1
& ((1 << idlen
) - 1)) == frag_id
) {
63 int length
= mapptr
- start
;
64 if (*offset
>= length
)
67 return start
+ *offset
- zone
;
69 } while (mapptr
< mapsize
);
73 int adfs_map_lookup (struct super_block
*sb
, int frag_id
, int offset
)
75 unsigned int start_zone
, zone
, max_zone
, mapoff
, secoff
;
77 zone
= start_zone
= frag_id
/ sb
->u
.adfs_sb
.s_ids_per_zone
;
78 max_zone
= sb
->u
.adfs_sb
.s_map_size
;
80 if (start_zone
>= max_zone
) {
81 adfs_error (sb
, "adfs_map_lookup", "fragment %X is invalid (zone = %d, max = %d)",
82 frag_id
, start_zone
, max_zone
);
86 /* Convert sector offset to map offset */
87 mapoff
= adfs_convert_sector_to_map (sb
, offset
);
88 /* Calculate sector offset into map block */
89 secoff
= offset
- adfs_convert_map_to_sector (sb
, mapoff
);
92 int result
= lookup_zone (sb
, zone
, frag_id
, &mapoff
);
95 result
+= zone
? (zone
* sb
->u
.adfs_sb
.s_zonesize
) - (ADFS_DR_SIZE
<< 3): 0;
96 return adfs_convert_map_to_sector (sb
, result
) + secoff
;
100 if (zone
>= max_zone
)
103 } while (zone
!= start_zone
);
105 adfs_error (sb
, "adfs_map_lookup", "fragment %X at offset %d not found in map (start zone %d)",
106 frag_id
, offset
, start_zone
);