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