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