Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / arch / all-mingw32 / devs / filesys / emul_handler / emul_handler.c
blobdc232f4bd9a837fab7f46cecfa675ced421a0aae
1 /*
2 Copyright 1995-2009, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Filesystem that accesses an underlying Windows filesystem.
6 Lang: english
8 Please always update the version-string below, if you modify the code!
9 */
11 /*********************************************************************************************/
13 #define DEBUG 0
14 #define DCMD(x)
15 #define DERROR(x)
16 #define DFNAME(x)
17 #define DFSIZE(x)
18 #define DOPEN(x)
19 #define DSEEK(x)
20 #define DASYNC(x)
22 #define __DOS_NOLIBBASE__
23 #define __HOSTLIB_NOLIBBASE__
24 #define __KERNEL_NOLIBBASE__
26 #include <aros/debug.h>
27 #include <aros/kernel.h>
28 #include <aros/system.h>
29 #include <aros/symbolsets.h>
30 #include <exec/resident.h>
31 #include <exec/memory.h>
32 #include <exec/alerts.h>
33 #include <devices/input.h>
34 #include <devices/inputevent.h>
35 #include <proto/exec.h>
36 #include <utility/tagitem.h>
37 #include <utility/hooks.h>
38 #include <dos/filesystem.h>
39 #include <dos/exall.h>
40 #include <dos/dosasl.h>
41 #include <dos/bptr.h>
42 #include <proto/dos.h>
43 #include <proto/arossupport.h>
44 #include <proto/expansion.h>
45 #include <proto/hostlib.h>
46 #include <proto/kernel.h>
47 #include <libraries/expansion.h>
48 #include <libraries/configvars.h>
49 #include <libraries/expansionbase.h>
51 #include <aros/host-conf.h>
53 #include <string.h>
55 #include "emul_handler_intern.h"
57 #include <string.h>
59 #include LC_LIBDEFS_FILE
61 /*********************************************************************************************/
63 /* Init DOSBase ourselves because emul_handler is initialized before dos.library */
64 static struct DosLibrary *DOSBase;
65 static APTR HostLibBase, KernelBase;
66 static struct EmulInterface *EmulIFace;
67 static struct KernelInterface *KernelIFace;
69 /*********************************** Support *******************************/
71 static void SendEvent(struct emulbase *emulbase, LONG event) {
72 struct IOStdReq *InputRequest;
73 struct MsgPort *InputPort;
74 struct InputEvent *ie;
75 D(bug("[emul] SendEvent\n"));
76 if ((InputPort = (struct MsgPort*)CreateMsgPort())) {
78 if ((InputRequest = (struct IOStdReq*)CreateIORequest(InputPort, sizeof(struct IOStdReq)))) {
80 if (!OpenDevice("input.device", 0, (struct IORequest*)InputRequest, 0)) {
82 if ((ie = AllocVec(sizeof(struct InputEvent), MEMF_PUBLIC|MEMF_CLEAR))) {
83 ie->ie_Class = event;
84 InputRequest->io_Command = IND_WRITEEVENT;
85 InputRequest->io_Data = ie;
86 InputRequest->io_Length = sizeof(struct InputEvent);
88 DoIO((struct IORequest*)InputRequest);
90 FreeVec(ie);
92 CloseDevice((struct IORequest*)InputRequest);
94 DeleteIORequest ((APTR)InputRequest);
96 DeleteMsgPort (InputPort);
100 /*********************************************************************************************/
102 static APTR emul_malloc(struct emulbase *emulbase, ULONG size)
104 ULONG *res;
106 // kprintf("** emul_malloc: size = %d **\n",size);
107 ObtainSemaphore(&emulbase->memsem);
109 size += sizeof(ULONG);
110 res = AllocPooled(emulbase->mempool, size);
111 if (res) *res++ = size;
113 ReleaseSemaphore(&emulbase->memsem);
115 // kprintf("** emul_malloc: size = %d result = %x **\n",size-sizeof(ULONG),res);
117 return res;
120 /*********************************************************************************************/
122 static void emul_free(struct emulbase *emulbase, APTR mem)
124 if (mem)
126 ULONG *m = (ULONG *)mem;
127 ULONG size = *--m;
129 // kprintf("** emul_free: size = %d memory = %x **\n",size-sizeof(ULONG),mem);
131 ObtainSemaphore(&emulbase->memsem);
132 FreePooled(emulbase->mempool, m, size);
133 ReleaseSemaphore(&emulbase->memsem);
135 D(else kprintf("*** emul_handler: tried to free NULL mem ***\n");)
138 /*********************************************************************************************/
140 /* Create a plain path out of the supplied filename.
141 Eg 'path1\path2\\path3\' becomes 'path1\path3'.
143 BOOL shrink(struct emulbase *emulbase, char *filename)
145 char *s, *s1,*s2;
146 unsigned long len;
148 /* We skip the first slash because it separates volume root prefix and the actual pathname */
149 s = filename;
150 if (*s == '\\')
151 s++;
153 for(;;)
155 /* leading slashes? --> return FALSE. */
156 if(*s == '\\') return FALSE;
158 /* remove superflous paths (ie paths that are followed by '\') */
159 s1 = strstr(s, "\\\\");
160 if(s1==NULL)
161 break;
162 s2=s1;
163 while(s2 > s)
165 if (s2[-1] == '\\') break;
166 s2--;
169 memmove(s2,s1+2,strlen(s1+1));
172 /* strip trailing slash */
173 len = strlen(filename);
174 if (len && (filename[len-1] == '\\'))
175 filename[len-1]=0;
177 return TRUE;
180 /*********************************************************************************************/
182 /* Allocate a buffer, in which the filename is appended to the pathname. */
183 static LONG makefilename(struct emulbase *emulbase, char **dest, char **part, struct filehandle * fh, STRPTR filename)
185 LONG ret = 0;
186 int len, flen, dirlen;
187 char *c, *s;
189 DFNAME(bug("[emul] makefilename(): directory \"%s\", file \"%s\")\n", fh->hostname, filename));
191 s = filename;
192 while (*s) {
193 if (*s == '.') {
194 do {
195 s++;
196 } while (*s == '.');
197 if ((*s == '/') || (!*s)) {
198 DFNAME(bug("[emul] Bad file name, contains dots-only component\n"));
199 return ERROR_INVALID_COMPONENT_NAME;
202 do {
203 if (*s == '\\') {
204 DFNAME(bug("[emul] Bad file name, contains backslash\n"));
205 return ERROR_INVALID_COMPONENT_NAME;
207 s++;
208 } while ((*s != '/') && *s);
209 while (*s == '/')
210 s++;
213 dirlen = strlen(fh->hostname);
214 flen = strlen(filename);
215 len = flen + dirlen + 2;
216 *dest=(char *)emul_malloc(emulbase, len);
217 if ((*dest)) {
218 CopyMem(fh->hostname, *dest, dirlen);
219 c = *dest + dirlen;
220 if (flen) {
221 *c++ = '\\';
222 /* We are on Windows, so we have to revert slashes while copying filename */
223 for (s = filename; *s; s++)
224 *c++ = (*s == '/') ? '\\' : *s;
226 *c = 0;
228 c = *dest + (fh->name - fh->hostname);
229 DFNAME(bug("[emul] Shrinking filename: \"%s\"\n", c));
230 if (!shrink(emulbase, c))
232 emul_free(emulbase, *dest);
233 *dest = NULL;
234 ret = ERROR_OBJECT_NOT_FOUND;
235 } else {
236 DFNAME(bug("[emul] resulting host filename: \"%s\"\n", *dest));
237 if (part) {
238 *part = c;
239 DFNAME(bug("[emul] resulting AROS filename: \"%s\"\n", c));
242 } else
243 ret = ERROR_NO_FREE_STORE;
244 return ret;
247 /*********************************************************************************************/
249 /* Make Windows protection bits out of AROS protection bits. */
250 ULONG prot_a2w(ULONG protect)
252 ULONG uprot = 0;
254 /* The following flags are low-active! */
255 if ((protect & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE))
256 uprot = FILE_ATTRIBUTE_READONLY;
257 /* The following flags are high-active again. */
258 if (protect & FIBF_ARCHIVE)
259 uprot |= FILE_ATTRIBUTE_ARCHIVE;
260 if (protect & FIBF_SCRIPT)
261 uprot |= FILE_ATTRIBUTE_SYSTEM;
263 /* TODO: 1) Support more NT-specific attributes ('Executable')
264 2) Write complete AROS protection bits support using NTFS streams */
266 return uprot;
269 /*********************************************************************************************/
271 /* Make AROS protection bits out of Windows protection bits. */
272 ULONG prot_w2a(ULONG protect)
274 ULONG uprot = 0;
276 /* The following three flags are low-active! */
277 if (protect & FILE_ATTRIBUTE_READONLY)
278 uprot = FIBF_WRITE|FIBF_DELETE;
279 if (protect & FILE_ATTRIBUTE_DIRECTORY)
280 uprot |= FIBF_EXECUTE;
281 /* The following flags are high-active again. */
282 if (protect & FILE_ATTRIBUTE_ARCHIVE)
283 uprot |= FIBF_ARCHIVE;
284 if (protect & FILE_ATTRIBUTE_SYSTEM)
285 uprot |= FIBF_SCRIPT;
287 /* TODO: 1) Support more NT-specific attributes ('Executable')
288 2) Write complete AROS protection bits support using NTFS streams */
290 return uprot;
293 /*********************************************************************************************/
295 static void FileTime2DateStamp(struct DateStamp *ds, UQUAD ft)
297 UQUAD totalmins;
299 /* Adjust from 01.01.1601 to 01.01.1978. This offset was calculated using a specially written program
300 which puts "01.01.1978 00:00:00" into SYSTEMTIME structure and converts it into FILETIME. */
301 ft -= 118969344000000000LL;
302 /* Adjust interval from 100 ns to 1/50 sec */
303 ft /= 200000;
304 totalmins = ft / (60*50);
305 ds->ds_Days = totalmins / (24*60);
306 ds->ds_Minute = totalmins % (24*60);
307 ds->ds_Tick = ft % (60*50);
310 /*********************************************************************************************/
312 /* Make an AROS error-code (<dos/dos.h>) out of a Windows error-code. */
313 static ULONG u2a[][2]=
315 { ERROR_PATH_NOT_FOUND, ERROR_OBJECT_NOT_FOUND },
316 { ERROR_ACCESS_DENIED, ERROR_OBJECT_WRONG_TYPE },
317 { ERROR_NO_MORE_FILES, ERROR_NO_MORE_ENTRIES },
318 { ERROR_NOT_ENOUGH_MEMORY, ERROR_NO_FREE_STORE },
319 { ERROR_FILE_NOT_FOUND, ERROR_OBJECT_NOT_FOUND },
320 { ERROR_FILE_EXISTS, ERROR_OBJECT_EXISTS },
321 { ERROR_WRITE_PROTECT, ERROR_WRITE_PROTECTED },
322 { WIN32_ERROR_DISK_FULL, ERROR_DISK_FULL },
323 { ERROR_DIR_NOT_EMPTY, ERROR_DIRECTORY_NOT_EMPTY },
324 { ERROR_SHARING_VIOLATION, ERROR_OBJECT_IN_USE },
325 { ERROR_LOCK_VIOLATION, ERROR_OBJECT_IN_USE },
326 { WIN32_ERROR_BUFFER_OVERFLOW, ERROR_OBJECT_TOO_LARGE },
327 { ERROR_INVALID_NAME, ERROR_OBJECT_NOT_FOUND },
328 { 0, 0 }
331 ULONG Errno_w2a(ULONG e)
333 ULONG i;
335 DERROR(printf("[EmulHandler] Windows error code: %lu\n", e));
336 for(i=0;i<sizeof(u2a)/sizeof(u2a[0]);i++)
337 if(u2a[i][0]==e) {
338 DERROR(printf("[EmulHandler] Translated to AROS error code: %lu\n", u2a[i][1]));
339 return u2a[i][1];
341 DERROR(printf("[EmulHandler] Unknown error code\n"));
342 return ERROR_UNKNOWN;
345 #define Errno() Errno_w2a(GetLastError())
347 /*********************************************************************************************/
349 void *DoOpen(char *path, int mode, int protect)
351 ULONG flags = 0;
352 ULONG lock;
353 ULONG create;
354 void *res;
356 D(bug("[emul] DoOpen(): mode 0x%08lX\n", mode));
357 if (mode & FMF_WRITE)
358 flags = GENERIC_WRITE;
359 if (mode & FMF_READ)
360 flags |= GENERIC_READ;
361 /* FILE_SHARE_WRITE looks strange here, however without it i can't reopen file which
362 is already open with MODE_OLDFILE, even just for reading with FMF_READ */
363 lock = (mode & FMF_LOCK) ? 0 : FILE_SHARE_READ|FILE_SHARE_WRITE;
364 if (mode & FMF_CREATE)
365 create = (flags & FMF_CLEAR) ? CREATE_ALWAYS : OPEN_ALWAYS;
366 else
367 create = (flags & FMF_CLEAR) ? TRUNCATE_EXISTING : OPEN_EXISTING;
368 D(bug("[emul] CreateFile: name \"%s\", flags 0x%08lX, lock 0x%08lX, create %lu\n", path, flags, lock, create));
369 Forbid();
370 res = OpenFile(path, flags, lock, NULL, create, prot_a2w(protect), NULL);
371 Permit();
372 DB2(bug("[emul] FileHandle = 0x%08lX\n", res));
373 return res;
376 /*********************************************************************************************/
378 /* Free a filehandle */
379 static LONG free_lock(struct emulbase *emulbase, struct filehandle *current)
381 D(bug("[emul] Lock type = %lu\n", current->type));
382 switch(current->type)
384 case FHD_FILE:
385 if((current->fd != emulbase->stdin_handle) && (current->fd != emulbase->stdout_handle) &&
386 (current->fd != emulbase->stderr_handle))
388 DB2(bug("[emul] CloseHandle(), fd = 0x%08lX\n", current->fd));
389 Forbid();
390 DoClose(current->fd);
391 Permit();
393 break;
394 case FHD_DIRECTORY:
395 if (current->fd != INVALID_HANDLE_VALUE)
397 D(bug("[emul] Closing directory search handle\n"));
398 Forbid();
399 FindEnd(current->fd);
400 Permit();
402 break;
404 if (current->pathname) {
405 D(bug("[emul] Freeing pathname: \"%s\"\n", current->pathname));
406 emul_free(emulbase, current->pathname);
408 D(bug("[emul] Freeing name: \"%s\"\n", current->hostname));
409 emul_free(emulbase, current->hostname);
410 D(bug("[emul] Freeing filehandle\n"));
411 FreeMem(current, sizeof(struct filehandle));
412 D(bug("[emul] Done\n"));
413 return 0;
416 /*********************************************************************************************/
418 static LONG open_(struct emulbase *emulbase, struct filehandle **handle, STRPTR name, LONG mode, LONG protect, BOOL AllowDir)
420 LONG ret = 0;
421 struct filehandle *fh;
423 DOPEN(bug("[emul] open_(\"%s\"), directories allowed: %lu\n", name, AllowDir));
425 fh=(struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC);
426 if(fh!=NULL) {
427 fh->pathname = NULL; /* just to make sure... */
428 fh->dl = (*handle)->dl;
429 /* If no filename is given and the file-descriptor is one of the
430 standard filehandles (stdin, stdout, stderr) ... */
431 if((!name[0]) && ((*handle)->type == FHD_FILE) &&
432 (((*handle)->fd == emulbase->stdin_handle) || ((*handle)->fd == emulbase->stdout_handle) || ((*handle)->fd == emulbase->stderr_handle)))
434 /* ... then just reopen that standard filehandle. */
435 fh->type = FHD_FILE;
436 fh->fd = (*handle)->fd;
437 fh->name = NULL;
438 fh->hostname = NULL;
439 fh->volumename = NULL;
440 *handle = fh;
441 return 0;
444 fh->volumename=(*handle)->volumename;
446 ret = makefilename(emulbase, &fh->hostname, &fh->name, *handle, name);
447 if (!ret)
449 int kind;
451 DOPEN(bug("[emul] Host object name: %s\n", fh->hostname));
452 kind = Stat(fh->hostname, NULL);
453 DOPEN(bug("[emul] object type: %ld\n", kind));
455 switch (kind) {
456 case ST_SOFTLINK:
457 ret = ERROR_IS_SOFT_LINK;
458 break;
459 case 0: /* Non-existing objects can be files opened for writing */
460 case ST_FILE:
461 fh->type=FHD_FILE;
462 fh->fd = DoOpen(fh->hostname, mode, protect);
463 if(fh->fd != INVALID_HANDLE_VALUE)
465 *handle=fh;
466 return 0;
468 ret = Errno();
469 break;
470 case ST_USERDIR:
471 /* file is a directory */
472 if (AllowDir) {
473 fh->type = FHD_DIRECTORY;
474 fh->fd = INVALID_HANDLE_VALUE;
475 fh->dirpos = 0;
476 *handle=fh;
477 return 0;
479 ret = ERROR_OBJECT_WRONG_TYPE;
480 break;
481 default:
482 ret = ERROR_OBJECT_WRONG_TYPE;
484 D(bug("[emul] Freeing pathname\n"));
485 emul_free(emulbase, fh->hostname);
487 D(bug("[emul] Freeing filehandle\n"));
488 FreeMem(fh, sizeof(struct filehandle));
489 } else
490 ret = ERROR_NO_FREE_STORE;
491 DOPEN(bug("[emul] open_() returns %lu\n", ret));
492 return ret;
495 /*********************************************************************************************/
497 static LONG seek_file(struct filehandle *fh, struct IFS_SEEK *io_SEEK, UQUAD *newpos)
499 ULONG error, mode;
500 ULONG pos_high = 0;
501 UQUAD oldpos;
503 if (fh->type == FHD_FILE) {
504 DB2(bug("[emul] LSeek() - getting current position\n"));
505 Forbid();
506 oldpos = LSeek(fh->fd, 0, &pos_high, FILE_CURRENT);
507 Permit();
508 oldpos |= (UQUAD)pos_high << 32;
509 D(bug("[emul] Original position: %llu\n", oldpos));
511 switch(io_SEEK->io_SeekMode) {
512 case OFFSET_BEGINNING:
513 mode = FILE_BEGIN;
514 break;
515 case OFFSET_CURRENT:
516 mode = FILE_CURRENT;
517 break;
518 default:
519 mode = FILE_END;
521 pos_high = io_SEEK->io_Offset >> 32;
522 DB2(bug("[emul] LSeek() - setting new position\n"));
523 Forbid();
524 error = LSeek(fh->fd, io_SEEK->io_Offset, &pos_high, mode);
525 Permit();
526 if (error == (ULONG)-1)
527 error = Errno();
528 else {
529 if (newpos) {
530 *newpos = error;
531 *newpos |= (UQUAD)pos_high << 32;
533 error = 0;
536 io_SEEK->io_Offset = oldpos;
537 } else
538 error = ERROR_OBJECT_WRONG_TYPE;
539 return error;
542 /*********************************************************************************************/
544 static LONG create_dir(struct emulbase *emulbase, struct filehandle **handle,
545 STRPTR filename, IPTR protect)
547 LONG ret = 0;
548 struct filehandle *fh;
550 fh = (struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC);
551 if (fh)
553 fh->pathname = NULL; /* just to make sure... */
554 fh->type = FHD_DIRECTORY;
555 fh->fd = INVALID_HANDLE_VALUE;
556 fh->dirpos = 0;
557 fh->volumename = (*handle)->volumename;
558 fh->dl = (*handle)->dl;
560 ret = makefilename(emulbase, &fh->hostname, &fh->name, *handle, filename);
561 if (!ret)
563 Forbid();
564 ret = MKDir(fh->hostname, NULL);
565 Permit();
566 if (ret) {
567 *handle = fh;
568 Forbid();
569 Chmod(fh->hostname, prot_a2w(protect));
570 Permit();
571 return 0;
573 ret = Errno();
575 free_lock(emulbase, fh);
576 } else
577 ret = ERROR_NO_FREE_STORE;
579 return ret;
582 /*********************************************************************************************/
584 static LONG delete_object(struct emulbase *emulbase, struct filehandle* fh,
585 STRPTR file)
587 LONG ret = 0;
588 char *filename = NULL;
590 ret = makefilename(emulbase, &filename, NULL, fh, file);
591 if (!ret)
593 if (!Delete(filename))
594 ret = Errno();
595 emul_free(emulbase, filename);
598 return ret;
601 /*********************************************************************************************/
603 static LONG set_protect(struct emulbase *emulbase, struct filehandle* fh,
604 STRPTR file, ULONG aprot)
606 LONG ret = 0;
607 char *filename = NULL;
609 if ((ret = makefilename(emulbase, &filename, NULL, fh, file)))
610 return ret;
612 Forbid();
613 ret = Chmod(filename, prot_a2w(aprot));
614 Permit();
615 ret = ret ? 0 : Errno();
617 emul_free(emulbase, filename);
619 return ret;
622 /*********************************************************************************************/
624 static void EmulIntHandler(struct AsyncReaderControl *msg, void *d)
626 DASYNC(bug("[emul] Interrupt on request 0x%p, task 0x%p, signal 0x%08lX\n", msg, msg->task, msg->sig));
627 Signal(msg->task, msg->sig);
630 /*********************************************************************************************/
631 static LONG startup(struct emulbase *emulbase)
633 struct Library *ExpansionBase;
634 struct filehandle *fhi = NULL;
635 struct filehandle *fho = NULL;
636 struct filehandle *fhe = NULL;
637 struct filehandle *fhv;
638 struct DeviceNode *dlv, *dlv2;
639 LONG ret = ERROR_NO_FREE_STORE;
640 ULONG res;
642 D(kprintf("[Emulhandler] startup\n"));
643 ExpansionBase = OpenLibrary("expansion.library",0);
644 if(ExpansionBase != NULL)
646 D(kprintf("[Emulhandler] startup: got ExpansionBase\n"));
647 fhv=(struct filehandle *)AllocMem(sizeof(struct filehandle) + 256 + AROS_WORSTALIGN, MEMF_PUBLIC);
648 if(fhv != NULL)
650 D(kprintf("[Emulhandler] startup allocated fhv\n"));
651 fhv->hostname = (char *)(fhv + 1);
652 fhv->type = FHD_DIRECTORY;
653 fhv->fd = INVALID_HANDLE_VALUE;
654 fhv->dirpos = 0;
655 fhv->pathname = NULL; /* just to make sure... */
657 Forbid();
658 res = GetCWD(256, fhv->hostname);
659 Permit();
660 if (res > 256)
661 res = 0;
662 if(res)
664 D(bug("[Emulhandler] startup got directory %s\n", fhv->hostname));
665 fhv->name = fhv->hostname + res;
666 #define DEVNAME "EMU"
667 #define VOLNAME "System"
669 static const char *devname = DEVNAME;
670 static const char *volname = VOLNAME;
672 fhv->volumename = VOLNAME;
674 Forbid();
675 emulbase->stdin_handle = GetStdFile(STD_INPUT_HANDLE);
676 emulbase->stdout_handle = GetStdFile(STD_OUTPUT_HANDLE);
677 emulbase->stderr_handle = GetStdFile(STD_ERROR_HANDLE);
678 Permit();
679 if (!emulbase->stdin_handle)
680 emulbase->stdin_handle = INVALID_HANDLE_VALUE;
681 if (!emulbase->stdout_handle)
682 emulbase->stdout_handle = INVALID_HANDLE_VALUE;
683 if (!emulbase->stderr_handle)
684 emulbase->stderr_handle = INVALID_HANDLE_VALUE;
686 if (emulbase->stdin_handle != INVALID_HANDLE_VALUE) {
687 fhi=(struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC|MEMF_CLEAR);
688 if(fhi!=NULL)
690 D(kprintf("[Emulhandler] allocated fhi\n"));
691 fhi->type = FHD_FILE;
692 fhi->fd = emulbase->stdin_handle;
693 emulbase->eb_stdin = fhi;
696 if (emulbase->stdout_handle != INVALID_HANDLE_VALUE) {
697 fho=(struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC|MEMF_CLEAR);
698 if(fho!=NULL)
700 D(kprintf("[Emulhandler] startup allocated fho\n"));
701 fho->type = FHD_FILE;
702 fho->fd = emulbase->stdout_handle;
703 emulbase->eb_stdout = fho;
706 if (emulbase->stderr_handle != INVALID_HANDLE_VALUE) {
707 fhe=(struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC|MEMF_CLEAR);
708 if(fhe!=NULL)
710 D(kprintf("[Emulhandler] startup allocated fhe\n"));
711 fhe->type = FHD_FILE;
712 fhe->fd = emulbase->stderr_handle;
713 emulbase->eb_stderr = fhe;
717 ret = ERROR_NO_FREE_STORE;
719 D(bug("[Emulhandler] Creating console reader\n"));
720 Forbid();
721 emulbase->ConsoleReader = InitNative();
722 Permit();
723 if (emulbase->ConsoleReader) {
724 D(bug("[Emulhandler] Created console reader %p\n", emulbase->ConsoleReader));
725 emulbase->ConsoleInt = KrnAddIRQHandler(1, EmulIntHandler, emulbase->ConsoleReader, NULL);
726 D(bug("[Emulhandler] Added console interrupt %p\n", emulbase->ConsoleReader));
727 if (emulbase->ConsoleInt) {
730 Allocate space for the string from same mem,
731 Use AROS_BSTR_MEMSIZE4LEN macro for space to
732 to allocate and add an extra 4 for alignment
733 purposes.
736 dlv = AllocMem(sizeof(struct DeviceNode) + 4 + AROS_BSTR_MEMSIZE4LEN(strlen(DEVNAME)), MEMF_CLEAR|MEMF_PUBLIC);
737 if (dlv) {
738 dlv2 = AllocMem(sizeof(struct DeviceNode) + 4 + AROS_BSTR_MEMSIZE4LEN(strlen(VOLNAME)), MEMF_CLEAR|MEMF_PUBLIC);
739 if(dlv2 != NULL)
741 BSTR s;
742 BSTR s2;
743 WORD i;
745 D(kprintf("[Emulhandler] startup allocated dlv/dlv2\n"));
746 /* We want s to point to the first 4-byte
747 aligned memory after the structure.
749 s = (BSTR)MKBADDR(((IPTR)dlv + sizeof(struct DeviceNode) + 3) & ~3);
750 s2 = (BSTR)MKBADDR(((IPTR)dlv2 + sizeof(struct DeviceNode) + 3) & ~3);
752 for(i = 0; i < sizeof(DEVNAME) - 1; i++)
754 AROS_BSTR_putchar(s, i, devname[i]);
756 AROS_BSTR_setstrlen(s, sizeof(DEVNAME) - 1);
758 dlv->dn_Type = DLT_DEVICE;
759 dlv->dn_Ext.dn_AROS.dn_Unit = (struct Unit *)fhv;
760 dlv->dn_Ext.dn_AROS.dn_Device = &emulbase->device;
761 dlv->dn_Handler = NULL;
762 dlv->dn_Startup = NULL;
763 dlv->dn_Name = s;
764 dlv->dn_Ext.dn_AROS.dn_DevName = AROS_BSTR_ADDR(dlv->dn_Name);
766 AddBootNode(5, 0, dlv, NULL);
769 /* Unfortunately, we cannot do the stuff below
770 as dos is not yet initialized... */
771 // AddDosEntry(MakeDosEntry("System", DLT_VOLUME));
773 for(i = 0; i < sizeof(VOLNAME) - 1; i++)
775 AROS_BSTR_putchar(s2, i, volname[i]);
777 AROS_BSTR_setstrlen(s2, sizeof(VOLNAME) - 1);
779 dlv2->dn_Type = DLT_VOLUME;
780 dlv2->dn_Ext.dn_AROS.dn_Unit = (struct Unit *)fhv;
781 dlv2->dn_Ext.dn_AROS.dn_Device = &emulbase->device;
782 dlv2->dn_Handler = NULL;
783 dlv2->dn_Startup = NULL;
784 dlv2->dn_Name = s2;
785 dlv2->dn_Ext.dn_AROS.dn_DevName = AROS_BSTR_ADDR(dlv2->dn_Name);
787 /* Make sure this is not booted from */
788 AddBootNode(-128, 0, dlv2, NULL);
789 fhv->dl = dlv2;
791 /* Increment our open counter because we use ourselves */
792 emulbase->device.dd_Library.lib_OpenCnt++;
793 return 0;
795 FreeMem(dlv, sizeof(struct DeviceNode) + 4 + AROS_BSTR_MEMSIZE4LEN(strlen(DEVNAME)));
799 if (fhe)
800 FreeMem(fhe, sizeof(struct filehandle));
801 if (fho)
802 FreeMem(fho, sizeof(struct filehandle));
803 if (fhi)
804 FreeMem(fhi, sizeof(struct filehandle));
805 } /* valid directory */
806 else
808 Alert(AT_DeadEnd|AO_Unknown|AN_Unknown );
810 free_lock(emulbase, fhv);
812 CloseLibrary(ExpansionBase);
815 return ret;
818 /*********************************************************************************************/
820 static const ULONG sizes[]=
821 { 0, offsetof(struct ExAllData,ed_Type), offsetof(struct ExAllData,ed_Size),
822 offsetof(struct ExAllData,ed_Prot), offsetof(struct ExAllData,ed_Days),
823 offsetof(struct ExAllData,ed_Comment), offsetof(struct ExAllData,ed_OwnerUID),
824 sizeof(struct ExAllData) };
826 /*********************************************************************************************/
828 /* Returns a emul_malloc()'ed buffer, containing a pathname, stripped by the
829 filename.
831 char *pathname_from_name (struct emulbase *emulbase, char *name)
833 long len = strlen(name);
834 long i = len;
835 char *result = NULL;
836 long c;
838 /* look for the first '\' in the filename starting at the end */
839 while (i != 0 && name[i] != '\\')
840 i--;
842 if (0 != i)
844 result = (char *)emul_malloc(emulbase, i + 1);
845 if(!result)
846 return NULL;
848 for (c = 0; c < i; c++)
849 result[c] = (name[c] == '\\') ? '/' : name[c];
850 result[i]=0x0;
852 return result;
855 /*********************************************************************************************/
857 ULONG examine_start(struct emulbase *emulbase, struct filehandle *fh)
859 char *c;
860 ULONG len;
862 if (fh->type != FHD_DIRECTORY)
863 return ERROR_OBJECT_WRONG_TYPE;
865 if (!fh->pathname) {
866 len = strlen(fh->hostname);
867 fh->pathname = emul_malloc(emulbase, len + 3);
868 if (!fh->pathname)
869 return ERROR_NO_FREE_STORE;
870 CopyMem(fh->hostname, fh->pathname, len);
871 c = fh->pathname + len;
872 strcpy(c, "\\*");
874 D(bug("[emul] Created search path: %s\n", fh->pathname));
875 return 0;
878 /*********************************************************************************************/
880 /* Resets dirpos in directory handle and close existing search handle */
881 static LONG CloseDir(struct filehandle *fh)
883 ULONG r;
885 if (fh->fd != INVALID_HANDLE_VALUE) {
886 Forbid();
887 r = FindEnd(fh->fd);
888 Permit();
889 if (!r)
890 return Errno();
891 fh->fd = INVALID_HANDLE_VALUE;
893 fh->dirpos = 0;
894 return 0;
897 /*********************************************************************************************/
899 #define is_special_dir(x) (x[0] == '.' && (!x[1] || (x[1] == '.' && !x[2])))
901 /* Positions to dirpos in directory, retrieves next item in it and updates dirpos */
902 ULONG ReadDir(struct filehandle *fh, LPWIN32_FIND_DATA FindData, ULONG *dirpos)
904 ULONG res;
907 * Windows does not support positioning within directory. The only thing i can do is to
908 * scan the directory in forward direction. In order to bypass this limitation we do the
909 * following:
910 * 1. Before starting we explicitly set current position (dirpos) to 0. Examine() will place
911 * it into our fib_DiskKey; in case of ExAll() this is eac_LastKey. We also maintain second
912 * directory position counter - in our directory handle. It reflects the real position of
913 * our file search handle.
914 * 2. Here we compare position in dirpos with position in the handle. If dirpos is smaller than
915 * filehandle's counter, we have to rewind the directory. This is done by closing the search
916 * handle in order to be able to restart from the beginning and setting handle's counter to 0.
918 D(bug("[emul] Current dirpos %lu, requested %lu\n", fh->dirpos, *dirpos));
919 if (fh->dirpos > *dirpos) {
920 D(bug("[emul] Resetting search handle\n"));
921 CloseDir(fh);
926 * 3. Now we will scan the next directory entry until its index is greater than original index
927 * in dirpos. This means that we've repositioned and scanned the next entry. After this we
928 * update dirpos.
930 do {
931 if (fh->fd == INVALID_HANDLE_VALUE) {
932 D(bug("[emul] Finding first file\n"));
933 Forbid();
934 fh->fd = FindFirst(fh->pathname, FindData);
935 Permit();
936 res = (fh->fd != INVALID_HANDLE_VALUE);
937 } else {
938 Forbid();
939 res = FindNext(fh->fd, FindData);
940 Permit();
942 if (!res)
943 return Errno();
944 fh->dirpos++;
945 D(bug("[emul] Found %s, position %lu\n", FindData->cFileName, fh->dirpos));
946 } while (fh->dirpos <= *dirpos);
947 (*dirpos)++;
948 D(bug("[emul] New dirpos: %lu\n", *dirpos));
950 * We also skip "." and ".." entries (however we count their indexes - just in case), because
951 * AmigaOS donesn't have them.
953 } while (is_special_dir(FindData->cFileName));
955 return 0;
958 /*********************************************************************************************/
960 ULONG examine_entry_sub(struct emulbase *emulbase, struct filehandle *fh, STRPTR FoundName, WIN32_FILE_ATTRIBUTE_DATA *FIB, LONG *kind)
962 STRPTR filename, name;
963 ULONG plen, flen;
964 ULONG error = 0;
966 D(bug("[emul] examine_entry_sub(): filehandle's path: %s\n", fh->hostname));
967 if (FoundName) {
968 D(bug("[emul] ...containing object: %s\n", FoundName));
969 plen = strlen(fh->hostname);
970 flen = strlen(FoundName);
971 name = emul_malloc(emulbase, plen + flen + 2);
972 if (NULL == name)
973 return ERROR_NO_FREE_STORE;
974 strcpy(name, fh->hostname);
975 filename = name + plen;
976 *filename++ = '\\';
977 strcpy(filename, FoundName);
978 } else
979 name = fh->hostname;
981 D(bug("[emul] Full name: %s\n", name));
982 *kind = Stat(name, FIB);
983 if (*kind == 0)
984 error = Errno();
985 if (FoundName) {
986 D(bug("[emul] Freeing full name\n"));
987 emul_free(emulbase, name);
989 return error;
992 /*********************************************************************************************/
994 ULONG examine_entry(struct emulbase *emulbase, struct filehandle *fh, STRPTR FoundName,
995 struct ExAllData *ead, ULONG size, ULONG type)
997 STRPTR next, last, end, name;
998 WIN32_FILE_ATTRIBUTE_DATA FIB;
999 LONG kind;
1000 ULONG error;
1002 /* Check, if the supplied buffer is large enough. */
1003 next=(STRPTR)ead+sizes[type];
1004 end =(STRPTR)ead+size;
1006 if(next>end) {
1007 D(bug("[emul] examine_entry(): end of buffer\n"));
1008 return ERROR_BUFFER_OVERFLOW;
1011 error = examine_entry_sub(emulbase, fh, FoundName, &FIB, &kind);
1012 if (error)
1013 return error;
1015 D(bug("[emul] Filling in object information\n"));
1016 switch(type)
1018 default:
1019 case ED_OWNER:
1020 ead->ed_OwnerUID = 0;
1021 ead->ed_OwnerGID = 0;
1022 case ED_COMMENT:
1023 ead->ed_Comment = NULL;
1024 /* TODO: Write Windows shell-compatible comments support using NTFS streams */
1025 case ED_DATE:
1026 FileTime2DateStamp((struct DateStamp *)&ead->ed_Days, FIB.ftLastWriteTime);
1027 case ED_PROTECTION:
1028 ead->ed_Prot = prot_w2a(FIB.dwFileAttributes);
1029 case ED_SIZE:
1030 ead->ed_Size = FIB.nFileSizeLow;
1031 case ED_TYPE:
1032 if ((kind == ST_USERDIR) && (!fh->name[0]))
1033 kind = ST_ROOT;
1034 ead->ed_Type = kind;
1035 case ED_NAME:
1036 if (FoundName)
1037 last = FoundName;
1038 else if (*fh->name) {
1039 name = fh->name;
1040 last = name;
1041 while(*name)
1042 if(*name++=='\\')
1043 last = name;
1044 } else
1045 last = fh->volumename;
1046 ead->ed_Name=next;
1047 for(;;)
1049 if(next>=end)
1050 return ERROR_BUFFER_OVERFLOW;
1051 if(!(*next++=*last++))
1052 break;
1054 case 0:
1055 ead->ed_Next=(struct ExAllData *)(((IPTR)next+AROS_PTRALIGN-1)&~(AROS_PTRALIGN-1));
1057 return 0;
1061 /*********************************************************************************************/
1063 static LONG examine(struct emulbase *emulbase, struct filehandle *fh,
1064 struct ExAllData *ead,
1065 ULONG size,
1066 ULONG type,
1067 LONG *dirpos)
1069 LONG error;
1071 /* Return an error, if supplied type is not supported. */
1072 if(type>ED_OWNER)
1073 return ERROR_BAD_NUMBER;
1075 /* Reset fh->dirpos to 0. If there is already a directory scan handle, it will be closed in order to start from the beginning */
1076 if (fh->type == FHD_DIRECTORY) {
1077 D(bug("[emul] examine(): Resetting search handle\n"));
1078 error = CloseDir(fh);
1079 if (error)
1080 return error;
1082 *dirpos = 0;
1084 return examine_entry(emulbase, fh, NULL, ead, size, type);
1087 /*********************************************************************************************/
1089 static LONG examine_next(struct emulbase *emulbase, struct filehandle *fh, struct FileInfoBlock *FIB)
1091 char *src, *dest;
1092 ULONG res;
1093 WIN32_FIND_DATA FindData;
1094 WIN32_FILE_ATTRIBUTE_DATA AttrData;
1096 res = examine_start(emulbase, fh);
1097 if (res)
1098 return res;
1100 res = ReadDir(fh, &FindData, &FIB->fib_DiskKey);
1101 if (!res)
1102 res = examine_entry_sub(emulbase, fh, FindData.cFileName, &AttrData, &FIB->fib_DirEntryType);
1103 if (res) {
1104 CloseDir(fh);
1105 return res;
1108 FIB->fib_OwnerUID = 0;
1109 FIB->fib_OwnerGID = 0;
1110 FIB->fib_Comment[0] = '\0'; /* TODO: no comments available yet! */
1111 FIB->fib_Protection = prot_w2a(AttrData.dwFileAttributes);
1112 FIB->fib_Size = AttrData.nFileSizeLow;
1113 FileTime2DateStamp(&FIB->fib_Date, AttrData.ftLastWriteTime);
1115 src = FindData.cFileName;
1116 dest = FIB->fib_FileName;
1117 for (res = 0; res<MAXFILENAMELENGTH-1; res++)
1119 if(! (*dest++=*src++) )
1121 break;
1125 return 0;
1128 /*********************************************************************************************/
1130 static LONG examine_all(struct emulbase *emulbase, struct filehandle *fh,
1131 struct ExAllData *ead,
1132 struct ExAllControl *eac,
1133 ULONG size,
1134 ULONG type)
1136 struct ExAllData *last = NULL;
1137 STRPTR end = (STRPTR)ead + size;
1138 LONG error;
1139 WIN32_FIND_DATA FindData;
1141 eac->eac_Entries = 0;
1142 error = examine_start(emulbase, fh);
1143 if (error)
1144 return error;
1146 for(;;)
1148 error = ReadDir(fh, &FindData, &eac->eac_LastKey);
1149 if (error) {
1150 D(bug("[emul] ReadDir() returned %lu\n", error));
1151 break;
1153 /* Try to match the filename, if required. */
1154 D(bug("[emul] Checking against MatchString\n"));
1155 if (eac->eac_MatchString && !MatchPatternNoCase(eac->eac_MatchString, FindData.cFileName))
1156 continue;
1157 D(bug("[emul] Examining object\n"));
1158 error = examine_entry(emulbase, fh, FindData.cFileName, ead, end-(STRPTR)ead, type);
1159 if(error)
1160 break;
1161 /* Do some more matching... */
1162 if ((eac->eac_MatchFunc) && !CALLHOOKPKT(eac->eac_MatchFunc, ead, &type))
1163 continue;
1164 eac->eac_Entries++;
1165 last = ead;
1166 ead = ead->ed_Next;
1168 if (last!=NULL)
1169 last->ed_Next=NULL;
1170 if((error==ERROR_BUFFER_OVERFLOW)&&last!=NULL)
1172 return 0;
1175 return error;
1178 /*********************************************************************************************/
1180 static LONG create_hardlink(struct emulbase *emulbase, struct filehandle *handle, STRPTR name, struct filehandle *oldfile)
1182 LONG error;
1183 char *fn;
1185 if (!KernelIFace->CreateHardLink)
1186 return ERROR_ACTION_NOT_KNOWN;
1188 error = makefilename(emulbase, &fn, NULL, handle, name);
1189 if (!error)
1191 D(bug("[emul] Creating hardlink %s to file %s\n", fn, oldfile->hostname));
1192 Forbid();
1193 error = Link(fn, oldfile->hostname, NULL);
1194 Permit();
1195 error = error ? 0 : Errno();
1196 emul_free(emulbase, fn);
1199 return error;
1202 /*********************************************************************************************/
1204 static LONG create_softlink(struct emulbase * emulbase,
1205 struct filehandle *handle, STRPTR name, STRPTR ref)
1207 LONG error=0L;
1208 char *src, *dest;
1210 /* TODO: implement symbolic links on earlier Windows versions using shell shortcuts */
1211 if (!KernelIFace->CreateSymbolicLink)
1212 return ERROR_ACTION_NOT_KNOWN;
1214 /* TODO: currently relative paths are converted to absolute one, this needs to be improved */
1215 error = makefilename(emulbase, &src, NULL, handle, name);
1216 if (!error)
1218 error = makefilename(emulbase, &dest, NULL, handle, ref);
1219 if (!error) {
1220 Forbid();
1221 error = SymLink(src, dest, 0);
1222 Permit();
1223 error = error ? 0 : Errno();
1224 emul_free(emulbase, dest);
1226 emul_free(emulbase, src);
1229 return error;
1232 /*********************************************************************************************/
1234 static LONG rename_object(struct emulbase * emulbase,
1235 struct filehandle *fh, STRPTR file, STRPTR newname)
1237 LONG ret = 0L;
1239 char *filename = NULL , *newfilename = NULL;
1241 ret = makefilename(emulbase, &filename, NULL, fh, file);
1242 if (!ret)
1244 ret = makefilename(emulbase, &newfilename, NULL, fh, newname);
1245 if (!ret)
1247 Forbid();
1248 ret = DoRename(filename,newfilename);
1249 Permit();
1250 ret = ret ? 0 : Errno();
1251 emul_free(emulbase, newfilename);
1253 emul_free(emulbase, filename);
1256 return ret;
1260 static LONG read_softlink(struct emulbase *emulbase,
1261 struct filehandle *fh,
1262 STRPTR buffer,
1263 ULONG size)
1265 /* TODO: implement symbolic links on pre-Vista using shell shortcuts
1267 if (DoReadLink(fh->name, buffer, size-1) == -1)
1268 return Errno();
1270 return 0L;*/
1271 return ERROR_ACTION_NOT_KNOWN;
1274 /*********************************************************************************************/
1276 ULONG parent_dir(struct emulbase *emulbase,
1277 struct filehandle *fh,
1278 char ** DirectoryName)
1280 *DirectoryName = pathname_from_name(emulbase, fh->name);
1281 D(bug("[emul] Parent directory: \"%s\"\n", *DirectoryName));
1282 return 0;
1285 /*********************************************************************************************/
1287 void parent_dir_post(struct emulbase *emulbase, char ** DirectoryName)
1289 /* free the previously allocated memory */
1290 emul_free(emulbase, *DirectoryName);
1291 **DirectoryName = 0;
1294 /*********************************************************************************************/
1296 /************************ Library entry points ************************/
1298 int loadhooks(struct emulbase *emulbase);
1300 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR emulbase)
1302 D(bug("Initializing emul_handler\n"));
1304 if (loadhooks(emulbase) != 0)
1305 return FALSE;
1307 InitSemaphore(&emulbase->memsem);
1309 emulbase->mempool = CreatePool(MEMF_ANY, 4096, 2000);
1310 if (!emulbase->mempool) return FALSE;
1312 if(!startup(emulbase))
1314 D(bug("emul_handler initialized OK\n"));
1315 return TRUE;
1318 DeletePool(emulbase->mempool);
1320 D(bug("emul_handler startup failed\n"));
1322 return FALSE;
1325 /*********************************************************************************************/
1327 static BOOL new_volume(struct IOFileSys *iofs, struct emulbase *emulbase)
1329 struct filehandle *fhv;
1330 struct DosList *doslist;
1331 char *unixpath;
1333 /* Volume name and Unix path are encoded into DEVICE entry of
1334 MountList like this: <volumename>:<unixpath> */
1336 unixpath = iofs->io_Union.io_OpenDevice.io_DeviceName;
1337 unixpath = strchr(unixpath, ':');
1339 if (unixpath)
1341 char *sp;
1343 *unixpath++ = '\0';
1345 if ((sp = strchr(unixpath, '~')))
1347 char home[260];
1348 char *newunixpath = 0;
1349 char *sp_end;
1350 BOOL ok = FALSE;
1351 WORD cmplen;
1352 char tmp;
1353 ULONG err;
1355 /* "~<name>" means home of user <name> */
1357 for(sp_end = sp + 1;
1358 sp_end[0] != '\0' && sp_end[0] != '\\';
1359 sp_end++);
1361 cmplen = sp_end - sp - 1;
1362 /* temporariliy zero terminate name */
1363 tmp = sp[cmplen+1]; sp[cmplen+1] = '\0';
1365 err = GetHome(sp+1, home);
1367 sp[cmplen+1] = tmp;
1369 if (err)
1370 err = Errno_w2a(err);
1371 else {
1372 newunixpath = AllocVec(strlen(unixpath) + strlen(home) + 1, MEMF_CLEAR);
1373 if (newunixpath)
1375 strncpy(newunixpath, unixpath, sp - unixpath);
1376 strcat(newunixpath, home);
1377 strcat(newunixpath, sp_end);
1379 ok = TRUE;
1380 unixpath = newunixpath;
1384 if (!ok)
1386 unixpath = 0;
1387 if (newunixpath) FreeVec(newunixpath);
1391 if (unixpath)
1393 if (Stat(unixpath, NULL)>0)
1395 fhv=(struct filehandle *)AllocMem(sizeof(struct filehandle), MEMF_PUBLIC);
1396 if (fhv != NULL)
1398 fhv->hostname = unixpath;
1399 fhv->name = unixpath + strlen(unixpath);
1400 fhv->type = FHD_DIRECTORY;
1401 fhv->pathname = NULL; /* just to make sure... */
1402 fhv->volumename = iofs->io_Union.io_OpenDevice.io_DeviceName;
1404 if ((doslist = MakeDosEntry(fhv->volumename, DLT_VOLUME)))
1406 fhv->dl = doslist;
1407 doslist->dol_Ext.dol_AROS.dol_Unit=(struct Unit *)fhv;
1408 doslist->dol_Ext.dol_AROS.dol_Device=&emulbase->device;
1409 AddDosEntry(doslist);
1411 iofs->IOFS.io_Unit = (struct Unit *)fhv;
1412 iofs->IOFS.io_Device = &emulbase->device;
1414 SendEvent(emulbase, IECLASS_DISKINSERTED);
1416 return TRUE;
1418 } /* if ((doslist = MakeDosEntry(fhv->volumename, DLT_VOLUME))) */
1420 FreeMem(fhv, sizeof(struct filehandle));
1422 } /* if (fhv != NULL)*/
1424 } /* if (!Stat(unixpath, &st)) */
1426 } /* if (unixpath) */
1428 } /* if (unixpath) */
1429 return FALSE;
1432 /*********************************************************************************************/
1434 static int GM_UNIQUENAME(Open)
1436 LIBBASETYPEPTR emulbase,
1437 struct IOFileSys *iofs,
1438 ULONG unitnum,
1439 ULONG flags
1442 /* Keep compiler happy */
1443 unitnum=0;
1444 flags=0;
1446 if (DOSBase == NULL)
1447 DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 41);
1449 if (DOSBase == NULL || !new_volume(iofs, emulbase))
1451 iofs->IOFS.io_Error = -1;
1452 return FALSE;
1455 /* Set returncode */
1456 iofs->IOFS.io_Error=0;
1457 return TRUE;
1460 /*********************************************************************************************/
1462 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
1463 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
1465 /*********************************************************************************************/
1467 AROS_LH1(void, beginio,
1468 AROS_LHA(struct IOFileSys *, iofs, A1),
1469 struct emulbase *, emulbase, 5, emul_handler)
1471 AROS_LIBFUNC_INIT
1473 LONG error = 0;
1475 /* WaitIO will look into this */
1476 iofs->IOFS.io_Message.mn_Node.ln_Type=NT_MESSAGE;
1479 Do everything quick no matter what. This is possible
1480 because I never need to Wait().
1482 switch(iofs->IOFS.io_Command)
1484 case FSA_OPEN:
1485 D(bug("[emul] FSA_OPEN(\"%s\")\n", iofs->io_Union.io_OPEN.io_Filename));
1486 error = open_(emulbase, (struct filehandle **)&iofs->IOFS.io_Unit,
1487 iofs->io_Union.io_OPEN.io_Filename, iofs->io_Union.io_OPEN.io_FileMode, 0, TRUE);
1488 if (
1489 (error == ERROR_WRITE_PROTECTED) &&
1490 (iofs->io_Union.io_OPEN.io_FileMode & FMF_AMIGADOS)
1493 D(bug("[emul] Retrying in read mode\n"));
1494 error = open_(emulbase, (struct filehandle **)&iofs->IOFS.io_Unit,
1495 iofs->io_Union.io_OPEN.io_Filename, iofs->io_Union.io_OPEN.io_FileMode & (~FMF_WRITE), 0, TRUE);
1497 D(bug("[emul] FSA_OPEN returning %lu\n", error));
1499 break;
1501 case FSA_CLOSE:
1502 D(bug("[emul] FSA_CLOSE\n"));
1503 error = free_lock(emulbase, (struct filehandle *)iofs->IOFS.io_Unit);
1504 D(bug("[emul] FSA_CLOSE returning %lu\n", error));
1505 break;
1507 case FSA_READ:
1509 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
1511 if (fh->type == FHD_FILE)
1513 if (fh->fd == emulbase->stdout_handle)
1514 fh->fd = emulbase->stdin_handle;
1515 if (fh->fd == emulbase->stdin_handle) {
1516 DASYNC(bug("[emul] Reading %lu bytes asynchronously \n", iofs->io_Union.io_READ.io_Length));
1517 emulbase->ConsoleReader->fh = fh->fd;
1518 emulbase->ConsoleReader->addr = iofs->io_Union.io_READ.io_Buffer;
1519 emulbase->ConsoleReader->len = iofs->io_Union.io_READ.io_Length;
1520 emulbase->ConsoleReader->sig = SIGF_DOS;
1521 emulbase->ConsoleReader->task = FindTask(NULL);
1522 emulbase->ConsoleReader->cmd = ASYNC_CMD_READ;
1523 SetSignal(0, emulbase->ConsoleReader->sig);
1524 if (RaiseEvent(emulbase->ConsoleReader->CmdEvent)) {
1525 Wait(emulbase->ConsoleReader->sig);
1526 DASYNC(bug("[emul] Read %ld bytes, error %lu\n", emulbase->EmulMsg.actual, emulbase->EmulMsg.error));
1527 iofs->io_Union.io_READ.io_Length = emulbase->ConsoleReader->actual;
1528 error = Errno_w2a(emulbase->ConsoleReader->error);
1529 if (!error) {
1530 char *c, *d;
1532 c = iofs->io_Union.io_READ.io_Buffer;
1533 d = c;
1534 while (*c) {
1535 if ((c[0] == '\r') && (c[1] == '\n')) {
1536 c++;
1537 iofs->io_Union.io_READ.io_Length--;
1539 *d++ = *c++;
1542 } else {
1543 DASYNC(bug("[emul] FSA_READ: RaiseEvent() failed!\n"));
1544 error = ERROR_UNKNOWN;
1546 } else {
1547 Forbid();
1548 error = DoRead(fh->fd, iofs->io_Union.io_READ.io_Buffer, iofs->io_Union.io_READ.io_Length, &iofs->io_Union.io_READ.io_Length, NULL);
1549 Permit();
1550 error = error ? 0 : Errno();
1553 else
1555 error = ERROR_OBJECT_WRONG_TYPE;
1558 break;
1561 case FSA_WRITE:
1563 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
1565 if (fh->type == FHD_FILE)
1567 if (fh->fd == emulbase->stdin_handle)
1568 fh->fd=emulbase->stdout_handle;
1569 Forbid();
1570 error = DoWrite(fh->fd, iofs->io_Union.io_WRITE.io_Buffer, iofs->io_Union.io_WRITE.io_Length, &iofs->io_Union.io_WRITE.io_Length, NULL);
1571 Permit();
1572 error = error ? 0 : Errno();
1574 else
1576 error = ERROR_OBJECT_WRONG_TYPE;
1579 break;
1582 case FSA_SEEK:
1584 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
1586 DSEEK(bug("[emul] FSA_SEEK, mode %ld, offset %llu\n", iofs->io_Union.io_SEEK.io_SeekMode, iofs->io_Union.io_SEEK.io_Offset));
1587 error = seek_file(fh, &iofs->io_Union.io_SEEK, NULL);
1588 DSEEK(bug("[emul] FSA_SEEK returning %lu\n", error));
1589 break;
1591 case FSA_SET_FILE_SIZE:
1593 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
1594 UQUAD newpos;
1595 LONG error2;
1597 DFSIZE(bug("[emul] FSA_SET_FILE_SIZE, mode %ld, offset %llu\n", iofs->io_Union.io_SET_FILE_SIZE.io_SeekMode, iofs->io_Union.io_SET_FILE_SIZE.io_Offset));
1598 /* First seek to the requested position. io_Offset will contain OLD position after that. NEW position will be in newpos */
1599 error = seek_file(fh, &iofs->io_Union.io_SEEK, &newpos);
1600 if (!error) {
1601 /* Set EOF to NEW position */
1602 Forbid();
1603 error = SetEOF(fh->fd);
1604 Permit();
1605 error = error ? 0 : Errno();
1606 /* If our OLD position was less than new file size, we seek back to it. io_Offset will again contain
1607 position before this seek - i. e. our NEW file size. */
1608 if (iofs->io_Union.io_SEEK.io_Offset < newpos) {
1609 iofs->io_Union.io_SEEK.io_SeekMode = OFFSET_BEGINNING;
1610 error2 = seek_file(fh, &iofs->io_Union.io_SEEK, NULL);
1611 if (!error)
1612 error = error2;
1613 } else
1614 iofs->io_Union.io_SEEK.io_Offset = newpos;
1616 D(bug("[emul] FSA_SET_FILE_SIZE returning %lu\n", error));
1617 break;
1619 case FSA_IS_INTERACTIVE:
1621 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
1623 if (fh->type == FHD_FILE)
1625 DB2(bug("[emul] GetFileType()\n"));
1626 Forbid();
1627 iofs->io_Union.io_IS_INTERACTIVE.io_IsInteractive = (GetFileType(fh->fd) == FILE_TYPE_CHAR) ? TRUE : FALSE;
1628 Permit();
1630 else
1632 iofs->io_Union.io_IS_INTERACTIVE.io_IsInteractive = FALSE;
1635 break;
1638 case FSA_SAME_LOCK:
1640 struct filehandle *lock1 = iofs->io_Union.io_SAME_LOCK.io_Lock[0],
1641 *lock2 = iofs->io_Union.io_SAME_LOCK.io_Lock[1];
1643 if (strcmp(lock1->hostname, lock2->hostname))
1645 iofs->io_Union.io_SAME_LOCK.io_Same = LOCK_DIFFERENT;
1647 else
1649 iofs->io_Union.io_SAME_LOCK.io_Same = LOCK_SAME;
1652 break;
1655 case FSA_EXAMINE:
1656 D(bug("[emul] FSA_EXAMINE\n"));
1657 error = examine(emulbase,
1658 (struct filehandle *)iofs->IOFS.io_Unit,
1659 iofs->io_Union.io_EXAMINE.io_ead,
1660 iofs->io_Union.io_EXAMINE.io_Size,
1661 iofs->io_Union.io_EXAMINE.io_Mode,
1662 &(iofs->io_DirPos));
1663 break;
1665 case FSA_EXAMINE_NEXT:
1666 D(bug("[emul] FSA_EXAMINE_NEXT\n"));
1667 error = examine_next(emulbase,
1668 (struct filehandle *)iofs->IOFS.io_Unit,
1669 iofs->io_Union.io_EXAMINE_NEXT.io_fib);
1670 break;
1672 case FSA_EXAMINE_ALL:
1673 D(bug("[emul] FSA_EXAMINE_ALL\n"));
1674 error = examine_all(emulbase,
1675 (struct filehandle *)iofs->IOFS.io_Unit,
1676 iofs->io_Union.io_EXAMINE_ALL.io_ead,
1677 iofs->io_Union.io_EXAMINE_ALL.io_eac,
1678 iofs->io_Union.io_EXAMINE_ALL.io_Size,
1679 iofs->io_Union.io_EXAMINE_ALL.io_Mode);
1680 break;
1682 case FSA_EXAMINE_ALL_END:
1683 CloseDir((struct filehandle *)iofs->IOFS.io_Unit);
1684 error = 0;
1685 break;
1687 case FSA_OPEN_FILE:
1688 D(bug("[emul] FSA_OPEN_FILE: name \"%s\", mode 0x%08lX)\n", iofs->io_Union.io_OPEN_FILE.io_Filename, iofs->io_Union.io_OPEN_FILE.io_FileMode));
1689 error = open_(emulbase, (struct filehandle **)&iofs->IOFS.io_Unit,
1690 iofs->io_Union.io_OPEN_FILE.io_Filename, iofs->io_Union.io_OPEN_FILE.io_FileMode,
1691 iofs->io_Union.io_OPEN_FILE.io_Protection, FALSE);
1692 if (
1693 (error == ERROR_WRITE_PROTECTED) &&
1694 (iofs->io_Union.io_OPEN_FILE.io_FileMode & FMF_AMIGADOS)
1697 D(bug("[emul] Retrying in read-only mode\n"));
1698 error = open_(emulbase,(struct filehandle **)&iofs->IOFS.io_Unit,
1699 iofs->io_Union.io_OPEN_FILE.io_Filename, iofs->io_Union.io_OPEN_FILE.io_FileMode & (~FMF_WRITE),
1700 iofs->io_Union.io_OPEN_FILE.io_Protection, FALSE);
1702 D(bug("[emul] FSA_OPEN_FILE returning %lu\n", error));
1703 break;
1705 case FSA_CREATE_DIR:
1706 error = create_dir(emulbase,
1707 (struct filehandle **)&iofs->IOFS.io_Unit,
1708 iofs->io_Union.io_CREATE_DIR.io_Filename,
1709 iofs->io_Union.io_CREATE_DIR.io_Protection);
1710 break;
1712 case FSA_CREATE_HARDLINK:
1713 D(bug("[emul] FSA_CREATE_HARDLINK: link name \"%s\"\n", iofs->io_Union.io_CREATE_HARDLINK.io_Filename));
1714 error = create_hardlink(emulbase,
1715 (struct filehandle *)iofs->IOFS.io_Unit,
1716 iofs->io_Union.io_CREATE_HARDLINK.io_Filename,
1717 (struct filehandle *)iofs->io_Union.io_CREATE_HARDLINK.io_OldFile);
1718 D(bug("[emul] FSA_CREATE_HARDLINK returning %lu\n", error));
1719 break;
1721 case FSA_CREATE_SOFTLINK:
1722 error = create_softlink(emulbase,
1723 (struct filehandle *)&iofs->IOFS.io_Unit,
1724 iofs->io_Union.io_CREATE_SOFTLINK.io_Filename,
1725 iofs->io_Union.io_CREATE_SOFTLINK.io_Reference);
1726 break;
1728 case FSA_RENAME:
1729 error = rename_object(emulbase,
1730 (struct filehandle *)iofs->IOFS.io_Unit,
1731 iofs->io_Union.io_RENAME.io_Filename,
1732 iofs->io_Union.io_RENAME.io_NewName);
1733 break;
1735 case FSA_READ_SOFTLINK:
1736 error = read_softlink(emulbase,
1737 (struct filehandle *)iofs->IOFS.io_Unit,
1738 iofs->io_Union.io_READ_SOFTLINK.io_Buffer,
1739 iofs->io_Union.io_READ_SOFTLINK.io_Size);
1740 break;
1742 case FSA_DELETE_OBJECT:
1743 error = delete_object(emulbase,
1744 (struct filehandle *)iofs->IOFS.io_Unit,
1745 iofs->io_Union.io_DELETE_OBJECT.io_Filename);
1746 break;
1748 case FSA_SET_PROTECT:
1749 error = set_protect(emulbase,
1750 (struct filehandle *)iofs->IOFS.io_Unit,
1751 iofs->io_Union.io_SET_PROTECT.io_Filename,
1752 iofs->io_Union.io_SET_PROTECT.io_Protection);
1753 break;
1755 case FSA_PARENT_DIR:
1756 /* error will always be 0 */
1757 error = parent_dir(emulbase,
1758 (struct filehandle *)iofs->IOFS.io_Unit,
1759 &(iofs->io_Union.io_PARENT_DIR.io_DirName));
1760 break;
1762 case FSA_PARENT_DIR_POST:
1763 /* error will always be 0 */
1764 error = 0;
1765 parent_dir_post(emulbase, &(iofs->io_Union.io_PARENT_DIR.io_DirName));
1766 break;
1768 case FSA_IS_FILESYSTEM:
1769 iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
1770 error = 0;
1771 break;
1773 case FSA_DISK_INFO:
1775 struct filehandle *fh = (struct filehandle *)iofs->IOFS.io_Unit;
1776 struct InfoData *id = iofs->io_Union.io_INFO.io_Info;
1778 error = StatFS(fh->hostname, id);
1779 if (error)
1780 error = Errno_w2a(error);
1781 else
1782 id->id_VolumeNode = fh->dl;
1783 break;
1785 /* FIXME: not supported yet
1786 case FSA_SET_COMMENT:
1787 case FSA_SET_OWNER:
1788 case FSA_SET_DATE:
1789 case FSA_MORE_CACHE:
1790 case FSA_MOUNT_MODE:
1791 case FSA_WAIT_CHAR:
1792 case FSA_FILE_MODE:*/
1793 default:
1794 DCMD(bug("[emul] Unknown action %lu\n", iofs->IOFS.io_Command));
1795 error = ERROR_ACTION_NOT_KNOWN;
1796 break;
1799 /* Set error code */
1800 iofs->io_DosError = error;
1802 /* If the quick bit is not set send the message to the port */
1803 if(!(iofs->IOFS.io_Flags & IOF_QUICK))
1805 ReplyMsg(&iofs->IOFS.io_Message);
1808 AROS_LIBFUNC_EXIT
1811 /*********************************************************************************************/
1813 AROS_LH1(LONG, abortio,
1814 AROS_LHA(struct IOFileSys *, iofs, A1),
1815 struct emulbase *, emulbase, 6, emul_handler)
1817 AROS_LIBFUNC_INIT
1819 /* Everything already done. */
1820 return 0;
1822 AROS_LIBFUNC_EXIT
1825 /*********************************************************************************************/
1827 const char *EmulSymbols[] = {
1828 "Emul_Init_Native",
1829 "EmulStat",
1830 "EmulDelete",
1831 "EmulGetHome",
1832 "EmulStatFS",
1833 NULL
1836 const char *KernelSymbols[] = {
1837 "CreateFileA",
1838 "CloseHandle",
1839 "ReadFile",
1840 "WriteFile",
1841 "SetFilePointer",
1842 "SetEndOfFile",
1843 "GetFileType",
1844 "GetStdHandle",
1845 "MoveFileA",
1846 "GetCurrentDirectoryA",
1847 "FindFirstFileA",
1848 "FindNextFileA",
1849 "FindClose",
1850 "CreateDirectoryA",
1851 "SetFileAttributesA",
1852 "GetLastError",
1853 "CreateHardLinkA",
1854 "CreateSymbolicLinkA",
1855 "SetEvent",
1856 NULL
1859 int loadhooks(struct emulbase *emulbase)
1861 ULONG r = 1;
1863 HostLibBase = OpenResource("hostlib.resource");
1864 if (!HostLibBase)
1865 return 1;
1866 D(kprintf("[EmulHandler] got hostlib.resource HostLibBase=%p\n", HostLibBase));
1868 emulbase->EmulHandle = HostLib_Open("Libs\\Host\\emul_handler.dll", NULL);
1869 if (emulbase->EmulHandle) {
1870 EmulIFace = (struct EmulInterface *)HostLib_GetInterface(emulbase->EmulHandle, EmulSymbols, &r);
1871 D(bug("[EmulHandler] Native library interface: 0x%08lX\n", EmulIFace));
1872 if (EmulIFace) {
1873 if (!r) {
1874 emulbase->KernelHandle = HostLib_Open("kernel32.dll", NULL);
1875 if (emulbase->KernelHandle) {
1876 KernelIFace = (struct KernelInterface *)HostLib_GetInterface(emulbase->KernelHandle, KernelSymbols, &r);
1877 if (KernelIFace) {
1878 D(bug("[EmulHandler] %lu unresolved symbols in kernel32.dll\n", r));
1879 if (r < 3) {
1880 D(bug("[EmulHandler] CreateHardLink() : 0x%08lX\n", KernelIFace->CreateHardLink));
1881 D(bug("[EmulHandler] CreateSymbolicLink() : 0x%08lX\n", KernelIFace->CreateSymbolicLink));
1882 KernelBase = OpenResource("kernel.resource");
1883 if (KernelBase)
1884 return 0;
1886 HostLib_DropInterface((APTR *)KernelIFace);
1888 D(else bug("[EmulHandler] Unable to get kernel32.dll interface!\n");)
1889 HostLib_Close(emulbase->KernelHandle, NULL);
1892 D(else bug("[EmulHandler] %lu unresolved symbols!\n", r);)
1893 HostLib_DropInterface((APTR *)EmulIFace);
1895 D(else bug("[EmulHandler] Unable go get host-side library interface!\n"));
1896 HostLib_Close(emulbase->EmulHandle, NULL);
1898 D(else bug("[EmulHandler] Unable to open emul.handler host-side library!\n"));
1899 return 1;