Added a test for MUIA_Listview_SelectChange.
[AROS.git] / arch / all-mingw32 / filesys / emul_handler / emul_host.c
blob944ce8261c32d66a2d8254d8c1d74f9343b63622
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 Low-level host-dependent subroutines for Windows.
7 Lang: english
8 */
10 /*********************************************************************************************/
12 #define DEBUG 0
13 #define DERROR(x)
14 #define DEXAM(x)
15 #define DFSIZE(x)
16 #define DLINK(x)
17 #define DLOCK(x)
18 #define DOPEN(x)
19 #define DOPEN2(x)
20 #define DSEEK(x)
21 #define DSTATFS(x)
22 #define DWRITE(x)
23 #define DASYNC(x)
25 #include <aros/debug.h>
26 #include <aros/kernel.h>
27 #include <aros/system.h>
28 #include <aros/symbolsets.h>
29 #include <exec/memory.h>
30 #include <proto/exec.h>
31 #include <utility/tagitem.h>
32 #include <utility/hooks.h>
33 #include <dos/exall.h>
34 #include <dos/dosasl.h>
35 #include <dos/bptr.h>
36 #include <proto/arossupport.h>
37 #include <proto/dos.h>
38 #include <proto/hostlib.h>
39 #include <proto/kernel.h>
41 #include <limits.h>
42 #include <string.h>
44 #include "emul_intern.h"
46 /*********************************************************************************************/
48 /* Make Windows protection bits out of AROS protection bits. */
49 static ULONG prot_a2w(ULONG protect)
51 ULONG uprot = 0;
53 /* The following flags are low-active! */
54 if ((protect & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE))
55 uprot = FILE_ATTRIBUTE_READONLY;
56 /* The following flags are high-active again. */
57 if (protect & FIBF_ARCHIVE)
58 uprot |= FILE_ATTRIBUTE_ARCHIVE;
59 if (protect & FIBF_SCRIPT)
60 uprot |= FILE_ATTRIBUTE_SYSTEM;
62 /* TODO: 1) Support more NT-specific attributes ('Executable')
63 2) Write complete AROS protection bits support using NTFS streams */
65 return uprot;
68 /*********************************************************************************************/
70 /* Make AROS protection bits out of Windows protection bits. */
71 static ULONG prot_w2a(ULONG protect)
73 ULONG uprot = 0;
75 /* The following three flags are low-active! */
76 if (protect & FILE_ATTRIBUTE_READONLY)
77 uprot = FIBF_WRITE|FIBF_DELETE;
78 if (protect & FILE_ATTRIBUTE_DIRECTORY)
79 uprot |= FIBF_EXECUTE;
80 /* The following flags are high-active again. */
81 if (protect & FILE_ATTRIBUTE_ARCHIVE)
82 uprot |= FIBF_ARCHIVE;
83 if (protect & FILE_ATTRIBUTE_SYSTEM)
84 uprot |= FIBF_SCRIPT;
86 /* TODO: 1) Support more NT-specific attributes ('Executable')
87 2) Write complete AROS protection bits support using NTFS streams */
89 return uprot;
92 /*********************************************************************************************/
94 static void FileTime2DateStamp(struct DateStamp *ds, UQUAD ft)
96 UQUAD totalmins;
98 /* Adjust from 01.01.1601 to 01.01.1978. This offset was calculated using a specially written program
99 which puts "01.01.1978 00:00:00" into SYSTEMTIME structure and converts it into FILETIME. */
100 ft -= 118969344000000000LL;
101 /* Adjust interval from 100 ns to 1/50 sec */
102 ft /= 200000;
103 totalmins = ft / (60*50);
104 ds->ds_Days = totalmins / (24*60);
105 ds->ds_Minute = totalmins % (24*60);
106 ds->ds_Tick = ft % (60*50);
109 /*********************************************************************************************/
111 static UQUAD DateStamp2FileTime(struct DateStamp *ds)
113 UQUAD ticks;
115 /* Get total number of minutes */
116 ticks = ds->ds_Days * (24*60) + ds->ds_Minute;
117 /* Convert to ticks and add ds_Tick */
118 ticks = ticks * (60*50) + ds->ds_Tick;
120 return ticks * 200000 + 118969344000000000LL;
123 /*********************************************************************************************/
125 /* Make an AROS error-code (<dos/dos.h>) out of a Windows error-code. */
126 static ULONG u2a[][2]=
128 { ERROR_PATH_NOT_FOUND , ERROR_OBJECT_NOT_FOUND },
129 { ERROR_NO_MORE_FILES , ERROR_NO_MORE_ENTRIES },
130 { ERROR_NOT_ENOUGH_MEMORY , ERROR_NO_FREE_STORE },
131 { ERROR_FILE_NOT_FOUND , ERROR_OBJECT_NOT_FOUND },
132 { ERROR_FILE_EXISTS , ERROR_OBJECT_EXISTS },
133 { ERROR_WRITE_PROTECT , ERROR_WRITE_PROTECTED },
134 { WIN32_ERROR_DISK_FULL , ERROR_DISK_FULL },
135 { ERROR_DIR_NOT_EMPTY , ERROR_DIRECTORY_NOT_EMPTY },
136 { ERROR_SHARING_VIOLATION , ERROR_OBJECT_IN_USE },
137 { ERROR_LOCK_VIOLATION , ERROR_OBJECT_IN_USE },
138 { WIN32_ERROR_BUFFER_OVERFLOW , ERROR_OBJECT_TOO_LARGE },
139 { ERROR_INVALID_NAME , ERROR_OBJECT_NOT_FOUND },
140 { ERROR_HANDLE_EOF , 0 },
141 { 0 , 0 }
144 static ULONG Errno_w2a(ULONG e, LONG mode)
146 ULONG i;
148 DERROR(printf("[EmulHandler] Windows error code: %lu\n", e));
150 /* ERROR_ACCESS_DENIED may mean different AmigaDOS errors depending
151 on the context */
152 if (e == ERROR_ACCESS_DENIED)
154 if (mode == MODE_OLDFILE)
155 return ERROR_READ_PROTECTED;
157 if (mode == MODE_READWRITE || mode == MODE_NEWFILE)
158 return ERROR_WRITE_PROTECTED;
160 if (mode == 0)
161 return ERROR_DELETE_PROTECTED;
163 return ERROR_READ_PROTECTED;
166 for(i=0;i<sizeof(u2a)/sizeof(u2a[0]);i++)
168 if(u2a[i][0]==e) {
169 DERROR(printf("[EmulHandler] Translated to AROS error code: %lu\n", u2a[i][1]));
170 return u2a[i][1];
174 DERROR(printf("[EmulHandler] Unknown error code\n"));
175 return ERROR_UNKNOWN;
178 /*********************************************************************************************/
180 /* Free a filehandle */
181 void DoClose(struct emulbase *emulbase, struct filehandle *current)
183 DLOCK(bug("[emul] Lock type = %lu\n", current->type));
184 switch(current->type)
186 case FHD_FILE:
187 /* Nothing will happen if type has FHD_STDIO set, this is intentional */
188 DLOCK(bug("[emul] CloseHandle(), fd = 0x%08lX\n", current->fd));
190 Forbid();
191 emulbase->pdata.KernelIFace->CloseHandle(current->fd);
192 Permit();
193 break;
195 case FHD_DIRECTORY:
196 if (current->fd != INVALID_HANDLE_VALUE)
198 DLOCK(bug("[emul] Closing directory search handle\n"));
199 Forbid();
200 emulbase->pdata.KernelIFace->FindClose(current->fd);
201 Permit();
204 if (current->ph.pathname)
206 DLOCK(bug("[emul] Freeing directory search path\n"));
207 FreeVecPooled(emulbase->mempool, current->ph.pathname);
209 break;
212 DLOCK(bug("[emul] Done\n"));
215 /*********************************************************************************************/
217 LONG DoOpen(struct emulbase *emulbase, struct filehandle *fh, LONG access, LONG mode, LONG protect, BOOL AllowDir)
219 ULONG kind;
221 DOPEN(bug("[emul] DoOpen(), directories allowed: %lu\n", AllowDir));
222 DOPEN(bug("[emul] AROS object name: %s, host object name: %s\n", fh->name, fh->hostname));
224 Forbid();
225 kind = emulbase->pdata.KernelIFace->GetFileAttributes(fh->hostname);
226 Permit();
228 DOPEN(bug("[emul] Object attributes: 0x%08X\n", kind));
230 /* Non-existing objects can be files opened for writing */
231 if (kind == INVALID_FILE_ATTRIBUTES)
232 kind = 0;
234 if (kind & FILE_ATTRIBUTE_DIRECTORY)
236 /* file is a directory */
237 if (!AllowDir)
238 return ERROR_OBJECT_WRONG_TYPE;
240 fh->type = FHD_DIRECTORY;
241 fh->fd = INVALID_HANDLE_VALUE;
242 fh->ph.dirpos = 0;
244 else
246 ULONG flags = GENERIC_READ | GENERIC_WRITE;
248 * FILE_SHARE_WRITE looks strange here, however without it i can't reopen file which
249 * is already open with MODE_OLDFILE, even just for reading with Read()
251 ULONG lock = FILE_SHARE_READ | FILE_SHARE_WRITE;
252 ULONG create, err;
254 DOPEN2(bug("[emul] Open file \"%s\", mode 0x%08lX\n", fh->hostname, mode));
256 switch (mode)
258 case MODE_NEWFILE:
259 flags = GENERIC_WRITE; /* Only for writing */
260 lock = 0; /* This will be an exclusive lock */
261 create = CREATE_ALWAYS;
262 break;
264 case MODE_READWRITE:
265 create = OPEN_ALWAYS;
266 break;
268 default: /* MODE_OLDFILE */
269 create = OPEN_EXISTING;
270 break;
274 * On post-XP systems files with 'system' attribute may be opened for writing
275 * only if we specify FILE_ATTRIBUTE_SYSTEM in CreateFile() call. So we keep
276 * if from kind value retrieved earlier by GetFileAttributes().
278 protect = prot_a2w(protect) | (kind & FILE_ATTRIBUTE_SYSTEM);
280 DOPEN2(bug("[emul] CreateFile: flags 0x%08lX, lock 0x%08lX, create %lu\n", flags, lock, create));
281 Forbid();
283 fh->fd = emulbase->pdata.KernelIFace->CreateFile(fh->hostname, flags, lock, NULL, create, protect, NULL);
285 if ((mode == MODE_OLDFILE) && (fh->fd == INVALID_HANDLE_VALUE))
288 * Hack against two problems:
290 * Problem 1: dll's in LIBS:Host and AROSBootstrap.exe are locked against writing by
291 * Windows while AROS is running. However we may still read them. MODE_OLDFILE
292 * also requests write access with shared lock, this is why it fails on these files.
294 * Problem 2: MODE_OLDFILE requests write access, which fails on files with read-only attribute.
296 * Here we try to work around these problems by attempting to open the file in read-only mode
297 * when we discover one of them.
299 * I hope this will not affect files really open in AROS because exclusive lock
300 * disallows read access too.
302 err = emulbase->pdata.KernelIFace->GetLastError();
304 DOPEN2(bug("[emul] Windows error: %u\n", err));
305 switch (err)
307 case ERROR_SHARING_VIOLATION:
308 case ERROR_ACCESS_DENIED:
309 fh->fd = emulbase->pdata.KernelIFace->CreateFile(fh->hostname, GENERIC_READ, lock, NULL, OPEN_EXISTING, protect, NULL);
313 err = emulbase->pdata.KernelIFace->GetLastError();
315 Permit();
317 DOPEN2(bug("[emul] FileHandle = 0x%08lX\n", fh->fd));
319 if (fh->fd == INVALID_HANDLE_VALUE)
320 return Errno_w2a(err, mode);
322 fh->type = FHD_FILE;
325 return 0;
328 /*********************************************************************************************/
330 LONG DoRead(struct emulbase *emulbase, struct filehandle *fh, APTR buff, ULONG len, SIPTR *err)
332 ULONG res;
333 ULONG werr;
335 if (fh->type & FHD_STDIO)
337 /* FIXME: This is not thread-safe. */
338 struct AsyncReaderControl *reader = emulbase->pdata.ConsoleReader;
340 DASYNC(bug("[emul] Reading %lu bytes asynchronously \n", len));
341 reader->fh = fh->fd;
342 reader->addr = buff;
343 reader->len = len;
344 reader->sig = SIGF_DOS;
345 reader->task = FindTask(NULL);
346 reader->cmd = ASYNC_CMD_READ;
347 SetSignal(0, reader->sig);
349 Forbid();
350 res = emulbase->pdata.KernelIFace->SetEvent(reader->CmdEvent);
351 werr = emulbase->pdata.KernelIFace->GetLastError();
352 Permit();
354 if (res)
356 Wait(reader->sig);
358 DASYNC(bug("[emul] Read %ld bytes, error %lu\n", reader->.actual, reader->error));
359 len = reader->actual;
360 werr = reader->error;
362 if (werr)
363 res = FALSE;
364 else
366 char *c, *d;
368 c = buff;
369 d = c;
370 while (*c) {
371 if ((c[0] == '\r') && (c[1] == '\n')) {
372 c++;
373 len--;
375 *d++ = *c++;
380 else
382 Forbid();
383 res = emulbase->pdata.KernelIFace->ReadFile(fh->fd, buff, len, &len, NULL);
384 werr = emulbase->pdata.KernelIFace->GetLastError();
385 Permit();
388 if (res)
390 *err = 0;
391 return len;
393 else
395 *err = Errno_w2a(werr, MODE_OLDFILE);
396 return -1;
400 LONG DoWrite(struct emulbase *emulbase, struct filehandle *fh, CONST_APTR buff, ULONG len, SIPTR *err)
402 ULONG success, werr;
404 Forbid();
405 success = emulbase->pdata.KernelIFace->WriteFile(fh->fd, (void *)buff, len, &len, NULL);
406 werr = emulbase->pdata.KernelIFace->GetLastError();
407 Permit();
409 DWRITE(bug("[emul] Write handle 0x%p: success %d, error %d\n", fh, success, werr));
411 if (success)
413 *err = 0;
414 return len;
416 else
418 *err = Errno_w2a(werr, MODE_NEWFILE);
420 return -1;
425 * This routine stores (absolute) original position in pOffset,
426 * and new position in newpos.
427 * Used in DoSeek() and DoSetSize().
429 static LONG seek_file(struct emulbase *emulbase, void *fd, SIPTR *pOffset, ULONG mode, UQUAD *newpos)
431 ULONG error, werror;
432 ULONG pos_high = 0;
433 UQUAD oldpos;
434 UQUAD offset = *pOffset;
436 DB2(bug("[emul] LSeek() - getting current position\n"));
437 Forbid();
438 oldpos = emulbase->pdata.KernelIFace->SetFilePointer(fd, 0, &pos_high, FILE_CURRENT);
439 Permit();
440 oldpos |= (UQUAD)pos_high << 32;
441 DSEEK(bug("[emul] Original position: %llu\n", oldpos));
443 switch(mode)
445 case OFFSET_BEGINNING:
446 mode = FILE_BEGIN;
447 break;
449 case OFFSET_CURRENT:
450 mode = FILE_CURRENT;
451 break;
453 default:
454 mode = FILE_END;
457 pos_high = offset >> 32;
458 DB2(bug("[emul] LSeek() - setting new position\n"));
459 Forbid();
460 error = emulbase->pdata.KernelIFace->SetFilePointer(fd, offset, &pos_high, mode);
461 werror = emulbase->pdata.KernelIFace->GetLastError();
462 Permit();
464 if (error == (ULONG)-1)
465 error = Errno_w2a(werror, MODE_OLDFILE);
466 else
468 if (newpos)
470 *newpos = error;
471 *newpos |= (UQUAD)pos_high << 32;
473 error = 0;
475 offset = oldpos;
478 *pOffset = offset;
480 return error;
483 SIPTR DoSeek(struct emulbase *emulbase, struct filehandle *fh, SIPTR offset, ULONG mode, SIPTR *err)
485 LONG error;
487 DSEEK(bug("[emul] DoSeek(0x%p, %ld, %d)\n", fh, offset, mode));
489 error = seek_file(emulbase, fh->fd, &offset, mode, NULL);
491 *err = error;
492 return error ? -1 : offset;
495 /*********************************************************************************************/
497 LONG DoMkDir(struct emulbase *emulbase, struct filehandle *fh, ULONG protect)
499 ULONG ret, werror;
501 Forbid();
502 ret = emulbase->pdata.KernelIFace->CreateDirectory(fh->hostname, NULL);
503 werror = emulbase->pdata.KernelIFace->GetLastError();
504 Permit();
506 if (ret)
508 fh->type = FHD_DIRECTORY;
509 fh->fd = INVALID_HANDLE_VALUE;
510 fh->ph.dirpos = 0;
512 Forbid();
513 emulbase->pdata.KernelIFace->SetFileAttributes(fh->hostname, prot_a2w(protect));
514 Permit();
516 return 0;
518 return Errno_w2a(werror, MODE_NEWFILE);
521 /*********************************************************************************************/
523 LONG DoDelete(struct emulbase *emulbase, char *file)
525 ULONG ret, err;
527 Forbid();
529 ret = emulbase->pdata.KernelIFace->GetFileAttributes(file);
530 if (ret != INVALID_FILE_ATTRIBUTES)
532 if (ret & FILE_ATTRIBUTE_DIRECTORY)
533 ret = emulbase->pdata.KernelIFace->RemoveDirectory(file);
534 else
535 ret = emulbase->pdata.KernelIFace->_DeleteFile(file);
537 else
538 ret = 0;
540 err = emulbase->pdata.KernelIFace->GetLastError();
542 Permit();
544 return ret ? 0 : Errno_w2a(err, 0);
547 /*********************************************************************************************/
549 LONG DoChMod(struct emulbase *emulbase, char *filename, ULONG aprot)
551 LONG ret;
552 ULONG err;
554 aprot = prot_a2w(aprot);
556 Forbid();
557 ret = emulbase->pdata.KernelIFace->SetFileAttributes(filename, aprot);
558 err = emulbase->pdata.KernelIFace->GetLastError();
559 Permit();
561 return ret ? 0 : Errno_w2a(err, MODE_READWRITE);
564 /*********************************************************************************************/
566 ULONG examine_start(struct emulbase *emulbase, struct filehandle *fh)
568 char *c;
569 ULONG len;
571 if (fh->type != FHD_DIRECTORY)
572 return ERROR_OBJECT_WRONG_TYPE;
574 if (!fh->ph.pathname)
576 DEXAM(bug("[emul] Creating search path for object: %s\n", fh->hostname));
577 len = strlen(fh->hostname);
578 fh->ph.pathname = AllocVecPooled(emulbase->mempool, len + 3);
579 if (!fh->ph.pathname)
580 return ERROR_NO_FREE_STORE;
582 CopyMem(fh->hostname, fh->ph.pathname, len);
583 c = fh->ph.pathname + len;
584 strcpy(c, "\\*");
586 DEXAM(bug("[emul] Created search path: %s\n", fh->ph.pathname));
587 return 0;
590 /*********************************************************************************************/
592 /* Reset dirpos in directory handle and close existing search handle */
593 LONG DoRewindDir(struct emulbase *emulbase, struct filehandle *fh)
595 ULONG r, err;
597 if (fh->fd != INVALID_HANDLE_VALUE)
599 Forbid();
600 r = emulbase->pdata.KernelIFace->FindClose(fh->fd);
601 err = emulbase->pdata.KernelIFace->GetLastError();
602 Permit();
604 if (!r)
605 return Errno_w2a(err, MODE_OLDFILE);
607 fh->fd = INVALID_HANDLE_VALUE;
610 fh->ph.dirpos = 0;
611 return 0;
614 /*********************************************************************************************/
616 #define is_special_dir(x) (x[0] == '.' && (!x[1] || (x[1] == '.' && !x[2])))
618 /* Positions to dirpos in directory, retrieves next item in it and updates dirpos */
619 static ULONG ReadDir(struct emulbase *emulbase, struct filehandle *fh, LPWIN32_FIND_DATA FindData, IPTR *dirpos)
621 ULONG res;
624 * Windows does not support positioning within directory. The only thing i can do is to
625 * scan the directory in forward direction. In order to bypass this limitation we do the
626 * following:
627 * 1. Before starting we explicitly set current position (dirpos) to 0. Examine() will place
628 * it into our fib_DiskKey; in case of ExAll() this is eac_LastKey. We also maintain second
629 * directory position counter - in our directory handle. It reflects the real position of
630 * our file search handle.
631 * 2. Here we compare position in dirpos with position in the handle. If dirpos is smaller than
632 * filehandle's counter, we have to rewind the directory. This is done by closing the search
633 * handle in order to be able to restart from the beginning and setting handle's counter to 0.
635 DEXAM(bug("[emul] Current dirpos %lu, requested %lu\n", fh->ph.dirpos, *dirpos));
636 if (fh->ph.dirpos > *dirpos)
638 DEXAM(bug("[emul] Resetting search handle\n"));
639 DoRewindDir(emulbase, fh);
645 * 3. Now we will scan the next directory entry until its index is greater than original index
646 * in dirpos. This means that we've repositioned and scanned the next entry. After this we
647 * update dirpos.
651 ULONG err;
653 if (fh->fd == INVALID_HANDLE_VALUE)
655 DEXAM(bug("[emul] Finding first file\n"));
656 Forbid();
657 fh->fd = emulbase->pdata.KernelIFace->FindFirstFile(fh->ph.pathname, FindData);
658 err = emulbase->pdata.KernelIFace->GetLastError();
659 Permit();
660 res = (fh->fd != INVALID_HANDLE_VALUE);
662 else
664 Forbid();
665 res = emulbase->pdata.KernelIFace->FindNextFile(fh->fd, FindData);
666 err = emulbase->pdata.KernelIFace->GetLastError();
667 Permit();
669 if (!res)
670 return Errno_w2a(err, MODE_OLDFILE);
672 fh->ph.dirpos++;
673 DEXAM(bug("[emul] Found %s, position %lu\n", FindData->cFileName, fh->ph.dirpos));
674 } while (fh->ph.dirpos <= *dirpos);
675 (*dirpos)++;
676 DEXAM(bug("[emul] New dirpos: %lu\n", *dirpos));
678 * We also skip "." and ".." entries (however we count their indexes - just in case), because
679 * AmigaOS donesn't have them.
681 } while (is_special_dir(FindData->cFileName));
683 return 0;
686 /*********************************************************************************************/
688 static ULONG DoExamineEntry_sub(struct emulbase *emulbase, struct filehandle *fh, STRPTR FoundName, WIN32_FILE_ATTRIBUTE_DATA *FIB)
690 STRPTR filename, name;
691 ULONG plen, flen;
692 ULONG error = 0;
693 ULONG werr;
695 DEXAM(bug("[emul] DoExamineEntry_sub(): filehandle's path: %s\n", fh->hostname));
696 if (FoundName)
698 DEXAM(bug("[emul] ...containing object: %s\n", FoundName));
699 plen = strlen(fh->hostname);
700 flen = strlen(FoundName);
701 name = AllocVecPooled(emulbase->mempool, plen + flen + 2);
702 if (!name)
703 return ERROR_NO_FREE_STORE;
705 strcpy(name, fh->hostname);
706 filename = name + plen;
707 *filename++ = '\\';
708 strcpy(filename, FoundName);
710 else
711 name = fh->hostname;
713 DEXAM(bug("[emul] Full name: %s\n", name));
714 Forbid();
715 error = emulbase->pdata.KernelIFace->GetFileAttributesEx(name, 0, FIB);
716 werr = emulbase->pdata.KernelIFace->GetLastError();
717 Permit();
719 if (FoundName)
721 DEXAM(bug("[emul] Freeing full name\n"));
722 FreeVecPooled(emulbase->mempool, name);
725 return error ? 0 : Errno_w2a(werr, MODE_OLDFILE);
728 /*********************************************************************************************/
730 LONG DoExamineEntry(struct emulbase *emulbase, struct filehandle *fh, char *FoundName,
731 struct ExAllData *ead, ULONG size, ULONG type)
733 STRPTR next, last, end, name;
734 WIN32_FILE_ATTRIBUTE_DATA FIB;
735 ULONG error;
737 /* Check, if the supplied buffer is large enough. */
738 next=(STRPTR)ead+sizes[type];
739 end =(STRPTR)ead+size;
741 if(next > end)
743 DEXAM(bug("[emul] DoExamineEntry(): end of buffer\n"));
744 return ERROR_BUFFER_OVERFLOW;
747 error = DoExamineEntry_sub(emulbase, fh, FoundName, &FIB);
748 if (error)
749 return error;
751 DEXAM(bug("[emul] Filling in object information\n"));
752 switch(type)
754 default:
755 case ED_OWNER:
756 ead->ed_OwnerUID = 0;
757 ead->ed_OwnerGID = 0;
758 case ED_COMMENT:
759 ead->ed_Comment = NULL;
760 /* TODO: Write Windows shell-compatible comments support using NTFS streams */
761 case ED_DATE:
762 FileTime2DateStamp((struct DateStamp *)&ead->ed_Days, FIB.ftLastWriteTime);
763 case ED_PROTECTION:
764 ead->ed_Prot = prot_w2a(FIB.dwFileAttributes);
765 case ED_SIZE:
766 ead->ed_Size = FIB.nFileSizeLow;
767 case ED_TYPE:
768 if (FIB.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
770 if (FoundName || fh->name[0])
771 ead->ed_Type = ST_USERDIR;
772 else
773 ead->ed_Type = ST_ROOT;
775 else
776 ead->ed_Type = ST_FILE;
777 case ED_NAME:
778 if (FoundName)
779 last = FoundName;
780 else if (*fh->name) {
781 name = fh->name;
782 last = name;
783 while(*name)
784 if(*name++=='\\')
785 last = name;
786 } else
787 last = fh->volumename;
788 ead->ed_Name=next;
789 for(;;)
791 if (next>=end)
792 return ERROR_BUFFER_OVERFLOW;
793 if (!(*next++=*last++))
794 break;
796 case 0:
797 ead->ed_Next=(struct ExAllData *)(((IPTR)next+AROS_PTRALIGN-1)&~(AROS_PTRALIGN-1));
798 return 0;
802 /*********************************************************************************************/
804 LONG DoExamineNext(struct emulbase *emulbase, struct filehandle *fh, struct FileInfoBlock *FIB)
806 char *src, *dest;
807 ULONG res;
808 WIN32_FIND_DATA FindData;
809 WIN32_FILE_ATTRIBUTE_DATA AttrData;
811 res = examine_start(emulbase, fh);
812 if (res)
813 return res;
815 res = ReadDir(emulbase, fh, &FindData, &FIB->fib_DiskKey);
816 if (!res)
817 res = DoExamineEntry_sub(emulbase, fh, FindData.cFileName, &AttrData);
818 if (res)
820 DoRewindDir(emulbase, fh);
821 return res;
824 FIB->fib_OwnerUID = 0;
825 FIB->fib_OwnerGID = 0;
826 FIB->fib_Comment[0] = '\0'; /* TODO: no comments available yet! */
827 FIB->fib_Protection = prot_w2a(AttrData.dwFileAttributes);
828 FIB->fib_Size = AttrData.nFileSizeLow;
830 FileTime2DateStamp(&FIB->fib_Date, AttrData.ftLastWriteTime);
831 if (AttrData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
832 FIB->fib_DirEntryType = ST_USERDIR;
833 else
834 FIB->fib_DirEntryType = ST_FILE;
836 src = FindData.cFileName;
837 dest = &FIB->fib_FileName[1];
838 for (res = 0; res<MAXFILENAMELENGTH-1; res++)
840 if (!(*dest++=*src++))
841 break;
843 FIB->fib_FileName[0] = res;
844 return 0;
847 /*********************************************************************************************/
849 LONG DoExamineAll(struct emulbase *emulbase, struct filehandle *fh, struct ExAllData *ead,
850 struct ExAllControl *eac, ULONG size, ULONG type, struct DosLibrary *DOSBase)
852 struct ExAllData *last = NULL;
853 STRPTR end = (STRPTR)ead + size;
854 LONG error;
855 WIN32_FIND_DATA FindData;
857 DEXAM(bug("[emul] DoExamineAll(%s)\n", fh->hostname));
859 eac->eac_Entries = 0;
860 error = examine_start(emulbase, fh);
861 if (error)
862 return error;
864 for(;;)
866 error = ReadDir(emulbase, fh, &FindData, &eac->eac_LastKey);
867 if (error) {
868 DEXAM(bug("[emul] ReadDir() returned %lu\n", error));
869 break;
872 /* Try to match the filename, if required. */
873 DEXAM(bug("[emul] Checking against MatchString\n"));
874 if (eac->eac_MatchString && !MatchPatternNoCase(eac->eac_MatchString, FindData.cFileName))
875 continue;
877 DEXAM(bug("[emul] Examining object\n"));
878 error = DoExamineEntry(emulbase, fh, FindData.cFileName, ead, end-(STRPTR)ead, type);
879 if(error)
880 break;
881 /* Do some more matching... */
882 if ((eac->eac_MatchFunc) && !CALLHOOKPKT(eac->eac_MatchFunc, ead, &type))
883 continue;
884 eac->eac_Entries++;
885 last = ead;
886 ead = ead->ed_Next;
889 if (last!=NULL)
890 last->ed_Next=NULL;
892 if ((error==ERROR_BUFFER_OVERFLOW) && last)
895 * ERROR_BUFFER_OVERFLOW happened while examining the last entry.
896 * We need to step back to it in order to re-examine it next time.
898 eac->eac_LastKey--;
899 return 0;
902 return error;
905 /*********************************************************************************************/
907 LONG DoHardLink(struct emulbase *emulbase, char *name, char *oldfile)
909 ULONG error, werr;
911 if (!emulbase->pdata.KernelIFace->CreateHardLink)
912 return ERROR_ACTION_NOT_KNOWN;
914 DLINK(bug("[emul] Creating hardlink %s to file %s\n", name, oldfile));
915 Forbid();
916 error = emulbase->pdata.KernelIFace->CreateHardLink(name, oldfile, NULL);
917 werr = emulbase->pdata.KernelIFace->GetLastError();
918 Permit();
920 return error ? 0 : Errno_w2a(werr, MODE_NEWFILE);
923 /*********************************************************************************************/
925 LONG DoSymLink(struct emulbase *emulbase, char *dest, char *src)
927 ULONG error, werr;
929 /* This subroutine is intentionally disabled because:
930 1. On Windows 7 CreateSymbolicLink() gives ERROR_PRIVILEGE_NOT_HELD error
931 2. Referred object name is supplied in AROS form. Windows seems not to like it,
932 and it needs to be translated to Windows path. This will not work in all cases
933 and this requires additional thinking and coding. Since reading symbolic links
934 is not implemented yet, i disabled creation too - Pavel Fedin <pavel_fedin@mail.ru>
935 if (!emulbase->pdata.KernelIFace->CreateSymbolicLink) */
936 return ERROR_ACTION_NOT_KNOWN;
938 Forbid();
939 error = emulbase->pdata.KernelIFace->CreateSymbolicLink(dest, src, 0);
940 werr = emulbase->pdata.KernelIFace->GetLastError();
941 Permit();
943 DLINK(bug("[emul] Result: %d, Windows error: %u\n", error, werr));
945 return error ? 0 : Errno_w2a(werr, MODE_NEWFILE);
948 /*********************************************************************************************/
950 LONG DoRename(struct emulbase *emulbase, char *filename, char *newname)
952 ULONG ret, werr;
954 Forbid();
955 ret = emulbase->pdata.KernelIFace->MoveFile(filename, newname);
956 werr = emulbase->pdata.KernelIFace->GetLastError();
957 Permit();
959 return ret ? 0 : Errno_w2a(werr, MODE_NEWFILE);
962 /*********************************************************************************************/
964 int DoReadLink(struct emulbase *emulbase, char *name, char *buffer, ULONG size, LONG *errPtr)
966 /* TODO: implement this. */
967 *errPtr = ERROR_ACTION_NOT_KNOWN;
968 return -1;
971 /*********************************************************************************************/
973 LONG DoSetDate(struct emulbase *emulbase, char *fullname, struct DateStamp *date)
975 void *handle;
976 LONG ret;
977 ULONG werr;
978 UQUAD ft;
980 ft = DateStamp2FileTime(date);
982 Forbid();
983 handle = emulbase->pdata.KernelIFace->CreateFile(fullname, FILE_WRITE_ATTRIBUTES,
984 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
985 NULL, OPEN_EXISTING, 0, NULL);
986 if (handle == INVALID_HANDLE_VALUE)
987 ret = 0;
988 else
989 ret = emulbase->pdata.KernelIFace->SetFileTime(handle, &ft, NULL, &ft);
991 werr = emulbase->pdata.KernelIFace->GetLastError();
993 if (handle != INVALID_HANDLE_VALUE)
994 emulbase->pdata.KernelIFace->CloseHandle(handle);
996 Permit();
998 return ret ? 0 : Errno_w2a(werr, MODE_READWRITE);
1001 SIPTR DoSetSize(struct emulbase *emulbase, struct filehandle *fh, SIPTR offset, ULONG mode, SIPTR *err)
1003 LONG error;
1004 ULONG werr;
1005 UQUAD newpos;
1007 DFSIZE(bug("[emul] DoSetSize(): mode %ld, offset %llu\n", mode, (unsigned long long)offset));
1009 /* First seek to the requested position. 'offset' will contain OLD position after that. NEW position will be in newpos */
1010 error = seek_file(emulbase, fh->fd, &offset, mode, &newpos);
1011 if (!error)
1013 /* Set EOF to NEW position */
1014 Forbid();
1015 error = emulbase->pdata.KernelIFace->SetEndOfFile(fh->fd);
1016 werr = emulbase->pdata.KernelIFace->GetLastError();
1017 Permit();
1019 error = error ? 0 : Errno_w2a(werr, MODE_READWRITE);
1022 * If our OLD position was less than new file size, we seek back to it. 'offset' will again contain
1023 * position before this seek - i. e. our NEW file size.
1025 if (offset < newpos)
1027 LONG error2;
1029 error2 = seek_file(emulbase, fh->fd, &offset, OFFSET_BEGINNING, NULL);
1030 if (!error)
1031 error = error2;
1032 } else
1033 offset = newpos;
1036 DFSIZE(bug("[emul] FSA_SET_FILE_SIZE returning %lu\n", error));
1037 *err = error;
1038 return offset;
1041 LONG DoStatFS(struct emulbase *emulbase, char *path, struct InfoData *id)
1043 char *c;
1044 char s;
1045 ULONG SectorsPerCluster, BytesPerSector, FreeBlocks;
1046 ULONG res, err;
1048 DSTATFS(printf("[EmulHandler] StatFS(\"%s\")\n", path));
1050 /* GetDiskFreeSpace() can be called only on root path. We always work with absolute pathnames, so let's get first part of the path */
1051 c = path;
1052 if ((c[0] == '\\') && (c[1] == '\\'))
1054 /* If the path starts with "\\", it's a UNC path. Its root is "\\Server\Share\", so we skip "\\Server\" part */
1055 c += 2;
1056 while (*c != '\\') {
1057 if (*c == 0)
1058 return ERROR_OBJECT_NOT_FOUND;
1059 c++;
1061 c++;
1064 /* Skip everything up to the first '\'. */
1065 while (*c != '\\')
1067 if (*c == 0)
1068 return ERROR_OBJECT_NOT_FOUND;
1069 c++;
1072 Forbid();
1074 /* Temporarily terminate the path */
1075 s = c[1];
1076 c[1] = 0;
1077 DSTATFS(printf("[EmulHandler] Root path: %s\n", path));
1079 res = emulbase->pdata.KernelIFace->GetDiskFreeSpace(path, &SectorsPerCluster, &BytesPerSector, &FreeBlocks, &id->id_NumBlocks);
1080 err = emulbase->pdata.KernelIFace->GetLastError();
1082 c[1] = s;
1083 Permit();
1085 if (res)
1087 id->id_NumSoftErrors = 0;
1088 id->id_UnitNumber = 0;
1089 id->id_DiskState = ID_VALIDATED;
1090 id->id_NumBlocksUsed = id->id_NumBlocks - FreeBlocks;
1091 id->id_BytesPerBlock = SectorsPerCluster*BytesPerSector;
1093 return 0;
1096 return Errno_w2a(err, MODE_OLDFILE);
1099 char *GetHomeDir(struct emulbase *emulbase, char *sp)
1101 char home[260];
1102 char *newunixpath = NULL;
1103 char *sp_end;
1104 WORD cmplen;
1105 char tmp;
1106 ULONG err;
1108 /* "~<name>" means home of user <name> */
1109 for(sp_end = sp; sp_end[0] != '\0' && sp_end[0] != '\\'; sp_end++);
1111 cmplen = sp_end - sp - 1;
1112 /* temporarily zero terminate name */
1113 tmp = sp[cmplen+1];
1114 sp[cmplen+1] = '\0';
1116 Forbid();
1117 err = emulbase->pdata.EmulIFace->EmulGetHome(sp+1, home);
1118 Permit();
1120 sp[cmplen+1] = tmp;
1122 if (!err)
1124 int hlen = strlen(home);
1125 int splen = strlen(sp_end);
1127 newunixpath = AllocVec(hlen + splen + 1, MEMF_PUBLIC);
1128 if (newunixpath)
1130 char *s = newunixpath;
1132 CopyMem(home, s, hlen);
1133 s += hlen;
1134 CopyMem(sp_end, s, splen);
1135 s += splen;
1136 *s = 0;
1140 return newunixpath;
1143 ULONG GetCurrentDir(struct emulbase *emulbase, char *path, ULONG len)
1145 ULONG res;
1147 Forbid();
1148 res = emulbase->pdata.KernelIFace->GetCurrentDirectory(len, path);
1149 Permit();
1151 return (res < len) ? TRUE : FALSE;
1154 BOOL CheckDir(struct emulbase *emulbase, char *path)
1156 ULONG attrs;
1158 Forbid();
1159 attrs = emulbase->pdata.KernelIFace->GetFileAttributes(path);
1160 Permit();
1162 if (attrs == INVALID_FILE_ATTRIBUTES)
1163 return TRUE;
1165 return (attrs & FILE_ATTRIBUTE_DIRECTORY) ? FALSE : TRUE;