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