clean up some makefile issues. (NicJA)
[AROS.git] / arch / all-mingw32 / filesys / emul_handler / emul_host.c
blobc7106a5e5147e50341f2447aa149168c9ad6f473
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();
670 if (!res)
671 return Errno_w2a(err, MODE_OLDFILE);
673 fh->ph.dirpos++;
674 DEXAM(bug("[emul] Found %s, position %lu\n", FindData->cFileName, fh->ph.dirpos));
675 } while (fh->ph.dirpos <= *dirpos);
676 (*dirpos)++;
677 DEXAM(bug("[emul] New dirpos: %lu\n", *dirpos));
679 * We also skip "." and ".." entries (however we count their indexes - just in case), because
680 * AmigaOS donesn't have them.
682 } while (is_special_dir(FindData->cFileName));
684 return 0;
687 /*********************************************************************************************/
689 static ULONG DoExamineEntry_sub(struct emulbase *emulbase, struct filehandle *fh, STRPTR FoundName, WIN32_FILE_ATTRIBUTE_DATA *FIB)
691 STRPTR filename, name;
692 ULONG plen, flen;
693 ULONG error = 0;
694 ULONG werr;
696 DEXAM(bug("[emul] DoExamineEntry_sub(): filehandle's path: %s\n", fh->hostname));
697 if (FoundName)
699 DEXAM(bug("[emul] ...containing object: %s\n", FoundName));
700 plen = strlen(fh->hostname);
701 flen = strlen(FoundName);
702 name = AllocVecPooled(emulbase->mempool, plen + flen + 2);
703 if (!name)
704 return ERROR_NO_FREE_STORE;
706 strcpy(name, fh->hostname);
707 filename = name + plen;
708 *filename++ = '\\';
709 strcpy(filename, FoundName);
711 else
712 name = fh->hostname;
714 DEXAM(bug("[emul] Full name: %s\n", name));
715 Forbid();
716 error = emulbase->pdata.KernelIFace->GetFileAttributesEx(name, 0, FIB);
717 werr = emulbase->pdata.KernelIFace->GetLastError();
718 Permit();
720 if (FoundName)
722 DEXAM(bug("[emul] Freeing full name\n"));
723 FreeVecPooled(emulbase->mempool, name);
726 return error ? 0 : Errno_w2a(werr, MODE_OLDFILE);
729 /*********************************************************************************************/
731 LONG DoExamineEntry(struct emulbase *emulbase, struct filehandle *fh, char *FoundName,
732 struct ExAllData *ead, ULONG size, ULONG type)
734 STRPTR next, last, end, name;
735 WIN32_FILE_ATTRIBUTE_DATA FIB;
736 ULONG error;
738 /* Check, if the supplied buffer is large enough. */
739 next=(STRPTR)ead+sizes[type];
740 end =(STRPTR)ead+size;
742 if(next > end)
744 DEXAM(bug("[emul] DoExamineEntry(): end of buffer\n"));
745 return ERROR_BUFFER_OVERFLOW;
748 error = DoExamineEntry_sub(emulbase, fh, FoundName, &FIB);
749 if (error)
750 return error;
752 DEXAM(bug("[emul] Filling in object information\n"));
753 switch(type)
755 default:
756 case ED_OWNER:
757 ead->ed_OwnerUID = 0;
758 ead->ed_OwnerGID = 0;
759 case ED_COMMENT:
760 ead->ed_Comment = NULL;
761 /* TODO: Write Windows shell-compatible comments support using NTFS streams */
762 case ED_DATE:
763 FileTime2DateStamp((struct DateStamp *)&ead->ed_Days, FIB.ftLastWriteTime);
764 case ED_PROTECTION:
765 ead->ed_Prot = prot_w2a(FIB.dwFileAttributes);
766 case ED_SIZE:
767 ead->ed_Size = FIB.nFileSizeLow;
768 case ED_TYPE:
769 if (FIB.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
771 if (FoundName || fh->name[0])
772 ead->ed_Type = ST_USERDIR;
773 else
774 ead->ed_Type = ST_ROOT;
776 else
777 ead->ed_Type = ST_FILE;
778 case ED_NAME:
779 if (FoundName)
780 last = FoundName;
781 else if (*fh->name) {
782 name = fh->name;
783 last = name;
784 while(*name)
785 if(*name++=='\\')
786 last = name;
787 } else
788 last = fh->volumename;
789 ead->ed_Name=next;
790 for(;;)
792 if (next>=end)
793 return ERROR_BUFFER_OVERFLOW;
794 if (!(*next++=*last++))
795 break;
797 case 0:
798 ead->ed_Next=(struct ExAllData *)(((IPTR)next+AROS_PTRALIGN-1)&~(AROS_PTRALIGN-1));
799 return 0;
803 /*********************************************************************************************/
805 LONG DoExamineNext(struct emulbase *emulbase, struct filehandle *fh, struct FileInfoBlock *FIB)
807 char *src, *dest;
808 ULONG res;
809 WIN32_FIND_DATA FindData;
810 WIN32_FILE_ATTRIBUTE_DATA AttrData;
812 res = examine_start(emulbase, fh);
813 if (res)
814 return res;
816 res = ReadDir(emulbase, fh, &FindData, &FIB->fib_DiskKey);
817 if (!res)
818 res = DoExamineEntry_sub(emulbase, fh, FindData.cFileName, &AttrData);
819 if (res)
821 DoRewindDir(emulbase, fh);
822 return res;
825 FIB->fib_OwnerUID = 0;
826 FIB->fib_OwnerGID = 0;
827 FIB->fib_Comment[0] = '\0'; /* TODO: no comments available yet! */
828 FIB->fib_Protection = prot_w2a(AttrData.dwFileAttributes);
829 FIB->fib_Size = AttrData.nFileSizeLow;
831 FileTime2DateStamp(&FIB->fib_Date, AttrData.ftLastWriteTime);
832 if (AttrData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
833 FIB->fib_DirEntryType = ST_USERDIR;
834 else
835 FIB->fib_DirEntryType = ST_FILE;
837 src = FindData.cFileName;
838 dest = &FIB->fib_FileName[1];
839 for (res = 0; res<MAXFILENAMELENGTH-1; res++)
841 if (!(*dest++=*src++))
842 break;
844 FIB->fib_FileName[0] = res;
845 return 0;
848 /*********************************************************************************************/
850 LONG DoExamineAll(struct emulbase *emulbase, struct filehandle *fh, struct ExAllData *ead,
851 struct ExAllControl *eac, ULONG size, ULONG type, struct DosLibrary *DOSBase)
853 struct ExAllData *last = NULL;
854 STRPTR end = (STRPTR)ead + size;
855 LONG error;
856 WIN32_FIND_DATA FindData;
858 DEXAM(bug("[emul] DoExamineAll(%s)\n", fh->hostname));
860 eac->eac_Entries = 0;
861 error = examine_start(emulbase, fh);
862 if (error)
863 return error;
865 for(;;)
867 error = ReadDir(emulbase, fh, &FindData, &eac->eac_LastKey);
868 if (error) {
869 DEXAM(bug("[emul] ReadDir() returned %lu\n", error));
870 break;
873 /* Try to match the filename, if required. */
874 DEXAM(bug("[emul] Checking against MatchString\n"));
875 if (eac->eac_MatchString && !MatchPatternNoCase(eac->eac_MatchString, FindData.cFileName))
876 continue;
878 DEXAM(bug("[emul] Examining object\n"));
879 error = DoExamineEntry(emulbase, fh, FindData.cFileName, ead, end-(STRPTR)ead, type);
880 if(error)
881 break;
882 /* Do some more matching... */
883 if ((eac->eac_MatchFunc) && !CALLHOOKPKT(eac->eac_MatchFunc, ead, &type))
884 continue;
885 eac->eac_Entries++;
886 last = ead;
887 ead = ead->ed_Next;
890 if (last!=NULL)
891 last->ed_Next=NULL;
893 if ((error==ERROR_BUFFER_OVERFLOW) && last)
896 * ERROR_BUFFER_OVERFLOW happened while examining the last entry.
897 * We need to step back to it in order to re-examine it next time.
899 eac->eac_LastKey--;
900 return 0;
903 return error;
906 /*********************************************************************************************/
908 LONG DoHardLink(struct emulbase *emulbase, char *name, char *oldfile)
910 ULONG error, werr;
912 if (!emulbase->pdata.KernelIFace->CreateHardLink)
913 return ERROR_ACTION_NOT_KNOWN;
915 DLINK(bug("[emul] Creating hardlink %s to file %s\n", name, oldfile));
916 Forbid();
917 error = emulbase->pdata.KernelIFace->CreateHardLink(name, oldfile, NULL);
918 werr = emulbase->pdata.KernelIFace->GetLastError();
919 Permit();
921 return error ? 0 : Errno_w2a(werr, MODE_NEWFILE);
924 /*********************************************************************************************/
926 LONG DoSymLink(struct emulbase *emulbase, char *dest, char *src)
928 ULONG error, werr;
930 /* This subroutine is intentionally disabled because:
931 1. On Windows 7 CreateSymbolicLink() gives ERROR_PRIVILEGE_NOT_HELD error
932 2. Referred object name is supplied in AROS form. Windows seems not to like it,
933 and it needs to be translated to Windows path. This will not work in all cases
934 and this requires additional thinking and coding. Since reading symbolic links
935 is not implemented yet, i disabled creation too - Pavel Fedin <pavel_fedin@mail.ru>
936 if (!emulbase->pdata.KernelIFace->CreateSymbolicLink) */
937 return ERROR_ACTION_NOT_KNOWN;
939 Forbid();
940 error = emulbase->pdata.KernelIFace->CreateSymbolicLink(dest, src, 0);
941 werr = emulbase->pdata.KernelIFace->GetLastError();
942 Permit();
944 DLINK(bug("[emul] Result: %d, Windows error: %u\n", error, werr));
946 return error ? 0 : Errno_w2a(werr, MODE_NEWFILE);
949 /*********************************************************************************************/
951 LONG DoRename(struct emulbase *emulbase, char *filename, char *newname)
953 ULONG ret, werr;
955 Forbid();
956 ret = emulbase->pdata.KernelIFace->MoveFile(filename, newname);
957 werr = emulbase->pdata.KernelIFace->GetLastError();
958 Permit();
960 return ret ? 0 : Errno_w2a(werr, MODE_NEWFILE);
963 /*********************************************************************************************/
965 int DoReadLink(struct emulbase *emulbase, char *name, char *buffer, ULONG size, LONG *errPtr)
967 /* TODO: implement this. */
968 *errPtr = ERROR_ACTION_NOT_KNOWN;
969 return -1;
972 /*********************************************************************************************/
974 LONG DoSetDate(struct emulbase *emulbase, char *fullname, struct DateStamp *date)
976 void *handle;
977 LONG ret;
978 ULONG werr;
979 UQUAD ft;
981 ft = DateStamp2FileTime(date);
983 Forbid();
984 handle = emulbase->pdata.KernelIFace->CreateFile(fullname, FILE_WRITE_ATTRIBUTES,
985 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
986 NULL, OPEN_EXISTING, 0, NULL);
987 if (handle == INVALID_HANDLE_VALUE)
988 ret = 0;
989 else
990 ret = emulbase->pdata.KernelIFace->SetFileTime(handle, &ft, NULL, &ft);
992 werr = emulbase->pdata.KernelIFace->GetLastError();
994 if (handle != INVALID_HANDLE_VALUE)
995 emulbase->pdata.KernelIFace->CloseHandle(handle);
997 Permit();
999 return ret ? 0 : Errno_w2a(werr, MODE_READWRITE);
1002 SIPTR DoSetSize(struct emulbase *emulbase, struct filehandle *fh, SIPTR offset, ULONG mode, SIPTR *err)
1004 LONG error;
1005 ULONG werr;
1006 UQUAD newpos;
1008 DFSIZE(bug("[emul] DoSetSize(): mode %ld, offset %llu\n", mode, (unsigned long long)offset));
1010 /* First seek to the requested position. 'offset' will contain OLD position after that. NEW position will be in newpos */
1011 error = seek_file(emulbase, fh->fd, &offset, mode, &newpos);
1012 if (!error)
1014 /* Set EOF to NEW position */
1015 Forbid();
1016 error = emulbase->pdata.KernelIFace->SetEndOfFile(fh->fd);
1017 werr = emulbase->pdata.KernelIFace->GetLastError();
1018 Permit();
1020 error = error ? 0 : Errno_w2a(werr, MODE_READWRITE);
1023 * If our OLD position was less than new file size, we seek back to it. 'offset' will again contain
1024 * position before this seek - i. e. our NEW file size.
1026 if (offset < newpos)
1028 LONG error2;
1030 error2 = seek_file(emulbase, fh->fd, &offset, OFFSET_BEGINNING, NULL);
1031 if (!error)
1032 error = error2;
1033 } else
1034 offset = newpos;
1037 DFSIZE(bug("[emul] FSA_SET_FILE_SIZE returning %lu\n", error));
1038 *err = error;
1039 return offset;
1042 LONG DoStatFS(struct emulbase *emulbase, char *path, struct InfoData *id)
1044 char *c;
1045 char s;
1046 ULONG SectorsPerCluster, BytesPerSector, FreeBlocks;
1047 ULONG res, err;
1049 DSTATFS(printf("[EmulHandler] StatFS(\"%s\")\n", path));
1051 /* GetDiskFreeSpace() can be called only on root path. We always work with absolute pathnames, so let's get first part of the path */
1052 c = path;
1053 if ((c[0] == '\\') && (c[1] == '\\'))
1055 /* If the path starts with "\\", it's a UNC path. Its root is "\\Server\Share\", so we skip "\\Server\" part */
1056 c += 2;
1057 while (*c != '\\') {
1058 if (*c == 0)
1059 return ERROR_OBJECT_NOT_FOUND;
1060 c++;
1062 c++;
1065 /* Skip everything up to the first '\'. */
1066 while (*c != '\\')
1068 if (*c == 0)
1069 return ERROR_OBJECT_NOT_FOUND;
1070 c++;
1073 Forbid();
1075 /* Temporarily terminate the path */
1076 s = c[1];
1077 c[1] = 0;
1078 DSTATFS(printf("[EmulHandler] Root path: %s\n", path));
1080 res = emulbase->pdata.KernelIFace->GetDiskFreeSpace(path, &SectorsPerCluster, &BytesPerSector, &FreeBlocks, &id->id_NumBlocks);
1081 err = emulbase->pdata.KernelIFace->GetLastError();
1083 c[1] = s;
1084 Permit();
1086 if (res)
1088 id->id_NumSoftErrors = 0;
1089 id->id_UnitNumber = 0;
1090 id->id_DiskState = ID_VALIDATED;
1091 id->id_NumBlocksUsed = id->id_NumBlocks - FreeBlocks;
1092 id->id_BytesPerBlock = SectorsPerCluster*BytesPerSector;
1094 return 0;
1097 return Errno_w2a(err, MODE_OLDFILE);
1100 char *GetHomeDir(struct emulbase *emulbase, char *sp)
1102 char home[260];
1103 char *newunixpath = NULL;
1104 char *sp_end;
1105 WORD cmplen;
1106 char tmp;
1107 ULONG err;
1109 /* "~<name>" means home of user <name> */
1110 for(sp_end = sp; sp_end[0] != '\0' && sp_end[0] != '\\'; sp_end++);
1112 cmplen = sp_end - sp - 1;
1113 /* temporarily zero terminate name */
1114 tmp = sp[cmplen+1];
1115 sp[cmplen+1] = '\0';
1117 Forbid();
1118 err = emulbase->pdata.EmulIFace->EmulGetHome(sp+1, home);
1119 Permit();
1121 sp[cmplen+1] = tmp;
1123 if (!err)
1125 int hlen = strlen(home);
1126 int splen = strlen(sp_end);
1128 newunixpath = AllocVec(hlen + splen + 1, MEMF_PUBLIC);
1129 if (newunixpath)
1131 char *s = newunixpath;
1133 CopyMem(home, s, hlen);
1134 s += hlen;
1135 CopyMem(sp_end, s, splen);
1136 s += splen;
1137 *s = 0;
1141 return newunixpath;
1144 ULONG GetCurrentDir(struct emulbase *emulbase, char *path, ULONG len)
1146 ULONG res;
1148 Forbid();
1149 res = emulbase->pdata.KernelIFace->GetCurrentDirectory(len, path);
1150 Permit();
1152 return (res < len) ? TRUE : FALSE;
1155 BOOL CheckDir(struct emulbase *emulbase, char *path)
1157 ULONG attrs;
1159 Forbid();
1160 attrs = emulbase->pdata.KernelIFace->GetFileAttributes(path);
1161 Permit();
1163 if (attrs == INVALID_FILE_ATTRIBUTES)
1164 return TRUE;
1166 return (attrs & FILE_ATTRIBUTE_DIRECTORY) ? FALSE : TRUE;