1 #ifdef FSYS_AFFS
2 #include "shared.h"
3 #include "filesys.h"
4
5 /******************************** RDB definitions */
6 #define RDB_LOCATION_LIMIT 16
7 #define IDNAME_RIGIDDISK 0x5244534B /* 'RDSK' */
8
9 struct RigidDiskBlock
10 {
11 unsigned long rdb_ID;
12 unsigned long rdb_SummedLongs;
13 long rdb_ChkSum;
14 unsigned long rdb_HostID;
15 unsigned long rdb_BlockBytes;
16 unsigned long rdb_Flags;
17 unsigned long rdb_BadBlockList;
18 unsigned long rdb_PartitionList;
19 unsigned long rdb_FileSysHeaderList;
20 unsigned long rdb_DriveInit;
21 unsigned long rdb_Reserved1[6];
22 unsigned long rdb_Cylinders;
23 unsigned long rdb_Sectors;
24 unsigned long rdb_Heads;
25 unsigned long rdb_Interleave;
26 unsigned long rdb_Park;
27 unsigned long rdb_Reserved2[3];
28 unsigned long rdb_WritePreComp;
29 unsigned long rdb_ReducedWrite;
30 unsigned long rdb_StepRate;
31 unsigned long rdb_Reserved3[5];
32 unsigned long rdb_RDBBlocksLo;
33 unsigned long rdb_RDBBlocksHi;
34 unsigned long rdb_LoCylinder;
35 unsigned long rdb_HiCylinder;
36 unsigned long rdb_CylBlocks;
37 unsigned long rdb_AutoParkSeconds;
38 unsigned long rdb_HighRDSKBlock;
39 unsigned long rdb_Reserved4;
40 char rdb_DiskVendor[8];
41 char rdb_DiskProduct[16];
42 char rdb_DiskRevision[4];
43 char rdb_ControllerVendor[8];
44 char rdb_ControllerProduct[16];
45 char rdb_ControllerRevision[4];
46 char rdb_DriveInitName[40];
47 };
48
49 struct PartitionBlock
50 {
51 unsigned long pb_ID;
52 unsigned long pb_SummedLongs;
53 long pb_ChkSum;
54 unsigned long pb_HostID;
55 unsigned long pb_Next;
56 unsigned long pb_Flags;
57 unsigned long pb_Reserved1[2];
58 unsigned long pb_DevFlags;
59 char pb_DriveName[32];
60 unsigned long pb_Reserved2[15];
61 unsigned long pb_Environment[20];
62 unsigned long pb_EReserved[12];
63 };
64
65 #define DE_TABLESIZE 0
66 #define DE_SIZEBLOCK 1
67 #define DE_BLOCKSIZE 2
68 #define DE_NUMHEADS 3
69 #define DE_SECSPERBLOCK 4
70 #define DE_BLKSPERTRACK 5
71 #define DE_RESERVEDBLKS 6
72 #define DE_PREFAC 7
73 #define DE_INTERLEAVE 8
74 #define DE_LOWCYL 9
75 #define DE_HIGHCYL 10
76 #define DE_UPPERCYL DE_HIGHCYL
77 #define DE_NUMBUFFERS 11
78 #define DE_BUFMEMTYPE 12
79 #define DE_MEMBUFTYPE DE_BUFMEMTYPE
80 #define DE_MAXTRANSFER 13
81 #define DE_MASK 14
82 #define DE_BOOTPRI 15
83 #define DE_DOSTYPE 16
84 #define DE_BAUD 17
85 #define DE_CONTROL 18
86 #define DE_BOOTBLOCKS 19
87
88
89 /******************************** AFFS definitions */
90 #define T_SHORT 2
91 #define T_LIST 16
92
93 #define ST_FILE -3
94 #define ST_ROOT 1
95 #define ST_USERDIR 2
96
97 struct BootBlock{
98 int id;
99 int chksum;
100 int rootblock;
101 int data[127];
102 };
103
104 struct RootBlock{
105 int p_type; //0
106 int n1[2]; //1-2
107 int hashtable_size; //3
108 int n2; //4
109 int checksum; //5
110 int hashtable[72]; //6-77
111 int bitmap_valid_flag; //78
112 int bitmap_ptrs[25]; //79-103
113 int bitmap_extension; //104
114 int root_days; //105
115 int root_mins; //106
116 int root_ticks; //107;
117 char diskname[32]; //108-115
118 int n3[2]; //116-117
119 int volume_days; //118
120 int volume_mins; //119
121 int volume_ticks; //120
122 int creation_days; //121
123 int creation_mins; //122
124 int creation_ticks; //123
125 int n4[3]; //124-126
126 int s_type; //127
127 };
128
129 struct DirHeader {
130 int p_type; //0
131 int own_key; //1
132 int n1[3]; //2-4
133 int checksum; //5
134 int hashtable[72]; //6-77
135 int n2; //78
136 int owner; //79
137 int protection; //80
138 int n3; //81
139 char comment[92]; //82-104
140 int days; //105
141 int mins; //106
142 int ticks; //107
143 char name[32]; //108-115
144 int n4[2]; //116-117
145 int linkchain; //118
146 int n5[5]; //119-123
147 int hashchain; //124
148 int parent; //125
149 int n6; //126
150 int s_type; //127
151 };
152
153 struct FileHeader {
154 int p_type; //0
155 int own_key; //1
156 int n1[3]; //2-4
157 int checksum; //5
158 int filekey_table[72]; //6-77
159 int n2; //78
160 int owner; //79
161 int protection; //80
162 int bytesize; //81
163 char comment[92]; //82-104
164 int days; //105
165 int mins; //106
166 int ticks; //107
167 char name[32]; //108-115
168 int n3[2]; //116-117
169 int linkchain; //118
170 int n4[5]; //119-123
171 int hashchain; //124
172 int parent; //125
173 int extension; //126
174 int s_type; //127
175 };
176
177 struct FileKeyExtension{
178 int p_type; //0
179 int own_key; //1
180 int table_size; //2
181 int n1[2]; //3-4
182 int checksum; //5
183 int filekey_table[72]; //6-77
184 int info[46]; //78-123
185 int n2; //124
186 int parent; //125
187 int extension; //126
188 int s_type; //127
189 };
190
191 struct Position {
192 unsigned int block;
193 short filekey;
194 unsigned short byte;
195 unsigned int offset;
196 };
197
198 struct ReadData {
199 unsigned int header_block;
200 struct Position current;
201 unsigned int filesize;
202 };
203
204 //#warning "Big vs. little endian for configure needed"
205 #define AROS_BE2LONG(l) \
206 ( \
207 ((((unsigned long)(l)) >> 24) & 0x000000FFUL) | \
208 ((((unsigned long)(l)) >> 8) & 0x0000FF00UL) | \
209 ((((unsigned long)(l)) << 8) & 0x00FF0000UL) | \
210 ((((unsigned long)(l)) << 24) & 0xFF000000UL) \
211 )
212
213 struct CacheBlock {
214 int blocknum;
215 unsigned short flags;
216 unsigned short access_count;
217 unsigned int blockbuffer[128];
218 };
219 #define LockBuffer(x) (((struct CacheBlock *)(x))->flags |= 0x0001)
220 #define UnLockBuffer(x) (((struct CacheBlock *)(x))->flags &= ~0x0001)
221
222 #define MAX_CACHE_BLOCKS 10
223
224 struct FSysBuffer {
225 struct ReadData file;
226 struct CacheBlock blocks[MAX_CACHE_BLOCKS];
227 };
228
229 #define bootBlock(x) ((struct BootBlock *)(x)->blockbuffer)
230 #define rootBlock(x) ((struct RootBlock *)(x)->blockbuffer)
231 #define dirHeader(x) ((struct DirHeader *)(x)->blockbuffer)
232 #define fileHeader(x) ((struct FileHeader *)(x)->blockbuffer)
233 #define extensionBlock(x) ((struct FileKeyExtension *)(x)->blockbuffer)
234
235 #define rdsk(x) ((struct RigidDiskBlock *)(x)->blockbuffer)
236 #define part(x) ((struct PartitionBlock *)(x)->blockbuffer)
237
238 static struct FSysBuffer *fsysb;
239 static int blockoffset; /* offset if there is an embedded RDB partition */
240 static int rootb; /* block number of root block */
241 static int rdbb; /* block number of rdb block */
242
initCache(void)243 static void initCache(void)
244 {
245 int i;
246
247 for (i=0;i<MAX_CACHE_BLOCKS;i++)
248 {
249 fsysb->blocks[i].blocknum = -1;
250 fsysb->blocks[i].flags = 0;
251 fsysb->blocks[i].access_count = 0;
252 }
253 }
254
getBlock(unsigned int block)255 static struct CacheBlock *getBlock(unsigned int block)
256 {
257 struct CacheBlock *freeblock;
258 int i;
259
260 /* get first unlocked block */
261 i = 0;
262 do
263 {
264 freeblock = &fsysb->blocks[i++];
265 } while (freeblock->flags & 0x0001);
266 /* search through list if block is already loaded in */
267 for (i=0;i<MAX_CACHE_BLOCKS;i++)
268 {
269 if (fsysb->blocks[i].blocknum == block)
270 {
271 fsysb->blocks[i].access_count++;
272 return &fsysb->blocks[i];
273 }
274 if (!(fsysb->blocks[i].flags & 0x0001))
275 if (freeblock->access_count>fsysb->blocks[i].access_count)
276 freeblock = &fsysb->blocks[i];
277 }
278 freeblock->blocknum = block;
279 devread(block+blockoffset, 0, 512, (char *)freeblock->blockbuffer);
280 return freeblock;
281 }
282
calcChkSum(unsigned short SizeBlock,unsigned int * buffer)283 static unsigned int calcChkSum(unsigned short SizeBlock, unsigned int *buffer)
284 {
285 unsigned int sum=0,count=0;
286
287 for (count=0;count<SizeBlock;count++)
288 sum += AROS_BE2LONG(buffer[count]);
289 return sum;
290 }
291
affs_mount(void)292 int affs_mount(void) {
293 struct CacheBlock *cblock;
294 int i;
295
296 if (
297 (current_drive & 0x80) &&
298 (current_partition != 0xFFFFFF) &&
299 (current_slice != 0x30)
300 )
301 return 0;
302 fsysb = (struct FSysBuffer *)FSYS_BUF;
303 blockoffset = 0;
304 initCache();
305 /* check for rdb partitiontable */
306 for (i=0;i<RDB_LOCATION_LIMIT;i++)
307 {
308 cblock = getBlock(i);
309 if (
310 (
311 ((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFFFFFF00)==0x444F5300) &&
312 ((AROS_BE2LONG(bootBlock(cblock)->id) & 0xFF)>0)
313 ) ||
314 (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK)
315 )
316 break;
317 }
318 if (i == RDB_LOCATION_LIMIT)
319 return 0;
320 if (AROS_BE2LONG(cblock->blockbuffer[0]) == IDNAME_RIGIDDISK)
321 {
322 /* we have an RDB partition table within a MBR-Partition */
323 rdbb = i;
324 }
325 else if (i<2)
326 {
327 /* partition type is 0x30 = AROS and AFFS formatted */
328 rdbb = RDB_LOCATION_LIMIT;
329 rootb = (part_length-1+2)/2;
330 cblock = getBlock(rootb);
331 if (
332 (AROS_BE2LONG(rootBlock(cblock)->p_type) != T_SHORT) ||
333 (AROS_BE2LONG(rootBlock(cblock)->s_type) != ST_ROOT) ||
334 calcChkSum(128, cblock->blockbuffer)
335 )
336 return 0;
337 }
338 else
339 return 0;
340 return 1;
341 }
342
seek(unsigned long offset)343 static int seek(unsigned long offset)
344 {
345 struct CacheBlock *cblock;
346 unsigned long block;
347 unsigned long togo;
348
349 block = fsysb->file.header_block;
350
351 togo = offset / 512;
352 fsysb->file.current.filekey = 71-(togo % 72);
353 togo /= 72;
354 fsysb->file.current.byte = offset % 512;
355 fsysb->file.current.offset = offset;
356 while ((togo) && (block))
357 {
358 disk_read_func = disk_read_hook;
359 cblock = getBlock(block);
360 disk_read_func = NULL;
361 block = AROS_BE2LONG(extensionBlock(cblock)->extension);
362 togo--;
363 }
364 if (togo)
365 return 1;
366 fsysb->file.current.block = block;
367 return 0;
368 }
369
affs_read(char * buf,int len)370 int affs_read(char *buf, int len) {
371 struct CacheBlock *cblock;
372 unsigned short size;
373 unsigned int readbytes = 0;
374
375 if (fsysb->file.current.offset != filepos)
376 {
377 if (seek(filepos))
378 return ERR_FILELENGTH;
379 }
380 if (fsysb->file.current.block == 0)
381 return 0;
382 if (len>(fsysb->file.filesize-fsysb->file.current.offset))
383 len=fsysb->file.filesize-fsysb->file.current.offset;
384 disk_read_func = disk_read_hook;
385 cblock = getBlock(fsysb->file.current.block);
386 disk_read_func = NULL;
387 while (len)
388 {
389 disk_read_func = disk_read_hook;
390 if (fsysb->file.current.filekey<0)
391 {
392 fsysb->file.current.filekey = 71;
393 fsysb->file.current.block = AROS_BE2LONG(extensionBlock(cblock)->extension);
394 if (fsysb->file.current.block)
395 {
396 cblock = getBlock(fsysb->file.current.block);
397 }
398 //#warning "else shouldn't occour"
399 }
400 size = 512;
401 size -= fsysb->file.current.byte;
402 if (size>len)
403 {
404 size = len;
405 devread
406 (
407 AROS_BE2LONG
408 (
409 extensionBlock(cblock)->filekey_table
410 [fsysb->file.current.filekey]
411 )+blockoffset,
412 fsysb->file.current.byte, size, (char *)((long)buf+readbytes)
413 );
414 fsysb->file.current.byte += size;
415 }
416 else
417 {
418 devread
419 (
420 AROS_BE2LONG
421 (
422 extensionBlock(cblock)->filekey_table
423 [fsysb->file.current.filekey]
424 )+blockoffset,
425 fsysb->file.current.byte, size, (char *)((long)buf+readbytes)
426 );
427 fsysb->file.current.byte = 0;
428 fsysb->file.current.filekey--;
429 }
430 disk_read_func = NULL;
431 len -= size;
432 readbytes += size;
433 }
434 fsysb->file.current.offset += readbytes;
435 filepos = fsysb->file.current.offset;
436 return readbytes;
437 }
438
capitalch(unsigned char ch,unsigned char flags)439 static unsigned char capitalch(unsigned char ch, unsigned char flags)
440 {
441
442 if ((flags==0) || (flags==1))
443 return (unsigned char)((ch>='a') && (ch<='z') ? ch-('a'-'A') : ch);
444 else // DOS\(>=2)
445 return (unsigned char)(((ch>=224) && (ch<=254) && (ch!=247)) ||
446 ((ch>='a') && (ch<='z')) ? ch-('a'-'A') : ch);
447 }
448
449 // str2 is a BCPL string
noCaseStrCmp(char * str1,char * str2,unsigned char flags)450 static int noCaseStrCmp(char *str1, char *str2, unsigned char flags)
451 {
452 unsigned char length;
453
454 length=str2++[0];
455 do {
456 if ((*str1==0) && (length==0))
457 return 0;
458 length--;
459 // if ((*str1==0) && (*str2==0)) return 1;
460 } while (capitalch(*str1++,flags)==capitalch(*str2++,flags));
461 str1--;
462 return (*str1) ? 1 : -1;
463 }
464
getHashKey(char * name,unsigned int tablesize,unsigned char flags)465 static unsigned int getHashKey(char *name,unsigned int tablesize, unsigned char flags)
466 {
467 unsigned int length;
468
469 length=0;
470 while (name[length] != 0)
471 length++;
472 while (*name!=0)
473 length=(length * 13 +capitalch(*name++,flags)) & 0x7FF;
474 return length%tablesize;
475 }
476
getHeaderBlock(char * name,struct CacheBlock ** dirh)477 static grub_error_t getHeaderBlock(char *name, struct CacheBlock **dirh)
478 {
479 int key;
480
481 key = getHashKey(name, 72, 1);
482 if (!dirHeader(*dirh)->hashtable[key])
483 return ERR_FILE_NOT_FOUND;
484 *dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashtable[key]));
485 if (calcChkSum(128, (*dirh)->blockbuffer))
486 {
487 #ifdef DEBUG_AFFS
488 printf("ghb: %d\n", (*dirh)->blocknum);
489 #endif
490 return ERR_FSYS_CORRUPT;
491 }
492 if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT)
493 return ERR_BAD_FILETYPE;
494 while (noCaseStrCmp(name,dirHeader(*dirh)->name,1) != 0)
495 {
496 if (!dirHeader(*dirh)->hashchain)
497 return ERR_FILE_NOT_FOUND;
498 *dirh = getBlock(AROS_BE2LONG(dirHeader(*dirh)->hashchain));
499 if (calcChkSum(128, (*dirh)->blockbuffer))
500 {
501 #ifdef DEBUG_AFFS
502 printf("ghb2: %d\n", (*dirh)->blocknum);
503 #endif
504 return ERR_FSYS_CORRUPT;
505 }
506 if (AROS_BE2LONG(dirHeader(*dirh)->p_type) != T_SHORT)
507 return ERR_BAD_FILETYPE;
508 }
509 return 0;
510 }
511
copyPart(char * src,char * dst)512 static char *copyPart(char *src, char *dst)
513 {
514 while ((*src != '/') && (*src))
515 *dst++ = *src++;
516 if (*src == '/')
517 src++;
518 *dst-- = 0;
519 /* cut off spaces at the end */
520 while (*dst == ' ')
521 *dst-- = 0;
522 return src;
523 }
524
findBlock(char * name,struct CacheBlock ** dirh)525 static grub_error_t findBlock(char *name, struct CacheBlock **dirh)
526 {
527 char dname[32];
528 int block;
529
530 name++; /* skip "/" */
531 /* partition table part */
532 if (rdbb < RDB_LOCATION_LIMIT)
533 {
534 int bpc;
535
536 blockoffset = 0;
537 *dirh = getBlock(rdbb);
538 if (*name==0)
539 return 0;
540 name = copyPart(name, dname);
541 bpc = AROS_BE2LONG(rdsk(*dirh)->rdb_Sectors)*AROS_BE2LONG(rdsk(*dirh)->rdb_Heads);
542 block = AROS_BE2LONG(rdsk(*dirh)->rdb_PartitionList);
543 while (block != -1)
544 {
545 *dirh = getBlock(block);
546 if (noCaseStrCmp(dname, part(*dirh)->pb_DriveName, 1) == 0)
547 break;
548 block = AROS_BE2LONG(part(*dirh)->pb_Next);
549 }
550 if (block == -1)
551 return ERR_FILE_NOT_FOUND;
552 if (
553 ((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFFFFFF00)!=0x444F5300) ||
554 ((AROS_BE2LONG(part(*dirh)->pb_Environment[DE_DOSTYPE]) & 0xFF)==0)
555 )
556 return ERR_BAD_FILETYPE;
557 blockoffset = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_LOWCYL]);
558 rootb = AROS_BE2LONG(part(*dirh)->pb_Environment[DE_HIGHCYL]);
559 rootb = rootb-blockoffset+1; /* highcyl-lowcyl+1 */
560 rootb *= bpc;
561 rootb = rootb-1+AROS_BE2LONG(part(*dirh)->pb_Environment[DE_RESERVEDBLKS]);
562 rootb /= 2;
563 blockoffset *= bpc;
564 }
565
566 /* filesystem part */
567 *dirh = getBlock(rootb);
568 while (*name)
569 {
570 if (
571 (AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_ROOT) &&
572 (AROS_BE2LONG(dirHeader(*dirh)->s_type) != ST_USERDIR)
573 )
574 return ERR_BAD_FILETYPE;
575 name = copyPart(name, dname);
576 errnum = getHeaderBlock(dname, dirh);
577 if (errnum)
578 return errnum;
579 }
580 return 0;
581 }
582
583 #ifndef STAGE1_5
checkPossibility(char * filename,char * bstr)584 static void checkPossibility(char *filename, char *bstr)
585 {
586 char cstr[32];
587
588 if (noCaseStrCmp(filename, bstr, 1)<=0)
589 {
590 if (print_possibilities>0)
591 print_possibilities = -print_possibilities;
592 memcpy(cstr, bstr+1, bstr[0]);
593 cstr[bstr[0]]=0;
594 print_a_completion(cstr);
595 }
596 }
597 #else
598 #define checkPossibility(a, b) do { } while(0)
599 #endif
600
affs_dir(char * dirname)601 int affs_dir(char *dirname)
602 {
603 struct CacheBlock *buffer1;
604 struct CacheBlock *buffer2;
605 char *current = dirname;
606 char filename[128];
607 char *fname = filename;
608 int i,block;
609
610 if (print_possibilities)
611 {
612 while (*current)
613 current++;
614 while (*current != '/')
615 current--;
616 current++;
617 while (*current)
618 {
619 *fname++ = *current;
620 *current++ = 0;
621 }
622 *fname=0;
623 errnum = findBlock(dirname, &buffer1);
624 if (errnum)
625 return 0;
626 if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == IDNAME_RIGIDDISK)
627 {
628 block = AROS_BE2LONG(rdsk(buffer1)->rdb_PartitionList);
629 while (block != -1)
630 {
631 buffer1 = getBlock(block);
632 checkPossibility(filename, part(buffer1)->pb_DriveName);
633 block = AROS_BE2LONG(part(buffer1)->pb_Next);
634 }
635 #ifndef STAGE1_5
636 if (*filename == 0)
637 if (print_possibilities>0)
638 print_possibilities = -print_possibilities;
639 #endif
640 }
641 else if (AROS_BE2LONG(dirHeader(buffer1)->p_type) == T_SHORT)
642 {
643 LockBuffer(buffer1);
644 for (i=0;i<72;i++)
645 {
646 block = dirHeader(buffer1)->hashtable[i];
647 while (block)
648 {
649 buffer2 = getBlock(AROS_BE2LONG(block));
650 if (calcChkSum(128, buffer2->blockbuffer))
651 {
652 errnum = ERR_FSYS_CORRUPT;
653 return 0;
654 }
655 if (AROS_BE2LONG(dirHeader(buffer2)->p_type) != T_SHORT)
656 {
657 errnum = ERR_BAD_FILETYPE;
658 return 0;
659 }
660 checkPossibility(filename, dirHeader(buffer2)->name);
661 block = dirHeader(buffer2)->hashchain;
662 }
663 }
664 UnLockBuffer(buffer1);
665 #ifndef STAGE1_5
666 if (*filename == 0)
667 if (print_possibilities>0)
668 print_possibilities = -print_possibilities;
669 #endif
670 }
671 else
672 {
673 errnum = ERR_BAD_FILETYPE;
674 return 0;
675 }
676 while (*current != '/')
677 current--;
678 current++;
679 fname = filename;
680 while (*fname)
681 *current++ = *fname++;
682 //#warning "TODO: add some more chars until possibilities differ"
683 if (print_possibilities>0)
684 errnum = ERR_FILE_NOT_FOUND;
685 return (print_possibilities<0);
686 }
687 else
688 {
689 while (*current && !isspace(*current))
690 *fname++ = *current++;
691 *fname = 0;
692
693 errnum = findBlock(filename, &buffer2);
694 if (errnum)
695 return 0;
696 if (AROS_BE2LONG(fileHeader(buffer2)->s_type)!=ST_FILE)
697 {
698 errnum = ERR_BAD_FILETYPE;
699 return 0;
700 }
701 fsysb->file.header_block = AROS_BE2LONG(fileHeader(buffer2)->own_key);
702 fsysb->file.current.block = AROS_BE2LONG(fileHeader(buffer2)->own_key);
703 fsysb->file.current.filekey = 71;
704 fsysb->file.current.byte = 0;
705 fsysb->file.current.offset = 0;
706 fsysb->file.filesize = AROS_BE2LONG(fileHeader(buffer2)->bytesize);
707 filepos = 0;
708 filemax = fsysb->file.filesize;
709 return 1;
710 }
711 }
712 #endif
713