Extract common OMFS code into a library
[omfsprogs.git] / check.c
blobb4934b85da43d65e4f7ef9764f09a624af0e3c77
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include "omfs.h"
7 #include "dirscan.h"
8 #include "check.h"
9 #include "crc.h"
10 #include "fix.h"
11 #include "bits.h"
12 #include "io.h"
15 * TODO:
17 * - check hash table index
18 * - clear extents from free bitmap and make sure free bitmap is null
19 * - sanity check block size, sys block size, mirrors, etc
20 * - check that extent count is valid
21 * - check that terminator matches
22 * - make sure file sizes match up
25 int check_crc(u8 *blk)
27 u16 crc;
28 size_t hdr_size = sizeof(struct omfs_header);
29 struct omfs_inode *oi;
31 oi = (struct omfs_inode *) blk;
33 crc = crc_ccitt_msb(0, blk + hdr_size,
34 swap_be32(oi->i_head.h_body_size));
36 return (crc == swap_be16(oi->i_head.h_crc));
39 int check_header(u8 *blk)
41 int i;
42 int xor;
43 struct omfs_inode *oi;
45 oi = (struct omfs_inode *) blk;
47 xor = blk[0];
48 for (i = 1; i < OMFS_XOR_COUNT; i++)
49 xor ^= blk[i];
51 return (xor == oi->i_head.h_check_xor);
54 int check_sanity(check_context_t *ctx)
56 omfs_inode_t *inode = ctx->current_inode;
57 if (swap_be32(inode->i_head.h_body_size) >
58 swap_be32(ctx->omfs_info->super->s_sys_blocksize))
59 return 0;
61 // check device size here too.
62 return 1;
65 int check_bitmap(check_context_t *ctx)
67 int i;
68 int is_ok = 1;
69 int bsize, first_blk;
70 omfs_super_t *super = ctx->omfs_info->super;
71 omfs_root_t *root = ctx->omfs_info->root;
73 if (!ctx->bitmap)
74 return 0;
76 bsize = (swap_be64(super->s_num_blocks) + 7) / 8;
77 first_blk = swap_be64(root->r_bitmap) + (bsize +
78 swap_be32(super->s_blocksize)-1) /
79 swap_be32(super->s_blocksize);
81 for (i=0; i < first_blk; i++)
82 set_bit(ctx->visited, i);
84 for (i=0; i < bsize; i++)
86 if (ctx->bitmap[i] != ctx->visited[i])
88 is_ok = 0;
89 if (!ctx->config->is_quiet)
91 printf("Wrong bitmap byte at %d (%02x,%02x)\n",
92 i, ctx->bitmap[i], ctx->visited[i]);
96 if (!is_ok)
98 fix_problem(E_BITMAP, ctx);
100 return is_ok;
103 void visit_extents(check_context_t *ctx)
105 struct omfs_extent *oe;
106 struct omfs_extent_entry *entry;
107 u64 last, next;
108 int extent_count, i;
109 u8 *buf;
111 next = ctx->block;
112 buf = omfs_get_block(ctx->omfs_info, next);
113 if (!buf)
114 return;
116 oe = (struct omfs_extent *) &buf[OMFS_EXTENT_START];
118 for(;;)
120 extent_count = swap_be32(oe->e_extent_count);
121 last = next;
122 next = swap_be64(oe->e_next);
123 entry = &oe->e_entry;
125 // ignore last entry as it is the terminator
126 for (; extent_count > 1; extent_count--)
128 u64 start = swap_be64(entry->e_cluster);
130 for (i=0; i<swap_be64(entry->e_blocks); i++)
131 set_bit(ctx->visited, start + i);
133 entry++;
136 set_bit(ctx->visited, last);
137 set_bit(ctx->visited, last+1);
139 if (next == ~0)
140 break;
142 free(buf);
143 buf = omfs_get_block(ctx->omfs_info, next);
144 if (!buf)
145 goto err;
146 oe = (struct omfs_extent *) &buf[OMFS_EXTENT_CONT];
148 free(buf);
149 err:
150 return;
153 int check_inode(check_context_t *ctx)
155 int i;
156 int ret = 1;
157 omfs_inode_t *inode = ctx->current_inode;
159 if (test_bit(ctx->visited, ctx->block))
161 fix_problem(E_LOOP, ctx);
162 return 0;
164 for (i=0; i < swap_be32(ctx->omfs_info->super->s_mirrors); i++)
165 set_bit(ctx->visited, ctx->block + i);
167 if (!check_sanity(ctx))
169 fix_problem(E_INSANE, ctx);
170 return 0;
172 if (!check_header((u8 *)inode))
174 fix_problem(E_HEADER_XOR, ctx);
175 ret = 0;
177 if (!check_crc((u8 *)inode))
179 fix_problem(E_HEADER_CRC, ctx);
180 ret = 0;
182 if (swap_be64(inode->i_head.h_self) != ctx->block)
184 fix_problem(E_SELF_PTR, ctx);
185 ret = 0;
187 if (swap_be64(inode->i_parent) != ctx->parent)
189 fix_problem(E_PARENT_PTR, ctx);
190 ret = 0;
192 if (omfs_compute_hash(ctx->omfs_info, inode->i_name) != ctx->hash)
194 fix_problem(E_HASH_WRONG, ctx);
195 ret = 0;
197 if (inode->i_type == OMFS_FILE)
199 visit_extents(ctx);
202 return ret;
205 static int on_node(dirscan_t *d, dirscan_entry_t *entry, void *user)
207 check_context_t *ctx = (check_context_t *) user;
209 ctx->current_inode = entry->inode;
210 ctx->block = entry->block;
211 ctx->parent = entry->parent;
212 ctx->hash = entry->hindex;
213 return check_inode(ctx);
216 int check_fs(FILE *fp, check_fs_config_t *config)
218 int res;
219 check_context_t ctx;
220 int bsize;
221 omfs_super_t super;
222 omfs_root_t root;
223 omfs_info_t info = {
224 .dev = fp,
225 .super = &super,
226 .root = &root
229 ctx.config = config;
231 if (omfs_read_super(&info))
233 fix_problem(E_READ_SUPER, &ctx);
234 return 0;
236 if (omfs_read_root_block(&info))
238 fix_problem(E_READ_ROOT, &ctx);
239 return 0;
242 ctx.omfs_info = &info;
243 omfs_load_bitmap(&info);
244 ctx.bitmap = info.bitmap->bmap;
245 bsize = (swap_be64(info.super->s_num_blocks) + 7) / 8;
246 ctx.visited = calloc(1, bsize);
248 /* FIXME error codes are all over the place. */
249 res = dirscan_begin(&info, on_node, &ctx);
251 if (res < 0)
253 fix_problem(E_SCAN, &ctx);
254 return 0;
256 if (res != 0)
257 return 0;
259 res = check_bitmap(&ctx);
261 if (ctx.bitmap)
262 free(ctx.bitmap);
263 free(ctx.visited);
264 return res;