- Fixed a memory leak.
[AROS.git] / arch / all-hosted / filesys / emul_handler / emul_handler.c
blobc71fe7f4fdaddf0663b04118746e738ec02ea8f2
1 /*
2 Copyright 1995-2014, 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 access, 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 FreeVecPooled(emulbase->mempool, fh->hostname);
203 FreeMem(fh, sizeof(*fh));
204 if (!AllowDir) {
205 *handle = 0;
206 return ERROR_OBJECT_WRONG_TYPE;
208 *handle = fhv;
209 return 0;
212 ret = DoOpen(emulbase, fh, access, mode, protect, AllowDir);
213 if (!ret)
215 *handle = fh;
216 return 0;
219 DOPEN(bug("[emul] Freeing pathname\n"));
220 FreeVecPooled(emulbase->mempool, fh->hostname);
222 DOPEN(bug("[emul] Freeing filehandle\n"));
223 FreeMem(fh, sizeof(struct filehandle));
224 } else
225 ret = ERROR_NO_FREE_STORE;
226 DOPEN(bug("[emul] open_() returns %lu\n", ret));
227 return ret;
231 /*********************************************************************************************/
233 static LONG create_dir(struct emulbase *emulbase, struct filehandle **handle,
234 const char *filename, ULONG protect)
236 LONG ret = 0;
237 struct filehandle *fh;
239 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC|MEMF_CLEAR);
240 if (fh)
242 fh->volumename = (*handle)->volumename;
243 fh->dl = (*handle)->dl;
245 ret = makefilename(emulbase, &fh->hostname, &fh->name, *handle, filename);
246 if (!ret)
248 ret = DoMkDir(emulbase, fh, protect);
249 if (!ret)
251 *handle = fh;
252 return 0;
255 free_lock(emulbase, fh);
256 } else
257 ret = ERROR_NO_FREE_STORE;
259 return ret;
262 /*********************************************************************************************/
264 static LONG delete_object(struct emulbase *emulbase, struct filehandle* fh, const char *file)
266 LONG ret = 0;
267 char *filename = NULL;
269 DDEL(bug("[emul] Deleting object %s in handle 0x%p (%s)\n", file, fh, fh->hostname));
271 ret = makefilename(emulbase, &filename, NULL, fh, file);
272 if (!ret)
274 ret = DoDelete(emulbase, filename);
275 FreeVecPooled(emulbase->mempool, filename);
278 return ret;
281 /*********************************************************************************************/
283 static LONG set_protect(struct emulbase *emulbase, struct filehandle* fh,
284 const char *file, ULONG aprot)
286 LONG ret = 0;
287 char *filename = NULL;
289 if ((ret = makefilename(emulbase, &filename, NULL, fh, file)))
290 return ret;
292 ret = DoChMod(emulbase, filename, aprot);
294 FreeVecPooled(emulbase->mempool, filename);
295 return ret;
298 /*********************************************************************************************/
300 const ULONG sizes[] = {
302 offsetof(struct ExAllData,ed_Type),
303 offsetof(struct ExAllData,ed_Size),
304 offsetof(struct ExAllData,ed_Prot),
305 offsetof(struct ExAllData,ed_Days),
306 offsetof(struct ExAllData,ed_Comment),
307 offsetof(struct ExAllData,ed_OwnerUID),
308 sizeof(struct ExAllData)
311 static SIPTR examine(struct emulbase *emulbase, struct filehandle *fh,
312 struct FileInfoBlock *fib)
314 UBYTE buff[sizeof(struct ExAllData) +
315 sizeof(fib->fib_FileName) + 1 +
316 sizeof(fib->fib_Comment) + 1];
317 struct ExAllData *ead = (APTR)&buff[0];
318 SIPTR err;
320 err = DoExamineEntry(emulbase, fh, NULL, ead, sizeof(buff), ED_OWNER);
321 if (err)
322 return err;
324 memset(fib, 0, sizeof(*fib));
326 if (ead->ed_Name) {
327 fib->fib_FileName[0] = strlen(ead->ed_Name) + 1;
328 if (fib->fib_FileName[0] > sizeof(fib->fib_FileName)-1)
329 fib->fib_FileName[0] = sizeof(fib->fib_FileName)-1;
330 CopyMem(ead->ed_Name, &fib->fib_FileName[1], fib->fib_FileName[0]);
333 if (ead->ed_Comment) {
334 fib->fib_Comment[0] = strlen(ead->ed_Comment) + 1;
335 if (fib->fib_Comment[0] > sizeof(fib->fib_Comment)-1)
336 fib->fib_Comment[0] = sizeof(fib->fib_Comment)-1;
337 CopyMem(ead->ed_Comment, &fib->fib_Comment[1], fib->fib_Comment[0]);
340 fib->fib_DiskKey = 0;
341 fib->fib_DirEntryType = ead->ed_Type;
342 fib->fib_Protection = ead->ed_Prot;
343 fib->fib_EntryType = ead->ed_Type;
344 fib->fib_Size = ead->ed_Size;
345 fib->fib_NumBlocks = (ead->ed_Size + 512 - 1) / 512;
346 fib->fib_Date.ds_Days = ead->ed_Days;
347 fib->fib_Date.ds_Minute = ead->ed_Mins;
348 fib->fib_Date.ds_Tick = ead->ed_Ticks;
349 fib->fib_OwnerUID = ead->ed_OwnerUID;
350 fib->fib_OwnerGID = ead->ed_OwnerGID;
352 return 0;
355 /*********************************************************************************************/
357 static LONG create_hardlink(struct emulbase *emulbase, struct filehandle *handle, const char *name, struct filehandle *oldfile)
359 LONG error;
360 char *fn;
362 DLINK(bug("[emul] Creating hardlink %s to file %s\n", name, oldfile->hostname));
363 error = makefilename(emulbase, &fn, NULL, handle, name);
364 if (!error)
366 DLINK(bug("[emul] Host name of the link: %s\n", fn));
367 error = DoHardLink(emulbase, fn, oldfile->hostname);
368 FreeVecPooled(emulbase->mempool, fn);
371 return error;
374 /*********************************************************************************************/
376 static LONG create_softlink(struct emulbase * emulbase,
377 struct filehandle *handle, const char *name, const char *ref)
379 LONG error;
380 char *dest;
382 DLINK(bug("[emul] Creating softlink %s to file %s\n", name, ref));
383 DLINK(bug("[emul] Handle 0x%p, pathname %s\n", handle, handle->hostname));
384 error = makefilename(emulbase, &dest, NULL, handle, name);
385 if (!error)
387 char *src = AllocVecPooled(emulbase->mempool, strlen(ref)+1);
388 if (src)
390 strcpy(src, ref);
391 DLINK(bug("[emul] Link host name: %s\n", dest));
392 error = DoSymLink(emulbase, src, dest);
393 DLINK(bug("[emul] Error: %d\n", error));
395 FreeVecPooled(emulbase->mempool, src);
397 else
398 error = ERROR_NO_FREE_STORE;
400 FreeVecPooled(emulbase->mempool, dest);
403 return error;
406 /*********************************************************************************************/
408 static LONG rename_object(struct emulbase * emulbase, struct filehandle *fh,
409 const char *file, struct filehandle *fh2, const char *newname)
411 LONG ret = 0L;
413 char *filename = NULL , *newfilename = NULL;
415 /* FIXME: fh2 is unused! */
416 ret = makefilename(emulbase, &filename, NULL, fh, file);
417 if (!ret)
419 ret = makefilename(emulbase, &newfilename, NULL, fh, newname);
420 if (!ret)
422 ret = DoRename(emulbase, filename, newfilename);
423 FreeVecPooled(emulbase->mempool, newfilename);
425 FreeVecPooled(emulbase->mempool, filename);
428 return ret;
431 /*********************************************************************************************/
433 static LONG read_softlink(struct emulbase *emulbase, struct filehandle *fh, CONST_STRPTR link,
434 STRPTR buffer, SIPTR *size, struct DosLibrary *DOSBase)
436 char *ln;
437 LONG ret = 0;
438 char *filename = NULL;
439 long l = strlen(link) + 1;
441 DLINK(bug("read_softlink: link %s len %d\n", link, l));
443 /* don't mess with link itself */
444 ln = AllocVecPooled(emulbase->mempool, l);
446 if (!ln)
447 return ERROR_NO_FREE_STORE;
449 CopyMem(link, ln, l);
451 ret = makefilename(emulbase, &filename, NULL, fh, ln);
452 if (!ret)
454 int targetlen = DoReadLink(emulbase, filename, buffer, *size, &ret);
455 DLINK(bug("read_softlink: targetlen %d\n", targetlen));
457 FreeVecPooled(emulbase->mempool, filename);
459 if (targetlen < 0)
460 *size = targetlen;
461 else
463 buffer[targetlen] = '\0';
464 DLINK(bug("read_softlink: buffer after DoReadLink %s\n", buffer));
465 if (strchr(buffer, ':') == NULL)
467 STRPTR source = FilePart(ln);
469 /* strip file part of link */
470 *source = '\0';
471 if (strlen(ln) + targetlen >= *size)
473 DLINK(bug("read_softlink: buffer too small %d>=%u\n", strlen(ln) + targetlen, *size));
474 /* Buffer was too small */
475 *size = -2;
477 else
479 /* copy buffer to create resolved link path in it */
480 char* target = AllocVecPooled(emulbase->mempool, targetlen+1);
481 if (target)
483 strcpy(target, buffer);
484 if (shrink(target))
486 strcpy(buffer, ln);
487 strcat(buffer, target);
488 *size = strlen(buffer);
491 FreeVecPooled(emulbase->mempool, target);
493 else
494 ret = ERROR_NO_FREE_STORE;
497 else
499 *size = targetlen >= *size ? -2 : strlen(buffer);
504 DLINK(if (!ret) bug("read_softlink: buffer %s\n", buffer));
505 FreeVecPooled(emulbase->mempool, ln);
507 return ret;
510 /*********************************************************************************************/
512 static SIPTR parent_dir(struct emulbase *emulbase,
513 struct filehandle *fhv,
514 struct filehandle **fhp)
516 SIPTR err;
518 DCHDIR(bug("[emul] Original directory: \"%s\"\n", (*fhp)->name));
519 err = open_(emulbase, fhv, fhp, "/", ACCESS_READ, MODE_OLDFILE, 0, TRUE);
520 DCHDIR(bug("[emul] Parent directory: \"%s\"\n", err ? NULL : (*fhp)->name));
522 return err;
525 /*********************************************************************************************/
527 static LONG set_date(struct emulbase *emulbase, struct filehandle *fh,
528 const char *FileName, struct DateStamp *date)
530 char *fullname;
531 LONG ret;
533 ret = makefilename(emulbase, &fullname, NULL, fh, FileName);
534 if (!ret)
536 ret = DoSetDate(emulbase, fullname, date);
538 FreeVecPooled(emulbase->mempool, fullname);
540 return ret;
543 static LONG disk_info(struct emulbase *emulbase, struct filehandle *fh, struct InfoData *id)
545 LONG Res2 = DoStatFS(emulbase, fh->hostname, id);
547 if (!Res2)
549 /* Fill in host-independent part */
550 id->id_UnitNumber = 0;
551 id->id_DiskType = ID_DOS_DISK; /* Well, not really true... */
552 id->id_VolumeNode = MKBADDR(fh->dl);
553 id->id_InUse = TRUE; /* Perhaps we should count locks? */
556 return Res2;
559 /*********************************************************************************************/
561 #define VOLNAME "System"
562 #define VOLNAME_LEN 6
564 static struct filehandle *new_volume(struct emulbase *emulbase, const char *path, struct MsgPort *mp, struct DosLibrary *DOSBase)
566 struct filehandle *fhv;
567 struct DosList *doslist;
568 char *unixpath;
569 const char *vol;
570 int vol_len = 0;
571 char *sp;
574 * MakeDosNode() creates zero-length fssm_Device instead of BNULL pointer when ParamPkt[1] is zero.
575 * CHECKME: is this correct, or MakeDosNode() needs to be fixed?
577 if (path && path[0])
579 DMOUNT(bug("[emul] Mounting volume %s\n", path));
582 * Volume name and Unix path are encoded into DEVICE entry of
583 * MountList like this: <volumename>:<unixpath>
585 vol = path;
588 if (*path == 0)
589 return NULL;
591 vol_len++;
592 } while (*path++ != ':');
593 DMOUNT(bug("[emul] Host path: %s, volume name length %u\n", path, vol_len));
595 sp = strchr(path, '~');
596 if (sp)
598 unixpath = GetHomeDir(emulbase, sp + 1);
599 if (!unixpath)
600 return NULL;
601 } else {
602 unixpath = AllocVecPooled(emulbase->mempool, strlen(path)+1);
603 if (!unixpath)
604 return NULL;
606 CopyMem(path, unixpath, strlen(path)+1);
609 else
611 ULONG res;
613 DMOUNT(bug("[emul] Mounting root volume\n"));
615 unixpath = AllocVecPooled(emulbase->mempool, PATH_MAX);
616 if (!unixpath)
617 return NULL;
619 res = GetCurrentDir(emulbase, unixpath, PATH_MAX);
620 DMOUNT(bug("[emul] GetCurrentDir() returned %d\n", res));
621 if(!res)
623 FreeVec(unixpath);
625 return NULL;
627 D(bug("[emul] startup directory %s\n", unixpath));
629 vol = VOLNAME;
630 vol_len = VOLNAME_LEN + 1;
633 DMOUNT(bug("[emul] Resolved host path: %s\n", unixpath));
635 if (CheckDir(emulbase, unixpath))
637 FreeVecPooled(emulbase->mempool, unixpath);
638 return NULL;
641 fhv = AllocMem(sizeof(struct filehandle) + vol_len, MEMF_PUBLIC|MEMF_CLEAR);
642 DMOUNT(bug("[emul] Volume file handle: 0x%p\n", fhv));
643 if (fhv)
645 char *volname = (char *)fhv + sizeof(struct filehandle);
647 CopyMem(vol, volname, vol_len - 1);
648 volname[vol_len - 1] = 0;
650 fhv->hostname = unixpath;
651 fhv->name = unixpath + strlen(unixpath);
652 fhv->type = FHD_DIRECTORY;
653 fhv->volumename = volname;
654 if (!DoOpen(emulbase, fhv, ACCESS_READ, MODE_OLDFILE, 0, TRUE)) {
655 DMOUNT(bug("[emul] Making volume node %s\n", volname));
657 doslist = MakeDosEntry(volname, DLT_VOLUME);
658 DMOUNT(bug("[emul] Volume node 0x%p\n", doslist));
659 if (doslist)
661 fhv->dl = doslist;
662 doslist->dol_Task = mp;
663 AddDosEntry(doslist);
665 SendEvent(emulbase, IECLASS_DISKINSERTED);
667 DMOUNT(bug("[emul] Mounting done\n"));
668 return fhv;
670 DMOUNT(bug("[emul] DOS Volume add failed, freeing volume node\n"));
673 DMOUNT(bug("[emul] Failed, freeing volume node\n"));
674 FreeVecPooled(emulbase->mempool, unixpath);
675 FreeMem(fhv, sizeof(struct filehandle) + vol_len);
678 DMOUNT(bug("[emul] Mounting failed\n"));
679 return NULL;
682 #define FH_FROM(x) ((struct filehandle *)(x))
683 #define FH_FROM_LOCK(x) \
684 ({ BPTR _x = (BPTR)x; \
685 APTR _fh; \
686 if (_x == BNULL) { \
687 _fh = fhv; \
688 } else { \
689 _fh = (APTR)(((struct FileLock *)BADDR(_x))->fl_Key); \
691 (struct filehandle *)_fh;\
694 static void handlePacket(struct emulbase *emulbase, struct filehandle *fhv, struct MsgPort *mp, struct DosPacket *dp, struct DosLibrary *DOSBase)
696 SIPTR Res1 = DOSFALSE;
697 SIPTR Res2 = ERROR_UNKNOWN;
698 struct filehandle *fh, *fh2;
699 struct FileHandle *f;
700 struct FileLock *fl, *fl2;
701 struct InfoData *id;
703 DB2(bug("[emul] Got command %u\n", dp->dp_Type));
705 switch(dp->dp_Type)
707 case ACTION_FINDINPUT:
708 case ACTION_FINDOUTPUT:
709 case ACTION_FINDUPDATE:
710 f = BADDR(dp->dp_Arg1);
711 fh2 = FH_FROM_LOCK(dp->dp_Arg2);
713 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));
714 Res2 = open_(emulbase, fhv, &fh2, AROS_BSTR_ADDR(dp->dp_Arg3), ACCESS_WRITE, dp->dp_Type, 0, FALSE);
716 if (Res2 == 0)
718 f->fh_Arg1 = (SIPTR)fh2;
719 if (fh2 != fhv)
720 fh2->locks++;
721 Res1 = DOSTRUE;
723 else
724 Res1 = DOSFALSE;
726 break;
728 case ACTION_END:
729 fh = FH_FROM(dp->dp_Arg1);
730 DCMD(bug("[emul] %p ACTION_END\n", fhv, fh));
731 if (fh != fhv) {
732 fh->locks--;
733 if (!fh->locks)
734 free_lock(emulbase, fh);
736 Res2 = 0;
737 Res1 = DOSTRUE;
738 break;
740 case ACTION_READ:
741 fh = FH_FROM(dp->dp_Arg1);
742 DCMD(bug("[emul] %p ACTION_READ\n", fhv, fh));
744 if (fh->type & FHD_FILE)
746 Res1 = DoRead(emulbase, fh, (APTR)dp->dp_Arg2, dp->dp_Arg3, &Res2);
748 else {
749 Res1 = -1;
750 Res2 = ERROR_OBJECT_WRONG_TYPE;
752 break;
754 case ACTION_WRITE:
755 fh = FH_FROM(dp->dp_Arg1);
756 DCMD(bug("[emul] %p ACTION_WRITE\n", fhv, fh));
758 if (fh->type & FHD_FILE)
760 Res1 = DoWrite(emulbase, fh, (APTR)dp->dp_Arg2, dp->dp_Arg3, &Res2);
761 } else {
762 Res1 = -1;
763 Res2 = ERROR_OBJECT_WRONG_TYPE;
765 break;
767 case ACTION_SEEK:
768 fh = FH_FROM(dp->dp_Arg1);
769 DCMD(bug("[emul] %p ACTION_SEEK %p, mode %ld, offset %lu\n", fhv, fh, dp->dp_Arg3, dp->dp_Arg2));
771 if (fh->type == FHD_FILE)
772 Res1 = DoSeek(emulbase, fh, dp->dp_Arg2, dp->dp_Arg3, &Res2);
773 else {
774 Res1 = DOSFALSE;
775 Res2 = ERROR_OBJECT_WRONG_TYPE;
778 break;
780 case ACTION_SET_FILE_SIZE:
781 fh = FH_FROM(dp->dp_Arg1);
782 DCMD(bug("[emul] %p ACTION_SET_FILE_SIZE: %p, mode %ld, offset %llu\n", fhv, fh, dp->dp_Arg2, dp->dp_Arg3));
784 Res1 = DoSetSize(emulbase, fh, dp->dp_Arg2, dp->dp_Arg3, &Res2);
785 if (Res2 != 0) {
786 Res1 = -1;
788 break;
790 case ACTION_SAME_LOCK:
791 fh = FH_FROM_LOCK(dp->dp_Arg1);
792 fh2 = FH_FROM_LOCK(dp->dp_Arg2);
794 DCMD(bug("[emul] %p ACTION_SAME_LOCK: %p, %p\n", fhv, fh, fh2));
795 DSAME(bug("[emul] Paths: %s, %s\n", fh->hostname, fh2->hostname));
797 Res2 = 0;
798 /* DOSTRUE means 'Same', DOSFALSE means 'Different' */
799 Res1 = strcasecmp(fh->hostname, fh2->hostname) ? DOSFALSE : DOSTRUE;
801 DSAME(bug("[emul] Replying with 0x%p, %ld\n", Res1, Res2));
802 break;
804 case ACTION_EXAMINE_FH:
805 fh = FH_FROM(dp->dp_Arg1);
806 DCMD(bug("[emul] %p ACTION_EXAMINE_FH: %p, fib %p\n", fhv, fh, BADDR(dp->dp_Arg2)));
807 Res2 = examine(emulbase, fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
808 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
809 break;
811 case ACTION_EXAMINE_OBJECT:
812 fh = FH_FROM_LOCK(dp->dp_Arg1);
813 DCMD(bug("[emul] %p ACTION_EXAMINE_OBJECT: %p, fib %p\n", fhv, fh, BADDR(dp->dp_Arg2)));
814 Res2 = examine(emulbase, fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
815 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
816 break;
818 case ACTION_EXAMINE_NEXT:
819 fh = FH_FROM_LOCK(dp->dp_Arg1);
820 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));
821 Res2 = DoExamineNext(emulbase, (struct filehandle *)fh, (struct FileInfoBlock *)BADDR(dp->dp_Arg2));
822 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
823 break;
825 case ACTION_EXAMINE_ALL:
826 fh = FH_FROM_LOCK(dp->dp_Arg1);
827 DCMD(bug("[emul] %p ACTION_EXAMINE_ALL: %p\n", fhv, fh));
828 Res2 = DoExamineAll(emulbase, fh, (APTR)dp->dp_Arg2, BADDR(dp->dp_Arg5),
829 dp->dp_Arg3, dp->dp_Arg4, DOSBase);
830 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
831 break;
833 case ACTION_EXAMINE_ALL_END:
834 /* Just rewind */
835 fh = FH_FROM_LOCK(dp->dp_Arg1);
836 DCMD(bug("[emul] %p ACTION_EXAMINE_ALL_END: %p\n", fhv, fh));
837 Res2 = DoRewindDir(emulbase, (struct filehandle *)fh);
838 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
839 break;
841 case ACTION_CREATE_DIR:
842 fh = FH_FROM_LOCK(dp->dp_Arg1);
843 DCMD(bug("[emul] %p ACTION_CREATE_DIR: %p, %b\n", fhv, fh, dp->dp_Arg2));
845 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
846 if (!fl) {
847 Res2 = ERROR_NO_FREE_STORE;
848 Res1 = DOSFALSE;
849 break;
852 Res2 = create_dir(emulbase, &fh, AROS_BSTR_ADDR(dp->dp_Arg2),
853 FIBF_GRP_EXECUTE | FIBF_GRP_READ |
854 FIBF_OTR_EXECUTE | FIBF_OTR_READ);
855 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
856 if (Res1 != DOSTRUE) {
857 FreeMem(fl, sizeof(*fl));
858 break;
861 /* Make a lock */
862 fl->fl_Link = BNULL;
863 fl->fl_Key = (IPTR)fh;
864 fl->fl_Access = ACCESS_READ;
865 fl->fl_Task = mp;
866 fl->fl_Volume = MKBADDR(fh->dl);
867 if (fh != fhv)
868 fh->locks++;
869 Res2 = 0;
870 Res1 = (SIPTR)fl;
871 break;
872 case ACTION_LOCATE_OBJECT:
873 fh = FH_FROM_LOCK(dp->dp_Arg1);
874 DCMD(bug("[emul] %p ACTION_LOCATE_OBJECT: %p, %b\n", fhv, fh, dp->dp_Arg2));
876 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
877 if (!fl) {
878 Res2 = ERROR_NO_FREE_STORE;
879 Res1 = DOSFALSE;
880 break;
883 Res2 = open_(emulbase, fhv, &fh, AROS_BSTR_ADDR(dp->dp_Arg2), dp->dp_Arg3, MODE_OLDFILE, 0755, TRUE);
884 if (Res2) {
885 Res1 = DOSFALSE;
886 FreeMem(fl, sizeof(*fl));
887 break;
890 /* Make a lock */
891 fl->fl_Link = BNULL;
892 fl->fl_Key = (IPTR)fh;
893 fl->fl_Access = dp->dp_Arg3;
894 fl->fl_Task = mp;
895 fl->fl_Volume = MKBADDR(fh->dl);
896 if (fh != fhv)
897 fh->locks++;
898 Res2 = 0;
899 Res1 = (SIPTR)fl;
900 break;
902 case ACTION_FH_FROM_LOCK:
903 f = BADDR(dp->dp_Arg1);
904 fh2 = FH_FROM_LOCK(dp->dp_Arg2);
905 fl = BADDR(dp->dp_Arg2);
906 DCMD(bug("[emul] %p ACTION_FH_FROM_LOCK: %p, lock %p\n", fhv, fh, fh2));
908 f->fh_Arg1 = (SIPTR)fh2;
910 if (fl)
911 FreeMem(fl, sizeof(*fl));
913 Res2 = 0;
914 Res1 = DOSTRUE;
915 break;
917 case ACTION_COPY_DIR: /* DupLock */
918 fh = FH_FROM_LOCK(dp->dp_Arg1);
919 fl = BADDR(dp->dp_Arg1);
920 DCMD(bug("[emul] %p ACTION_COPY_DIR: %p\n", fhv, fh));
922 fl2 = AllocMem(sizeof(*fl2), MEMF_ANY | MEMF_CLEAR);
923 if (!fl2) {
924 Res2 = ERROR_NO_FREE_STORE;
925 Res1 = DOSFALSE;
926 break;
929 CopyMem(fl, fl2, sizeof(*fl2));
930 if (fh != fhv)
931 fh->locks++;
933 Res2 = 0;
934 Res1 = (SIPTR)MKBADDR(fl2);
935 break;
937 case ACTION_COPY_DIR_FH: /* Dup */
938 fh = FH_FROM(dp->dp_Arg1);
939 DCMD(bug("[emul] %p ACTION_COPY_DIR_FH: %p\n", fhv, fh));
941 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
942 if (!fl) {
943 Res2 = ERROR_NO_FREE_STORE;
944 Res1 = DOSFALSE;
945 break;
948 /* Make a lock */
949 fl->fl_Link = BNULL;
950 fl->fl_Key = (IPTR)fh;
951 fl->fl_Access = ACCESS_READ;
952 fl->fl_Task = mp;
953 fl->fl_Volume = MKBADDR(fh->dl);
954 if (fh != fhv)
955 fh->locks++;
957 Res2 = 0;
958 Res1 = (SIPTR)MKBADDR(fl);
959 break;
961 case ACTION_FREE_LOCK:
962 fh = FH_FROM_LOCK(dp->dp_Arg1);
963 fl = BADDR(dp->dp_Arg1);
964 DCMD(bug("[emul] %p ACTION_FREE_LOCK: %p\n", fhv, fh));
966 FreeMem(fl, sizeof(*fl));
967 if (fh != fhv) {
968 fh->locks--;
969 if (!fh->locks)
970 free_lock(emulbase, fh);
973 Res2 = 0;
974 Res1 = DOSTRUE;
975 break;
977 case ACTION_MAKE_LINK:
978 fh = FH_FROM_LOCK(dp->dp_Arg1);
980 Res2 = ERROR_UNKNOWN;
981 if (dp->dp_Arg4 == LINK_SOFT) {
982 DCMD(bug("[emul] %p ACTION_MAKE_LINK: %p, dest \"%b\", src \"%b\"\n", fhv, fh, dp->dp_Arg2, dp->dp_Arg3));
983 Res2 = create_softlink(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), AROS_BSTR_ADDR(dp->dp_Arg3));
984 } else if (dp->dp_Arg4 == LINK_HARD) {
985 fh2 = FH_FROM_LOCK(dp->dp_Arg3);
986 DCMD(bug("[emul] %p ACTION_MAKE_LINK: %p, dest \"%b\", src %p\n", fhv, fh, dp->dp_Arg2, fh2));
987 Res2 = create_hardlink(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), fh2);
990 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
991 break;
993 case ACTION_RENAME_OBJECT:
994 fh = FH_FROM_LOCK(dp->dp_Arg1);
995 fh2 = FH_FROM_LOCK(dp->dp_Arg3);
996 DCMD(bug("[emul] %p ACTION_RENAME_OBJECT: %p, \"%b\" => %p, \"%b\"\n", fhv, fh, dp->dp_Arg2, fh2, dp->dp_Arg4));
997 Res2 = rename_object(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2), fh2, AROS_BSTR_ADDR(dp->dp_Arg4));
999 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1000 break;
1002 case ACTION_READ_LINK:
1003 fh = FH_FROM_LOCK(dp->dp_Arg1);
1004 DCMD(bug("[emul] %p ACTION_READ_LINK: %p\n", fhv, fh));
1005 Res1 = dp->dp_Arg4;
1006 Res2 = read_softlink(emulbase, fh, (APTR)dp->dp_Arg2, (APTR)dp->dp_Arg3, &Res1, DOSBase);
1007 break;
1009 case ACTION_DELETE_OBJECT:
1010 fh = FH_FROM_LOCK(dp->dp_Arg1);
1011 DCMD(bug("[emul] %p ACTION_DELETE_OBJECT: %p\n", fhv, fh));
1012 Res2 = delete_object(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg2));
1013 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1014 break;
1016 case ACTION_SET_PROTECT:
1017 /* dp_Arg1 is unused */
1018 fh = FH_FROM_LOCK(dp->dp_Arg2);
1019 DCMD(bug("[emul] %p ACTION_SET_PROTECT: %p\n", fhv, fh));
1020 Res2 = set_protect(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg3), dp->dp_Arg4);
1021 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1022 break;
1024 case ACTION_PARENT:
1025 fh = FH_FROM_LOCK(dp->dp_Arg1);
1026 DCMD(bug("[emul] %p ACTION_PARENT: %p\n", fhv, fh));
1028 if (fh == fhv) {
1029 Res1 = 0;
1030 Res2 = 0;
1031 break;
1034 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
1035 if (!fl) {
1036 Res2 = ERROR_NO_FREE_STORE;
1037 Res1 = DOSFALSE;
1038 break;
1041 Res2 = parent_dir(emulbase, fhv, &fh);
1042 if (Res2) {
1043 FreeMem(fl, sizeof(*fl));
1044 Res1 = DOSFALSE;
1045 break;
1048 /* Make a lock */
1049 fl->fl_Link = BNULL;
1050 fl->fl_Key = (IPTR)fh;
1051 fl->fl_Access = ACCESS_READ;
1052 fl->fl_Task = mp;
1053 fl->fl_Volume = MKBADDR(fh->dl);
1054 if (fh != fhv)
1055 fh->locks++;
1057 Res1 = (SIPTR)MKBADDR(fl);
1058 Res2 = 0;
1059 break;
1061 case ACTION_PARENT_FH:
1062 fh = FH_FROM(dp->dp_Arg1);
1063 DCMD(bug("[emul] %p ACTION_PARENT_FH: %p\n", fhv, fh));
1065 if (fh == fhv) {
1066 Res1 = 0;
1067 Res2 = 0;
1068 break;
1071 fl = AllocMem(sizeof(*fl), MEMF_ANY | MEMF_CLEAR);
1072 if (!fl) {
1073 Res2 = ERROR_NO_FREE_STORE;
1074 Res1 = DOSFALSE;
1075 break;
1078 Res2 = parent_dir(emulbase, fhv, &fh);
1079 if (Res2) {
1080 FreeMem(fl, sizeof(*fl));
1081 Res1 = DOSFALSE;
1082 break;
1085 /* Make a lock */
1086 fl->fl_Link = BNULL;
1087 fl->fl_Key = (IPTR)fh;
1088 fl->fl_Access = ACCESS_READ;
1089 fl->fl_Task = mp;
1090 fl->fl_Volume = MKBADDR(fh->dl);
1091 if (fh != fhv)
1092 fh->locks++;
1094 Res1 = (SIPTR)MKBADDR(fl);
1095 Res2 = 0;
1096 break;
1098 case ACTION_IS_FILESYSTEM:
1099 DCMD(bug("[emul] %p ACTION_IS_FILESYSTEM:\n", fhv));
1100 Res2 = 0;
1101 Res1 = DOSTRUE;
1102 break;
1104 case ACTION_INFO:
1105 fh = FH_FROM_LOCK(dp->dp_Arg1);
1106 id = BADDR(dp->dp_Arg2);
1107 DCMD(bug("[emul] %p ACTION_INFO:\n", fhv));
1109 Res2 = disk_info(emulbase, fh, id);
1110 Res1 = Res2 ? DOSFALSE : DOSTRUE;
1111 break;
1113 case ACTION_DISK_INFO:
1114 id = (struct InfoData *)BADDR(dp->dp_Arg1);
1115 DCMD(bug("[emul] %p ACTION_DISK_INFO:\n", fhv));
1117 Res2 = disk_info(emulbase, fhv, id);
1118 Res1 = Res2 ? DOSFALSE : DOSTRUE;
1119 break;
1121 case ACTION_SET_DATE:
1122 /* dp_Arg1 is unused */
1123 fh = FH_FROM_LOCK(dp->dp_Arg2);
1124 DCMD(bug("[emul] %p ACTION_SET_DATE: %p\n", fhv, fh));
1125 Res2 = set_date(emulbase, fh, AROS_BSTR_ADDR(dp->dp_Arg3), (struct DateStamp *)dp->dp_Arg4);
1126 Res1 = (Res2 == 0) ? DOSTRUE : DOSFALSE;
1127 break;
1129 case ACTION_SET_OWNER:
1130 /* pretend to have changed owner, avoids tons of error messages from e.g. tar */
1131 Res1 = DOSTRUE;
1132 break;
1134 /* FIXME: not supported yet
1135 case ACTION_SET_COMMENT:
1136 case ACTION_MORE_CACHE:
1137 case ACTION_WAIT_CHAR:
1139 default:
1140 DCMD(bug("[emul] Unknown action %lu\n", dp->dp_Type));
1141 Res2 = ERROR_ACTION_NOT_KNOWN;
1142 Res1 = DOSFALSE;
1143 break;
1146 /* Set error code */
1147 DCMD(bug("[emul] Replying with 0x%p, %ld\n", Res1, Res2));
1149 ReplyPkt(dp, Res1, Res2);
1152 static void EmulHandler_work(struct ExecBase *SysBase)
1154 struct DosLibrary *DOSBase;
1155 struct DosPacket *dp;
1156 struct DeviceNode *dn;
1157 struct FileSysStartupMsg *fssm;
1158 STRPTR devpath = NULL;
1159 struct MsgPort *mp;
1160 struct filehandle *fhv;
1161 struct emulbase *emulbase;
1162 const STRPTR hname = "emul-handler";
1164 DOSBase = (APTR)OpenLibrary("dos.library", 0);
1165 if (!DOSBase)
1166 return;
1168 mp = &((struct Process *)FindTask(NULL))->pr_MsgPort;
1170 /* Wait for startup message. */
1171 D(bug("EMUL: Waiting for startup...\n"));
1172 WaitPort(mp);
1173 dp = (struct DosPacket *)(GetMsg(mp)->mn_Node.ln_Name);
1175 D(bug("EMUL: Open resource\n"));
1176 emulbase = OpenResource(hname);
1177 if (!emulbase)
1179 D(bug("EMUL: FATAL - can't find myself\n"));
1180 ReplyPkt(dp, DOSFALSE, ERROR_INVALID_RESIDENT_LIBRARY);
1181 return;
1184 /* emul-handler is really a .resource. This causes the problem that the startup code is not put
1185 * at the beginning of module, making RunHandler not beeing able to "start" the handler if it
1186 * is loaded at later date (for example by "mount home:"). Making the module resident is
1187 * a workaround for this problem. The full solution would most likely mean separating most of
1188 * the code to real .resource and then building a thin "real handler" emul-handler on top of
1189 * that resource.
1191 if (FindSegment(hname, NULL, TRUE) == BNULL)
1192 AddSegment(hname, CreateSegList(EmulHandlerMain), CMD_INTERNAL);
1195 fssm = BADDR(dp->dp_Arg2);
1196 if (fssm)
1197 devpath = AROS_BSTR_ADDR(fssm->fssm_Device);
1199 fhv = new_volume(emulbase, devpath, mp, DOSBase);
1200 if (!fhv)
1202 D(bug("EMUL: FATAL - can't create the inital volume \"%s\"\n", devpath));
1203 ReplyPkt(dp, DOSFALSE, ERROR_NO_FREE_STORE);
1204 return;
1207 /* Now, once we know all is well with the world,
1208 * we tell DOS that we're the handler for this
1209 * DeviceNode
1211 dn = BADDR(dp->dp_Arg3);
1212 dn->dn_Task = mp;
1214 ReplyPkt(dp, DOSTRUE, 0);
1216 fhv->locks = 1;
1217 while (fhv->locks)
1219 dp = WaitPkt();
1220 handlePacket(emulbase, fhv, mp, dp, DOSBase);
1223 D(bug("EMUL: Closing volume %s\n", fhv->volumename));
1224 RemDosEntry(fhv->dl);
1225 free_lock(emulbase, fhv);
1226 CloseLibrary((APTR)DOSBase);
1229 AROS_PROCH(EmulHandlerMain, argptr, argstr, SysBase)
1231 AROS_PROCFUNC_INIT
1233 EmulHandler_work(SysBase);
1235 return RETURN_OK;
1237 AROS_PROCFUNC_EXIT