1 /*
2  * UAE - The Un*x Amiga Emulator
3  *
4  * Unix file system handler for AmigaDOS
5  *
6  * Copyright 1996 Ed Hanway
7  * Copyright 1996, 1997 Bernd Schmidt
8  *
9  * Version 0.4: 970308
10  *
11  * Based on example code (c) 1988 The Software Distillery
12  * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
13  * (May - August 1989)
14  *
15  * Known limitations:
16  * Does not support several (useless) 2.0+ packet types.
17  * May not return the correct error code in some cases.
18  * Does not check for sane values passed by AmigaDOS.  May crash the emulation
19  * if passed garbage values.
20  * Could do tighter checks on malloc return values.
21  * Will probably fail spectacularly in some cases if the filesystem is
22  * modified at the same time by another process while UAE is running.
23  */
24 
25 #include "sysconfig.h"
26 #include "sysdeps.h"
27 
28 #include "threaddep/thread.h"
29 #include "options.h"
30 #include "uae.h"
31 #include "misc.h"
32 #include "memory_uae.h"
33 #include "custom.h"
34 #include "events.h"
35 #include "newcpu.h"
36 #include "filesys.h"
37 #include "autoconf.h"
38 #include "traps.h"
39 #include "fsusage.h"
40 #include "native2amiga.h"
41 #include "scsidev.h"
42 #include "fsdb.h"
43 #include "zfile.h"
44 #include "gui.h"
45 #include "gayle.h"
46 #include "savestate.h"
47 #include "a2091.h"
48 #include "cdtv.h"
49 #include "sana2.h"
50 #include "bsdsocket.h"
51 #include "uaeresource.h"
52 #include "inputdevice.h"
53 #include "clipboard.h"
54 #include "consolehook.h"
55 #include "blkdev.h"
56 #include "isofs_api.h"
57 
58 #ifdef VITA
59 #include <psp2/types.h>
60 #include <psp2/io/dirent.h>
61 #include <psp2/kernel/threadmgr.h>
62 #define mkdir(name,mode) sceIoMkdir(name, 0777)
63 #endif
64 
65 #ifdef TARGET_AMIGAOS
66 #include <dos/dos.h>
67 #include <proto/dos.h>
68 #endif
69 
70 #define TRACING_ENABLED 1
71 int log_filesys = 0;
72 
73 #if TRACING_ENABLED
74 #if 0
75 #define TRACE(x) if (log_filesys > 0 && (unit->volflags & MYVOLUMEINFO_CDFS)) { write_log x; }
76 #else
77 #define TRACE(x) if (log_filesys > 0) { write_log x; }
78 #endif
79 #define TRACEI(x) if (log_filesys > 0) { write_log x; }
80 #define TRACE2(x) if (log_filesys >= 2) { write_log x; }
81 #define TRACE3(x) if (log_filesys >= 3) { write_log x; }
82 #define DUMPLOCK(u,x) dumplock(u,x)
83 #else
84 #define TRACE(x)
85 #define DUMPLOCK(u,x)
86 #define TRACE2(x)
87 #define TRACE3(x)
88 #endif
89 
90 #define UNIT_LED(unit) ((unit)->ui.unit_type == UNIT_CDFS ? LED_CD : LED_HD)
91 
92 #define RTAREA_HEARTBEAT 0xFFFC
93 
94 static uae_sem_t test_sem;
95 
96 static int bootrom_header;
97 
dlg(uae_u32 a)98 static uae_u32 dlg (uae_u32 a)
99 {
100 	return (dbg (a + 0) << 24) | (dbg (a + 1) << 16) | (dbg (a + 2) << 8) | (dbg (a + 3) << 0);
101 }
102 
aino_test(a_inode * aino)103 static void aino_test (a_inode *aino)
104 {
105 #ifdef AINO_DEBUG
106 	a_inode *aino2 = aino, *aino3;
107 	for (;;) {
108 		if (!aino || !aino->next)
109 			return;
110 		if ((aino->checksum1 ^ aino->checksum2) != 0xaaaa5555) {
111 			write_log (_T("PANIC: corrupted or freed but used aino detected!"), aino);
112 		}
113 		aino3 = aino;
114 		aino = aino->next;
115 		if (aino->prev != aino3) {
116 			write_log (_T("PANIC: corrupted aino linking!\n"));
117 			break;
118 		}
119 		if (aino == aino2) break;
120 	}
121 #endif
122 }
123 
aino_test_init(a_inode * aino)124 static void aino_test_init (a_inode *aino)
125 {
126 #ifdef AINO_DEBUG
127 	aino->checksum1 = (uae_u32)aino;
128 	aino->checksum2 = aino->checksum1 ^ 0xaaaa5555;
129 #endif
130 }
131 
132 
133 uaecptr filesys_initcode;
134 static uae_u32 fsdevname, fshandlername, filesys_configdev;
135 static uae_u32 cdfs_devname, cdfs_handlername;
136 static int filesys_in_interrupt;
137 static uae_u32 mountertask;
138 static int automountunit = -1;
139 static int cd_unit_offset, cd_unit_number;
140 
141 #define FS_STARTUP 0
142 #define FS_GO_DOWN 1
143 
144 #define DEVNAMES_PER_HDF 32
145 
146 #define UNIT_FILESYSTEM 0
147 #define UNIT_CDFS 1
148 
149 typedef struct {
150 	int unit_type;
151 	bool open;
152 	TCHAR *devname; /* device name, e.g. UAE0: */
153 	uaecptr devname_amiga;
154 	uaecptr startup;
155 	uaecptr devicenode;
156 	TCHAR *volname; /* volume name, e.g. CDROM, WORK, etc. */
157 	int volflags; /* volume flags, readonly, stream uaefsdb support */
158 	TCHAR *rootdir; /* root native directory/hdf. empty drive if invalid path */
159 	struct zvolume *zarchive;
160 	TCHAR *rootdirdiff; /* "diff" file/directory */
161 	bool readonly; /* disallow write access? */
162 	bool locked; /* action write protect */
163 	bool unknown_media; /* ID_UNREADABLE_DISK */
164 	int bootpri; /* boot priority. -128 = no autoboot, -129 = no mount */
165 	int devno;
166 	int controller;
167 	bool wasisempty; /* if true, this unit was created empty */
168 	bool canremove; /* if true, this unit can be safely ejected and remounted */
169 	bool configureddrive; /* if true, this is drive that was manually configured */
170 
171 	struct hardfiledata hf;
172 
173 	/* Threading stuff */
174 	smp_comm_pipe *volatile unit_pipe, *volatile back_pipe;
175 	uae_thread_id tid;
176 	struct _unit *self;
177 	/* Reset handling */
178 	uae_sem_t reset_sync_sem;
179 	volatile int reset_state;
180 
181 	/* RDB stuff */
182 	uaecptr rdb_devname_amiga[DEVNAMES_PER_HDF];
183 	int rdb_lowcyl;
184 	int rdb_highcyl;
185 	int rdb_cylblocks;
186 	uae_u8 *rdb_filesysstore;
187 	int rdb_filesyssize;
188 	TCHAR *filesysdir;
189 	/* filesystem seglist */
190 	uaecptr filesysseg;
191 
192 	/* CDFS */
193 	bool cd_open;
194 	int cddevno;
195 	void *cdfs_superblock;
196 
197 } UnitInfo;
198 
199 struct uaedev_mount_info {
200 	UnitInfo ui[MAX_FILESYSTEM_UNITS];
201 };
202 
203 static struct uaedev_mount_info mountinfo;
204 
nr_units(void)205 int nr_units (void)
206 {
207 	int i, cnt = 0;
208 	for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
209 		if (mountinfo.ui[i].open)
210 			cnt++;
211 	}
212 	return cnt;
213 }
214 
nr_directory_units(struct uae_prefs * p)215 int nr_directory_units (struct uae_prefs *p)
216 {
217 	int i, cnt = 0;
218 	if (p) {
219 		for (i = 0; i < p->mountitems; i++) {
220 			if (p->mountconfig[i].ci.controller == 0)
221 				cnt++;
222 		}
223 	} else {
224 		for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
225 			if (mountinfo.ui[i].open && mountinfo.ui[i].controller == 0)
226 				cnt++;
227 		}
228 	}
229 	return cnt;
230 }
231 
is_virtual(int unit_no)232 static int is_virtual (int unit_no)
233 {
234 	int t = is_hardfile (unit_no);
235 	return t == FILESYS_VIRTUAL || t == FILESYS_CD;
236 }
237 
is_hardfile(int unit_no)238 int is_hardfile (int unit_no)
239 {
240 	if (mountinfo.ui[unit_no].volname || mountinfo.ui[unit_no].wasisempty || mountinfo.ui[unit_no].unknown_media) {
241 		if (unit_no >= cd_unit_offset && unit_no < cd_unit_offset + cd_unit_number)
242 			return FILESYS_CD;
243 		return FILESYS_VIRTUAL;
244 	}
245 	if (mountinfo.ui[unit_no].hf.ci.sectors == 0) {
246 		if (mountinfo.ui[unit_no].hf.flags & 1)
247 			return FILESYS_HARDDRIVE;
248 		return FILESYS_HARDFILE_RDB;
249 	}
250 	return FILESYS_HARDFILE;
251 }
252 
close_filesys_unit(UnitInfo * uip)253 static void close_filesys_unit (UnitInfo *uip)
254 {
255 	if (!uip->open)
256 		return;
257 	if (uip->hf.handle_valid)
258 		hdf_close (&uip->hf);
259 	if (uip->volname != 0)
260 		xfree (uip->volname);
261 	if (uip->devname != 0)
262 		xfree (uip->devname);
263 	if (uip->rootdir != 0)
264 		xfree (uip->rootdir);
265 	if (uip->unit_pipe)
266 		xfree (uip->unit_pipe);
267 	if (uip->back_pipe)
268 		xfree (uip->back_pipe);
269 	if (uip->cd_open) {
270 #ifdef SCSI
271 		sys_command_close (uip->cddevno);
272 		isofs_unmount (uip->cdfs_superblock);
273 #endif
274 	}
275 
276 	uip->unit_pipe = 0;
277 	uip->back_pipe = 0;
278 
279 	uip->hf.handle_valid = 0;
280 	uip->volname = 0;
281 	uip->devname = 0;
282 	uip->rootdir = 0;
283 	uip->open = 0;
284 	uip->cd_open = 0;
285 }
286 
getuci(struct uaedev_config_data * uci,int nr)287 static struct uaedev_config_data *getuci (struct uaedev_config_data *uci, int nr)
288 {
289 	return &uci[nr];
290 }
291 
292 
getuip(struct uae_prefs * p,int index)293 static UnitInfo *getuip (struct uae_prefs *p, int index)
294 {
295 	if (index < 0)
296 		return NULL;
297 	index = p->mountconfig[index].configoffset;
298 	if (index < 0)
299 		return NULL;
300 	return &mountinfo.ui[index];
301 }
302 
get_filesys_unitconfig(struct uae_prefs * p,int index,struct mountedinfo * mi)303 int get_filesys_unitconfig (struct uae_prefs *p, int index, struct mountedinfo *mi)
304 {
305 	UnitInfo *ui = getuip(p, index);
306 	struct uaedev_config_data *uci = &p->mountconfig[index];
307 	UnitInfo uitmp;
308 
309 	memset (mi, 0, sizeof (struct mountedinfo));
310 	memset (&uitmp, 0, sizeof uitmp);
311 	_tcscpy (mi->rootdir, uci->ci.rootdir);
312 	if (!ui) {
313 		ui = &uitmp;
314 		if (uci->ci.type == UAEDEV_DIR) {
315 			mi->ismounted = 1;
316 			if (uci->ci.rootdir && _tcslen (uci->ci.rootdir) == 0)
317 				return FILESYS_VIRTUAL;
318 			if (my_existsfile (uci->ci.rootdir)) {
319 				mi->ismedia = 1;
320 				return FILESYS_VIRTUAL;
321 			}
322 			if (my_getvolumeinfo (uci->ci.rootdir) < 0)
323 				return -1;
324 			mi->ismedia = true;
325 			return FILESYS_VIRTUAL;
326 		} else if (uci->ci.type == UAEDEV_HDF) {
327 			ui->hf.ci.readonly = true;
328 			ui->hf.ci.blocksize = uci->ci.blocksize;
329 			if (!hdf_open (&ui->hf, uci->ci.rootdir)) {
330 				mi->ismedia = false;
331 				mi->ismounted = true;
332 				if (uci->ci.reserved == 0 && uci->ci.sectors == 0 && uci->ci.surfaces == 0) {
333 					if (ui->hf.flags & 1)
334 						return FILESYS_HARDDRIVE;
335 					return FILESYS_HARDFILE_RDB;
336 				}
337 				return -1;
338 			}
339 			mi->ismedia = true;
340 			if (ui->hf.drive_empty)
341 				mi->ismedia = 0;
342 			hdf_close (&ui->hf);
343 		} else if (uci->ci.type == UAEDEV_CD) {
344 			struct device_info di;
345 			ui->hf.ci.readonly = true;
346 			ui->hf.ci.blocksize = uci->ci.blocksize;
347 			mi->size = -1;
348 			mi->ismounted = true;
349 #if !defined(ANDROID) && !defined(_WIN32) && !defined(__CELLOS_LV2__)
350 			if (blkdev_get_info (p, ui->hf.ci.cd_emu_unit, &di)) {
351 				mi->ismedia = di.media_inserted != 0;
352 				_tcscpy (mi->rootdir, di.label);
353 			}
354 #endif
355 #if 0
356 			if (ui->hf.ci.cd_emu_unit == 0)
357 				_tcscpy (mi->rootdir, _T("CD"));
358 			else
359 				_stprintf (mi->rootdir, _T("CD %d"), ui->hf.ci.cd_emu_unit);
360 #endif
361 		}
362 	} else {
363 		if (!ui->controller || (ui->controller && p->cs_ide)) {
364 			mi->ismounted = 1;
365 			if (uci->ci.type == UAEDEV_HDF)
366 				mi->ismedia = ui->hf.drive_empty ? false : true;
367 			else
368 				mi->ismedia = true;
369 		}
370 	}
371 	if (mi->size < 0)
372 		return -1;
373 	mi->size = ui->hf.virtsize;
374 	if (uci->ci.highcyl) {
375 		uci->ci.cyls = mi->nrcyls = uci->ci.highcyl;
376 	} else {
377 		uci->ci.cyls = mi->nrcyls = (int)(uci->ci.sectors * uci->ci.surfaces ? (ui->hf.virtsize / uci->ci.blocksize) / (uci->ci.sectors * uci->ci.surfaces) : 0);
378 	}
379 	if (uci->ci.type == UAEDEV_DIR)
380 		return FILESYS_VIRTUAL;
381 	if (uci->ci.reserved == 0 && uci->ci.sectors == 0 && uci->ci.surfaces == 0) {
382 		if (ui->hf.flags & 1)
383 			return FILESYS_HARDDRIVE;
384 		return FILESYS_HARDFILE_RDB;
385 	}
386 	return FILESYS_HARDFILE;
387 }
388 
stripsemicolon(TCHAR * s)389 static void stripsemicolon (TCHAR *s)
390 {
391 	if (!s)
392 		return;
393 	while (_tcslen(s) > 0 && s[_tcslen(s) - 1] == ':')
394 		s[_tcslen(s) - 1] = 0;
395 }
stripspace(TCHAR * s)396 static void stripspace (TCHAR *s)
397 {
398 	int i = 0;
399 	if (!s)
400 		return;
401 	for ( ; i < _tcslen (s); i++) {
402 		if (s[i] == ' ')
403 			s[i] = '_';
404 	}
405 }
striplength(TCHAR * s,int len)406 static void striplength (TCHAR *s, int len)
407 {
408 	if (!s)
409 		return;
410 	if ((int)_tcslen (s) <= len)
411 		return;
412 	s[len] = 0;
413 }
fixcharset(TCHAR * s)414 static void fixcharset (TCHAR *s)
415 {
416 	char tmp[MAX_DPATH];
417 	if (!s)
418 		return;
419 	//ua_fs_copy (tmp, MAX_DPATH, s, '_');
420 	strcpy (tmp, s);
421 	au_fs_copy (s, strlen (tmp) + 1, tmp);
422 }
423 
validatevolumename(TCHAR * s)424 TCHAR *validatevolumename (TCHAR *s)
425 {
426 	stripsemicolon (s);
427 	fixcharset (s);
428 	striplength (s, 30);
429 	return s;
430 }
validatedevicename(TCHAR * s)431 TCHAR *validatedevicename (TCHAR *s)
432 {
433 	stripsemicolon (s);
434 	stripspace (s);
435 	fixcharset (s);
436 	striplength (s, 30);
437 	return s;
438 }
439 
filesys_createvolname(const TCHAR * volname,const TCHAR * rootdir,const TCHAR * def)440 TCHAR *filesys_createvolname (const TCHAR *volname, const TCHAR *rootdir, const TCHAR *def)
441 {
442 	TCHAR *nvol = NULL;
443 	int i, archivehd;
444 	TCHAR *p = NULL;
445 
446 	archivehd = -1;
447 	if (my_existsfile (rootdir))
448 		archivehd = 1;
449 	else if (my_existsdir (rootdir))
450 		archivehd = 0;
451 
452 	if ((!volname || _tcslen (volname) == 0) && rootdir && archivehd >= 0) {
453 		p = my_strdup (rootdir);
454 		for (i = _tcslen (p) - 1; i >= 0; i--) {
455 			TCHAR c = p[i];
456 			if (c == ':' || c == '/' || c == '\\') {
457 				if (i == (int)_tcslen (p) - 1)
458 					continue;
459 				if (!_tcscmp (p + i, _T(":\\"))) {
460 					xfree (p);
461 					p = xmalloc (TCHAR, 10);
462 					p[0] = rootdir[0];
463 					p[1] = 0;
464 					i = 0;
465 				} else {
466 					i++;
467 				}
468 				break;
469 			}
470 		}
471 		if (i >= 0)
472 			nvol = my_strdup (p + i);
473 	}
474 	if (!nvol && archivehd >= 0) {
475 /* REMOVEME:
476  * nowhere used
477  */
478 #if 0
479 		TCHAR *s = NULL;
480 #endif
481 		if (volname && _tcslen (volname) > 0)
482 			nvol = my_strdup (volname);
483 		else
484 			nvol = my_strdup (def);
485 	}
486 	if (!nvol) {
487 		if (volname && _tcslen (volname))
488 			nvol = my_strdup (volname);
489 		else
490 			nvol = my_strdup (_T(""));
491 	}
492 	validatevolumename (nvol);
493 	xfree (p);
494 	return nvol;
495 }
496 
set_filesys_volume(const TCHAR * rootdir,int * flags,bool * readonly,bool * emptydrive,struct zvolume ** zvp)497 static int set_filesys_volume (const TCHAR *rootdir, int *flags, bool *readonly, bool *emptydrive, struct zvolume **zvp)
498 {
499 	*emptydrive = 0;
500 	if (my_existsfile (rootdir)) {
501 		struct zvolume *zv;
502 		zv = zfile_fopen_archive (rootdir);
503 		if (!zv) {
504 			write_log (_T("'%s' is not a supported archive file\n"), rootdir);
505 			return -1;
506 		}
507 		*zvp = zv;
508 		*flags = MYVOLUMEINFO_ARCHIVE;
509 		*readonly = 1;
510 	} else {
511 		*flags = my_getvolumeinfo (rootdir);
512 		if (*flags < 0) {
513 			if (rootdir && rootdir[0])
514 				write_log (_T("directory '%s' not found, mounting as empty drive\n"), rootdir);
515 			*emptydrive = 1;
516 			*flags = 0;
517 		} else if ((*flags) & MYVOLUMEINFO_READONLY) {
518 			write_log (_T("'%s' set to read-only\n"), rootdir);
519 			*readonly = 1;
520 		}
521 	}
522 	return 1;
523 }
524 
uci_set_defaults(struct uaedev_config_info * uci,bool rdb)525 void uci_set_defaults (struct uaedev_config_info *uci, bool rdb)
526 {
527 	memset (uci, 0, sizeof (struct uaedev_config_info));
528 	if (!rdb) {
529 		uci->sectors = 32;
530 		uci->reserved = 2;
531 		uci->surfaces = 1;
532 	}
533 	uci->blocksize = 512;
534 	uci->maxtransfer = 0x7fffffff;
535 	uci->mask = 0xffffffff;
536 	uci->bufmemtype = 1;
537 	uci->buffers = 50;
538 	uci->stacksize = 4000;
539 	uci->priority = -129;
540 	uci->sectorsperblock = 1;
541 	uci->cd_emu_unit = -1;
542 }
543 
set_filesys_unit_1(int nr,struct uaedev_config_info * ci)544 static int set_filesys_unit_1 (int nr, struct uaedev_config_info *ci)
545 {
546 	UnitInfo *ui;
547 	int i;
548 	bool emptydrive = false;
549 	bool iscd;
550 	struct uaedev_config_info c;
551 
552 	memcpy (&c, ci, sizeof (struct uaedev_config_info));
553 
554 	if (ci->controller)
555 		return -1;
556 	if (nr < 0) {
557 		for (nr = 0; nr < MAX_FILESYSTEM_UNITS; nr++) {
558 			if (!mountinfo.ui[nr].open)
559 				break;
560 		}
561 		if (nr == MAX_FILESYSTEM_UNITS) {
562 			write_log (_T("No slot allocated for this unit\n"));
563 			return -1;
564 		}
565 	}
566 
567 //	my_resolvesoftlink (c.rootdir, MAX_DPATH);
568 	iscd = nr >= cd_unit_offset && nr < cd_unit_offset + cd_unit_number;
569 
570 	for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
571 		if (nr == i || !mountinfo.ui[i].open || mountinfo.ui[i].rootdir == NULL || is_hardfile (i) == FILESYS_CD)
572 			continue;
573 		if (_tcslen (c.rootdir) > 0 && !_tcsicmp (mountinfo.ui[i].rootdir, c.rootdir)) {
574 			write_log (_T("directory/hardfile '%s' already added\n"), c.rootdir);
575 			return -1;
576 		}
577 	}
578 
579 	ui = &mountinfo.ui[nr];
580 	memset (ui, 0, sizeof (UnitInfo));
581 
582 	if (iscd) {
583 		ui->unit_type = UNIT_CDFS;
584 		emptydrive = 1;
585 		ui->volflags = MYVOLUMEINFO_CDFS | MYVOLUMEINFO_READONLY;
586 		c.readonly = true;
587 	} else if (c.volname[0]) {
588 		int flags = 0;
589 		emptydrive = 1;
590 		if (c.rootdir[0]) {
591 			if (set_filesys_volume (c.rootdir, &flags, &c.readonly, &emptydrive, &ui->zarchive) < 0)
592 				return -1;
593 		}
594 		ui->volname = filesys_createvolname (c.volname, c.rootdir, _T("harddrive"));
595 		ui->volflags = flags;
596 	} else {
597 		ui->unit_type = UNIT_FILESYSTEM;
598 		memcpy (&ui->hf.ci, &c, sizeof (struct uaedev_config_info));
599 		ui->hf.unitnum = nr;
600 		ui->volname = 0;
601 		if (ui->hf.ci.rootdir[0]) {
602 			if (!hdf_open (&ui->hf, NULL) && !c.readonly) {
603 			write_log (_T("Attempting to open in read-only mode\n"));
604 				ui->hf.ci.readonly = c.readonly = true;
605 				hdf_open (&ui->hf, NULL);
606 			}
607 		} else {
608 			// empty drive?
609 			ui->hf.drive_empty = 1;
610 		}
611 		if (!ui->hf.drive_empty) {
612 			if (ui->hf.handle_valid == 0) {
613 				write_log (_T("Hardfile %s not found\n"), ui->hf.device_name);
614 				goto err;
615 			}
616 			if ((uae_u64)(ui->hf.ci.blocksize) > ui->hf.virtsize || ui->hf.virtsize == 0) {
617 				write_log (_T("Hardfile %s too small\n"), ui->hf.device_name);
618 				goto err;
619 			}
620 		}
621 		if ((ui->hf.ci.blocksize & (ui->hf.ci.blocksize - 1)) != 0 || ui->hf.ci.blocksize == 0) {
622 			write_log (_T("Hardfile %s bad blocksize\n"), ui->hf.device_name);
623 				goto err;
624 			}
625 		if ((ui->hf.ci.sectors || ui->hf.ci.surfaces || ui->hf.ci.reserved) &&
626 			(ui->hf.ci.sectors < 1 || ui->hf.ci.surfaces < 1 || ui->hf.ci.surfaces > 1023 ||
627 			ui->hf.ci.reserved < 0 || ui->hf.ci.reserved > 1023) != 0) {
628 				write_log (_T("Hardfile %s bad hardfile geometry\n"), ui->hf.device_name);
629 				goto err;
630 		}
631 		if (!ui->hf.ci.highcyl) {
632 			ui->hf.ci.cyls = (int)(ui->hf.ci.sectors * ui->hf.ci.surfaces ? (ui->hf.virtsize / ui->hf.ci.blocksize) / (ui->hf.ci.sectors * ui->hf.ci.surfaces) : 0);
633 	}
634 		if (!ui->hf.ci.cyls)
635 			ui->hf.ci.cyls = ui->hf.ci.highcyl;
636 		if (!ui->hf.ci.cyls)
637 			ui->hf.ci.cyls = 1;
638 	}
639 	ui->self = 0;
640 	ui->reset_state = FS_STARTUP;
641 	ui->wasisempty = emptydrive;
642 	ui->canremove = emptydrive && (ci->flags & MYVOLUMEINFO_REUSABLE);
643 	ui->rootdir = my_strdup (c.rootdir);
644 	ui->devname = my_strdup (c.devname);
645 	stripsemicolon(ui->devname);
646 	if (c.filesys[0])
647 		ui->filesysdir = my_strdup (c.filesys);
648 	ui->readonly = c.readonly;
649 	if (c.bootpri < -129)
650 		c.bootpri = -129;
651 	if (c.bootpri > 127)
652 		c.bootpri = 127;
653 	ui->bootpri = c.bootpri;
654 	ui->open = 1;
655 
656 	return nr;
657 err:
658 	if (ui->hf.handle_valid)
659 		hdf_close (&ui->hf);
660 	return -1;
661 }
662 
set_filesys_unit(int nr,struct uaedev_config_info * ci)663 static int set_filesys_unit (int nr, struct uaedev_config_info *ci)
664 {
665 	int ret;
666 
667 	ret = set_filesys_unit_1 (nr, ci);
668 	return ret;
669 }
670 
add_filesys_unit(struct uaedev_config_info * ci)671 static int add_filesys_unit (struct uaedev_config_info *ci)
672 {
673 	int ret;
674 
675 	if (nr_units() >= MAX_FILESYSTEM_UNITS)
676 		return -1;
677 
678 	ret = set_filesys_unit_1 (-1, ci);
679 #ifdef RETROPLATFORM
680 	if (ret >= 0) {
681 		rp_hd_device_enable (ret, true);
682 		rp_harddrive_image_change (ret, ci->readonly, ci->rootdir);
683 	}
684 #endif
685 	return ret;
686 }
687 
kill_filesys_unitconfig(struct uae_prefs * p,int nr)688 int kill_filesys_unitconfig (struct uae_prefs *p, int nr)
689 {
690 	struct uaedev_config_data *uci;
691 
692 	if (nr < 0)
693 		return 0;
694 	uci = getuci (p->mountconfig, nr);
695 	hardfile_do_disk_change (uci, 0);
696 	if (uci->configoffset >= 0 && uci->ci.controller == 0)
697 		filesys_media_change (uci->ci.rootdir, 0, uci);
698 	while (nr < MOUNT_CONFIG_SIZE) {
699 		memmove (&p->mountconfig[nr], &p->mountconfig[nr + 1], sizeof (struct uaedev_config_data));
700 		nr++;
701 	}
702 	p->mountitems--;
703 	memset (&p->mountconfig[MOUNT_CONFIG_SIZE - 1], 0, sizeof (struct uaedev_config_data));
704 	return 1;
705 }
706 
move_filesys_unitconfig(struct uae_prefs * p,int nr,int to)707 int move_filesys_unitconfig (struct uae_prefs *p, int nr, int to)
708 {
709 	struct uaedev_config_data *uci1, *uci2, tmpuci;
710 
711 	uci1 = getuci (p->mountconfig, nr);
712 	uci2 = getuci (p->mountconfig, to);
713 	if (nr == to)
714 		return 0;
715 	memcpy (&tmpuci, uci1, sizeof (struct uaedev_config_data));
716 	memcpy (uci1, uci2, sizeof (struct uaedev_config_data));
717 	memcpy (uci2, &tmpuci, sizeof (struct uaedev_config_data));
718 	return 1;
719 }
720 
721 
filesys_addexternals(void)722 static void filesys_addexternals (void)
723 {
724 	/// FIXME : not implemented, yet
725 }
726 
allocuci(struct uae_prefs * p,int nr,int idx)727 static void allocuci (struct uae_prefs *p, int nr, int idx)
728 {
729 	struct uaedev_config_data *uci = &p->mountconfig[nr];
730 	if (idx >= 0) {
731 		UnitInfo *ui;
732 		uci->configoffset = idx;
733 		ui = &mountinfo.ui[idx];
734 		ui->configureddrive = 1;
735 	} else {
736 		uci->configoffset = -1;
737 	}
738 }
739 
initialize_mountinfo(void)740 static void initialize_mountinfo (void)
741 {
742 	int nr;
743 /* REMOVEME:
744  * nowhere used
745  */
746 #if 0
747 	UnitInfo *uip = &mountinfo.ui[0];
748 #endif
749 
750 	cd_unit_offset = MAX_FILESYSTEM_UNITS;
751 
752 	for (nr = 0; nr < currprefs.mountitems; nr++) {
753 		struct uaedev_config_data *uci = &currprefs.mountconfig[nr];
754 		if (uci->ci.controller == HD_CONTROLLER_UAE) {
755 			struct uaedev_config_info ci;
756 			memcpy (&ci, &uci->ci, sizeof (struct uaedev_config_info));
757 			ci.flags = MYVOLUMEINFO_REUSABLE;
758 			int idx = set_filesys_unit_1 (-1, &ci);
759 			allocuci (&currprefs, nr, idx);
760 		}
761 	}
762 	filesys_addexternals ();
763 	nr = nr_units ();
764 	cd_unit_offset = nr;
765 	cd_unit_number = 0;
766 #ifdef SCSI
767 	if (currprefs.scsi /*&& currprefs.win32_automount_cddrives*/) {
768 		uae_u32 mask = scsi_get_cd_drive_mask ();
769 		for (int i = 0; i < 32; i++) {
770 			if (mask & (1 << i)) {
771 				struct uaedev_config_info ci = { 0 };
772 				_stprintf (ci.devname, _T("CD%d"), i);
773 				cd_unit_number++;
774 				_tcscpy (ci.rootdir, _T("/"));
775 				ci.readonly = true;
776 				ci.sectors = 1;
777 				ci.surfaces = 1;
778 				ci.blocksize = 2048;
779 				int idx = set_filesys_unit_1 (i + cd_unit_offset, &ci);
780 				allocuci (&currprefs, nr, idx);
781 				nr++;
782 			}
783 		}
784 	}
785 #endif
786 	for (nr = 0; nr < currprefs.mountitems; nr++) {
787 		struct uaedev_config_info *uci = &currprefs.mountconfig[nr].ci;
788 		if (uci->controller == HD_CONTROLLER_UAE)
789 			continue;
790 		if (uci->controller <= HD_CONTROLLER_IDE3) {
791 #ifdef GAYLE
792 			gayle_add_ide_unit (uci->controller - HD_CONTROLLER_IDE0, uci);
793 			allocuci (&currprefs, nr, -1);
794 #endif
795 		} else if (uci->controller <= HD_CONTROLLER_SCSI6) {
796 			if (currprefs.cs_mbdmac > 0) {
797 #ifdef A2091
798 				a3000_add_scsi_unit (uci->controller - HD_CONTROLLER_SCSI0, uci);
799 				allocuci (&currprefs, nr, -1);
800 #endif
801 			} else if (currprefs.cs_a2091) {
802 #ifdef A2091
803 				a2091_add_scsi_unit (uci->controller - HD_CONTROLLER_SCSI0, uci);
804 				allocuci (&currprefs, nr, -1);
805 #endif
806 			} else if (currprefs.cs_cdtvscsi) {
807 #ifdef CDTV
808 				cdtv_add_scsi_hd_unit (uci->controller - HD_CONTROLLER_SCSI0, uci);
809 				allocuci (&currprefs, nr, -1);
810 #endif
811 			}
812 		} else if (uci->controller == HD_CONTROLLER_PCMCIA_SRAM) {
813 #ifdef GAYLE
814 			gayle_add_pcmcia_sram_unit (uci->rootdir, uci->readonly);
815 			allocuci (&currprefs, nr, -1);
816 #endif
817 		} else if (uci->controller == HD_CONTROLLER_PCMCIA_IDE) {
818 #ifdef GAYLE
819 			gayle_add_pcmcia_ide_unit (uci->rootdir, uci->readonly);
820 			allocuci (&currprefs, nr, -1);
821 #endif
822 		}
823 	}
824 
825 
826 }
827 
828 
sprintf_filesys_unit(TCHAR * buffer,int num)829 int sprintf_filesys_unit (TCHAR *buffer, int num)
830 {
831 	UnitInfo *uip = mountinfo.ui;
832 
833 	if (uip[num].volname != 0)
834 		_stprintf (buffer, _T("(DH%d:) Filesystem, %s: %s %s"), num, uip[num].volname,
835 		uip[num].rootdir, uip[num].readonly ? "ro" : "");
836 	else
837 		_stprintf (buffer, _T("(DH%d:) Hardfile, \"%s\", size %d Mbytes"), num,
838 		uip[num].rootdir, (int)(uip[num].hf.virtsize / (1024 * 1024)));
839 	return 0;
840 }
841 
free_mountinfo(void)842 static void free_mountinfo (void)
843 {
844 	int i;
845 	for (i = 0; i < MAX_FILESYSTEM_UNITS; i++)
846 		close_filesys_unit (mountinfo.ui + i);
847 #ifdef GAYLE
848 	gayle_free_units ();
849 #endif
850 }
851 
get_hardfile_data(int nr)852 struct hardfiledata *get_hardfile_data (int nr)
853 {
854 	UnitInfo *uip = mountinfo.ui;
855 	if (nr < 0 || nr >= MAX_FILESYSTEM_UNITS || uip[nr].open == 0 || is_virtual (nr))
856 		return 0;
857 	return &uip[nr].hf;
858 }
859 
860 /* minimal AmigaDOS definitions */
861 
862 /* field offsets in DosPacket */
863 #define dp_Type 8
864 #define dp_Res1 12
865 #define dp_Res2 16
866 #define dp_Arg1 20
867 #define dp_Arg2 24
868 #define dp_Arg3 28
869 #define dp_Arg4 32
870 #define dp_Arg5 36
871 
872 #define DP64_INIT       -3L
873 
874 #define dp64_Type 8
875 #define dp64_Res0 12
876 #define dp64_Res2 16
877 #define dp64_Res1 24
878 #define dp64_Arg1 32
879 #define dp64_Arg2 40
880 #define dp64_Arg3 48
881 #define dp64_Arg4 52
882 #define dp64_Arg5 56
883 
884 /* result codes */
885 #define DOS_TRUE ((uae_u32)-1L)
886 #define DOS_FALSE (0L)
887 
888 /* DirEntryTypes */
889 #define ST_PIPEFILE -5
890 #define ST_LINKFILE -4
891 #define ST_FILE -3
892 #define ST_ROOT 1
893 #define ST_USERDIR 2
894 #define ST_SOFTLINK 3
895 #define ST_LINKDIR 4
896 
897 #define MAXFILESIZE32 (0x7fffffff)
898 
899 /* Passed as type to Lock() */
900 #define SHARED_LOCK		-2  /* File is readable by others */
901 #define ACCESS_READ		-2  /* Synonym */
902 #define EXCLUSIVE_LOCK	-1  /* No other access allowed  */
903 #define ACCESS_WRITE	-1  /* Synonym */
904 
905 /* packet types */
906 #define ACTION_CURRENT_VOLUME	 7
907 #define ACTION_LOCATE_OBJECT	 8
908 #define ACTION_RENAME_DISK		 9
909 #define ACTION_FREE_LOCK		15
910 #define ACTION_DELETE_OBJECT	16
911 #define ACTION_RENAME_OBJECT	17
912 #define ACTION_MORE_CACHE		18
913 #define ACTION_COPY_DIR			19
914 #define ACTION_SET_PROTECT		21
915 #define ACTION_CREATE_DIR		22
916 #define ACTION_EXAMINE_OBJECT	23
917 #define ACTION_EXAMINE_NEXT		24
918 #define ACTION_DISK_INFO		25
919 #define ACTION_INFO				26
920 #define ACTION_FLUSH			27
921 #define ACTION_SET_COMMENT		28
922 #define ACTION_PARENT			29
923 #define ACTION_SET_DATE			34
924 #define ACTION_FIND_WRITE		1004
925 #define ACTION_FIND_INPUT		1005
926 #define ACTION_FIND_OUTPUT		1006
927 #define ACTION_END				1007
928 #define ACTION_SEEK				1008
929 #define ACTION_WRITE_PROTECT	1023
930 #define ACTION_IS_FILESYSTEM	1027
931 #define ACTION_READ				 'R'
932 #define ACTION_WRITE			 'W'
933 
934 /* 2.0+ packet types */
935 #define ACTION_INHIBIT			  31
936 #define ACTION_SET_FILE_SIZE	1022
937 #define ACTION_LOCK_RECORD		2008
938 #define ACTION_FREE_RECORD		2009
939 #define ACTION_SAME_LOCK		  40
940 #define ACTION_CHANGE_MODE		1028
941 #define ACTION_FH_FROM_LOCK		1026
942 #define ACTION_COPY_DIR_FH		1030
943 #define ACTION_PARENT_FH		1031
944 #define ACTION_EXAMINE_ALL		1033
945 #define ACTION_EXAMINE_FH		1034
946 #define ACTION_EXAMINE_ALL_END	1035
947 
948 #define ACTION_FORMAT			1020
949 #define ACTION_IS_FILESYSTEM	1027
950 #define ACTION_ADD_NOTIFY		4097
951 #define ACTION_REMOVE_NOTIFY	4098
952 
953 #define ACTION_READ_LINK		1024
954 
955 #define ACTION_CHANGE_FILE_POSITION64  8001
956 #define ACTION_GET_FILE_POSITION64     8002
957 #define ACTION_CHANGE_FILE_SIZE64      8003
958 #define ACTION_GET_FILE_SIZE64         8004
959 
960 /* not supported */
961 #define ACTION_MAKE_LINK		1021
962 
963 #define DISK_TYPE_DOS 0x444f5300 /* DOS\0 */
964 #define DISK_TYPE_DOS_FFS 0x444f5301 /* DOS\1 */
965 #define CDFS_DOSTYPE 0x43440000 /* CDxx */
966 
967 typedef struct {
968 	uae_u32 uniq;
969 	/* The directory we're going through.  */
970 	a_inode *aino;
971 	/* The file we're going to look up next.  */
972 	a_inode *curr_file;
973 } ExamineKey;
974 
975 struct lockrecord
976 {
977 	struct lockrecord *next;
978 	uae_u32 packet;
979 	uae_u32 pos;
980 	uae_u32 len;
981 	uae_u32 mode;
982 	uae_u32 timeout;
983 	uae_u32 msg;
984 };
985 
986 typedef struct key {
987 	struct key *next;
988 	a_inode *aino;
989 	uae_u32 uniq;
990 	struct fs_filehandle *fd;
991 	off_t file_pos;
992 	int dosmode;
993 	int createmode;
994 	int notifyactive;
995 	struct lockrecord *record;
996 } Key;
997 
998 typedef struct notify {
999 	struct notify *next;
1000 	uaecptr notifyrequest;
1001 	TCHAR *fullname;
1002 	TCHAR *partname;
1003 } Notify;
1004 
1005 typedef struct exallkey {
1006 	uae_u32 id;
1007 	struct fs_dirhandle *dirhandle;
1008 	TCHAR *fn;
1009 	uaecptr control;
1010 } ExAllKey;
1011 
1012 /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
1013  * some of these around
1014  */
1015 
1016 #define EXKEYS 128
1017 #define EXALLKEYS 100
1018 #define MAX_AINO_HASH 128
1019 #define NOTIFY_HASH_SIZE 127
1020 
1021 /* handler state info */
1022 
1023 typedef struct _unit {
1024 	struct _unit *next;
1025 
1026 	/* Amiga stuff */
1027 	uaecptr dosbase;
1028 	uaecptr volume;
1029 	uaecptr port;	/* Our port */
1030 	uaecptr locklist;
1031 
1032 	/* Native stuff */
1033 	uae_s32 unit;	/* unit number */
1034 	UnitInfo ui;	/* unit startup info */
1035 	TCHAR tmpbuf3[256];
1036 
1037 	/* Dummy message processing */
1038 	uaecptr dummy_message;
1039 	volatile unsigned int cmds_sent;
1040 	volatile unsigned int cmds_complete;
1041 	volatile unsigned int cmds_acked;
1042 
1043 	/* ExKeys */
1044 	ExamineKey examine_keys[EXKEYS];
1045 	int next_exkey;
1046 	unsigned long total_locked_ainos;
1047 
1048 	/* ExAll */
1049 	ExAllKey exalls[EXALLKEYS];
1050 	uae_u32 exallid;
1051 
1052 	/* Keys */
1053 	struct key *keys;
1054 
1055 	struct lockrecord *waitingrecords;
1056 
1057 	a_inode rootnode;
1058 	unsigned long aino_cache_size;
1059 	a_inode *aino_hash[MAX_AINO_HASH];
1060 	unsigned long nr_cache_hits;
1061 	unsigned long nr_cache_lookups;
1062 
1063 	struct notify *notifyhash[NOTIFY_HASH_SIZE];
1064 
1065 	int volflags;
1066 	uae_u32 lockkey;
1067 	bool inhibited;
1068 	bool canremovable;
1069 	/* increase when media is changed.
1070 	 * used to detect if cached aino is valid
1071 	 */
1072 	unsigned int mountcount;
1073 	int mount_changed;
1074 	struct zvolume *zarchive;
1075 	void *cdfs_superblock;
1076 
1077 	TCHAR *mount_volume;
1078 	TCHAR *mount_rootdir;
1079 	bool mount_readonly;
1080 	int mount_flags;
1081 
1082 	int reinsertdelay;
1083 	TCHAR *newvolume;
1084 	TCHAR *newrootdir;
1085 	bool newreadonly;
1086 	int newflags;
1087 
1088 } Unit;
1089 
1090 static uae_u32 a_uniq, key_uniq;
1091 
1092 typedef uaecptr dpacket;
1093 #define PUT_PCK_RES1(p,v) do { put_long ((p) + dp_Res1, (v)); } while (0)
1094 #define PUT_PCK_RES2(p,v) do { put_long ((p) + dp_Res2, (v)); } while (0)
1095 #define GET_PCK_TYPE(p) ((uae_s32)(get_long ((p) + dp_Type)))
1096 #define GET_PCK_RES1(p) ((uae_s32)(get_long ((p) + dp_Res1)))
1097 #define GET_PCK_RES2(p) ((uae_s32)(get_long ((p) + dp_Res2)))
1098 #define GET_PCK_ARG1(p) ((uae_s32)(get_long ((p) + dp_Arg1)))
1099 #define GET_PCK_ARG2(p) ((uae_s32)(get_long ((p) + dp_Arg2)))
1100 #define GET_PCK_ARG3(p) ((uae_s32)(get_long ((p) + dp_Arg3)))
1101 #define GET_PCK_ARG4(p) ((uae_s32)(get_long ((p) + dp_Arg4)))
1102 #define GET_PCK_ARG5(p) ((uae_s32)(get_long ((p) + dp_Arg5)))
1103 
1104 #define PUT_PCK64_RES0(p,v) do { put_long ((p) + dp64_Res0, (v)); } while (0)
1105 #define PUT_PCK64_RES1(p,v) do { put_long ((p) + dp64_Res1, (((uae_u64)v) >> 32)); put_long ((p) + dp64_Res1 + 4, ((uae_u32)v)); } while (0)
1106 #define PUT_PCK64_RES2(p,v) do { put_long ((p) + dp64_Res2, (v)); } while (0)
1107 
1108 #define GET_PCK64_TYPE(p) ((uae_s32)(get_long ((p) + dp64_Type)))
1109 #define GET_PCK64_RES0(p) ((uae_s32)(get_long ((p) + dp64_Res0)))
1110 #define GET_PCK64_RES1(p) ( (((uae_s64)(get_long ((p) + dp64_Res1))) << 32) | (((uae_s64)(get_long ((p) + dp64_Res1 + 4))) << 0) )
1111 #define GET_PCK64_ARG1(p) ((uae_s32)(get_long ((p) + dp64_Arg1)))
1112 #define GET_PCK64_ARG2(p) ( (((uae_s64)(get_long ((p) + dp64_Arg2))) << 32) | (((uae_s64)(get_long ((p) + dp64_Arg2 + 4))) << 0) )
1113 #define GET_PCK64_ARG3(p) ((uae_s32)(get_long ((p) + dp64_Arg3)))
1114 #define GET_PCK64_ARG4(p) ((uae_s32)(get_long ((p) + dp64_Arg4)))
1115 #define GET_PCK64_ARG5(p) ( (((uae_s64)(get_long ((p) + dp64_Arg5))) << 32) | (((uae_s64)(get_long ((p) + dp64_Arg5 + 4))) << 0) )
1116 
1117 static int flush_cache (Unit *unit, int num);
1118 
char1(uaecptr addr)1119 static TCHAR *char1 (uaecptr addr)
1120 {
1121 	static uae_char buf[1024];
1122 	static TCHAR bufx[1024];
1123 	unsigned int i = 0;
1124 	do {
1125 		buf[i] = get_byte (addr);
1126 		addr++;
1127 	} while (buf[i++] && i < sizeof (buf));
1128 	return au_fs_copy (bufx, sizeof (bufx) / sizeof (TCHAR), buf);
1129 }
1130 
bstr1(uaecptr addr)1131 static TCHAR *bstr1 (uaecptr addr)
1132 {
1133 	static TCHAR bufx[257];
1134 	static uae_char buf[257];
1135 	int i;
1136 	int n = get_byte (addr);
1137 	addr++;
1138 
1139 	for (i = 0; i < n; i++, addr++)
1140 		buf[i] = get_byte (addr);
1141 	buf[i] = 0;
1142 	return au_fs_copy (bufx, sizeof (bufx) / sizeof (TCHAR), buf);
1143 }
1144 
bstr(Unit * unit,uaecptr addr)1145 static TCHAR *bstr (Unit *unit, uaecptr addr)
1146 {
1147 	int i;
1148 	int n = get_byte (addr);
1149 	uae_char buf[257];
1150 
1151 	addr++;
1152 	for (i = 0; i < n; i++, addr++)
1153 		buf[i] = get_byte (addr);
1154 	buf[i] = 0;
1155 	au_fs_copy (unit->tmpbuf3, sizeof (unit->tmpbuf3) / sizeof (TCHAR), buf);
1156 	return unit->tmpbuf3;
1157 }
cstr(Unit * unit,uaecptr addr)1158 static TCHAR *cstr (Unit *unit, uaecptr addr)
1159 {
1160 	int i;
1161 	uae_char buf[257];
1162 
1163 	for (i = 0;;i++,addr++) {
1164 		buf[i] = get_byte (addr);
1165 		if (!buf[i])
1166 			break;
1167 	}
1168 	au_fs_copy (unit->tmpbuf3, sizeof (unit->tmpbuf3) / sizeof (TCHAR), buf);
1169 	return unit->tmpbuf3;
1170 }
1171 
bstr_cut(Unit * unit,uaecptr addr)1172 static TCHAR *bstr_cut (Unit *unit, uaecptr addr)
1173 {
1174 	TCHAR *p = unit->tmpbuf3;
1175 	int i, colon_seen = 0, off;
1176 	int n = get_byte (addr);
1177 	uae_char buf[257];
1178 
1179 	off = 0;
1180 	addr++;
1181 	for (i = 0; i < n; i++, addr++) {
1182 		uae_u8 c = get_byte (addr);
1183 		buf[i] = c;
1184 		if (c == '/' || (c == ':' && colon_seen++ == 0))
1185 			off = i + 1;
1186 	}
1187 	buf[i] = 0;
1188 	au_fs_copy (unit->tmpbuf3, sizeof (unit->tmpbuf3) / sizeof (TCHAR), buf);
1189 	return &p[off];
1190 }
1191 
1192 /* convert time_t to/from AmigaDOS time */
1193 static const uae_s64 msecs_per_day = 24 * 60 * 60 * 1000;
1194 static const uae_s64 diff = ((8 * 365 + 2) * (24 * 60 * 60)) * (uae_u64)1000;
1195 
timeval_to_amiga(struct mytimeval * tv,int * days,int * mins,int * ticks)1196 void timeval_to_amiga (struct mytimeval *tv, int *days, int *mins, int *ticks)
1197 {
1198 	/* tv.tv_sec is secs since 1-1-1970 */
1199 	/* days since 1-1-1978 */
1200 	/* mins since midnight */
1201 	/* ticks past minute @ 50Hz */
1202 
1203 	uae_s64 t = tv->tv_sec * 1000 + tv->tv_usec / 1000;
1204 	t -= diff;
1205 	if (t < 0)
1206 		t = 0;
1207 	*days = t / msecs_per_day;
1208 	t -= *days * msecs_per_day;
1209 	*mins = t / (60 * 1000);
1210 	t -= *mins * (60 * 1000);
1211 	*ticks = t / (1000 / 50);
1212 }
1213 
amiga_to_timeval(struct mytimeval * tv,int days,int mins,int ticks)1214 void amiga_to_timeval (struct mytimeval *tv, int days, int mins, int ticks)
1215 {
1216 	uae_s64 t;
1217 
1218 	if (days < 0)
1219 		days = 0;
1220 	if (days > 9900 * 365)
1221 		days = 9900 * 365; // in future far enough?
1222 	if (mins < 0 || mins >= 24 * 60)
1223 		mins = 0;
1224 	if (ticks < 0 || ticks >= 60 * 50)
1225 		ticks = 0;
1226 
1227 	t = ticks * 20;
1228 	t += mins * (60 * 1000);
1229 	t += ((uae_u64)days) * msecs_per_day;
1230 	t += diff;
1231 
1232 	tv->tv_sec = t / 1000;
1233 	tv->tv_usec = (t % 1000) * 1000;
1234 }
1235 
1236 static Unit *units = 0;
1237 
1238 static Unit*
find_unit(uaecptr port)1239 	find_unit (uaecptr port)
1240 {
1241 	Unit* u;
1242 	for (u = units; u; u = u->next)
1243 		if (u->port == port)
1244 			break;
1245 
1246 	return u;
1247 }
1248 
fs_opendir(Unit * u,a_inode * aino)1249 static struct fs_dirhandle *fs_opendir (Unit *u, a_inode *aino)
1250 {
1251 	struct fs_dirhandle *fsd = xmalloc (struct fs_dirhandle, 1);
1252 	fsd->fstype = (u->volflags & MYVOLUMEINFO_ARCHIVE) ? FS_ARCHIVE : ((u->volflags & MYVOLUMEINFO_CDFS) ? FS_CDFS : FS_DIRECTORY);
1253 	if (fsd->fstype == FS_ARCHIVE) {
1254 		fsd->zd = zfile_opendir_archive (aino->nname);
1255 		if (fsd->zd)
1256 			return fsd;
1257 	} else if (fsd->fstype == FS_DIRECTORY) {
1258 		fsd->od = my_opendir (aino->nname, 0);
1259 		if (fsd->od)
1260 			return fsd;
1261 	/*} else if (fsd->fstype == FS_CDFS) {
1262 		fsd->isod = isofs_opendir (u->ui.cdfs_superblock, aino->uniq_external);
1263 		if (fsd->isod)
1264 			return fsd;*/
1265 	}
1266 	xfree (fsd);
1267 	return NULL;
1268 }
fs_closedir(struct fs_dirhandle * fsd)1269 static void fs_closedir (struct fs_dirhandle *fsd)
1270 {
1271 	if (!fsd)
1272 		return;
1273 	if (fsd->fstype  == FS_ARCHIVE)
1274 		zfile_closedir_archive (fsd->zd);
1275 	else if (fsd->fstype == FS_DIRECTORY)
1276 		my_closedir (fsd->od);
1277 /*	else if (fsd->fstype == FS_CDFS)
1278 		isofs_closedir (fsd->isod);*/
1279 	xfree (fsd);
1280 }
fs_openfile(Unit * u,a_inode * aino,int flags)1281 static struct fs_filehandle *fs_openfile (Unit *u, a_inode *aino, int flags)
1282 {
1283 	struct fs_filehandle *fsf = xmalloc (struct fs_filehandle, 1);
1284 	fsf->fstype = (u->volflags & MYVOLUMEINFO_ARCHIVE) ? FS_ARCHIVE : ((u->volflags & MYVOLUMEINFO_CDFS) ? FS_CDFS : FS_DIRECTORY);
1285 	if (fsf->fstype == FS_ARCHIVE) {
1286 		fsf->zf = zfile_open_archive (aino->nname, flags);
1287 		if (fsf->zf)
1288 	return fsf;
1289 	} else if (fsf->fstype == FS_DIRECTORY) {
1290 		fsf->of = my_open (aino->nname, flags);
1291 		if (fsf->of)
1292 			return fsf;
1293 	} else if (fsf->fstype == FS_CDFS) {
1294 	/*	fsf->isof = isofs_openfile (u->ui.cdfs_superblock, aino->uniq_external, flags);
1295 		if (fsf->isof)
1296 			return fsf;*/
1297 	}
1298 	xfree (fsf);
1299 	return NULL;
1300 }
fs_closefile(struct fs_filehandle * fsf)1301 static void fs_closefile (struct fs_filehandle *fsf)
1302 {
1303 	if (!fsf)
1304 		return;
1305 	if (fsf->fstype == FS_ARCHIVE) {
1306 		zfile_close_archive (fsf->zf);
1307 	} else if (fsf->fstype == FS_DIRECTORY) {
1308 		my_close (fsf->of);
1309 	/*} else if (fsf->fstype == FS_CDFS) {
1310 		isofs_closefile (fsf->isof);*/
1311 	}
1312 	xfree (fsf);
1313 }
fs_read(struct fs_filehandle * fsf,void * b,unsigned int size)1314 static unsigned int fs_read (struct fs_filehandle *fsf, void *b, unsigned int size)
1315 {
1316 	if (fsf->fstype == FS_ARCHIVE)
1317 		return zfile_read_archive (fsf->zf, b, size);
1318 	else if (fsf->fstype == FS_DIRECTORY)
1319 		return my_read (fsf->of, b, size);
1320 /*	else if (fsf->fstype == FS_CDFS)
1321 		return isofs_read (fsf->isof, b, size);*/
1322 	return 0;
1323 }
fs_write(struct fs_filehandle * fsf,void * b,unsigned int size)1324 static unsigned int fs_write (struct fs_filehandle *fsf, void *b, unsigned int size)
1325 {
1326 	if (fsf->fstype == FS_DIRECTORY)
1327 		return my_write (fsf->of, b, size);
1328 	return 0;
1329 }
1330 
1331 /* return value = old position. -1 = error. */
fs_lseek64(struct fs_filehandle * fsf,uae_s64 offset,int whence)1332 static uae_u64 fs_lseek64 (struct fs_filehandle *fsf, uae_s64 offset, int whence)
1333 {
1334 	if (fsf->fstype == FS_ARCHIVE)
1335 		return zfile_lseek_archive (fsf->zf, offset, whence);
1336 	else if (fsf->fstype == FS_DIRECTORY)
1337 		return my_lseek (fsf->of, offset, whence);
1338 /*	else if (fsf->fstype == FS_CDFS)
1339 		return isofs_lseek (fsf->isof, offset, whence);*/
1340 	return -1;
1341 }
fs_lseek(struct fs_filehandle * fsf,uae_s32 offset,int whence)1342 static uae_u32 fs_lseek (struct fs_filehandle *fsf, uae_s32 offset, int whence)
1343 {
1344 	return (uae_u32)fs_lseek64 (fsf, offset, whence);
1345 }
fs_fsize64(struct fs_filehandle * fsf)1346 static uae_u64 fs_fsize64 (struct fs_filehandle *fsf)
1347 {
1348 	if (fsf->fstype == FS_ARCHIVE)
1349 		return zfile_fsize_archive (fsf->zf);
1350 	else if (fsf->fstype == FS_DIRECTORY)
1351 		return my_fsize (fsf->of);
1352 /*	else if (fsf->fstype == FS_CDFS)
1353 		return isofs_fsize (fsf->isof);*/
1354 	return -1;
1355 }
fs_fsize(struct fs_filehandle * fsf)1356 static uae_u32 fs_fsize (struct fs_filehandle *fsf)
1357 {
1358 	return (uae_u32)fs_fsize64 (fsf);
1359 }
1360 
1361 #ifdef SCSI
set_highcyl(UnitInfo * ui,uae_u32 blocks)1362 static void set_highcyl (UnitInfo *ui, uae_u32 blocks)
1363 {
1364 	uaecptr startup = get_long (ui->devicenode + 7 * 4) << 2;
1365 	uaecptr env = get_long (startup + 8) << 2;
1366 	put_long (env + 10 * 4, blocks);
1367 }
1368 #endif
1369 
set_volume_name(Unit * unit,struct mytimeval * tv)1370 static void set_volume_name (Unit *unit, struct mytimeval *tv)
1371 {
1372 	int namelen;
1373 	int i;
1374 	char *s;
1375 
1376 	s = ua_fs (unit->ui.volname, -1);
1377 	namelen = strlen (s);
1378 	put_byte (unit->volume + 44, namelen);
1379 	for (i = 0; i < namelen; i++)
1380 		put_byte (unit->volume + 45 + i, s[i]);
1381 	put_byte (unit->volume + 45 + namelen, 0);
1382 	if (tv && (tv->tv_sec || tv->tv_usec)) {
1383 		int days, mins, ticks;
1384 		timeval_to_amiga (tv, &days, &mins, &ticks);
1385 		put_long (unit->volume + 16, days);
1386 		put_long (unit->volume + 20, mins);
1387 		put_long (unit->volume + 24, ticks);
1388 	}
1389 	xfree (s);
1390 	unit->rootnode.aname = unit->ui.volname;
1391 	unit->rootnode.nname = unit->ui.rootdir;
1392 	unit->rootnode.mountcount = unit->mountcount;
1393 }
1394 
filesys_isvolume(Unit * unit)1395 static int filesys_isvolume (Unit *unit)
1396 {
1397 	if (!unit->volume)
1398 		return 0;
1399 	return get_byte (unit->volume + 44) || unit->ui.unknown_media;
1400 }
1401 
clear_exkeys(Unit * unit)1402 static void clear_exkeys (Unit *unit)
1403 {
1404 	int i;
1405 	a_inode *a;
1406 	for (i = 0; i < EXKEYS; i++) {
1407 		unit->examine_keys[i].aino = 0;
1408 		unit->examine_keys[i].curr_file = 0;
1409 		unit->examine_keys[i].uniq = 0;
1410 	}
1411 	for (i = 0; i < EXALLKEYS; i++) {
1412 		fs_closedir (unit->exalls[i].dirhandle);
1413 		unit->exalls[i].dirhandle = NULL;
1414 		xfree (unit->exalls[i].fn);
1415 		unit->exalls[i].fn = NULL;
1416 		unit->exalls[i].id = 0;
1417 	}
1418 	unit->exallid = 0;
1419 	unit->next_exkey = 1;
1420 	a = &unit->rootnode;
1421 	while (a) {
1422 		a->exnext_count = 0;
1423 		if (a->locked_children) {
1424 			a->locked_children = 0;
1425 			unit->total_locked_ainos--;
1426 		}
1427 		a = a->next;
1428 		if (a == &unit->rootnode)
1429 			break;
1430 	}
1431 }
1432 
filesys_delayed_change(Unit * u,int frames,const TCHAR * rootdir,const TCHAR * volume,bool readonly,int flags)1433 static void filesys_delayed_change (Unit *u, int frames, const TCHAR *rootdir, const TCHAR *volume, bool readonly, int flags)
1434 {
1435 	u->reinsertdelay = 50;
1436 	u->newflags = flags;
1437 	u->newreadonly = readonly;
1438 	u->newrootdir = my_strdup (rootdir);
1439 	if (volume)
1440 		u->newvolume = my_strdup (volume);
1441 	filesys_eject (u->unit);
1442 	if (!rootdir || _tcslen (rootdir) == 0)
1443 		u->reinsertdelay = 0;
1444 	if (u->reinsertdelay > 0)
1445 		write_log (_T("FILESYS: delayed insert %d: '%s' ('%s')\n"), u->unit, volume ? volume : _T("<none>"), rootdir);
1446 }
1447 
filesys_eject(int nr)1448 int filesys_eject (int nr)
1449 {
1450 	UnitInfo *ui = &mountinfo.ui[nr];
1451 	Unit *u = ui->self;
1452 
1453 	if (!mountertask || u->mount_changed)
1454 		return 0;
1455 	if (!ui->open || u == NULL)
1456 		return 0;
1457 	if (!is_virtual (nr))
1458 		return 0;
1459 	if (!filesys_isvolume (u))
1460 		return 0;
1461 	u->mount_changed = -1;
1462 	u->mountcount++;
1463 	write_log (_T("FILESYS: volume '%s' removal request\n"), u->ui.volname);
1464 	// -1 = remove, -2 = remove + remove device node
1465 	put_byte (u->volume + 172 - 32, ui->unit_type == UNIT_CDFS ? -1 : -2);
1466 	uae_Signal (get_long (u->volume + 176 - 32), 1 << 13);
1467 	return 1;
1468 }
1469 
1470 static uae_u32 heartbeat;
1471 static int heartbeat_count;
1472 static int heartbeat_task;
1473 
1474 // This uses filesystem process to reduce resource usage
setsystime(void)1475 void setsystime (void)
1476 {
1477 	if (!currprefs.tod_hack)
1478 		return;
1479 	heartbeat = get_long (rtarea_base + RTAREA_HEARTBEAT);
1480 	heartbeat_task = 1;
1481 	heartbeat_count = 10;
1482 }
1483 
setsystime_vblank(void)1484 static void setsystime_vblank (void)
1485 {
1486 	Unit *u;
1487 	for (u = units; u; u = u->next) {
1488 		if (is_virtual (u->unit) && filesys_isvolume (u)) {
1489 			put_byte (u->volume + 173 - 32, 1);
1490 			uae_Signal (get_long (u->volume + 176 - 32), 1 << 13);
1491 			break;
1492 		}
1493 	}
1494 }
1495 
filesys_insert(int nr,const TCHAR * volume,const TCHAR * rootdir,bool readonly,int flags)1496 int filesys_insert (int nr, const TCHAR *volume, const TCHAR *rootdir, bool readonly, int flags)
1497 {
1498 	UnitInfo *ui;
1499 	Unit *u;
1500 
1501 	if (!mountertask)
1502 		return 0;
1503 
1504 	write_log (_T("filesys_insert(%d,'%s','%s','%d','%d)\n"), nr, volume ? volume : _T("<?>"), rootdir, readonly, flags);
1505 
1506 	if (nr < 0) {
1507 		for (u = units; u; u = u->next) {
1508 			if (is_virtual (u->unit)) {
1509 				if (!filesys_isvolume (u) && mountinfo.ui[u->unit].canremove)
1510 					break;
1511 			}
1512 		}
1513 		if (!u) {
1514 			for (u = units; u; u = u->next) {
1515 				if (is_virtual (u->unit)) {
1516 					if (mountinfo.ui[u->unit].canremove)
1517 						break;
1518 				}
1519 			}
1520 		}
1521 		if (!u)
1522 			return 0;
1523 		nr = u->unit;
1524 		ui = &mountinfo.ui[nr];
1525 	} else {
1526 		ui = &mountinfo.ui[nr];
1527 		u = ui->self;
1528 	}
1529 
1530 	if (!ui->open || u == NULL)
1531 		return 0;
1532 	if (u->reinsertdelay)
1533 		return -1;
1534 	if (!is_virtual (nr))
1535 		return 0;
1536 	if (filesys_isvolume (u)) {
1537 		filesys_delayed_change (u, 50, rootdir, volume, readonly, flags);
1538 		return -1;
1539 	}
1540 	u->mountcount++;
1541 	u->mount_changed = 1;
1542 	u->mount_volume = volume ? my_strdup (volume) : NULL;
1543 	u->mount_rootdir = my_strdup (rootdir);
1544 	u->mount_readonly = readonly;
1545 	u->mount_flags = flags;
1546 
1547 	write_log (_T("filesys_insert %d done!\n"), nr);
1548 
1549 	put_byte (u->volume + 172 - 32, -3); // wait for insert
1550 	uae_Signal (get_long (u->volume + 176 - 32), 1 << 13);
1551 
1552 	return 100 + nr;
1553 }
1554 
filesys_media_change_reply(TrapContext * ctx,int mode)1555 static uae_u32 filesys_media_change_reply (TrapContext *ctx, int mode)
1556 {
1557 	int nr;
1558 	UnitInfo *ui = NULL;
1559 	Unit *u;
1560 
1561 	for (nr = 0; nr < MAX_FILESYSTEM_UNITS; nr++) {
1562 		ui = &mountinfo.ui[nr];
1563 		u = ui->self;
1564 		if (u && u->mount_changed)
1565 			break;
1566 	}
1567 	if (nr >= MAX_FILESYSTEM_UNITS) {
1568 		write_log (_T("FILESYS: filesys_media_change_reply without mount_changed flag!?\n"));
1569 		return 0;
1570 	}
1571 
1572 	if (u->mount_changed < 0) {
1573 		// eject
1574 		if (mode == 0) {
1575 			write_log (_T("FILESYS: got media change reply, '%s' removal finished\n"), u->ui.volname);
1576 			flush_cache (u, -1);
1577 #ifdef SCSI
1578 			isofs_unmount (u->ui.cdfs_superblock);
1579 #endif
1580 			ui->cdfs_superblock = u->ui.cdfs_superblock = NULL;
1581 			zfile_fclose_archive (u->zarchive);
1582 			u->zarchive = NULL;
1583 			u->ui.unknown_media = false;
1584 #ifdef RETROPLATFORM
1585 			if (ui->unit_type == UNIT_CDFS)
1586 				rp_cd_image_change (ui->cddevno, NULL);
1587 			else
1588 				rp_harddrive_image_change (nr, false, NULL);
1589 #endif
1590 		} else {
1591 			u->mount_changed = 0;
1592 		}
1593 		return 1;
1594 	} else if (u->mount_changed > 0) {
1595 		if (mode == 0) {
1596 			// insert
1597 			struct mytimeval ctime = { 0 };
1598 			bool emptydrive = false;
1599 			struct uaedev_config_data *uci = NULL;
1600 
1601 			clear_exkeys (u);
1602 			xfree (u->ui.rootdir);
1603 			ui->rootdir = u->ui.rootdir = my_strdup (u->mount_rootdir);
1604 			flush_cache (u, -1);
1605 			xfree (u->ui.volname);
1606 			ui->volname = u->ui.volname = NULL;
1607 			if (ui->unit_type == UNIT_CDFS) {
1608 #ifdef SCSI
1609 				uae_u64 uniq;
1610 				ui->cdfs_superblock = u->ui.cdfs_superblock = isofs_mount (ui->cddevno, &uniq);
1611 				u->rootnode.uniq_external = uniq;
1612 					u->ui.unknown_media = true;
1613 				if (!u->ui.cdfs_superblock)
1614 					return 0;
1615 				struct isofs_info ii;
1616 				set_highcyl (ui, 0);
1617 				bool r = isofs_mediainfo (ui->cdfs_superblock, &ii);
1618 				if (r && ii.media) {
1619 					u->ui.unknown_media = ii.unknown_media;
1620 					if (!ii.unknown_media) {
1621 						u->ui.volname = ui->volname = my_strdup (ii.volumename);
1622 						ctime.tv_sec = ii.creation;
1623 						ctime.tv_usec = 0;
1624 						set_highcyl (ui, ii.blocks);
1625 #ifdef RETROPLATFORM
1626 						rp_cd_image_change (ui->cddevno, ii.devname);
1627 #endif
1628 					}
1629 				}
1630 #endif
1631 			} else {
1632 				if (set_filesys_volume (u->mount_rootdir, &u->mount_flags, &u->mount_readonly, &emptydrive, &u->zarchive) < 0)
1633 					return 0;
1634 				if (emptydrive)
1635 					return 0;
1636 				xfree (u->ui.volname);
1637 				ui->volname = u->ui.volname = filesys_createvolname (u->mount_volume, u->mount_rootdir, _T("removable"));
1638 #ifdef RETROPLATFORM
1639 				rp_harddrive_image_change (nr, u->mount_readonly, u->mount_rootdir);
1640 #endif
1641 				uci = getuci (currprefs.mountconfig, nr);
1642 			}
1643 			if (u->ui.unknown_media) {
1644 				write_log (_T("FILESYS: inserted unreadable volume NR=%d RO=%d\n"), nr, u->mount_readonly);
1645 			} else {
1646 				write_log (_T("FILESYS: inserted volume NR=%d RO=%d '%s' ('%s')\n"), nr, u->mount_readonly, ui->volname, u->mount_rootdir);
1647 				set_volume_name (u, &ctime);
1648 				if (u->mount_flags >= 0)
1649 					ui->volflags = u->volflags = u->ui.volflags = u->mount_flags;
1650 				if (uci != NULL) {
1651 					_tcscpy (uci->ci.volname, ui->volname);
1652 					_tcscpy (uci->ci.rootdir, u->mount_rootdir);
1653 				}
1654 				if (u->mount_flags >= 0) {
1655 					ui->readonly = u->ui.readonly = u->mount_readonly;
1656 					if (uci != NULL)
1657 						uci->ci.readonly = u->mount_readonly;
1658 				}
1659 				put_byte (u->volume + 44, 0);
1660 				put_byte (u->volume + 172 - 32, 1);
1661 			}
1662 
1663 			xfree (u->mount_volume);
1664 			xfree (u->mount_rootdir);
1665 			u->mount_rootdir = NULL;
1666 			u->mount_volume = NULL;
1667 		} else {
1668 			u->mount_changed = 0;
1669 		}
1670 
1671 		return 1;
1672 
1673 	}
1674 	return 0;
1675 }
1676 
filesys_media_change(const TCHAR * rootdir,int inserted,struct uaedev_config_data * uci)1677 int filesys_media_change (const TCHAR *rootdir, int inserted, struct uaedev_config_data *uci)
1678 {
1679 	Unit *u;
1680 	UnitInfo *ui;
1681 	int nr = -1;
1682 	TCHAR volname[MAX_DPATH], *volptr;
1683 	TCHAR devname[MAX_DPATH];
1684 
1685 	if (!mountertask)
1686 		return 0;
1687 	if (automountunit >= 0)
1688 		return -1;
1689 
1690 	write_log (_T("filesys_media_change('%s',%d,%p)\n"), rootdir, inserted, uci);
1691 
1692 	nr = -1;
1693 	for (u = units; u; u = u->next) {
1694 		if (is_virtual (u->unit)) {
1695 			ui = &mountinfo.ui[u->unit];
1696 			if (ui->rootdir && !memcmp (ui->rootdir, rootdir, _tcslen (rootdir)) && _tcslen (rootdir) + 3 >= _tcslen (ui->rootdir)) {
1697 				if (filesys_isvolume (u) && inserted) {
1698 					if (uci)
1699 						filesys_delayed_change (u, 50, rootdir, uci->ci.volname, uci->ci.readonly, 0);
1700 					return 0;
1701 				}
1702 				nr = u->unit;
1703 				break;
1704 			}
1705 		}
1706 	}
1707 	ui = NULL;
1708 	if (nr >= 0)
1709 		ui = &mountinfo.ui[nr];
1710 	/* only configured drives have automount support if automount is disabled */
1711 	if (/*!currprefs.win32_automount_removable &&*/ (!ui || !ui->configureddrive) && (inserted == 0 || inserted == 1))
1712 		return 0;
1713 	if (nr < 0 && !inserted)
1714 		return 0;
1715 	/* already mounted volume was ejected? */
1716 	if (nr >= 0 && !inserted)
1717 		return filesys_eject (nr);
1718 	if (inserted) {
1719 		struct uaedev_config_info ci = { 0 };
1720 		if (uci) {
1721 			volptr = my_strdup (uci->ci.volname);
1722 		} else {
1723 			volname[0] = 0;
1724 			//FIXME: target_get_volume_name (&mountinfo, rootdir, volname, MAX_DPATH, 1, 0);
1725 			volptr = volname;
1726 			if (!volname[0])
1727 				volptr = NULL;
1728 			if (ui && ui->configureddrive && ui->volname) {
1729 				volptr = volname;
1730 				_tcscpy (volptr, ui->volname);
1731 			}
1732 		}
1733 		if (!volptr) {
1734 			volptr = filesys_createvolname (NULL, rootdir, _T("removable"));
1735 			_tcscpy (volname, volptr);
1736 			xfree (volptr);
1737 			volptr = volname;
1738 		}
1739 
1740 		/* new volume inserted and it was previously mounted? */
1741 		if (nr >= 0) {
1742 			if (!filesys_isvolume (u)) /* not going to mount twice */
1743 				return filesys_insert (nr, volptr, rootdir, false, -1);
1744 			return 0;
1745 		}
1746 		if (inserted < 0) /* -1 = only mount if already exists */
1747 			return 0;
1748 		/* new volume inserted and it was not previously mounted?
1749 		* perhaps we have some empty device slots? */
1750 		nr = filesys_insert (-1, volptr, rootdir, 0, 0);
1751 		if (nr >= 100) {
1752 			if (uci)
1753 				uci->configoffset = nr - 100;
1754 			return nr;
1755 		}
1756 		/* nope, uh, need black magic now.. */
1757 		if (uci)
1758 			_tcscpy (devname, uci->ci.devname);
1759 		else
1760 			_stprintf (devname, _T("RDH%d"), nr_units ());
1761 		_tcscpy (ci.devname, devname);
1762 		_tcscpy (ci.volname, volptr);
1763 		_tcscpy (ci.rootdir, rootdir);
1764 		ci.flags = MYVOLUMEINFO_REUSABLE;
1765 		nr = add_filesys_unit (&ci);
1766 		if (nr < 0)
1767 			return 0;
1768 		if (inserted > 1)
1769 			mountinfo.ui[nr].canremove = 1;
1770 		automountunit = nr;
1771 		uae_Signal (mountertask, 1 << 13);
1772 		/* poof */
1773 		if (uci)
1774 			uci->configoffset = nr;
1775 		return 100 + nr;
1776 	}
1777 	return 0;
1778 }
1779 
hardfile_media_change(struct hardfiledata * hfd,struct uaedev_config_info * ci,bool inserted,bool timer)1780 int hardfile_media_change (struct hardfiledata *hfd, struct uaedev_config_info *ci, bool inserted, bool timer)
1781 {
1782 	if (!hfd)
1783 		return 0;
1784 	if (!timer)
1785 		hfd->reinsertdelay = 0;
1786 	if (hfd->reinsertdelay < 0) {
1787 		hfd->reinsertdelay = 0;
1788 		if (!hfd->isreinsert) {
1789 			hdf_close (hfd);
1790 			hardfile_send_disk_change (hfd, false);
1791 			if (hfd->delayedci.rootdir[0]) {
1792 				hfd->reinsertdelay = 50;
1793 				hfd->isreinsert = true;
1794 				write_log (_T("HARDFILE: delayed insert %d: '%s'\n"), hfd->unitnum, ci->rootdir ? ci->rootdir : _T("<none>"));
1795 				return 0;
1796 			} else {
1797 				return 1;
1798 			}
1799 		}
1800 		memcpy (&hfd->ci, &hfd->delayedci, sizeof (struct uaedev_config_info));
1801 		if (!hdf_open (hfd, NULL)) {
1802 			write_log (_T("HARDFILE: '%s' failed to open\n"), hfd->ci.rootdir);
1803 			return 0;
1804 		}
1805 		hardfile_send_disk_change (hfd, true);
1806 		return 1;
1807 	}
1808 
1809 	if (ci) {
1810 		memcpy (&hfd->delayedci, ci, sizeof (struct uaedev_config_info));
1811 		if (hfd && !hfd->drive_empty) {
1812 			hfd->reinsertdelay = 50;
1813 			hfd->isreinsert = false;
1814 			write_log (_T("HARDFILE: delayed eject %d: '%s'\n"), hfd->unitnum, hfd->ci.rootdir ? hfd->ci.rootdir : _T("<none>"));
1815 			return 0;
1816 		}
1817 		if (!hfd) {
1818 			return 0;
1819 		}
1820 		hfd->reinsertdelay = 2;
1821 		hfd->isreinsert = true;
1822 	} else {
1823 		if (inserted) {
1824 			hfd->reinsertdelay = 2;
1825 			hfd->isreinsert = true;
1826 			memcpy (&hfd->delayedci, &hfd->ci, sizeof (struct uaedev_config_info));
1827 		} else {
1828 			hfd->reinsertdelay = 2;
1829 			hfd->isreinsert = false;
1830 			memcpy (&hfd->delayedci, &hfd->ci, sizeof (struct uaedev_config_info));
1831 			hfd->delayedci.rootdir[0] = 0;
1832 		}
1833 	}
1834 	return 0;
1835 }
1836 
1837 /** REMOVEME:
1838   * nowhere used
1839 **/
1840 #if 0
1841 int hardfile_remount (int nr)
1842 {
1843 	/* this does work but every media reinsert duplicates the device.. */
1844 #if 0
1845 	if (!mountertask)
1846 		return 0;
1847 	automountunit = nr;
1848 	uae_Signal (mountertask, 1 << 13);
1849 #endif
1850 	return 1;
1851 }
1852 #endif // 0
1853 
filesys_do_disk_change(int cdunitnum,bool insert)1854 bool filesys_do_disk_change (int cdunitnum, bool insert)
1855 {
1856 	int nr = cdunitnum + cd_unit_offset;
1857 	UnitInfo *ui = &mountinfo.ui[nr];
1858 	Unit *u = ui->self;
1859 
1860 	if (!ui->cd_open)
1861 		return false;
1862 	if (insert) {
1863 		if (filesys_isvolume (u))
1864 			return false;
1865 		filesys_insert (nr, NULL, _T("/"), true, MYVOLUMEINFO_CDFS | MYVOLUMEINFO_READONLY);
1866 		return true;
1867 	} else {
1868 		if (!filesys_isvolume (u))
1869 			return false;
1870 		filesys_eject (nr);
1871 		return true;
1872 	}
1873 }
1874 
1875 /* flags and comments supported? */
fsdb_cando(Unit * unit)1876 static int fsdb_cando (Unit *unit)
1877 {
1878 	if (unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS))
1879 		return 1;
1880 	if (currprefs.filesys_custom_uaefsdb  && (unit->volflags & MYVOLUMEINFO_STREAMS))
1881 		return 1;
1882 	if (!currprefs.filesys_no_uaefsdb)
1883 		return 1;
1884 	return 0;
1885 }
1886 
prepare_for_open(TCHAR * name)1887 static void prepare_for_open (TCHAR *name)
1888 {
1889 }
1890 
de_recycle_aino(Unit * unit,a_inode * aino)1891 static void de_recycle_aino (Unit *unit, a_inode *aino)
1892 {
1893 	aino_test (aino);
1894 	if (aino->next == 0 || aino == &unit->rootnode)
1895 		return;
1896 	aino->next->prev = aino->prev;
1897 	aino->prev->next = aino->next;
1898 	aino->next = aino->prev = 0;
1899 	unit->aino_cache_size--;
1900 }
1901 
dispose_aino(Unit * unit,a_inode ** aip,a_inode * aino)1902 static void dispose_aino (Unit *unit, a_inode **aip, a_inode *aino)
1903 {
1904 	int hash = aino->uniq % MAX_AINO_HASH;
1905 	if (unit->aino_hash[hash] == aino)
1906 		unit->aino_hash[hash] = 0;
1907 
1908 	if (aino->dirty && aino->parent)
1909 		fsdb_dir_writeback (aino->parent);
1910 
1911 	*aip = aino->sibling;
1912 
1913 	if (unit->volflags & MYVOLUMEINFO_ARCHIVE) {
1914 		;
1915 	}
1916 #ifdef SCSI
1917 	else if (unit->volflags & MYVOLUMEINFO_CDFS) {
1918 		isofs_dispose_inode (unit->ui.cdfs_superblock, aino->uniq_external);
1919 	}
1920 #endif
1921 
1922 	xfree (aino->aname);
1923 	xfree (aino->comment);
1924 	xfree (aino->nname);
1925 	xfree (aino);
1926 }
1927 
free_all_ainos(Unit * u,a_inode * parent)1928 static void free_all_ainos (Unit *u, a_inode *parent)
1929 {
1930 	a_inode *a;
1931 	while ((a = parent->child)) {
1932 		free_all_ainos (u, a);
1933 		dispose_aino (u, &parent->child, a);
1934 	}
1935 }
1936 
flush_cache(Unit * unit,int num)1937 static int flush_cache (Unit *unit, int num)
1938 {
1939 	int i = 0;
1940 	int cnt = 100;
1941 
1942 	//write_log (_T("FILESYS: flushing cache unit %d (max %d items)\n"), unit->unit, num);
1943 	if (num == 0)
1944 		num = -1;
1945 	while (i < num || num < 0) {
1946 		int ii = i;
1947 		a_inode *parent = unit->rootnode.prev->parent;
1948 		a_inode **aip;
1949 
1950 		aip = &parent->child;
1951 		aino_test (parent);
1952 		if (parent && !parent->locked_children) {
1953 			for (;;) {
1954 				a_inode *aino = *aip;
1955 				aino_test (aino);
1956 				if (aino == 0)
1957 					break;
1958 				/* Not recyclable if next == 0 (i.e., not chained into
1959 				recyclable list), or if parent directory is being
1960 				ExNext()ed.  */
1961 				if (aino->next == 0) {
1962 					aip = &aino->sibling;
1963 				} else {
1964 					if (aino->shlock > 0 || aino->elock)
1965 						write_log (_T("panic: freeing locked a_inode!\n"));
1966 					de_recycle_aino (unit, aino);
1967 					dispose_aino (unit, aip, aino);
1968 					i++;
1969 				}
1970 			}
1971 		}
1972 		{ //if (unit->rootnode.next != unit->rootnode.prev) {
1973 			/* In the previous loop, we went through all children of one
1974 			parent.  Re-arrange the recycled list so that we'll find a
1975 			different parent the next time around.
1976 			(infinite loop if there is only one parent?)
1977 			*/
1978 			int maxloop = 10000;
1979 			do {
1980 				unit->rootnode.next->prev = unit->rootnode.prev;
1981 				unit->rootnode.prev->next = unit->rootnode.next;
1982 				unit->rootnode.next = unit->rootnode.prev;
1983 				unit->rootnode.prev = unit->rootnode.prev->prev;
1984 				unit->rootnode.prev->next = unit->rootnode.next->prev = &unit->rootnode;
1985 			} while (unit->rootnode.prev->parent == parent && maxloop-- > 0);
1986 		}
1987 		if (i == ii)
1988 			cnt--;
1989 		if (cnt <= 0)
1990 			break;
1991 	}
1992 	return unit->aino_cache_size > 0 ? 0 : 1;
1993 }
1994 
recycle_aino(Unit * unit,a_inode * new_aino)1995 static void recycle_aino (Unit *unit, a_inode *new_aino)
1996 {
1997 	aino_test (new_aino);
1998 	if (new_aino->dir || new_aino->shlock > 0
1999 		|| new_aino->elock || new_aino == &unit->rootnode)
2000 		/* Still in use */
2001 		return;
2002 
2003 	TRACE3((_T("Recycling; cache size %d, total_locked %d\n"),
2004 		unit->aino_cache_size, unit->total_locked_ainos));
2005 	if (unit->aino_cache_size > 5000 + unit->total_locked_ainos) {
2006 		/* Reap a few. */
2007 		flush_cache (unit, 50);
2008 #if 0
2009 		{
2010 			TCHAR buffer[40];
2011 			_stprintf (buffer, "%d ainos reaped.\n", i);
2012 			TRACE ((buffer));
2013 		}
2014 #endif
2015 	}
2016 
2017 	aino_test (new_aino);
2018 	/* Chain it into circular list. */
2019 	new_aino->next = unit->rootnode.next;
2020 	new_aino->prev = &unit->rootnode;
2021 	new_aino->prev->next = new_aino;
2022 	new_aino->next->prev = new_aino;
2023 	aino_test (new_aino->next);
2024 	aino_test (new_aino->prev);
2025 
2026 	unit->aino_cache_size++;
2027 }
2028 
filesys_flush_cache(void)2029 void filesys_flush_cache (void)
2030 {
2031 }
2032 
update_child_names(Unit * unit,a_inode * a,a_inode * parent)2033 static void update_child_names (Unit *unit, a_inode *a, a_inode *parent)
2034 {
2035 	int l0 = _tcslen (parent->nname) + 2;
2036 
2037 	while (a != 0) {
2038 		TCHAR *name_start;
2039 		TCHAR *new_name;
2040 		TCHAR dirsep[2] = { FSDB_DIR_SEPARATOR, '\0' };
2041 
2042 		a->parent = parent;
2043 		name_start = _tcsrchr (a->nname, FSDB_DIR_SEPARATOR);
2044 		if (name_start == 0) {
2045 			write_log (_T("malformed file name"));
2046 		}
2047 		name_start++;
2048 		new_name = xmalloc (TCHAR, _tcslen (name_start) + l0);
2049 		_tcscpy (new_name, parent->nname);
2050 		_tcscat (new_name, dirsep);
2051 		_tcscat (new_name, name_start);
2052 		xfree (a->nname);
2053 		a->nname = new_name;
2054 		if (a->child)
2055 			update_child_names (unit, a->child, a);
2056 		a = a->sibling;
2057 	}
2058 }
2059 
move_aino_children(Unit * unit,a_inode * from,a_inode * to)2060 static void move_aino_children (Unit *unit, a_inode *from, a_inode *to)
2061 {
2062 	aino_test (from);
2063 	aino_test (to);
2064 	to->child = from->child;
2065 	from->child = 0;
2066 	update_child_names (unit, to->child, to);
2067 }
2068 
delete_aino(Unit * unit,a_inode * aino)2069 static void delete_aino (Unit *unit, a_inode *aino)
2070 {
2071 	a_inode **aip;
2072 
2073 	TRACE((_T("deleting aino %x\n"), aino->uniq));
2074 
2075 	aino_test (aino);
2076 	aino->dirty = 1;
2077 	aino->deleted = 1;
2078 	de_recycle_aino (unit, aino);
2079 
2080 	/* If any ExKeys are currently pointing at us, advance them.  */
2081 	if (aino->parent->exnext_count > 0) {
2082 		int i;
2083 		TRACE((_T("entering exkey validation\n")));
2084 		for (i = 0; i < EXKEYS; i++) {
2085 			ExamineKey *k = unit->examine_keys + i;
2086 			if (k->uniq == 0)
2087 				continue;
2088 			if (k->aino == aino->parent) {
2089 				TRACE((_T("Same parent found for %d\n"), i));
2090 				if (k->curr_file == aino) {
2091 					k->curr_file = aino->sibling;
2092 					TRACE((_T("Advancing curr_file\n")));
2093 				}
2094 			}
2095 		}
2096 	}
2097 
2098 	aip = &aino->parent->child;
2099 	while (*aip != aino && *aip != 0)
2100 		aip = &(*aip)->sibling;
2101 	if (*aip != aino) {
2102 		write_log (_T("Couldn't delete aino.\n"));
2103 		return;
2104 	}
2105 	dispose_aino (unit, aip, aino);
2106 }
2107 
lookup_sub(a_inode * dir,uae_u32 uniq)2108 static a_inode *lookup_sub (a_inode *dir, uae_u32 uniq)
2109 {
2110 	a_inode **cp = &dir->child;
2111 	a_inode *c, *retval;
2112 
2113 	for (;;) {
2114 		c = *cp;
2115 		if (c == 0)
2116 			return 0;
2117 
2118 		if (c->uniq == uniq) {
2119 			retval = c;
2120 			break;
2121 		}
2122 		if (c->dir) {
2123 			a_inode *a = lookup_sub (c, uniq);
2124 			if (a != 0) {
2125 				retval = a;
2126 				break;
2127 			}
2128 		}
2129 		cp = &c->sibling;
2130 	}
2131 	if (! dir->locked_children) {
2132 		/* Move to the front to speed up repeated lookups.  Don't do this if
2133 		an ExNext is going on in this directory, or we'll terminally
2134 		confuse it.  */
2135 		*cp = c->sibling;
2136 		c->sibling = dir->child;
2137 		dir->child = c;
2138 	}
2139 	return retval;
2140 }
2141 
lookup_aino(Unit * unit,uae_u32 uniq)2142 static a_inode *lookup_aino (Unit *unit, uae_u32 uniq)
2143 {
2144 	a_inode *a;
2145 	int hash = uniq % MAX_AINO_HASH;
2146 
2147 	if (uniq == 0)
2148 		return &unit->rootnode;
2149 	a = unit->aino_hash[hash];
2150 	if (a == 0 || a->uniq != uniq)
2151 		a = lookup_sub (&unit->rootnode, uniq);
2152 	else
2153 		unit->nr_cache_hits++;
2154 	unit->nr_cache_lookups++;
2155 	unit->aino_hash[hash] = a;
2156 	aino_test (a);
2157 	return a;
2158 }
2159 
aino_from_lock(Unit * unit,uaecptr lock)2160 static a_inode *aino_from_lock (Unit *unit, uaecptr lock)
2161 {
2162 	return lookup_aino (unit, get_long (lock + 4));
2163 }
2164 
build_nname(const TCHAR * d,const TCHAR * n)2165 TCHAR *build_nname (const TCHAR *d, const TCHAR *n)
2166 {
2167 	TCHAR dsep[2] = { FSDB_DIR_SEPARATOR, 0 };
2168 	TCHAR *p = xmalloc (TCHAR, _tcslen (d) + 1 + _tcslen (n) + 1);
2169 	_tcscpy (p, d);
2170 	_tcscat (p, dsep);
2171 	_tcscat (p, n);
2172 	return p;
2173 }
2174 
build_aname(const TCHAR * d,const TCHAR * n)2175 TCHAR *build_aname (const TCHAR *d, const TCHAR *n)
2176 {
2177 	TCHAR *p = xmalloc (TCHAR, _tcslen (d) + 1 + _tcslen (n) + 1);
2178 	_tcscpy (p, d);
2179 	_tcscat (p, _T("/"));
2180 	_tcscat (p, n);
2181 	return p;
2182 }
2183 
2184 /* This gets called to translate an Amiga name that some program used to
2185 * a name that we can use on the native filesystem.  */
get_nname(Unit * unit,a_inode * base,TCHAR * rel,TCHAR ** modified_rel,uae_u64 * uniq_ext)2186 static TCHAR *get_nname (Unit *unit, a_inode *base, TCHAR *rel, TCHAR **modified_rel, uae_u64 *uniq_ext)
2187 {
2188 	TCHAR *found;
2189 /* REMOVEME:
2190  * nowhere used
2191  */
2192 #if 0
2193 	TCHAR *p = 0;
2194 #endif
2195 
2196 	*modified_rel = 0;
2197 
2198 	if (unit->volflags & MYVOLUMEINFO_ARCHIVE) {
2199 		if (zfile_exists_archive(base->nname, rel))
2200 			return build_nname(base->nname, rel);
2201 		return NULL;
2202 	}
2203 #ifdef SCSI
2204 	 else if (unit->volflags & MYVOLUMEINFO_CDFS) {
2205 		if (isofs_exists (unit->ui.cdfs_superblock, base->uniq_external, rel, uniq_ext))
2206 			return build_nname (base->nname, rel);
2207 		return NULL;
2208 	}
2209 #endif
2210 
2211 	aino_test (base);
2212 
2213 	/* If we have a mapping of some other aname to "rel", we must pretend
2214 	* it does not exist.
2215 	* This can happen for example if an Amiga program creates a
2216 	* file called ".".  We can't represent this in our filesystem,
2217 	* so we create a special file "uae_xxx" and record the mapping
2218 	* aname "." -> nname "uae_xxx" in the database.  Then, the Amiga
2219 	* program looks up "uae_xxx" (yes, it's contrived).  The filesystem
2220 	* should not make the uae_xxx file visible to the Amiga side.  */
2221 	if (fsdb_used_as_nname (base, rel))
2222 		return 0;
2223 	/* A file called "." (or whatever else is invalid on this filesystem)
2224 	* does not exist, as far as the Amiga side is concerned.  */
2225 	if (fsdb_name_invalid_dir (rel))
2226 		return 0;
2227 
2228 	/* See if we have a file that has the same name as the aname we are
2229 	* looking for.  */
2230 	found = fsdb_search_dir (base->nname, rel);
2231 	if (found == 0)
2232 		return found;
2233 	if (found == rel)
2234 		return build_nname (base->nname, rel);
2235 
2236 	*modified_rel = found;
2237 	return build_nname (base->nname, found);
2238 }
2239 
create_nname(Unit * unit,a_inode * base,TCHAR * rel)2240 static TCHAR *create_nname (Unit *unit, a_inode *base, TCHAR *rel)
2241 {
2242 	TCHAR *p;
2243 
2244 	aino_test (base);
2245 	/* We are trying to create a file called REL.  */
2246 
2247 	/* If the name is used otherwise in the directory (or globally), we
2248 	* need a new unique nname.  */
2249 	if (fsdb_name_invalid (rel) || fsdb_used_as_nname (base, rel)) {
2250 #if 0
2251 oh_dear:
2252 #endif
2253 		if (currprefs.filesys_no_uaefsdb && !(base->volflags & MYVOLUMEINFO_STREAMS)) {
2254 			write_log (_T("illegal filename '%s', no stream supporting filesystem and uaefsdb disabled\n"), rel);
2255 			return 0;
2256 		}
2257 		p = fsdb_create_unique_nname (base, rel);
2258 		return p;
2259 	}
2260 	p = build_nname (base->nname, rel);
2261 #if 0
2262 	/* Delete this code once we know everything works.  */
2263 	if (access (p, R_OK) >= 0 || errno != ENOENT) {
2264 		write_log (_T("Filesystem in trouble... please report.\n"));
2265 		xfree (p);
2266 		goto oh_dear;
2267 	}
2268 #endif
2269 	return p;
2270 }
2271 
fill_file_attrs(Unit * u,a_inode * base,a_inode * c)2272 static int fill_file_attrs (Unit *u, a_inode *base, a_inode *c)
2273 {
2274 	if (u->volflags & MYVOLUMEINFO_ARCHIVE) {
2275 		int isdir, flags;
2276 		TCHAR *comment;
2277 		zfile_fill_file_attrs_archive (c->nname, &isdir, &flags, &comment);
2278 		c->dir = isdir;
2279 		c->amigaos_mode = 0;
2280 		if (flags >= 0)
2281 			c->amigaos_mode = flags;
2282 		c->comment = comment;
2283 		return 1;
2284 	} else if (u->volflags & MYVOLUMEINFO_CDFS) {
2285 #ifdef SCSI
2286 		int isdir, flags;
2287 		TCHAR *comment;
2288 		isofss_fill_file_attrs (u->ui.cdfs_superblock, base->uniq_external, &isdir, &flags, &comment, c->uniq_external);
2289 		c->dir = isdir;
2290 		c->amigaos_mode = 0;
2291 		if (flags >= 0)
2292 			c->amigaos_mode = flags;
2293 		c->comment = comment;
2294 		return 1;
2295 #endif
2296 	} else {
2297 		return fsdb_fill_file_attrs (base, c);
2298 	}
2299 	return 0;
2300 }
2301 
test_softlink(a_inode * aino)2302 static int test_softlink (a_inode *aino)
2303 {
2304 	int err;
2305 	if (aino->softlink && my_resolvesoftlink (aino->nname, -1))
2306 		err = ERROR_IS_SOFT_LINK;
2307 	else
2308 		err = ERROR_OBJECT_NOT_AROUND;
2309 	return err;
2310 }
2311 
handle_softlink(Unit * unit,dpacket packet,a_inode * aino)2312 static void handle_softlink (Unit *unit, dpacket packet, a_inode *aino)
2313 {
2314 	PUT_PCK_RES1 (packet, DOS_FALSE);
2315 	PUT_PCK_RES2 (packet, test_softlink (aino));
2316 }
2317 
2318 /*
2319  * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object
2320  * for which we know the name on the native filesystem, but no corresponding
2321  * Amiga filesystem name.
2322  * @@@ For DOS filesystems, it might make sense to declare the new name
2323  * "weak", so that it can get overriden by a subsequent call to get_nname().
2324  * That way, if someone does "dir :" and there is a file "foobar.inf", and
2325  * someone else tries to open "foobar.info", get_nname() could maybe made to
2326  * figure out that this is supposed to be the file "foobar.inf".
2327  * DOS sucks...
2328  */
get_aname(Unit * unit,a_inode * base,TCHAR * rel)2329 static TCHAR *get_aname (Unit *unit, a_inode *base, TCHAR *rel)
2330 {
2331 	return my_strdup (rel);
2332 }
2333 
init_child_aino_tree(Unit * unit,a_inode * base,a_inode * aino)2334 static void init_child_aino_tree (Unit *unit, a_inode *base, a_inode *aino)
2335 {
2336 	/* Update tree structure */
2337 	aino->parent = base;
2338 	aino->child = 0;
2339 	aino->sibling = base->child;
2340 	base->child = aino;
2341 	aino->next = aino->prev = 0;
2342 	aino->volflags = unit->volflags;
2343 }
2344 
init_child_aino(Unit * unit,a_inode * base,a_inode * aino)2345 static void init_child_aino (Unit *unit, a_inode *base, a_inode *aino)
2346 {
2347 	aino->uniq = ++a_uniq;
2348 	if (a_uniq == 0xFFFFFFFF) {
2349 		write_log (_T("Running out of a_inodes (prepare for big trouble)!\n"));
2350 	}
2351 	aino->shlock = 0;
2352 	aino->elock = 0;
2353 
2354 	aino->dirty = 0;
2355 	aino->deleted = 0;
2356 	aino->mountcount = unit->mountcount;
2357 
2358 	/* For directories - this one isn't being ExNext()ed yet.  */
2359 	aino->locked_children = 0;
2360 	aino->exnext_count = 0;
2361 	/* But the parent might be.  */
2362 	if (base->exnext_count) {
2363 		unit->total_locked_ainos++;
2364 		base->locked_children++;
2365 	}
2366 	init_child_aino_tree (unit, base, aino);
2367 
2368 	aino_test_init (aino);
2369 	aino_test (aino);
2370 }
2371 
new_child_aino(Unit * unit,a_inode * base,TCHAR * rel)2372 static a_inode *new_child_aino (Unit *unit, a_inode *base, TCHAR *rel)
2373 {
2374 	TCHAR *modified_rel;
2375 	TCHAR *nn;
2376 	a_inode *aino = NULL;
2377 	int isvirtual = unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS);
2378 
2379 	TRACE((_T("new_child_aino %s, %s\n"), base->aname, rel));
2380 
2381 	if (!isvirtual)
2382 		aino = fsdb_lookup_aino_aname (base, rel);
2383 	if (aino == 0) {
2384 		uae_u64 uniq_ext = 0;
2385 		nn = get_nname (unit, base, rel, &modified_rel, &uniq_ext);
2386 		if (nn == 0)
2387 			return 0;
2388 
2389 		aino = xcalloc (a_inode, 1);
2390 		if (aino == 0)
2391 			return 0;
2392 		aino->uniq_external = uniq_ext;
2393 		aino->aname = modified_rel ? modified_rel : my_strdup (rel);
2394 		aino->nname = nn;
2395 
2396 		aino->comment = 0;
2397 		aino->has_dbentry = 0;
2398 
2399 		if (!fill_file_attrs (unit, base, aino)) {
2400 			xfree (aino);
2401 			return 0;
2402 		}
2403 		if (aino->dir && !isvirtual)
2404 			fsdb_clean_dir (aino);
2405 	}
2406 	init_child_aino (unit, base, aino);
2407 
2408 	recycle_aino (unit, aino);
2409 	TRACE((_T("created aino %x, lookup, amigaos_mode %d\n"), aino->uniq, aino->amigaos_mode));
2410 	return aino;
2411 }
2412 
create_child_aino(Unit * unit,a_inode * base,TCHAR * rel,int isdir)2413 static a_inode *create_child_aino (Unit *unit, a_inode *base, TCHAR *rel, int isdir)
2414 {
2415 	a_inode *aino = xcalloc (a_inode, 1);
2416 	if (aino == 0)
2417 		return 0;
2418 
2419 	aino->nname = create_nname (unit, base, rel);
2420 	if (!aino->nname) {
2421 		xfree (aino);
2422 		return 0;
2423 	}
2424 	aino->aname = my_strdup (rel);
2425 
2426 	init_child_aino (unit, base, aino);
2427 	aino->amigaos_mode = 0;
2428 	aino->dir = isdir;
2429 
2430 	aino->comment = 0;
2431 	aino->has_dbentry = 0;
2432 	aino->dirty = 1;
2433 
2434 	recycle_aino (unit, aino);
2435 	TRACE((_T("created aino %x, create\n"), aino->uniq));
2436 	return aino;
2437 }
2438 
lookup_child_aino(Unit * unit,a_inode * base,TCHAR * rel,int * err)2439 static a_inode *lookup_child_aino (Unit *unit, a_inode *base, TCHAR *rel, int *err)
2440 {
2441 	a_inode *c = base->child;
2442 	int l0 = _tcslen (rel);
2443 
2444 	aino_test (base);
2445 	aino_test (c);
2446 
2447 	if (base->dir == 0) {
2448 		*err = ERROR_OBJECT_WRONG_TYPE;
2449 		return 0;
2450 	}
2451 
2452 	while (c != 0) {
2453 		int l1 = _tcslen (c->aname);
2454 		if ((l0 <= l1)
2455 			&& same_aname (rel, c->aname + l1 - l0)
2456 			&& ( (l0 == l1) || (c->aname[l1-l0-1] == '/') )
2457 			&& c->mountcount == unit->mountcount)
2458 			break;
2459 		c = c->sibling;
2460 	}
2461 	if (c != 0)
2462 		return c;
2463 	c = new_child_aino (unit, base, rel);
2464 	if (c == 0)
2465 		*err = ERROR_OBJECT_NOT_AROUND;
2466 	return c;
2467 }
2468 
2469 /* Different version because for this one, REL is an nname.  */
lookup_child_aino_for_exnext(Unit * unit,a_inode * base,TCHAR * rel,uae_u32 * err,uae_u64 uniq_external)2470 static a_inode *lookup_child_aino_for_exnext (Unit *unit, a_inode *base, TCHAR *rel, uae_u32 *err, uae_u64 uniq_external)
2471 {
2472 	a_inode *c = base->child;
2473 	int l0 = _tcslen (rel);
2474 	int isvirtual = unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS);
2475 
2476 	aino_test (base);
2477 	aino_test (c);
2478 
2479 	*err = 0;
2480 	while (c != 0) {
2481 		int l1 = _tcslen (c->nname);
2482 		/* Note: using _tcscmp here.  */
2483 		if (l0 <= l1 && _tcscmp (rel, c->nname + l1 - l0) == 0
2484 			&& (l0 == l1 || c->nname[l1-l0-1] == FSDB_DIR_SEPARATOR) && c->mountcount == unit->mountcount)
2485 			break;
2486 		c = c->sibling;
2487 	}
2488 	if (c != 0)
2489 		return c;
2490 	if (!isvirtual)
2491 		c = fsdb_lookup_aino_nname (base, rel);
2492 	if (c == 0) {
2493 		c = xcalloc (a_inode, 1);
2494 		if (c == 0) {
2495 			*err = ERROR_NO_FREE_STORE;
2496 			return 0;
2497 		}
2498 
2499 		c->nname = build_nname (base->nname, rel);
2500 		c->aname = get_aname (unit, base, rel);
2501 		c->comment = 0;
2502 		c->uniq_external = uniq_external;
2503 		c->has_dbentry = 0;
2504 		if (!fill_file_attrs (unit, base, c)) {
2505 			xfree (c);
2506 			*err = ERROR_NO_FREE_STORE;
2507 			return 0;
2508 		}
2509 		if (c->dir && !isvirtual)
2510 			fsdb_clean_dir (c);
2511 	}
2512 	init_child_aino (unit, base, c);
2513 
2514 	recycle_aino (unit, c);
2515 	TRACE((_T("created aino %x, exnext\n"), c->uniq));
2516 
2517 	return c;
2518 }
2519 
get_aino(Unit * unit,a_inode * base,const TCHAR * rel,int * err)2520 static a_inode *get_aino (Unit *unit, a_inode *base, const TCHAR *rel, int *err)
2521 {
2522 	TCHAR *tmp;
2523 	TCHAR *p;
2524 	a_inode *curr, *prev;
2525 	int i;
2526 
2527 	aino_test (base);
2528 
2529 	*err = 0;
2530 	TRACE((_T("get_path(%s,%s)\n"), base->aname, rel));
2531 
2532 	/* root-relative path? */
2533 	for (i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++)
2534 		;
2535 	if (':' == rel[i])
2536 		rel += i+1;
2537 
2538 	tmp = my_strdup (rel);
2539 	p = tmp;
2540 	curr = base;
2541 	prev = NULL;
2542 
2543 	while (*p) {
2544 		/* start with a slash? go up a level. */
2545 		if (*p == '/') {
2546 			if (curr->parent != 0)
2547 				curr = curr->parent;
2548 			p++;
2549 		} else {
2550 			a_inode *next;
2551 
2552 
2553 			if (prev && prev->softlink) {
2554 				*err = test_softlink (prev);
2555 				curr = NULL;
2556 				break;
2557 			}
2558 
2559 			TCHAR *component_end;
2560 			component_end = _tcschr (p, '/');
2561 			if (component_end != 0)
2562 				*component_end = '\0';
2563 			next = lookup_child_aino (unit, curr, p, err);
2564 			if (next == 0) {
2565 				/* if only last component not found, return parent dir. */
2566 				if (*err != ERROR_OBJECT_NOT_AROUND || component_end != 0)
2567 					curr = NULL;
2568 				/* ? what error is appropriate? */
2569 				break;
2570 			}
2571 			prev = next;
2572 			curr = next;
2573 			if (component_end)
2574 				p = component_end+1;
2575 			else
2576 				break;
2577 		}
2578 	}
2579 	xfree (tmp);
2580 	return curr;
2581 }
2582 
2583 
notifyhash(const TCHAR * s)2584 static uae_u32 notifyhash (const TCHAR *s)
2585 {
2586 	uae_u32 hash = 0;
2587 	while (*s)
2588 		hash = (hash << 5) + *s++;
2589 	return hash % NOTIFY_HASH_SIZE;
2590 }
2591 
new_notify(Unit * unit,TCHAR * name)2592 static Notify *new_notify (Unit *unit, TCHAR *name)
2593 {
2594 	Notify *n = xmalloc (Notify, 1);
2595 	uae_u32 hash = notifyhash (name);
2596 	n->next = unit->notifyhash[hash];
2597 	unit->notifyhash[hash] = n;
2598 	n->partname = name;
2599 	return n;
2600 }
2601 
2602 #if 0
2603 static void free_notify_item (Notify *n)
2604 {
2605 	xfree (n->fullname);
2606 	xfree (n->partname);
2607 	xfree (n);
2608 }
2609 #endif
2610 
free_notify(Unit * unit,int hash,Notify * n)2611 static void free_notify (Unit *unit, int hash, Notify *n)
2612 {
2613 	Notify *n1, *prev = 0;
2614 	for (n1 = unit->notifyhash[hash]; n1; n1 = n1->next) {
2615 		if (n == n1) {
2616 			if (prev)
2617 				prev->next = n->next;
2618 			else
2619 				unit->notifyhash[hash] = n->next;
2620 			break;
2621 		}
2622 		prev = n1;
2623 	}
2624 }
2625 
startup_update_unit(Unit * unit,UnitInfo * uinfo)2626 static void startup_update_unit (Unit *unit, UnitInfo *uinfo)
2627 {
2628 	if (!unit)
2629 		return;
2630 	xfree (unit->ui.volname);
2631 	memcpy (&unit->ui, uinfo, sizeof (UnitInfo));
2632 	unit->ui.devname = uinfo->devname;
2633 	unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */
2634 }
2635 
startup_create_unit(UnitInfo * uinfo,int num)2636 static Unit *startup_create_unit (UnitInfo *uinfo, int num)
2637 {
2638 	int i;
2639 	Unit *unit, *u;
2640 
2641 	unit = xcalloc (Unit, 1);
2642 	/* keep list in insertion order */
2643 	u = units;
2644 	if (u) {
2645 		while (u->next)
2646 			u = u->next;
2647 		u->next = unit;
2648 	} else {
2649 		units = unit;
2650 	}
2651 	uinfo->self = unit;
2652 
2653 	unit->volume = 0;
2654 	unit->port = m68k_areg (regs, 5);
2655 	unit->unit = num;
2656 
2657 	startup_update_unit (unit, uinfo);
2658 
2659 	unit->cmds_complete = 0;
2660 	unit->cmds_sent = 0;
2661 	unit->cmds_acked = 0;
2662 	clear_exkeys (unit);
2663 	unit->total_locked_ainos = 0;
2664 	unit->keys = 0;
2665 	for (i = 0; i < NOTIFY_HASH_SIZE; i++) {
2666 		Notify *n = unit->notifyhash[i];
2667 		while (n) {
2668 			Notify *n2 = n;
2669 			n = n->next;
2670 			xfree (n2->fullname);
2671 			xfree (n2->partname);
2672 			xfree (n2);
2673 		}
2674 		unit->notifyhash[i] = 0;
2675 	}
2676 
2677 	unit->rootnode.aname = uinfo->volname;
2678 	unit->rootnode.nname = uinfo->rootdir;
2679 	unit->rootnode.sibling = 0;
2680 	unit->rootnode.next = unit->rootnode.prev = &unit->rootnode;
2681 	unit->rootnode.uniq = 0;
2682 	unit->rootnode.parent = 0;
2683 	unit->rootnode.child = 0;
2684 	unit->rootnode.dir = 1;
2685 	unit->rootnode.amigaos_mode = 0;
2686 	unit->rootnode.shlock = 0;
2687 	unit->rootnode.elock = 0;
2688 	unit->rootnode.comment = 0;
2689 	unit->rootnode.has_dbentry = 0;
2690 	unit->rootnode.volflags = uinfo->volflags;
2691 	aino_test_init (&unit->rootnode);
2692 	unit->aino_cache_size = 0;
2693 	for (i = 0; i < MAX_AINO_HASH; i++)
2694 		unit->aino_hash[i] = 0;
2695 	return unit;
2696 }
2697 
2698 /*
2699 static bool mount_cd (UnitInfo *uinfo, int nr, struct mytimeval *ctime, uae_u64 *uniq)
2700 {
2701 	uinfo->cddevno = nr - cd_unit_offset;
2702 	if (!sys_command_open (uinfo->cddevno)) {
2703 		write_log (_T("Failed attempt to open CD unit %d\n"), uinfo->cddevno);
2704 		return false;
2705 	}
2706 #ifdef RETROPLATFORM
2707 	rp_cd_device_enable (uinfo->cddevno, true);
2708 #endif
2709 	uinfo->cdfs_superblock = isofs_mount(uinfo->cddevno, uniq);
2710 	uinfo->wasisempty = true;
2711 	struct isofs_info ii;
2712 	if (isofs_mediainfo (uinfo->cdfs_superblock, &ii)) {
2713 		xfree (uinfo->volname);
2714 		if (ii.media) {
2715 			uinfo->wasisempty = false;
2716 			if (!ii.unknown_media) {
2717 				uinfo->volname = my_strdup (ii.volumename);
2718 				if (ctime) {
2719 					ctime->tv_sec = ii.creation;
2720 					ctime->tv_usec = 0;
2721 				}
2722 				set_highcyl (uinfo, ii.totalblocks);
2723 #ifdef RETROPLATFORM
2724 				rp_cd_image_change (uinfo->cddevno, ii.devname);
2725 #endif
2726 			}
2727 		}
2728 		uinfo->unknown_media = ii.unknown_media;
2729 	}
2730 	uinfo->cd_open = true;
2731 	return true;
2732 }
2733 */
2734 
2735 #ifdef UAE_FILESYS_THREADS
2736 static void *filesys_thread (void *unit_v);
2737 #endif
filesys_start_thread(UnitInfo * ui,int nr)2738 static void filesys_start_thread (UnitInfo *ui, int nr)
2739 {
2740 	ui->unit_pipe = 0;
2741 	ui->back_pipe = 0;
2742 	ui->reset_state = FS_STARTUP;
2743 	if (!isrestore ()) {
2744 		ui->startup = 0;
2745 		ui->self = 0;
2746 	}
2747 #ifdef UAE_FILESYS_THREADS
2748 	if (is_virtual (nr)) {
2749 		ui->unit_pipe = xmalloc (smp_comm_pipe, 1);
2750 		ui->back_pipe = xmalloc (smp_comm_pipe, 1);
2751 		init_comm_pipe (ui->unit_pipe, 100, 3);
2752 		init_comm_pipe (ui->back_pipe, 100, 1);
2753 		uae_start_thread (_T("filesys"), filesys_thread, (void *)ui, &ui->tid);
2754 	}
2755 #endif
2756 	if (isrestore ()) {
2757 		/*if (ui->unit_type == UNIT_CDFS) {
2758 			mount_cd (ui, nr, NULL, &ui->self->rootnode.uniq_external);
2759 		}*/
2760 		startup_update_unit (ui->self, ui);
2761 	}
2762 }
2763 
2764 
startup_handler(TrapContext * context)2765 static uae_u32 REGPARAM2 startup_handler (TrapContext *context)
2766 {
2767 	/* Just got the startup packet. It's in D3. DosBase is in A2,
2768 	* our allocated volume structure is in A3, A5 is a pointer to
2769 	* our port. */
2770 // REMOVEME:
2771 #if 0
2772 	uaecptr rootnode = get_long (m68k_areg (regs, 2) + 34);
2773 	uaecptr dos_info = get_long (rootnode + 24) << 2;
2774 #endif
2775 	uaecptr pkt = m68k_dreg (regs, 3);
2776 	//uaecptr arg1 = get_long (pkt + dp_Arg1);
2777 	uaecptr arg2 = get_long (pkt + dp_Arg2);
2778 	//uaecptr arg3 = get_long (pkt + dp_Arg3);
2779 	// 1.3:
2780 	// dp_Arg1 contains crap (Should be name of device)
2781 	// dp_Arg2 = works as documented
2782 	// dp_Arg3 = NULL (!?). (Should be DeviceNode)
2783 	uaecptr devnode;
2784 	int nr;
2785 	Unit *unit;
2786 	UnitInfo *uinfo;
2787 	int late = 0;
2788 	int ed = 0, ef = 0;
2789 	uae_u64 uniq = 0;
2790 	uae_u32 cdays;
2791 	struct mytimeval ctime = { 0 };
2792 
2793 	for (nr = 0; nr < MAX_FILESYSTEM_UNITS; nr++) {
2794 		/* Hardfile volume name? */
2795 		if (!mountinfo.ui[nr].open)
2796 			continue;
2797 		if (!is_virtual (nr))
2798 			continue;
2799 		if (mountinfo.ui[nr].startup == arg2)
2800 			break;
2801 	}
2802 
2803 	if (nr == MAX_FILESYSTEM_UNITS) {
2804 		write_log (_T("Attempt to mount unknown filesystem device\n"));
2805 		put_long (pkt + dp_Res1, DOS_FALSE);
2806 		put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
2807 		return 0;
2808 	}
2809 	uinfo = mountinfo.ui + nr;
2810 	//devnode = arg3 << 2;
2811 	devnode = uinfo->devicenode;
2812 	cdays = 3800 + nr;
2813 
2814 	if (uinfo->unit_type == UNIT_CDFS) {
2815 #ifdef SCSI
2816 		ed = ef = 0;
2817 /*		if (!mount_cd (uinfo, nr, &ctime, &uniq)) {
2818 			put_long (pkt + dp_Res1, DOS_FALSE);
2819 			put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
2820 			return 0;
2821 		}*/
2822 #endif
2823 	} else {
2824 	ed = my_existsdir (uinfo->rootdir);
2825 	ef = my_existsfile (uinfo->rootdir);
2826 		if (!uinfo->wasisempty && !ef && !ed) {
2827 			write_log (_T("Failed attempt to mount device '%s' (%s)\n"), uinfo->devname, uinfo->rootdir);
2828 		put_long (pkt + dp_Res1, DOS_FALSE);
2829 		put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
2830 		return 0;
2831 	}
2832 	}
2833 
2834 	if (!uinfo->unit_pipe) {
2835 		late = 1;
2836 		filesys_start_thread (uinfo, nr);
2837 	}
2838 	unit = startup_create_unit (uinfo, nr);
2839 	unit->volflags = uinfo->volflags;
2840 	unit->rootnode.uniq_external = uniq;
2841 
2842 	/*    write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/
2843 
2844 	write_log (_T("FS: %s (flags=%08X,E=%d,ED=%d,EF=%d,native='%s') starting..\n"),
2845 		unit->ui.volname, unit->volflags, uinfo->wasisempty, ed, ef, unit->ui.rootdir);
2846 
2847 	/* fill in our process in the device node */
2848 	put_long (devnode + 8, unit->port);
2849 	unit->dosbase = m68k_areg (regs, 2);
2850 
2851 	/* make new volume */
2852 	unit->volume = m68k_areg (regs, 3) + 32;
2853 	put_long (unit->volume + 180 - 32, devnode);
2854 #ifdef UAE_FILESYS_THREADS
2855 	unit->locklist = m68k_areg (regs, 3) + 8;
2856 #else
2857 	unit->locklist = m68k_areg (regs, 3);
2858 #endif
2859 	unit->dummy_message = m68k_areg (regs, 3) + 12;
2860 
2861 	put_long (unit->dummy_message + 10, 0);
2862 
2863 	/* Prepare volume information */
2864 	put_long (unit->volume + 4, 2); /* Type = dt_volume */
2865 	put_long (unit->volume + 12, 0); /* Lock */
2866 	put_long (unit->volume + 16, cdays); /* Creation Date */
2867 	put_long (unit->volume + 20, 0);
2868 	put_long (unit->volume + 24, 0);
2869 	put_long (unit->volume + 28, 0); /* lock list */
2870 	put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
2871 
2872 	put_byte (unit->volume + 44, 0);
2873 	if (!uinfo->wasisempty && !uinfo->unknown_media) {
2874 		int isvirtual = unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS);
2875 		/* Set volume if non-empty */
2876 		set_volume_name (unit, &ctime);
2877 		if (!isvirtual)
2878 			fsdb_clean_dir (&unit->rootnode);
2879 	}
2880 
2881 	put_long (unit->volume + 8, unit->port);
2882 	put_long (unit->volume + 32, uinfo->unit_type == UNIT_CDFS ? DISK_TYPE_DOS : DISK_TYPE_DOS_FFS);
2883 
2884 	put_long (pkt + dp_Res1, DOS_TRUE);
2885 
2886 	return 1 | (late ? 2 : 0);
2887 }
2888 
2889 static void
do_info(Unit * unit,dpacket packet,uaecptr info,bool disk_info)2890 	do_info (Unit *unit, dpacket packet, uaecptr info, bool disk_info)
2891 {
2892 	struct fs_usage fsu;
2893 	int ret, err = ERROR_NO_FREE_STORE;
2894 	int blocksize, nr;
2895 	uae_u32 dostype;
2896 	bool fs = false, media = false;
2897 
2898 	blocksize = 512;
2899 	/* not FFS because it is not understood by WB1.x C:Info */
2900 	dostype = DISK_TYPE_DOS;
2901 	nr = unit->unit;
2902 	if (unit->volflags & MYVOLUMEINFO_ARCHIVE) {
2903 		ret = zfile_fs_usage_archive (unit->ui.rootdir, 0, &fsu);
2904 		fs = true;
2905 		media = filesys_isvolume (unit) != 0;
2906 #ifdef SCSI
2907 	} else if (unit->volflags & MYVOLUMEINFO_CDFS) {
2908 		struct isofs_info ii;
2909 		ret = isofs_mediainfo (unit->ui.cdfs_superblock, &ii) ? 0 : 1;
2910 		if (!ret) {
2911 			media = ii.media;
2912 			nr = unit->unit - cd_unit_offset;
2913 			blocksize = ii.blocksize;
2914 			if (ii.media) {
2915 				fsu.fsu_blocks = ii.blocks;
2916 				fsu.fsu_bavail = 0;
2917 			}
2918 		}
2919 #endif
2920 	} else {
2921 		ret = get_fs_usage (unit->ui.rootdir, 0, &fsu);
2922 		if (ret)
2923 			err = dos_errno ();
2924 		fs = true;
2925 		media = filesys_isvolume (unit) != 0;
2926 	}
2927 	if (ret != 0) {
2928 		PUT_PCK_RES1 (packet, DOS_FALSE);
2929 		PUT_PCK_RES2 (packet, err);
2930 		return;
2931 	}
2932 	put_long (info, 0); /* errors */
2933 	put_long (info + 4, nr); /* unit number */
2934 	put_long (info + 8, unit->ui.readonly || unit->ui.locked ? 80 : 82); /* state  */
2935 	put_long (info + 20, blocksize); /* bytesperblock */
2936 	put_long (info + 32, 0); /* inuse */
2937 	if (unit->ui.unknown_media) {
2938 		if (!disk_info) {
2939 			PUT_PCK_RES1 (packet, DOS_FALSE);
2940 			PUT_PCK_RES2 (packet, ERROR_NOT_A_DOS_DISK);
2941 			return;
2942 		}
2943 		put_long (info + 12, 0);
2944 		put_long (info + 16, 0);
2945 		put_long (info + 24, ('B' << 24) | ('A' << 16) | ('D' << 8) | (0 << 0)); /* ID_UNREADABLE_DISK */
2946 		put_long (info + 28, 0);
2947 	} else if (!media) {
2948 		if (!disk_info) {
2949 			PUT_PCK_RES1 (packet, DOS_FALSE);
2950 			PUT_PCK_RES2 (packet, ERROR_NO_DISK);
2951 			return;
2952 		}
2953 		put_long (info + 12, 0);
2954 		put_long (info + 16, 0);
2955 		put_long (info + 24, -1); /* ID_NO_DISK_PRESENT */
2956 		put_long (info + 28, 0);
2957 	} else {
2958 		if (fs && currprefs.filesys_limit) {
2959 			if (fsu.fsu_blocks > (uae_u64)currprefs.filesys_limit * 1024 / blocksize) {
2960 				uae_u32 oldblocks = fsu.fsu_blocks;
2961 				fsu.fsu_blocks = (uae_u32)((uae_u64)currprefs.filesys_limit * 1024 / blocksize);
2962 				fsu.fsu_bavail = (uae_u32)((uae_u64)fsu.fsu_bavail * fsu.fsu_blocks / oldblocks);
2963 			}
2964 		}
2965 		put_long (info + 12, fsu.fsu_blocks ); /* numblocks */
2966 		put_long (info + 16, fsu.fsu_blocks - fsu.fsu_bavail); /* inuse */
2967 		put_long (info + 24, dostype); /* disk type */
2968 		put_long (info + 28, unit->volume >> 2); /* volume node */
2969 		put_long (info + 32, (get_long (unit->volume + 28) || unit->keys) ? -1 : 0); /* inuse */
2970 	}
2971 	PUT_PCK_RES1 (packet, DOS_TRUE);
2972 }
2973 
2974 static void
action_disk_info(Unit * unit,dpacket packet)2975 	action_disk_info (Unit *unit, dpacket packet)
2976 {
2977 	TRACE((_T("ACTION_DISK_INFO\n")));
2978 	do_info (unit, packet, GET_PCK_ARG1 (packet) << 2, true);
2979 }
2980 
2981 static void
action_info(Unit * unit,dpacket packet)2982 	action_info (Unit *unit, dpacket packet)
2983 {
2984 	TRACE((_T("ACTION_INFO\n")));
2985 	do_info (unit, packet, GET_PCK_ARG2 (packet) << 2, false);
2986 }
2987 
free_key(Unit * unit,Key * k)2988 static void free_key (Unit *unit, Key *k)
2989 {
2990 	Key *k1;
2991 	Key *prev = 0;
2992 	for (k1 = unit->keys; k1; k1 = k1->next) {
2993 		if (k == k1) {
2994 			if (prev)
2995 				prev->next = k->next;
2996 			else
2997 				unit->keys = k->next;
2998 			break;
2999 		}
3000 		prev = k1;
3001 	}
3002 
3003 	struct lockrecord *lr;
3004 	for (lr = k->record; lr;) {
3005 		struct lockrecord *next = lr->next;
3006 		xfree (lr);
3007 		lr = next;
3008 	}
3009 
3010 	if (k->fd != NULL)
3011 		fs_closefile (k->fd);
3012 
3013 	xfree(k);
3014 }
3015 
lookup_key(Unit * unit,uae_u32 uniq)3016 static Key *lookup_key (Unit *unit, uae_u32 uniq)
3017 {
3018 	Key *k;
3019 	unsigned int total = 0;
3020 	/* It's hardly worthwhile to optimize this - most of the time there are
3021 	* only one or zero keys. */
3022 	for (k = unit->keys; k; k = k->next) {
3023 		total++;
3024 		if (uniq == k->uniq)
3025 			return k;
3026 	}
3027 	write_log (_T("Error: couldn't find key %u / %u!\n"), uniq, total);
3028 	return 0;
3029 }
3030 
new_key(Unit * unit)3031 static Key *new_key (Unit *unit)
3032 {
3033 	Key *k = xcalloc (Key, 1);
3034 	k->uniq = ++key_uniq;
3035 	k->fd = NULL;
3036 	k->file_pos = 0;
3037 	k->next = unit->keys;
3038 	unit->keys = k;
3039 
3040 	return k;
3041 }
3042 
3043 #if TRACING_ENABLED
3044 static void
dumplock(Unit * unit,uaecptr lock)3045 	dumplock (Unit *unit, uaecptr lock)
3046 {
3047 	a_inode *a;
3048 	TRACE((_T("LOCK: 0x%lx"), lock));
3049 	if (!lock) {
3050 		TRACE((_T("\n")));
3051 		return;
3052 	}
3053 	TRACE((_T("{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx "),
3054 		get_long (lock) << 2, get_long (lock+8),
3055 		get_long (lock+12), get_long (lock+16),
3056 		get_long (lock + 4)));
3057 	a = aino_from_lock (unit, lock);
3058 	if (a == 0) {
3059 		TRACE((_T("not found!")));
3060 	} else {
3061 		TRACE((_T("%s"), a->nname));
3062 	}
3063 	TRACE((_T(" }\n")));
3064 }
3065 #endif
3066 
find_aino(Unit * unit,uaecptr lock,const TCHAR * name,int * err)3067 static a_inode *find_aino (Unit *unit, uaecptr lock, const TCHAR *name, int *err)
3068 {
3069 	a_inode *a;
3070 
3071 	if (lock) {
3072 		a_inode *olda = aino_from_lock (unit, lock);
3073 		if (olda == 0) {
3074 			/* That's the best we can hope to do. */
3075 			a = get_aino (unit, &unit->rootnode, name, err);
3076 		} else {
3077 			TRACE((_T("aino: 0x%08lx"), (unsigned long int)olda->uniq));
3078 			TRACE((_T(" \"%s\"\n"), olda->nname));
3079 			a = get_aino (unit, olda, name, err);
3080 		}
3081 	} else {
3082 		a = get_aino (unit, &unit->rootnode, name, err);
3083 	}
3084 	if (a) {
3085 		TRACE((_T("aino=\"%s\"\n"), a->nname));
3086 	}
3087 	aino_test (a);
3088 	return a;
3089 }
3090 
make_lock(Unit * unit,uae_u32 uniq,long mode)3091 static uaecptr make_lock (Unit *unit, uae_u32 uniq, long mode)
3092 {
3093 	/* allocate lock from the list kept by the assembly code */
3094 	uaecptr lock;
3095 
3096 	lock = get_long (unit->locklist);
3097 	put_long (unit->locklist, get_long (lock));
3098 	lock += 4;
3099 
3100 	put_long (lock + 4, uniq);
3101 	put_long (lock + 8, mode);
3102 	put_long (lock + 12, unit->port);
3103 	put_long (lock + 16, unit->volume >> 2);
3104 
3105 	/* prepend to lock chain */
3106 	put_long (lock, get_long (unit->volume + 28));
3107 	put_long (unit->volume + 28, lock >> 2);
3108 
3109 	DUMPLOCK(unit, lock);
3110 	return lock;
3111 }
3112 
3113 #define NOTIFY_CLASS	0x40000000
3114 #define NOTIFY_CODE	0x1234
3115 
3116 #ifndef TARGET_AMIGAOS
3117 #define NRF_SEND_MESSAGE 1
3118 #define NRF_SEND_SIGNAL 2
3119 #define NRF_WAIT_REPLY 8
3120 #define NRF_NOTIFY_INITIAL 16
3121 #define NRF_MAGIC (1 << 31)
3122 #endif
3123 
notify_send(Unit * unit,Notify * n)3124 static void notify_send (Unit *unit, Notify *n)
3125 {
3126 	uaecptr nr = n->notifyrequest;
3127 	int flags = get_long (nr + 12);
3128 
3129 	if (flags & NRF_SEND_MESSAGE) {
3130 		if (!(flags & NRF_WAIT_REPLY) || ((flags & NRF_WAIT_REPLY) && !(flags & NRF_MAGIC))) {
3131 			uae_NotificationHack (unit->port, nr);
3132 		} else if (flags & NRF_WAIT_REPLY) {
3133 			put_long (nr + 12, get_long (nr + 12) | NRF_MAGIC);
3134 		}
3135 	} else if (flags & NRF_SEND_SIGNAL) {
3136 		uae_Signal (get_long (nr + 16), 1 << get_byte (nr + 20));
3137 	}
3138 }
3139 
notify_check(Unit * unit,a_inode * a)3140 static void notify_check (Unit *unit, a_inode *a)
3141 {
3142 	Notify *n;
3143 	int hash = notifyhash (a->aname);
3144 	for (n = unit->notifyhash[hash]; n; n = n->next) {
3145 /* REMOVEME:
3146  * nowhere used
3147  */
3148 #if 0
3149 		uaecptr nr = n->notifyrequest;
3150 #endif
3151 		if (same_aname (n->partname, a->aname)) {
3152 			int err;
3153 			a_inode *a2 = find_aino (unit, 0, n->fullname, &err);
3154 			if (err == 0 && a == a2)
3155 				notify_send (unit, n);
3156 		}
3157 	}
3158 	if (a->parent) {
3159 		hash = notifyhash (a->parent->aname);
3160 		for (n = unit->notifyhash[hash]; n; n = n->next) {
3161 // REMOVEME:
3162 #if 0
3163 			uaecptr nr = n->notifyrequest;
3164 #endif
3165 			if (same_aname (n->partname, a->parent->aname)) {
3166 				int err;
3167 				a_inode *a2 = find_aino (unit, 0, n->fullname, &err);
3168 				if (err == 0 && a->parent == a2)
3169 					notify_send (unit, n);
3170 			}
3171 		}
3172 	}
3173 }
3174 
3175 static void
action_add_notify(Unit * unit,dpacket packet)3176 	action_add_notify (Unit *unit, dpacket packet)
3177 {
3178 	uaecptr nr = GET_PCK_ARG1 (packet);
3179 	int flags;
3180 	Notify *n;
3181 	TCHAR *name, *p, *partname;
3182 
3183 	TRACE((_T("ACTION_ADD_NOTIFY\n")));
3184 
3185 	name = my_strdup (char1 (get_long (nr + 4)));
3186 	flags = get_long (nr + 12);
3187 
3188 	if (!(flags & (NRF_SEND_MESSAGE | NRF_SEND_SIGNAL))) {
3189 		PUT_PCK_RES1 (packet, DOS_FALSE);
3190 		PUT_PCK_RES2 (packet, ERROR_BAD_NUMBER);
3191 		return;
3192 	}
3193 
3194 #if 0
3195 	write_log (_T("Notify:\n"));
3196 	write_log (_T("nr_Name '%s'\n"), char1 (get_long (nr + 0)));
3197 	write_log (_T("nr_FullName '%s'\n"), name);
3198 	write_log (_T("nr_UserData %08X\n"), get_long (nr + 8));
3199 	write_log (_T("nr_Flags %08X\n"), flags);
3200 	if (flags & NRF_SEND_MESSAGE) {
3201 		write_log (_T("Message NotifyRequest, port = %08X\n"), get_long (nr + 16));
3202 	} else if (flags & NRF_SEND_SIGNAL) {
3203 		write_log (_T("Signal NotifyRequest, Task = %08X signal = %d\n"), get_long (nr + 16), get_long (nr + 20));
3204 	} else {
3205 		write_log (_T("corrupt NotifyRequest\n"));
3206 	}
3207 #endif
3208 
3209 	p = name + _tcslen (name) - 1;
3210 	if (p[0] == ':')
3211 		p--;
3212 	while (p > name && p[0] != ':' && p[0] != '/')
3213 		p--;
3214 	if (p[0] == ':' || p[0] == '/')
3215 		p++;
3216 	partname = my_strdup (p);
3217 	n = new_notify (unit, partname);
3218 	n->notifyrequest = nr;
3219 	n->fullname = name;
3220 	if (flags & NRF_NOTIFY_INITIAL) {
3221 		int err;
3222 // REMOVEME:
3223 #if 0
3224 		a_inode *a = find_aino (unit, 0, n->fullname, &err);
3225 #else
3226 		find_aino (unit, 0, n->fullname, &err);
3227 #endif
3228 		if (err == 0)
3229 			notify_send (unit, n);
3230 	}
3231 	PUT_PCK_RES1 (packet, DOS_TRUE);
3232 }
3233 static void
action_remove_notify(Unit * unit,dpacket packet)3234 	action_remove_notify (Unit *unit, dpacket packet)
3235 {
3236 	uaecptr nr = GET_PCK_ARG1 (packet);
3237 	Notify *n;
3238 	int hash;
3239 
3240 	TRACE((_T("ACTION_REMOVE_NOTIFY\n")));
3241 	for (hash = 0; hash < NOTIFY_HASH_SIZE; hash++) {
3242 		for (n = unit->notifyhash[hash]; n; n = n->next) {
3243 			if (n->notifyrequest == nr) {
3244 				//write_log (_T("NotifyRequest %08X freed\n"), n->notifyrequest);
3245 				xfree (n->fullname);
3246 				xfree (n->partname);
3247 				free_notify (unit, hash, n);
3248 				PUT_PCK_RES1 (packet, DOS_TRUE);
3249 				return;
3250 			}
3251 		}
3252 	}
3253 	write_log (_T("Tried to free non-existing NotifyRequest %08X\n"), nr);
3254 	PUT_PCK_RES1 (packet, DOS_TRUE);
3255 }
3256 
free_lock(Unit * unit,uaecptr lock)3257 static void free_lock (Unit *unit, uaecptr lock)
3258 {
3259 	if (! lock)
3260 		return;
3261 
3262 	if (lock == get_long (unit->volume + 28) << 2) {
3263 		put_long (unit->volume + 28, get_long (lock));
3264 	} else {
3265 		uaecptr current = get_long (unit->volume + 28);
3266 		uaecptr next = 0;
3267 		while (current) {
3268 			next = get_long (current << 2);
3269 			if (lock == next << 2)
3270 				break;
3271 			current = next;
3272 		}
3273 		if (!current) {
3274 			write_log (_T("tried to unlock non-existing lock %x\n"), lock);
3275 			return;
3276 		}
3277 		put_long (current << 2, get_long (lock));
3278 	}
3279 	lock -= 4;
3280 	put_long (lock, get_long (unit->locklist));
3281 	put_long (unit->locklist, lock);
3282 }
3283 
3284 static void
action_lock(Unit * unit,dpacket packet)3285 	action_lock (Unit *unit, dpacket packet)
3286 {
3287 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
3288 	uaecptr name = GET_PCK_ARG2 (packet) << 2;
3289 	long mode = GET_PCK_ARG3 (packet);
3290 	a_inode *a;
3291 	int err;
3292 
3293 	if (mode != SHARED_LOCK && mode != EXCLUSIVE_LOCK) {
3294 		TRACE((_T("Bad mode %d (should be %d or %d).\n"), mode, SHARED_LOCK, EXCLUSIVE_LOCK));
3295 		mode = SHARED_LOCK;
3296 	}
3297 
3298 	TRACE((_T("ACTION_LOCK(0x%08x, \"%s\", %d)\n"), lock, bstr (unit, name), mode));
3299 	DUMPLOCK(unit, lock);
3300 
3301 	a = find_aino (unit, lock, bstr (unit, name), &err);
3302 	if (err == 0 && a->softlink) {
3303 		err = test_softlink (a);
3304 	}
3305 	if (err == 0 && (a->elock || (mode != SHARED_LOCK && a->shlock > 0))) {
3306 		err = ERROR_OBJECT_IN_USE;
3307 	}
3308 	/* Lock() doesn't do access checks. */
3309 	if (err != 0) {
3310 		PUT_PCK_RES1 (packet, DOS_FALSE);
3311 		PUT_PCK_RES2 (packet, err);
3312 		return;
3313 	}
3314 	if (mode == SHARED_LOCK)
3315 		a->shlock++;
3316 	else
3317 		a->elock = 1;
3318 	de_recycle_aino (unit, a);
3319 	PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2);
3320 }
action_read_link_add_parent(Unit * u,a_inode * a,TCHAR * path)3321 static void action_read_link_add_parent (Unit *u, a_inode *a, TCHAR *path)
3322 {
3323 	if (a == NULL)
3324 		return;
3325 	action_read_link_add_parent(u, a->parent, path);
3326 	if (a == &u->rootnode) {
3327 		_tcscat (path, a->aname);
3328 		_tcscat (path, _T(":"));
3329 	} else {
3330 		if (path[0] && path[_tcslen (path) - 1] != ':')
3331 			_tcscat (path, _T("/"));
3332 		_tcscat (path, a->aname);
3333 	}
3334 }
3335 
3336 #define LINK_HARD 0
3337 #define LINK_SOFT 1
3338 
action_make_link(Unit * unit,dpacket packet)3339 static void action_make_link (Unit *unit, dpacket packet)
3340 {
3341 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
3342 	uaecptr name = GET_PCK_ARG2 (packet) << 2;
3343 	uaecptr target = GET_PCK_ARG3 (packet);
3344 	int type = GET_PCK_ARG4 (packet);
3345 	a_inode *a1, *a2;
3346 	int err;
3347 	TCHAR tmp[256], tmp2[MAX_DPATH], tmp3[MAX_DPATH];
3348 
3349 	_tcscpy (tmp, bstr (unit, name));
3350 	a1 = aino_from_lock (unit, lock);
3351 
3352 	if (type == LINK_HARD) {
3353 
3354 		// we don't support hard links
3355 		uaecptr tlock = target << 2;
3356 		a2 = aino_from_lock (unit, tlock);
3357 		write_log (_T("ACTION_MAKE_LINK(HARD,'%s','%s','%s')\n"),
3358 			a1 ? a1->aname : _T("?"), tmp,
3359 			a2 ? a2->aname : _T("?"));
3360 
3361 		PUT_PCK_RES1 (packet, DOS_FALSE);
3362 		PUT_PCK_RES2 (packet, ERROR_NOT_IMPLEMENTED);
3363 
3364 	} else {
3365 
3366 		a_inode *a3;
3367 		TCHAR *link = cstr (unit, target);
3368 		write_log (_T("ACTION_MAKE_LINK(SOFT,'%s','%s','%s')\n"),
3369 			a1 ? a1->aname : _T("?"), tmp, link);
3370 		if (!a1) {
3371 		PUT_PCK_RES1 (packet, DOS_FALSE);
3372 			PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
3373 		return;
3374 	}
3375 		// try to find softlink target
3376 		for (Unit *u = units; u; u = u->next) {
3377 			if (u->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS))
3378 				continue;
3379 			a3 = find_aino (u, 0, link, &err);
3380 			if (err || !a3)
3381 				continue;
3382 			_tcscpy (tmp2, a1->nname);
3383 			_tcscat (tmp2, FSDB_DIR_SEPARATOR_S);
3384 			_tcscat (tmp2, tmp);
3385 			tmp3[0] = 0;
3386 			action_read_link_add_parent (u, a3, tmp3);
3387 //			if (!my_createshortcut (tmp2, a3->nname, tmp3)) {
3388 //				PUT_PCK_RES1 (packet, DOS_FALSE);
3389 //				PUT_PCK_RES2 (packet, dos_errno ());
3390 //			}
3391 		return;
3392 	}
3393 		// real Amiga softlinks would accept invalid paths too,
3394 		// we won't.
3395 		PUT_PCK_RES1 (packet, DOS_FALSE);
3396 		PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
3397 	}
3398 }
3399 
action_read_link(Unit * unit,dpacket packet)3400 static void action_read_link (Unit *unit, dpacket packet)
3401 {
3402 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
3403 	uaecptr name = GET_PCK_ARG2 (packet);
3404 	uaecptr newname = GET_PCK_ARG3 (packet);
3405 	int size = GET_PCK_ARG4 (packet);
3406 	a_inode *a, *matched_aino;
3407 	Unit *u = NULL, *u2 = NULL, *matched_unit;
3408 	int err, i, matched_len;
3409 	TCHAR tmp[MAX_DPATH];
3410 	TCHAR *namep, *extrapath;
3411 
3412 	extrapath = NULL;
3413 	namep = cstr (unit, name);
3414 	for (;;) {
3415 		a = find_aino (unit, lock, namep, &err);
3416 		if (err != ERROR_IS_SOFT_LINK)
3417 			break;
3418 		for (i = _tcslen (namep) - 1; i > 0; i--) {
3419 			if (namep[i] == '/') {
3420 				namep[i] = 0;
3421 				xfree (extrapath);
3422 				extrapath = my_strdup (namep + i + 1);
3423 				break;
3424 			}
3425 		}
3426 	}
3427 	if (!a->softlink)
3428 		err = ERROR_OBJECT_WRONG_TYPE;
3429 	if (err != 0) {
3430 		PUT_PCK_RES1 (packet, DOS_FALSE);
3431 		PUT_PCK_RES2 (packet, err);
3432 		return;
3433 	}
3434 	_tcscpy (tmp, a->nname);
3435 	write_log (_T("Resolving softlink '%s'\n"), tmp);
3436 	if (!my_resolvesoftlink (tmp, sizeof tmp / sizeof (TCHAR))) {
3437 		PUT_PCK_RES1 (packet, DOS_FALSE);
3438 		//  not sure what to return
3439 		PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
3440 		return;
3441 	}
3442 	write_log (_T("-> '%s'\n"), tmp);
3443 	matched_aino = NULL;
3444 	matched_unit = NULL;
3445 	err = 0;
3446 	matched_len = 0;
3447 	for (u = units; u; u = u->next) {
3448 		if (!(u->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS))) {
3449 			TCHAR path[MAX_DPATH];
3450 			i = my_issamevolume (u->rootnode.nname, tmp, path);
3451 			if (i > matched_len) {
3452 				a = find_aino (u, 0, path, &err);
3453 				if (a && !err) {
3454 					write_log (_T("Match found from '%s' (%d)\n"), u->rootnode.aname, i);
3455 					matched_aino = a;
3456 					matched_unit = u;
3457 					matched_len = i;
3458 				}
3459 			}
3460 		}
3461 	}
3462 	if (!matched_aino) {
3463 		write_log (_T("Path not found in any mounted drive\n"));
3464 		PUT_PCK_RES1 (packet, DOS_FALSE);
3465 		PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
3466 		return;
3467 	}
3468 	tmp[0] = 0;
3469 	action_read_link_add_parent (matched_unit, matched_aino, tmp);
3470 	if (extrapath) {
3471 		_tcscat (tmp, _T("/"));
3472 		_tcscat (tmp, extrapath);
3473 	}
3474 	xfree (extrapath);
3475 	write_log (_T("got target '%s'\n"), tmp);
3476 	char *s = ua_fs (tmp, -1);
3477 	for (i = 0; s[i]; i++) {
3478 		if (i >= size - 1)
3479 			break;
3480 		put_byte (newname + i, s[i]);
3481 	}
3482 	xfree (s);
3483 	put_byte (newname + i, 0);
3484 }
3485 
action_free_lock(Unit * unit,dpacket packet)3486 static void action_free_lock (Unit *unit, dpacket packet)
3487 {
3488 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
3489 	a_inode *a;
3490 	TRACE((_T("ACTION_FREE_LOCK(0x%lx)\n"), lock));
3491 	DUMPLOCK(unit, lock);
3492 
3493 	a = aino_from_lock (unit, lock);
3494 	if (a == 0) {
3495 		PUT_PCK_RES1 (packet, DOS_FALSE);
3496 		PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
3497 		return;
3498 	}
3499 	if (a->elock)
3500 		a->elock = 0;
3501 	else
3502 		a->shlock--;
3503 	recycle_aino (unit, a);
3504 	free_lock(unit, lock);
3505 
3506 	PUT_PCK_RES1 (packet, DOS_TRUE);
3507 }
3508 
3509 static uaecptr
action_dup_lock_2(Unit * unit,dpacket packet,uae_u32 uniq)3510 	action_dup_lock_2 (Unit *unit, dpacket packet, uae_u32 uniq)
3511 {
3512 	uaecptr out;
3513 	a_inode *a;
3514 
3515 	a = lookup_aino (unit, uniq);
3516 	if (a == 0) {
3517 		PUT_PCK_RES1 (packet, DOS_FALSE);
3518 		PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
3519 		return 0;
3520 	}
3521 	/* DupLock()ing exclusive locks isn't possible, says the Autodoc, but
3522 	* at least the RAM-Handler seems to allow it. Let's see what happens
3523 	* if we don't. */
3524 	if (a->elock) {
3525 		PUT_PCK_RES1 (packet, DOS_FALSE);
3526 		PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
3527 		return 0;
3528 	}
3529 	a->shlock++;
3530 	de_recycle_aino (unit, a);
3531 	out = make_lock (unit, a->uniq, -2) >> 2;
3532 	PUT_PCK_RES1 (packet, out);
3533 	return out;
3534 }
3535 
3536 static void
action_dup_lock(Unit * unit,dpacket packet)3537 	action_dup_lock (Unit *unit, dpacket packet)
3538 {
3539 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
3540 	TRACE((_T("ACTION_DUP_LOCK(0x%lx)\n"), lock));
3541 	if (!lock) {
3542 		PUT_PCK_RES1 (packet, 0);
3543 		return;
3544 	}
3545 	action_dup_lock_2 (unit, packet, get_long (lock + 4));
3546 }
3547 
3548 
3549 static void
action_lock_from_fh(Unit * unit,dpacket packet)3550 	action_lock_from_fh (Unit *unit, dpacket packet)
3551 {
3552 	Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
3553 	TRACE((_T("ACTION_COPY_DIR_FH(0x%lx,'%s')\n"), GET_PCK_ARG1 (packet), k ? k->aino->aname : _T("<null>")));
3554 	if (k == 0) {
3555 		PUT_PCK_RES1 (packet, DOS_FALSE);
3556 		return;
3557 	}
3558 	action_dup_lock_2 (unit, packet, k->aino->uniq);
3559 }
3560 
free_exkey(Unit * unit,ExamineKey * ek)3561 static void free_exkey (Unit *unit, ExamineKey *ek)
3562 {
3563 	if (--ek->aino->exnext_count == 0) {
3564 		TRACE ((_T("Freeing ExKey and reducing total_locked from %d by %d\n"),
3565 			unit->total_locked_ainos, ek->aino->locked_children));
3566 		unit->total_locked_ainos -= ek->aino->locked_children;
3567 		ek->aino->locked_children = 0;
3568 	}
3569 	ek->aino = 0;
3570 	ek->uniq = 0;
3571 }
3572 
lookup_exkey(Unit * unit,uae_u32 uniq)3573 static ExamineKey *lookup_exkey (Unit *unit, uae_u32 uniq)
3574 {
3575 	ExamineKey *ek;
3576 	int i;
3577 
3578 	ek = unit->examine_keys;
3579 	for (i = 0; i < EXKEYS; i++, ek++) {
3580 		/* Did we find a free one? */
3581 		if (ek->uniq == uniq)
3582 			return ek;
3583 	}
3584 	write_log (_T("Houston, we have a BIG problem.\n"));
3585 	return 0;
3586 }
3587 
3588 /* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */
new_exkey(Unit * unit,a_inode * aino)3589 static ExamineKey *new_exkey (Unit *unit, a_inode *aino)
3590 {
3591 	uae_u32 uniq;
3592 	uae_u32 oldest = 0xFFFFFFFE;
3593 	ExamineKey *ek, *oldest_ek = 0;
3594 	int i;
3595 
3596 	ek = unit->examine_keys;
3597 	for (i = 0; i < EXKEYS; i++, ek++) {
3598 		/* Did we find a free one? */
3599 		if (ek->aino == 0)
3600 			continue;
3601 		if (ek->uniq < oldest)
3602 			oldest = (oldest_ek = ek)->uniq;
3603 	}
3604 	ek = unit->examine_keys;
3605 	for (i = 0; i < EXKEYS; i++, ek++) {
3606 		/* Did we find a free one? */
3607 		if (ek->aino == 0)
3608 			goto found;
3609 	}
3610 	/* This message should usually be harmless. */
3611 	write_log (_T("Houston, we have a problem (%s).\n"), aino->nname);
3612 	free_exkey (unit, oldest_ek);
3613 	ek = oldest_ek;
3614 found:
3615 
3616 	uniq = unit->next_exkey;
3617 	if (uniq >= 0xFFFFFFFE) {
3618 		/* Things will probably go wrong, but most likely the Amiga will crash
3619 		* before this happens because of something else. */
3620 		uniq = 1;
3621 	}
3622 	unit->next_exkey = uniq + 1;
3623 	ek->aino = aino;
3624 	ek->curr_file = 0;
3625 	ek->uniq = uniq;
3626 	return ek;
3627 }
3628 
move_exkeys(Unit * unit,a_inode * from,a_inode * to)3629 static void move_exkeys (Unit *unit, a_inode *from, a_inode *to)
3630 {
3631 	int i;
3632 	unsigned long tmp = 0;
3633 	for (i = 0; i < EXKEYS; i++) {
3634 		ExamineKey *k = unit->examine_keys + i;
3635 		if (k->uniq == 0)
3636 			continue;
3637 		if (k->aino == from) {
3638 			k->aino = to;
3639 			tmp++;
3640 		}
3641 	}
3642 	if (tmp != from->exnext_count)
3643 		write_log (_T("filesys.c: Bug in ExNext bookkeeping.  BAD.\n"));
3644 	to->exnext_count = from->exnext_count;
3645 	to->locked_children = from->locked_children;
3646 	from->exnext_count = 0;
3647 	from->locked_children = 0;
3648 }
3649 
3650 static void
get_fileinfo(Unit * unit,dpacket packet,uaecptr info,a_inode * aino)3651 	get_fileinfo (Unit *unit, dpacket packet, uaecptr info, a_inode *aino)
3652 {
3653 	struct mystat statbuf;
3654 	int days, mins, ticks;
3655 	int i, n, entrytype, blocksize;
3656 	int fsdb_can = fsdb_cando (unit);
3657 	TCHAR *xs;
3658 	char *x;
3659 /* REMOVEME:
3660  * nowhere used
3661  */
3662 #if 0
3663 	char *x2;
3664 #endif
3665 	bool ok = true;
3666 
3667 	memset (&statbuf, 0, sizeof statbuf);
3668 	/* No error checks - this had better work. */
3669 	if (unit->volflags & MYVOLUMEINFO_ARCHIVE)
3670 		ok = zfile_stat_archive (aino->nname, &statbuf) != 0;
3671 /*	else if (unit->volflags & MYVOLUMEINFO_CDFS)
3672 		ok = isofs_stat (unit->ui.cdfs_superblock, aino->uniq_external, &statbuf);*/
3673 	else
3674 		my_stat (aino->nname, &statbuf);
3675 
3676 	if (!ok) {
3677 		PUT_PCK_RES1 (packet, DOS_FALSE);
3678 		PUT_PCK_RES2 (packet, ERROR_NOT_A_DOS_DISK);
3679 		return;
3680 	}
3681 
3682 	if (aino->parent == 0) {
3683 		/* Guru book says ST_ROOT = 1 (root directory, not currently used)
3684 		* but some programs really expect 2 from root dir..
3685 		*/
3686 		entrytype = ST_USERDIR;
3687 		xs = unit->ui.volname;
3688 	} else {
3689 		entrytype = aino->softlink ? ST_SOFTLINK : (aino->dir ? ST_USERDIR : ST_FILE);
3690 		xs = aino->aname;
3691 	}
3692 	put_long (info + 4, entrytype);
3693 	/* AmigaOS docs say these have to contain the same value. */
3694 	put_long (info + 120, entrytype);
3695 
3696 	TRACE((_T("name=\"%s\"\n"), xs));
3697 	x = ua_fs (xs, -1);
3698 	n = strlen (x);
3699 	if (n > 106)
3700 		n = 106;
3701 	i = 8;
3702 	put_byte (info + i, n); i++;
3703 	while (n--)
3704 		put_byte (info + i, *x), i++, x++;
3705 	while (i < 108)
3706 		put_byte (info + i, 0), i++;
3707 
3708 	put_long (info + 116, fsdb_can ? aino->amigaos_mode : fsdb_mode_supported (aino));
3709 	put_long (info + 124, statbuf.size > MAXFILESIZE32 ? MAXFILESIZE32 : (uae_u32)statbuf.size);
3710 #if 0 //HAVE_ST_BLOCKS
3711 	put_long (info + 128, statbuf.st_blocks);
3712 #else
3713 	blocksize = (unit->volflags & MYVOLUMEINFO_CDFS) ? 2048 : 512;
3714 	put_long (info + 128, (statbuf.size + blocksize - 1) / blocksize);
3715 #endif
3716 	timeval_to_amiga (&statbuf.mtime, &days, &mins, &ticks);
3717 	put_long (info + 132, days);
3718 	put_long (info + 136, mins);
3719 	put_long (info + 140, ticks);
3720 	if (aino->comment == 0 || !fsdb_can)
3721 		put_long (info + 144, 0);
3722 	else {
3723 		TRACE((_T("comment=\"%s\"\n"), aino->comment));
3724 		i = 144;
3725 		xs = aino->comment;
3726 		if (!xs)
3727 			xs= _T("");
3728 		x = ua_fs (xs, -1);
3729 		n = strlen (x);
3730 		if (n > 78)
3731 			n = 78;
3732 		put_byte (info + i, n); i++;
3733 		while (n--)
3734 			put_byte (info + i, *x), i++, x++;
3735 		while (i < 224)
3736 			put_byte (info + i, 0), i++;
3737 	}
3738 	PUT_PCK_RES1 (packet, DOS_TRUE);
3739 }
3740 
get_native_path(uae_u32 lock,TCHAR * out)3741 int get_native_path (uae_u32 lock, TCHAR *out)
3742 {
3743 	int i = 0;
3744 	for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
3745 		if (mountinfo.ui[i].self) {
3746 			a_inode *a = aino_from_lock (mountinfo.ui[i].self, lock << 2);
3747 			if (a) {
3748 				_tcscpy (out, a->nname);
3749 				return 0;
3750 			}
3751 		}
3752 	}
3753 	return -1;
3754 }
3755 
3756 
3757 #define REC_EXCLUSIVE 0
3758 #define REC_EXCLUSIVE_IMMED 1
3759 #define REC_SHARED 2
3760 #define REC_SHARED_IMMED 3
3761 
new_record(uae_u32 packet,uae_u32 pos,uae_u32 len,uae_u32 mode,uae_u32 timeout,uae_u32 msg)3762 static struct lockrecord *new_record (uae_u32 packet, uae_u32 pos, uae_u32 len, uae_u32 mode, uae_u32 timeout, uae_u32 msg)
3763 {
3764 	struct lockrecord *lr = xcalloc (struct lockrecord, 1);
3765 	lr->packet = packet;
3766 	lr->pos = pos;
3767 	lr->len = len;
3768 	lr->mode = mode;
3769 	lr->timeout = timeout * vblank_hz / 50;
3770 	lr->msg = msg;
3771 	return lr;
3772 }
3773 
record_hit(Unit * unit,Key * k,uae_u32 pos,uae_u32 len,uae_u32 mode)3774 static bool record_hit (Unit *unit, Key *k, uae_u32 pos, uae_u32 len, uae_u32 mode)
3775 {
3776 	Key *k2;
3777 	struct lockrecord *lr;
3778 
3779 	bool exclusive = mode == REC_EXCLUSIVE || mode == REC_EXCLUSIVE_IMMED;
3780 	for (k2 = unit->keys; k2; k2 = k2->next) {
3781 		if (k2->aino->uniq == k->aino->uniq) {
3782 			if (k2 == k)
3783 				continue;
3784 			for (lr = k2->record; lr; lr = lr->next) {
3785 				bool exclusive2 = lr->mode == REC_EXCLUSIVE || lr->mode == REC_EXCLUSIVE_IMMED;
3786 				if (exclusive || exclusive2) {
3787 					uae_u32 a1 = pos;
3788 					uae_u32 a2 = pos + len;
3789 					uae_u32 b1 = lr->pos;
3790 					uae_u32 b2 = lr->pos + lr->len;
3791 					if (len && lr->len) {
3792 						bool hit = (a1 >= b1 && a1 < b2) || (a2 > b1 && a2 < b2) || (b1 >= a1 && b1 < a2) || (b2 > a1 && b2 < a2);
3793 						if (hit)
3794 							return true;
3795 					}
3796 				}
3797 			}
3798 		}
3799 	}
3800 	return false;
3801 }
3802 
record_timeout(Unit * unit)3803 static void record_timeout (Unit *unit)
3804 {
3805 	bool retry = true;
3806 	struct lockrecord *lr;
3807 
3808 	while (retry) {
3809 		retry = false;
3810 		struct lockrecord *prev = NULL;
3811 		for (lr = unit->waitingrecords; lr; lr = lr->next) {
3812 			lr->timeout--;
3813 			if (lr->timeout == 0) {
3814 				Key *k = lookup_key (unit, GET_PCK_ARG1 (lr->packet));
3815 				PUT_PCK_RES1 (lr->packet, DOS_FALSE);
3816 				PUT_PCK_RES2 (lr->packet, ERROR_LOCK_TIMEOUT);
3817 				// mark packet as complete
3818 				put_long (lr->msg + 4, 0xfffffffe);
3819 				uae_Signal (get_long (unit->volume + 176 - 32), 1 << 13);
3820 				if (prev)
3821 					prev->next = lr->next;
3822 				else
3823 					unit->waitingrecords = lr->next;
3824 				write_log (_T("queued record timed out '%s',%d,%d,%d,%d\n"), k ? k->aino->nname : _T("NULL"), lr->pos, lr->len, lr->mode, lr->timeout);
3825 				xfree (lr);
3826 				retry = true;
3827 				break;
3828 			}
3829 			prev = lr;
3830 		}
3831 	}
3832 }
3833 
record_check_waiting(Unit * unit)3834 static void record_check_waiting (Unit *unit)
3835 {
3836 	bool retry = true;
3837 	struct lockrecord *lr;
3838 
3839 	while (retry) {
3840 		retry = false;
3841 		struct lockrecord *prev = NULL;
3842 		for (lr = unit->waitingrecords; lr; lr = lr->next) {
3843 			Key *k = lookup_key (unit, GET_PCK_ARG1 (lr->packet));
3844 			if (!k || !record_hit (unit, k, lr->pos, lr->len, lr->mode)) {
3845 				if (prev)
3846 					prev->next = lr->next;
3847 				else
3848 					unit->waitingrecords = lr->next;
3849 				write_log (_T("queued record released '%s',%d,%d,%d,%d\n"), k->aino->nname, lr->pos, lr->len, lr->mode, lr->timeout);
3850 				// mark packet as complete
3851 				put_long (lr->msg + 4, 0xffffffff);
3852 				xfree (lr);
3853 				retry = true;
3854 				break;
3855 			}
3856 			prev = lr;
3857 		}
3858 	}
3859 }
3860 
action_lock_record(Unit * unit,dpacket packet,uae_u32 msg)3861 static int action_lock_record (Unit *unit, dpacket packet, uae_u32 msg)
3862 {
3863 	Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
3864 	uae_u32 pos = GET_PCK_ARG2 (packet);
3865 	uae_u32 len = GET_PCK_ARG3 (packet);
3866 	uae_u32 mode = GET_PCK_ARG4 (packet);
3867 	uae_u32 timeout = GET_PCK_ARG5 (packet);
3868 
3869 /* REMOVEME:
3870  * nowhere used
3871  */
3872 #if 0
3873 	bool exclusive = mode == REC_EXCLUSIVE || mode == REC_EXCLUSIVE_IMMED;
3874 #endif
3875 
3876 	write_log (_T("action_lock_record('%s',%d,%d,%d,%d)\n"), k ? k->aino->nname : _T("null"), pos, len, mode, timeout);
3877 
3878 	if (!k || mode > REC_SHARED_IMMED) {
3879 		PUT_PCK_RES1 (packet, DOS_FALSE);
3880 		PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
3881 		return 1;
3882 	}
3883 
3884 	if (mode == REC_EXCLUSIVE_IMMED || mode == REC_SHARED_IMMED)
3885 		timeout = 0;
3886 
3887 	if (record_hit (unit, k, pos, len, mode)) {
3888 		if (timeout && msg) {
3889 			// queue it and do not reply
3890 			struct lockrecord *lr = new_record (packet, pos, len, mode, timeout, msg);
3891 			if (unit->waitingrecords) {
3892 				lr->next = unit->waitingrecords;
3893 				unit->waitingrecords = lr;
3894 			} else {
3895 				unit->waitingrecords = lr;
3896 			}
3897 			write_log (_T("-> collision, timeout queued\n"));
3898 			return -1;
3899 		}
3900 		PUT_PCK_RES1 (packet, DOS_FALSE);
3901 		PUT_PCK_RES2 (packet, ERROR_LOCK_COLLISION);
3902 		write_log (_T("-> ERROR_LOCK_COLLISION\n"));
3903 		return 1;
3904 	}
3905 
3906 	struct lockrecord *lr = new_record (GET_PCK_ARG1 (packet), pos, len, mode, timeout, 0);
3907 	if (k->record) {
3908 		lr->next = k->record;
3909 		k->record = lr;
3910 	} else {
3911 		k->record = lr;
3912 	}
3913 	PUT_PCK_RES1 (packet, DOS_TRUE);
3914 	write_log (_T("-> OK\n"));
3915 	return 1;
3916 }
3917 
action_free_record(Unit * unit,dpacket packet)3918 static void action_free_record (Unit *unit, dpacket packet)
3919 {
3920 	Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
3921 	uae_u32 pos = GET_PCK_ARG2 (packet);
3922 	uae_u32 len = GET_PCK_ARG3 (packet);
3923 
3924 	write_log (_T("action_free_record('%s',%d,%d)\n"), k ? k->aino->nname : _T("null"), pos, len);
3925 
3926 	if (!k) {
3927 		PUT_PCK_RES1 (packet, DOS_FALSE);
3928 		PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
3929 		return;
3930 	}
3931 
3932 	struct lockrecord *prev = NULL;
3933 	struct lockrecord *lr;
3934 	for (lr = k->record; lr; lr = lr->next) {
3935 		if (lr->pos == pos && lr->len == len) {
3936 			if (prev)
3937 				prev->next = lr->next;
3938 			else
3939 				k->record = lr->next;
3940 			xfree (lr);
3941 			write_log (_T("->OK\n"));
3942 			record_check_waiting (unit);
3943 			PUT_PCK_RES1 (packet, DOS_TRUE);
3944 			return;
3945 		}
3946 	}
3947 	write_log (_T("-> ERROR_RECORD_NOT_LOCKED\n"));
3948 	PUT_PCK_RES1 (packet, DOS_FALSE);
3949 	PUT_PCK_RES2 (packet, ERROR_RECORD_NOT_LOCKED);
3950 }
3951 
3952 #define EXALL_DEBUG 0
3953 #define EXALL_END 0xde1111ad
3954 
getexall(Unit * unit,uaecptr control,uae_u32 id)3955 static ExAllKey *getexall (Unit *unit, uaecptr control, uae_u32 id)
3956 {
3957 	int i;
3958 	/* Update
3959 	 * was : if (id < 0) {
3960 	 * But the id is used as an uae_u32 everywhere.
3961 	 * However, action_examine_all() uses -1 as an id if
3962 	 * it has none.
3963 	 * - Sven
3964 	 */
3965 	 if ((uae_u32)-1 == id) {
3966 		for (i = 0; i < EXALLKEYS; i++) {
3967 			if (unit->exalls[i].id == 0) {
3968 				unit->exallid++;
3969 				if (unit->exallid == EXALL_END)
3970 					unit->exallid++;
3971 				unit->exalls[i].id = unit->exallid;
3972 				unit->exalls[i].control = control;
3973 				return &unit->exalls[i];
3974 			}
3975 		}
3976 	} else if (id > 0) {
3977 		for (i = 0; i < EXALLKEYS; i++) {
3978 			if (unit->exalls[i].id == id)
3979 				return &unit->exalls[i];
3980 		}
3981 	}
3982 	return NULL;
3983 }
3984 
exalldo(uaecptr exalldata,uae_u32 exalldatasize,uae_u32 type,uaecptr control,Unit * unit,a_inode * aino)3985 static int exalldo (uaecptr exalldata, uae_u32 exalldatasize, uae_u32 type, uaecptr control, Unit *unit, a_inode *aino)
3986 {
3987 	uaecptr exp = exalldata;
3988 	int i;
3989 	uae_u32 size, size2;
3990 	int entrytype;
3991 	TCHAR *xs = NULL, *commentx = NULL;
3992 	uae_u32 flags = 15;
3993 	int days = 0, mins = 0, ticks = 0;
3994 	struct mystat statbuf;
3995 	int fsdb_can = fsdb_cando (unit);
3996 	uae_u16 uid = 0, gid = 0;
3997 	char *x = NULL, *comment = NULL;
3998 	int ret = 0;
3999 
4000 	memset (&statbuf, 0, sizeof statbuf);
4001 	if (unit->volflags & MYVOLUMEINFO_ARCHIVE)
4002 		zfile_stat_archive (aino->nname, &statbuf);
4003 /*	else if (unit->volflags & MYVOLUMEINFO_CDFS)
4004 		isofs_stat (unit->ui.cdfs_superblock, aino->uniq_external, &statbuf);*/
4005 	else
4006 		my_stat (aino->nname, &statbuf);
4007 
4008 	if (aino->parent == 0) {
4009 		entrytype = ST_USERDIR;
4010 		xs = unit->ui.volname;
4011 	} else {
4012 		entrytype = aino->softlink ? ST_SOFTLINK : (aino->dir ? ST_USERDIR : ST_FILE);
4013 		xs = aino->aname;
4014 	}
4015 	x = ua_fs (xs, -1);
4016 
4017 	size = 0;
4018 	size2 = 4;
4019 	if (type >= 1) {
4020 		size2 += 4;
4021 		size += strlen (x) + 1;
4022 		size = (size + 3) & ~3;
4023 	}
4024 	if (type >= 2)
4025 		size2 += 4;
4026 	if (type >= 3)
4027 		size2 += 4;
4028 	if (type >= 4) {
4029 		flags = fsdb_can ? aino->amigaos_mode : fsdb_mode_supported (aino);
4030 		size2 += 4;
4031 	}
4032 	if (type >= 5) {
4033 		timeval_to_amiga (&statbuf.mtime, &days, &mins, &ticks);
4034 		size2 += 12;
4035 	}
4036 	if (type >= 6) {
4037 		size2 += 4;
4038 		if (aino->comment == 0 || !fsdb_can)
4039 			commentx = _T("");
4040 		else
4041 			commentx = aino->comment;
4042 		comment = ua_fs (commentx, -1);
4043 		size += strlen (comment) + 1;
4044 		size = (size + 3) & ~3;
4045 	}
4046 	if (type >= 7) {
4047 		size2 += 4;
4048 		uid = 0;
4049 		gid = 0;
4050 	}
4051 
4052 	i = get_long (control + 0);
4053 	while (i > 0) {
4054 		exp = get_long (exp); /* ed_Next */
4055 		i--;
4056 	}
4057 
4058 	if (exalldata + exalldatasize - exp < size + size2)
4059 		goto end; /* not enough space */
4060 
4061 #if EXALL_DEBUG > 0
4062 	write_log (_T("ID=%d, %d, %08x: '%s'%s\n"),
4063 		get_long (control + 4), get_long (control + 0), exp, xs, aino->dir ? _T(" [DIR]") : _T(""));
4064 #endif
4065 
4066 	put_long (exp, exp + size + size2); /* ed_Next */
4067 	if (type >= 1) {
4068 		put_long (exp + 4, exp + size2);
4069 		for (i = 0; i <= (int)strlen (x); i++) {
4070 			put_byte (exp + size2, x[i]);
4071 			size2++;
4072 		}
4073 	}
4074 	if (type >= 2)
4075 		put_long (exp + 8, entrytype);
4076 	if (type >= 3)
4077 		put_long (exp + 12, statbuf.size > MAXFILESIZE32 ? MAXFILESIZE32 : statbuf.size);
4078 	if (type >= 4)
4079 		put_long (exp + 16, flags);
4080 	if (type >= 5) {
4081 		put_long (exp + 20, days);
4082 		put_long (exp + 24, mins);
4083 		put_long (exp + 28, ticks);
4084 	}
4085 	if (type >= 6) {
4086 		put_long (exp + 32, exp + size2);
4087 		put_byte (exp + size2, strlen (comment));
4088 		for (i = 0; i <= (int)strlen (comment); i++) {
4089 			put_byte (exp + size2, comment[i]);
4090 			size2++;
4091 		}
4092 	}
4093 	if (type >= 7) {
4094 		put_word (exp + 36, uid);
4095 		put_word (exp + 38, gid);
4096 	}
4097 	put_long (control + 0, get_long (control + 0) + 1);
4098 	ret = 1;
4099 end:
4100 	if (x)
4101 		xfree (x);
4102 	if (comment)
4103 		xfree (comment);
4104 	return ret;
4105 }
4106 
action_examine_all_do(Unit * unit,uaecptr lock,ExAllKey * eak,uaecptr exalldata,uae_u32 exalldatasize,uae_u32 type,uaecptr control)4107 static int action_examine_all_do (Unit *unit, uaecptr lock, ExAllKey *eak, uaecptr exalldata, uae_u32 exalldatasize, uae_u32 type, uaecptr control)
4108 {
4109 	a_inode *aino, *base = NULL;
4110         struct dirent *ok = NULL;
4111 	uae_u32 err;
4112 	struct fs_dirhandle *d;
4113 	TCHAR fn[MAX_DPATH];
4114 
4115 	if (lock != 0)
4116 		base = aino_from_lock (unit, lock);
4117 	if (base == 0)
4118 		base = &unit->rootnode;
4119 	for (;;) {
4120 		uae_u64 uniq = 0;
4121 		d = eak->dirhandle;
4122 		if (!eak->fn) {
4123 			do {
4124 				if (d->fstype == FS_ARCHIVE)
4125 					;///*fixme*/ ok = zfile_readdir_archive (d->zd, fn);
4126 				else if (d->fstype == FS_DIRECTORY)
4127 					ok = my_readdir (d->od, 0);
4128 				/*else if (d->fstype == FS_CDFS)
4129 					ok = isofs_readdir (d->isod, fn, &uniq);*/
4130 				else
4131 					ok = 0;
4132 			} while (ok && d->fstype  == FS_DIRECTORY && fsdb_name_invalid (ok->d_name));
4133 			if (!ok)
4134 				return 0;
4135 		} else {
4136 			//_tcscpy (ok->d_name, eak->fn);
4137 			xfree (eak->fn);
4138 			eak->fn = NULL;
4139 		}
4140 		aino = lookup_child_aino_for_exnext (unit, base, ok->d_name, &err, uniq);
4141 		if (!aino)
4142 			return 0;
4143 		eak->id = unit->exallid++;
4144 		put_long (control + 4, eak->id);
4145 		if (!exalldo (exalldata, exalldatasize, type, control, unit, aino)) {
4146 			//eak->fn = my_strdup (ok->d_name); /* no space in exallstruct, save current entry */
4147 			break;
4148 		}
4149 	}
4150 	return 1;
4151 }
4152 
action_examine_all_end(Unit * unit,dpacket packet)4153 static int action_examine_all_end (Unit *unit, dpacket packet)
4154 {
4155 	uae_u32 id;
4156 	uae_u32 doserr = 0;
4157 	ExAllKey *eak;
4158 	uaecptr control = GET_PCK_ARG5 (packet);
4159 
4160 	if (kickstart_version < 36)
4161 		return 0;
4162 	id = get_long (control + 4);
4163 	eak = getexall (unit, control, id);
4164 #if EXALL_DEBUG > 0
4165 	write_log (_T("EXALL_END ID=%d %x\n"), id, eak);
4166 #endif
4167 	if (!eak) {
4168 		write_log (_T("FILESYS: EXALL_END non-existing ID %d\n"), id);
4169 		doserr = ERROR_OBJECT_WRONG_TYPE;
4170 	} else {
4171 		eak->id = 0;
4172 		fs_closedir (eak->dirhandle);
4173 		xfree (eak->fn);
4174 		eak->fn = NULL;
4175 		eak->dirhandle = NULL;
4176 	}
4177 	if (doserr) {
4178 		PUT_PCK_RES1 (packet, DOS_FALSE);
4179 		PUT_PCK_RES2 (packet, doserr);
4180 	} else {
4181 		PUT_PCK_RES1 (packet, DOS_TRUE);
4182 	}
4183 	return 1;
4184 }
4185 
action_examine_all(Unit * unit,dpacket packet)4186 static int action_examine_all (Unit *unit, dpacket packet)
4187 {
4188 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
4189 	uaecptr exalldata = GET_PCK_ARG2 (packet);
4190 	uae_u32 exalldatasize = GET_PCK_ARG3 (packet);
4191 	uae_u32 type = GET_PCK_ARG4 (packet);
4192 	uaecptr control = GET_PCK_ARG5 (packet);
4193 
4194 	ExAllKey *eak = NULL;
4195 	a_inode *base = NULL;
4196 	struct fs_dirhandle *d;
4197 	int ok, i;
4198 	uaecptr exp;
4199 	uae_u32 id, doserr = ERROR_NO_MORE_ENTRIES;
4200 
4201 	ok = 0;
4202 
4203 #if EXALL_DEBUG > 0
4204 	write_log (_T("exall: %08x %08x-%08x %d %d %08x\n"),
4205 		lock, exalldata, exalldata + exalldatasize, exalldatasize, type, control);
4206 	write_log (_T("exall: MatchString %08x, MatchFunc %08x\n"),
4207 		get_long (control + 8), get_long (control + 12));
4208 #endif
4209 
4210 	put_long (control + 0, 0); /* eac_Entries */
4211 
4212 	/* EXAMINE ALL might use dos.library MatchPatternNoCase() which is >=36 */
4213 	if (kickstart_version < 36)
4214 		return 0;
4215 
4216 	if (type == 0 || type > 7) {
4217 		doserr = ERROR_BAD_NUMBER;
4218 		goto fail;
4219 	}
4220 
4221 	PUT_PCK_RES1 (packet, DOS_TRUE);
4222 	id = get_long (control + 4);
4223 	if (id == EXALL_END) {
4224 		write_log (_T("FILESYS: EXALL called twice with ERROR_NO_MORE_ENTRIES\n"));
4225 		goto fail; /* already ended exall() */
4226 	}
4227 	if (id) {
4228 		eak = getexall (unit, control, id);
4229 		if (!eak) {
4230 			write_log (_T("FILESYS: EXALL non-existing ID %d\n"), id);
4231 			doserr = ERROR_OBJECT_WRONG_TYPE;
4232 			goto fail;
4233 		}
4234 		if (!action_examine_all_do (unit, lock, eak, exalldata, exalldatasize, type, control))
4235 			goto fail;
4236 		if (get_long (control + 0) == 0) {
4237 			/* uh, no space for first entry.. */
4238 			doserr = ERROR_NO_FREE_STORE;
4239 			goto fail;
4240 		}
4241 
4242 	} else {
4243 
4244 		eak = getexall (unit, control, -1);
4245 		if (!eak)
4246 			goto fail;
4247 		if (lock != 0)
4248 			base = aino_from_lock (unit, lock);
4249 		if (base == 0)
4250 			base = &unit->rootnode;
4251 #if EXALL_DEBUG > 0
4252 		write_log("exall: ID=%d '%s'\n", eak->id, base->nname);
4253 #endif
4254 		d = fs_opendir (unit, base);
4255 		if (!d)
4256 			goto fail;
4257 		eak->dirhandle = d;
4258 		put_long (control + 4, eak->id);
4259 		if (!action_examine_all_do (unit, lock, eak, exalldata, exalldatasize, type, control))
4260 			goto fail;
4261 		if (get_long (control + 0) == 0) {
4262 			/* uh, no space for first entry.. */
4263 			doserr = ERROR_NO_FREE_STORE;
4264 			goto fail;
4265 		}
4266 
4267 	}
4268 	ok = 1;
4269 
4270 fail:
4271 	/* Clear last ed_Next. This "list" is quite non-Amiga like.. */
4272 	exp = exalldata;
4273 	i = get_long (control + 0);
4274 	for (;;) {
4275 		if (i <= 1) {
4276 			if (exp)
4277 				put_long (exp, 0);
4278 			break;
4279 		}
4280 		exp = get_long (exp); /* ed_Next */
4281 		i--;
4282 	}
4283 #if EXALL_DEBUG > 0
4284 	write_log("ok=%d, err=%d, eac_Entries = %d\n", ok, ok ? -1 : doserr, get_long (control + 0));
4285 #endif
4286 
4287 	if (!ok) {
4288 		PUT_PCK_RES1 (packet, DOS_FALSE);
4289 		PUT_PCK_RES2 (packet, doserr);
4290 		if (eak) {
4291 			eak->id = 0;
4292 			fs_closedir (eak->dirhandle);
4293 			eak->dirhandle = NULL;
4294 			xfree (eak->fn);
4295 			eak->fn = NULL;
4296 		}
4297 		if (doserr == ERROR_NO_MORE_ENTRIES)
4298 			put_long (control + 4, EXALL_END);
4299 	}
4300 	return 1;
4301 }
4302 
exall_helpder(TrapContext * context)4303 static uae_u32 exall_helpder(TrapContext *context)
4304 {
4305 	int i;
4306 	Unit *u;
4307 	uaecptr packet = m68k_areg (regs, 4);
4308 	uaecptr control = get_long (packet + dp_Arg5);
4309 	uae_u32 id = get_long (control + 4);
4310 
4311 #if EXALL_DEBUG > 0
4312 	write_log (_T("FILESYS: EXALL extra round ID=%d\n"), id);
4313 #endif
4314 	if (id == EXALL_END)
4315 		return 1;
4316 	for (u = units; u; u = u->next) {
4317 		for (i = 0; i < EXALLKEYS; i++) {
4318 			if (u->exalls[i].id == id && u->exalls[i].control == control) {
4319 				action_examine_all (u, packet);
4320 			}
4321 		}
4322 	}
4323 	return 1;
4324 }
4325 
fsmisc_helper(TrapContext * context)4326 static uae_u32 REGPARAM2 fsmisc_helper (TrapContext *context)
4327 {
4328 	int mode = m68k_dreg (regs, 0);
4329 	uae_u32 t;
4330 
4331 	switch (mode)
4332 	{
4333 	case 0:
4334 		return exall_helpder (context);
4335 	case 1:
4336 		return filesys_media_change_reply (context, 0);
4337 	case 2:
4338 		return filesys_media_change_reply (context, 1);
4339 	case 3:
4340 		t = getlocaltime ();
4341 		uae_u32 secs = (uae_u32)t - (8 * 365 + 2) * 24 * 60 * 60;
4342 		return secs;
4343 	}
4344 	return 0;
4345 }
4346 
action_examine_object(Unit * unit,dpacket packet)4347 static void action_examine_object (Unit *unit, dpacket packet)
4348 {
4349 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
4350 	uaecptr info = GET_PCK_ARG2 (packet) << 2;
4351 	a_inode *aino = 0;
4352 
4353 	TRACE((_T("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n"), lock, info));
4354 	DUMPLOCK(unit, lock);
4355 
4356 	if (lock != 0)
4357 		aino = aino_from_lock (unit, lock);
4358 	if (aino == 0)
4359 		aino = &unit->rootnode;
4360 
4361 	get_fileinfo (unit, packet, info, aino);
4362 	if (aino->dir) {
4363 		put_long (info, 0xFFFFFFFF);
4364 	} else
4365 		put_long (info, 0);
4366 }
4367 
4368 /* Read a directory's contents, create a_inodes for each file, and
4369    mark them as locked in memory so that recycle_aino will not reap
4370    them.
4371    We do this to avoid problems with the host OS: we don't want to
4372    leave the directory open on the host side until all ExNext()s have
4373    finished - they may never finish!  */
4374 
populate_directory(Unit * unit,a_inode * base)4375 static void populate_directory (Unit *unit, a_inode *base)
4376 {
4377 	struct fs_dirhandle *d;
4378 	a_inode *aino;
4379 
4380 	d = fs_opendir (unit, base);
4381 	if (!d)
4382 		return;
4383 	for (aino = base->child; aino; aino = aino->sibling) {
4384 		base->locked_children++;
4385 		unit->total_locked_ainos++;
4386 	}
4387 	TRACE3((_T("Populating directory, child %p, locked_children %d\n"),
4388 		base->child, base->locked_children));
4389 	for (;;) {
4390 		uae_u64 uniq = 0;
4391 		TCHAR fn[MAX_DPATH];
4392 		struct dirent *ok = NULL;
4393 		uae_u32 err;
4394 
4395 		/* Find next file that belongs to the Amiga fs (skipping things
4396 		like "..", "." etc.  */
4397 		do {
4398 			if (d->fstype == FS_ARCHIVE)
4399 				;///*fixme*/ok = zfile_readdir_archive (d->zd, fn);
4400 			else if (d->fstype == FS_DIRECTORY)
4401 				ok = my_readdir (d->od, 0);
4402 			else if (d->fstype == FS_CDFS)
4403 			;//	ok = isofs_readdir (d->isod, fn, &uniq);
4404 			else
4405 				ok = 0;
4406 		} while (ok && d->fstype == FS_DIRECTORY && fsdb_name_invalid (ok->d_name));
4407 		if (!ok)
4408 			break;
4409 		/* This calls init_child_aino, which will notice that the parent is
4410 		being ExNext()ed, and it will increment the locked counts.  */
4411 		aino = lookup_child_aino_for_exnext (unit, base, ok->d_name, &err, uniq);
4412 	}
4413 	fs_closedir (d);
4414 }
4415 
do_examine(Unit * unit,dpacket packet,ExamineKey * ek,uaecptr info)4416 static void do_examine (Unit *unit, dpacket packet, ExamineKey *ek, uaecptr info)
4417 {
4418 	for (;;) {
4419 		TCHAR *name;
4420 		if (ek->curr_file == 0)
4421 			break;
4422 		name = ek->curr_file->nname;
4423 		get_fileinfo (unit, packet, info, ek->curr_file);
4424 		ek->curr_file = ek->curr_file->sibling;
4425 		if (!(unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS)) && !fsdb_exists(name)) {
4426 			TRACE ((_T("%s orphaned"), name));
4427 			continue;
4428 		}
4429 		TRACE ((_T("curr_file set to %p %s\n"), ek->curr_file,
4430 			ek->curr_file ? ek->curr_file->aname : _T("NULL")));
4431 		return;
4432 	}
4433 	TRACE((_T("no more entries\n")));
4434 	free_exkey (unit, ek);
4435 	PUT_PCK_RES1 (packet, DOS_FALSE);
4436 	PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
4437 }
4438 
action_examine_next(Unit * unit,dpacket packet)4439 static void action_examine_next (Unit *unit, dpacket packet)
4440 {
4441 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
4442 	uaecptr info = GET_PCK_ARG2 (packet) << 2;
4443 	a_inode *aino = 0;
4444 	ExamineKey *ek;
4445 	uae_u32 uniq;
4446 
4447 	TRACE((_T("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n"), lock, info));
4448 	gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
4449 	DUMPLOCK(unit, lock);
4450 
4451 	if (lock != 0)
4452 		aino = aino_from_lock (unit, lock);
4453 	if (aino == 0)
4454 		aino = &unit->rootnode;
4455 	for(;;) {
4456 		uniq = get_long (info);
4457 		if (uniq == 0) {
4458 			write_log (_T("ExNext called for a file! (Houston?)\n"));
4459 			goto no_more_entries;
4460 		} else if (uniq == 0xFFFFFFFE)
4461 			goto no_more_entries;
4462 		else if (uniq == 0xFFFFFFFF) {
4463 			TRACE((_T("Creating new ExKey\n")));
4464 			ek = new_exkey (unit, aino);
4465 			if (ek) {
4466 				if (aino->exnext_count++ == 0)
4467 					populate_directory (unit, aino);
4468 				ek->curr_file = aino->child;
4469 				TRACE((_T("Initial curr_file: %p %s\n"), ek->curr_file,
4470 					ek->curr_file ? ek->curr_file->aname : _T("NULL")));
4471 			}
4472 		} else {
4473 			TRACE((_T("Looking up ExKey\n")));
4474 			ek = lookup_exkey (unit, get_long (info));
4475 		}
4476 		if (ek == 0) {
4477 			write_log (_T("Couldn't find a matching ExKey. Prepare for trouble.\n"));
4478 			goto no_more_entries;
4479 		}
4480 		put_long (info, ek->uniq);
4481 		if (!ek->curr_file || ek->curr_file->mountcount == unit->mountcount)
4482 			break;
4483 		ek->curr_file = ek->curr_file->sibling;
4484 		if (!ek->curr_file)
4485 			goto no_more_entries;
4486 	}
4487 	do_examine (unit, packet, ek, info);
4488 	return;
4489 
4490 no_more_entries:
4491 	PUT_PCK_RES1 (packet, DOS_FALSE);
4492 	PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
4493 }
4494 
do_find(Unit * unit,dpacket packet,int mode,int create,int fallback)4495 static void do_find (Unit *unit, dpacket packet, int mode, int create, int fallback)
4496 {
4497 	uaecptr fh = GET_PCK_ARG1 (packet) << 2;
4498 	uaecptr lock = GET_PCK_ARG2 (packet) << 2;
4499 	uaecptr name = GET_PCK_ARG3 (packet) << 2;
4500 	a_inode *aino;
4501 	Key *k;
4502 	struct fs_filehandle *fd;
4503 	int err;
4504 	mode_t openmode;
4505 	int aino_created = 0;
4506 	int isvirtual = unit->volflags & (MYVOLUMEINFO_ARCHIVE | MYVOLUMEINFO_CDFS);
4507 
4508 	TRACE((_T("ACTION_FIND_*(0x%08x,0x%08x,\"%s\",%d,%d)\n"), fh, lock, bstr (unit, name), mode, create));
4509 	TRACE((_T("fh=%x lock=%x name=%x\n"), fh, lock, name));
4510 	DUMPLOCK(unit, lock);
4511 
4512 	aino = find_aino (unit, lock, bstr (unit, name), &err);
4513 
4514 	if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) {
4515 		/* Whatever it is, we can't handle it. */
4516 		PUT_PCK_RES1 (packet, DOS_FALSE);
4517 		PUT_PCK_RES2 (packet, err);
4518 		return;
4519 	}
4520 	if (aino->softlink) {
4521 		handle_softlink (unit, packet, aino);
4522 		return;
4523 	}
4524 	if (err == 0) {
4525 		/* Object exists. */
4526 		if (aino->dir) {
4527 			PUT_PCK_RES1 (packet, DOS_FALSE);
4528 			PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
4529 			return;
4530 		}
4531 		if (aino->elock || (create == 2 && aino->shlock > 0)) {
4532 			PUT_PCK_RES1 (packet, DOS_FALSE);
4533 			PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
4534 			return;
4535 		}
4536 		if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) {
4537 			PUT_PCK_RES1 (packet, DOS_FALSE);
4538 			PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
4539 			return;
4540 		}
4541 		if (create != 2) {
4542 			if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || unit->ui.readonly || unit->ui.locked)
4543 				&& fallback)
4544 			{
4545 				mode &= ~A_FIBF_WRITE;
4546 			}
4547 			/* Kick 1.3 doesn't check read and write access bits - maybe it would be
4548 			* simpler just not to do that either. */
4549 			if ((mode & A_FIBF_WRITE) != 0 && (unit->ui.readonly || unit->ui.locked)) {
4550 				PUT_PCK_RES1 (packet, DOS_FALSE);
4551 				PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
4552 				return;
4553 			}
4554 			if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0
4555 				|| mode == 0)
4556 			{
4557 				PUT_PCK_RES1 (packet, DOS_FALSE);
4558 				PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED);
4559 				return;
4560 			}
4561 			if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) {
4562 				PUT_PCK_RES1 (packet, DOS_FALSE);
4563 				PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED);
4564 				return;
4565 			}
4566 		}
4567 	} else if (create == 0) {
4568 		PUT_PCK_RES1 (packet, DOS_FALSE);
4569 		PUT_PCK_RES2 (packet, err);
4570 		return;
4571 	} else {
4572 		/* Object does not exist. aino points to containing directory. */
4573 		aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 0);
4574 		if (aino == 0) {
4575 			PUT_PCK_RES1 (packet, DOS_FALSE);
4576 			PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
4577 			return;
4578 		}
4579 		aino_created = 1;
4580 	}
4581 
4582 	prepare_for_open (aino->nname);
4583 
4584 	openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY
4585 		: (mode & A_FIBF_WRITE) == 0 ? O_RDONLY
4586 		: O_RDWR)
4587 		| (create ? O_CREAT : 0)
4588 		| (create == 2 ? O_TRUNC : 0));
4589 
4590 	fd = fs_openfile (unit, aino, openmode | O_BINARY);
4591 	if (fd == NULL) {
4592 		if (aino_created)
4593 			delete_aino (unit, aino);
4594 		PUT_PCK_RES1 (packet, DOS_FALSE);
4595 		/* archive and fd == NULL = corrupt archive or out of memory */
4596 		PUT_PCK_RES2 (packet, isvirtual ? ERROR_OBJECT_NOT_AROUND : dos_errno ());
4597 		return;
4598 	}
4599 
4600 	k = new_key (unit);
4601 	k->fd = fd;
4602 	k->aino = aino;
4603 	k->dosmode = mode;
4604 	k->createmode = create;
4605 	k->notifyactive = create ? 1 : 0;
4606 
4607 	if (create && isvirtual)
4608 		fsdb_set_file_attrs (aino);
4609 
4610 	put_long (fh + 36, k->uniq);
4611 	if (create == 2) {
4612 		aino->elock = 1;
4613 		// clear comment if file already existed
4614 		if (aino->comment) {
4615 			xfree (aino->comment);
4616 			aino->comment = 0;
4617 		}
4618 		fsdb_set_file_attrs (aino);
4619 	} else {
4620 		aino->shlock++;
4621 	}
4622 	de_recycle_aino (unit, aino);
4623 
4624 	PUT_PCK_RES1 (packet, DOS_TRUE);
4625 }
4626 
4627 static void
action_fh_from_lock(Unit * unit,dpacket packet)4628 	action_fh_from_lock (Unit *unit, dpacket packet)
4629 {
4630 	uaecptr fh = GET_PCK_ARG1 (packet) << 2;
4631 	uaecptr lock = GET_PCK_ARG2 (packet) << 2;
4632 	a_inode *aino;
4633 	Key *k;
4634 	struct fs_filehandle *fd;
4635 	mode_t openmode;
4636 	int mode;
4637 
4638 	TRACE((_T("ACTION_FH_FROM_LOCK(0x%lx,0x%lx)\n"), fh, lock));
4639 	DUMPLOCK(unit,lock);
4640 
4641 	if (!lock) {
4642 		PUT_PCK_RES1 (packet, DOS_FALSE);
4643 		PUT_PCK_RES2 (packet, 0);
4644 		return;
4645 	}
4646 
4647 	aino = aino_from_lock (unit, lock);
4648 	if (aino == 0)
4649 		aino = &unit->rootnode;
4650 	if (aino->softlink) {
4651 		handle_softlink (unit, packet, aino);
4652 		return;
4653 	}
4654 
4655 	mode = aino->amigaos_mode; /* Use same mode for opened filehandle as existing Lock() */
4656 
4657 	prepare_for_open (aino->nname);
4658 
4659 	TRACE ((_T("  mode is %d\n"), mode));
4660 	openmode = (((mode & A_FIBF_READ) ? O_WRONLY
4661 		: (mode & A_FIBF_WRITE) ? O_RDONLY
4662 		: O_RDWR));
4663 
4664 	/* the files on CD really can have the write-bit set.  */
4665 	if (unit->ui.readonly || unit->ui.locked)
4666 		openmode = O_RDONLY;
4667 
4668 	fd = fs_openfile (unit, aino, openmode | O_BINARY);
4669 
4670 	if (fd == NULL) {
4671 		PUT_PCK_RES1 (packet, DOS_FALSE);
4672 		PUT_PCK_RES2 (packet, dos_errno ());
4673 		return;
4674 	}
4675 	k = new_key (unit);
4676 	k->fd = fd;
4677 	k->aino = aino;
4678 
4679 	put_long (fh + 36, k->uniq);
4680 	/* I don't think I need to play with shlock count here, because I'm
4681 	opening from an existing lock ??? */
4682 
4683 	de_recycle_aino (unit, aino);
4684 	free_lock (unit, lock); /* lock must be unlocked */
4685 	PUT_PCK_RES1 (packet, DOS_TRUE);
4686 	/* PUT_PCK_RES2 (packet, k->uniq); - this shouldn't be necessary, try without it */
4687 }
4688 
4689 static void
action_find_input(Unit * unit,dpacket packet)4690 	action_find_input (Unit *unit, dpacket packet)
4691 {
4692 	do_find (unit, packet, A_FIBF_READ | A_FIBF_WRITE, 0, 1);
4693 }
4694 
4695 static void
action_find_output(Unit * unit,dpacket packet)4696 	action_find_output (Unit *unit, dpacket packet)
4697 {
4698 	if (unit->ui.readonly || unit->ui.locked) {
4699 		PUT_PCK_RES1 (packet, DOS_FALSE);
4700 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
4701 		return;
4702 	}
4703 	do_find (unit, packet, A_FIBF_READ | A_FIBF_WRITE, 2, 0);
4704 }
4705 
4706 static void
action_find_write(Unit * unit,dpacket packet)4707 	action_find_write (Unit *unit, dpacket packet)
4708 {
4709 	if (unit->ui.readonly || unit->ui.locked) {
4710 		PUT_PCK_RES1 (packet, DOS_FALSE);
4711 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
4712 		return;
4713 	}
4714 	do_find (unit, packet, A_FIBF_READ | A_FIBF_WRITE, 1, 0);
4715 }
4716 
4717 /* change file/dir's parent dir modification time */
updatedirtime(a_inode * a1,int now)4718 static void updatedirtime (a_inode *a1, int now)
4719 {
4720 	struct mystat statbuf;
4721 
4722 	if (!a1->parent)
4723 		return;
4724 	if (!now) {
4725 		if (!my_stat (a1->nname, &statbuf))
4726 			return;
4727 		my_utime (a1->parent->nname, &statbuf.mtime);
4728 	} else {
4729 		my_utime (a1->parent->nname, NULL);
4730 	}
4731 }
4732 
4733 static void
action_end(Unit * unit,dpacket packet)4734 	action_end (Unit *unit, dpacket packet)
4735 {
4736 	Key *k;
4737 	TRACE((_T("ACTION_END(0x%lx)\n"), GET_PCK_ARG1 (packet)));
4738 
4739 	k = lookup_key (unit, GET_PCK_ARG1 (packet));
4740 	if (k != 0) {
4741 		if (k->notifyactive) {
4742 			notify_check (unit, k->aino);
4743 			updatedirtime (k->aino, 1);
4744 		}
4745 		if (k->aino->elock)
4746 			k->aino->elock = 0;
4747 		else
4748 			k->aino->shlock--;
4749 		recycle_aino (unit, k->aino);
4750 		free_key (unit, k);
4751 	}
4752 	PUT_PCK_RES1 (packet, DOS_TRUE);
4753 	PUT_PCK_RES2 (packet, 0);
4754 }
4755 
4756 static void
action_read(Unit * unit,dpacket packet)4757 	action_read (Unit *unit, dpacket packet)
4758 {
4759 	Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
4760 	uaecptr addr = GET_PCK_ARG2 (packet);
4761 	uae_u32 size = GET_PCK_ARG3 (packet);
4762 	uae_u32 actual = 0;
4763 
4764 	if (k == 0) {
4765 		PUT_PCK_RES1 (packet, DOS_FALSE);
4766 		/* PUT_PCK_RES2 (packet, EINVAL); */
4767 		return;
4768 	}
4769 	TRACE((_T("ACTION_READ(%s,0x%lx,%ld)\n"), k->aino->nname, addr, size));
4770 	gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
4771 
4772 	if (size == 0) {
4773 		PUT_PCK_RES1 (packet, 0);
4774 		PUT_PCK_RES2 (packet, 0);
4775 	} else if (!valid_address (addr, size)) {
4776 		/* check if filesize < size */
4777 		uae_s64 filesize, cur;
4778 
4779 		filesize = fs_fsize64 (k->fd);
4780 		cur = k->file_pos;
4781 		if (size > filesize - cur)
4782 			size = filesize - cur;
4783 
4784 		if (size == 0) {
4785 			PUT_PCK_RES1 (packet, 0);
4786 			PUT_PCK_RES2 (packet, 0);
4787 		} else if (!valid_address (addr, size)) {
4788 			/* it really crosses memory boundary */
4789 			uae_u8 *buf;
4790 
4791 			write_log (_T("unixfs warning: Bad pointer passed for read: %08x, size %d\n"), addr, size);
4792 			/* ugh this is inefficient but easy */
4793 
4794 			if ((uae_u64)-1 == fs_lseek64 (k->fd, k->file_pos, SEEK_SET)) {
4795 				PUT_PCK_RES1 (packet, 0);
4796 				PUT_PCK_RES2 (packet, dos_errno ());
4797 				return;
4798 			}
4799 
4800 		buf = xmalloc (uae_u8, size);
4801 		if (!buf) {
4802 			PUT_PCK_RES1 (packet, -1);
4803 			PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
4804 			return;
4805 		}
4806 
4807 		actual = fs_read (k->fd, buf, size);
4808 
4809 			if (actual < 0) {
4810 				PUT_PCK_RES1 (packet, 0);
4811 				PUT_PCK_RES2 (packet, dos_errno ());
4812 			} else {
4813 				int i;
4814 			PUT_PCK_RES1 (packet, actual);
4815 			for ( ; i < actual; i++)
4816 				put_byte (addr + i, buf[i]);
4817 			k->file_pos += actual;
4818 		}
4819 		xfree (buf);
4820 			flush_dcache (addr, size);
4821 			size = 0;
4822 		}
4823 	}
4824 	if (size) {
4825 		/* normal fast read */
4826 		uae_u8 *realpt = get_real_address (addr);
4827 
4828 		if ((uae_u64)-1 == fs_lseek64 (k->fd, k->file_pos, SEEK_SET)) {
4829 			PUT_PCK_RES1 (packet, 0);
4830 			PUT_PCK_RES2 (packet, dos_errno ());
4831 			return;
4832 		}
4833 
4834 		actual = fs_read (k->fd, realpt, size);
4835 
4836 		if (actual == 0) {
4837 			PUT_PCK_RES1 (packet, 0);
4838 			PUT_PCK_RES2 (packet, 0);
4839 		} else if ((uae_u32)-1 == actual) {
4840 			PUT_PCK_RES1 (packet, 0);
4841 			PUT_PCK_RES2 (packet, dos_errno ());
4842 		} else {
4843 			PUT_PCK_RES1 (packet, actual);
4844 			k->file_pos += actual;
4845 		}
4846 		flush_dcache (addr, size);
4847 	}
4848 
4849 	TRACE((_T("=%d\n"), actual));
4850 }
4851 
4852 static void
action_write(Unit * unit,dpacket packet)4853 	action_write (Unit *unit, dpacket packet)
4854 {
4855 	Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
4856 	uaecptr addr = GET_PCK_ARG2 (packet);
4857 	uae_u32 size = GET_PCK_ARG3 (packet);
4858 	uae_u32 actual;
4859 	uae_u8 *buf;
4860 	uae_u32 i;
4861 
4862 	if (k == 0) {
4863 		PUT_PCK_RES1 (packet, DOS_FALSE);
4864 		/* PUT_PCK_RES2 (packet, EINVAL); */
4865 		return;
4866 	}
4867 
4868 	gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
4869 	TRACE((_T("ACTION_WRITE(%s,0x%lx,%ld)\n"), k->aino->nname, addr, size));
4870 
4871 	if (unit->ui.readonly || unit->ui.locked) {
4872 		PUT_PCK_RES1 (packet, DOS_FALSE);
4873 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
4874 		return;
4875 	}
4876 
4877 	if (size == 0) {
4878 		actual = 0;
4879 		PUT_PCK_RES1 (packet, 0);
4880 		PUT_PCK_RES2 (packet, 0);
4881 	} else if (valid_address (addr, size)) {
4882 		uae_u8 *realpt = get_real_address (addr);
4883 
4884 		if ((uae_u64)-1 == fs_lseek64 (k->fd, k->file_pos, SEEK_SET)) {
4885 			PUT_PCK_RES1 (packet, 0);
4886 			PUT_PCK_RES2 (packet, dos_errno ());
4887 			return;
4888 		}
4889 
4890 		actual = fs_write (k->fd, realpt, size);
4891 	} else {
4892 		write_log (_T("unixfs warning: Bad pointer passed for write: %08x, size %d\n"), addr, size);
4893 		/* ugh this is inefficient but easy */
4894 
4895 		if ((uae_u64)-1 == fs_lseek64 (k->fd, k->file_pos, SEEK_SET)) {
4896 			PUT_PCK_RES1 (packet, 0);
4897 			PUT_PCK_RES2 (packet, dos_errno ());
4898 			return;
4899 		}
4900 
4901 		buf = xmalloc (uae_u8, size);
4902 		if (!buf) {
4903 			PUT_PCK_RES1 (packet, -1);
4904 			PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
4905 			return;
4906 		}
4907 
4908 		for (i = 0; i < size; i++)
4909 			buf[i] = get_byte (addr + i);
4910 
4911 		actual = fs_write (k->fd, buf, size);
4912 		xfree (buf);
4913 	}
4914 
4915 	TRACE((_T("=%d\n"), actual));
4916 	PUT_PCK_RES1 (packet, actual);
4917 	if (actual != size)
4918 		PUT_PCK_RES2 (packet, dos_errno ());
4919 	if ((uae_u32)-1 != actual)
4920 		k->file_pos += actual;
4921 
4922 	k->notifyactive = 1;
4923 }
4924 
4925 static void
action_seek(Unit * unit,dpacket packet)4926 	action_seek (Unit *unit, dpacket packet)
4927 {
4928 	Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
4929 	long pos = (uae_s32)GET_PCK_ARG2 (packet);
4930 	long mode = (uae_s32)GET_PCK_ARG3 (packet);
4931 	uae_s64 res;
4932 	uae_s64 cur;
4933 	int whence = SEEK_CUR;
4934 	uae_s64 temppos = 0, filesize = 0;
4935 
4936 	if (k == 0) {
4937 		PUT_PCK_RES1 (packet, -1);
4938 		PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
4939 		return;
4940 	}
4941 
4942 	if (mode > 0)
4943 		whence = SEEK_END;
4944 	if (mode < 0)
4945 		whence = SEEK_SET;
4946 
4947 	cur = k->file_pos;
4948 	TRACE((_T("ACTION_SEEK(%s,%d,%d)=%d\n"), k->aino->nname, pos, mode, cur));
4949 	gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
4950 
4951 	filesize = fs_fsize64 (k->fd);
4952 	if (whence == SEEK_CUR)
4953 		temppos = cur + pos;
4954 	if (whence == SEEK_SET)
4955 		temppos = pos;
4956 	if (whence == SEEK_END)
4957 		temppos = filesize + pos;
4958 	if (filesize < temppos) {
4959 		PUT_PCK_RES1 (packet, -1);
4960 		PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
4961 		return;
4962 	}
4963 
4964 	res = fs_lseek64 (k->fd, pos, whence);
4965 	if (-1 == res || cur > MAXFILESIZE32) {
4966 		PUT_PCK_RES1 (packet, -1);
4967 		PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
4968 		fs_lseek64 (k->fd, cur, SEEK_SET);
4969 	} else {
4970 		PUT_PCK_RES1 (packet, cur);
4971 		k->file_pos = fs_lseek64 (k->fd, 0, SEEK_CUR);
4972 	}
4973 }
4974 
4975 static void
action_set_protect(Unit * unit,dpacket packet)4976 	action_set_protect (Unit *unit, dpacket packet)
4977 {
4978 	uaecptr lock = GET_PCK_ARG2 (packet) << 2;
4979 	uaecptr name = GET_PCK_ARG3 (packet) << 2;
4980 	uae_u32 mask = GET_PCK_ARG4 (packet);
4981 	a_inode *a;
4982 	int err;
4983 
4984 	TRACE((_T("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n"), lock, bstr (unit, name), mask));
4985 
4986 	if (unit->ui.readonly || unit->ui.locked) {
4987 		PUT_PCK_RES1 (packet, DOS_FALSE);
4988 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
4989 		return;
4990 	}
4991 
4992 	a = find_aino (unit, lock, bstr (unit, name), &err);
4993 	if (err != 0) {
4994 		PUT_PCK_RES1 (packet, DOS_FALSE);
4995 		PUT_PCK_RES2 (packet, err);
4996 		return;
4997 	}
4998 	if (a->softlink) {
4999 		handle_softlink (unit, packet, a);
5000 		return;
5001 	}
5002 
5003 	a->amigaos_mode = mask;
5004 	if (!fsdb_cando (unit))
5005 		a->amigaos_mode = fsdb_mode_supported (a);
5006 	err = fsdb_set_file_attrs (a);
5007 	if (err != 0) {
5008 		PUT_PCK_RES1 (packet, DOS_FALSE);
5009 		PUT_PCK_RES2 (packet, err);
5010 	} else {
5011 		PUT_PCK_RES1 (packet, DOS_TRUE);
5012 	}
5013 	notify_check (unit, a);
5014 	gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
5015 }
5016 
action_set_comment(Unit * unit,dpacket packet)5017 static void action_set_comment (Unit * unit, dpacket packet)
5018 {
5019 	uaecptr lock = GET_PCK_ARG2 (packet) << 2;
5020 	uaecptr name = GET_PCK_ARG3 (packet) << 2;
5021 	uaecptr comment = GET_PCK_ARG4 (packet) << 2;
5022 	TCHAR *commented = NULL;
5023 	a_inode *a;
5024 	int err;
5025 
5026 	if (unit->ui.readonly || unit->ui.locked) {
5027 		PUT_PCK_RES1 (packet, DOS_FALSE);
5028 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
5029 		return;
5030 	}
5031 
5032 	if (fsdb_cando (unit)) {
5033 		commented = bstr (unit, comment);
5034 		if (_tcslen (commented) > 80) {
5035 			PUT_PCK_RES1 (packet, DOS_FALSE);
5036 			PUT_PCK_RES2 (packet, ERROR_COMMENT_TOO_BIG);
5037 			return;
5038 		}
5039 		if (_tcslen (commented) > 0) {
5040 			TCHAR *p = commented;
5041 			commented = xmalloc (TCHAR, 81);
5042 			_tcsncpy (commented, p, 80);
5043 			commented[80] = 0;
5044 		} else {
5045 			commented = NULL;
5046 		}
5047 	}
5048 	TRACE ((_T("ACTION_SET_COMMENT(0x%lx,\"%s\")\n"), lock, commented));
5049 
5050 	a = find_aino (unit, lock, bstr (unit, name), &err);
5051 	if (err != 0) {
5052 		PUT_PCK_RES1 (packet, DOS_FALSE);
5053 		PUT_PCK_RES2 (packet, err);
5054 
5055 maybe_free_and_out:
5056 		if (commented)
5057 			xfree (commented);
5058 		return;
5059 	}
5060 	if (a->softlink) {
5061 		handle_softlink (unit, packet, a);
5062 		goto maybe_free_and_out;
5063 	}
5064 
5065 	PUT_PCK_RES1 (packet, DOS_TRUE);
5066 	PUT_PCK_RES2 (packet, 0);
5067 	if (a->comment == 0 && commented == 0)
5068 		goto maybe_free_and_out;
5069 	if (a->comment != 0 && commented != 0 && _tcscmp (a->comment, commented) == 0)
5070 		goto maybe_free_and_out;
5071 	if (a->comment)
5072 		xfree (a->comment);
5073 	a->comment = commented;
5074 	fsdb_set_file_attrs (a);
5075 	notify_check (unit, a);
5076 	gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
5077 }
5078 
5079 static void
action_same_lock(Unit * unit,dpacket packet)5080 	action_same_lock (Unit *unit, dpacket packet)
5081 {
5082 	uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
5083 	uaecptr lock2 = GET_PCK_ARG2 (packet) << 2;
5084 
5085 	TRACE((_T("ACTION_SAME_LOCK(0x%lx,0x%lx)\n"), lock1, lock2));
5086 	DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2);
5087 
5088 	if (!lock1 || !lock2) {
5089 		PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE);
5090 	} else {
5091 		PUT_PCK_RES1 (packet, get_long (lock1 + 4) == get_long (lock2 + 4) ? DOS_TRUE : DOS_FALSE);
5092 	}
5093 }
5094 
5095 static void
action_change_mode(Unit * unit,dpacket packet)5096 	action_change_mode (Unit *unit, dpacket packet)
5097 {
5098 #define CHANGE_LOCK 0
5099 #define CHANGE_FH 1
5100 	/* will be CHANGE_FH or CHANGE_LOCK value */
5101 	long type = GET_PCK_ARG1 (packet);
5102 	/* either a file-handle or lock */
5103 	uaecptr object = GET_PCK_ARG2 (packet) << 2;
5104 	/* will be EXCLUSIVE_LOCK/SHARED_LOCK if CHANGE_LOCK,
5105 	* or MODE_OLDFILE/MODE_NEWFILE/MODE_READWRITE if CHANGE_FH *
5106 	* Above is wrong, it is always *_LOCK. TW. */
5107 	long mode = GET_PCK_ARG3 (packet);
5108 	unsigned long uniq;
5109 	a_inode *a = NULL;
5110 // REMOVEME:
5111 #if 0
5112 	a_inode *olda = NULL;
5113 #endif
5114 	int err = 0;
5115 	TRACE((_T("ACTION_CHANGE_MODE(0x%lx,%d,%d)\n"), object, type, mode));
5116 
5117 	if (! object || (type != CHANGE_FH && type != CHANGE_LOCK)) {
5118 		PUT_PCK_RES1 (packet, DOS_FALSE);
5119 		PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
5120 		return;
5121 	}
5122 
5123 	if (type == CHANGE_LOCK) {
5124 		uniq = get_long (object + 4);
5125 	} else {
5126 		Key *k = lookup_key (unit, get_long (object + 36));
5127 		if (!k) {
5128 			PUT_PCK_RES1 (packet, DOS_FALSE);
5129 			PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
5130 			return;
5131 		}
5132 		uniq = k->aino->uniq;
5133 	}
5134 	a = lookup_aino (unit, uniq);
5135 
5136 	if (! a) {
5137 		err = ERROR_INVALID_LOCK;
5138 	} else {
5139 		if (mode == -1) {
5140 			if (a->shlock > 1) {
5141 				err = ERROR_OBJECT_IN_USE;
5142 			} else {
5143 				a->shlock = 0;
5144 				a->elock = 1;
5145 			}
5146 		} else { /* Must be SHARED_LOCK == -2 */
5147 			a->elock = 0;
5148 			a->shlock++;
5149 		}
5150 	}
5151 
5152 	if (err) {
5153 		PUT_PCK_RES1 (packet, DOS_FALSE);
5154 		PUT_PCK_RES2 (packet, err);
5155 		return;
5156 	} else {
5157 		de_recycle_aino (unit, a);
5158 		PUT_PCK_RES1 (packet, DOS_TRUE);
5159 	}
5160 }
5161 
5162 static void
action_parent_common(Unit * unit,dpacket packet,unsigned long uniq)5163 	action_parent_common (Unit *unit, dpacket packet, unsigned long uniq)
5164 {
5165 	a_inode *olda = lookup_aino (unit, uniq);
5166 	if (olda == 0) {
5167 		PUT_PCK_RES1 (packet, DOS_FALSE);
5168 		PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
5169 		return;
5170 	}
5171 
5172 	if (olda->parent == 0) {
5173 		PUT_PCK_RES1 (packet, 0);
5174 		PUT_PCK_RES2 (packet, 0);
5175 		return;
5176 	}
5177 	if (olda->parent->elock) {
5178 		PUT_PCK_RES1 (packet, DOS_FALSE);
5179 		PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
5180 		return;
5181 	}
5182 	olda->parent->shlock++;
5183 	de_recycle_aino (unit, olda->parent);
5184 	PUT_PCK_RES1 (packet, make_lock (unit, olda->parent->uniq, -2) >> 2);
5185 }
5186 
5187 static void
action_parent_fh(Unit * unit,dpacket packet)5188 	action_parent_fh (Unit *unit, dpacket packet)
5189 {
5190 	Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
5191 	if (!k) {
5192 		PUT_PCK_RES1 (packet, DOS_FALSE);
5193 		PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
5194 		return;
5195 	}
5196 	action_parent_common (unit, packet, k->aino->uniq);
5197 }
5198 
5199 static void
action_parent(Unit * unit,dpacket packet)5200 	action_parent (Unit *unit, dpacket packet)
5201 {
5202 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
5203 
5204 	TRACE((_T("ACTION_PARENT(0x%lx)\n"),lock));
5205 
5206 	if (!lock) {
5207 		PUT_PCK_RES1 (packet, 0);
5208 		PUT_PCK_RES2 (packet, 0);
5209 	} else {
5210 		action_parent_common (unit, packet, get_long (lock + 4));
5211 	}
5212 	TRACE((_T("=%x %d\n"), GET_PCK_RES1 (packet), GET_PCK_RES2 (packet)));
5213 }
5214 
5215 #ifdef _WIN32
my_mkdir(const TCHAR * name)5216 int my_mkdir (const TCHAR *name)
5217 {
5218         const TCHAR *namep;
5219         TCHAR path[MAX_DPATH];
5220 /*
5221         if (currprefs.win32_filesystem_mangle_reserved_names == false) {
5222                 _tcscpy (path, PATHPREFIX);
5223                 _tcscat (path, name);
5224                 namep = path;
5225         } else */{
5226                 namep = name;
5227         }
5228         return CreateDirectory (namep, NULL) == 0 ? -1 : 0;
5229 }
5230 #endif
5231 
5232 static void
action_create_dir(Unit * unit,dpacket packet)5233 	action_create_dir (Unit *unit, dpacket packet)
5234 {
5235 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
5236 	uaecptr name = GET_PCK_ARG2 (packet) << 2;
5237 	a_inode *aino;
5238 	int err;
5239 
5240 	TRACE((_T("ACTION_CREATE_DIR(0x%lx,\"%s\")\n"), lock, bstr (unit, name)));
5241 
5242 	if (unit->ui.readonly || unit->ui.locked) {
5243 		PUT_PCK_RES1 (packet, DOS_FALSE);
5244 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
5245 		return;
5246 	}
5247 
5248 	aino = find_aino (unit, lock, bstr (unit, name), &err);
5249 	if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) {
5250 		PUT_PCK_RES1 (packet, DOS_FALSE);
5251 		PUT_PCK_RES2 (packet, err);
5252 		return;
5253 	}
5254 	if (err == 0) {
5255 		/* Object exists. */
5256 		PUT_PCK_RES1 (packet, DOS_FALSE);
5257 		PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS);
5258 		return;
5259 	}
5260 	/* Object does not exist. aino points to containing directory. */
5261 	aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1);
5262 	if (aino == 0) {
5263 		PUT_PCK_RES1 (packet, DOS_FALSE);
5264 		PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
5265 		return;
5266 	}
5267 #ifdef _WIN32
5268    if (my_mkdir (aino->nname) == -1) {
5269                 PUT_PCK_RES1 (packet, DOS_FALSE);
5270                 PUT_PCK_RES2 (packet, dos_errno ());
5271                 return;
5272         }
5273 #else
5274 	if (mkdir (aino->nname, 0777) == -1) {
5275 		PUT_PCK_RES1 (packet, DOS_FALSE);
5276 		PUT_PCK_RES2 (packet, dos_errno ());
5277 		return;
5278 	}
5279 #endif
5280 	aino->shlock = 1;
5281 	fsdb_set_file_attrs (aino);
5282 	de_recycle_aino (unit, aino);
5283 	notify_check (unit, aino);
5284 	updatedirtime (aino, 0);
5285 	PUT_PCK_RES1 (packet, make_lock (unit, aino->uniq, -2) >> 2);
5286 	gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
5287 }
5288 
5289 static void
action_examine_fh(Unit * unit,dpacket packet)5290 	action_examine_fh (Unit *unit, dpacket packet)
5291 {
5292 	Key *k;
5293 	a_inode *aino = 0;
5294 	uaecptr info = GET_PCK_ARG2 (packet) << 2;
5295 
5296 	TRACE((_T("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n"),
5297 		GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) ));
5298 
5299 	k = lookup_key (unit, GET_PCK_ARG1 (packet));
5300 	if (k != 0)
5301 		aino = k->aino;
5302 	if (aino == 0)
5303 		aino = &unit->rootnode;
5304 
5305 	get_fileinfo (unit, packet, info, aino);
5306 	if (aino->dir)
5307 		put_long (info, 0xFFFFFFFF);
5308 	else
5309 		put_long (info, 0);
5310 }
5311 
5312 /* For a nice example of just how contradictory documentation can be, see the
5313  * Autodoc for DOS:SetFileSize and the Packets.txt description of this packet...
5314  * This implementation tries to mimic the behaviour of the Kick 3.1 ramdisk
5315  * (which seems to match the Autodoc description). */
5316 static void
action_set_file_size(Unit * unit,dpacket packet)5317 	action_set_file_size (Unit *unit, dpacket packet)
5318 {
5319 	Key *k, *k1;
5320 	off_t offset = GET_PCK_ARG2 (packet);
5321 	long mode = (uae_s32)GET_PCK_ARG3 (packet);
5322 	int whence = SEEK_CUR;
5323 
5324 	if (mode > 0)
5325 		whence = SEEK_END;
5326 	if (mode < 0)
5327 		whence = SEEK_SET;
5328 
5329 	TRACE((_T("ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n"), GET_PCK_ARG1 (packet), offset, mode));
5330 
5331 	k = lookup_key (unit, GET_PCK_ARG1 (packet));
5332 	if (k == 0) {
5333 		PUT_PCK_RES1 (packet, DOS_TRUE);
5334 		PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
5335 		return;
5336 	}
5337 
5338 	gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
5339 	k->notifyactive = 1;
5340 	/* If any open files have file pointers beyond this size, truncate only
5341 	* so far that these pointers do not become invalid.  */
5342 	for (k1 = unit->keys; k1; k1 = k1->next) {
5343 		if (k != k1 && k->aino == k1->aino) {
5344 			if (k1->file_pos > offset)
5345 				offset = (off_t)k1->file_pos;
5346 		}
5347 	}
5348 
5349 	/* Write one then truncate: that should give the right size in all cases.  */
5350 	fs_lseek (k->fd, offset, whence);
5351 	offset = fs_lseek (k->fd, 0, SEEK_CUR);
5352 	fs_write (k->fd, /* whatever */(uae_u8*)&k1, 1);
5353 	if (k->file_pos > offset)
5354 		k->file_pos = offset;
5355 	fs_lseek (k->fd, (off_t)k->file_pos, SEEK_SET);
5356 
5357 	/* Brian: no bug here; the file _must_ be one byte too large after writing
5358 	 * The write is supposed to guarantee that the file can't be smaller than
5359 	 * the requested size, the truncate guarantees that it can't be larger.
5360 	 * If we were to write one byte earlier we'd clobber file data.  */
5361 	if (my_truncate (k->aino->nname, offset) == -1) {
5362 		PUT_PCK_RES1 (packet, DOS_FALSE);
5363 		PUT_PCK_RES2 (packet, dos_errno ());
5364 		return;
5365 	}
5366 
5367 	PUT_PCK_RES1 (packet, offset);
5368 	PUT_PCK_RES2 (packet, 0);
5369 }
5370 
relock_do(Unit * unit,a_inode * a1)5371 static int relock_do(Unit *unit, a_inode *a1)
5372 {
5373 	Key *k1, *knext;
5374 	int wehavekeys = 0;
5375 
5376 	for (k1 = unit->keys; k1; k1 = knext) {
5377 		knext = k1->next;
5378 		if (k1->aino == a1 && k1->fd) {
5379 			wehavekeys++;
5380 			fs_closefile (k1->fd);
5381 			write_log (_T("handle %p freed\n"), k1->fd);
5382 		}
5383 	}
5384 	return wehavekeys;
5385 }
5386 
relock_re(Unit * unit,a_inode * a1,a_inode * a2,int failed)5387 static void relock_re (Unit *unit, a_inode *a1, a_inode *a2, int failed)
5388 {
5389 	Key *k1, *knext;
5390 
5391 	for (k1 = unit->keys; k1; k1 = knext) {
5392 		knext = k1->next;
5393 		if (k1->aino == a1 && k1->fd) {
5394 			int mode = (k1->dosmode & A_FIBF_READ) == 0 ? O_WRONLY : (k1->dosmode & A_FIBF_WRITE) == 0 ? O_RDONLY : O_RDWR;
5395 			mode |= O_BINARY;
5396 			if (failed) {
5397 				/* rename still failed, restore fd */
5398 				k1->fd = fs_openfile (unit, a1, mode);
5399 				write_log (_T("restoring old handle '%s' %d\n"), a1->nname, k1->dosmode);
5400 			} else {
5401 				/* transfer fd to new name */
5402 				if (a2) {
5403 					k1->aino = a2;
5404 					k1->fd = fs_openfile (unit, a2, mode);
5405 					write_log (_T("restoring new handle '%s' %d\n"), a2->nname, k1->dosmode);
5406 				} else {
5407 					write_log (_T("no new handle, deleting old lock(s).\n"));
5408 				}
5409 			}
5410 			if (k1->fd == NULL) {
5411 				write_log (_T("relocking failed '%s' -> '%s'\n"), a1->nname, a2->nname);
5412 				free_key (unit, k1);
5413 			} else {
5414 				fs_lseek64 (k1->fd, k1->file_pos, SEEK_SET);
5415 			}
5416 		}
5417 	}
5418 }
5419 
5420 static void
action_delete_object(Unit * unit,dpacket packet)5421 	action_delete_object (Unit *unit, dpacket packet)
5422 {
5423 	uaecptr lock = GET_PCK_ARG1 (packet) << 2;
5424 	uaecptr name = GET_PCK_ARG2 (packet) << 2;
5425 	a_inode *a;
5426 	int err;
5427 
5428 	TRACE((_T("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n"), lock, bstr (unit, name)));
5429 
5430 	if (unit->ui.readonly || unit->ui.locked) {
5431 		PUT_PCK_RES1 (packet, DOS_FALSE);
5432 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
5433 		return;
5434 	}
5435 
5436 	a = find_aino (unit, lock, bstr (unit, name), &err);
5437 
5438 	if (err != 0) {
5439 		PUT_PCK_RES1 (packet, DOS_FALSE);
5440 		PUT_PCK_RES2 (packet, err);
5441 		return;
5442 	}
5443 	if (a->amigaos_mode & A_FIBF_DELETE) {
5444 		PUT_PCK_RES1 (packet, DOS_FALSE);
5445 		PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
5446 		return;
5447 	}
5448 	if (a->shlock > 0 || a->elock) {
5449 		PUT_PCK_RES1 (packet, DOS_FALSE);
5450 		PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
5451 		return;
5452 	}
5453 	if (a->dir) {
5454 		/* This should take care of removing the fsdb if no files remain.  */
5455 		fsdb_dir_writeback (a);
5456 		if (my_rmdir (a->nname) == -1) {
5457 			PUT_PCK_RES1 (packet, DOS_FALSE);
5458 			PUT_PCK_RES2 (packet, dos_errno ());
5459 			return;
5460 		}
5461 	} else {
5462 		if (my_unlink (a->nname) == -1) {
5463 			PUT_PCK_RES1 (packet, DOS_FALSE);
5464 			PUT_PCK_RES2 (packet, dos_errno ());
5465 			return;
5466 		}
5467 	}
5468 	notify_check (unit, a);
5469 	updatedirtime (a, 1);
5470 	if (a->child != 0) {
5471 		write_log (_T("Serious error in action_delete_object.\n"));
5472 		a->deleted = 1;
5473 	} else {
5474 		delete_aino (unit, a);
5475 	}
5476 	PUT_PCK_RES1 (packet, DOS_TRUE);
5477 	gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
5478 }
5479 
5480 static void
action_set_date(Unit * unit,dpacket packet)5481 	action_set_date (Unit *unit, dpacket packet)
5482 {
5483 	uaecptr lock = GET_PCK_ARG2 (packet) << 2;
5484 	uaecptr name = GET_PCK_ARG3 (packet) << 2;
5485 	uaecptr date = GET_PCK_ARG4 (packet);
5486 	a_inode *a;
5487 	struct mytimeval tv;
5488 	int err;
5489 
5490 	TRACE((_T("ACTION_SET_DATE(0x%lx,\"%s\")\n"), lock, bstr (unit, name)));
5491 
5492 	if (unit->ui.readonly || unit->ui.locked) {
5493 		PUT_PCK_RES1 (packet, DOS_FALSE);
5494 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
5495 		return;
5496 	}
5497 
5498 	a = find_aino (unit, lock, bstr (unit, name), &err);
5499 	if (err != 0) {
5500 		PUT_PCK_RES1 (packet, DOS_FALSE);
5501 		PUT_PCK_RES2 (packet, err);
5502 		return;
5503 	}
5504 	if (a->softlink) {
5505 		handle_softlink (unit, packet, a);
5506 		return;
5507 	}
5508 	amiga_to_timeval (&tv, get_long (date), get_long (date + 4), get_long (date + 8));
5509 	write_log (_T("%llu.%u (%d,%d,%d) %s\n"), tv.tv_sec, tv.tv_usec, get_long (date), get_long (date + 4), get_long (date + 8), a->nname);
5510 	if (!my_utime (a->nname, &tv))
5511 		err = dos_errno ();
5512 	if (err != 0) {
5513 		PUT_PCK_RES1 (packet, DOS_FALSE);
5514 		PUT_PCK_RES2 (packet, err);
5515 		return;
5516 	} else {
5517 		notify_check (unit, a);
5518 		PUT_PCK_RES1 (packet, DOS_TRUE);
5519 	}
5520 	gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
5521 }
5522 
5523 static void
action_rename_object(Unit * unit,dpacket packet)5524 	action_rename_object (Unit *unit, dpacket packet)
5525 {
5526 	uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
5527 	uaecptr name1 = GET_PCK_ARG2 (packet) << 2;
5528 	uaecptr lock2 = GET_PCK_ARG3 (packet) << 2;
5529 	uaecptr name2 = GET_PCK_ARG4 (packet) << 2;
5530 	a_inode *a1, *a2;
5531 	int err1, err2;
5532 	Key *k1, *knext;
5533 	int wehavekeys = 0;
5534 
5535 	TRACE((_T("ACTION_RENAME_OBJECT(0x%lx,\"%s\","), lock1, bstr (unit, name1)));
5536 	TRACE((_T("0x%lx,\"%s\")\n"), lock2, bstr (unit, name2)));
5537 
5538 	if (unit->ui.readonly || unit->ui.locked) {
5539 		PUT_PCK_RES1 (packet, DOS_FALSE);
5540 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
5541 		return;
5542 	}
5543 
5544 	a1 = find_aino (unit, lock1, bstr (unit, name1), &err1);
5545 	if (err1 != 0) {
5546 		PUT_PCK_RES1 (packet, DOS_FALSE);
5547 		PUT_PCK_RES2 (packet, err1);
5548 		return;
5549 	}
5550 
5551 	/* rename always fails if file is open for writing */
5552 	for (k1 = unit->keys; k1; k1 = knext) {
5553 		knext = k1->next;
5554 		if (k1->aino == a1 && k1->fd && k1->createmode == 2) {
5555 			PUT_PCK_RES1 (packet, DOS_FALSE);
5556 			PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
5557 			return;
5558 		}
5559 	}
5560 
5561 	/* See whether the other name already exists in the filesystem.  */
5562 	a2 = find_aino (unit, lock2, bstr (unit, name2), &err2);
5563 
5564 	if (a2 == a1) {
5565 		/* Renaming to the same name, but possibly different case.  */
5566 		if (_tcscmp (a1->aname, bstr_cut (unit, name2)) == 0) {
5567 			/* Exact match -> do nothing.  */
5568 			notify_check (unit, a1);
5569 			updatedirtime (a1, 1);
5570 			PUT_PCK_RES1 (packet, DOS_TRUE);
5571 			return;
5572 		}
5573 		a2 = a2->parent;
5574 	} else if (a2 == 0 || err2 != ERROR_OBJECT_NOT_AROUND) {
5575 		PUT_PCK_RES1 (packet, DOS_FALSE);
5576 		PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2);
5577 		return;
5578 	}
5579 
5580 	a2 = create_child_aino (unit, a2, bstr_cut (unit, name2), a1->dir);
5581 	if (a2 == 0) {
5582 		PUT_PCK_RES1 (packet, DOS_FALSE);
5583 		PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
5584 		return;
5585 	}
5586 
5587 	if (-1 == my_rename (a1->nname, a2->nname)) {
5588 		int ret = -1;
5589 		/* maybe we have open file handles that caused failure? */
5590 		write_log (_T("rename '%s' -> '%s' failed, trying relocking..\n"), a1->nname, a2->nname);
5591 		wehavekeys = relock_do (unit, a1);
5592 		/* try again... */
5593 		ret = my_rename (a1->nname, a2->nname);
5594 		/* restore locks */
5595 		relock_re (unit, a1, a2, ret == -1 ? 1 : 0);
5596 		if (ret == -1) {
5597 			delete_aino (unit, a2);
5598 			PUT_PCK_RES1 (packet, DOS_FALSE);
5599 			PUT_PCK_RES2 (packet, dos_errno ());
5600 			return;
5601 		}
5602 	}
5603 
5604 	notify_check (unit, a1);
5605 	notify_check (unit, a2);
5606 	a2->comment = a1->comment;
5607 	a1->comment = 0;
5608 	a2->amigaos_mode = a1->amigaos_mode;
5609 	a2->uniq = a1->uniq;
5610 	a2->elock = a1->elock;
5611 	a2->shlock = a1->shlock;
5612 	a2->has_dbentry = a1->has_dbentry;
5613 	a2->db_offset = a1->db_offset;
5614 	a2->dirty = 0;
5615 	move_exkeys (unit, a1, a2);
5616 	move_aino_children (unit, a1, a2);
5617 	delete_aino (unit, a1);
5618 	a2->dirty = 1;
5619 	if (a2->parent)
5620 		fsdb_dir_writeback (a2->parent);
5621 	updatedirtime (a2, 1);
5622 	fsdb_set_file_attrs (a2);
5623 	if (a2->elock > 0 || a2->shlock > 0 || wehavekeys > 0)
5624 		de_recycle_aino (unit, a2);
5625 	PUT_PCK_RES1 (packet, DOS_TRUE);
5626 	gui_flicker_led (UNIT_LED(unit), unit->unit, 2);
5627 }
5628 
5629 static void
action_current_volume(Unit * unit,dpacket packet)5630 	action_current_volume (Unit *unit, dpacket packet)
5631 {
5632 	if (filesys_isvolume(unit))
5633 		PUT_PCK_RES1 (packet, unit->volume >> 2);
5634 	else
5635 		PUT_PCK_RES1 (packet, 0);
5636 }
5637 
5638 static void
action_rename_disk(Unit * unit,dpacket packet)5639 	action_rename_disk (Unit *unit, dpacket packet)
5640 {
5641 	uaecptr name = GET_PCK_ARG1 (packet) << 2;
5642 
5643 	TRACE((_T("ACTION_RENAME_DISK(\"%s\")\n"), bstr (unit, name)));
5644 
5645 	if (unit->ui.readonly || unit->ui.locked) {
5646 		PUT_PCK_RES1 (packet, DOS_FALSE);
5647 		PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
5648 		return;
5649 	}
5650 
5651 	/* get volume name */
5652 	xfree (unit->ui.volname);
5653 	unit->ui.volname = bstr1 (name);
5654 	set_volume_name (unit, 0);
5655 
5656 	PUT_PCK_RES1 (packet, DOS_TRUE);
5657 }
5658 
5659 static void
action_is_filesystem(Unit * unit,dpacket packet)5660 	action_is_filesystem (Unit *unit, dpacket packet)
5661 {
5662 	TRACE((_T("ACTION_IS_FILESYSTEM()\n")));
5663 	PUT_PCK_RES1 (packet, DOS_TRUE);
5664 }
5665 
5666 static void
action_flush(Unit * unit,dpacket packet)5667 	action_flush (Unit *unit, dpacket packet)
5668 {
5669 	TRACE((_T("ACTION_FLUSH()\n")));
5670 	PUT_PCK_RES1 (packet, DOS_TRUE);
5671 	flush_cache (unit, 0);
5672 }
5673 
5674 static void
action_more_cache(Unit * unit,dpacket packet)5675 	action_more_cache (Unit *unit, dpacket packet)
5676 {
5677 	TRACE((_T("ACTION_MORE_CACHE()\n")));
5678 	PUT_PCK_RES1 (packet, 50); /* bug but AmigaOS expects it */
5679 	if (GET_PCK_ARG1 (packet) != 0)
5680 		flush_cache (unit, 0);
5681 }
5682 
5683 static void
action_inhibit(Unit * unit,dpacket packet)5684 	action_inhibit (Unit *unit, dpacket packet)
5685 {
5686 	PUT_PCK_RES1 (packet, DOS_TRUE);
5687 	flush_cache (unit, 0);
5688 	unit->inhibited = GET_PCK_ARG1 (packet) != 0;
5689 	TRACE((_T("ACTION_INHIBIT(%d:%d)\n"), unit->unit, unit->inhibited));
5690 }
5691 
5692 static void
action_write_protect(Unit * unit,dpacket packet)5693 	action_write_protect (Unit *unit, dpacket packet)
5694 {
5695 	TRACE((_T("ACTION_WRITE_PROTECT()\n")));
5696 	PUT_PCK_RES1 (packet, DOS_TRUE);
5697 	if (GET_PCK_ARG1 (packet)) {
5698 		if (!unit->ui.locked) {
5699 			unit->ui.locked = true;
5700 			unit->lockkey = GET_PCK_ARG2 (packet);
5701 		}
5702 	} else {
5703 		if (unit->ui.locked) {
5704 			if (unit->lockkey == (uae_u32)GET_PCK_ARG2 (packet) || unit->lockkey == 0) {
5705 				unit->ui.locked = false;
5706 			} else {
5707 				PUT_PCK_RES1 (packet, DOS_FALSE);
5708 				PUT_PCK_RES2 (packet, 0);
5709 			}
5710 		}
5711 	}
5712 }
5713 
action_change_file_position64(Unit * unit,dpacket packet)5714 static void action_change_file_position64 (Unit *unit, dpacket packet)
5715 {
5716 	Key *k = lookup_key (unit, GET_PCK64_ARG1 (packet));
5717 	uae_s64 pos = GET_PCK64_ARG2 (packet);
5718 	long mode = GET_PCK64_ARG3 (packet);
5719 	long whence = SEEK_CUR;
5720 	uae_s64 res, cur;
5721 
5722 	PUT_PCK64_RES0 (packet, DP64_INIT);
5723 
5724 	if (k == 0) {
5725 		PUT_PCK64_RES1 (packet, DOS_FALSE);
5726 		PUT_PCK64_RES2 (packet, ERROR_INVALID_LOCK);
5727 		return;
5728 	}
5729 
5730 	if (mode > 0)
5731 		whence = SEEK_END;
5732 	if (mode < 0)
5733 		whence = SEEK_SET;
5734 
5735 	TRACE((_T("ACTION_CHANGE_FILE_POSITION64(%s,%lld,%d)\n"), k->aino->nname, pos, mode));
5736 	gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
5737 
5738 	cur = k->file_pos;
5739 	{
5740 		uae_s64 temppos = 0;
5741 		uae_s64 filesize = fs_fsize64 (k->fd);
5742 
5743 		if (whence == SEEK_CUR)
5744 			temppos = cur + pos;
5745 		if (whence == SEEK_SET)
5746 			temppos = pos;
5747 		if (whence == SEEK_END)
5748 			temppos = filesize + pos;
5749 		if (filesize < temppos) {
5750 			res = -1;
5751 			PUT_PCK64_RES1 (packet, res);
5752 			PUT_PCK64_RES2 (packet, ERROR_SEEK_ERROR);
5753 			return;
5754 		}
5755 	}
5756 	res = fs_lseek64 (k->fd, pos, whence);
5757 
5758 	if (-1 == res) {
5759 		PUT_PCK64_RES1 (packet, DOS_FALSE);
5760 		PUT_PCK64_RES2 (packet, ERROR_SEEK_ERROR);
5761 	} else {
5762 		PUT_PCK64_RES1 (packet, true);
5763 		PUT_PCK64_RES2 (packet, 0);
5764 		k->file_pos = fs_lseek64 (k->fd, 0, SEEK_CUR);
5765 	}
5766 	TRACE((_T("= oldpos %lld newpos %lld\n"), cur, k->file_pos));
5767 
5768 }
5769 
action_get_file_position64(Unit * unit,dpacket packet)5770 static void action_get_file_position64 (Unit *unit, dpacket packet)
5771 {
5772 	Key *k = lookup_key (unit, GET_PCK64_ARG1 (packet));
5773 
5774 	PUT_PCK64_RES0 (packet, DP64_INIT);
5775 
5776 	if (k == 0) {
5777 		PUT_PCK64_RES1 (packet, DOS_FALSE);
5778 		PUT_PCK64_RES2 (packet, ERROR_INVALID_LOCK);
5779 		return;
5780 	}
5781 	TRACE((_T("ACTION_GET_FILE_POSITION64(%s)=%lld\n"), k->aino->nname, k->file_pos));
5782 	PUT_PCK64_RES1 (packet, k->file_pos);
5783 	PUT_PCK64_RES2 (packet, 0);
5784 }
5785 
action_change_file_size64(Unit * unit,dpacket packet)5786 static void action_change_file_size64 (Unit *unit, dpacket packet)
5787 {
5788 	Key *k, *k1;
5789 	uae_s64 offset = GET_PCK64_ARG2 (packet);
5790 	long mode = (uae_s32)GET_PCK64_ARG3 (packet);
5791 	int whence = SEEK_CUR;
5792 
5793 	PUT_PCK64_RES0 (packet, DP64_INIT);
5794 
5795 	if (mode > 0)
5796 		whence = SEEK_END;
5797 	if (mode < 0)
5798 		whence = SEEK_SET;
5799 
5800 	TRACE((_T("ACTION_CHANGE_FILE_SIZE64(0x%lx, %lld, 0x%x)\n"), GET_PCK64_ARG1 (packet), offset, mode));
5801 
5802 	k = lookup_key (unit, GET_PCK64_ARG1 (packet));
5803 	if (k == 0) {
5804 		PUT_PCK64_RES1 (packet, DOS_FALSE);
5805 		PUT_PCK64_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
5806 		return;
5807 	}
5808 
5809 	gui_flicker_led (UNIT_LED(unit), unit->unit, 1);
5810 	k->notifyactive = 1;
5811 	/* If any open files have file pointers beyond this size, truncate only
5812 	* so far that these pointers do not become invalid.  */
5813 	for (k1 = unit->keys; k1; k1 = k1->next) {
5814 		if (k != k1 && k->aino == k1->aino) {
5815 			if (k1->file_pos > offset)
5816 				offset = k1->file_pos;
5817 		}
5818 	}
5819 
5820 	/* Write one then truncate: that should give the right size in all cases.  */
5821 	fs_lseek (k->fd, offset, whence);
5822 	offset = fs_lseek64 (k->fd, offset, whence);
5823 	fs_write (k->fd, /* whatever */(uae_u8*)&k1, 1);
5824 	if (k->file_pos > offset)
5825 		k->file_pos = offset;
5826 	fs_lseek64 (k->fd, k->file_pos, SEEK_SET);
5827 
5828 	if (my_truncate (k->aino->nname, offset) == -1) {
5829 		PUT_PCK64_RES1 (packet, DOS_FALSE);
5830 		PUT_PCK64_RES2 (packet, dos_errno ());
5831 		return;
5832 	}
5833 
5834 	PUT_PCK64_RES1 (packet, DOS_TRUE);
5835 	PUT_PCK64_RES2 (packet, 0);
5836 }
5837 
5838 
action_get_file_size64(Unit * unit,dpacket packet)5839 static void action_get_file_size64 (Unit *unit, dpacket packet)
5840 {
5841 	Key *k = lookup_key (unit, GET_PCK64_ARG1 (packet));
5842 	uae_s64 filesize;
5843 
5844 	PUT_PCK64_RES0 (packet, DP64_INIT);
5845 
5846 	if (k == 0) {
5847 		PUT_PCK64_RES1 (packet, DOS_FALSE);
5848 		PUT_PCK64_RES2 (packet, ERROR_INVALID_LOCK);
5849 		return;
5850 	}
5851 	filesize = fs_fsize64 (k->fd);
5852 	TRACE((_T("ACTION_GET_FILE_SIZE64(%s)=%lld\n"), k->aino->nname, filesize));
5853 	if (filesize >= 0) {
5854 		PUT_PCK64_RES1 (packet, filesize);
5855 		PUT_PCK64_RES2 (packet, 0);
5856 		return;
5857 	}
5858 	PUT_PCK64_RES1 (packet, DOS_FALSE);
5859 	PUT_PCK64_RES2 (packet, ERROR_SEEK_ERROR);
5860 }
5861 
5862 /* We don't want multiple interrupts to be active at the same time. I don't
5863 * know whether AmigaOS takes care of that, but this does. */
5864 static uae_sem_t singlethread_int_sem;
5865 
exter_int_helper(TrapContext * context)5866 static uae_u32 REGPARAM2 exter_int_helper (TrapContext *context)
5867 {
5868 	UnitInfo *uip = mountinfo.ui;
5869 	uaecptr port;
5870 	int n = m68k_dreg (regs, 0);
5871 	static int unit_no;
5872 
5873 	switch (n) {
5874 	case 0:
5875 		/* Determine whether a given EXTER interrupt is for us. */
5876 		if (uae_int_requested & 1) {
5877 			if (uae_sem_trywait (&singlethread_int_sem) != 0)
5878 				/* Pretend it isn't for us. We might get it again later. */
5879 				return 0;
5880 			/* Clear the interrupt flag _before_ we do any processing.
5881 			* That way, we can get too many interrupts, but never not
5882 			* enough. */
5883 			filesys_in_interrupt++;
5884 			uae_int_requested &= ~1;
5885 			unit_no = 0;
5886 			return 1;
5887 		}
5888 		return 0;
5889 	case 1:
5890 		/* Release a message_lock. This is called as soon as the message is
5891 		* received by the assembly code. We use the opportunity to check
5892 		* whether we have some locks that we can give back to the assembler
5893 		* code.
5894 		* Note that this is called from the main loop, unlike the other cases
5895 		* in this switch statement which are called from the interrupt handler.
5896 		*/
5897 #ifdef UAE_FILESYS_THREADS
5898 		{
5899 			Unit *unit = find_unit (m68k_areg (regs, 5));
5900 			uaecptr msg = m68k_areg (regs, 4);
5901 			unit->cmds_complete = unit->cmds_acked;
5902 			while (comm_pipe_has_data (unit->ui.back_pipe)) {
5903 				uaecptr locks, lockend;
5904 				int cnt = 0;
5905 				locks = read_comm_pipe_int_blocking (unit->ui.back_pipe);
5906 				lockend = locks;
5907 				while (get_long (lockend) != 0) {
5908 					if (get_long (lockend) == lockend) {
5909 						write_log (_T("filesystem lock queue corrupted!\n"));
5910 						break;
5911 					}
5912 					lockend = get_long (lockend);
5913 					cnt++;
5914 				}
5915 				TRACE3((_T("message_lock: %d %x %x %x\n"), cnt, locks, lockend, m68k_areg (regs, 3)));
5916 				put_long (lockend, get_long (m68k_areg (regs, 3)));
5917 				put_long (m68k_areg (regs, 3), locks);
5918 			}
5919 		}
5920 #else
5921 		write_log (_T("exter_int_helper should not be called with arg 1!\n"));
5922 #endif
5923 		break;
5924 	case 2:
5925 		/* Find work that needs to be done:
5926 		* return d0 = 0: none
5927 		*        d0 = 1: PutMsg(), port in a0, message in a1
5928 		*        d0 = 2: Signal(), task in a1, signal set in d1
5929 		*        d0 = 3: ReplyMsg(), message in a1
5930 		*        d0 = 4: Cause(), interrupt in a1
5931 		*        d0 = 5: Send FileNofication message, port in a0, notifystruct in a1
5932 		*/
5933 
5934 #ifdef SUPPORT_THREADS
5935 		/* First, check signals/messages */
5936 		while (comm_pipe_has_data (&native2amiga_pending)) {
5937 			int cmd = read_comm_pipe_int_blocking (&native2amiga_pending);
5938 			switch (cmd) {
5939 			case 0: /* Signal() */
5940 				m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
5941 				m68k_dreg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
5942 				return 2;
5943 
5944 			case 1: /* PutMsg() */
5945 				m68k_areg (regs, 0) = read_comm_pipe_u32_blocking (&native2amiga_pending);
5946 				m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
5947 				return 1;
5948 
5949 			case 2: /* ReplyMsg() */
5950 				m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
5951 				return 3;
5952 
5953 			case 3: /* Cause() */
5954 				m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
5955 				return 4;
5956 
5957 			case 4: /* NotifyHack() */
5958 				m68k_areg (regs, 0) = read_comm_pipe_u32_blocking (&native2amiga_pending);
5959 				m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
5960 				return 5;
5961 
5962 			default:
5963 				write_log (_T("exter_int_helper: unknown native action %X\n"), cmd);
5964 				break;
5965 			}
5966 		}
5967 #endif
5968 
5969 		/* Find some unit that needs a message sent, and return its port,
5970 		* or zero if all are done.
5971 		* Take care not to dereference self for units that didn't have their
5972 		* startup packet sent. */
5973 		for (;;) {
5974 			if (unit_no >= MAX_FILESYSTEM_UNITS)
5975 				return 0;
5976 
5977 			if (uip[unit_no].open && uip[unit_no].self != 0
5978 				&& uip[unit_no].self->cmds_acked == uip[unit_no].self->cmds_complete
5979 				&& uip[unit_no].self->cmds_acked != uip[unit_no].self->cmds_sent)
5980 				break;
5981 			unit_no++;
5982 		}
5983 		uip[unit_no].self->cmds_acked = uip[unit_no].self->cmds_sent;
5984 		port = uip[unit_no].self->port;
5985 		if (port) {
5986 			m68k_areg (regs, 0) = port;
5987 			m68k_areg (regs, 1) = find_unit (port)->dummy_message;
5988 			unit_no++;
5989 			return 1;
5990 		}
5991 		break;
5992 	case 3:
5993 		uae_sem_wait (&singlethread_int_sem);
5994 		break;
5995 	case 4:
5996 		/* Exit the interrupt, and release the single-threading lock. */
5997 		filesys_in_interrupt--;
5998 		uae_sem_post (&singlethread_int_sem);
5999 		break;
6000 
6001 	default:
6002 		write_log (_T("Shouldn't happen in exter_int_helper.\n"));
6003 		break;
6004 	}
6005 	return 0;
6006 }
6007 
handle_packet(Unit * unit,dpacket pck,uae_u32 msg)6008 static int handle_packet (Unit *unit, dpacket pck, uae_u32 msg)
6009 {
6010 	uae_s32 type = GET_PCK_TYPE (pck);
6011 	PUT_PCK_RES2 (pck, 0);
6012 
6013 	TRACE((_T("unit=%x packet=%d\n"), unit, type));
6014 	if (unit->inhibited && filesys_isvolume (unit)
6015 		&& type != ACTION_INHIBIT && type != ACTION_MORE_CACHE
6016 		&& type != ACTION_DISK_INFO) {
6017 			PUT_PCK_RES1 (pck, DOS_FALSE);
6018 			PUT_PCK_RES2 (pck, ERROR_NOT_A_DOS_DISK);
6019 			return 1;
6020 	}
6021 	if (type != ACTION_INHIBIT && type != ACTION_CURRENT_VOLUME
6022 		&& type != ACTION_IS_FILESYSTEM && type != ACTION_MORE_CACHE
6023 		&& type != ACTION_WRITE_PROTECT && type != ACTION_DISK_INFO
6024 		&& !filesys_isvolume (unit)) {
6025 			PUT_PCK_RES1 (pck, DOS_FALSE);
6026 			PUT_PCK_RES2 (pck, unit->ui.unknown_media ? ERROR_NOT_A_DOS_DISK : ERROR_NO_DISK);
6027 			return 1;
6028 	}
6029 
6030 	switch (type) {
6031 	case ACTION_LOCATE_OBJECT: action_lock (unit, pck); break;
6032 	case ACTION_FREE_LOCK: action_free_lock (unit, pck); break;
6033 	case ACTION_COPY_DIR: action_dup_lock (unit, pck); break;
6034 	case ACTION_DISK_INFO: action_disk_info (unit, pck); break;
6035 	case ACTION_INFO: action_info (unit, pck); break;
6036 	case ACTION_EXAMINE_OBJECT: action_examine_object (unit, pck); break;
6037 	case ACTION_EXAMINE_NEXT: action_examine_next (unit, pck); break;
6038 	case ACTION_FIND_INPUT: action_find_input (unit, pck); break;
6039 	case ACTION_FIND_WRITE: action_find_write (unit, pck); break;
6040 	case ACTION_FIND_OUTPUT: action_find_output (unit, pck); break;
6041 	case ACTION_END: action_end (unit, pck); break;
6042 	case ACTION_READ: action_read (unit, pck); break;
6043 	case ACTION_WRITE: action_write (unit, pck); break;
6044 	case ACTION_SEEK: action_seek (unit, pck); break;
6045 	case ACTION_SET_PROTECT: action_set_protect (unit, pck); break;
6046 	case ACTION_SET_COMMENT: action_set_comment (unit, pck); break;
6047 	case ACTION_SAME_LOCK: action_same_lock (unit, pck); break;
6048 	case ACTION_PARENT: action_parent (unit, pck); break;
6049 	case ACTION_CREATE_DIR: action_create_dir (unit, pck); break;
6050 	case ACTION_DELETE_OBJECT: action_delete_object (unit, pck); break;
6051 	case ACTION_RENAME_OBJECT: action_rename_object (unit, pck); break;
6052 	case ACTION_SET_DATE: action_set_date (unit, pck); break;
6053 	case ACTION_CURRENT_VOLUME: action_current_volume (unit, pck); break;
6054 	case ACTION_RENAME_DISK: action_rename_disk (unit, pck); break;
6055 	case ACTION_IS_FILESYSTEM: action_is_filesystem (unit, pck); break;
6056 	case ACTION_FLUSH: action_flush (unit, pck); break;
6057 	case ACTION_MORE_CACHE: action_more_cache (unit, pck); break;
6058 	case ACTION_INHIBIT: action_inhibit (unit, pck); break;
6059 	case ACTION_WRITE_PROTECT: action_write_protect (unit, pck); break;
6060 
6061 		/* 2.0+ packet types */
6062 	case ACTION_SET_FILE_SIZE: action_set_file_size (unit, pck); break;
6063 	case ACTION_EXAMINE_FH: action_examine_fh (unit, pck); break;
6064 	case ACTION_FH_FROM_LOCK: action_fh_from_lock (unit, pck); break;
6065 	case ACTION_COPY_DIR_FH: action_lock_from_fh (unit, pck); break;
6066 	case ACTION_CHANGE_MODE: action_change_mode (unit, pck); break;
6067 	case ACTION_PARENT_FH: action_parent_fh (unit, pck); break;
6068 	case ACTION_ADD_NOTIFY: action_add_notify (unit, pck); break;
6069 	case ACTION_REMOVE_NOTIFY: action_remove_notify (unit, pck); break;
6070 	case ACTION_EXAMINE_ALL: return action_examine_all (unit, pck);
6071 	case ACTION_EXAMINE_ALL_END: return action_examine_all_end (unit, pck);
6072 	case ACTION_LOCK_RECORD: return action_lock_record (unit, pck, msg); break;
6073 	case ACTION_FREE_RECORD: action_free_record (unit, pck); break;
6074 	case ACTION_READ_LINK: action_read_link (unit, pck); break;
6075 	case ACTION_MAKE_LINK: action_make_link (unit, pck); break;
6076 
6077 		/* OS4+ packet types */
6078 	case ACTION_CHANGE_FILE_POSITION64: action_change_file_position64 (unit, pck); break;
6079 	case ACTION_GET_FILE_POSITION64: action_get_file_position64 (unit, pck); break;
6080 	case ACTION_CHANGE_FILE_SIZE64: action_change_file_size64 (unit, pck); break;
6081 	case ACTION_GET_FILE_SIZE64: action_get_file_size64 (unit, pck); break;
6082 
6083 		/* unsupported packets */
6084 	case ACTION_FORMAT:
6085 		write_log (_T("FILESYS: UNSUPPORTED PACKET %x\n"), type);
6086 		return 0;
6087 	default:
6088 		write_log (_T("FILESYS: UNKNOWN PACKET %x\n"), type);
6089 		return 0;
6090 	}
6091 	return 1;
6092 }
6093 
6094 #ifdef UAE_FILESYS_THREADS
6095 
filesys_iteration(UnitInfo * ui)6096 static int filesys_iteration(UnitInfo *ui)
6097 {
6098 	dpacket pck;
6099 	uaecptr msg;
6100 	uae_u32 morelocks;
6101 
6102 	pck = read_comm_pipe_u32_blocking (ui->unit_pipe);
6103 	msg = read_comm_pipe_u32_blocking (ui->unit_pipe);
6104 	morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe);
6105 
6106 	if (ui->reset_state == FS_GO_DOWN) {
6107 		if (pck != 0)
6108 		   return 1;
6109 		/* Death message received. */
6110 		uae_sem_post (&ui->reset_sync_sem);
6111 		/* Die.  */
6112 		return 0;
6113 	}
6114 
6115 	put_long (get_long (morelocks), get_long (ui->self->locklist));
6116 	put_long (ui->self->locklist, morelocks);
6117 	int ret = handle_packet (ui->self, pck, msg);
6118 	if (!ret) {
6119 		PUT_PCK_RES1 (pck, DOS_FALSE);
6120 		PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
6121 	}
6122 	if (ret >= 0) {
6123 		/* Mark the packet as processed for the list scan in the assembly code. */
6124 		put_long (msg + 4, 0xffffffff);
6125 	}
6126 	/* Acquire the message lock, so that we know we can safely send the message. */
6127 	ui->self->cmds_sent++;
6128 	/* The message is sent by our interrupt handler, so make sure an interrupt happens. */
6129 	do_uae_int_requested ();
6130 	/* Send back the locks. */
6131 	if (get_long (ui->self->locklist) != 0)
6132 		write_comm_pipe_int (ui->back_pipe, (int)(get_long (ui->self->locklist)), 0);
6133 	put_long (ui->self->locklist, 0);
6134 	return 1;
6135 }
6136 
6137 
filesys_thread(void * unit_v)6138 static void *filesys_thread (void *unit_v)
6139 {
6140 	UnitInfo *ui = (UnitInfo *)unit_v;
6141 
6142 	uae_set_thread_priority (NULL, 1);
6143 	for (;;) {
6144 		if (!filesys_iteration (ui)) {
6145 			return 0;
6146 		}
6147 	}
6148 	return 0;
6149 }
6150 #endif
6151 
6152 /* Talk about spaghetti code... */
filesys_handler(TrapContext * context)6153 static uae_u32 REGPARAM2 filesys_handler (TrapContext *context)
6154 {
6155 	Unit *unit = find_unit (m68k_areg (regs, 5));
6156 	uaecptr packet_addr = m68k_dreg (regs, 3);
6157 	uaecptr message_addr = m68k_areg (regs, 4);
6158 	if (! valid_address (packet_addr, 36) || ! valid_address (message_addr, 14)) {
6159 		write_log (_T("FILESYS: Bad address %x/%x passed for packet.\n"), packet_addr, message_addr);
6160 		goto error2;
6161 	}
6162 
6163 	put_long (message_addr + 4, 0xffffffff);
6164 	if (!unit || !unit->volume) {
6165 		write_log (_T("FILESYS: was not initialized.\n"));
6166 		goto error;
6167 	}
6168 #ifdef UAE_FILESYS_THREADS
6169 	{
6170 		uae_u32 morelocks;
6171 		if (!unit->ui.unit_pipe)
6172 			goto error;
6173 		/* Get two more locks and hand them over to the other thread. */
6174 		morelocks = get_long (m68k_areg (regs, 3));
6175 		put_long (m68k_areg (regs, 3), get_long (get_long (morelocks)));
6176 		put_long (get_long (morelocks), 0);
6177 
6178 		/* The packet wasn't processed yet. */
6179 		put_long (message_addr + 4, 0);
6180 		write_comm_pipe_u32 (unit->ui.unit_pipe, packet_addr, 0);
6181 		write_comm_pipe_u32 (unit->ui.unit_pipe, message_addr, 0);
6182 		write_comm_pipe_int (unit->ui.unit_pipe, (int)morelocks, 1);
6183 		/* Don't reply yet. */
6184 		return 1;
6185 	}
6186 #endif
6187 
6188 	if (! handle_packet (unit, packet_addr, 0)) {
6189 error:
6190 		PUT_PCK_RES1 (packet_addr, DOS_FALSE);
6191 		PUT_PCK_RES2 (packet_addr, ERROR_ACTION_NOT_KNOWN);
6192 	}
6193 	TRACE((_T("reply: %8lx, %ld\n"), GET_PCK_RES1 (packet_addr), GET_PCK_RES2 (packet_addr)));
6194 
6195 error2:
6196 
6197 	return 0;
6198 }
6199 
init_filesys_diagentry(void)6200 static void init_filesys_diagentry (void)
6201 {
6202 	do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname);
6203 	do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev);
6204 	do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname);
6205 	do_put_mem_word ((uae_u16 *)(filesysory + 0x210e), nr_units ());
6206 		do_put_mem_word ((uae_u16 *)(filesysory + 0x210c), 0);
6207 	native2amiga_startup ();
6208 }
6209 
filesys_start_threads(void)6210 void filesys_start_threads (void)
6211 {
6212 	int i;
6213 
6214 	filesys_in_interrupt = 0;
6215 	for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
6216 		UnitInfo *ui = &mountinfo.ui[i];
6217 		if (!ui->open)
6218 			continue;
6219 		filesys_start_thread (ui, i);
6220 	}
6221 }
6222 
filesys_cleanup(void)6223 void filesys_cleanup (void)
6224 {
6225 	filesys_free_handles ();
6226 	free_mountinfo ();
6227 }
6228 
filesys_free_handles(void)6229 void filesys_free_handles (void)
6230 {
6231 	Unit *u, *u1;
6232 	for (u = units; u; u = u1) {
6233 		Key *k1, *knext;
6234 		u1 = u->next;
6235 		for (k1 = u->keys; k1; k1 = knext) {
6236 			knext = k1->next;
6237 			if (k1->fd)
6238 				fs_closefile (k1->fd);
6239 			xfree (k1);
6240 		}
6241 		u->keys = NULL;
6242 		struct lockrecord *lrnext;
6243 		struct lockrecord *lr;
6244 		for (lr = u->waitingrecords; lr; lr = lrnext) {
6245 			lrnext = lr->next;
6246 			xfree (lr);
6247 		}
6248 		u->waitingrecords = NULL;
6249 		free_all_ainos (u, &u->rootnode);
6250 		u->rootnode.next = u->rootnode.prev = &u->rootnode;
6251 		u->aino_cache_size = 0;
6252 		xfree (u->newrootdir);
6253 		xfree (u->newvolume);
6254 		u->newrootdir = NULL;
6255 		u->newvolume = NULL;
6256 	}
6257 }
6258 
filesys_reset2(void)6259 static void filesys_reset2 (void)
6260 {
6261 	Unit *u, *u1;
6262 
6263 
6264 	filesys_free_handles ();
6265 	for (u = units; u; u = u1) {
6266 		u1 = u->next;
6267 		xfree (u);
6268 	}
6269 	units = 0;
6270 	key_uniq = 0;
6271 	a_uniq = 0;
6272 	free_mountinfo ();
6273 }
6274 
filesys_reset(void)6275 void filesys_reset (void)
6276 {
6277 	if (isrestore ())
6278 		return;
6279 	filesys_reset2 ();
6280 	initialize_mountinfo ();
6281 }
6282 
filesys_prepare_reset2(void)6283 static void filesys_prepare_reset2 (void)
6284 {
6285 #ifdef UAE_FILESYS_THREADS
6286 	UnitInfo *uip;
6287 	//    Unit *u;
6288 	int i;
6289 
6290 	uip = mountinfo.ui;
6291 	for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
6292 		if (uip[i].open && uip[i].unit_pipe != 0) {
6293 			uae_sem_init (&uip[i].reset_sync_sem, 0, 0);
6294 			uip[i].reset_state = FS_GO_DOWN;
6295 			/* send death message */
6296 			write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
6297 			write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
6298 			write_comm_pipe_int (uip[i].unit_pipe, 0, 1);
6299 			uae_sem_wait (&uip[i].reset_sync_sem);
6300 			uae_end_thread (&uip[i].tid);
6301 		}
6302 	}
6303 #endif
6304 	filesys_free_handles();
6305 #if 0
6306 	u = units;
6307 	while (u != 0) {
6308 		free_all_ainos (u, &u->rootnode);
6309 		u->rootnode.next = u->rootnode.prev = &u->rootnode;
6310 		u->aino_cache_size = 0;
6311 		u = u->next;
6312 	}
6313 #endif
6314 }
6315 
filesys_prepare_reset(void)6316 void filesys_prepare_reset (void)
6317 {
6318 	if (isrestore ())
6319 		return;
6320 	filesys_prepare_reset2 ();
6321 }
6322 
filesys_diagentry(TrapContext * context)6323 static uae_u32 REGPARAM2 filesys_diagentry (TrapContext *context)
6324 {
6325 	uaecptr resaddr = m68k_areg (regs, 2) + 0x10;
6326 	uaecptr start = resaddr;
6327 	uaecptr residents, tmp;
6328 
6329 	write_log (_T("filesystem: diagentry called: %x\n"), resaddr);
6330 
6331 	filesys_configdev = m68k_areg (regs, 3);
6332 	init_filesys_diagentry ();
6333 
6334 	if (ROM_hardfile_resid != 0) {
6335 		/* Build a struct Resident. This will set up and initialize
6336 		* the uae.device */
6337 		put_word (resaddr + 0x0, 0x4AFC);
6338 		put_long (resaddr + 0x2, resaddr);
6339 		put_long (resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
6340 		put_word (resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
6341 		put_word (resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
6342 		put_long (resaddr + 0xE, ROM_hardfile_resname);
6343 		put_long (resaddr + 0x12, ROM_hardfile_resid);
6344 		put_long (resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */
6345 	}
6346 	resaddr += 0x1A;
6347 	tmp = resaddr;
6348 	/* The good thing about this function is that it always gets called
6349 	* when we boot. So we could put all sorts of stuff that wants to be done
6350 	* here.
6351 	* We can simply add more Resident structures here. Although the Amiga OS
6352 	* only knows about the one at address DiagArea + 0x10, we scan for other
6353 	* Resident structures and call InitResident() for them at the end of the
6354 	* diag entry. */
6355 
6356 	resaddr = uaeres_startup (resaddr);
6357 #ifdef BSDSOCKET
6358 	resaddr = bsdlib_startup (resaddr);
6359 #endif
6360 #ifdef SCSIEMU
6361 	resaddr = scsidev_startup (resaddr);
6362 #endif
6363 #ifdef SANA2
6364 	resaddr = netdev_startup (resaddr);
6365 #endif
6366 #ifdef UAESERIAL
6367 	resaddr = uaeserialdev_startup (resaddr);
6368 #endif
6369 	/* scan for Residents and return pointer to array of them */
6370 	residents = resaddr;
6371 	while (tmp < residents && tmp > start) {
6372 		if (get_word (tmp) == 0x4AFC &&
6373 			get_long (tmp + 0x2) == tmp) {
6374 				put_word (resaddr, 0x227C);         /* movea.l #tmp,a1 */
6375 				put_long (resaddr + 2, tmp);
6376 				put_word (resaddr + 6, 0x7200);     /* moveq.l #0,d1 */
6377 				put_long (resaddr + 8, 0x4EAEFF9A); /* jsr -$66(a6) ; InitResident */
6378 				resaddr += 12;
6379 				tmp = get_long (tmp + 0x6);
6380 		} else {
6381 			tmp++;
6382 		}
6383 	}
6384 	/* call setup_exter */
6385 	put_word (resaddr +  0, 0x2079);
6386 	put_long (resaddr +  2, rtarea_base + bootrom_header + 4 + 5 * 4); /* move.l RTAREA_BASE+setup_exter,a0 */
6387 	put_word (resaddr +  6, 0xd1fc);
6388 	put_long (resaddr +  8, rtarea_base + bootrom_header); /* add.l #RTAREA_BASE+bootrom_header,a0 */
6389 	put_word (resaddr + 12, 0x4e90); /* jsr (a0) */
6390 	put_word (resaddr + 14, 0x7001); /* moveq.l #1,d0 */
6391 	put_word (resaddr + 16, RTS);
6392 
6393 	m68k_areg (regs, 0) = residents;
6394 	return 1;
6395 }
6396 
6397 /* don't forget filesys.asm! */
6398 #define PP_MAXSIZE 4 * 96
6399 #define PP_FSSIZE 400
6400 #define PP_FSPTR 404
6401 #define PP_ADDTOFSRES 408
6402 #define PP_FSRES 412
6403 #define PP_FSRES_CREATED 416
6404 #define PP_EXPLIB 420
6405 #define PP_FSHDSTART 424
6406 
filesys_dev_bootfilesys(TrapContext * context)6407 static uae_u32 REGPARAM2 filesys_dev_bootfilesys (TrapContext *context)
6408 {
6409 	uaecptr devicenode = m68k_areg (regs, 3);
6410 	uaecptr parmpacket = m68k_areg (regs, 1);
6411 	uaecptr fsres = get_long (parmpacket + PP_FSRES);
6412 	uaecptr fsnode;
6413 	uae_u32 dostype, dostype2;
6414 	int no = m68k_dreg (regs, 6) & 0x7fffffff;
6415 	int unit_no = no & 65535;
6416 	UnitInfo *uip = &mountinfo.ui[unit_no];
6417 	int iscd = (m68k_dreg (regs, 6) & 0x80000000) != 0 || uip->unit_type == UNIT_CDFS;
6418 	int type;
6419 
6420 	if (iscd) {
6421 		if (!get_long (devicenode + 16))
6422 			put_long (devicenode + 16, cdfs_handlername);
6423 		return 0;
6424 	} else {
6425 		type = is_hardfile (unit_no);
6426 	}
6427 
6428 	if (type == FILESYS_VIRTUAL) {
6429 		if (!get_long (devicenode + 16))
6430 			put_long (devicenode + 16, fshandlername);
6431 		return 0;
6432 	}
6433 
6434 	if (get_long (parmpacket + PP_FSPTR) && !get_long (parmpacket + PP_ADDTOFSRES)) {
6435 		uaecptr fsptr = get_long (parmpacket + PP_FSPTR);
6436 		uip->filesysseg = fsptr;
6437 		// filesystem but was not added to fs.resource
6438 		uae_u32 pf = get_long (parmpacket + PP_FSHDSTART + 8); // fse_PatchFlags
6439 		for (int i = 0; i < 32; i++) {
6440 			if (pf & (1 << i))
6441 				put_long (devicenode + 4 + i * 4, get_long (parmpacket + PP_FSHDSTART + 8 + 4 + i * 4));
6442 		}
6443 		put_long (devicenode + 4 + 7 * 4, fsptr >> 2); // seglist
6444 		return 1;
6445 	}
6446 	dostype = get_long (parmpacket + 80);
6447 	fsnode = get_long (fsres + 18);
6448 	while (get_long (fsnode)) {
6449 		dostype2 = get_long (fsnode + 14);
6450 		if (dostype2 == dostype) {
6451 			int i;
6452 			uae_u32 pf = get_long (fsnode + 22); // fse_PatchFlags
6453 			for (i = 0; i < 32; i++) {
6454 				if (pf & (1 << i))
6455 					put_long (devicenode + 4 + i * 4, get_long (fsnode + 22 + 4 + i * 4));
6456 			}
6457 			return 1;
6458 		}
6459 		fsnode = get_long (fsnode);
6460 	}
6461 	if (type == FILESYS_HARDFILE) {
6462 		uae_u32 pf = get_long (parmpacket + PP_FSHDSTART + 8); // fse_PatchFlags
6463 		for (int i = 0; i < 32; i++) {
6464 			if (pf & (1 << i))
6465 				put_long (devicenode + 4 + i * 4, get_long (parmpacket + PP_FSHDSTART + 8 + 4 + i * 4));
6466 		}
6467 		put_long (devicenode + 4 + 7 * 4, 0); // seglist
6468 	}
6469 	return 0;
6470 }
6471 
filesys_init_storeinfo(TrapContext * context)6472 static uae_u32 REGPARAM2 filesys_init_storeinfo (TrapContext *context)
6473 {
6474 	int ret = -1;
6475 	switch (m68k_dreg (regs, 1))
6476 	{
6477 	case 1:
6478 		mountertask = m68k_areg (regs, 1);
6479 #ifdef PICASSO96
6480 		picasso96_alloc (context);
6481 #endif
6482 		break;
6483 	case 2:
6484 		ret = automountunit;
6485 		automountunit = -1;
6486 		break;
6487 	case 3:
6488 		return 0;
6489 	}
6490 	return ret;
6491 }
6492 
6493 /* REMOVEME:
6494  * orphaned, nowhere used
6495  */
6496 #if 0
6497 static uae_u8 *cdfs_handler;
6498 static int cdfs_handler_len;
6499 #endif
6500 
6501 /* Remember a pointer AmigaOS gave us so we can later use it to identify
6502 * which unit a given startup message belongs to.  */
filesys_dev_remember(TrapContext * context)6503 static uae_u32 REGPARAM2 filesys_dev_remember (TrapContext *context)
6504 {
6505 	int no = m68k_dreg (regs, 6) & 0x7fffffff;
6506 	int unit_no = no & 65535;
6507 	/// REMOVEME: unused : int sub_no = no >> 16;
6508 	UnitInfo *uip = &mountinfo.ui[unit_no];
6509 	/// REMOVEME: unused : int iscd = (m68k_dreg (regs, 6) & 0x80000000) != 0 || uip->unit_type == UNIT_CDFS;
6510 	int i;
6511 	uaecptr devicenode = m68k_areg (regs, 3);
6512 	uaecptr parmpacket = m68k_areg (regs, 1);
6513 	int fssize;
6514 	uae_u8 *fs;
6515 
6516 	uip->devicenode = devicenode;
6517 		fssize = uip->rdb_filesyssize;
6518 		fs = uip->rdb_filesysstore;
6519 
6520 	/* copy filesystem loaded from RDB */
6521 	if (get_long (parmpacket + PP_FSPTR)) {
6522 		for (i = 0; i < fssize; i++)
6523 			put_byte (get_long (parmpacket + PP_FSPTR) + i, fs[i]);
6524 	}
6525 
6526 	xfree (fs);
6527 	uip->rdb_filesysstore = 0;
6528 	uip->rdb_filesyssize = 0;
6529 	// struct regstruct.regs is unsigned
6530 	// was: if (m68k_dreg (regs, 3) >= 0)
6531 	uip->startup = get_long (devicenode + 28);
6532 
6533 	return devicenode;
6534 }
6535 
legalrdbblock(UnitInfo * uip,int block)6536 static int legalrdbblock (UnitInfo *uip, int block)
6537 {
6538 	if (block <= 0)
6539 		return 0;
6540 	if ((uae_u64)block >= (uip->hf.virtsize / uip->hf.ci.blocksize) )
6541 		return 0;
6542 	return 1;
6543 }
6544 
rl(uae_u8 * p)6545 static uae_u32 rl (uae_u8 *p)
6546 {
6547 	return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
6548 }
6549 
rdb_checksum(uae_char * id,uae_u8 * p,int block)6550 static int rdb_checksum (uae_char *id, uae_u8 *p, int block)
6551 {
6552 	uae_u32 sum = 0;
6553 	int i, blocksize;
6554 
6555 	if (memcmp (id, p, 4))
6556 		return 0;
6557 	blocksize = rl (p + 4);
6558 	if (blocksize < 1 || blocksize * 4 > FILESYS_MAX_BLOCKSIZE)
6559 		return 0;
6560 	for (i = 0; i < blocksize; i++)
6561 		sum += rl (p + i * 4);
6562 	sum = -sum;
6563 	if (sum) {
6564 		TCHAR *s = au (id);
6565 		write_log (_T("RDB: block %d ('%s') checksum error\n"), block, s);
6566 		xfree (s);
6567 		return 0;
6568 	}
6569 	return 1;
6570 }
6571 
device_isdup(uaecptr expbase,TCHAR * devname)6572 static int device_isdup (uaecptr expbase, TCHAR *devname)
6573 {
6574 	uaecptr bnode, dnode, name;
6575 	int len, i;
6576 	TCHAR dname[256];
6577 
6578 	bnode = get_long (expbase + 74); /* expansion.library bootnode list */
6579 	while (get_long (bnode)) {
6580 		dnode = get_long (bnode + 16); /* device node */
6581 		name = get_long (dnode + 40) << 2; /* device name BSTR */
6582 		len = get_byte (name);
6583 		for (i = 0; i < len; i++)
6584 			dname[i] = get_byte (name + 1 + i);
6585 		dname[len] = 0;
6586 		if (!_tcsicmp (devname, dname))
6587 			return 1;
6588 		bnode = get_long (bnode);
6589 	}
6590 	return 0;
6591 }
6592 
device_dupfix(uaecptr expbase,TCHAR * devname)6593 static TCHAR *device_dupfix (uaecptr expbase, TCHAR *devname)
6594 {
6595 	int modified;
6596 	TCHAR newname[256];
6597 
6598 	_tcscpy (newname, devname);
6599 	modified = 1;
6600 	while (modified) {
6601 		modified = 0;
6602 		if (device_isdup (expbase, newname)) {
6603 			if (_tcslen (newname) > 2 && newname[_tcslen (newname) - 2] == '_') {
6604 				newname[_tcslen (newname) - 1]++;
6605 			} else {
6606 				_tcscat (newname, _T("_0"));
6607 			}
6608 			modified = 1;
6609 		}
6610 	}
6611 	return my_strdup (newname);
6612 }
6613 
dostypes(uae_u32 dostype)6614 static const TCHAR *dostypes (uae_u32 dostype)
6615 {
6616 	static TCHAR dt[32];
6617 	int j;
6618 
6619 	j = 0;
6620 	for (int i = 0; i < 4; i++) {
6621 		uae_u8 c = dostype >> ((3 - i) * 8);
6622 		if (c >= ' ' && c <= 'z') {
6623 			dt[j++] = c;
6624 		} else {
6625 			dt[j++] = '\\';
6626 			_stprintf (&dt[j], _T("%d"), c);
6627 			j += _tcslen (&dt[j]);
6628 		}
6629 	}
6630 	dt[j] = 0;
6631 	return dt;
6632 }
6633 
dump_partinfo(struct hardfiledata * hfd,uae_u8 * pp)6634 static void dump_partinfo (struct hardfiledata *hfd, uae_u8 *pp)
6635 {
6636 	TCHAR *s;
6637 	uae_u32 dostype;
6638 	uae_u64 size;
6639 	int blocksize, surfaces, spb, spt, reserved;
6640 	int lowcyl, highcyl;
6641 	uae_u32 block, flags;
6642 	uae_u8 buf[512];
6643 
6644 	flags = rl (pp + 20);
6645 	pp[37 + pp[36]] = 0;
6646 	s = au ((char*)pp + 37);
6647 	pp += 128;
6648 	dostype = rl (pp + 64);
6649 	size = ((uae_u64)rl (pp + 4)) * 4 * rl (pp + 12) * rl (pp + 20) * (rl (pp + 40) - rl (pp + 36) + 1);
6650 	blocksize = rl (pp + 4) * 4;
6651 	surfaces = rl (pp + 12);
6652 	spb = rl (pp + 16);
6653 	spt = rl (pp + 20);
6654 	reserved = rl (pp + 24);
6655 	lowcyl = rl (pp + 36);
6656 	highcyl = rl (pp + 40);
6657 
6658 	write_log (_T("Partition '%s' Dostype=%08X (%s) Flags: %08X\n"), s, dostype, dostypes (dostype), flags);
6659 	write_log (_T("BlockSize: %d, Surfaces: %d, SectorsPerBlock %d\n"),
6660 		blocksize, surfaces, spb);
6661 	write_log (_T("SectorsPerTrack: %d, Reserved: %d, LowCyl %d, HighCyl %d, Size %dM\n"),
6662 		spt, reserved, lowcyl, highcyl, (uae_u32)(size >> 20));
6663 	write_log (_T("Buffers: %d, BufMemType: %08x, MaxTransfer: %08x, Mask: %08x, BootPri: %d\n"),
6664 		rl (pp + 44), rl (pp + 48), rl (pp + 52), rl (pp + 56), rl (pp + 60));
6665 
6666 	if (hfd->drive_empty) {
6667 		write_log (_T("Empty drive\n"));
6668 	} else {
6669 		block = lowcyl * surfaces * spt;
6670 		if (hdf_read (hfd, buf, (uae_u64)blocksize * block, sizeof buf)) {
6671 			write_log (_T("First block %d dostype: %08X (%s)\n"), block, rl (buf), dostypes (rl (buf)));
6672 		} else {
6673 			write_log (_T("First block %d read failed!\n"), block);
6674 		}
6675 		xfree (s);
6676 
6677 		if ((uae_u64)highcyl * spt * surfaces * blocksize > hfd->virtsize) {
6678 			write_log (_T("RDB: WARNING: end of partition > size of disk! (%llu > %llu)\n"),
6679 				(uae_u64)highcyl * spt * surfaces * blocksize, hfd->virtsize);
6680 		}
6681 	}
6682 }
6683 
dump_rdb(UnitInfo * uip,struct hardfiledata * hfd,uae_u8 * bufrdb,uae_u8 * buf,int readblocksize)6684 static void dump_rdb (UnitInfo *uip, struct hardfiledata *hfd, uae_u8 *bufrdb, uae_u8 *buf, int readblocksize)
6685 {
6686 	write_log (_T("RDB: HostID: %08x Flags: %08x\n"),
6687 		rl (bufrdb + 3 * 4), rl (bufrdb + 5 * 4));
6688 	write_log (_T("RDB: BL: %d BH: %d LC: %d HC: %d CB: %d HB: %d\n"),
6689 		rl (bufrdb + 128), rl (bufrdb + 132), rl (bufrdb + 136), rl (bufrdb + 140), rl (bufrdb + 144), rl (bufrdb + 152));
6690 	for (int i = 0; i < 100; i++) {
6691 		int partblock;
6692 		if (i == 0)
6693 			partblock = rl (bufrdb + 28);
6694 		else
6695 			partblock = rl (buf + 4 * 4);
6696 		if ((uae_u32)partblock == 0xffffffff)
6697 			break;
6698 		write_log (_T("RDB: PART block %d:\n"), partblock);
6699 		if (!legalrdbblock (uip, partblock)) {
6700 			write_log (_T("RDB: corrupt PART pointer %d\n"), partblock);
6701 			break;
6702 		}
6703 		memset (buf, 0, readblocksize);
6704 		hdf_read (hfd, buf, partblock * hfd->ci.blocksize, readblocksize);
6705 		if (!rdb_checksum ("PART", buf, partblock)) {
6706 			write_log (_T("RDB: checksum error PART block %d\n"), partblock);
6707 			break;
6708 		}
6709 		dump_partinfo (hfd, buf);
6710 	}
6711 	for (int i = 0; i < 100; i++) {
6712 		int fileblock;
6713 		if (i == 0)
6714 			fileblock = rl (bufrdb + 32);
6715 		else
6716 			fileblock = rl (buf + 4 * 4);
6717 		if ((uae_u32)fileblock == 0xffffffff)
6718 			break;
6719 		write_log (_T("RDB: LSEG block %d:\n"), fileblock);
6720 		if (!legalrdbblock (uip, fileblock)) {
6721 			write_log (_T("RDB: corrupt FSHD pointer %d\n"), fileblock);
6722 			break;
6723 		}
6724 		memset (buf, 0, readblocksize);
6725 		hdf_read (hfd, buf, fileblock * hfd->ci.blocksize, readblocksize);
6726 		if (!rdb_checksum ("FSHD", buf, fileblock)) {
6727 			write_log (_T("RDB: checksum error FSHD block %d\n"), fileblock);
6728 			break;
6729 		}
6730 		uae_u32 dostype = rl (buf + 32);
6731 		int version = (buf[36] << 8) | buf[37];
6732 		int revision = (buf[38] << 8) | buf[39];
6733 		write_log (_T("LSEG: %08x (%s) %d.%d\n"), dostype, dostypes (dostype), version, revision);
6734 	}
6735 }
6736 
6737 #define rdbmnt write_log (_T("Mounting uaehf.device %d (%d) (size=%llu):\n"), unit_no, partnum, hfd->virtsize);
6738 
rdb_mount(UnitInfo * uip,int unit_no,int partnum,uaecptr parmpacket)6739 static int rdb_mount (UnitInfo *uip, int unit_no, int partnum, uaecptr parmpacket)
6740 {
6741 	int lastblock = 63, blocksize, readblocksize, badblock, driveinitblock;
6742 	uae_u8 bufrdb[FILESYS_MAX_BLOCKSIZE], *buf = 0;
6743 	uae_u8 *fsmem = 0;
6744 	int rdblock, partblock, fileblock, lsegblock, i;
6745 	uae_u32 flags;
6746 	struct hardfiledata *hfd = &uip->hf;
6747 	uae_u32 dostype;
6748 	uaecptr fsres, fsnode;
6749 	int err = 0;
6750 	int oldversion, oldrevision;
6751 	int newversion, newrevision;
6752 	TCHAR *s;
6753 	bool showdebug = partnum == 0;
6754 
6755 	write_log (_T("%s:\n"), uip->rootdir);
6756 	if (hfd->drive_empty) {
6757 		rdbmnt
6758 		write_log (_T("ignored, drive is empty\n"));
6759 		return -2;
6760 	}
6761 	if (hfd->ci.blocksize == 0) {
6762 		rdbmnt
6763 		write_log (_T("failed, blocksize == 0\n"));
6764 		return -1;
6765 	}
6766 	if ((lastblock > 0) && (((uae_u64)lastblock * hfd->ci.blocksize) > hfd->virtsize) ) {
6767 		rdbmnt
6768 		write_log (_T("failed, too small (%d*%d > %llu)\n"), lastblock, hfd->ci.blocksize, hfd->virtsize);
6769 		return -2;
6770 	}
6771 	for (rdblock = 0; rdblock < lastblock; rdblock++) {
6772 		hdf_read_rdb (hfd, bufrdb, rdblock * hfd->ci.blocksize, hfd->ci.blocksize);
6773 		if (rdb_checksum ("RDSK", bufrdb, rdblock))
6774 			break;
6775 		hdf_read_rdb (hfd, bufrdb, rdblock * hfd->ci.blocksize, hfd->ci.blocksize);
6776 		if (!memcmp ("RDSK", bufrdb, 4)) {
6777 			bufrdb[0xdc] = 0;
6778 			bufrdb[0xdd] = 0;
6779 			bufrdb[0xde] = 0;
6780 			bufrdb[0xdf] = 0;
6781 			if (rdb_checksum ("RDSK", bufrdb, rdblock)) {
6782 				write_log (_T("Windows 95/98/ME trashed RDB detected, fixing..\n"));
6783 				hdf_write (hfd, bufrdb, rdblock * hfd->ci.blocksize, hfd->ci.blocksize);
6784 				break;
6785 			}
6786 		}
6787 	}
6788 	if (rdblock == lastblock) {
6789 		rdbmnt
6790 		write_log (_T("failed, no RDB detected\n"));
6791 		return -2;
6792 	}
6793 	blocksize = rl (bufrdb + 16);
6794 	readblocksize = blocksize > hfd->ci.blocksize ? blocksize : hfd->ci.blocksize;
6795 	badblock = rl (bufrdb + 24);
6796 	if (badblock != -1) {
6797 		rdbmnt
6798 		write_log (_T("RDB: badblock list is not yet supported. Contact the author.\n"));
6799 		return -2;
6800 	}
6801 	driveinitblock = rl (bufrdb + 36);
6802 	if (driveinitblock != -1) {
6803 		rdbmnt
6804 		write_log (_T("RDB: driveinit is not yet supported. Contact the author.\n"));
6805 		return -2;
6806 	}
6807 	hfd->rdbcylinders = rl (bufrdb + 64);
6808 	hfd->rdbsectors = rl (bufrdb + 68);
6809 	hfd->rdbheads = rl (bufrdb + 72);
6810 #if 0
6811 	{
6812 		int cyls, secs, heads;
6813 		getchsgeometry_hdf (hfd, hfd->virtsize, &cyls, &secs, &heads);
6814 		if (cyls * secs * heads > hfd->cylinders * hfd->sectors * hfd->heads) {
6815 			hfd->cylinders = cyls;
6816 			hfd->sectors = secs;
6817 			hfd->heads = heads;
6818 		}
6819 	}
6820 #endif
6821 	fileblock = rl (bufrdb + 32);
6822 
6823 	buf = xmalloc (uae_u8, readblocksize);
6824 
6825 	if (showdebug) {
6826 		if ((uae_u64)hfd->rdbcylinders * hfd->rdbsectors * hfd->rdbheads * blocksize > hfd->virtsize)
6827 			write_log (_T("RDB: WARNING: RDSK header disk size > disk size! (%llu > %llu)\n"),
6828 				(uae_u64)hfd->rdbcylinders * hfd->rdbsectors * hfd->rdbheads * blocksize, hfd->virtsize);
6829 		write_log (_T("RDSK dump start\n"));
6830 		write_log (_T("RDSK at %d, C=%d S=%d H=%d\n"),
6831 			rdblock, hfd->rdbcylinders, hfd->rdbsectors, hfd->rdbheads);
6832 		dump_rdb (uip, hfd, bufrdb, buf, readblocksize);
6833 		write_log (_T("RDSK dump end\n"));
6834 	}
6835 
6836 	for (i = 0; i <= partnum; i++) {
6837 		if (i == 0)
6838 			partblock = rl (bufrdb + 28);
6839 		else
6840 			partblock = rl (buf + 4 * 4);
6841 		if (!legalrdbblock (uip, partblock)) {
6842 			err = -2;
6843 			goto error;
6844 		}
6845 		memset (buf, 0, readblocksize);
6846 		hdf_read (hfd, buf, partblock * hfd->ci.blocksize, readblocksize);
6847 		if (!rdb_checksum ("PART", buf, partblock)) {
6848 			err = -2;
6849 			goto error;
6850 		}
6851 	}
6852 
6853 	rdbmnt
6854 	flags = rl (buf + 20);
6855 	if ((flags & 2) || uip->bootpri <= -129) { /* do not mount */
6856 		err = -1;
6857 		write_log (_T("RDB: Automount disabled, not mounting\n"));
6858 		goto error;
6859 	}
6860 
6861 	if (!(flags & 1) || uip->bootpri <= -128) /* not bootable */
6862 		m68k_dreg (regs, 7) = m68k_dreg (regs, 7) & ~1;
6863 
6864 	buf[37 + buf[36]] = 0; /* zero terminate BSTR */
6865 	s = au ((char*)buf + 37);
6866 	uip->rdb_devname_amiga[partnum] = ds (device_dupfix (get_long (parmpacket + PP_EXPLIB), s));
6867 	xfree (s);
6868 	put_long (parmpacket, uip->rdb_devname_amiga[partnum]); /* name */
6869 	put_long (parmpacket + 4, ROM_hardfile_resname);
6870 	put_long (parmpacket + 8, uip->devno);
6871 	put_long (parmpacket + 12, 0); /* Device flags */
6872 	for (i = 0; i < PP_MAXSIZE; i++)
6873 		put_byte (parmpacket + 16 + i, buf[128 + i]);
6874 	dostype = get_long (parmpacket + 80);
6875 
6876 	if (dostype == 0) {
6877 		write_log (_T("RDB: mount failed, dostype=0\n"));
6878 		err = -1;
6879 		goto error;
6880 	}
6881 	if (dostype == 0xffffffff) {
6882 		write_log (_T("RDB: WARNING: dostype = 0xFFFFFFFF. FFS bug can report partition in \"no disk inserted\" state!!\n"));
6883 	}
6884 
6885 	err = 2;
6886 
6887 	/* load custom filesystems if needed */
6888 	if (fileblock == -1 || !legalrdbblock (uip, fileblock))
6889 		goto error;
6890 
6891 	fsres = get_long (parmpacket + PP_FSRES);
6892 	if (!fsres) {
6893 		write_log (_T("RDB: FileSystem.resource not found, this shouldn't happen!\n"));
6894 		goto error;
6895 	}
6896 	fsnode = get_long (fsres + 18);
6897 	while (get_long (fsnode)) {
6898 		if (get_long (fsnode + 14) == dostype)
6899 			break;
6900 		fsnode = get_long (fsnode);
6901 	}
6902 	oldversion = oldrevision = -1;
6903 	if (get_long (fsnode)) {
6904 		oldversion = get_word (fsnode + 18);
6905 		oldrevision = get_word (fsnode + 20);
6906 	} else {
6907 		fsnode = 0;
6908 	}
6909 
6910 	for (;;) {
6911 		if (fileblock == -1) {
6912 			if (!fsnode)
6913 				write_log (_T("RDB: FS %08X (%s) not in FileSystem.resource or in RDB\n"), dostype, dostypes (dostype));
6914 			goto error;
6915 		}
6916 		if (!legalrdbblock (uip, fileblock)) {
6917 			write_log (_T("RDB: corrupt FSHD pointer %d\n"), fileblock);
6918 			goto error;
6919 		}
6920 		memset (buf, 0, readblocksize);
6921 		hdf_read (hfd, buf, fileblock * hfd->ci.blocksize, readblocksize);
6922 		if (!rdb_checksum ("FSHD", buf, fileblock)) {
6923 			write_log (_T("RDB: checksum error in FSHD block %d\n"), fileblock);
6924 			goto error;
6925 		}
6926 		fileblock = rl (buf + 16);
6927 		uae_u32 rdbdostype = rl (buf + 32);
6928 		if (((dostype >> 8) == (rdbdostype >> 8) && (dostype != 0x444f5300 && (dostype & 0xffffff00) == 0x444f5300)) || (dostype == rdbdostype))
6929 			break;
6930 	}
6931 	newversion = (buf[36] << 8) | buf[37];
6932 	newrevision = (buf[38] << 8) | buf[39];
6933 
6934 	write_log (_T("RDB: RDB filesystem %08X (%s) version %d.%d\n"), dostype, dostypes (dostype), newversion, newrevision);
6935 	if (fsnode) {
6936 		write_log (_T("RDB: %08X (%s) in FileSystem.resource version %d.%d\n"), dostype, dostypes (dostype), oldversion, oldrevision);
6937 	}
6938 	if (newversion * 65536 + newrevision <= oldversion * 65536 + oldrevision && oldversion >= 0) {
6939 		write_log (_T("RDB: FS in FileSystem.resource is newer or same, ignoring RDB filesystem\n"));
6940 		goto error;
6941 	}
6942 
6943 	for (i = 0; i < 140; i++)
6944 		put_byte (parmpacket + PP_FSHDSTART + i, buf[32 + i]);
6945 	put_long (parmpacket + PP_FSHDSTART, dostype);
6946 	/* we found required FSHD block */
6947 	fsmem = xmalloc (uae_u8, 262144);
6948 	lsegblock = rl (buf + 72);
6949 	i = 0;
6950 	for (;;) {
6951 		int pb = lsegblock;
6952 		if (!legalrdbblock (uip, lsegblock))
6953 			goto error;
6954 		memset (buf, 0, readblocksize);
6955 		hdf_read (hfd, buf, lsegblock * hfd->ci.blocksize, readblocksize);
6956 		if (!rdb_checksum ("LSEG", buf, lsegblock))
6957 			goto error;
6958 		lsegblock = rl (buf + 16);
6959 		if (lsegblock == pb)
6960 			goto error;
6961 		if ((i + 1) * (blocksize - 20) >= 262144)
6962 			goto error;
6963 		memcpy (fsmem + i * (blocksize - 20), buf + 20, blocksize - 20);
6964 		i++;
6965 		if (lsegblock == -1)
6966 			break;
6967 	}
6968 	write_log (_T("RDB: Filesystem loaded, %d bytes\n"), i * (blocksize - 20));
6969 	put_long (parmpacket + PP_FSSIZE, i * (blocksize - 20)); /* RDB filesystem size hack */
6970 	put_long (parmpacket + PP_ADDTOFSRES, -1);
6971 	uip->rdb_filesysstore = fsmem;
6972 	uip->rdb_filesyssize = i * (blocksize - 20);
6973 	xfree (buf);
6974 	return 2;
6975 error:
6976 	xfree (buf);
6977 	xfree (fsmem);
6978 	return err;
6979 }
6980 
addfakefilesys(uaecptr parmpacket,uae_u32 dostype,int ver,int rev,struct uaedev_config_info * ci)6981 static void addfakefilesys (uaecptr parmpacket, uae_u32 dostype, int ver, int rev, struct uaedev_config_info *ci)
6982 {
6983 	int i;
6984 	uae_u32 flags;
6985 
6986 	flags = 0x180;
6987 	for (i = 0; i < 140; i++)
6988 		put_byte (parmpacket + PP_FSHDSTART + i, 0);
6989 	if (dostype) {
6990 		put_long (parmpacket + 80, dostype);
6991 		put_long (parmpacket + PP_FSHDSTART, dostype);
6992 	}
6993 	if (ver >= 0 && rev >= 0)
6994 		put_long (parmpacket + PP_FSHDSTART + 4, (ver << 16) | rev);
6995 
6996 	put_long (parmpacket + PP_FSHDSTART + 12 + 4 * 4, ci->stacksize);
6997 	flags |= 0x10;
6998 
6999 	if (ci->priority != -129) {
7000 		put_long (parmpacket + PP_FSHDSTART + 12 + 5 * 4, ci->priority);
7001 		flags |= 0x20;
7002 	}
7003 	put_long (parmpacket + PP_FSHDSTART + 12 + 8 * 4, dostype == 0x444f5300 ? 0 : -1); // globvec
7004 	// if OFS = seglist -> NULL
7005 	if ((dostype & 0xffffff00) == 0x444f5300)
7006 		flags &= ~0x080;
7007 	put_long (parmpacket + PP_FSHDSTART + 8, flags); // patchflags
7008 }
7009 
getfakefilesysseg(UnitInfo * uip)7010 static uaecptr getfakefilesysseg (UnitInfo *uip)
7011 {
7012 	if (uip->filesysdir && _tcslen (uip->filesysdir) > 0) {
7013 		for (int i = 0; &mountinfo.ui[i] != uip; i++) {
7014 			UnitInfo *uip2 = &mountinfo.ui[i];
7015 			if (!uip2->filesysdir)
7016 				continue;
7017 			if (_tcsicmp (uip2->filesysdir, uip->filesysdir) != 0)
7018 				continue;
7019 			if (uip2->filesysseg)
7020 				return uip2->filesysseg;
7021 		}
7022 	}
7023 	return 0;
7024 }
7025 
dofakefilesys(UnitInfo * uip,uaecptr parmpacket,struct uaedev_config_info * ci)7026 static int dofakefilesys (UnitInfo *uip, uaecptr parmpacket, struct uaedev_config_info *ci)
7027 {
7028 	int i, size;
7029 	TCHAR tmp[MAX_DPATH];
7030 	uae_u8 buf[512];
7031 	struct zfile *zf;
7032 	int ver = -1, rev = -1;
7033 	uae_u32 dostype;
7034 	bool autofs = false;
7035 
7036 	// we already have custom filesystem loaded for earlier hardfile?
7037 	if (!ci->forceload) {
7038 		uaecptr seg = getfakefilesysseg (uip);
7039 		if (seg) {
7040 			// yes, re-use it.
7041 			put_long (parmpacket + PP_FSSIZE, 0);
7042 			put_long (parmpacket + PP_FSPTR, seg);
7043 			put_long (parmpacket + PP_ADDTOFSRES, 0);
7044 			write_log (_T("RDB: faked RDB filesystem '%s' reused\n"), uip->filesysdir);
7045 			return FILESYS_HARDFILE;
7046 		}
7047 	}
7048 
7049 	if (!ci->dostype) {
7050 		memset (buf, 0, 4);
7051 		hdf_read (&uip->hf, buf, 0, 512);
7052 		dostype = (buf[0] << 24) | (buf[1] << 16) |(buf[2] << 8) | buf[3];
7053 	} else {
7054 		dostype = ci->dostype;
7055 	}
7056 	if (dostype == 0) {
7057 		addfakefilesys (parmpacket, dostype, ver, rev, ci);
7058 			return FILESYS_HARDFILE;
7059 	}
7060 	if ((dostype & 0xffffff00) == 0x444f5300 && (!uip->filesysdir || !uip->filesysdir[0])) {
7061 		write_log (_T("RDB: OFS, using ROM default FS.\n"));
7062 		return FILESYS_HARDFILE;
7063 	}
7064 
7065 	tmp[0] = 0;
7066 	if (uip->filesysdir && _tcslen (uip->filesysdir) > 0) {
7067 		_tcscpy (tmp, uip->filesysdir);
7068 	} else if ((dostype & 0xffffff00) == 0x444f5300) {
7069 		_tcscpy (tmp, currprefs.romfile);
7070 		i = _tcslen (tmp);
7071 		while (i > 0 && tmp[i - 1] != '/' && tmp[i - 1] != '\\')
7072 			i--;
7073 		_tcscpy (tmp + i, _T("FastFileSystem"));
7074 		autofs = true;
7075 	}
7076 	if (tmp[0] == 0) {
7077 		write_log (_T("RDB: no filesystem for dostype 0x%08X (%s)\n"), dostype, dostypes (dostype));
7078 		addfakefilesys (parmpacket, dostype, ver, rev, ci);
7079 		if ((dostype & 0xffffff00) == 0x444f5300)
7080 			return FILESYS_HARDFILE;
7081 		write_log (_T("RDB: mounted without filesys\n"));
7082 		return FILESYS_HARDFILE;
7083 	}
7084 	write_log (_T("RDB: fakefilesys, trying to load '%s', dostype 0x%08X (%s)\n"), tmp, dostype, dostypes (dostype));
7085 	zf = zfile_fopen (tmp, _T("rb"), ZFD_NORMAL);
7086 	if (!zf) {
7087 		addfakefilesys (parmpacket, dostype, ver, rev, ci);
7088 		write_log (_T("RDB: filesys not found, mounted without filesys\n"));
7089 		return FILESYS_HARDFILE;
7090 	}
7091 
7092 	uae_u32 fsres, fsnode;
7093 	int oldversion = -1;
7094 	int oldrevision = -1;
7095 	fsres = get_long (parmpacket + PP_FSRES);
7096 	fsnode = get_long (fsres + 18);
7097 	while (get_long (fsnode)) {
7098 		uae_u32 fsdostype = get_long (fsnode + 14);
7099 		if (fsdostype == dostype) {
7100 			oldversion = get_word (fsnode + 18);
7101 			oldrevision = get_word (fsnode + 20);
7102 			write_log (_T("RDB: %08X (%s) in FileSystem.resource version %d.%d\n"), dostype, dostypes (dostype), oldversion, oldrevision);
7103 			break;
7104 		}
7105 		fsnode = get_long (fsnode);
7106 	}
7107 	// if automatically found FastFileSystem, do not replace matching FileSystem.resource FS
7108 	if (autofs && oldversion >= 0) {
7109 		zfile_fclose (zf);
7110 		addfakefilesys (parmpacket, dostype, ver, rev, ci);
7111 		write_log (_T("RDB: not replacing FileSystem.resource\n"));
7112 		return FILESYS_HARDFILE;
7113 	}
7114 
7115 	zfile_fseek (zf, 0, SEEK_END);
7116 	size = zfile_ftell (zf);
7117 	if (size > 0) {
7118 		zfile_fseek (zf, 0, SEEK_SET);
7119 		uip->rdb_filesysstore = xmalloc (uae_u8, size);
7120 		zfile_fread (uip->rdb_filesysstore, size, 1, zf);
7121 		for (i = 0; i < size - 6; i++) {
7122 			uae_u8 *p = uip->rdb_filesysstore + i;
7123 			if (p[0] == 'V' && p[1] == 'E' && p[2] == 'R' && p[3] == ':' && p[4] == ' ') {
7124 				uae_u8 *p2;
7125 				p += 5;
7126 				p2 = p;
7127 				while (*p2 && p2 - uip->rdb_filesysstore < size)
7128 					p2++;
7129 				if (p2[0] == 0) {
7130 					while (*p && (ver < 0 || rev < 0)) {
7131 						if (*p == ' ') {
7132 							p++;
7133 							ver = atol ((char*)p);
7134 							if (ver < 0)
7135 								ver = 0;
7136 							while (*p) {
7137 								if (*p == ' ')
7138 									break;
7139 								if (*p == '.') {
7140 									p++;
7141 									rev = atol ((char*)p);
7142 									if (rev < 0)
7143 										rev = 0;
7144 								} else {
7145 									p++;
7146 								}
7147 							}
7148 							break;
7149 						} else {
7150 							p++;
7151 						}
7152 					}
7153 				}
7154 				break;
7155 			}
7156 		}
7157 	}
7158 	zfile_fclose (zf);
7159 	uip->rdb_filesyssize = size;
7160 
7161 	// DOS\0 is not in fs.resource and fs.resource already existed?
7162 	if (dostype == 0x444f5300 && oldversion < 0)
7163 		oldversion = 0;
7164 	put_long (parmpacket + PP_FSSIZE, uip->rdb_filesyssize);
7165 	put_long (parmpacket + PP_ADDTOFSRES, oldversion < 0 ? -1 : 0);
7166 	addfakefilesys (parmpacket, dostype, ver, rev, ci);
7167 	write_log (_T("RDB: faked RDB filesystem %08X (%s %d.%d) loaded. ADD2FS=%d\n"), dostype, dostypes (dostype), ver, rev, oldversion < 0 ? 1 : 0);
7168 	return FILESYS_HARDFILE;
7169 }
7170 
get_new_device(int type,uaecptr parmpacket,TCHAR ** devname,uaecptr * devname_amiga,int unit_no)7171 static void get_new_device (int type, uaecptr parmpacket, TCHAR **devname, uaecptr *devname_amiga, int unit_no)
7172 {
7173 	TCHAR buffer[80];
7174 	uaecptr expbase = get_long (parmpacket + PP_EXPLIB);
7175 
7176 	if (*devname == 0 || _tcslen (*devname) == 0) {
7177 		int un = unit_no;
7178 		for (;;) {
7179 			_stprintf (buffer, type == FILESYS_CD ? _T("CD%d") : _T("DH%d"), un++);
7180 			if (type == FILESYS_CD)
7181 				*devname = my_strdup (buffer);
7182 			if (!device_isdup (expbase, buffer))
7183 				break;
7184 		}
7185 	} else {
7186 		_tcscpy (buffer, *devname);
7187 	}
7188 	*devname_amiga = ds (device_dupfix (expbase, buffer));
7189 	if (type == FILESYS_CD)
7190 		write_log (_T("FS: mounted CD unit %s\n"), buffer);
7191 	else if (type == FILESYS_VIRTUAL)
7192 		write_log (_T("FS: mounted virtual unit %s (%s)\n"), buffer, mountinfo.ui[unit_no].rootdir);
7193 	else
7194 		write_log (_T("FS: mounted HDF unit %s (%04x-%08x, %s)\n"), buffer,
7195 		(uae_u32)(mountinfo.ui[unit_no].hf.virtsize >> 32),
7196 		(uae_u32)(mountinfo.ui[unit_no].hf.virtsize),
7197 		mountinfo.ui[unit_no].rootdir);
7198 }
7199 
7200 /* Fill in per-unit fields of a parampacket */
filesys_dev_storeinfo(TrapContext * context)7201 static uae_u32 REGPARAM2 filesys_dev_storeinfo (TrapContext *context)
7202 {
7203 	UnitInfo *uip = mountinfo.ui;
7204 	int no = m68k_dreg (regs, 6) & 0x7fffffff;
7205 	int unit_no = no & 65535;
7206 	int sub_no = no >> 16;
7207 	int iscd = (m68k_dreg (regs, 6) & 0x80000000) != 0 || uip[unit_no].unit_type == UNIT_CDFS;
7208 	int type;
7209 	uaecptr parmpacket = m68k_areg (regs, 0);
7210 	struct uaedev_config_info *ci = &uip[unit_no].hf.ci;
7211 
7212 	put_long (parmpacket + PP_ADDTOFSRES, 0);
7213 	put_long (parmpacket + PP_FSSIZE, 0);
7214 	if (iscd) {
7215 /* REMOVEME:
7216  * nowhere used
7217  */
7218 #if 0
7219 		TCHAR *cdname = NULL;
7220 #endif
7221 		uaecptr cdname_amiga;
7222 		int cd_unit_no = unit_no - cd_unit_offset;
7223 
7224 		if (sub_no)
7225 			return -2;
7226 
7227 		type = FILESYS_CD;
7228 			get_new_device (type, parmpacket, &uip[unit_no].devname, &uip[unit_no].devname_amiga, cd_unit_no);
7229 			cdname_amiga = uip[unit_no].devname_amiga;
7230 			uip[unit_no].devno = unit_no;
7231 			type = FILESYS_VIRTUAL;
7232 		gui_flicker_led (LED_CD, cd_unit_no, 0);
7233 
7234 		write_log (_T("Mounting uaescsi.device %d: (%d)\n"), cd_unit_no, unit_no);
7235 		put_long (parmpacket + 0, cdname_amiga);
7236 		put_long (parmpacket + 4, cdfs_devname);
7237 		put_long (parmpacket + 8, cd_unit_no);
7238 		put_long (parmpacket + 12, 0); /* Device flags */
7239 		put_long (parmpacket + 16, 19); /* Env. size */
7240 		put_long (parmpacket + 20, 2048 >> 2); /* longwords per block */
7241 		put_long (parmpacket + 24, 0); /* unused */
7242 		put_long (parmpacket + 28, 1); /* heads */
7243 		put_long (parmpacket + 32, 1); /* sectors per block */
7244 		put_long (parmpacket + 36, 1); /* sectors per track */
7245 		put_long (parmpacket + 40, 0); /* reserved blocks */
7246 		put_long (parmpacket + 44, 0); /* unused */
7247 		put_long (parmpacket + 48, 0); /* interleave */
7248 		put_long (parmpacket + 52, 0); /* lowCyl */
7249 		put_long (parmpacket + 56, 0); /* hiCyl */
7250 		put_long (parmpacket + 60, 50); /* Number of buffers */
7251 		put_long (parmpacket + 64, 1); /* Buffer mem type */
7252 		put_long (parmpacket + 68, 0x7FFFFFFE); /* largest transfer */
7253 		put_long (parmpacket + 72, 0xFFFFFFFE); /* dma mask */
7254 #ifdef SCSI
7255 		put_long (parmpacket + 76, scsi_get_cd_drive_media_mask () & (1 << cd_unit_no) ? -127 : -128); /* bootPri */
7256 #endif
7257 		put_long (parmpacket + 80, CDFS_DOSTYPE | (((cd_unit_no / 10) + '0') << 8) | ((cd_unit_no % 10) + '0'));
7258 		put_long (parmpacket + 84, 0); /* baud */
7259 		put_long (parmpacket + 88, 0); /* control */
7260 		put_long (parmpacket + 92, 0); /* bootblocks */
7261 		return type;
7262 
7263 	} else {
7264 
7265 		gui_flicker_led (LED_HD, unit_no, 0);
7266 		type = is_hardfile (unit_no);
7267 		if (type == FILESYS_HARDFILE_RDB || type == FILESYS_HARDDRIVE) {
7268 			/* RDB hardfile */
7269 			uip[unit_no].devno = unit_no;
7270 			return rdb_mount (&uip[unit_no], unit_no, sub_no, parmpacket);
7271 		}
7272 		if (sub_no)
7273 			return -2;
7274 		write_log (_T("Mounting uaehf.device %d (%d):\n"), unit_no, sub_no);
7275 		get_new_device (type, parmpacket, &uip[unit_no].devname, &uip[unit_no].devname_amiga, unit_no);
7276 		uip[unit_no].devno = unit_no;
7277 		put_long (parmpacket, uip[unit_no].devname_amiga);
7278 		put_long (parmpacket + 8, uip[unit_no].devno);
7279 		put_long (parmpacket + 12, 0); /* Device flags */
7280 		put_long (parmpacket + 16, 16); /* Env. size */
7281 		put_long (parmpacket + 24, 0); /* unused */
7282 		put_long (parmpacket + 44, 0); /* unused */
7283 		put_long (parmpacket + 48, 0); /* interleave */
7284 		put_long (parmpacket + 60, 50); /* Number of buffers */
7285 		put_long (parmpacket + 64, 1); /* Buffer mem type */
7286 		put_long (parmpacket + 68, 0x7FFFFFFE); /* largest transfer */
7287 		put_long (parmpacket + 72, 0xFFFFFFFE); /* dma mask */
7288 		put_long (parmpacket + 76, uip[unit_no].bootpri); /* bootPri */
7289 		put_long (parmpacket + 80, DISK_TYPE_DOS); /* DOS\0 */
7290 		if (type == FILESYS_VIRTUAL) {
7291 			put_long (parmpacket + 4, fsdevname);
7292 			put_long (parmpacket + 20, 512 >> 2); /* longwords per block */
7293 			put_long (parmpacket + 28, 15); /* heads */
7294 			put_long (parmpacket + 32, 1); /* sectors per block */
7295 			put_long (parmpacket + 36, 127); /* sectors per track */
7296 			put_long (parmpacket + 40, 2); /* reserved blocks */
7297 			put_long (parmpacket + 52, 0); /* lowCyl */
7298 			put_long (parmpacket + 56, 1); /* hiCyl */
7299 		} else {
7300 			uae_u8 buf[512] = { 0 };
7301 			char *s = ua_fs (uip[unit_no].devname, -1);
7302 			buf[36] = strlen (s);
7303 			for (int i = 0; i < buf[36]; i++)
7304 				buf[37 + i] = s[i];
7305 			xfree (s);
7306 			put_long (parmpacket + 4, ROM_hardfile_resname);
7307 			put_long (parmpacket + 20, ci->blocksize >> 2); /* longwords per block */
7308 			put_long (parmpacket + 28, ci->surfaces); /* heads */
7309 			put_long (parmpacket + 32, ci->sectorsperblock); /* sectors per block */
7310 			put_long (parmpacket + 36, ci->sectors); /* sectors per track */
7311 			put_long (parmpacket + 40, ci->reserved); /* reserved blocks */
7312 			put_long (parmpacket + 52, ci->lowcyl); /* lowCyl */
7313 			put_long (parmpacket + 56, ci->highcyl <= 0 ? ci->cyls - 1 : ci->highcyl - 1); /* hiCyl */
7314 			put_long (parmpacket + 48, ci->interleave); /* interleave */
7315 			put_long (parmpacket + 60, ci->buffers); /* Number of buffers */
7316 			put_long (parmpacket + 64, ci->bufmemtype); /* Buffer mem type */
7317 			put_long (parmpacket + 68, ci->maxtransfer); /* largest transfer */
7318 			put_long (parmpacket + 72, ci->mask); /* dma mask */
7319 			if (ci->dostype) // forced dostype?
7320 				put_long (parmpacket + 80, ci->dostype); /* dostype */
7321 			for (int i = 0; i < 80; i++)
7322 				buf[i + 128] = get_byte (parmpacket + 16 + i);
7323 			dump_partinfo (&uip[unit_no].hf, buf);
7324 		}
7325 		if (type == FILESYS_HARDFILE)
7326 			type = dofakefilesys (&uip[unit_no], parmpacket, ci);
7327 		if (uip[unit_no].bootpri < -127 || (type == FILESYS_HARDFILE && ci->rootdir[0] == 0))
7328 			m68k_dreg (regs, 7) = m68k_dreg (regs, 7) & ~1; /* do not boot */
7329 		if (uip[unit_no].bootpri < -128)
7330 			return -1; /* do not mount */
7331 		return type;
7332 	}
7333 }
7334 
mousehack_done(TrapContext * context)7335 static uae_u32 REGPARAM2 mousehack_done (TrapContext *context)
7336 {
7337 	int mode = m68k_dreg (regs, 1);
7338 	if (mode < 10) {
7339 		uaecptr diminfo = m68k_areg (regs, 2);
7340 		uaecptr dispinfo = m68k_areg (regs, 3);
7341 		uaecptr vp = m68k_areg (regs, 4);
7342 		return input_mousehack_status (mode, diminfo, dispinfo, vp, m68k_dreg (regs, 2));
7343 	} else if (mode == 10) {
7344 		;//amiga_clipboard_die ();
7345 	} else if (mode == 11) {
7346 		;//amiga_clipboard_got_data (m68k_areg (regs, 2), m68k_dreg (regs, 2), m68k_dreg (regs, 0) + 8);
7347 	} else if (mode == 12) {
7348 		;//return amiga_clipboard_want_data ();
7349 	} else if (mode == 13) {
7350 		return amiga_clipboard_proc_start ();
7351 	} else if (mode == 14) {
7352 		;//amiga_clipboard_task_start (m68k_dreg (regs, 0));
7353 	} else if (mode == 15) {
7354 		;//amiga_clipboard_init ();
7355 	} else if (mode == 16) {
7356 		uaecptr a2 = m68k_areg (regs, 2);
7357 		input_mousehack_mouseoffset (a2);
7358 	} else if (mode == 17) {
7359 		uae_u32 v = 0;
7360 		/*if (currprefs.clipboard_sharing)
7361 			v |= 1;
7362 		if (consolehook_activate ())
7363 			v |= 2;*/
7364 		return v;
7365 	} else if (mode == 18) {
7366 		return rtarea_base + RTAREA_HEARTBEAT;
7367 	} else if (mode == 101) {
7368 		consolehook_ret (m68k_areg (regs, 1), m68k_areg (regs, 2));
7369 	} else if (mode == 102) {
7370 		uaecptr ret = consolehook_beginio (m68k_areg (regs, 1));
7371 		put_long (m68k_areg (regs, 7) + 4 * 4, ret);
7372 	} else {
7373 		write_log (_T("Unknown mousehack hook %d\n"), mode);
7374 	}
7375 	return 1;
7376 }
7377 
7378 extern void cia_heartbeat (void);
filesys_vsync(void)7379 void filesys_vsync (void)
7380 {
7381 	Unit *u;
7382 
7383 	if (!uae_boot_rom)
7384 		return;
7385 	if (heartbeat == get_long (rtarea_base + RTAREA_HEARTBEAT)) {
7386 		if (heartbeat_count > 0)
7387 			heartbeat_count--;
7388 		return;
7389 	}
7390 	heartbeat = get_long (rtarea_base + RTAREA_HEARTBEAT);
7391 	cia_heartbeat ();
7392 
7393 	for (u = units; u; u = u->next) {
7394 		if (u->reinsertdelay > 0) {
7395 			u->reinsertdelay--;
7396 			if (u->reinsertdelay == 0) {
7397 				filesys_insert (u->unit, u->newvolume, u->newrootdir, u->newreadonly, u->newflags);
7398 				xfree (u->newvolume);
7399 				u->newvolume = NULL;
7400 				xfree (u->newrootdir);
7401 				u->newrootdir = NULL;
7402 			}
7403 		}
7404 		record_timeout (u);
7405 	}
7406 
7407 	for (int i = 0; i < currprefs.mountitems; i++) {
7408 		struct hardfiledata *hfd = get_hardfile_data (currprefs.mountconfig[i].configoffset);
7409 		if (!hfd)
7410 			continue;
7411 		if (hfd->reinsertdelay > 0) {
7412 			hfd->reinsertdelay--;
7413 			if (hfd->reinsertdelay == 0) {
7414 				hfd->reinsertdelay = -1;
7415 				hardfile_media_change (hfd, &hfd->delayedci, true, true);
7416 			}
7417 		}
7418 	}
7419 
7420 	if (heartbeat_count <= 0)
7421 		return;
7422 
7423 	if (heartbeat_task & 1) {
7424 		setsystime_vblank ();
7425 		heartbeat_task &= ~1;
7426 	}
7427 }
7428 
filesys_install(void)7429 void filesys_install (void)
7430 {
7431 	uaecptr loop;
7432 
7433 	TRACEI ((_T("Installing filesystem\n")));
7434 
7435 	uae_sem_init (&singlethread_int_sem, 0, 1);
7436 	uae_sem_init (&test_sem, 0, 1);
7437 
7438 	ROM_filesys_resname = ds("UAEunixfs.resource");
7439 	ROM_filesys_resid = ds("UAE unixfs 0.4");
7440 
7441 	fsdevname = ds ("uae.device"); /* does not really exist */
7442 	fshandlername = ds ("uaefs");
7443 	cdfs_devname = ds ("uaescsi.device");
7444 	cdfs_handlername = ds ("uaecdfs");
7445 	ROM_filesys_diagentry = here ();
7446 	calltrap (deftrap2 (filesys_diagentry, 0, _T("filesys_diagentry")));
7447 	dw(0x4ED0); /* JMP (a0) - jump to code that inits Residents */
7448 
7449 	loop = here ();
7450 
7451 	org (rtarea_base + RTAREA_HEARTBEAT);
7452 	dl (0);
7453 	heartbeat = 0;
7454 	heartbeat_task = 0;
7455 
7456 	org (rtarea_base + 0xFF18);
7457 	calltrap (deftrap2 (filesys_dev_bootfilesys, 0, _T("filesys_dev_bootfilesys")));
7458 	dw (RTS);
7459 
7460 	/* Special trap for the assembly make_dev routine */
7461 	org (rtarea_base + 0xFF20);
7462 	calltrap (deftrap2 (filesys_dev_remember, 0, _T("filesys_dev_remember")));
7463 	dw (RTS);
7464 
7465 	org (rtarea_base + 0xFF28);
7466 	calltrap (deftrap2 (filesys_dev_storeinfo, 0, _T("filesys_dev_storeinfo")));
7467 	dw (RTS);
7468 
7469 	org (rtarea_base + 0xFF30);
7470 	calltrap (deftrap2 (filesys_handler, 0, _T("filesys_handler")));
7471 	dw (RTS);
7472 
7473 	org (rtarea_base + 0xFF38);
7474 	calltrap (deftrap2 (mousehack_done, 0, _T("mousehack_done")));
7475 	dw (RTS);
7476 
7477 	org (rtarea_base + 0xFF40);
7478 	calltrap (deftrap2 (startup_handler, 0, _T("startup_handler")));
7479 	dw (RTS);
7480 
7481 	org (rtarea_base + 0xFF48);
7482 	calltrap (deftrap2 (filesys_init_storeinfo, TRAPFLAG_EXTRA_STACK, _T("filesys_init_storeinfo")));
7483 	dw (RTS);
7484 
7485 	org (rtarea_base + 0xFF50);
7486 	calltrap (deftrap2 (exter_int_helper, 0, _T("exter_int_helper")));
7487 	dw (RTS);
7488 
7489 	org (rtarea_base + 0xFF58);
7490 	calltrap (deftrap2 (fsmisc_helper, 0, _T("fsmisc_helper")));
7491 	dw (RTS);
7492 
7493 	org (loop);
7494 }
7495 
7496 extern unsigned char cdfs_rom[];
7497 extern unsigned int cdfs_rom_len;
7498 
filesys_install_code(void)7499 void filesys_install_code (void)
7500 {
7501 	uae_u32 a, b, items;
7502 
7503 	bootrom_header = 3 * 4;
7504 	align(4);
7505 	a = here ();
7506 #include "filesys_bootrom.c"
7507 
7508 	items = dlg (a + 8) & 0xffff;
7509 	/* The last offset comes from the code itself, look for it near the top. */
7510 	EXPANSION_bootcode = a + bootrom_header + items * 4 - 4;
7511 	b = a + bootrom_header + 3 * 4 - 4;
7512 	filesys_initcode = a + dlg (b) + bootrom_header - 4;
7513 }
7514 
7515 #ifdef SAVESTATE
restore_filesys_hardfile(UnitInfo * ui,uae_u8 * src)7516 static uae_u8 *restore_filesys_hardfile (UnitInfo *ui, uae_u8 *src)
7517 {
7518 	struct hardfiledata *hfd = &ui->hf;
7519 	TCHAR *s;
7520 
7521 	hfd->virtsize = restore_u64();
7522 	hfd->offset = restore_u64();
7523 	hfd->ci.highcyl = restore_u32 ();
7524 	hfd->ci.sectors = restore_u32 ();
7525 	hfd->ci.surfaces = restore_u32 ();
7526 	hfd->ci.reserved = restore_u32 ();
7527 	hfd->ci.blocksize = restore_u32 ();
7528 	hfd->ci.readonly = restore_u32 () != 0;
7529 	hfd->flags = restore_u32();
7530 	hfd->rdbcylinders = restore_u32 ();
7531 	hfd->rdbsectors = restore_u32 ();
7532 	hfd->rdbheads = restore_u32 ();
7533 	s = restore_string();
7534 	_tcscpy (hfd->vendor_id, s);
7535 	xfree(s);
7536 	s = restore_string();
7537 	_tcscpy (hfd->product_id, s);
7538 	xfree(s);
7539 	s = restore_string();
7540 	_tcscpy (hfd->product_rev, s);
7541 	xfree(s);
7542 	s = restore_string();
7543 	_tcscpy (hfd->device_name, s);
7544 	xfree(s);
7545 	return src;
7546 }
7547 
save_filesys_hardfile(UnitInfo * ui,uae_u8 * dst)7548 static uae_u8 *save_filesys_hardfile (UnitInfo *ui, uae_u8 *dst)
7549 {
7550 	struct hardfiledata *hfd = &ui->hf;
7551 
7552 	save_u64 (hfd->virtsize);
7553 	save_u64 (hfd->offset);
7554 	save_u32 (hfd->ci.highcyl);
7555 	save_u32 (hfd->ci.sectors);
7556 	save_u32 (hfd->ci.surfaces);
7557 	save_u32 (hfd->ci.reserved);
7558 	save_u32 (hfd->ci.blocksize);
7559 	save_u32 (hfd->ci.readonly);
7560 	save_u32 (hfd->flags);
7561 	save_u32 (hfd->rdbcylinders);
7562 	save_u32 (hfd->rdbsectors);
7563 	save_u32 (hfd->rdbheads);
7564 	save_string (hfd->vendor_id);
7565 	save_string (hfd->product_id);
7566 	save_string (hfd->product_rev);
7567 	save_string (hfd->device_name);
7568 	return dst;
7569 }
7570 
restore_filesys_get_base(Unit * u,TCHAR * npath)7571 static a_inode *restore_filesys_get_base (Unit *u, TCHAR *npath)
7572 {
7573 	TCHAR *path, *p, *p2;
7574 	a_inode *a;
7575 	int cnt, err, i;
7576 
7577 	/* no '/' = parent is root */
7578 	if (!_tcschr (npath, '/'))
7579 		return &u->rootnode;
7580 
7581 	/* iterate from root to last to previous path part,
7582 	* create ainos if not already created.
7583 	*/
7584 	path = xcalloc(TCHAR, _tcslen (npath) + 2);
7585 	cnt = 1;
7586 	for (;;) {
7587 		_tcscpy (path, npath);
7588 		_tcscat (path, _T("/"));
7589 		p = path;
7590 		for (i = 0; i < cnt ;i++) {
7591 			if (i > 0)
7592 				p++;
7593 			while (*p != '/' && *p != 0)
7594 				p++;
7595 		}
7596 		if (*p) {
7597 			*p = 0;
7598 			err = 0;
7599 			get_aino (u, &u->rootnode, path, &err);
7600 			if (err) {
7601 				write_log (_T("*** FS: missing path '%s'!\n"), path);
7602 				return NULL;
7603 			}
7604 			cnt++;
7605 		} else {
7606 			break;
7607 		}
7608 	}
7609 
7610 	/* find base (parent) of last path part */
7611 	_tcscpy (path, npath);
7612 	p = path;
7613 	a = u->rootnode.child;
7614 	for (;;) {
7615 		if (*p == 0) {
7616 			write_log (_T("*** FS: base aino NOT found '%s' ('%s')\n"), a->nname, npath);
7617 			xfree (path);
7618 			return NULL;
7619 		}
7620 		p2 = p;
7621 		while(*p2 != '/' && *p2 != '\\' && *p2 != 0)
7622 			p2++;
7623 		*p2 = 0;
7624 		while (a) {
7625 			if (!same_aname(p, a->aname)) {
7626 				a = a->sibling;
7627 				continue;
7628 			}
7629 			p = p2 + 1;
7630 			if (*p == 0) {
7631 				write_log (_T("FS: base aino found '%s' ('%s')\n"), a->nname, npath);
7632 				xfree (path);
7633 				return a;
7634 			}
7635 			a = a->child;
7636 			break;
7637 		}
7638 		if (!a) {
7639 			write_log (_T("*** FS: path part '%s' not found ('%s')\n"), p, npath);
7640 			xfree (path);
7641 			return NULL;
7642 		}
7643 	}
7644 }
7645 
makenativepath(UnitInfo * ui,TCHAR * apath)7646 static TCHAR *makenativepath (UnitInfo *ui, TCHAR *apath)
7647 {
7648 	uae_u32 i = 0;
7649 	TCHAR *pn;
7650 	/* create native path. FIXME: handle 'illegal' characters */
7651 	pn = xcalloc (TCHAR, _tcslen (apath) + 1 + _tcslen (ui->rootdir) + 1);
7652 	_stprintf (pn, _T("%s/%s"), ui->rootdir, apath);
7653 	if (FSDB_DIR_SEPARATOR != '/') {
7654 		for ( ; i < _tcslen (pn); i++) {
7655 			if (pn[i] == '/')
7656 				pn[i] = FSDB_DIR_SEPARATOR;
7657 		}
7658 	}
7659 	return pn;
7660 }
7661 
restore_aino(UnitInfo * ui,Unit * u,uae_u8 * src)7662 static uae_u8 *restore_aino (UnitInfo *ui, Unit *u, uae_u8 *src)
7663 {
7664 	TCHAR *p, *p2, *pn;
7665 	uae_u32 flags;
7666 	int missing;
7667 	a_inode *base, *a;
7668 
7669 	missing = 0;
7670 	a = xcalloc (a_inode, 1);
7671 	a->uniq = restore_u64 ();
7672 	a->locked_children = restore_u32 ();
7673 	a->exnext_count = restore_u32 ();
7674 	a->shlock = restore_u32 ();
7675 	flags = restore_u32 ();
7676 	if (flags & 1)
7677 		a->elock = 1;
7678 	if (flags & 4)
7679 		a->uniq_external = restore_u64 ();
7680 	/* full Amiga-side path without drive, eg. "C/SetPatch" */
7681 	p = restore_string ();
7682 	/* root (p = volume label) */
7683 	if (a->uniq == 0) {
7684 		a->nname = my_strdup (ui->rootdir);
7685 		a->aname = p;
7686 		a->dir = 1;
7687 		if (ui->volflags < 0) {
7688 			write_log (_T("FS: Volume '%s' ('%s') missing!\n"), a->aname, a->nname);
7689 		} else {
7690 			a->volflags = ui->volflags;
7691 			recycle_aino (u, a);
7692 			write_log (_T("FS: Lock (root) '%s' ('%s')\n"), a->aname, a->nname);
7693 		}
7694 		return src;
7695 	}
7696 	p2 = _tcsrchr(p, '/');
7697 	if (p2)
7698 		p2++;
7699 	else
7700 		p2 = p;
7701 	pn = makenativepath (ui, p);
7702 	a->nname = pn;
7703 	a->aname = my_strdup (p2);
7704 	/* find parent of a->aname (Already restored previously. I hope..) */
7705 	if (p2 != p)
7706 		p2[-1] = 0;
7707 	base = restore_filesys_get_base (u, p);
7708 	xfree(p);
7709 	if (flags & 2) {
7710 		a->dir = 1;
7711 		if (!my_existsdir(a->nname))
7712 			write_log (_T("*** FS: Directory '%s' missing!\n"), a->nname);
7713 		else
7714 			fsdb_clean_dir (a);
7715 	} else {
7716 		if (!my_existsfile(a->nname))
7717 			write_log (_T("*** FS: File '%s' missing!\n"), a->nname);
7718 	}
7719 	if (base) {
7720 		fill_file_attrs (u, base, a);
7721 		init_child_aino_tree (u, base, a);
7722 	} else {
7723 		write_log (_T("*** FS: parent directory missing '%s' ('%s')\n"), a->aname, a->nname);
7724 		missing = 1;
7725 	}
7726 	if (missing) {
7727 		write_log (_T("*** FS: Lock restore failed '%s' ('%s')\n"), a->aname, a->nname);
7728 		xfree (a->nname);
7729 		xfree (a->aname);
7730 		xfree (a);
7731 	} else {
7732 		write_log (_T("FS: Lock '%s' ('%s')\n"), a->aname, a->nname);
7733 		recycle_aino (u, a);
7734 	}
7735 	return src;
7736 }
7737 
restore_key(UnitInfo * ui,Unit * u,uae_u8 * src)7738 static uae_u8 *restore_key (UnitInfo *ui, Unit *u, uae_u8 *src)
7739 {
7740 	uae_u32 uniq;
7741 	TCHAR *p, *pn;
7742 	mode_t openmode;
7743 	int err;
7744 	int missing;
7745 	a_inode *a;
7746 	Key *k;
7747 	uae_u64 savedsize, size, pos;
7748 
7749 	missing = 0;
7750 	k = xcalloc (Key, 1);
7751 	k->uniq = restore_u64 ();
7752 	k->file_pos = restore_u32 ();
7753 	k->createmode = restore_u32 ();
7754 	k->dosmode = restore_u32 ();
7755 	savedsize = restore_u32 ();
7756 	uniq = restore_u64 ();
7757 	p = restore_string ();
7758 	pos = restore_u64 ();
7759 	size = restore_u64 ();
7760 	if (size) {
7761 		savedsize = size;
7762 		k->file_pos = pos;
7763 	}
7764 	pn = makenativepath (ui, p);
7765 	openmode = ((k->dosmode & A_FIBF_READ) == 0 ? O_WRONLY
7766 		: (k->dosmode & A_FIBF_WRITE) == 0 ? O_RDONLY
7767 		: O_RDWR);
7768 	write_log (_T("FS: open file '%s' ('%s'), pos=%llu\n"), p, pn, k->file_pos);
7769 	a = get_aino (u, &u->rootnode, p, &err);
7770 	if (!a)
7771 		write_log (_T("*** FS: Open file aino creation failed '%s'\n"), p);
7772 	missing = 1;
7773 	if (a) {
7774 		missing = 0;
7775 		k->aino = a;
7776 		if (a->uniq != uniq)
7777 			write_log (_T("*** FS: Open file '%s' aino id %d != %d\n"), p, uniq, a->uniq);
7778 		if (!my_existsfile(pn)) {
7779 			write_log (_T("*** FS: Open file '%s' is missing, creating dummy file!\n"), p);
7780 			if (savedsize < 10 * 1024 * 1024) {
7781 				k->fd = fs_openfile (u, a, openmode | O_CREAT |O_BINARY);
7782 				if (k->fd) {
7783 					uae_u8 *buf = xcalloc (uae_u8, 10000);
7784 					uae_u64 sp = savedsize;
7785 					while (sp) {
7786 						uae_u32 s = sp >= 10000 ? 10000 : sp;
7787 						fs_write (k->fd, buf, s);
7788 						sp -= s;
7789 					}
7790 					xfree(buf);
7791 					write_log (_T("*** FS: dummy file created\n"));
7792 			     } else {
7793 					write_log (_T("*** FS: Open file '%s', couldn't create dummy file!\n"), p);
7794 			     }
7795 			} else {
7796 				write_log (_T("*** FS: Too big, ignored\n"));
7797 			}
7798                 } else {
7799 			k->fd = fs_openfile (u, a, openmode | O_BINARY);
7800 		}
7801 		if (!k->fd) {
7802 			write_log (_T("*** FS: Open file '%s' failed to open!\n"), p);
7803 			missing = 1;
7804 		} else {
7805 			uae_s64 s;
7806 			s = fs_fsize64 (k->fd);
7807 			if (s != (uae_s64)savedsize)
7808 				write_log (_T("FS: restored file '%s' size changed! orig=%llu, now=%lld!!\n"), p, savedsize, s);
7809 			if (k->file_pos > s) {
7810 				write_log (_T("FS: restored filepos larger than size of file '%s'!! %llu > %lld\n"), p, k->file_pos, s);
7811 				k->file_pos = s;
7812 			}
7813 			fs_lseek64 (k->fd, k->file_pos, SEEK_SET);
7814 		}
7815 	}
7816 	xfree (p);
7817 	if (missing) {
7818 		xfree(k);
7819 	} else {
7820 		k->next = u->keys;
7821 		u->keys = k;
7822 	}
7823 	return src;
7824 }
7825 
restore_notify(UnitInfo * ui,Unit * u,uae_u8 * src)7826 static uae_u8 *restore_notify (UnitInfo *ui, Unit *u, uae_u8 *src)
7827 {
7828 	Notify *n = xcalloc (Notify, 1);
7829 	uae_u32 hash;
7830 	TCHAR *s;
7831 
7832 	n->notifyrequest = restore_u32 ();
7833 	s = restore_string ();
7834 	n->fullname = xmalloc (TCHAR, _tcslen (ui->volname) + 2 + _tcslen (s) + 1);
7835 	_stprintf (n->fullname, _T("%s:%s"), ui->volname, s);
7836 	xfree(s);
7837 	s = _tcsrchr (n->fullname, '/');
7838 	if (s)
7839 		s++;
7840 	else
7841 		s = n->fullname;
7842 	n->partname = my_strdup (s);
7843 	hash = notifyhash (n->fullname);
7844 	n->next = u->notifyhash[hash];
7845 	u->notifyhash[hash] = n;
7846 	write_log (_T("FS: notify %08X '%s' '%s'\n"), n->notifyrequest, n->fullname, n->partname);
7847 	return src;
7848 }
7849 
restore_exkey(UnitInfo * ui,Unit * u,uae_u8 * src)7850 static uae_u8 *restore_exkey (UnitInfo *ui, Unit *u, uae_u8 *src)
7851 {
7852 	restore_u64 ();
7853 	restore_u64 ();
7854 	restore_u64 ();
7855 	return src;
7856 }
7857 
restore_filesys_virtual(UnitInfo * ui,uae_u8 * src,int num)7858 static uae_u8 *restore_filesys_virtual (UnitInfo *ui, uae_u8 *src, int num)
7859 {
7860 	Unit *u = startup_create_unit (ui, num);
7861 	int cnt;
7862 
7863 	u->dosbase = restore_u32 ();
7864 	u->volume = restore_u32 ();
7865 	u->port = restore_u32 ();
7866 	u->locklist = restore_u32 ();
7867 	u->dummy_message = restore_u32 ();
7868 	u->cmds_sent = restore_u64 ();
7869 	u->cmds_complete = restore_u64 ();
7870 	u->cmds_acked = restore_u64 ();
7871 	u->next_exkey = restore_u32 ();
7872 	u->total_locked_ainos = restore_u32 ();
7873 	u->volflags = ui->volflags;
7874 
7875 	cnt = restore_u32 ();
7876 	write_log (_T("FS: restoring %d locks\n"), cnt);
7877 	while (cnt-- > 0)
7878 		src = restore_aino(ui, u, src);
7879 
7880 	cnt = restore_u32 ();
7881 	write_log (_T("FS: restoring %d open files\n"), cnt);
7882 	while (cnt-- > 0)
7883 		src = restore_key(ui, u, src);
7884 
7885 	cnt = restore_u32 ();
7886 	write_log (_T("FS: restoring %d notifications\n"), cnt);
7887 	while (cnt-- > 0)
7888 		src = restore_notify (ui, u, src);
7889 
7890 	cnt = restore_u32 ();
7891 	write_log (_T("FS: restoring %d exkeys\n"), cnt);
7892 	while (cnt-- > 0)
7893 		src = restore_exkey (ui, u, src);
7894 
7895 	return src;
7896 }
7897 
getfullaname(a_inode * a)7898 static TCHAR *getfullaname(a_inode *a)
7899 {
7900 	TCHAR *p;
7901 	int first = 1;
7902 
7903 	p = xcalloc (TCHAR, 2000);
7904 	while (a) {
7905 		int len = _tcslen (a->aname);
7906 		memmove (p + len + 1, p, (_tcslen (p) + 1) * sizeof (TCHAR));
7907 		memcpy (p, a->aname, _tcslen (a->aname) * sizeof (TCHAR));
7908 		if (!first)
7909 			p[len] = '/';
7910 		first = 0;
7911 		a = a->parent;
7912 		if (a && a->uniq == 0)
7913 			return p;
7914 	}
7915 	return p;
7916 }
7917 
7918 /* scan and save all Lock()'d files */
recurse_aino(UnitInfo * ui,a_inode * a,int cnt,uae_u8 ** dstp)7919 static int recurse_aino (UnitInfo *ui, a_inode *a, int cnt, uae_u8 **dstp)
7920 {
7921 	uae_u8 *dst = NULL;
7922 	int dirty = 0;
7923 	a_inode *a2 = a;
7924 
7925 	if (dstp)
7926 		dst = *dstp;
7927 	while (a) {
7928 		//write_log("recurse '%s' '%s' %d %08x\n", a->aname, a->nname, a->uniq, a->parent);
7929 		if (a->elock || a->shlock || a->uniq == 0) {
7930 			if (dst) {
7931 				TCHAR *fn = NULL;
7932 				write_log (_T("uniq=%d %lld s=%d e=%d d=%d '%s' '%s'\n"), a->uniq, a->uniq_external, a->shlock, a->elock, a->dir, a->aname, a->nname);
7933 				if (a->aname) {
7934 				fn = getfullaname(a);
7935 					write_log (_T("->'%s'\n"), fn);
7936 				}
7937 				save_u64 (a->uniq);
7938 				save_u32 (a->locked_children);
7939 				save_u32 (a->exnext_count);
7940 				save_u32 (a->shlock);
7941 				save_u32 ((a->elock ? 1 : 0) | (a->dir ? 2 : 0) | 4);
7942 				save_u64 (a->uniq_external);
7943 				save_string (fn);
7944 				xfree(fn);
7945 			}
7946 			cnt++;
7947 		}
7948 		if (a->dirty)
7949 			dirty = 1;
7950 		if (a->child)
7951 			cnt = recurse_aino (ui, a->child, cnt, &dst);
7952 		a = a->sibling;
7953 	}
7954 	if (dirty && a2->parent)
7955 		fsdb_dir_writeback (a2->parent);
7956 	if (dst)
7957 		*dstp = dst;
7958 	return cnt;
7959 }
7960 
save_key(uae_u8 * dst,Key * k)7961 static uae_u8 *save_key (uae_u8 *dst, Key *k)
7962 {
7963 	TCHAR *fn = getfullaname (k->aino);
7964 	uae_u64 size;
7965 	save_u64 (k->uniq);
7966 	save_u32 ((uae_u32)k->file_pos);
7967 	save_u32 (k->createmode);
7968 	save_u32 (k->dosmode);
7969 	size = fs_fsize (k->fd);
7970 	save_u32 ((uae_u32)size);
7971 	save_u64 (k->aino->uniq);
7972 	save_string (fn);
7973 	save_u64 (k->file_pos);
7974 	save_u64 (size);
7975 	write_log (_T("'%s' uniq=%d size=%lld seekpos=%lld mode=%d dosmode=%d\n"),
7976 		fn, k->uniq, size, k->file_pos, k->createmode, k->dosmode);
7977 	xfree (fn);
7978 	return dst;
7979 }
7980 
save_notify(UnitInfo * ui,uae_u8 * dst,Notify * n)7981 static uae_u8 *save_notify (UnitInfo *ui, uae_u8 *dst, Notify *n)
7982 {
7983 	TCHAR *s;
7984 	save_u32 (n->notifyrequest);
7985 	s = n->fullname;
7986 	if (_tcslen (s) >= _tcslen (ui->volname) && !_tcsncmp (n->fullname, ui->volname, _tcslen (ui->volname)))
7987 		s = n->fullname + _tcslen (ui->volname) + 1;
7988 	save_string (s);
7989 	write_log (_T("FS: notify %08X '%s'\n"), n->notifyrequest, n->fullname);
7990 	return dst;
7991 }
7992 
save_exkey(uae_u8 * dst,ExamineKey * ek)7993 static uae_u8 *save_exkey (uae_u8 *dst, ExamineKey *ek)
7994 {
7995 	save_u64 (ek->uniq);
7996 	save_u64 (ek->aino->uniq);
7997 	save_u64 (ek->curr_file->uniq);
7998 	return dst;
7999 }
8000 
save_filesys_virtual(UnitInfo * ui,uae_u8 * dst)8001 static uae_u8 *save_filesys_virtual (UnitInfo *ui, uae_u8 *dst)
8002 {
8003 	Unit *u = ui->self;
8004 	Key *k;
8005 	int cnt, i, j;
8006 
8007 	write_log (_T("FSSAVE: '%s'\n"), ui->devname);
8008 	save_u32 (u->dosbase);
8009 	save_u32 (u->volume);
8010 	save_u32 (u->port);
8011 	save_u32 (u->locklist);
8012 	save_u32 (u->dummy_message);
8013 	save_u64 (u->cmds_sent);
8014 	save_u64 (u->cmds_complete);
8015 	save_u64 (u->cmds_acked);
8016 	save_u32 (u->next_exkey);
8017 	save_u32 (u->total_locked_ainos);
8018 	cnt = recurse_aino (ui, &u->rootnode, 0, NULL);
8019 	save_u32 (cnt);
8020 	write_log (_T("%d open locks\n"), cnt);
8021 	cnt = recurse_aino (ui, &u->rootnode, 0, &dst);
8022 	cnt = 0;
8023 	for (k = u->keys; k; k = k->next)
8024 		cnt++;
8025 	save_u32 (cnt);
8026 	write_log (_T("%d open files\n"), cnt);
8027 	for (k = u->keys; k; k = k->next)
8028 		dst = save_key (dst, k);
8029 	for (j = 0; j < 2; j++) {
8030 		cnt = 0;
8031 		for (i = 0; i < NOTIFY_HASH_SIZE; i++) {
8032 			Notify *n = u->notifyhash[i];
8033 			while (n) {
8034 				if (j > 0)
8035 					dst = save_notify (ui, dst, n);
8036 				cnt++;
8037 				n = n->next;
8038 			}
8039 		}
8040 		if (j == 0) {
8041 			save_u32 (cnt);
8042 			write_log (_T("%d notify requests\n"), cnt);
8043 		}
8044 	}
8045 	for (j = 0; j < 2; j++) {
8046 		cnt = 0;
8047 		for (i = 0; i < EXKEYS; i++) {
8048 			ExamineKey *ek = &u->examine_keys[i];
8049 			if (ek->uniq) {
8050 				cnt++;
8051 				if (j > 0)
8052 					dst = save_exkey (dst, ek);
8053 			}
8054 		}
8055 		if (j == 0) {
8056 			save_u32 (cnt);
8057 			write_log (_T("%d exkeys\n"), cnt);
8058 		}
8059 	}
8060 	write_log (_T("END\n"));
8061 	return dst;
8062 }
8063 
save_filesys_common(int * len)8064 uae_u8 *save_filesys_common (int *len)
8065 {
8066 	uae_u8 *dstbak, *dst;
8067 	if (nr_units () == 0)
8068 		return NULL;
8069 	dstbak = dst = xmalloc (uae_u8, 1000);
8070 	save_u32 (2);
8071 	save_u64 (a_uniq);
8072 	save_u64 (key_uniq);
8073 	*len = dst - dstbak;
8074 	return dstbak;
8075 }
8076 
restore_filesys_common(uae_u8 * src)8077 uae_u8 *restore_filesys_common (uae_u8 *src)
8078 {
8079 	if (restore_u32 () != 2)
8080 		return src;
8081 	cd_unit_offset = MAX_FILESYSTEM_UNITS;
8082 	cd_unit_number = 0;
8083 	filesys_prepare_reset2 ();
8084 	filesys_reset2 ();
8085 	a_uniq = restore_u64 ();
8086 	key_uniq = restore_u64 ();
8087 	return src;
8088 }
8089 
save_filesys(int num,int * len)8090 uae_u8 *save_filesys (int num, int *len)
8091 {
8092 	uae_u8 *dstbak, *dst;
8093 	UnitInfo *ui;
8094 	int type = is_hardfile (num);
8095 
8096 	ui = &mountinfo.ui[num];
8097 	if (!ui->open)
8098 		return NULL;
8099 	/* not initialized yet, do not save */
8100 	if ((type == FILESYS_VIRTUAL || type == FILESYS_CD) && ui->self == NULL)
8101 		return NULL;
8102 	write_log (_T("FS_FILESYS: '%s' '%s'\n"), ui->devname, ui->volname ? ui->volname : _T("<no name>"));
8103 	dstbak = dst = xmalloc (uae_u8, 100000);
8104 	save_u32 (2); /* version */
8105 	save_u32 (ui->devno);
8106 	save_u16 (type);
8107 	if (type == FILESYS_VIRTUAL || type == FILESYS_CD)
8108 		save_path (ui->rootdir, SAVESTATE_PATH_VDIR);
8109 	else if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB)
8110 		save_path (ui->rootdir, SAVESTATE_PATH_HDF);
8111 	else if (type == FILESYS_HARDDRIVE)
8112 		save_path (ui->rootdir, SAVESTATE_PATH_HD);
8113 	else
8114 		save_path (ui->rootdir, SAVESTATE_PATH);
8115 	save_string (ui->devname);
8116 	save_string (ui->volname);
8117 	save_path (ui->filesysdir, SAVESTATE_PATH);
8118 	save_u8 (ui->bootpri);
8119 	save_u8 (ui->readonly);
8120 	save_u32 (ui->startup);
8121 	save_u32 (filesys_configdev);
8122 	if (type == FILESYS_VIRTUAL || type == FILESYS_CD)
8123 		dst = save_filesys_virtual (ui, dst);
8124 	if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB)
8125 		dst = save_filesys_hardfile (ui, dst);
8126 	*len = dst - dstbak;
8127 	return dstbak;
8128 }
8129 
restore_filesys(uae_u8 * src)8130 uae_u8 *restore_filesys (uae_u8 *src)
8131 {
8132 	int type, devno;
8133 	UnitInfo *ui;
8134 	TCHAR *devname = 0, *volname = 0, *rootdir = 0, *filesysdir = 0;
8135 	uae_u32 startup;
8136 	struct uaedev_config_info *ci;
8137 
8138 	if (restore_u32 () != 2)
8139 		return src;
8140 	devno = restore_u32 ();
8141 	ui = &mountinfo.ui[devno];
8142 	ci = &ui->hf.ci;
8143 	uci_set_defaults (ci, false);
8144 	type = restore_u16 ();
8145 	if (type == FILESYS_VIRTUAL) {
8146 		rootdir = restore_path (SAVESTATE_PATH_VDIR);
8147 	} else if (type == FILESYS_CD) {
8148 		rootdir = restore_path (SAVESTATE_PATH_VDIR);
8149 		if (cd_unit_offset == MAX_FILESYSTEM_UNITS)
8150 			cd_unit_offset = devno;
8151 		cd_unit_number++;
8152 	} else if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB) {
8153 		rootdir = restore_path (SAVESTATE_PATH_HDF);
8154 	} else if (type == FILESYS_HARDDRIVE) {
8155 		rootdir = restore_path (SAVESTATE_PATH_HD);
8156 	} else {
8157 		rootdir = restore_path (SAVESTATE_PATH);
8158 	}
8159 	devname = restore_string ();
8160 	volname = restore_string ();
8161 	filesysdir = restore_path (SAVESTATE_PATH);
8162 	ci->bootpri = restore_u8 ();
8163 	ci->readonly = restore_u8 () != 0;
8164 	startup = restore_u32 ();
8165 	filesys_configdev = restore_u32 ();
8166 	if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB) {
8167 		src = restore_filesys_hardfile (ui, src);
8168 		xfree (volname);
8169 		volname = NULL;
8170 	}
8171 	_tcscpy (ci->rootdir, rootdir);
8172 	_tcscpy (ci->devname, devname);
8173 	_tcscpy (ci->volname, volname ? volname : _T(""));
8174 	_tcscpy (ci->filesys, filesysdir);
8175 
8176 	if (set_filesys_unit (devno, ci) < 0) {
8177 		write_log (_T("filesys '%s' failed to restore\n"), rootdir);
8178 		goto end;
8179 	}
8180 	ui->devno = devno;
8181 	ui->startup = startup;
8182 	if (type == FILESYS_VIRTUAL || type == FILESYS_CD)
8183 		src = restore_filesys_virtual (ui, src, devno);
8184 	write_log (_T("'%s' restored\n"), rootdir);
8185 end:
8186 	xfree (rootdir);
8187 	xfree (devname);
8188 	xfree (volname);
8189 	xfree (filesysdir);
8190 	return src;
8191 }
8192 
save_filesys_cando(void)8193 int save_filesys_cando (void)
8194 {
8195 	if (nr_units () == 0)
8196 		return -1;
8197 	return filesys_in_interrupt ? 0 : 1;
8198 }
8199 
8200 #endif
8201