2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Filesystem that accesses an underlying host OS filesystem.
6 Low-level host-dependent subroutines for Windows.
10 /*********************************************************************************************/
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>
36 #include <proto/arossupport.h>
37 #include <proto/dos.h>
38 #include <proto/hostlib.h>
39 #include <proto/kernel.h>
44 #include "emul_intern.h"
46 /*********************************************************************************************/
48 /* Make Windows protection bits out of AROS protection bits. */
49 static ULONG
prot_a2w(ULONG protect
)
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 */
68 /*********************************************************************************************/
70 /* Make AROS protection bits out of Windows protection bits. */
71 static ULONG
prot_w2a(ULONG protect
)
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
)
86 /* TODO: 1) Support more NT-specific attributes ('Executable')
87 2) Write complete AROS protection bits support using NTFS streams */
92 /*********************************************************************************************/
94 static void FileTime2DateStamp(struct DateStamp
*ds
, UQUAD ft
)
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 */
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
)
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 },
144 static ULONG
Errno_w2a(ULONG e
, LONG mode
)
148 DERROR(printf("[EmulHandler] Windows error code: %lu\n", e
));
150 /* ERROR_ACCESS_DENIED may mean different AmigaDOS errors depending
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
;
161 return ERROR_DELETE_PROTECTED
;
163 return ERROR_READ_PROTECTED
;
166 for(i
=0;i
<sizeof(u2a
)/sizeof(u2a
[0]);i
++)
169 DERROR(printf("[EmulHandler] Translated to AROS error code: %lu\n", 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
)
187 /* Nothing will happen if type has FHD_STDIO set, this is intentional */
188 DLOCK(bug("[emul] CloseHandle(), fd = 0x%08lX\n", current
->fd
));
191 emulbase
->pdata
.KernelIFace
->CloseHandle(current
->fd
);
196 if (current
->fd
!= INVALID_HANDLE_VALUE
)
198 DLOCK(bug("[emul] Closing directory search handle\n"));
200 emulbase
->pdata
.KernelIFace
->FindClose(current
->fd
);
204 if (current
->ph
.pathname
)
206 DLOCK(bug("[emul] Freeing directory search path\n"));
207 FreeVecPooled(emulbase
->mempool
, current
->ph
.pathname
);
212 DLOCK(bug("[emul] Done\n"));
215 /*********************************************************************************************/
217 LONG
DoOpen(struct emulbase
*emulbase
, struct filehandle
*fh
, LONG access
, LONG mode
, LONG protect
, BOOL AllowDir
)
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
));
225 kind
= emulbase
->pdata
.KernelIFace
->GetFileAttributes(fh
->hostname
);
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
)
234 if (kind
& FILE_ATTRIBUTE_DIRECTORY
)
236 /* file is a directory */
238 return ERROR_OBJECT_WRONG_TYPE
;
240 fh
->type
= FHD_DIRECTORY
;
241 fh
->fd
= INVALID_HANDLE_VALUE
;
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
;
254 DOPEN2(bug("[emul] Open file \"%s\", mode 0x%08lX\n", fh
->hostname
, mode
));
259 flags
= GENERIC_WRITE
; /* Only for writing */
260 lock
= 0; /* This will be an exclusive lock */
261 create
= CREATE_ALWAYS
;
265 create
= OPEN_ALWAYS
;
268 default: /* MODE_OLDFILE */
269 create
= OPEN_EXISTING
;
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
));
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
));
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();
317 DOPEN2(bug("[emul] FileHandle = 0x%08lX\n", fh
->fd
));
319 if (fh
->fd
== INVALID_HANDLE_VALUE
)
320 return Errno_w2a(err
, mode
);
328 /*********************************************************************************************/
330 LONG
DoRead(struct emulbase
*emulbase
, struct filehandle
*fh
, APTR buff
, ULONG len
, SIPTR
*err
)
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
));
344 reader
->sig
= SIGF_DOS
;
345 reader
->task
= FindTask(NULL
);
346 reader
->cmd
= ASYNC_CMD_READ
;
347 SetSignal(0, reader
->sig
);
350 res
= emulbase
->pdata
.KernelIFace
->SetEvent(reader
->CmdEvent
);
351 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
358 DASYNC(bug("[emul] Read %ld bytes, error %lu\n", reader
->.actual
, reader
->error
));
359 len
= reader
->actual
;
360 werr
= reader
->error
;
371 if ((c
[0] == '\r') && (c
[1] == '\n')) {
383 res
= emulbase
->pdata
.KernelIFace
->ReadFile(fh
->fd
, buff
, len
, &len
, NULL
);
384 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
395 *err
= Errno_w2a(werr
, MODE_OLDFILE
);
400 LONG
DoWrite(struct emulbase
*emulbase
, struct filehandle
*fh
, CONST_APTR buff
, ULONG len
, SIPTR
*err
)
405 success
= emulbase
->pdata
.KernelIFace
->WriteFile(fh
->fd
, (void *)buff
, len
, &len
, NULL
);
406 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
409 DWRITE(bug("[emul] Write handle 0x%p: success %d, error %d\n", fh
, success
, werr
));
418 *err
= Errno_w2a(werr
, MODE_NEWFILE
);
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
)
434 UQUAD offset
= *pOffset
;
436 DB2(bug("[emul] LSeek() - getting current position\n"));
438 oldpos
= emulbase
->pdata
.KernelIFace
->SetFilePointer(fd
, 0, &pos_high
, FILE_CURRENT
);
440 oldpos
|= (UQUAD
)pos_high
<< 32;
441 DSEEK(bug("[emul] Original position: %llu\n", oldpos
));
445 case OFFSET_BEGINNING
:
457 pos_high
= offset
>> 32;
458 DB2(bug("[emul] LSeek() - setting new position\n"));
460 error
= emulbase
->pdata
.KernelIFace
->SetFilePointer(fd
, offset
, &pos_high
, mode
);
461 werror
= emulbase
->pdata
.KernelIFace
->GetLastError();
464 if (error
== (ULONG
)-1)
465 error
= Errno_w2a(werror
, MODE_OLDFILE
);
471 *newpos
|= (UQUAD
)pos_high
<< 32;
483 SIPTR
DoSeek(struct emulbase
*emulbase
, struct filehandle
*fh
, SIPTR offset
, ULONG mode
, SIPTR
*err
)
487 DSEEK(bug("[emul] DoSeek(0x%p, %ld, %d)\n", fh
, offset
, mode
));
489 error
= seek_file(emulbase
, fh
->fd
, &offset
, mode
, NULL
);
492 return error
? -1 : offset
;
495 /*********************************************************************************************/
497 LONG
DoMkDir(struct emulbase
*emulbase
, struct filehandle
*fh
, ULONG protect
)
502 ret
= emulbase
->pdata
.KernelIFace
->CreateDirectory(fh
->hostname
, NULL
);
503 werror
= emulbase
->pdata
.KernelIFace
->GetLastError();
508 fh
->type
= FHD_DIRECTORY
;
509 fh
->fd
= INVALID_HANDLE_VALUE
;
513 emulbase
->pdata
.KernelIFace
->SetFileAttributes(fh
->hostname
, prot_a2w(protect
));
518 return Errno_w2a(werror
, MODE_NEWFILE
);
521 /*********************************************************************************************/
523 LONG
DoDelete(struct emulbase
*emulbase
, char *file
)
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
);
535 ret
= emulbase
->pdata
.KernelIFace
->_DeleteFile(file
);
540 err
= emulbase
->pdata
.KernelIFace
->GetLastError();
544 return ret
? 0 : Errno_w2a(err
, 0);
547 /*********************************************************************************************/
549 LONG
DoChMod(struct emulbase
*emulbase
, char *filename
, ULONG aprot
)
554 aprot
= prot_a2w(aprot
);
557 ret
= emulbase
->pdata
.KernelIFace
->SetFileAttributes(filename
, aprot
);
558 err
= emulbase
->pdata
.KernelIFace
->GetLastError();
561 return ret
? 0 : Errno_w2a(err
, MODE_READWRITE
);
564 /*********************************************************************************************/
566 ULONG
examine_start(struct emulbase
*emulbase
, struct filehandle
*fh
)
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
;
586 DEXAM(bug("[emul] Created search path: %s\n", fh
->ph
.pathname
));
590 /*********************************************************************************************/
592 /* Reset dirpos in directory handle and close existing search handle */
593 LONG
DoRewindDir(struct emulbase
*emulbase
, struct filehandle
*fh
)
597 if (fh
->fd
!= INVALID_HANDLE_VALUE
)
600 r
= emulbase
->pdata
.KernelIFace
->FindClose(fh
->fd
);
601 err
= emulbase
->pdata
.KernelIFace
->GetLastError();
605 return Errno_w2a(err
, MODE_OLDFILE
);
607 fh
->fd
= INVALID_HANDLE_VALUE
;
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
)
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
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
653 if (fh
->fd
== INVALID_HANDLE_VALUE
)
655 DEXAM(bug("[emul] Finding first file\n"));
657 fh
->fd
= emulbase
->pdata
.KernelIFace
->FindFirstFile(fh
->ph
.pathname
, FindData
);
658 err
= emulbase
->pdata
.KernelIFace
->GetLastError();
660 res
= (fh
->fd
!= INVALID_HANDLE_VALUE
);
665 res
= emulbase
->pdata
.KernelIFace
->FindNextFile(fh
->fd
, FindData
);
666 err
= emulbase
->pdata
.KernelIFace
->GetLastError();
671 return Errno_w2a(err
, MODE_OLDFILE
);
674 DEXAM(bug("[emul] Found %s, position %lu\n", FindData
->cFileName
, fh
->ph
.dirpos
));
675 } while (fh
->ph
.dirpos
<= *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
));
687 /*********************************************************************************************/
689 static ULONG
DoExamineEntry_sub(struct emulbase
*emulbase
, struct filehandle
*fh
, STRPTR FoundName
, WIN32_FILE_ATTRIBUTE_DATA
*FIB
)
691 STRPTR filename
, name
;
696 DEXAM(bug("[emul] DoExamineEntry_sub(): filehandle's path: %s\n", fh
->hostname
));
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);
704 return ERROR_NO_FREE_STORE
;
706 strcpy(name
, fh
->hostname
);
707 filename
= name
+ plen
;
709 strcpy(filename
, FoundName
);
714 DEXAM(bug("[emul] Full name: %s\n", name
));
716 error
= emulbase
->pdata
.KernelIFace
->GetFileAttributesEx(name
, 0, FIB
);
717 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
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
;
738 /* Check, if the supplied buffer is large enough. */
739 next
=(STRPTR
)ead
+sizes
[type
];
740 end
=(STRPTR
)ead
+size
;
744 DEXAM(bug("[emul] DoExamineEntry(): end of buffer\n"));
745 return ERROR_BUFFER_OVERFLOW
;
748 error
= DoExamineEntry_sub(emulbase
, fh
, FoundName
, &FIB
);
752 DEXAM(bug("[emul] Filling in object information\n"));
757 ead
->ed_OwnerUID
= 0;
758 ead
->ed_OwnerGID
= 0;
760 ead
->ed_Comment
= NULL
;
761 /* TODO: Write Windows shell-compatible comments support using NTFS streams */
763 FileTime2DateStamp((struct DateStamp
*)&ead
->ed_Days
, FIB
.ftLastWriteTime
);
765 ead
->ed_Prot
= prot_w2a(FIB
.dwFileAttributes
);
767 ead
->ed_Size
= FIB
.nFileSizeLow
;
769 if (FIB
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
771 if (FoundName
|| fh
->name
[0])
772 ead
->ed_Type
= ST_USERDIR
;
774 ead
->ed_Type
= ST_ROOT
;
777 ead
->ed_Type
= ST_FILE
;
781 else if (*fh
->name
) {
788 last
= fh
->volumename
;
793 return ERROR_BUFFER_OVERFLOW
;
794 if (!(*next
++=*last
++))
798 ead
->ed_Next
=(struct ExAllData
*)(((IPTR
)next
+AROS_PTRALIGN
-1)&~(AROS_PTRALIGN
-1));
803 /*********************************************************************************************/
805 LONG
DoExamineNext(struct emulbase
*emulbase
, struct filehandle
*fh
, struct FileInfoBlock
*FIB
)
809 WIN32_FIND_DATA FindData
;
810 WIN32_FILE_ATTRIBUTE_DATA AttrData
;
812 res
= examine_start(emulbase
, fh
);
816 res
= ReadDir(emulbase
, fh
, &FindData
, &FIB
->fib_DiskKey
);
818 res
= DoExamineEntry_sub(emulbase
, fh
, FindData
.cFileName
, &AttrData
);
821 DoRewindDir(emulbase
, fh
);
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
;
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
++))
844 FIB
->fib_FileName
[0] = res
;
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
;
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
);
867 error
= ReadDir(emulbase
, fh
, &FindData
, &eac
->eac_LastKey
);
869 DEXAM(bug("[emul] ReadDir() returned %lu\n", error
));
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
))
878 DEXAM(bug("[emul] Examining object\n"));
879 error
= DoExamineEntry(emulbase
, fh
, FindData
.cFileName
, ead
, end
-(STRPTR
)ead
, type
);
882 /* Do some more matching... */
883 if ((eac
->eac_MatchFunc
) && !CALLHOOKPKT(eac
->eac_MatchFunc
, ead
, &type
))
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.
906 /*********************************************************************************************/
908 LONG
DoHardLink(struct emulbase
*emulbase
, char *name
, char *oldfile
)
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
));
917 error
= emulbase
->pdata
.KernelIFace
->CreateHardLink(name
, oldfile
, NULL
);
918 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
921 return error
? 0 : Errno_w2a(werr
, MODE_NEWFILE
);
924 /*********************************************************************************************/
926 LONG
DoSymLink(struct emulbase
*emulbase
, char *dest
, char *src
)
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
;
940 error
= emulbase
->pdata
.KernelIFace
->CreateSymbolicLink(dest
, src
, 0);
941 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
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
)
956 ret
= emulbase
->pdata
.KernelIFace
->MoveFile(filename
, newname
);
957 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
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
;
972 /*********************************************************************************************/
974 LONG
DoSetDate(struct emulbase
*emulbase
, char *fullname
, struct DateStamp
*date
)
981 ft
= DateStamp2FileTime(date
);
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
)
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
);
999 return ret
? 0 : Errno_w2a(werr
, MODE_READWRITE
);
1002 SIPTR
DoSetSize(struct emulbase
*emulbase
, struct filehandle
*fh
, SIPTR offset
, ULONG mode
, SIPTR
*err
)
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
);
1014 /* Set EOF to NEW position */
1016 error
= emulbase
->pdata
.KernelIFace
->SetEndOfFile(fh
->fd
);
1017 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
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
)
1030 error2
= seek_file(emulbase
, fh
->fd
, &offset
, OFFSET_BEGINNING
, NULL
);
1037 DFSIZE(bug("[emul] FSA_SET_FILE_SIZE returning %lu\n", error
));
1042 LONG
DoStatFS(struct emulbase
*emulbase
, char *path
, struct InfoData
*id
)
1046 ULONG SectorsPerCluster
, BytesPerSector
, FreeBlocks
;
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 */
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 */
1057 while (*c
!= '\\') {
1059 return ERROR_OBJECT_NOT_FOUND
;
1065 /* Skip everything up to the first '\'. */
1069 return ERROR_OBJECT_NOT_FOUND
;
1075 /* Temporarily terminate the path */
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();
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
;
1097 return Errno_w2a(err
, MODE_OLDFILE
);
1100 char *GetHomeDir(struct emulbase
*emulbase
, char *sp
)
1103 char *newunixpath
= NULL
;
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 */
1115 sp
[cmplen
+1] = '\0';
1118 err
= emulbase
->pdata
.EmulIFace
->EmulGetHome(sp
+1, home
);
1125 int hlen
= strlen(home
);
1126 int splen
= strlen(sp_end
);
1128 newunixpath
= AllocVec(hlen
+ splen
+ 1, MEMF_PUBLIC
);
1131 char *s
= newunixpath
;
1133 CopyMem(home
, s
, hlen
);
1135 CopyMem(sp_end
, s
, splen
);
1144 ULONG
GetCurrentDir(struct emulbase
*emulbase
, char *path
, ULONG len
)
1149 res
= emulbase
->pdata
.KernelIFace
->GetCurrentDirectory(len
, path
);
1152 return (res
< len
) ? TRUE
: FALSE
;
1155 BOOL
CheckDir(struct emulbase
*emulbase
, char *path
)
1160 attrs
= emulbase
->pdata
.KernelIFace
->GetFileAttributes(path
);
1163 if (attrs
== INVALID_FILE_ATTRIBUTES
)
1166 return (attrs
& FILE_ATTRIBUTE_DIRECTORY
) ? FALSE
: TRUE
;