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