emul-handler: fh_Arg1 should be the only element of struct FileHandle touched during...
[AROS.git] / arch / all-hosted / filesys / emul_handler / emul_handler.c
blobc8d9898f8fe568952f977fb5f1fdbc8d521d8d6f
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 f->fh_Arg1 = (SIPTR)fh2;
742 if (fh2 != fhv)
743 fh2->locks++;
744 Res1 = DOSTRUE;
746 else
747 Res1 = DOSFALSE;
749 break;
751 case ACTION_END:
752 fh = FH_FROM(dp->dp_Arg1);
753 DCMD(bug("[emul] %p ACTION_END\n", fhv, fh));
754 if (fh != fhv) {
755 fh->locks--;
756 if (!fh->locks)
757 free_lock(emulbase, fh);
759 Res2 = 0;
760 Res1 = DOSTRUE;
761 break;
763 case ACTION_READ:
764 fh = FH_FROM(dp->dp_Arg1);
765 DCMD(bug("[emul] %p ACTION_READ\n", fhv, fh));
767 if (fh->type & FHD_FILE)
769 Res1 = DoRead(emulbase, fh, (APTR)dp->dp_Arg2, dp->dp_Arg3, &Res2);
771 else {
772 Res1 = -1;
773 Res2 = ERROR_OBJECT_WRONG_TYPE;
775 break;
777 case ACTION_WRITE:
778 fh = FH_FROM(dp->dp_Arg1);
779 DCMD(bug("[emul] %p ACTION_WRITE\n", fhv, fh));
781 if (fh->type & FHD_FILE)
783 Res1 = DoWrite(emulbase, fh, (APTR)dp->dp_Arg2, dp->dp_Arg3, &Res2);
784 } else {
785 Res1 = -1;
786 Res2 = ERROR_OBJECT_WRONG_TYPE;
788 break;
790 case ACTION_SEEK:
791 fh = FH_FROM(dp->dp_Arg1);
792 DCMD(bug("[emul] %p ACTION_SEEK %p, mode %ld, offset %lu\n", fhv, fh, dp->dp_Arg3, dp->dp_Arg2));
794 if (fh->type == FHD_FILE)
795 Res1 = DoSeek(emulbase, fh, dp->dp_Arg2, dp->dp_Arg3, &Res2);
796 else {
797 Res1 = DOSFALSE;
798 Res2 = ERROR_OBJECT_WRONG_TYPE;
801 break;
803 case ACTION_SET_FILE_SIZE:
804 fh = FH_FROM(dp->dp_Arg1);
805 DCMD(bug("[emul] %p ACTION_SET_FILE_SIZE: %p, mode %ld, offset %llu\n", fhv, fh, dp->dp_Arg2, dp->dp_Arg3));
807 Res1 = DoSetSize(emulbase, fh, dp->dp_Arg2, dp->dp_Arg3, &Res2);
808 if (Res2 != 0) {
809 Res1 = -1;
811 break;
813 case ACTION_SAME_LOCK:
814 fh = FH_FROM_LOCK(dp->dp_Arg1);
815 fh2 = FH_FROM_LOCK(dp->dp_Arg2);
817 DCMD(bug("[emul] %p ACTION_SAME_LOCK: %p, %p\n", fhv, fh, fh2));
818 DSAME(bug("[emul] Paths: %s, %s\n", fh->hostname, fh2->hostname));
820 Res2 = 0;
821 /* DOSTRUE means 'Same', DOSFALSE means 'Different' */
822 Res1 = strcasecmp(fh->hostname, fh2->hostname) ? DOSFALSE : DOSTRUE;
824 DSAME(bug("[emul] Replying with 0x%p, %ld\n", Res1, Res2));
825 break;
827 case ACTION_EXAMINE_FH:
828 fh = FH_FROM(dp->dp_Arg1);
829 DCMD(bug("[emul] %p ACTION_EXAMINE_FH: %p, fib %p\n", fhv, fh, BADDR(dp->dp_Arg2)));
830 Res2 = examine(emulbase, fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
831 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
832 break;
834 case ACTION_EXAMINE_OBJECT:
835 fh = FH_FROM_LOCK(dp->dp_Arg1);
836 DCMD(bug("[emul] %p ACTION_EXAMINE_OBJECT: %p, fib %p\n", fhv, fh, BADDR(dp->dp_Arg2)));
837 Res2 = examine(emulbase, fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
838 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
839 break;
841 case ACTION_EXAMINE_NEXT:
842 fh = FH_FROM_LOCK(dp->dp_Arg1);
843 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));
844 Res2 = DoExamineNext(emulbase, (struct filehandle *)fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
845 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
846 break;
848 case ACTION_EXAMINE_ALL:
849 fh = FH_FROM_LOCK(dp->dp_Arg1);
850 DCMD(bug("[emul] %p ACTION_EXAMINE_ALL: %p\n", fhv, fh));
851 Res2 = DoExamineAll(emulbase, fh, (APTR)dp->dp_Arg2, BADDR(dp->dp_Arg5),
852 dp->dp_Arg3, dp->dp_Arg4, DOSBase);
853 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
854 break;
856 case ACTION_EXAMINE_ALL_END:
857 /* Just rewind */
858 fh = FH_FROM_LOCK(dp->dp_Arg1);
859 DCMD(bug("[emul] %p ACTION_EXAMINE_ALL_END: %p\n", fhv, fh));
860 Res2 = DoRewindDir(emulbase, (struct filehandle *)fh);
861 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
862 break;
864 case ACTION_CREATE_DIR:
865 fh = FH_FROM_LOCK(dp->dp_Arg1);
866 DCMD(bug("[emul] %p ACTION_CREATE_DIR: %p, %b\n", fhv, fh, dp->dp_Arg2));
868 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
869 if (!fl) {
870 Res2 = ERROR_NO_FREE_STORE;
871 Res1 = DOSFALSE;
872 break;
875 Res2 = create_dir(emulbase, &fh, AROS_BSTR_ADDR(dp->dp_Arg2),
876 FIBF_GRP_EXECUTE | FIBF_GRP_READ |
877 FIBF_OTR_EXECUTE | FIBF_OTR_READ);
878 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
879 if (Res1 != DOSTRUE) {
880 FreeMem(fl, sizeof(*fl));
881 break;
884 /* Make a lock */
885 fl->fl_Link = BNULL;
886 fl->fl_Key = (IPTR)fh;
887 fl->fl_Access = ACCESS_READ;
888 fl->fl_Task = mp;
889 fl->fl_Volume = MKBADDR(fh->dl);
890 if (fh != fhv)
891 fh->locks++;
892 Res2 = 0;
893 Res1 = (SIPTR)fl;
894 break;
895 case ACTION_LOCATE_OBJECT:
896 fh = FH_FROM_LOCK(dp->dp_Arg1);
897 DCMD(bug("[emul] %p ACTION_LOCATE_OBJECT: %p, %b\n", fhv, fh, dp->dp_Arg2));
899 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
900 if (!fl) {
901 Res2 = ERROR_NO_FREE_STORE;
902 Res1 = DOSFALSE;
903 break;
906 Res2 = open_(emulbase, fhv, &fh, AROS_BSTR_ADDR(dp->dp_Arg2), (dp->dp_Arg3 == ACCESS_READ) ? MODE_OLDFILE : MODE_NEWFILE, 0755, TRUE);
907 if (Res2) {
908 Res1 = DOSFALSE;
909 FreeMem(fl, sizeof(*fl));
910 break;
913 /* Make a lock */
914 fl->fl_Link = BNULL;
915 fl->fl_Key = (IPTR)fh;
916 fl->fl_Access = dp->dp_Arg3;
917 fl->fl_Task = mp;
918 fl->fl_Volume = MKBADDR(fh->dl);
919 if (fh != fhv)
920 fh->locks++;
921 Res2 = 0;
922 Res1 = (SIPTR)fl;
923 break;
925 case ACTION_FH_FROM_LOCK:
926 f = BADDR(dp->dp_Arg1);
927 fh2 = FH_FROM_LOCK(dp->dp_Arg2);
928 fl = BADDR(dp->dp_Arg2);
929 DCMD(bug("[emul] %p ACTION_FH_FROM_LOCK: %p, lock %p\n", fhv, fh, fh2));
931 f->fh_Arg1 = (SIPTR)fh2;
933 if (fl)
934 FreeMem(fl, sizeof(*fl));
936 Res2 = 0;
937 Res1 = DOSTRUE;
938 break;
940 case ACTION_COPY_DIR: /* DupLock */
941 fh = FH_FROM_LOCK(dp->dp_Arg1);
942 fl = BADDR(dp->dp_Arg1);
943 DCMD(bug("[emul] %p ACTION_COPY_DIR: %p\n", fhv, fh));
945 fl2 = AllocMem(sizeof(*fl2), MEMF_ANY | MEMF_CLEAR);
946 if (!fl2) {
947 Res2 = ERROR_NO_FREE_STORE;
948 Res1 = DOSFALSE;
949 break;
952 CopyMem(fl, fl2, sizeof(*fl2));
953 if (fh != fhv)
954 fh->locks++;
956 Res2 = 0;
957 Res1 = (SIPTR)MKBADDR(fl2);
958 break;
960 case ACTION_COPY_DIR_FH: /* Dup */
961 fh = FH_FROM(dp->dp_Arg1);
962 DCMD(bug("[emul] %p ACTION_COPY_DIR_FH: %p\n", fhv, fh));
964 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
965 if (!fl) {
966 Res2 = ERROR_NO_FREE_STORE;
967 Res1 = DOSFALSE;
968 break;
971 /* Make a lock */
972 fl->fl_Link = BNULL;
973 fl->fl_Key = (IPTR)fh;
974 fl->fl_Access = ACCESS_READ;
975 fl->fl_Task = mp;
976 fl->fl_Volume = MKBADDR(fh->dl);
977 if (fh != fhv)
978 fh->locks++;
980 Res2 = 0;
981 Res1 = (SIPTR)MKBADDR(fl);
982 break;
984 case ACTION_FREE_LOCK:
985 fh = FH_FROM_LOCK(dp->dp_Arg1);
986 fl = BADDR(dp->dp_Arg1);
987 DCMD(bug("[emul] %p ACTION_FREE_LOCK: %p\n", fhv, fh));
989 /* Don't free the volume's filehandle */
990 if (fh == fhv) {
991 Res2 = 0;
992 Res1 = DOSTRUE;
993 break;
996 FreeMem(fl, sizeof(*fl));
997 if (fh != fhv) {
998 fh->locks--;
999 if (!fh->locks)
1000 free_lock(emulbase, fh);
1003 Res2 = 0;
1004 Res1 = DOSTRUE;
1005 break;
1007 case ACTION_MAKE_LINK:
1008 fh = FH_FROM_LOCK(dp->dp_Arg1);
1010 Res2 = ERROR_UNKNOWN;
1011 if (dp->dp_Arg4 == LINK_SOFT) {
1012 DCMD(bug("[emul] %p ACTION_MAKE_LINK: %p, dest \"%b\", src \"%b\"\n", fhv, fh, dp->dp_Arg2, dp->dp_Arg3));
1013 Res2 = create_softlink(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), AROS_BSTR_ADDR(dp->dp_Arg3));
1014 } else if (dp->dp_Arg4 == LINK_HARD) {
1015 fh2 = FH_FROM_LOCK(dp->dp_Arg3);
1016 DCMD(bug("[emul] %p ACTION_MAKE_LINK: %p, dest \"%b\", src %p\n", fhv, fh, dp->dp_Arg2, fh2));
1017 Res2 = create_hardlink(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), fh2);
1020 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1021 break;
1023 case ACTION_RENAME_OBJECT:
1024 fh = FH_FROM_LOCK(dp->dp_Arg1);
1025 fh2 = FH_FROM_LOCK(dp->dp_Arg3);
1026 DCMD(bug("[emul] %p ACTION_RENAME_OBJECT: %p, \"%b\" => %p, \"%b\"\n", fhv, fh, dp->dp_Arg2, fh2, dp->dp_Arg4));
1027 Res2 = rename_object(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), fh2, AROS_BSTR_ADDR(dp->dp_Arg4));
1029 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1030 break;
1032 case ACTION_READ_LINK:
1033 fh = FH_FROM_LOCK(dp->dp_Arg1);
1034 DCMD(bug("[emul] %p ACTION_READ_LINK: %p\n", fhv, fh));
1035 Res1 = dp->dp_Arg4;
1036 Res2 = read_softlink(emulbase, fh, (APTR)dp->dp_Arg2, (APTR)dp->dp_Arg3, &Res1, DOSBase);
1037 break;
1039 case ACTION_DELETE_OBJECT:
1040 fh = FH_FROM_LOCK(dp->dp_Arg1);
1041 DCMD(bug("[emul] %p ACTION_DELETE_OBJECT: %p\n", fhv, fh));
1042 Res2 = delete_object(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2));
1043 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1044 break;
1046 case ACTION_SET_PROTECT:
1047 /* dp_Arg1 is unused */
1048 fh = FH_FROM_LOCK(dp->dp_Arg2);
1049 DCMD(bug("[emul] %p ACTION_SET_PROTECT: %p\n", fhv, fh));
1050 Res2 = set_protect(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg3), dp->dp_Arg4);
1051 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1052 break;
1054 case ACTION_PARENT:
1055 fh = FH_FROM_LOCK(dp->dp_Arg1);
1056 DCMD(bug("[emul] %p ACTION_PARENT: %p\n", fhv, fh));
1058 if (fh == fhv) {
1059 Res1 = 0;
1060 Res2 = 0;
1061 break;
1064 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
1065 if (!fl) {
1066 Res2 = ERROR_NO_FREE_STORE;
1067 Res1 = DOSFALSE;
1068 break;
1071 Res2 = parent_dir(emulbase, fhv, &fh);
1072 if (Res2) {
1073 FreeMem(fl, sizeof(*fl));
1074 Res1 = DOSFALSE;
1075 break;
1078 /* Make a lock */
1079 fl->fl_Link = BNULL;
1080 fl->fl_Key = (IPTR)fh;
1081 fl->fl_Access = ACCESS_READ;
1082 fl->fl_Task = mp;
1083 fl->fl_Volume = MKBADDR(fh->dl);
1084 if (fh != fhv)
1085 fh->locks++;
1087 Res1 = (SIPTR)MKBADDR(fl);
1088 Res2 = 0;
1089 break;
1091 case ACTION_PARENT_FH:
1092 fh = FH_FROM(dp->dp_Arg1);
1093 DCMD(bug("[emul] %p ACTION_PARENT_FH: %p\n", fhv, fh));
1095 if (fh == fhv) {
1096 Res1 = 0;
1097 Res2 = 0;
1098 break;
1101 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
1102 if (!fl) {
1103 Res2 = ERROR_NO_FREE_STORE;
1104 Res1 = DOSFALSE;
1105 break;
1108 Res2 = parent_dir(emulbase, fhv, &fh);
1109 if (Res2) {
1110 FreeMem(fl, sizeof(*fl));
1111 Res1 = DOSFALSE;
1112 break;
1115 /* Make a lock */
1116 fl->fl_Link = BNULL;
1117 fl->fl_Key = (IPTR)fh;
1118 fl->fl_Access = ACCESS_READ;
1119 fl->fl_Task = mp;
1120 fl->fl_Volume = MKBADDR(fh->dl);
1121 if (fh != fhv)
1122 fh->locks++;
1124 Res1 = (SIPTR)MKBADDR(fl);
1125 Res2 = 0;
1126 break;
1127 case ACTION_IS_FILESYSTEM:
1128 DCMD(bug("[emul] %p ACTION_IS_FILESYSTEM:\n", fhv));
1129 Res2 = 0;
1130 Res1 = DOSTRUE;
1131 break;
1133 case ACTION_INFO:
1134 fh = FH_FROM_LOCK(dp->dp_Arg1);
1135 id = BADDR(dp->dp_Arg2);
1136 DCMD(bug("[emul] %p ACTION_INFO:\n", fhv));
1138 Res2 = disk_info(emulbase, fh, id);
1139 Res1 = Res2 ? DOSFALSE : DOSTRUE;
1140 break;
1142 case ACTION_DISK_INFO:
1143 id = (struct InfoData *)BADDR(dp->dp_Arg1);
1144 DCMD(bug("[emul] %p ACTION_DISK_INFO:\n", fhv));
1146 Res2 = disk_info(emulbase, fhv, id);
1147 Res1 = Res2 ? DOSFALSE : DOSTRUE;
1148 break;
1150 case ACTION_SET_DATE:
1151 /* dp_Arg1 is unused */
1152 fh = FH_FROM_LOCK(dp->dp_Arg2);
1153 DCMD(bug("[emul] %p ACTION_SET_DATE: %p\n", fhv, fh));
1154 Res2 = set_date(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg3), (struct DateStamp *)dp->dp_Arg4);
1155 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1156 break;
1158 case ACTION_SET_OWNER:
1159 /* pretend to have changed owner, avoids tons of error messages from e.g. tar */
1160 Res1 = DOSTRUE;
1161 break;
1163 /* FIXME: not supported yet
1164 case ACTION_SET_COMMENT:
1165 case ACTION_MORE_CACHE:
1166 case ACTION_WAIT_CHAR:
1168 default:
1169 DCMD(bug("[emul] Unknown action %lu\n", dp->dp_Type));
1170 Res2 = ERROR_ACTION_NOT_KNOWN;
1171 Res1 = DOSFALSE;
1172 break;
1175 /* Set error code */
1176 DCMD(bug("[emul] Replying with 0x%p, %ld\n", Res1, Res2));
1178 ReplyPkt(dp, Res1, Res2);
1181 static void EmulHandler_work(struct ExecBase *SysBase)
1183 struct DosLibrary *DOSBase;
1184 struct DosPacket *dp;
1185 struct DeviceNode *dn;
1186 struct FileSysStartupMsg *fssm;
1187 STRPTR devpath = NULL;
1188 struct MsgPort *mp;
1189 struct filehandle *fhv;
1190 struct emulbase *emulbase;
1192 DOSBase = (APTR)OpenLibrary("dos.library", 0);
1193 if (!DOSBase)
1194 return;
1196 mp = &((struct Process *)FindTask(NULL))->pr_MsgPort;
1198 /* Wait for startup message. */
1199 D(bug("EMUL: Waiting for startup...\n"));
1200 WaitPort(mp);
1201 dp = (struct DosPacket *)(GetMsg(mp)->mn_Node.ln_Name);
1203 D(bug("EMUL: Open resource\n"));
1204 emulbase = OpenResource("emul-handler");
1205 if (!emulbase)
1207 D(bug("EMUL: FATAL - can't find myself\n"));
1208 ReplyPkt(dp, DOSFALSE, ERROR_INVALID_RESIDENT_LIBRARY);
1209 return;
1212 fssm = BADDR(dp->dp_Arg2);
1213 if (fssm)
1214 devpath = AROS_BSTR_ADDR(fssm->fssm_Device);
1216 fhv = new_volume(emulbase, devpath, mp, DOSBase);
1217 if (!fhv)
1219 D(bug("EMUL: FATAL - can't create the inital volume \"%s\"\n", devpath));
1220 ReplyPkt(dp, DOSFALSE, ERROR_NO_FREE_STORE);
1221 return;
1224 /* Now, once we know all is well with the world,
1225 * we tell DOS that we're the handler for this
1226 * DeviceNode
1228 dn = BADDR(dp->dp_Arg3);
1229 dn->dn_Task = mp;
1231 ReplyPkt(dp, DOSTRUE, 0);
1233 fhv->locks = 1;
1234 while (fhv->locks)
1236 dp = WaitPkt();
1237 handlePacket(emulbase, fhv, mp, dp, DOSBase);
1240 D(bug("EMUL: Closing volume %s\n", fhv->volumename));
1241 RemDosEntry(fhv->dl);
1242 free_lock(emulbase, fhv);
1243 CloseLibrary((APTR)DOSBase);
1246 AROS_PROCH(EmulHandlerMain, argptr, argstr, SysBase)
1248 AROS_PROCFUNC_INIT
1250 EmulHandler_work(SysBase);
1252 return RETURN_OK;
1254 AROS_PROCFUNC_EXIT