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();
670 return Errno_w2a(err
, MODE_OLDFILE
);
673 DEXAM(bug("[emul] Found %s, position %lu\n", FindData
->cFileName
, fh
->ph
.dirpos
));
674 } while (fh
->ph
.dirpos
<= *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
));
686 /*********************************************************************************************/
688 static ULONG
DoExamineEntry_sub(struct emulbase
*emulbase
, struct filehandle
*fh
, STRPTR FoundName
, WIN32_FILE_ATTRIBUTE_DATA
*FIB
)
690 STRPTR filename
, name
;
695 DEXAM(bug("[emul] DoExamineEntry_sub(): filehandle's path: %s\n", fh
->hostname
));
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);
703 return ERROR_NO_FREE_STORE
;
705 strcpy(name
, fh
->hostname
);
706 filename
= name
+ plen
;
708 strcpy(filename
, FoundName
);
713 DEXAM(bug("[emul] Full name: %s\n", name
));
715 error
= emulbase
->pdata
.KernelIFace
->GetFileAttributesEx(name
, 0, FIB
);
716 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
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
;
737 /* Check, if the supplied buffer is large enough. */
738 next
=(STRPTR
)ead
+sizes
[type
];
739 end
=(STRPTR
)ead
+size
;
743 DEXAM(bug("[emul] DoExamineEntry(): end of buffer\n"));
744 return ERROR_BUFFER_OVERFLOW
;
747 error
= DoExamineEntry_sub(emulbase
, fh
, FoundName
, &FIB
);
751 DEXAM(bug("[emul] Filling in object information\n"));
756 ead
->ed_OwnerUID
= 0;
757 ead
->ed_OwnerGID
= 0;
759 ead
->ed_Comment
= NULL
;
760 /* TODO: Write Windows shell-compatible comments support using NTFS streams */
762 FileTime2DateStamp((struct DateStamp
*)&ead
->ed_Days
, FIB
.ftLastWriteTime
);
764 ead
->ed_Prot
= prot_w2a(FIB
.dwFileAttributes
);
766 ead
->ed_Size
= FIB
.nFileSizeLow
;
768 if (FIB
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
770 if (FoundName
|| fh
->name
[0])
771 ead
->ed_Type
= ST_USERDIR
;
773 ead
->ed_Type
= ST_ROOT
;
776 ead
->ed_Type
= ST_FILE
;
780 else if (*fh
->name
) {
787 last
= fh
->volumename
;
792 return ERROR_BUFFER_OVERFLOW
;
793 if (!(*next
++=*last
++))
797 ead
->ed_Next
=(struct ExAllData
*)(((IPTR
)next
+AROS_PTRALIGN
-1)&~(AROS_PTRALIGN
-1));
802 /*********************************************************************************************/
804 LONG
DoExamineNext(struct emulbase
*emulbase
, struct filehandle
*fh
, struct FileInfoBlock
*FIB
)
808 WIN32_FIND_DATA FindData
;
809 WIN32_FILE_ATTRIBUTE_DATA AttrData
;
811 res
= examine_start(emulbase
, fh
);
815 res
= ReadDir(emulbase
, fh
, &FindData
, &FIB
->fib_DiskKey
);
817 res
= DoExamineEntry_sub(emulbase
, fh
, FindData
.cFileName
, &AttrData
);
820 DoRewindDir(emulbase
, fh
);
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
;
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
++))
843 FIB
->fib_FileName
[0] = res
;
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
;
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
);
866 error
= ReadDir(emulbase
, fh
, &FindData
, &eac
->eac_LastKey
);
868 DEXAM(bug("[emul] ReadDir() returned %lu\n", error
));
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
))
877 DEXAM(bug("[emul] Examining object\n"));
878 error
= DoExamineEntry(emulbase
, fh
, FindData
.cFileName
, ead
, end
-(STRPTR
)ead
, type
);
881 /* Do some more matching... */
882 if ((eac
->eac_MatchFunc
) && !CALLHOOKPKT(eac
->eac_MatchFunc
, ead
, &type
))
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.
905 /*********************************************************************************************/
907 LONG
DoHardLink(struct emulbase
*emulbase
, char *name
, char *oldfile
)
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
));
916 error
= emulbase
->pdata
.KernelIFace
->CreateHardLink(name
, oldfile
, NULL
);
917 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
920 return error
? 0 : Errno_w2a(werr
, MODE_NEWFILE
);
923 /*********************************************************************************************/
925 LONG
DoSymLink(struct emulbase
*emulbase
, char *dest
, char *src
)
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
;
939 error
= emulbase
->pdata
.KernelIFace
->CreateSymbolicLink(dest
, src
, 0);
940 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
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
)
955 ret
= emulbase
->pdata
.KernelIFace
->MoveFile(filename
, newname
);
956 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
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
;
971 /*********************************************************************************************/
973 LONG
DoSetDate(struct emulbase
*emulbase
, char *fullname
, struct DateStamp
*date
)
980 ft
= DateStamp2FileTime(date
);
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
)
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
);
998 return ret
? 0 : Errno_w2a(werr
, MODE_READWRITE
);
1001 SIPTR
DoSetSize(struct emulbase
*emulbase
, struct filehandle
*fh
, SIPTR offset
, ULONG mode
, SIPTR
*err
)
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
);
1013 /* Set EOF to NEW position */
1015 error
= emulbase
->pdata
.KernelIFace
->SetEndOfFile(fh
->fd
);
1016 werr
= emulbase
->pdata
.KernelIFace
->GetLastError();
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
)
1029 error2
= seek_file(emulbase
, fh
->fd
, &offset
, OFFSET_BEGINNING
, NULL
);
1036 DFSIZE(bug("[emul] FSA_SET_FILE_SIZE returning %lu\n", error
));
1041 LONG
DoStatFS(struct emulbase
*emulbase
, char *path
, struct InfoData
*id
)
1045 ULONG SectorsPerCluster
, BytesPerSector
, FreeBlocks
;
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 */
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 */
1056 while (*c
!= '\\') {
1058 return ERROR_OBJECT_NOT_FOUND
;
1064 /* Skip everything up to the first '\'. */
1068 return ERROR_OBJECT_NOT_FOUND
;
1074 /* Temporarily terminate the path */
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();
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
;
1096 return Errno_w2a(err
, MODE_OLDFILE
);
1099 char *GetHomeDir(struct emulbase
*emulbase
, char *sp
)
1102 char *newunixpath
= NULL
;
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 */
1114 sp
[cmplen
+1] = '\0';
1117 err
= emulbase
->pdata
.EmulIFace
->EmulGetHome(sp
+1, home
);
1124 int hlen
= strlen(home
);
1125 int splen
= strlen(sp_end
);
1127 newunixpath
= AllocVec(hlen
+ splen
+ 1, MEMF_PUBLIC
);
1130 char *s
= newunixpath
;
1132 CopyMem(home
, s
, hlen
);
1134 CopyMem(sp_end
, s
, splen
);
1143 ULONG
GetCurrentDir(struct emulbase
*emulbase
, char *path
, ULONG len
)
1148 res
= emulbase
->pdata
.KernelIFace
->GetCurrentDirectory(len
, path
);
1151 return (res
< len
) ? TRUE
: FALSE
;
1154 BOOL
CheckDir(struct emulbase
*emulbase
, char *path
)
1159 attrs
= emulbase
->pdata
.KernelIFace
->GetFileAttributes(path
);
1162 if (attrs
== INVALID_FILE_ATTRIBUTES
)
1165 return (attrs
& FILE_ATTRIBUTE_DIRECTORY
) ? FALSE
: TRUE
;