Initialize root directory to have proper i_size.
[omfsprogs.git] / check.c
blob898b345b355163f562ef1e7914044236fa2c9d80
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->head.body_size));
36 return (crc == swap_be16(oi->head.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->head.check_xor);
54 int check_sanity(check_context_t *ctx)
56 omfs_inode_t *inode = ctx->current_inode;
57 if (swap_be32(inode->head.body_size) >
58 swap_be32(ctx->omfs_info->super->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->num_blocks) + 7) / 8;
77 first_blk = swap_be64(root->bitmap) + (bsize +
78 swap_be32(super->blocksize)-1) / swap_be32(super->blocksize);
80 for (i=0; i < first_blk; i++)
81 set_bit(ctx->visited, i);
83 for (i=0; i < bsize; i++)
85 if (ctx->bitmap[i] != ctx->visited[i])
87 is_ok = 0;
88 printf("Wrong bitmap byte at %d (%02x, %02x)\n", i,
89 ctx->bitmap[i], ctx->visited[i]);
92 if (!is_ok)
94 fix_problem(E_BITMAP, ctx);
96 return 0;
99 void visit_extents(check_context_t *ctx)
101 struct omfs_extent *oe;
102 struct omfs_extent_entry *entry;
103 u64 last, next;
104 int extent_count, i;
105 u8 *buf;
107 next = ctx->block;
108 buf = omfs_get_block(ctx->omfs_info->dev,
109 ctx->omfs_info->super, next);
110 if (!buf)
111 return;
113 oe = (struct omfs_extent *) &buf[OMFS_EXTENT_START];
115 for(;;)
117 extent_count = swap_be32(oe->extent_count);
118 last = next;
119 next = swap_be64(oe->next);
120 entry = &oe->entry;
122 // ignore last entry as it is the terminator
123 for (; extent_count > 1; extent_count--)
125 u64 start = swap_be64(entry->cluster);
127 for (i=0; i<swap_be64(entry->blocks); i++)
128 set_bit(ctx->visited, start + i);
130 entry++;
133 set_bit(ctx->visited, last);
134 set_bit(ctx->visited, last+1);
136 if (next == ~0)
137 break;
139 free(buf);
140 buf = omfs_get_block(ctx->omfs_info->dev,
141 ctx->omfs_info->super, next);
142 if (!buf)
143 goto err;
144 oe = (struct omfs_extent *) &buf[OMFS_EXTENT_CONT];
146 free(buf);
147 err:
148 return;
151 int check_inode(check_context_t *ctx)
153 int i;
154 int ret = 1;
155 omfs_inode_t *inode = ctx->current_inode;
157 if (test_bit(ctx->visited, ctx->block))
159 fix_problem(E_LOOP, ctx);
160 return 0;
162 for (i=0; i < swap_be32(ctx->omfs_info->super->mirrors); i++)
163 set_bit(ctx->visited, ctx->block + i);
165 if (!check_sanity(ctx))
167 fix_problem(E_INSANE, ctx);
168 return 0;
170 if (!check_header((u8 *)inode))
172 fix_problem(E_HEADER_XOR, ctx);
174 if (!check_crc((u8 *)inode))
176 fix_problem(E_HEADER_CRC, ctx);
178 if (swap_be64(inode->head.self) != ctx->block)
180 fix_problem(E_SELF_PTR, ctx);
181 ret = 0;
183 if (swap_be64(inode->parent) != ctx->parent)
185 fix_problem(E_PARENT_PTR, ctx);
186 ret = 0;
188 if (omfs_compute_hash(ctx->omfs_info, inode->name) != ctx->hash)
190 fix_problem(E_HASH_WRONG, ctx);
191 ret = 0;
193 if (inode->type == OMFS_FILE)
195 visit_extents(ctx);
198 return ret;
201 static int on_node(dirscan_t *d, dirscan_entry_t *entry, void *user)
203 char *name = escape(entry->inode->name);
204 check_context_t *ctx = (check_context_t *) user;
206 printf("inode: %*c%s%c %llx %d %d %llx %llx\n",
207 entry->level*2, ' ', name,
208 (entry->inode->type == OMFS_DIR) ? '/' : ' ',
209 swap_be64(entry->inode->head.self), entry->hindex,
210 swap_be16(entry->inode->head.crc),
211 entry->parent, entry->block);
212 free(name);
214 ctx->current_inode = entry->inode;
215 ctx->block = entry->block;
216 ctx->parent = entry->parent;
217 ctx->hash = entry->hindex;
218 check_inode(ctx);
220 return 0;
223 int check_fs(FILE *fp)
225 check_context_t ctx;
226 int bsize;
227 omfs_super_t super;
228 omfs_root_t root;
229 omfs_info_t info = {
230 .dev = fp,
231 .super = &super,
232 .root = &root
235 if (omfs_read_super(fp, &super))
237 fix_problem(E_READ_SUPER, 0);
238 return 0;
240 if (omfs_read_root_block(fp, &super, &root))
242 fix_problem(E_READ_ROOT, 0);
243 return 0;
246 ctx.omfs_info = &info;
247 ctx.bitmap = omfs_get_bitmap(&info);
248 bsize = (swap_be64(info.super->num_blocks) + 7) / 8;
249 ctx.visited = calloc(1, bsize);
251 if (dirscan_begin(&info, on_node, &ctx) != 0)
253 fix_problem(E_SCAN, 0);
254 return 0;
257 check_bitmap(&ctx);
259 if (ctx.bitmap)
260 free(ctx.bitmap);
261 free(ctx.visited);
262 return 1;