genmodule: Fix handler modules types' initialization
[AROS.git] / arch / all-hosted / filesys / emul_handler / emul_handler.c
blob898b50f9d9a1a3477bc963546b2d2b4300f3b4be
1 /*
2 Copyright 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Filesystem that accesses an underlying host OS filesystem.
6 Lang: english
7 */
9 /*********************************************************************************************/
11 #define DEBUG 0
12 #define DCHDIR(x)
13 #define DCMD(x)
14 #define DDEL(x)
15 #define DERROR(x)
16 #define DEXAM(x)
17 #define DFNAME(x)
18 #define DFSIZE(x)
19 #define DLINK(x)
20 #define DLOCK(x)
21 #define DMOUNT(x)
22 #define DOPEN(x)
23 #define DSAME(x)
24 #define DSEEK(x)
26 #include <aros/debug.h>
27 #include <aros/symbolsets.h>
28 #include <exec/memory.h>
29 #include <devices/input.h>
30 #include <devices/inputevent.h>
31 #include <libraries/expansion.h>
32 #include <proto/exec.h>
33 #include <utility/tagitem.h>
34 #include <dos/exall.h>
35 #include <dos/dosasl.h>
36 #include <proto/arossupport.h>
37 #include <proto/dos.h>
38 #include <proto/expansion.h>
40 #include "emul_intern.h"
42 #include <limits.h>
43 #include <string.h>
44 #include <stddef.h>
46 #ifdef AROS_FAST_BSTR
48 #define bstrcpy strcpy
50 #else
52 #define bstrcpy(d, s) \
53 d = (d + 3) & ~3; \
54 strcpy(d + 1, s); \
55 d[0] = strlen(s);
57 #endif
59 /*********************************************************************************************/
61 static void SendEvent(struct emulbase *emulbase, LONG event)
63 struct IOStdReq *InputRequest;
64 struct MsgPort *InputPort;
65 struct InputEvent *ie;
67 D(bug("[emul] SendEvent\n"));
68 if ((InputPort = (struct MsgPort*)CreateMsgPort())) {
70 if ((InputRequest = (struct IOStdReq*)CreateIORequest(InputPort, sizeof(struct IOStdReq)))) {
72 if (!OpenDevice("input.device", 0, (struct IORequest*)InputRequest, 0)) {
74 if ((ie = AllocVec(sizeof(struct InputEvent), MEMF_PUBLIC|MEMF_CLEAR))) {
75 ie->ie_Class = event;
76 InputRequest->io_Command = IND_WRITEEVENT;
77 InputRequest->io_Data = ie;
78 InputRequest->io_Length = sizeof(struct InputEvent);
80 DoIO((struct IORequest*)InputRequest);
82 FreeVec(ie);
84 CloseDevice((struct IORequest*)InputRequest);
86 DeleteIORequest ((APTR)InputRequest);
88 DeleteMsgPort (InputPort);
92 /*********************************************************************************************/
94 /* Allocate a buffer, in which the filename is appended to the pathname. */
95 static LONG makefilename(struct emulbase *emulbase, char **dest, char **part, struct filehandle *fh, const char *filename)
97 LONG ret = 0;
98 int len, flen, dirlen;
99 char *c;
101 DFNAME(bug("[emul] makefilename(): directory \"%s\", file \"%s\")\n", fh->hostname, filename));
104 * dos.library will give us whatever the user typed. It won't strip away device prefix.
105 * Here we have to do it ourselves.
107 c = strrchr(filename, ':');
108 if (c)
109 filename = c + 1;
111 ret = validate(filename);
112 if (ret)
113 return ret;
115 dirlen = strlen(fh->hostname);
116 flen = strlen(filename);
117 len = flen + dirlen + 2;
119 *dest = AllocVecPooled(emulbase->mempool, len);
120 if ((*dest))
122 CopyMem(fh->hostname, *dest, dirlen);
123 c = *dest + dirlen;
124 if (flen)
125 c = append(c, filename);
126 *c = 0;
128 c = *dest + (fh->name - fh->hostname);
129 DFNAME(bug("[emul] Shrinking filename: \"%s\"\n", c));
130 if (!shrink(c))
132 FreeVecPooled(emulbase->mempool, *dest);
133 *dest = NULL;
134 ret = ERROR_OBJECT_NOT_FOUND;
135 } else {
136 DFNAME(bug("[emul] resulting host filename: \"%s\"\n", *dest));
137 if (part) {
138 *part = c;
139 DFNAME(bug("[emul] resulting AROS filename: \"%s\"\n", c));
142 } else
143 ret = ERROR_NO_FREE_STORE;
144 return ret;
147 /*********************************************************************************************/
149 /* Free a filehandle */
150 static void free_lock(struct emulbase *emulbase, struct filehandle *current)
152 DLOCK(bug("[emul] Lock type = %lu\n", current->type));
153 DoClose(emulbase, current);
155 DLOCK(bug("[emul] Freeing name: \"%s\"\n", current->hostname));
156 FreeVecPooled(emulbase->mempool, current->hostname);
158 DLOCK(bug("[emul] Freeing filehandle\n"));
159 FreeMem(current, sizeof(struct filehandle));
161 DLOCK(bug("[emul] Done\n"));
164 /*********************************************************************************************/
166 static LONG open_(struct emulbase *emulbase, struct filehandle *fhv, struct filehandle **handle, const char *name, LONG mode, LONG protect, BOOL AllowDir)
168 LONG ret = 0;
169 struct filehandle *fh;
171 DOPEN(bug("[emul] open_(\"%s\", 0x%lx), directories allowed: %lu\n", name, mode, AllowDir));
173 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC|MEMF_CLEAR);
174 if (fh)
176 fh->dl = (*handle)->dl;
178 /* If no filename is given and the file-descriptor is one of the
179 standard filehandles (stdin, stdout, stderr) ... */
180 if((!name[0]) && ((*handle)->type & FHD_STDIO))
182 /* ... then just reopen that standard filehandle. */
183 fh->type = FHD_FILE|FHD_STDIO;
184 fh->fd = (*handle)->fd;
185 fh->name = NULL;
186 fh->hostname = NULL;
187 fh->volumename = NULL;
188 *handle = fh;
190 return 0;
193 fh->volumename=(*handle)->volumename;
195 ret = makefilename(emulbase, &fh->hostname, &fh->name, *handle, name);
196 if (!ret)
198 /* If the name is empty, this is an alias of the root
199 * volume's handle.
201 if (fh->name[0] == 0) {
202 FreeMem(fh, sizeof(*fh));
203 if (!AllowDir) {
204 *handle = 0;
205 return ERROR_OBJECT_WRONG_TYPE;
207 *handle = fhv;
208 return 0;
211 ret = DoOpen(emulbase, fh, mode, protect, AllowDir);
212 if (!ret)
214 *handle = fh;
215 return 0;
218 DOPEN(bug("[emul] Freeing pathname\n"));
219 FreeVecPooled(emulbase->mempool, fh->hostname);
221 DOPEN(bug("[emul] Freeing filehandle\n"));
222 FreeMem(fh, sizeof(struct filehandle));
223 } else
224 ret = ERROR_NO_FREE_STORE;
225 DOPEN(bug("[emul] open_() returns %lu\n", ret));
226 return ret;
230 /*********************************************************************************************/
232 static LONG create_dir(struct emulbase *emulbase, struct filehandle **handle,
233 const char *filename, ULONG protect)
235 LONG ret = 0;
236 struct filehandle *fh;
238 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC|MEMF_CLEAR);
239 if (fh)
241 fh->volumename = (*handle)->volumename;
242 fh->dl = (*handle)->dl;
244 ret = makefilename(emulbase, &fh->hostname, &fh->name, *handle, filename);
245 if (!ret)
247 ret = DoMkDir(emulbase, fh, protect);
248 if (!ret)
250 *handle = fh;
251 return 0;
254 free_lock(emulbase, fh);
255 } else
256 ret = ERROR_NO_FREE_STORE;
258 return ret;
261 /*********************************************************************************************/
263 static LONG delete_object(struct emulbase *emulbase, struct filehandle* fh, const char *file)
265 LONG ret = 0;
266 char *filename = NULL;
268 DDEL(bug("[emul] Deleting object %s in handle 0x%p (%s)\n", file, fh, fh->hostname));
270 ret = makefilename(emulbase, &filename, NULL, fh, file);
271 if (!ret)
273 ret = DoDelete(emulbase, filename);
274 FreeVecPooled(emulbase->mempool, filename);
277 return ret;
280 /*********************************************************************************************/
282 static LONG set_protect(struct emulbase *emulbase, struct filehandle* fh,
283 const char *file, ULONG aprot)
285 LONG ret = 0;
286 char *filename = NULL;
288 if ((ret = makefilename(emulbase, &filename, NULL, fh, file)))
289 return ret;
291 ret = DoChMod(emulbase, filename, aprot);
293 FreeVecPooled(emulbase->mempool, filename);
294 return ret;
297 /*********************************************************************************************/
299 const ULONG sizes[] = {
301 offsetof(struct ExAllData,ed_Type),
302 offsetof(struct ExAllData,ed_Size),
303 offsetof(struct ExAllData,ed_Prot),
304 offsetof(struct ExAllData,ed_Days),
305 offsetof(struct ExAllData,ed_Comment),
306 offsetof(struct ExAllData,ed_OwnerUID),
307 sizeof(struct ExAllData)
310 static SIPTR examine(struct emulbase *emulbase, struct filehandle *fh,
311 struct FileInfoBlock *fib)
313 UBYTE buff[sizeof(struct ExAllData) +
314 sizeof(fib->fib_FileName) + 1 +
315 sizeof(fib->fib_Comment) + 1];
316 struct ExAllData *ead = (APTR)&buff[0];
317 SIPTR err;
319 err = DoExamineEntry(emulbase, fh, NULL, ead, sizeof(buff), ED_OWNER);
320 if (err)
321 return err;
323 memset(fib, 0, sizeof(*fib));
325 if (ead->ed_Name) {
326 fib->fib_FileName[0] = strlen(ead->ed_Name) + 1;
327 if (fib->fib_FileName[0] > sizeof(fib->fib_FileName)-1)
328 fib->fib_FileName[0] = sizeof(fib->fib_FileName)-1;
329 CopyMem(ead->ed_Name, &fib->fib_FileName[1], fib->fib_FileName[0]);
332 if (ead->ed_Comment) {
333 fib->fib_Comment[0] = strlen(ead->ed_Comment) + 1;
334 if (fib->fib_Comment[0] > sizeof(fib->fib_Comment)-1)
335 fib->fib_Comment[0] = sizeof(fib->fib_Comment)-1;
336 CopyMem(ead->ed_Comment, &fib->fib_Comment[1], fib->fib_Comment[0]);
339 fib->fib_DiskKey = 0;
340 fib->fib_DirEntryType = ead->ed_Type;
341 fib->fib_Protection = ead->ed_Prot;
342 fib->fib_EntryType = ead->ed_Type;
343 fib->fib_Size = ead->ed_Size;
344 fib->fib_NumBlocks = (ead->ed_Size + 512 - 1) / 512;
345 fib->fib_Date.ds_Days = ead->ed_Days;
346 fib->fib_Date.ds_Minute = ead->ed_Mins;
347 fib->fib_Date.ds_Tick = ead->ed_Ticks;
348 fib->fib_OwnerUID = ead->ed_OwnerUID;
349 fib->fib_OwnerGID = ead->ed_OwnerGID;
351 return 0;
354 /*********************************************************************************************/
356 /* Returns an allocated buffer, containing a pathname, stripped by the filename. */
357 char *pathname_from_name (struct emulbase *emulbase, char *name)
359 long len = strlen(name);
360 long i;
361 char *result = NULL;
363 /* look for the first '\' in the filename starting at the end */
364 i = startpos(name, len);
366 if (0 != i)
368 result = AllocVecPooled(emulbase->mempool, i + 1);
369 if (!result)
370 return NULL;
372 copyname(result, name, i);
373 result[i]=0x0;
375 return result;
378 /*********************************************************************************************/
380 static LONG create_hardlink(struct emulbase *emulbase, struct filehandle *handle, const char *name, struct filehandle *oldfile)
382 LONG error;
383 char *fn;
385 DLINK(bug("[emul] Creating hardlink %s to file %s\n", name, oldfile->hostname));
386 error = makefilename(emulbase, &fn, NULL, handle, name);
387 if (!error)
389 DLINK(bug("[emul] Host name of the link: %s\n", fn));
390 error = DoHardLink(emulbase, fn, oldfile->hostname);
391 FreeVecPooled(emulbase->mempool, fn);
394 return error;
397 /*********************************************************************************************/
399 static LONG create_softlink(struct emulbase * emulbase,
400 struct filehandle *handle, const char *name, const char *ref)
402 LONG error;
403 char *dest;
405 DLINK(bug("[emul] Creating softlink %s to file %s\n", name, ref));
406 DLINK(bug("[emul] Handle 0x%p, pathname %s\n", handle, handle->hostname));
407 error = makefilename(emulbase, &dest, NULL, handle, name);
408 if (!error)
410 char *src = AllocVecPooled(emulbase->mempool, strlen(ref)+1);
411 if (src)
413 strcpy(src, ref);
414 DLINK(bug("[emul] Link host name: %s\n", dest));
415 error = DoSymLink(emulbase, src, dest);
416 DLINK(bug("[emul] Error: %d\n", error));
418 FreeVecPooled(emulbase->mempool, src);
420 else
421 error = ERROR_NO_FREE_STORE;
423 FreeVecPooled(emulbase->mempool, dest);
426 return error;
429 /*********************************************************************************************/
431 static LONG rename_object(struct emulbase * emulbase, struct filehandle *fh,
432 const char *file, struct filehandle *fh2, const char *newname)
434 LONG ret = 0L;
436 char *filename = NULL , *newfilename = NULL;
438 /* FIXME: fh2 is unused! */
439 ret = makefilename(emulbase, &filename, NULL, fh, file);
440 if (!ret)
442 ret = makefilename(emulbase, &newfilename, NULL, fh, newname);
443 if (!ret)
445 ret = DoRename(emulbase, filename, newfilename);
446 FreeVecPooled(emulbase->mempool, newfilename);
448 FreeVecPooled(emulbase->mempool, filename);
451 return ret;
454 /*********************************************************************************************/
456 static LONG read_softlink(struct emulbase *emulbase, struct filehandle *fh, CONST_STRPTR link,
457 STRPTR buffer, SIPTR *size, struct DosLibrary *DOSBase)
459 char *ln;
460 LONG ret = 0;
461 char *filename = NULL;
462 long l = strlen(link) + 1;
464 DLINK(bug("read_softlink: link %s len %d\n", link, l));
466 /* don't mess with link itself */
467 ln = AllocVecPooled(emulbase->mempool, l);
469 if (!ln)
470 return ERROR_NO_FREE_STORE;
472 CopyMem(link, ln, l);
474 ret = makefilename(emulbase, &filename, NULL, fh, ln);
475 if (!ret)
477 int targetlen = DoReadLink(emulbase, filename, buffer, *size, &ret);
478 DLINK(bug("read_softlink: targetlen %d\n", targetlen));
480 FreeVecPooled(emulbase->mempool, filename);
482 if (targetlen < 0)
483 *size = targetlen;
484 else
486 buffer[targetlen] = '\0';
487 DLINK(bug("read_softlink: buffer after DoReadLink %s\n", buffer));
488 if (strchr(buffer, ':') == NULL)
490 STRPTR source = FilePart(ln);
492 /* strip file part of link */
493 *source = '\0';
494 if (strlen(ln) + targetlen >= *size)
496 DLINK(bug("read_softlink: buffer too small %d>=%u\n", strlen(ln) + targetlen, *size));
497 /* Buffer was too small */
498 *size = -2;
500 else
502 /* copy buffer to create resolved link path in it */
503 char* target = AllocVecPooled(emulbase->mempool, targetlen+1);
504 if (target)
506 strcpy(target, buffer);
507 if (shrink(target))
509 strcpy(buffer, ln);
510 strcat(buffer, target);
511 *size = strlen(buffer);
514 FreeVecPooled(emulbase->mempool, target);
516 else
517 ret = ERROR_NO_FREE_STORE;
520 else
522 *size = targetlen >= *size ? -2 : strlen(buffer);
527 DLINK(if (!ret) bug("read_softlink: buffer %s\n", buffer));
528 FreeVecPooled(emulbase->mempool, ln);
530 return ret;
533 /*********************************************************************************************/
535 static SIPTR parent_dir(struct emulbase *emulbase,
536 struct filehandle *fhv,
537 struct filehandle **fhp)
539 SIPTR err;
541 DCHDIR(bug("[emul] Original directory: \"%s\"\n", (*fhp)->name));
542 err = open_(emulbase, fhv, fhp, "/", MODE_OLDFILE, 0, TRUE);
543 DCHDIR(bug("[emul] Parent directory: \"%s\"\n", err ? NULL : (*fhp)->name));
545 return err;
548 /*********************************************************************************************/
550 static LONG set_date(struct emulbase *emulbase, struct filehandle *fh,
551 const char *FileName, struct DateStamp *date)
553 char *fullname;
554 LONG ret;
556 ret = makefilename(emulbase, &fullname, NULL, fh, FileName);
557 if (!ret)
559 ret = DoSetDate(emulbase, fullname, date);
561 FreeVecPooled(emulbase->mempool, fullname);
563 return ret;
566 static LONG disk_info(struct emulbase *emulbase, struct filehandle *fh, struct InfoData *id)
568 LONG Res2 = DoStatFS(emulbase, fh->hostname, id);
570 if (!Res2)
572 /* Fill in host-independent part */
573 id->id_UnitNumber = 0;
574 id->id_DiskType = ID_DOS_DISK; /* Well, not really true... */
575 id->id_VolumeNode = MKBADDR(fh->dl);
576 id->id_InUse = TRUE; /* Perhaps we should count locks? */
579 return Res2;
582 /*********************************************************************************************/
584 #define VOLNAME "System"
585 #define VOLNAME_LEN 6
587 static struct filehandle *new_volume(struct emulbase *emulbase, const char *path, struct MsgPort *mp, struct DosLibrary *DOSBase)
589 struct filehandle *fhv;
590 struct DosList *doslist;
591 char *unixpath;
592 const char *vol;
593 int vol_len = 0;
594 char *sp;
597 * MakeDosNode() creates zero-length fssm_Device instead of BNULL pointer when ParamPkt[1] is zero.
598 * CHECKME: is this correct, or MakeDosNode() needs to be fixed?
600 if (path && path[0])
602 DMOUNT(bug("[emul] Mounting volume %s\n", path));
605 * Volume name and Unix path are encoded into DEVICE entry of
606 * MountList like this: <volumename>:<unixpath>
608 vol = path;
611 if (*path == 0)
612 return NULL;
614 vol_len++;
615 } while (*path++ != ':');
616 DMOUNT(bug("[emul] Host path: %s, volume name length %u\n", path, vol_len));
618 sp = strchr(path, '~');
619 if (sp)
621 unixpath = GetHomeDir(emulbase, sp + 1);
622 if (!unixpath)
623 return NULL;
624 } else {
625 unixpath = AllocVecPooled(emulbase->mempool, strlen(path)+1);
626 if (!unixpath)
627 return NULL;
629 CopyMem(path, unixpath, strlen(path)+1);
632 else
634 ULONG res;
636 DMOUNT(bug("[emul] Mounting root volume\n"));
638 unixpath = AllocVecPooled(emulbase->mempool, PATH_MAX);
639 if (!unixpath)
640 return NULL;
642 res = GetCurrentDir(emulbase, unixpath, PATH_MAX);
643 DMOUNT(bug("[emul] GetCurrentDir() returned %d\n", res));
644 if(!res)
646 FreeVec(unixpath);
648 return NULL;
650 D(bug("[emul] startup directory %s\n", unixpath));
652 vol = VOLNAME;
653 vol_len = VOLNAME_LEN + 1;
656 DMOUNT(bug("[emul] Resolved host path: %s\n", unixpath));
658 if (CheckDir(emulbase, unixpath))
660 FreeVecPooled(emulbase->mempool, unixpath);
661 return NULL;
664 fhv = AllocMem(sizeof(struct filehandle) + vol_len, MEMF_PUBLIC|MEMF_CLEAR);
665 DMOUNT(bug("[emul] Volume file handle: 0x%p\n", fhv));
666 if (fhv)
668 char *volname = (char *)fhv + sizeof(struct filehandle);
670 CopyMem(vol, volname, vol_len - 1);
671 volname[vol_len - 1] = 0;
673 fhv->hostname = unixpath;
674 fhv->name = unixpath + strlen(unixpath);
675 fhv->type = FHD_DIRECTORY;
676 fhv->volumename = volname;
677 if (!DoOpen(emulbase, fhv, MODE_OLDFILE, 0, TRUE)) {
678 DMOUNT(bug("[emul] Making volume node %s\n", volname));
680 doslist = MakeDosEntry(volname, DLT_VOLUME);
681 DMOUNT(bug("[emul] Volume node 0x%p\n", doslist));
682 if (doslist)
684 fhv->dl = doslist;
685 doslist->dol_Task = mp;
686 AddDosEntry(doslist);
688 SendEvent(emulbase, IECLASS_DISKINSERTED);
690 DMOUNT(bug("[emul] Mounting done\n"));
691 return fhv;
693 DMOUNT(bug("[emul] DOS Volume add failed, freeing volume node\n"));
696 DMOUNT(bug("[emul] Failed, freeing volume node\n"));
697 FreeVecPooled(emulbase->mempool, unixpath);
698 FreeMem(fhv, sizeof(struct filehandle) + vol_len);
701 DMOUNT(bug("[emul] Mounting failed\n"));
702 return NULL;
705 #define FH_FROM(x) ((struct filehandle *)(x))
706 #define FH_FROM_LOCK(x) \
707 ({ BPTR _x = (BPTR)x; \
708 APTR _fh; \
709 if (_x == BNULL) { \
710 _fh = fhv; \
711 } else { \
712 _fh = (APTR)(((struct FileLock *)BADDR(_x))->fl_Key); \
714 (struct filehandle *)_fh;\
717 static void handlePacket(struct emulbase *emulbase, struct filehandle *fhv, struct MsgPort *mp, struct DosPacket *dp, struct DosLibrary *DOSBase)
719 SIPTR Res1 = DOSFALSE;
720 SIPTR Res2 = ERROR_UNKNOWN;
721 struct filehandle *fh, *fh2;
722 struct FileHandle *f;
723 struct FileLock *fl, *fl2;
724 struct InfoData *id;
726 DB2(bug("[emul] Got command %u\n", dp->dp_Type));
728 switch(dp->dp_Type)
730 case ACTION_FINDINPUT:
731 case ACTION_FINDOUTPUT:
732 case ACTION_FINDUPDATE:
733 f = BADDR(dp->dp_Arg1);
734 fh2 = FH_FROM_LOCK(dp->dp_Arg2);
736 DCMD(bug("[emul] %p ACTION_FIND%s: %p, %p, %b\n", fhv, (dp->dp_Type == ACTION_FINDINPUT) ? "INPUT" : ((dp->dp_Type == ACTION_FINDOUTPUT) ? "OUTPUT" : "UPDATE"), fh, fh2, dp->dp_Arg3));
737 Res2 = open_(emulbase, fhv, &fh2, AROS_BSTR_ADDR(dp->dp_Arg3), dp->dp_Type, 0, FALSE);
739 if (Res2 == 0)
741 memset(f, 0, sizeof(*f));
742 f->fh_Type = mp;
743 f->fh_Arg1 = (SIPTR)fh2;
744 if (fh2 != fhv)
745 fh2->locks++;
746 Res1 = DOSTRUE;
748 else
749 Res1 = DOSFALSE;
751 break;
753 case ACTION_END:
754 fh = FH_FROM(dp->dp_Arg1);
755 DCMD(bug("[emul] %p ACTION_END\n", fhv, fh));
756 if (fh != fhv) {
757 fh->locks--;
758 if (!fh->locks)
759 free_lock(emulbase, fh);
761 Res2 = 0;
762 Res1 = DOSTRUE;
763 break;
765 case ACTION_READ:
766 fh = FH_FROM(dp->dp_Arg1);
767 DCMD(bug("[emul] %p ACTION_READ\n", fhv, fh));
769 if (fh->type & FHD_FILE)
771 Res1 = DoRead(emulbase, fh, (APTR)dp->dp_Arg2, dp->dp_Arg3, &Res2);
773 else {
774 Res1 = -1;
775 Res2 = ERROR_OBJECT_WRONG_TYPE;
777 break;
779 case ACTION_WRITE:
780 fh = FH_FROM(dp->dp_Arg1);
781 DCMD(bug("[emul] %p ACTION_WRITE\n", fhv, fh));
783 if (fh->type & FHD_FILE)
785 Res1 = DoWrite(emulbase, fh, (APTR)dp->dp_Arg2, dp->dp_Arg3, &Res2);
786 } else {
787 Res1 = -1;
788 Res2 = ERROR_OBJECT_WRONG_TYPE;
790 break;
792 case ACTION_SEEK:
793 fh = FH_FROM(dp->dp_Arg1);
794 DCMD(bug("[emul] %p ACTION_SEEK %p, mode %ld, offset %lu\n", fhv, fh, dp->dp_Arg3, dp->dp_Arg2));
796 if (fh->type == FHD_FILE)
797 Res1 = DoSeek(emulbase, fh, dp->dp_Arg2, dp->dp_Arg3, &Res2);
798 else {
799 Res1 = DOSFALSE;
800 Res2 = ERROR_OBJECT_WRONG_TYPE;
803 break;
805 case ACTION_SET_FILE_SIZE:
806 fh = FH_FROM(dp->dp_Arg1);
807 DCMD(bug("[emul] %p ACTION_SET_FILE_SIZE: %p, mode %ld, offset %llu\n", fhv, fh, dp->dp_Arg2, dp->dp_Arg3));
809 Res1 = DoSetSize(emulbase, fh, dp->dp_Arg2, dp->dp_Arg3, &Res2);
810 if (Res2 != 0) {
811 Res1 = -1;
813 break;
815 case ACTION_SAME_LOCK:
816 fh = FH_FROM_LOCK(dp->dp_Arg1);
817 fh2 = FH_FROM_LOCK(dp->dp_Arg2);
819 DCMD(bug("[emul] %p ACTION_SAME_LOCK: %p, %p\n", fhv, fh, fh2));
820 DSAME(bug("[emul] Paths: %s, %s\n", fh->hostname, fh2->hostname));
822 Res2 = 0;
823 /* DOSTRUE means 'Same', DOSFALSE means 'Different' */
824 Res1 = strcasecmp(fh->hostname, fh2->hostname) ? DOSFALSE : DOSTRUE;
826 DSAME(bug("[emul] Replying with 0x%p, %ld\n", Res1, Res2));
827 break;
829 case ACTION_EXAMINE_FH:
830 fh = FH_FROM(dp->dp_Arg1);
831 DCMD(bug("[emul] %p ACTION_EXAMINE_FH: %p, fib %p\n", fhv, fh, BADDR(dp->dp_Arg2)));
832 Res2 = examine(emulbase, fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
833 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
834 break;
836 case ACTION_EXAMINE_OBJECT:
837 fh = FH_FROM_LOCK(dp->dp_Arg1);
838 DCMD(bug("[emul] %p ACTION_EXAMINE_OBJECT: %p, fib %p\n", fhv, fh, BADDR(dp->dp_Arg2)));
839 Res2 = examine(emulbase, fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
840 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
841 break;
843 case ACTION_EXAMINE_NEXT:
844 fh = FH_FROM_LOCK(dp->dp_Arg1);
845 DCMD(bug("[emul] %p ACTION_EXAMINE_NEXT: %p, fib %p (key %d)\n", fhv, fh, BADDR(dp->dp_Arg2), ((struct FileInfoBlock *)BADDR(dp->dp_Arg2))->fib_DiskKey));
846 Res2 = DoExamineNext(emulbase, (struct filehandle *)fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
847 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
848 break;
850 case ACTION_EXAMINE_ALL:
851 fh = FH_FROM_LOCK(dp->dp_Arg1);
852 DCMD(bug("[emul] %p ACTION_EXAMINE_ALL: %p\n", fhv, fh));
853 Res2 = DoExamineAll(emulbase, fh, (APTR)dp->dp_Arg2, BADDR(dp->dp_Arg5),
854 dp->dp_Arg3, dp->dp_Arg4, DOSBase);
855 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
856 break;
858 case ACTION_EXAMINE_ALL_END:
859 /* Just rewind */
860 fh = FH_FROM_LOCK(dp->dp_Arg1);
861 DCMD(bug("[emul] %p ACTION_EXAMINE_ALL_END: %p\n", fhv, fh));
862 Res2 = DoRewindDir(emulbase, (struct filehandle *)fh);
863 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
864 break;
866 case ACTION_CREATE_DIR:
867 fh = FH_FROM_LOCK(dp->dp_Arg1);
868 DCMD(bug("[emul] %p ACTION_CREATE_DIR: %p, %b\n", fhv, fh, dp->dp_Arg2));
870 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
871 if (!fl) {
872 Res2 = ERROR_NO_FREE_STORE;
873 Res1 = DOSFALSE;
874 break;
877 Res2 = create_dir(emulbase, &fh, AROS_BSTR_ADDR(dp->dp_Arg2),
878 FIBF_GRP_EXECUTE | FIBF_GRP_READ |
879 FIBF_OTR_EXECUTE | FIBF_OTR_READ);
880 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
881 if (Res1 != DOSTRUE) {
882 FreeMem(fl, sizeof(*fl));
883 break;
886 /* Make a lock */
887 fl->fl_Link = BNULL;
888 fl->fl_Key = (IPTR)fh;
889 fl->fl_Access = ACCESS_READ;
890 fl->fl_Task = mp;
891 fl->fl_Volume = MKBADDR(fh->dl);
892 if (fh != fhv)
893 fh->locks++;
894 Res2 = 0;
895 Res1 = (SIPTR)fl;
896 break;
897 case ACTION_LOCATE_OBJECT:
898 fh = FH_FROM_LOCK(dp->dp_Arg1);
899 DCMD(bug("[emul] %p ACTION_LOCATE_OBJECT: %p, %b\n", fhv, fh, dp->dp_Arg2));
901 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
902 if (!fl) {
903 Res2 = ERROR_NO_FREE_STORE;
904 Res1 = DOSFALSE;
905 break;
908 Res2 = open_(emulbase, fhv, &fh, AROS_BSTR_ADDR(dp->dp_Arg2), (dp->dp_Arg3 == ACCESS_READ) ? MODE_OLDFILE : MODE_NEWFILE, 0755, TRUE);
909 if (Res2) {
910 Res1 = DOSFALSE;
911 FreeMem(fl, sizeof(*fl));
912 break;
915 /* Make a lock */
916 fl->fl_Link = BNULL;
917 fl->fl_Key = (IPTR)fh;
918 fl->fl_Access = dp->dp_Arg3;
919 fl->fl_Task = mp;
920 fl->fl_Volume = MKBADDR(fh->dl);
921 if (fh != fhv)
922 fh->locks++;
923 Res2 = 0;
924 Res1 = (SIPTR)fl;
925 break;
927 case ACTION_FH_FROM_LOCK:
928 f = BADDR(dp->dp_Arg1);
929 fh2 = FH_FROM_LOCK(dp->dp_Arg2);
930 fl = BADDR(dp->dp_Arg2);
931 DCMD(bug("[emul] %p ACTION_FH_FROM_LOCK: %p, lock %p\n", fhv, fh, fh2));
933 f->fh_Type = mp;
934 f->fh_Arg1 = (SIPTR)fh2;
936 if (fl)
937 FreeMem(fl, sizeof(*fl));
939 Res2 = 0;
940 Res1 = DOSTRUE;
941 break;
943 case ACTION_COPY_DIR: /* DupLock */
944 fh = FH_FROM_LOCK(dp->dp_Arg1);
945 fl = BADDR(dp->dp_Arg1);
946 DCMD(bug("[emul] %p ACTION_COPY_DIR: %p\n", fhv, fh));
948 fl2 = AllocMem(sizeof(*fl2), MEMF_ANY | MEMF_CLEAR);
949 if (!fl2) {
950 Res2 = ERROR_NO_FREE_STORE;
951 Res1 = DOSFALSE;
952 break;
955 CopyMem(fl, fl2, sizeof(*fl2));
956 if (fh != fhv)
957 fh->locks++;
959 Res2 = 0;
960 Res1 = (SIPTR)MKBADDR(fl2);
961 break;
963 case ACTION_COPY_DIR_FH: /* Dup */
964 fh = FH_FROM(dp->dp_Arg1);
965 DCMD(bug("[emul] %p ACTION_COPY_DIR_FH: %p\n", fhv, fh));
967 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
968 if (!fl) {
969 Res2 = ERROR_NO_FREE_STORE;
970 Res1 = DOSFALSE;
971 break;
974 /* Make a lock */
975 fl->fl_Link = BNULL;
976 fl->fl_Key = (IPTR)fh;
977 fl->fl_Access = ACCESS_READ;
978 fl->fl_Task = mp;
979 fl->fl_Volume = MKBADDR(fh->dl);
980 if (fh != fhv)
981 fh->locks++;
983 Res2 = 0;
984 Res1 = (SIPTR)MKBADDR(fl);
985 break;
987 case ACTION_FREE_LOCK:
988 fh = FH_FROM_LOCK(dp->dp_Arg1);
989 fl = BADDR(dp->dp_Arg1);
990 DCMD(bug("[emul] %p ACTION_FREE_LOCK: %p\n", fhv, fh));
992 /* Don't free the volume's filehandle */
993 if (fh == fhv) {
994 Res2 = 0;
995 Res1 = DOSTRUE;
996 break;
999 FreeMem(fl, sizeof(*fl));
1000 if (fh != fhv) {
1001 fh->locks--;
1002 if (!fh->locks)
1003 free_lock(emulbase, fh);
1006 Res2 = 0;
1007 Res1 = DOSTRUE;
1008 break;
1010 case ACTION_MAKE_LINK:
1011 fh = FH_FROM_LOCK(dp->dp_Arg1);
1013 Res2 = ERROR_UNKNOWN;
1014 if (dp->dp_Arg4 == LINK_SOFT) {
1015 DCMD(bug("[emul] %p ACTION_MAKE_LINK: %p, dest \"%b\", src \"%b\"\n", fhv, fh, dp->dp_Arg2, dp->dp_Arg3));
1016 Res2 = create_softlink(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), AROS_BSTR_ADDR(dp->dp_Arg3));
1017 } else if (dp->dp_Arg4 == LINK_HARD) {
1018 fh2 = FH_FROM_LOCK(dp->dp_Arg3);
1019 DCMD(bug("[emul] %p ACTION_MAKE_LINK: %p, dest \"%b\", src %p\n", fhv, fh, dp->dp_Arg2, fh2));
1020 Res2 = create_hardlink(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), fh2);
1023 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1024 break;
1026 case ACTION_RENAME_OBJECT:
1027 fh = FH_FROM_LOCK(dp->dp_Arg1);
1028 fh2 = FH_FROM_LOCK(dp->dp_Arg3);
1029 DCMD(bug("[emul] %p ACTION_RENAME_OBJECT: %p, \"%b\" => %p, \"%b\"\n", fhv, fh, dp->dp_Arg2, fh2, dp->dp_Arg4));
1030 Res2 = rename_object(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), fh2, AROS_BSTR_ADDR(dp->dp_Arg4));
1032 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1033 break;
1035 case ACTION_READ_LINK:
1036 fh = FH_FROM_LOCK(dp->dp_Arg1);
1037 DCMD(bug("[emul] %p ACTION_READ_LINK: %p\n", fhv, fh));
1038 Res1 = dp->dp_Arg4;
1039 Res2 = read_softlink(emulbase, fh, (APTR)dp->dp_Arg2, (APTR)dp->dp_Arg3, &Res1, DOSBase);
1040 break;
1042 case ACTION_DELETE_OBJECT:
1043 fh = FH_FROM_LOCK(dp->dp_Arg1);
1044 DCMD(bug("[emul] %p ACTION_DELETE_OBJECT: %p\n", fhv, fh));
1045 Res2 = delete_object(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2));
1046 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1047 break;
1049 case ACTION_SET_PROTECT:
1050 /* dp_Arg1 is unused */
1051 fh = FH_FROM_LOCK(dp->dp_Arg2);
1052 DCMD(bug("[emul] %p ACTION_SET_PROTECT: %p\n", fhv, fh));
1053 Res2 = set_protect(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg3), dp->dp_Arg4);
1054 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1055 break;
1057 case ACTION_PARENT:
1058 fh = FH_FROM_LOCK(dp->dp_Arg1);
1059 DCMD(bug("[emul] %p ACTION_PARENT: %p\n", fhv, fh));
1061 if (fh == fhv) {
1062 Res1 = 0;
1063 Res2 = 0;
1064 break;
1067 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
1068 if (!fl) {
1069 Res2 = ERROR_NO_FREE_STORE;
1070 Res1 = DOSFALSE;
1071 break;
1074 Res2 = parent_dir(emulbase, fhv, &fh);
1075 if (Res2) {
1076 FreeMem(fl, sizeof(*fl));
1077 Res1 = DOSFALSE;
1078 break;
1081 /* Make a lock */
1082 fl->fl_Link = BNULL;
1083 fl->fl_Key = (IPTR)fh;
1084 fl->fl_Access = ACCESS_READ;
1085 fl->fl_Task = mp;
1086 fl->fl_Volume = MKBADDR(fh->dl);
1087 if (fh != fhv)
1088 fh->locks++;
1090 Res1 = (SIPTR)MKBADDR(fl);
1091 Res2 = 0;
1092 break;
1094 case ACTION_PARENT_FH:
1095 fh = FH_FROM(dp->dp_Arg1);
1096 DCMD(bug("[emul] %p ACTION_PARENT_FH: %p\n", fhv, fh));
1098 if (fh == fhv) {
1099 Res1 = 0;
1100 Res2 = 0;
1101 break;
1104 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
1105 if (!fl) {
1106 Res2 = ERROR_NO_FREE_STORE;
1107 Res1 = DOSFALSE;
1108 break;
1111 Res2 = parent_dir(emulbase, fhv, &fh);
1112 if (Res2) {
1113 FreeMem(fl, sizeof(*fl));
1114 Res1 = DOSFALSE;
1115 break;
1118 /* Make a lock */
1119 fl->fl_Link = BNULL;
1120 fl->fl_Key = (IPTR)fh;
1121 fl->fl_Access = ACCESS_READ;
1122 fl->fl_Task = mp;
1123 fl->fl_Volume = MKBADDR(fh->dl);
1124 if (fh != fhv)
1125 fh->locks++;
1127 Res1 = (SIPTR)MKBADDR(fl);
1128 Res2 = 0;
1129 break;
1130 case ACTION_IS_FILESYSTEM:
1131 DCMD(bug("[emul] %p ACTION_IS_FILESYSTEM:\n", fhv));
1132 Res2 = 0;
1133 Res1 = DOSTRUE;
1134 break;
1136 case ACTION_INFO:
1137 fh = FH_FROM_LOCK(dp->dp_Arg1);
1138 id = BADDR(dp->dp_Arg2);
1139 DCMD(bug("[emul] %p ACTION_INFO:\n", fhv));
1141 Res2 = disk_info(emulbase, fh, id);
1142 Res1 = Res2 ? DOSFALSE : DOSTRUE;
1143 break;
1145 case ACTION_DISK_INFO:
1146 id = (struct InfoData *)BADDR(dp->dp_Arg1);
1147 DCMD(bug("[emul] %p ACTION_DISK_INFO:\n", fhv));
1149 Res2 = disk_info(emulbase, fhv, id);
1150 Res1 = Res2 ? DOSFALSE : DOSTRUE;
1151 break;
1153 case ACTION_SET_DATE:
1154 /* dp_Arg1 is unused */
1155 fh = FH_FROM_LOCK(dp->dp_Arg2);
1156 DCMD(bug("[emul] %p ACTION_SET_DATE: %p\n", fhv, fh));
1157 Res2 = set_date(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg3), (struct DateStamp *)dp->dp_Arg4);
1158 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1159 break;
1161 case ACTION_SET_OWNER:
1162 /* pretend to have changed owner, avoids tons of error messages from e.g. tar */
1163 Res1 = DOSTRUE;
1164 break;
1166 /* FIXME: not supported yet
1167 case ACTION_SET_COMMENT:
1168 case ACTION_MORE_CACHE:
1169 case ACTION_WAIT_CHAR:
1171 default:
1172 DCMD(bug("[emul] Unknown action %lu\n", dp->dp_Type));
1173 Res2 = ERROR_ACTION_NOT_KNOWN;
1174 Res1 = DOSFALSE;
1175 break;
1178 /* Set error code */
1179 DCMD(bug("[emul] Replying with 0x%p, %ld\n", Res1, Res2));
1181 ReplyPkt(dp, Res1, Res2);
1184 static void EmulHandler_work(struct ExecBase *SysBase)
1186 struct DosLibrary *DOSBase;
1187 struct DosPacket *dp;
1188 struct DeviceNode *dn;
1189 struct FileSysStartupMsg *fssm;
1190 STRPTR devpath = NULL;
1191 struct MsgPort *mp;
1192 struct filehandle *fhv;
1193 struct emulbase *emulbase;
1195 DOSBase = (APTR)OpenLibrary("dos.library", 0);
1196 if (!DOSBase)
1197 return;
1199 mp = &((struct Process *)FindTask(NULL))->pr_MsgPort;
1201 /* Wait for startup message. */
1202 D(bug("EMUL: Waiting for startup...\n"));
1203 WaitPort(mp);
1204 dp = (struct DosPacket *)(GetMsg(mp)->mn_Node.ln_Name);
1206 D(bug("EMUL: Open resource\n"));
1207 emulbase = OpenResource("emul-handler");
1208 if (!emulbase)
1210 D(bug("EMUL: FATAL - can't find myself\n"));
1211 ReplyPkt(dp, DOSFALSE, ERROR_INVALID_RESIDENT_LIBRARY);
1212 return;
1215 fssm = BADDR(dp->dp_Arg2);
1216 if (fssm)
1217 devpath = AROS_BSTR_ADDR(fssm->fssm_Device);
1219 fhv = new_volume(emulbase, devpath, mp, DOSBase);
1220 if (!fhv)
1222 D(bug("EMUL: FATAL - can't create the inital volume \"%s\"\n", devpath));
1223 ReplyPkt(dp, DOSFALSE, ERROR_NO_FREE_STORE);
1224 return;
1227 /* Now, once we know all is well with the world,
1228 * we tell DOS that we're the handler for this
1229 * DeviceNode
1231 dn = BADDR(dp->dp_Arg3);
1232 dn->dn_Task = mp;
1234 ReplyPkt(dp, DOSTRUE, 0);
1236 fhv->locks = 1;
1237 while (fhv->locks)
1239 dp = WaitPkt();
1240 handlePacket(emulbase, fhv, mp, dp, DOSBase);
1243 D(bug("EMUL: Closing volume %s\n", fhv->volumename));
1244 RemDosEntry(fhv->dl);
1245 free_lock(emulbase, fhv);
1246 CloseLibrary((APTR)DOSBase);
1249 AROS_PROCH(EmulHandlerMain, argptr, argstr, SysBase)
1251 AROS_PROCFUNC_INIT
1253 EmulHandler_work(SysBase);
1255 return RETURN_OK;
1257 AROS_PROCFUNC_EXIT