2 * Copyright (c) 2011 Josef 'Jeff' Sipek
15 struct list_head list
;
18 u8 fn
[8]; /* EBCDIC */
19 u8 ft
[8]; /* EBCDIC */
20 u8 level
; /* 0 = data */
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
))
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
);
77 map
= malloc(sizeof(struct block_map
));
81 memcpy(map
->fn
, fn
, 8);
82 memcpy(map
->ft
, ft
, 8);
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
);
100 snprintf(buf
,128,"%s could not find block %d at level %d\n",
101 __func__
, blk
, level
);
109 map
->buf
= malloc(adt
->adt
.DBSIZ
);
113 read_blk(map
->buf
, map
->lba
);
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
)
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
) {
141 write_blk(cur
->buf
, cur
->lba
);
146 * fills in *fst with existing file info and returns 0, or if file doesn't
149 int find_file(char *fn
, char *ft
, struct FST
*fst
)
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
));
177 static void update_directory(struct FST
*fst
)
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
);
199 static int file_blocks_at_level(u32 ADBC
, int level
)
201 const u32 ptrs_per_block
= adt
->adt
.DBSIZ
/ 4;
206 for(i
=0; i
<level
; i
++)
207 blks
*= ptrs_per_block
;
208 blks
= (ADBC
+ blks
- 1) / blks
;
213 static void __read_file(struct FST
*fst
)
215 const u32 ptrs_per_block
= adt
->adt
.DBSIZ
/ fst
->PTRSZ
;
223 block_map_add(fst
->FNAME
, fst
->FTYPE
, 0, 0, fst
->FOP
);
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)
240 /* read in each block */
241 for(i
=0; i
<blocks
; i
++) {
242 blk_ptrs
= read_file_blk(fst
->FNAME
,
247 /* and add each pointer to the next level */
248 for(j
=0; j
<ptrs_per_block
; j
++) {
249 block_map_add(fst
->FNAME
,
252 (i
*ptrs_per_block
) + 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
276 append_record(directory
, (u8
*) fst
);
281 static u32
__get_free_block()
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
++) {
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' */
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;
322 static void __append_block(struct FST
*fst
)
324 struct block_map
*map
;
330 /* no data blocks yet */
334 fst
->FOP
= __get_free_block();
336 block_map_add(fst
->FNAME
, fst
->FTYPE
, 0, 0, fst
->FOP
);
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);
351 buf
= read_file_blk(fst
->FNAME
, fst
->FTYPE
, lvl
,
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);
363 lba
= __get_free_block();
365 block_map_add(fst
->FNAME
, fst
->FTYPE
, lvl
, blk
-1, lba
);
370 buf
= read_file_blk(fst
->FNAME
, fst
->FTYPE
, lvl
, blk
-1);
371 blk_set_dirty(fst
->FNAME
, fst
->FTYPE
, lvl
, blk
-1);
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);
391 void append_record(struct FST
*fst
, u8
*buf
)
400 if (fst
->RECFM
!= FSTDFIX
)
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
)
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
);
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);
429 update_directory(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
)))
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
))
461 __read_file(&fst
[0]); /* the directory */
462 __read_file(&fst
[1]); /* the alloc map */