installer: be less verbose when dumping files & writing back buffers
[hvf.git] / installer / edf.c
blobe98363b4bee4ac967d204ea5c3fd215633b4e30e
1 /*
2 * Copyright (c) 2011 Josef 'Jeff' Sipek
3 */
4 #include "loader.h"
5 #include <string.h>
6 #include <ebcdic.h>
7 #include <list.h>
9 union adt_u {
10 struct ADT adt;
11 char buf[4096];
14 struct block_map {
15 struct list_head list;
17 /* key */
18 u8 fn[8]; /* EBCDIC */
19 u8 ft[8]; /* EBCDIC */
20 u8 level; /* 0 = data */
21 u32 blk_no;
23 /* value */
24 u32 lba;
25 void *buf;
27 /* dirty list */
28 int dirty;
31 static union adt_u *adt;
32 static struct FST *directory;
33 static struct FST *allocmap;
35 static LIST_HEAD(block_map);
37 /* borrowed from Linux */
38 #define container_of(ptr, type, member) ({ \
39 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
40 (type *)( (char *)__mptr - offsetof(type,member) );})
42 /* borrowed from Linux */
43 #define offsetof(type, member) __builtin_offsetof(type,member)
45 #define DIRECTOR_FN ((u8*) "\x00\x00\x00\x01\x00\x00\x00\x00")
46 #define DIRECTOR_FT ((u8*) "\xc4\xc9\xd9\xc5\xc3\xe3\xd6\xd9")
47 #define ALLOCMAP_FN ((u8*) "\x00\x00\x00\x02\x00\x00\x00\x00")
48 #define ALLOCMAP_FT ((u8*) "\xc1\xd3\xd3\xd6\xc3\xd4\xc1\xd7")
50 static struct block_map *block_map_find(u8 *fn, u8 *ft, u8 level, u32 blk_no)
52 struct block_map *cur;
54 list_for_each_entry(cur, &block_map, list) {
55 if (!memcmp(fn, cur->fn, 8) &&
56 !memcmp(ft, cur->ft, 8) &&
57 (level == cur->level) &&
58 (blk_no == cur->blk_no))
59 return cur;
62 return NULL;
65 static void block_map_add(u8 *fn, u8 *ft, u8 level, u32 blk_no, u32 lba)
67 struct block_map *map;
69 map = block_map_find(fn, ft, level, blk_no);
70 if (map) {
71 if (map->lba != lba)
72 die();
74 return;
77 map = malloc(sizeof(struct block_map));
78 if (!map)
79 die();
81 memcpy(map->fn, fn, 8);
82 memcpy(map->ft, ft, 8);
83 map->level = level;
84 map->blk_no = blk_no;
86 map->lba = lba;
87 map->buf = NULL;
88 map->dirty = 0;
90 list_add(&map->list, &block_map);
93 static void *read_file_blk(u8 *fn, u8 *ft, u8 level, u32 blk)
95 struct block_map *map;
97 map = block_map_find(fn, ft, level, blk);
98 if (!map) {
99 char buf[128];
100 snprintf(buf,128,"%s could not find block %d at level %d\n",
101 __func__, blk, level);
102 wto(buf);
103 die();
106 if (map->buf)
107 return map->buf;
109 map->buf = malloc(adt->adt.DBSIZ);
110 if (!map->buf)
111 die();
113 read_blk(map->buf, map->lba);
115 return map->buf;
118 static void blk_set_dirty(u8 *fn, u8 *ft, u8 level, u32 blk)
120 struct block_map *map;
122 map = block_map_find(fn, ft, level, blk);
123 if (!map || !map->buf)
124 die();
126 map->dirty = 1;
129 void writeback_buffers()
131 struct block_map *cur;
133 wto("beginning buffer write back\n");
134 list_for_each_entry(cur, &block_map, list) {
135 if (!cur->dirty)
136 continue;
138 if (!cur->buf)
139 die();
141 write_blk(cur->buf, cur->lba);
146 * fills in *fst with existing file info and returns 0, or if file doesn't
147 * exist, returns -1
149 int find_file(char *fn, char *ft, struct FST *fst)
151 struct FST *FST;
152 u8 FN[8];
153 u8 FT[8];
154 int rec;
155 int blk;
157 memcpy(FN, fn, 8);
158 memcpy(FT, ft, 8);
159 ascii2ebcdic(FN, 8);
160 ascii2ebcdic(FT, 8);
162 for(blk=0; blk<directory->ADBC; blk++) {
163 FST = read_file_blk(DIRECTOR_FN, DIRECTOR_FT, 0, blk);
165 for(rec=0; rec<adt->adt.NFST; rec++) {
166 if ((!memcmp(FST[rec].FNAME, FN, 8)) &&
167 (!memcmp(FST[rec].FTYPE, FT, 8))) {
168 memcpy(fst, &FST[rec], sizeof(struct FST));
169 return 0;
174 return -1;
177 static void update_directory(struct FST *fst)
179 struct FST *FST;
180 int rec;
181 int blk;
183 for(blk=0; blk<directory->ADBC; blk++) {
184 FST = read_file_blk(DIRECTOR_FN, DIRECTOR_FT, 0, blk);
186 for(rec=0; rec<adt->adt.NFST; rec++) {
187 if ((!memcmp(FST[rec].FNAME, fst->FNAME, 8)) &&
188 (!memcmp(FST[rec].FTYPE, fst->FTYPE, 8))) {
189 memcpy(&FST[rec], fst, sizeof(struct FST));
190 blk_set_dirty(DIRECTOR_FN, DIRECTOR_FT, 0, blk);
191 return;
196 die();
199 static int file_blocks_at_level(u32 ADBC, int level)
201 const u32 ptrs_per_block = adt->adt.DBSIZ / 4;
202 int blks;
203 int i;
205 blks = 1;
206 for(i=0; i<level; i++)
207 blks *= ptrs_per_block;
208 blks = (ADBC + blks - 1) / blks;
210 return blks;
213 static void __read_file(struct FST *fst)
215 const u32 ptrs_per_block = adt->adt.DBSIZ / fst->PTRSZ;
216 u32 *blk_ptrs;
217 int level;
219 int blocks;
220 int i,j;
222 if (!fst->NLVL) {
223 block_map_add(fst->FNAME, fst->FTYPE, 0, 0, fst->FOP);
224 return;
227 /* there are pointer blocks, let's read them in and then
228 * follow each pointer
231 block_map_add(fst->FNAME, fst->FTYPE, fst->NLVL, 0, fst->FOP);
233 /* for each level of pointers... */
234 for(level=fst->NLVL; level>0; level--) {
235 blocks = file_blocks_at_level(fst->ADBC, level);
237 if (level == fst->NLVL && blocks != 1)
238 die();
240 /* read in each block */
241 for(i=0; i<blocks; i++) {
242 blk_ptrs = read_file_blk(fst->FNAME,
243 fst->FTYPE,
244 level,
247 /* and add each pointer to the next level */
248 for(j=0; j<ptrs_per_block; j++) {
249 block_map_add(fst->FNAME,
250 fst->FTYPE,
251 level-1,
252 (i*ptrs_per_block) + j,
253 blk_ptrs[j]);
259 int create_file(char *fn, char *ft, int lrecl, struct FST *fst)
261 /* first, fill in the FST */
262 memset(fst, 0, sizeof(struct FST));
264 memcpy(fst->FNAME, fn, 8);
265 memcpy(fst->FTYPE, ft, 8);
267 ascii2ebcdic(fst->FNAME, 8);
268 ascii2ebcdic(fst->FTYPE, 8);
270 fst->FMODE[0] = '\xc1'; // EBCDIC 'A'
271 fst->FMODE[1] = '\xf1'; // EBCDIC '1'
272 fst->RECFM = FSTDFIX; // fixed record size
273 fst->LRECL = lrecl;
274 fst->PTRSZ = 4;
276 append_record(directory, (u8*) fst);
278 return 0;
281 static u32 __get_free_block()
283 u32 blk;
284 u8 *buf;
285 u32 i;
286 u32 bit;
288 for(blk=0; blk<allocmap->ADBC; blk++) {
289 buf = read_file_blk(allocmap->FNAME, allocmap->FTYPE, 0, blk);
291 for(i=0; i<adt->adt.DBSIZ; i++) {
292 if (buf[i] == 0xff)
293 continue;
295 if ((buf[i] & 0x80) == 0) { bit = 0; goto found; }
296 if ((buf[i] & 0x40) == 0) { bit = 1; goto found; }
297 if ((buf[i] & 0x20) == 0) { bit = 2; goto found; }
298 if ((buf[i] & 0x10) == 0) { bit = 3; goto found; }
299 if ((buf[i] & 0x08) == 0) { bit = 4; goto found; }
300 if ((buf[i] & 0x04) == 0) { bit = 5; goto found; }
301 if ((buf[i] & 0x02) == 0) { bit = 6; goto found; }
302 if ((buf[i] & 0x01) == 0) { bit = 7; goto found; }
304 continue; /* this is not necessary since we check
305 for 0xff right away, but GCC really
306 likes to complain about possibly
307 uninitialized use of 'bit' */
309 found:
310 buf[i] |= (0x80 >> bit);
312 blk_set_dirty(allocmap->FNAME, allocmap->FTYPE, 0, blk);
314 return ((blk * adt->adt.DBSIZ * 8) + (i * 8) + bit) + 1;
318 die();
319 return 0;
322 static void __append_block(struct FST *fst)
324 struct block_map *map;
325 u32 *buf;
326 u32 lba, prevlba;
327 u32 blk;
328 u8 lvl;
330 /* no data blocks yet */
331 if (!fst->ADBC) {
332 fst->ADBC = 1;
333 fst->NLVL = 0;
334 fst->FOP = __get_free_block();
336 block_map_add(fst->FNAME, fst->FTYPE, 0, 0, fst->FOP);
337 return;
340 prevlba = 0; /* make gcc not warn about uninit variable */
341 for(lvl=0; lvl<=fst->NLVL; lvl++, prevlba=lba) {
342 blk = file_blocks_at_level(fst->ADBC+1, lvl);
344 map = block_map_find(fst->FNAME, fst->FTYPE, lvl, blk-1);
345 if (map) {
346 int x;
348 if (!lvl)
349 die();
351 buf = read_file_blk(fst->FNAME, fst->FTYPE, lvl,
352 blk-1);
353 blk_set_dirty(fst->FNAME, fst->FTYPE, lvl, blk-1);
355 x = file_blocks_at_level(fst->ADBC+1, lvl-1) %
356 (adt->adt.DBSIZ / 4);
357 buf[x-1] = prevlba;
359 fst->ADBC++;
360 return;
363 lba = __get_free_block();
365 block_map_add(fst->FNAME, fst->FTYPE, lvl, blk-1, lba);
367 if (!lvl)
368 continue;
370 buf = read_file_blk(fst->FNAME, fst->FTYPE, lvl, blk-1);
371 blk_set_dirty(fst->FNAME, fst->FTYPE, lvl, blk-1);
373 *buf = prevlba;
376 lba = __get_free_block();
377 block_map_add(fst->FNAME, fst->FTYPE, fst->NLVL+1, 0, lba);
379 buf = read_file_blk(fst->FNAME, fst->FTYPE, fst->NLVL+1, 0);
380 blk_set_dirty(fst->FNAME, fst->FTYPE, fst->NLVL+1, 0);
382 buf[0] = fst->FOP;
383 buf[1] = prevlba;
385 fst->FOP = lba;
387 fst->NLVL++;
388 fst->ADBC++;
391 void append_record(struct FST *fst, u8 *buf)
393 u32 foff;
394 u32 blk;
395 u32 off;
396 u32 rem;
398 u8 *dbuf;
400 if (fst->RECFM != FSTDFIX)
401 die();
403 foff = fst->AIC * fst->LRECL;
405 blk = foff / adt->adt.DBSIZ;
406 off = foff % adt->adt.DBSIZ;
407 rem = (fst->ADBC * adt->adt.DBSIZ) - foff;
409 /* need to add another block */
410 if (rem < fst->LRECL)
411 __append_block(fst);
413 dbuf = read_file_blk(fst->FNAME, fst->FTYPE, 0, blk);
415 if (!rem || (rem >= fst->LRECL)) {
416 memcpy(dbuf + off, buf, fst->LRECL);
417 blk_set_dirty(fst->FNAME, fst->FTYPE, 0, blk);
418 } else {
419 memcpy(dbuf + off, buf, rem);
420 blk_set_dirty(fst->FNAME, fst->FTYPE, 0, blk);
422 dbuf = read_file_blk(fst->FNAME, fst->FTYPE, 0, blk+1);
423 memcpy(dbuf, buf + rem, fst->LRECL - rem);
424 blk_set_dirty(fst->FNAME, fst->FTYPE, 0, blk+1);
427 fst->AIC++;
429 update_directory(fst);
432 void mount_fs()
434 struct FST *fst;
436 adt = malloc(sizeof(union adt_u));
438 read_blk(adt, EDF_LABEL_BLOCK_NO);
440 if ((adt->adt.IDENT != __ADTIDENT) ||
441 (adt->adt.DBSIZ != EDF_SUPPORTED_BLOCK_SIZE) ||
442 (adt->adt.OFFST != 0) ||
443 (adt->adt.FSTSZ != sizeof(struct FST)))
444 die();
446 block_map_add(DIRECTOR_FN, DIRECTOR_FT, 0, 0, adt->adt.DOP);
448 fst = read_file_blk(DIRECTOR_FN, DIRECTOR_FT, 0, 0);
450 if (memcmp(fst[0].FNAME, DIRECTOR_FN, 8) ||
451 memcmp(fst[0].FTYPE, DIRECTOR_FT, 8) ||
452 (fst[0].RECFM != FSTDFIX) ||
453 memcmp(fst[1].FNAME, ALLOCMAP_FN, 8) ||
454 memcmp(fst[1].FTYPE, ALLOCMAP_FT, 8) ||
455 (fst[1].RECFM != FSTDFIX))
456 die();
458 directory = fst;
459 allocmap = fst+1;
461 __read_file(&fst[0]); /* the directory */
462 __read_file(&fst[1]); /* the alloc map */