Import 2.3.26pre2
[davej-history.git] / fs / adfs / map.c
blob31d560143b9fcdd0dcb7963971162a95155b3be1
1 /*
2 * linux/fs/adfs/map.c
4 * Copyright (C) 1997 Russell King
5 */
7 #include <linux/errno.h>
8 #include <linux/fs.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;
16 else
17 mapoff >>= -sb->u.adfs_sb.s_map2blk;
18 return mapoff;
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;
26 else
27 secoff <<= -sb->u.adfs_sb.s_map2blk;
28 return secoff;
31 static int lookup_zone (struct super_block *sb, int zone, int frag_id, int *offset)
33 unsigned int mapptr, idlen, mapsize;
34 unsigned long *map;
36 map = ((unsigned long *)sb->u.adfs_sb.s_map[zone]->b_data) + 1;
37 zone =
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;
42 do {
43 unsigned long v1, v2;
44 unsigned int start;
46 v1 = map[mapptr>>5];
47 v2 = map[(mapptr>>5)+1];
49 v1 = (v1 >> (mapptr & 31)) | (v2 << (32 - (mapptr & 31)));
50 start = mapptr;
51 mapptr += idlen;
53 v2 = map[mapptr >> 5] >> (mapptr & 31);
54 if (!v2) {
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);
60 mapptr += 1;
62 if ((v1 & ((1 << idlen) - 1)) == frag_id) {
63 int length = mapptr - start;
64 if (*offset >= length)
65 *offset -= length;
66 else
67 return start + *offset - zone;
69 } while (mapptr < mapsize);
70 return -1;
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);
83 return 0;
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);
91 do {
92 int result = lookup_zone (sb, zone, frag_id, &mapoff);
94 if (result != -1) {
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;
99 zone ++;
100 if (zone >= max_zone)
101 zone = 0;
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);
107 return 0;