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