1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * transparent archive handling
5 *
6 * 2007 Toni Wilen
7 */
8
9 #include "sysconfig.h"
10 #include "sysdeps.h"
11
12 #if defined(__CELLOS_LV2__) || defined(_WIN32) || defined(WIIU) || defined(__SWITCH__) || defined(VITA)
13 #define tzset()
14 #define timezone 0
15 #define daylight 0
16 #endif
17
18 #if defined(__FreeBSD__)
19 #include <time.h>
20 #include <sys/time.h>
21 #endif
22
23 #include "options.h"
24 #include "zfile.h"
25 #include "archivers/zip/unzip.h"
26 #include "archivers/dms/pfile.h"
27 #include "crc32.h"
28 #include "disk.h"
29 #include "fsdb.h"
30 #include "misc.h"
31
32 #include <zlib.h>
33
34 #define unpack_log write_log
35 #undef unpack_log
36 #define unpack_log(...) { }
37
fromdostime(uae_u32 dd)38 static time_t fromdostime (uae_u32 dd)
39 {
40 struct tm tm;
41 time_t t;
42
43 memset (&tm, 0, sizeof tm);
44 tm.tm_hour = (dd >> 11) & 0x1f;
45 tm.tm_min = (dd >> 5) & 0x3f;
46 tm.tm_sec = ((dd >> 0) & 0x1f) * 2;
47 tm.tm_year = ((dd >> 25) & 0x7f) + 80;
48 tm.tm_mon = ((dd >> 21) & 0x0f) - 1;
49 tm.tm_mday = (dd >> 16) & 0x1f;
50 t = mktime (&tm);
51 tzset ();
52 #if defined(__FreeBSD__)
53 time_t time_now = time(NULL);
54 struct tm* tm_local;
55 tm_local = localtime(&time_now);
56 t -= tm_local->tm_gmtoff;
57 #else
58 t -= (time_t)timezone;
59 #endif
60 return t;
61 }
62
getzvolume(struct znode * parent,struct zfile * zf,unsigned int id)63 static struct zvolume *getzvolume (struct znode *parent, struct zfile *zf, unsigned int id)
64 {
65 struct zvolume *zv = NULL;
66
67 switch (id)
68 {
69 #ifdef A_ZIP
70 case ArchiveFormatZIP:
71 zv = archive_directory_zip (zf);
72 break;
73 #endif
74 #ifdef A_7Z
75 // case ArchiveFormat7Zip:
76 // zv = archive_directory_7z (zf);
77 // break;
78 #endif
79 #ifdef A_RAR
80 // case ArchiveFormatRAR:
81 // zv = archive_directory_rar (zf);
82 // break;
83 #endif
84 #ifdef A_LHA
85 // case ArchiveFormatLHA:
86 // zv = archive_directory_lha (zf);
87 // break;
88 #endif
89 #ifdef A_LZX
90 // case ArchiveFormatLZX:
91 // zv = archive_directory_lzx (zf);
92 // break;
93 #endif
94 case ArchiveFormatPLAIN:
95 zv = archive_directory_plain (zf);
96 break;
97 case ArchiveFormatADF:
98 zv = archive_directory_adf (parent, zf);
99 break;
100 case ArchiveFormatRDB:
101 zv = archive_directory_rdb (zf);
102 break;
103 case ArchiveFormatTAR:
104 zv = archive_directory_tar (zf);
105 break;
106 case ArchiveFormatFAT:
107 zv = archive_directory_fat (zf);
108 break;
109 }
110 #ifdef ARCHIVEACCESS
111 if (!zv)
112 zv = archive_directory_arcacc (zf, id);
113 #endif
114 return zv;
115 }
116
archive_access_select(struct znode * parent,struct zfile * zf,unsigned int id,int dodefault,int * retcode,int index)117 struct zfile *archive_access_select (struct znode *parent, struct zfile *zf, unsigned int id, int dodefault, int *retcode, int index)
118 {
119 struct zvolume *zv;
120 struct znode *zn;
121 int zipcnt, first, select;
122 TCHAR tmphist[MAX_DPATH];
123 struct zfile *z = NULL;
124 int we_have_file;
125 int diskimg;
126 int mask = zf->zfdmask;
127 int canhistory = (mask & ZFD_DISKHISTORY) && !(mask & ZFD_CHECKONLY);
128 int getflag = (mask & ZFD_DELAYEDOPEN) ? FILE_DELAYEDOPEN : 0;
129
130 if (retcode)
131 *retcode = 0;
132 if (index > 0)
133 return NULL;
134 if (zfile_needwrite (zf)) {
135 if (retcode)
136 *retcode = -1;
137 return NULL;
138 }
139 zv = getzvolume (parent, zf, id);
140 if (!zv)
141 return NULL;
142 we_have_file = 0;
143 tmphist[0] = 0;
144 zipcnt = 1;
145 first = 1;
146 zn = &zv->root;
147 while (zn) {
148 int isok = 1;
149
150 diskimg = -1;
151 if (zn->type != ZNODE_FILE)
152 isok = 0;
153 if (zfile_is_ignore_ext (zn->fullname))
154 isok = 0;
155 diskimg = zfile_is_diskimage (zn->fullname);
156 if (isok) {
157 if (tmphist[0]) {
158 #ifndef _CONSOLE
159 if (diskimg >= 0 && canhistory)
160 DISK_history_add (tmphist, -1, diskimg, 1);
161 #endif
162 tmphist[0] = 0;
163 first = 0;
164 }
165 if (first) {
166 if (diskimg >= 0)
167 _tcscpy (tmphist, zn->fullname);
168 } else {
169 _tcscpy (tmphist, zn->fullname);
170 #ifndef _CONSOLE
171 if (diskimg >= 0 && canhistory)
172 DISK_history_add (tmphist, -1, diskimg, 1);
173 #endif
174 tmphist[0] = 0;
175 }
176 select = 0;
177 if (!zf->zipname)
178 select = 1;
179 if (zf->zipname && _tcslen (zn->fullname) >= _tcslen (zf->zipname) && !strcasecmp (zf->zipname, zn->fullname + _tcslen (zn->fullname) - _tcslen (zf->zipname)))
180 select = -1;
181 if (zf->zipname && zf->zipname[0] == '#' && _tstol (zf->zipname + 1) == zipcnt)
182 select = -1;
183 if (select && we_have_file < 10) {
184 struct zfile *zt = NULL;
185 TCHAR *ext = _tcsrchr (zn->fullname, '.');
186 int whf = 1;
187 int ft = 0;
188 if (mask & ZFD_CD) {
189 if (ext && !_tcsicmp (ext, _T(".iso"))) {
190 whf = 2;
191 ft = ZFILE_CDIMAGE;
192 }
193 if (ext && !_tcsicmp (ext, _T(".chd"))) {
194 whf = 2;
195 ft = ZFILE_CDIMAGE;
196 }
197 if (ext && !_tcsicmp (ext, _T(".ccd"))) {
198 whf = 9;
199 ft = ZFILE_CDIMAGE;
200 }
201 if (ext && !_tcsicmp (ext, _T(".cue"))) {
202 whf = 10;
203 ft = ZFILE_CDIMAGE;
204 }
205 } else {
206 zt = archive_getzfile (zn, id, getflag);
207 ft = zfile_gettype (zt);
208 }
209 if ((select < 0 || ft) && whf > we_have_file) {
210 if (!zt)
211 zt = archive_getzfile (zn, id, getflag);
212 we_have_file = whf;
213 if (z)
214 zfile_fclose (z);
215 z = zt;
216 zt = NULL;
217 }
218 zfile_fclose (zt);
219 }
220 }
221 zipcnt++;
222 zn = zn->next;
223 }
224 #ifndef _CONSOLE
225 diskimg = zfile_is_diskimage (zfile_getname (zf));
226 if (diskimg >= 0 && first && tmphist[0] && canhistory)
227 DISK_history_add (zfile_getname (zf), -1, diskimg, 1);
228 #endif
229 zfile_fclose_archive (zv);
230 if (z) {
231 zfile_fclose (zf);
232 zf = z;
233 } else if (!dodefault && zf->zipname && zf->zipname[0]) {
234 if (retcode)
235 *retcode = -1;
236 zf = NULL;
237 } else {
238 zf = NULL;
239 }
240 return zf;
241 }
242
archive_access_arcacc_select(struct zfile * zf,unsigned int id,int * retcode)243 struct zfile *archive_access_arcacc_select (struct zfile *zf, unsigned int id, int *retcode)
244 {
245 if (zfile_needwrite (zf)) {
246 if (retcode)
247 *retcode = -1;
248 return NULL;
249 }
250 return zf;
251 }
252
archive_access_scan(struct zfile * zf,zfile_callback zc,void * user,unsigned int id)253 void archive_access_scan (struct zfile *zf, zfile_callback zc, void *user, unsigned int id)
254 {
255 struct zvolume *zv;
256 struct znode *zn;
257
258 zv = getzvolume (NULL, zf, id);
259 if (!zv)
260 return;
261 zn = &zv->root;
262 while (zn) {
263 if (zn->type == ZNODE_FILE) {
264 struct zfile *zf2 = archive_getzfile (zn, id, 0);
265 if (zf2) {
266 int ztype = iszip (zf2);
267 if (ztype) {
268 zfile_fclose (zf2);
269 } else {
270 int ret = zc (zf2, user);
271 zfile_fclose (zf2);
272 if (ret)
273 break;
274 }
275 }
276 }
277 zn = zn->next;
278 }
279 zfile_fclose_archive (zv);
280 }
281
282 /* TAR */
283
archive_close_tar(void * handle)284 static void archive_close_tar (void *handle)
285 {
286 }
287
archive_directory_tar(struct zfile * z)288 struct zvolume *archive_directory_tar (struct zfile *z)
289 {
290 struct zvolume *zv;
291 struct znode *zn;
292
293 tzset ();
294 #if defined(__FreeBSD__)
295 time_t time_now = time(NULL);
296 struct tm* tm_local;
297 tm_local = localtime(&time_now);
298 #endif
299 zv = zvolume_alloc (z, ArchiveFormatTAR, NULL, NULL);
300 for (;;) {
301 uae_u8 block[512];
302 char name[MAX_DPATH];
303 int ustar = 0;
304 struct zarchive_info zai;
305 int valid = 1;
306 uae_u64 size;
307
308 if (zfile_fread (block, 512, 1, z) != 1)
309 break;
310 if (block[0] == 0)
311 break;
312
313 if (!memcmp (block + 257, "ustar ", 8))
314 ustar = 1;
315 name[0] = 0;
316 if (ustar)
317 strcpy (name, (char*)block + 345);
318 strcat (name, (char*)block);
319
320 if (name[0] == 0)
321 valid = 0;
322 if (block[156] != '0')
323 valid = 0;
324 if (ustar && (block[256] != 0 && block[256] != '0'))
325 valid = 0;
326
327 size = _strtoui64 ((char*)block + 124, NULL, 8);
328
329 if (valid) {
330 memset (&zai, 0, sizeof zai);
331 zai.name = au (name);
332 zai.size = size;
333 zai.tv.tv_sec = _strtoui64 ((char*)block + 136, NULL, 8);
334 #if defined(__FreeBSD__)
335 zai.tv.tv_sec += tm_local->tm_gmtoff;
336 if (tm_local->tm_isdst)
337 #else
338 zai.tv.tv_sec += timezone;
339 if (daylight)
340 #endif
341 zai.tv.tv_sec -= 1 * 60 * 60;
342 if (zai.name[_tcslen (zai.name) - 1] == '/') {
343 zn = zvolume_adddir_abs (zv, &zai);
344 } else {
345 zn = zvolume_addfile_abs (zv, &zai);
346 if (zn)
347 zn->offset = zfile_ftell (z);
348 }
349 xfree (zai.name);
350 }
351 zfile_fseek (z, (size + 511) & ~511, SEEK_CUR);
352 }
353 zv->method = ArchiveFormatTAR;
354 return zv;
355 }
356
archive_access_tar(struct znode * zn)357 struct zfile *archive_access_tar (struct znode *zn)
358 {
359 #if 0
360 struct zfile *zf = zfile_fopen_empty (zn->volume->archive, zn->fullname, zn->size);
361 zfile_fseek (zn->volume->archive, zn->offset, SEEK_SET);
362 zfile_fwrite (zf->data, zn->size, 1, zn->volume->archive);
363 return zf;
364 #else
365 return zfile_fopen_parent (zn->volume->archive, zn->fullname, zn->offset, zn->size);
366 #endif
367 }
368
369 /* ZIP */
370 #ifdef A_ZIP
371
archive_close_zip(void * handle)372 static void archive_close_zip (void *handle)
373 {
374 }
375
archive_directory_zip(struct zfile * z)376 struct zvolume *archive_directory_zip (struct zfile *z)
377 {
378 unzFile uz;
379 unz_file_info file_info;
380 struct zvolume *zv;
381 int err;
382
383 uz = unzOpen (z);
384 if (!uz)
385 return 0;
386 if (unzGoToFirstFile (uz) != UNZ_OK)
387 return 0;
388 zv = zvolume_alloc (z, ArchiveFormatZIP, NULL, NULL);
389 for (;;) {
390 char filename_inzip2[MAX_DPATH];
391 TCHAR c;
392 struct zarchive_info zai;
393 time_t t;
394 unsigned int dd;
395 TCHAR *filename_inzip;
396
397 err = unzGetCurrentFileInfo (uz, &file_info, filename_inzip2, sizeof (filename_inzip2), NULL, 0, NULL, 0);
398 if (err != UNZ_OK)
399 return 0;
400 if (file_info.flag & (1 << 11)) { // UTF-8 encoded
401 filename_inzip = utf8u (filename_inzip2);
402 } else {
403 filename_inzip = au (filename_inzip2);
404 }
405 dd = file_info.dosDate;
406 t = fromdostime (dd);
407 memset (&zai, 0, sizeof zai);
408 zai.name = filename_inzip;
409 zai.tv.tv_sec = t;
410 zai.flags = -1;
411 c = filename_inzip[_tcslen (filename_inzip) - 1];
412 if (c != '/' && c != '\\') {
413 int err = unzOpenCurrentFile (uz);
414 if (err == UNZ_OK) {
415 struct znode *zn;
416 zai.size = file_info.uncompressed_size;
417 zn = zvolume_addfile_abs (zv, &zai);
418 }
419 } else {
420 filename_inzip[_tcslen (filename_inzip) - 1] = 0;
421 zvolume_adddir_abs (zv, &zai);
422 }
423 xfree (filename_inzip);
424 err = unzGoToNextFile (uz);
425 if (err != UNZ_OK)
426 break;
427 }
428 unzClose (uz);
429 zv->method = ArchiveFormatZIP;
430 return zv;
431 }
432
433
archive_do_zip(struct znode * zn,struct zfile * z,int flags)434 static struct zfile *archive_do_zip (struct znode *zn, struct zfile *z, int flags)
435 {
436 unzFile uz;
437 int i;
438 TCHAR tmp[MAX_DPATH];
439 TCHAR *name = z ? z->archiveparent->name : zn->volume->root.fullname;
440 char *s;
441
442 uz = unzOpen (z ? z->archiveparent : zn->volume->archive);
443 if (!uz)
444 return 0;
445 if (z)
446 _tcscpy (tmp, z->archiveparent->name);
447 else
448 _tcscpy (tmp, zn->fullname + _tcslen (zn->volume->root.fullname) + 1);
449 if (unzGoToFirstFile (uz) != UNZ_OK)
450 goto error;
451 for (i = 0; tmp[i]; i++) {
452 if (tmp[i] == '\\')
453 tmp[i] = '/';
454 }
455 s = ua (tmp);
456 if (unzLocateFile (uz, s, 1) != UNZ_OK) {
457 xfree (s);
458 for (i = 0; tmp[i]; i++) {
459 if (tmp[i] == '/')
460 tmp[i] = '\\';
461 }
462 s = ua (tmp);
463 if (unzLocateFile (uz, s, 1) != UNZ_OK) {
464 xfree (s);
465 goto error;
466 }
467 }
468 xfree (s);
469 s = NULL;
470 if (unzOpenCurrentFile (uz) != UNZ_OK)
471 goto error;
472 if (!z)
473 z = zfile_fopen_empty (NULL, zn->fullname, zn->size);
474 if (z) {
475 int err = -1;
476 if (!(flags & FILE_DELAYEDOPEN) || z->size <= PEEK_BYTES) {
477 unpack_log (_T("ZIP: unpacking %s, flags=%d\n"), name, flags);
478 err = unzReadCurrentFile (uz, z->data, z->datasize);
479 unpack_log (_T("ZIP: unpacked, code=%d\n"), err);
480 } else {
481 z->archiveparent = zfile_dup (zn->volume->archive);
482 if (z->archiveparent) {
483 unpack_log (_T("ZIP: delayed open '%s'\n"), name);
484 xfree (z->archiveparent->name);
485 z->archiveparent->name = my_strdup (tmp);
486 z->datasize = PEEK_BYTES;
487 err = unzReadCurrentFile (uz, z->data, z->datasize);
488 unpack_log (_T("ZIP: unpacked, code=%d\n"), err);
489 } else {
490 unpack_log (_T("ZIP: unpacking %s (failed DELAYEDOPEN)\n"), name);
491 err = unzReadCurrentFile (uz, z->data, z->datasize);
492 unpack_log (_T("ZIP: unpacked, code=%d\n"), err);
493 }
494 }
495 }
496 unzCloseCurrentFile (uz);
497 unzClose (uz);
498 return z;
499 error:
500 unzClose (uz);
501 return NULL;
502 }
503
archive_access_zip(struct znode * zn,int flags)504 struct zfile *archive_access_zip (struct znode *zn, int flags)
505 {
506 return archive_do_zip (zn, NULL, flags);
507 }
archive_unpack_zip(struct zfile * zf)508 static struct zfile *archive_unpack_zip (struct zfile *zf)
509 {
510 return archive_do_zip (NULL, zf, 0);
511 }
512 #endif
513
514 /* ArchiveAccess */
515
516
517 #if defined(ARCHIVEACCESS)
518
519 struct aaFILETIME
520 {
521 uae_u32 dwLowDateTime;
522 uae_u32 dwHighDateTime;
523 };
524 typedef void* aaHandle;
525 // This struct contains file information from an archive. The caller may store
526 // this information for accessing this file after calls to findFirst, findNext
527 #define FileInArchiveInfoStringSize 1024
528 struct aaFileInArchiveInfo {
529 int ArchiveHandle; // handle for Archive/class pointer
530 uae_u64 CompressedFileSize;
531 uae_u64 UncompressedFileSize;
532 uae_u32 attributes;
533 int IsDir;
534 struct aaFILETIME LastWriteTime;
535 char path[FileInArchiveInfoStringSize];
536 };
537
538
539 #define ARCACC_STACKSIZE 10
540 static struct zfile *arcacc_stack[ARCACC_STACKSIZE];
541 static int arcacc_stackptr = -1;
542
arcacc_push(struct zfile * f)543 static int arcacc_push (struct zfile *f)
544 {
545 if (arcacc_stackptr == ARCACC_STACKSIZE - 1)
546 return -1;
547 arcacc_stackptr++;
548 arcacc_stack[arcacc_stackptr] = f;
549 return arcacc_stackptr;
550 }
arcacc_pop(void)551 static void arcacc_pop (void)
552 {
553 arcacc_stackptr--;
554 }
555
readCallback(int StreamID,uae_u64 offset,uae_u32 count,void * buf,uae_u32 * processedSize)556 static HRESULT __stdcall readCallback (int StreamID, uae_u64 offset, uae_u32 count, void *buf, uae_u32 *processedSize)
557 {
558 struct zfile *f = arcacc_stack[StreamID];
559 int ret;
560
561 zfile_fseek (f, (long)offset, SEEK_SET);
562 ret = zfile_fread (buf, 1, count, f);
563 if (processedSize)
564 *processedSize = ret;
565 return 0;
566 }
writeCallback(int StreamID,uae_u64 offset,uae_u32 count,const void * buf,uae_u32 * processedSize)567 static HRESULT __stdcall writeCallback (int StreamID, uae_u64 offset, uae_u32 count, const void *buf, uae_u32 *processedSize)
568 {
569 struct zfile *f = arcacc_stack[StreamID];
570 int ret;
571
572 ret = zfile_fwrite ((void*)buf, 1, count, f);
573 if (processedSize)
574 *processedSize = ret;
575 if (ret != count)
576 return -1;
577 return 0;
578 }
579
archive_directory_arcacc(struct zfile * z,unsigned int id)580 struct zvolume *archive_directory_arcacc (struct zfile *z, unsigned int id)
581 {
582 aaHandle ah;
583 int id_r, status;
584 int fc, f;
585 struct zvolume *zv;
586 int skipsize = 0;
587
588 if (!arcacc_init (z))
589 return NULL;
590 zv = zvolume_alloc (z, ArchiveFormatAA, NULL, NULL);
591 id_r = arcacc_push (z);
592 ah = aaOpenArchive (readCallback, id_r, zv->archivesize, id, &status, NULL);
593 if (!status) {
594 zv->handle = ah;
595 fc = aaGetFileCount (ah);
596 for (f = 0; f < fc; f++) {
597 struct aaFileInArchiveInfo fi;
598 TCHAR *name;
599 struct znode *zn;
600 struct zarchive_info zai;
601
602 memset (&fi, 0, sizeof (fi));
603 aaGetFileInfo (ah, f, &fi);
604 if (fi.IsDir)
605 continue;
606
607 name = au (fi.path);
608 memset (&zai, 0, sizeof zai);
609 zai.name = name;
610 zai.flags = -1;
611 zai.size = (unsigned int)fi.UncompressedFileSize;
612 zn = zvolume_addfile_abs (zv, &zai);
613 xfree (name);
614 zn->offset = f;
615 zn->method = id;
616
617 if (id == ArchiveFormat7Zip) {
618 if (fi.CompressedFileSize)
619 skipsize = 0;
620 skipsize += (int)fi.UncompressedFileSize;
621 }
622 }
623 aaCloseArchive (ah);
624 }
625 arcacc_pop ();
626 zv->method = ArchiveFormatAA;
627 return zv;
628 }
629
630
archive_access_arcacc(struct znode * zn)631 static struct zfile *archive_access_arcacc (struct znode *zn)
632 {
633 struct zfile *zf;
634 struct zfile *z = zn->volume->archive;
635 int status, id_r, id_w;
636 aaHandle ah;
637 int ok = 0;
638
639 id_r = arcacc_push (z);
640 ah = aaOpenArchive (readCallback, id_r, zn->volume->archivesize, zn->method, &status, NULL);
641 if (!status) {
642 int err;
643 uae_u64 written = 0;
644 struct aaFileInArchiveInfo fi;
645 memset (&fi, 0, sizeof (fi));
646 aaGetFileInfo (ah, zn->offset, &fi);
647 zf = zfile_fopen_empty (z, zn->fullname, zn->size);
648 id_w = arcacc_push (zf);
649 err = aaExtract(ah, zn->offset, id_w, writeCallback, &written);
650 if (zf->seek == fi.UncompressedFileSize)
651 ok = 1;
652 arcacc_pop();
653 }
654 aaCloseArchive(ah);
655 arcacc_pop();
656 if (ok)
657 return zf;
658 zfile_fclose(zf);
659 return NULL;
660 }
661 #endif
662
663 /* plain single file */
664
addfile(struct zvolume * zv,struct zfile * zf,const TCHAR * path,uae_u8 * data,int size)665 static struct znode *addfile (struct zvolume *zv, struct zfile *zf, const TCHAR *path, uae_u8 *data, int size)
666 {
667 struct zarchive_info zai;
668 struct znode *zn;
669 struct zfile *z;
670
671 z = zfile_fopen_empty (zf, path, size);
672 if (!z)
673 return NULL;
674 zfile_fwrite (data, size, 1, z);
675 memset (&zai, 0, sizeof zai);
676 zai.name = my_strdup (path);
677 zai.flags = -1;
678 zai.size = size;
679 zn = zvolume_addfile_abs (zv, &zai);
680 if (zn)
681 zn->f = z;
682 else
683 zfile_fclose (z);
684 xfree (zai.name);
685 return zn;
686 }
687
688 static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00};
archive_directory_plain(struct zfile * z)689 struct zvolume *archive_directory_plain (struct zfile *z)
690 {
691 struct zfile *zf, *zf2;
692 struct zvolume *zv;
693 struct znode *zn;
694 struct zarchive_info zai;
695 uae_u8 id[8];
696 int rc, index;
697
698 memset (&zai, 0, sizeof zai);
699 zv = zvolume_alloc (z, ArchiveFormatPLAIN, NULL, NULL);
700 memset(id, 0, sizeof id);
701 zai.name = zfile_getfilename (z);
702 zai.flags = -1;
703 zfile_fseek(z, 0, SEEK_END);
704 zai.size = zfile_ftell (z);
705 zfile_fseek(z, 0, SEEK_SET);
706 zfile_fread(id, sizeof id, 1, z);
707 zfile_fseek(z, 0, SEEK_SET);
708 zn = zvolume_addfile_abs (zv, &zai);
709 if (!memcmp (id, exeheader, sizeof id)) {
710 char *an = ua (zai.name);
711 char *data = xmalloc (char, 1 + strlen (an) + 1 + 1 + 1);
712 sprintf (data, "\"%s\"\n", an);
713 zn = addfile (zv, z, _T("s/startup-sequence"), (uae_u8*)data, strlen (data));
714 xfree (data);
715 xfree (an);
716 }
717 index = 0;
718 for (;;) {
719 zf = zfile_dup (z);
720 if (!zf)
721 break;
722 zf2 = zuncompress (NULL, zf, 0, ZFD_ALL & ~ZFD_ADF, &rc, index);
723 if (zf2) {
724 zf = NULL;
725 zai.name = zfile_getfilename (zf2);
726 zai.flags = -1;
727 zfile_fseek (zf2, 0, SEEK_END);
728 zai.size = zfile_ftell (zf2);
729 zfile_fseek (zf2, 0, SEEK_SET);
730 zn = zvolume_addfile_abs (zv, &zai);
731 zn->f = zf2;
732 // if (zn)
733 // zn->offset = index + 1;
734 // zfile_fclose (zf2);
735 } else {
736 if (rc == 0) {
737 zfile_fclose (zf);
738 break;
739 }
740 }
741 index++;
742 zfile_fclose (zf);
743 }
744 return zv;
745 }
746
archive_access_plain(struct znode * zn)747 static struct zfile *archive_access_plain (struct znode *zn)
748 {
749 struct zfile *z = NULL;
750
751 if (zn->offset) {
752 struct zfile *zf;
753 z = zfile_fopen_empty (zn->volume->archive, zn->fullname, zn->size);
754 zf = zfile_fopen4 (zfile_getname (zn->volume->archive), _T("rb"), zn->volume->archive->zfdmask & ~ZFD_ADF, zn->offset - 1);
755 if (zf) {
756 zfile_fread (z->data, zn->size, 1, zf);
757 zfile_fclose (zf);
758 }
759 } else {
760 z = zfile_fopen_empty (zn->volume->archive, zn->fullname, zn->size);
761 if (z) {
762 zfile_fseek (zn->volume->archive, 0, SEEK_SET);
763 zfile_fread (z->data, zn->size, 1, zn->volume->archive);
764 }
765 }
766 return z;
767 }
768
769 struct adfhandle {
770 int size;
771 int highblock;
772 int blocksize;
773 int rootblock;
774 struct zfile *z;
775 uae_u8 block[65536];
776 uae_u32 dostype;
777 };
778
779
dos_checksum(uae_u8 * p,int blocksize)780 static int dos_checksum (uae_u8 *p, int blocksize)
781 {
782 uae_u32 cs = 0;
783 int i;
784 for (i = 0; i < blocksize; i += 4)
785 cs += (p[i] << 24) | (p[i + 1] << 16) | (p[i + 2] << 8) | (p[i + 3] << 0);
786 return cs;
787 }
sfs_checksum(uae_u8 * p,int blocksize,int sfs2)788 static int sfs_checksum (uae_u8 *p, int blocksize, int sfs2)
789 {
790 uae_u32 cs = sfs2 ? 2 : 1;
791 int i;
792 for (i = 0; i < blocksize; i += 4)
793 cs += (p[i] << 24) | (p[i + 1] << 16) | (p[i + 2] << 8) | (p[i + 3] << 0);
794 return cs;
795 }
796
getBSTR(uae_u8 * bstr)797 static TCHAR *getBSTR (uae_u8 *bstr)
798 {
799 int n = *bstr++;
800 uae_char buf[257];
801 int i;
802
803 for (i = 0; i < n; i++)
804 buf[i] = *bstr++;
805 buf[i] = 0;
806 return au (buf);
807 }
808
gl(struct adfhandle * adf,int off)809 static uae_u32 gl (struct adfhandle *adf, int off)
810 {
811 uae_u8 *p = adf->block + off;
812 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
813 }
glx(uae_u8 * p)814 static uae_u32 glx (uae_u8 *p)
815 {
816 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
817 }
gwx(uae_u8 * p)818 static uae_u32 gwx (uae_u8 *p)
819 {
820 return (p[0] << 8) | (p[1] << 0);
821 }
822
823 static const int secs_per_day = 24 * 60 * 60;
824 static const int diff = (8 * 365 + 2) * (24 * 60 * 60);
825 static const int diff2 = (-8 * 365 - 2) * (24 * 60 * 60);
put_time(long days,long mins,long ticks)826 static time_t put_time (long days, long mins, long ticks)
827 {
828 time_t t;
829
830 if (days < 0)
831 days = 0;
832 if (days > 9900 * 365)
833 days = 9900 * 365; // in future far enough?
834 if (mins < 0 || mins >= 24 * 60)
835 mins = 0;
836 if (ticks < 0 || ticks >= 60 * 50)
837 ticks = 0;
838
839 t = ticks / 50;
840 t += mins * 60;
841 t += ((uae_u64)days) * secs_per_day;
842 t += diff;
843
844 return t;
845 }
846
adf_read_block(struct adfhandle * adf,int block)847 static int adf_read_block (struct adfhandle *adf, int block)
848 {
849 memset (adf->block, 0, adf->blocksize);
850 if (block >= adf->highblock || block < 0)
851 return 0;
852 zfile_fseek (adf->z, block * adf->blocksize, SEEK_SET);
853 zfile_fread (adf->block, adf->blocksize, 1, adf->z);
854 return 1;
855 }
856
recurseadf(struct znode * zn,int root,TCHAR * name)857 static void recurseadf (struct znode *zn, int root, TCHAR *name)
858 {
859 int i;
860 struct zvolume *zv = zn->volume;
861 struct adfhandle *adf = (struct adfhandle*)zv->handle;
862 TCHAR name2[MAX_DPATH];
863 int bs = adf->blocksize;
864
865 for (i = 0; i < bs / 4 - 56; i++) {
866 int block;
867 if (!adf_read_block (adf, root))
868 return;
869 block = gl (adf, (i + 6) * 4);
870 while (block > 0 && block < adf->size / bs) {
871 struct zarchive_info zai;
872 TCHAR *fname;
873 uae_u32 size, secondary;
874
875 if (!adf_read_block (adf, block))
876 return;
877 if (gl (adf, 0) != 2)
878 break;
879 if (gl (adf, 1 * 4) != (uae_u32)block)
880 break;
881 secondary = gl (adf, bs - 1 * 4);
882 /* Note: secondary is unsigned, and gl() returns unsigned.
883 * It can _NEVER_ be lower than 0.
884 * But as gl() is just producing a bitmask, it might
885 * be meant as a representation?
886 * Please confirm or correct this before editing.
887 * - Sven
888 */
889 if (secondary != (uae_u32)-3 && secondary != 2)
890 break;
891 memset (&zai, 0, sizeof zai);
892 fname = getBSTR (adf->block + bs - 20 * 4);
893 size = gl (adf, bs - 47 * 4);
894 name2[0] = 0;
895 if (name[0]) {
896 TCHAR sep[] = { FSDB_DIR_SEPARATOR, 0 };
897 _tcscpy (name2, name);
898 _tcscat (name2, sep);
899 }
900 _tcscat (name2, fname);
901 zai.name = name2;
902 if (size > 0x7fffffff)
903 size = 0;
904 zai.size = size;
905 zai.flags = gl (adf, bs - 48 * 4);
906 amiga_to_timeval (&zai.tv, gl (adf, bs - 23 * 4), gl (adf, bs - 22 * 4),gl (adf, bs - 21 * 4));
907 if (secondary == (uae_u32)-3) {
908 struct znode *znnew = zvolume_addfile_abs (zv, &zai);
909 znnew->offset = block;
910 } else {
911 struct znode *znnew = zvolume_adddir_abs (zv, &zai);
912 znnew->offset = block;
913 recurseadf (znnew, block, name2);
914 if (!adf_read_block (adf, block))
915 return;
916 }
917 xfree (fname);
918 block = gl (adf, bs - 4 * 4);
919 }
920 }
921 }
922
recursesfs(struct znode * zn,int root,TCHAR * name,int sfs2)923 static void recursesfs (struct znode *zn, int root, TCHAR *name, int sfs2)
924 {
925 struct zvolume *zv = zn->volume;
926 struct adfhandle *adf = (struct adfhandle*)zv->handle;
927 TCHAR name2[MAX_DPATH];
928 int bs = adf->blocksize;
929 int block;
930 uae_u8 *p, *s;
931 struct zarchive_info zai;
932
933 block = root;
934 while (block) {
935 if (!adf_read_block (adf, block))
936 return;
937 p = adf->block + 12 + 3 * 4;
938 while (glx (p + 4) && p < adf->block + adf->blocksize - 27) {
939 TCHAR *fname;
940 int i;
941 int align;
942
943 memset (&zai, 0, sizeof zai);
944 zai.flags = glx (p + 8) ^ 0x0f;
945 s = p + (sfs2 ? 27 : 25);
946 fname = au ((char*)s);
947 i = 0;
948 while (*s) {
949 s++;
950 i++;
951 }
952 s++;
953 i++;
954 if (*s)
955 zai.comment = au ((char*)s);
956 while (*s) {
957 s++;
958 i++;
959 }
960 s++;
961 i++;
962 i += sfs2 ? 27 : 25;
963 align = i & 1;
964
965 name2[0] = 0;
966 if (name[0]) {
967 TCHAR sep[] = { FSDB_DIR_SEPARATOR, 0 };
968 _tcscpy (name2, name);
969 _tcscat (name2, sep);
970 }
971 _tcscat (name2, fname);
972 zai.name = name2;
973 if (sfs2)
974 zai.tv.tv_sec = glx (p + 22) - diff2;
975 else
976 zai.tv.tv_sec = glx (p + 20) - diff;
977 if (p[sfs2 ? 26 : 24] & 0x80) { // dir
978 struct znode *znnew = zvolume_adddir_abs (zv, &zai);
979 int newblock = glx (p + 16);
980 if (newblock) {
981 znnew->offset = block;
982 recursesfs (znnew, newblock, name2, sfs2);
983 }
984 if (!adf_read_block (adf, block))
985 return;
986 } else {
987 struct znode *znnew;
988 if (sfs2) {
989 uae_u64 b1 = p[16];
990 uae_u64 b2 = p[17];
991 zai.size = (b1 << 40) | (b2 << 32) | glx (p + 18) ;
992 } else {
993 zai.size = glx (p + 16);
994 }
995 znnew = zvolume_addfile_abs (zv, &zai);
996 znnew->offset = block;
997 znnew->offset2 = p - adf->block;
998 }
999 xfree (zai.comment);
1000 xfree (fname);
1001 p += i + align;
1002 }
1003 block = gl (adf, 12 + 4);
1004 }
1005
1006 }
1007
archive_directory_adf(struct znode * parent,struct zfile * z)1008 struct zvolume *archive_directory_adf (struct znode *parent, struct zfile *z)
1009 {
1010 struct zvolume *zv;
1011 struct adfhandle *adf;
1012 TCHAR *volname = NULL;
1013 TCHAR name[MAX_DPATH];
1014 int gotroot = 0;
1015
1016 adf = xcalloc (struct adfhandle, 1);
1017 zfile_fseek (z, 0, SEEK_END);
1018 adf->size = zfile_ftell (z);
1019 zfile_fseek (z, 0, SEEK_SET);
1020
1021 adf->blocksize = 512;
1022 if (parent && parent->offset2) {
1023 if (parent->offset2 == 1024 || parent->offset2 == 2048 || parent->offset2 == 4096 || parent->offset2 == 8192 ||
1024 parent->offset2 == 16384 || parent->offset2 == 32768 || parent->offset2 == 65536) {
1025 adf->blocksize = parent->offset2;
1026 gotroot = 1;
1027 }
1028 }
1029
1030 adf->highblock = adf->size / adf->blocksize;
1031 adf->z = z;
1032
1033 if (!adf_read_block (adf, 0))
1034 goto fail;
1035 adf->dostype = gl (adf, 0);
1036
1037 if ((adf->dostype & 0xffffff00) == 0x444f5300 /* 'DOS' */) {
1038 int bs = adf->blocksize;
1039 int res;
1040
1041 adf->rootblock = ((adf->size / bs) - 1 + 2) / 2;
1042 if (!gotroot) {
1043 for (res = 2; res >= 1; res--) {
1044 for (bs = 512; bs < 65536; bs <<= 1) {
1045 adf->blocksize = bs;
1046 adf->rootblock = ((adf->size / bs) - 1 + res) / 2;
1047 if (!adf_read_block (adf, adf->rootblock))
1048 continue;
1049 if (gl (adf, 0) != 2 || gl (adf, bs - 1 * 4) != 1)
1050 continue;
1051 if (dos_checksum (adf->block, bs) != 0)
1052 continue;
1053 gotroot = 1;
1054 break;
1055 }
1056 if (gotroot)
1057 break;
1058 }
1059 }
1060 if (!gotroot) {
1061 bs = adf->blocksize = 512;
1062 if (adf->size < 2000000 && adf->rootblock != 880) {
1063 adf->rootblock = 880;
1064 if (!adf_read_block (adf, adf->rootblock))
1065 goto fail;
1066 if (gl (adf, 0) != 2 || gl (adf, bs - 1 * 4) != 1)
1067 goto fail;
1068 if (dos_checksum (adf->block, bs) != 0)
1069 goto fail;
1070 }
1071 }
1072
1073 if (!adf_read_block (adf, adf->rootblock))
1074 goto fail;
1075 if (gl (adf, 0) != 2 || gl (adf, bs - 1 * 4) != 1)
1076 goto fail;
1077 if (dos_checksum (adf->block, adf->blocksize) != 0)
1078 goto fail;
1079 adf->blocksize = bs;
1080 adf->highblock = adf->size / adf->blocksize;
1081 volname = getBSTR (adf->block + adf->blocksize - 20 * 4);
1082 zv = zvolume_alloc (z, ArchiveFormatADF, NULL, NULL);
1083 zv->method = ArchiveFormatADF;
1084 zv->handle = adf;
1085
1086 name[0] = 0;
1087 recurseadf (&zv->root, adf->rootblock, name);
1088
1089 } else if ((adf->dostype & 0xffffff00) == 0x53465300 /* 'SFS' */) {
1090
1091 uae_u16 version, sfs2;
1092
1093 for (;;) {
1094 for (;;) {
1095 version = gl (adf, 12) >> 16;
1096 sfs2 = version > 3;
1097 if (version > 4)
1098 break;
1099 adf->rootblock = gl (adf, 104);
1100 if (!adf_read_block (adf, adf->rootblock))
1101 break;
1102 if (gl (adf, 0) != 0x4f424a43 /* 'OBJC' */)
1103 break;
1104 if (sfs_checksum (adf->block, adf->blocksize, sfs2))
1105 break;
1106 adf->rootblock = gl (adf, 40);
1107 if (!adf_read_block (adf, adf->rootblock))
1108 break;
1109 if (gl (adf, 0) != 0x4f424a43 /* 'OBJC' */)
1110 break;
1111 if (sfs_checksum (adf->block, adf->blocksize, sfs2))
1112 break;
1113 gotroot = 1;
1114 break;
1115 }
1116 if (gotroot)
1117 break;
1118 adf->blocksize <<= 1;
1119 if (adf->blocksize == 65536)
1120 break;
1121 }
1122 if (!gotroot)
1123 goto fail;
1124
1125 zv = zvolume_alloc (z, ArchiveFormatADF, NULL, NULL);
1126 zv->method = ArchiveFormatADF;
1127 zv->handle = adf;
1128
1129 name[0] = 0;
1130 recursesfs (&zv->root, adf->rootblock, name, version > 3);
1131
1132 } else {
1133 goto fail;
1134 }
1135
1136
1137 xfree (volname);
1138 return zv;
1139 fail:
1140 xfree (adf);
1141 return NULL;
1142 }
1143
1144 struct sfsblock
1145 {
1146 int block;
1147 int length;
1148 };
1149
sfsfindblock(struct adfhandle * adf,int btree,int theblock,struct sfsblock ** sfsb,int * sfsblockcnt,int * sfsmaxblockcnt,int sfs2)1150 static int sfsfindblock (struct adfhandle *adf, int btree, int theblock, struct sfsblock **sfsb, int *sfsblockcnt, int *sfsmaxblockcnt, int sfs2)
1151 {
1152 int nodecount, isleaf, nodesize;
1153 int i;
1154 uae_u8 *p;
1155
1156 if (!btree)
1157 return 0;
1158 if (!adf_read_block (adf, btree))
1159 return 0;
1160 if (memcmp (adf->block, "BNDC", 4))
1161 return 0;
1162 nodecount = gwx (adf->block + 12);
1163 isleaf = adf->block[14];
1164 nodesize = adf->block[15];
1165 p = adf->block + 16;
1166 for (i = 0; i < nodecount; i++) {
1167 if (isleaf) {
1168 uae_u32 key = glx (p);
1169 uae_u32 next = glx (p + 4);
1170 uae_u32 prev = glx (p + 8);
1171 uae_u32 blocks;
1172 if (sfs2)
1173 blocks = glx (p + 12);
1174 else
1175 blocks = gwx (p + 12);
1176 if (key == (uae_u32)theblock) {
1177 struct sfsblock *sb;
1178 if (*sfsblockcnt >= *sfsmaxblockcnt) {
1179 *sfsmaxblockcnt += 100;
1180 *sfsb = xrealloc (struct sfsblock, *sfsb, *sfsmaxblockcnt);
1181 }
1182 sb = *sfsb + (*sfsblockcnt);
1183 sb->block = key;
1184 sb->length = blocks;
1185 (*sfsblockcnt)++;
1186 return next;
1187 }
1188 } else {
1189 uae_u32 key = glx (p);
1190 uae_u32 data = glx (p + 4);
1191 int newblock = sfsfindblock (adf, data, theblock, sfsb, sfsblockcnt, sfsmaxblockcnt, sfs2);
1192 if (newblock)
1193 return newblock;
1194 if (!adf_read_block (adf, btree))
1195 return 0;
1196 if (memcmp (adf->block, "BNDC", 4))
1197 return 0;
1198 }
1199 p += nodesize;
1200 }
1201 return 0;
1202 }
1203
1204
archive_access_adf(struct znode * zn)1205 static struct zfile *archive_access_adf (struct znode *zn)
1206 {
1207 struct zfile *z = NULL;
1208 int root, ffs;
1209 struct adfhandle *adf = (struct adfhandle*)zn->volume->handle;
1210 int size, bs;
1211 int i;
1212 uae_u8 *dst;
1213
1214 size = zn->size;
1215 bs = adf->blocksize;
1216 z = zfile_fopen_empty (zn->volume->archive, zn->fullname, size);
1217 if (!z)
1218 return NULL;
1219
1220 if ((adf->dostype & 0xffffff00) == 0x444f5300 /* 'DOS' */) {
1221
1222 ffs = adf->dostype & 1;
1223 root = zn->offset;
1224 dst = z->data;
1225 for (;;) {
1226 adf_read_block (adf, root);
1227 for (i = bs / 4 - 51; i >= 6; i--) {
1228 int bsize = ffs ? bs : bs - 24;
1229 int block = gl (adf, i * 4);
1230 if (size < bsize)
1231 bsize = size;
1232 if (ffs)
1233 zfile_fseek (adf->z, block * adf->blocksize, SEEK_SET);
1234 else
1235 zfile_fseek (adf->z, block * adf->blocksize + 24, SEEK_SET);
1236 zfile_fread (dst, bsize, 1, adf->z);
1237 size -= bsize;
1238 dst += bsize;
1239 if (size <= 0)
1240 break;
1241 }
1242 if (size <= 0)
1243 break;
1244 root = gl (adf, bs - 2 * 4);
1245 }
1246 } else if ((adf->dostype & 0xffffff00) == 0x53465300 /* 'SFS' */) {
1247
1248 struct sfsblock *sfsblocks;
1249 int sfsblockcnt, sfsmaxblockcnt, i;
1250 int bsize;
1251 int block = zn->offset;
1252 int dblock;
1253 int btree, version, sfs2;
1254 uae_u8 *p;
1255
1256 if (!adf_read_block (adf, 0))
1257 goto end;
1258 btree = glx (adf->block + 108);
1259 version = gwx (adf->block + 12);
1260 sfs2 = version > 3;
1261
1262 if (!adf_read_block (adf, block))
1263 goto end;
1264 p = adf->block + zn->offset2;
1265 dblock = glx (p + 12);
1266
1267 sfsblockcnt = 0;
1268 sfsmaxblockcnt = 0;
1269 sfsblocks = NULL;
1270 if (size > 0) {
1271 int nextblock = dblock;
1272 while (nextblock) {
1273 nextblock = sfsfindblock (adf, btree, nextblock, &sfsblocks, &sfsblockcnt, &sfsmaxblockcnt, sfs2);
1274 }
1275 }
1276
1277 bsize = 0;
1278 for (i = 0; i < sfsblockcnt; i++)
1279 bsize += sfsblocks[i].length * adf->blocksize;
1280 if (bsize < size)
1281 write_log (_T("SFS extracting error, %s size mismatch %d<%d\n"), z->name, bsize, size);
1282
1283 dst = z->data;
1284 block = zn->offset;
1285 for (i = 0; i < sfsblockcnt; i++) {
1286 block = sfsblocks[i].block;
1287 bsize = sfsblocks[i].length * adf->blocksize;
1288 zfile_fseek (adf->z, block * adf->blocksize, SEEK_SET);
1289 if (bsize > size)
1290 bsize = size;
1291 zfile_fread (dst, bsize, 1, adf->z);
1292 dst += bsize;
1293 size -= bsize;
1294 }
1295
1296 xfree (sfsblocks);
1297 }
1298 return z;
1299 end:
1300 zfile_fclose (z);
1301 return NULL;
1302 }
1303
archive_close_adf(void * v)1304 static void archive_close_adf (void *v)
1305 {
1306 struct adfhandle *adf = (struct adfhandle*)v;
1307 xfree (adf);
1308 }
1309
rl(uae_u8 * p)1310 static int rl (uae_u8 *p)
1311 {
1312 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
1313 }
tochar(uae_u8 * s,int len)1314 static TCHAR *tochar (uae_u8 *s, int len)
1315 {
1316 int i, j;
1317 uae_char tmp[256];
1318 j = 0;
1319 for (i = 0; i < len; i++) {
1320 uae_char c = *s++;
1321 if (c >= 0 && c <= 9) {
1322 tmp[j++] = FSDB_DIR_SEPARATOR;
1323 tmp[j++] = '0' + c;
1324 } else if (c < ' ' || c > 'z') {
1325 tmp[j++] = '.';
1326 } else {
1327 tmp[j++] = c;
1328 }
1329 tmp[j] = 0;
1330 }
1331 return au (tmp);
1332 }
1333
archive_directory_rdb(struct zfile * z)1334 struct zvolume *archive_directory_rdb (struct zfile *z)
1335 {
1336 uae_u8 buf[512] = { 0 };
1337 int partnum, bs;
1338 TCHAR *devname;
1339 struct zvolume *zv;
1340 struct zarchive_info zai;
1341 uae_u8 *p;
1342 struct znode *zn;
1343
1344 zv = zvolume_alloc (z, ArchiveFormatRDB, NULL, NULL);
1345
1346 zfile_fseek (z, 0, SEEK_SET);
1347 zfile_fread (buf, 1, 512, z);
1348
1349 partnum = 0;
1350 for (;;) {
1351 int partblock;
1352 TCHAR tmp[MAX_DPATH];
1353 int surf, spt, spb, lowcyl, highcyl, reserved;
1354 int size, block, blocksize, rootblock;
1355 TCHAR comment[81], *dos;
1356
1357 if (partnum == 0)
1358 partblock = rl (buf + 28);
1359 else
1360 partblock = rl (buf + 4 * 4);
1361 partnum++;
1362 if (partblock <= 0)
1363 break;
1364 zfile_fseek (z, partblock * 512, SEEK_SET);
1365 zfile_fread (buf, 1, 512, z);
1366 if (memcmp (buf, "PART", 4))
1367 break;
1368
1369 p = buf + 128 - 16;
1370 surf = rl (p + 28);
1371 spb = rl (p + 32);
1372 spt = rl (p + 36);
1373 reserved = rl (p + 40);
1374 lowcyl = rl (p + 52);
1375 highcyl = rl (p + 56);
1376 blocksize = rl (p + 20) * 4 * spb;
1377 block = lowcyl * surf * spt;
1378
1379 size = (highcyl - lowcyl + 1) * surf * spt;
1380 size *= blocksize;
1381
1382 dos = tochar (buf + 192, 4);
1383
1384 if (!memcmp (dos, _T("DOS"), 3))
1385 rootblock = ((size / blocksize) - 1 + 2) / 2;
1386 else
1387 rootblock = 0;
1388
1389 devname = getBSTR (buf + 36);
1390 _stprintf (tmp, _T("%s.hdf"), devname);
1391 memset (&zai, 0, sizeof zai);
1392 _stprintf (comment, _T("FS=%s LO=%d HI=%d HEADS=%d SPT=%d RES=%d BLOCK=%d ROOT=%d"),
1393 dos, lowcyl, highcyl, surf, spt, reserved, blocksize, rootblock);
1394 zai.comment = comment;
1395 xfree (dos);
1396 zai.name = tmp;
1397 zai.size = size;
1398 zai.flags = -1;
1399 zn = zvolume_addfile_abs (zv, &zai);
1400 zn->offset = partblock;
1401 zn->offset2 = blocksize; // abuse of offset2..
1402 }
1403
1404 zfile_fseek (z, 0, SEEK_SET);
1405 p = buf;
1406 zfile_fread (buf, 1, 512, z);
1407 zai.name = _T("rdb_dump.dat");
1408 bs = rl (p + 16);
1409 zai.size = rl (p + 140) * bs;
1410 zai.comment = NULL;
1411 zn = zvolume_addfile_abs (zv, &zai);
1412 zn->offset = 0;
1413
1414 zv->method = ArchiveFormatRDB;
1415 return zv;
1416 }
1417
archive_access_rdb(struct znode * zn)1418 static struct zfile *archive_access_rdb (struct znode *zn)
1419 {
1420 struct zfile *z = zn->volume->archive;
1421 struct zfile *zf;
1422 uae_u8 buf[512] = { 0 };
1423 int surf, spb, spt, lowcyl, highcyl;
1424 int size, block, blocksize;
1425 uae_u8 *p;
1426
1427 if (zn->offset) {
1428 zfile_fseek (z, zn->offset * 512, SEEK_SET);
1429 zfile_fread (buf, 1, 512, z);
1430
1431 p = buf + 128 - 16;
1432 surf = rl (p + 28);
1433 spb = rl (p + 32);
1434 spt = rl (p + 36);
1435 lowcyl = rl (p + 52);
1436 highcyl = rl (p + 56);
1437 blocksize = rl (p + 20) * 4;
1438 block = lowcyl * surf * spt;
1439
1440 size = (highcyl - lowcyl + 1) * surf * spt;
1441 size *= blocksize;
1442 } else {
1443 zfile_fseek (z, 0, SEEK_SET);
1444 zfile_fread (buf, 1, 512, z);
1445 p = buf;
1446 blocksize = rl (p + 16);
1447 block = 0;
1448 size = zn->size;
1449 }
1450
1451 zf = zfile_fopen_parent (z, zn->fullname, block * blocksize, size);
1452 return zf;
1453 }
1454
isfat(uae_u8 * p)1455 int isfat (uae_u8 *p)
1456 {
1457 int i, b;
1458
1459 if ((p[0x15] & 0xf0) != 0xf0)
1460 return 0;
1461 if (p[0x0b] != 0x00 || p[0x0c] != 0x02)
1462 return 0;
1463 b = 0;
1464 for (i = 0; i < 8; i++) {
1465 if (p[0x0d] & (1 << i))
1466 b++;
1467 }
1468 if (b != 1)
1469 return 0;
1470 if (p[0x0f] != 0)
1471 return 0;
1472 if (p[0x0e] > 8 || p[0x0e] == 0)
1473 return 0;
1474 if (p[0x10] == 0 || p[0x10] > 8)
1475 return 0;
1476 b = (p[0x12] << 8) | p[0x11];
1477 if (b > 8192 || b <= 0)
1478 return 0;
1479 b = p[0x16] | (p[0x17] << 8);
1480 if (b == 0 || b > 8192)
1481 return 0;
1482 return 1;
1483 }
1484
1485 /*
1486 * The epoch of FAT timestamp is 1980.
1487 * : bits : value
1488 * date: 0 - 4: day (1 - 31)
1489 * date: 5 - 8: month (1 - 12)
1490 * date: 9 - 15: year (0 - 127) from 1980
1491 * time: 0 - 4: sec (0 - 29) 2sec counts
1492 * time: 5 - 10: min (0 - 59)
1493 * time: 11 - 15: hour (0 - 23)
1494 */
1495 #define SECS_PER_MIN 60
1496 #define SECS_PER_HOUR (60 * 60)
1497 #define SECS_PER_DAY (SECS_PER_HOUR * 24)
1498 #define UNIX_SECS_1980 315532800L
1499 #if BITS_PER_LONG == 64
1500 #define UNIX_SECS_2108 4354819200L
1501 #endif
1502 /* days between 1.1.70 and 1.1.80 (2 leap days) */
1503 #define DAYS_DELTA (365 * 10 + 2)
1504 /* 120 (2100 - 1980) isn't leap year */
1505 #define YEAR_2100 120
1506 #define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100)
1507
1508 /* Linear day numbers of the respective 1sts in non-leap years. */
1509 static time_t days_in_year[] = {
1510 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1511 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
1512 };
1513
1514 /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
fat_time_fat2unix(uae_u16 time,uae_u16 date,int fat12)1515 static time_t fat_time_fat2unix (uae_u16 time, uae_u16 date, int fat12)
1516 {
1517 time_t second, day, leap_day, month, year;
1518
1519 if (0 && fat12) {
1520 year = date & 0x7f;
1521 month = (date >> 7) & 0x0f;
1522 day = (date >> 11);
1523 } else {
1524 year = date >> 9;
1525 month = max(1, (date >> 5) & 0xf);
1526 day = max(1, date & 0x1f) - 1;
1527 }
1528
1529 leap_day = (year + 3) / 4;
1530 if (year > YEAR_2100) /* 2100 isn't leap year */
1531 leap_day--;
1532 if (IS_LEAP_YEAR(year) && month > 2)
1533 leap_day++;
1534
1535 second = (time & 0x1f) << 1;
1536 second += ((time >> 5) & 0x3f) * SECS_PER_MIN;
1537 second += (time >> 11) * SECS_PER_HOUR;
1538 second += (year * 365 + leap_day
1539 + days_in_year[month] + day
1540 + DAYS_DELTA) * SECS_PER_DAY;
1541 return second;
1542 }
1543
getcluster(struct zfile * z,int cluster,int fatstart,int fatbits)1544 static int getcluster (struct zfile *z, int cluster, int fatstart, int fatbits)
1545 {
1546 uae_u32 fat = 0;
1547 uae_u8 p[4];
1548 int offset = cluster * fatbits;
1549 zfile_fseek (z, fatstart * 512 + offset / 8, SEEK_SET);
1550 if (fatbits == 12) {
1551 zfile_fread (p, 2, 1, z);
1552 if ((offset & 4))
1553 fat = ((p[0] & 0xf0) >> 4) | (p[1] << 4);
1554 else
1555 fat = (p[0]) | ((p[1] & 0x0f) << 8);
1556 if (fat >= 0xff0)
1557 return -1;
1558 } else if (fatbits == 16) {
1559 zfile_fread (p, 2, 1, z);
1560 fat = p[0] | (p[1] << 8);
1561 if (fat >= 0xfff0)
1562 return -1;
1563 } else if (fatbits == 32) {
1564 zfile_fread (p, 4, 1, z);
1565 fat = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
1566 fat &= ~0x0fffffff;
1567 if (fat >= 0x0ffffff0)
1568 return -1;
1569 }
1570 return fat;
1571 }
1572
fatdirectory(struct zfile * z,struct zvolume * zv,TCHAR * name,int startblock,int entries,int sectorspercluster,int fatstart,int dataregion,int fatbits)1573 static void fatdirectory (struct zfile *z, struct zvolume *zv, TCHAR *name, int startblock, int entries, int sectorspercluster, int fatstart, int dataregion, int fatbits)
1574 {
1575 struct zarchive_info zai;
1576 struct znode *znnew;
1577 int i, j;
1578
1579 for (i = 0; i < entries; i++) {
1580 TCHAR name2[MAX_DPATH], *fname;
1581 uae_s64 size;
1582 uae_u8 fatname[16];
1583 uae_u8 buf[32];
1584 int attr, cnt, ext;
1585 int startcluster;
1586
1587 memset (buf, 0, sizeof buf);
1588 memset (&zai, 0, sizeof zai);
1589 zfile_fseek (z, startblock * 512 + i * 32, SEEK_SET);
1590 zfile_fread (buf, 32, 1, z);
1591 if (buf[0] == 0)
1592 break;
1593 if (buf[0] == 0xe5)
1594 continue;
1595 if (buf[0] == 0x05)
1596 buf[0] = 0xe5;
1597 size = buf[0x1c] | (buf[0x1d] << 8) | (buf[0x1e] << 16) | (buf[0x1f] << 24);
1598 attr = buf[0x0b];
1599 startcluster = buf[0x1a] | (buf[0x1b] << 8);
1600 if ((attr & (0x4 | 0x2)) == 0x06) // system+hidden
1601 continue;
1602 if (attr & 8) // disk name
1603 continue;
1604 if (attr & 1) // read-only
1605 zai.flags |= 1 << 3;
1606 if (!(attr & 32)) // archive
1607 zai.flags |= 1 << 4;
1608
1609 cnt = 0;
1610 ext = 0;
1611 for (j = 0; j < 8 && buf[j] != 0x20 && buf[j] != 0; j++)
1612 fatname[cnt++] = buf[j];
1613 for (j = 0; j < 3 && buf[8 + j] != 0x20 && buf[8 + j] != 0; j++) {
1614 if (ext == 0)
1615 fatname[cnt++] = '.';
1616 ext = 1;
1617 fatname[cnt++] = buf[8 + j];
1618 }
1619 fatname[cnt] = 0;
1620
1621 fname = au ((char*)fatname);
1622 name2[0] = 0;
1623 if (name[0]) {
1624 TCHAR sep[] = { FSDB_DIR_SEPARATOR, 0 };
1625 _tcscpy (name2, name);
1626 _tcscat (name2, sep);
1627 }
1628 _tcscat (name2, fname);
1629
1630 zai.name = name2;
1631 zai.tv.tv_sec = fat_time_fat2unix (buf[0x16] | (buf[0x17] << 8), buf[0x18] | (buf[0x19] << 8), 1);
1632 if (attr & (16 | 8)) {
1633 int nextblock, cluster;
1634 nextblock = dataregion + (startcluster - 2) * sectorspercluster;
1635 cluster = getcluster (z, startcluster, fatstart, fatbits);
1636 if ((cluster < 0 || cluster >= 3) && nextblock != startblock) {
1637 znnew = zvolume_adddir_abs (zv, &zai);
1638 fatdirectory (z, zv, name2, nextblock, sectorspercluster * 512 / 32, sectorspercluster, fatstart, dataregion, fatbits);
1639 while (cluster >= 3) {
1640 nextblock = dataregion + (cluster - 2) * sectorspercluster;
1641 fatdirectory (z, zv, name2, nextblock, sectorspercluster * 512 / 32, sectorspercluster, fatstart, dataregion, fatbits);
1642 cluster = getcluster (z, cluster, fatstart, fatbits);
1643 }
1644 }
1645 } else {
1646 zai.size = size;
1647 znnew = zvolume_addfile_abs (zv, &zai);
1648 znnew->offset = startcluster;
1649 }
1650
1651 xfree (fname);
1652 }
1653 }
1654
archive_directory_fat(struct zfile * z)1655 struct zvolume *archive_directory_fat (struct zfile *z)
1656 {
1657 uae_u8 buf[512] = { 0 };
1658 int fatbits = 12;
1659 struct zvolume *zv;
1660 int rootdir, reserved, sectorspercluster;
1661 int numfats, sectorsperfat, rootentries;
1662 int dataregion;
1663
1664 zfile_fseek (z, 0, SEEK_SET);
1665 zfile_fread (buf, 1, 512, z);
1666
1667 if (!isfat (buf))
1668 return NULL;
1669 reserved = buf[0x0e] | (buf[0x0f] << 8);
1670 numfats = buf[0x10];
1671 sectorsperfat = buf[0x16] | (buf[0x17] << 8);
1672 rootentries = buf[0x11] | (buf[0x12] << 8);
1673 sectorspercluster = buf[0x0d];
1674 rootdir = reserved + numfats * sectorsperfat;
1675 dataregion = rootdir + rootentries * 32 / 512;
1676
1677 zv = zvolume_alloc (z, ArchiveFormatFAT, NULL, NULL);
1678 fatdirectory (z, zv, _T(""), rootdir, rootentries, sectorspercluster, reserved, dataregion, fatbits);
1679 zv->method = ArchiveFormatFAT;
1680 return zv;
1681 }
1682
archive_access_fat(struct znode * zn)1683 static struct zfile *archive_access_fat (struct znode *zn)
1684 {
1685 uae_u8 buf[512] = { 0 };
1686 int fatbits = 12;
1687 int size = zn->size;
1688 struct zfile *sz, *dz;
1689 int rootdir, reserved, sectorspercluster;
1690 int numfats, sectorsperfat, rootentries;
1691 int dataregion;
1692 int offset, cluster;
1693
1694 sz = zn->volume->archive;
1695
1696 zfile_fseek (sz, 0, SEEK_SET);
1697 zfile_fread (buf, 1, 512, sz);
1698
1699 if (!isfat (buf))
1700 return NULL;
1701 reserved = buf[0x0e] | (buf[0x0f] << 8);
1702 numfats = buf[0x10];
1703 sectorsperfat = buf[0x16] | (buf[0x17] << 8);
1704 rootentries = buf[0x11] | (buf[0x12] << 8);
1705 sectorspercluster = buf[0x0d];
1706 rootdir = reserved + numfats * sectorsperfat;
1707 dataregion = rootdir + rootentries * 32 / 512;
1708
1709 dz = zfile_fopen_empty (sz, zn->fullname, size);
1710 if (!dz)
1711 return NULL;
1712
1713 offset = 0;
1714 cluster = zn->offset;
1715 while (size && cluster >= 2) {
1716 int left = size > sectorspercluster * 512 ? sectorspercluster * 512 : size;
1717 int sector = dataregion + (cluster - 2) * sectorspercluster;
1718 zfile_fseek (sz, sector * 512, SEEK_SET);
1719 zfile_fread (dz->data + offset, 1, left, sz);
1720 size -= left;
1721 offset += left;
1722 cluster = getcluster (sz, cluster, reserved, fatbits);
1723 }
1724
1725 return dz;
1726 }
1727
archive_access_close(void * handle,unsigned int id)1728 void archive_access_close (void *handle, unsigned int id)
1729 {
1730 switch (id)
1731 {
1732 #ifdef A_ZIP
1733 case ArchiveFormatZIP:
1734 archive_close_zip (handle);
1735 break;
1736 #endif
1737 #ifdef A_7Z
1738 // case ArchiveFormat7Zip:
1739 // archive_close_7z (handle);
1740 // break;
1741 #endif
1742 #ifdef A_RAR
1743 // case ArchiveFormatRAR:
1744 // archive_close_rar (handle);
1745 // break;
1746 #endif
1747 #ifdef A_LHA
1748 case ArchiveFormatLHA:
1749 break;
1750 #endif
1751 case ArchiveFormatADF:
1752 archive_close_adf (handle);
1753 break;
1754 case ArchiveFormatTAR:
1755 archive_close_tar (handle);
1756 break;
1757 }
1758 }
1759
archive_access_dir(struct znode * zn)1760 static struct zfile *archive_access_dir (struct znode *zn)
1761 {
1762 return zfile_fopen (zn->fullname, _T("rb"), 0);
1763 }
1764
1765
archive_unpackzfile(struct zfile * zf)1766 struct zfile *archive_unpackzfile (struct zfile *zf)
1767 {
1768 #ifdef A_ZIP
1769 struct zfile *zout = NULL;
1770 #endif
1771 if (!zf->archiveparent)
1772 return NULL;
1773 unpack_log (_T("delayed unpack '%s'\n"), zf->name);
1774 zf->datasize = zf->size;
1775 switch (zf->archiveid)
1776 {
1777 #ifdef A_ZIP
1778 case ArchiveFormatZIP:
1779 zout = archive_unpack_zip (zf);
1780 break;
1781 #endif
1782 }
1783 zfile_fclose (zf->archiveparent);
1784 zf->archiveparent = NULL;
1785 zf->archiveid = 0;
1786 return NULL;
1787 }
1788
archive_getzfile(struct znode * zn,unsigned int id,int flags)1789 struct zfile *archive_getzfile (struct znode *zn, unsigned int id, int flags)
1790 {
1791 struct zfile *zf = NULL;
1792
1793 switch (id)
1794 {
1795 #ifdef A_ZIP
1796 case ArchiveFormatZIP:
1797 zf = archive_access_zip (zn, flags);
1798 break;
1799 #endif
1800 #ifdef A_7Z
1801 // case ArchiveFormat7Zip:
1802 // zf = archive_access_7z (zn);
1803 // break;
1804 #endif
1805 #ifdef A_RAR
1806 // case ArchiveFormatRAR:
1807 // zf = archive_access_rar (zn);
1808 // break;
1809 #endif
1810 #ifdef A_LHA
1811 // case ArchiveFormatLHA:
1812 // zf = archive_access_lha (zn);
1813 // break;
1814 #endif
1815 #ifdef A_LZX
1816 // case ArchiveFormatLZX:
1817 // zf = archive_access_lzx (zn);
1818 // break;
1819 #endif
1820 case ArchiveFormatPLAIN:
1821 zf = archive_access_plain (zn);
1822 break;
1823 case ArchiveFormatADF:
1824 zf = archive_access_adf (zn);
1825 break;
1826 case ArchiveFormatRDB:
1827 zf = archive_access_rdb (zn);
1828 break;
1829 case ArchiveFormatFAT:
1830 zf = archive_access_fat (zn);
1831 break;
1832 case ArchiveFormatDIR:
1833 zf = archive_access_dir (zn);
1834 break;
1835 case ArchiveFormatTAR:
1836 zf = archive_access_tar (zn);
1837 break;
1838 }
1839 if (zf)
1840 zf->archiveid = id;
1841 return zf;
1842 }
1843