2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
6 #include "unix_hints.h"
8 #ifdef HOST_LONG_ALIGNED
16 #include <sys/types.h>
20 /* This prevents redefinition of struct timeval */
21 #define _AROS_TYPES_TIMEVAL_S_H_
32 #include <aros/debug.h>
33 #include <aros/symbolsets.h>
34 #include <dos/dosasl.h>
35 #include <hidd/unixio.h>
36 #include <utility/date.h>
37 #include <proto/dos.h>
38 #include <proto/exec.h>
39 #include <proto/hostlib.h>
40 #include <proto/kernel.h>
41 #include <proto/utility.h>
43 #include "emul_intern.h"
44 #include "emul_unix.h"
46 #define NO_CASE_SENSITIVITY
48 struct dirent
*ReadDir(struct emulbase
*emulbase
, struct filehandle
*fh
, IPTR
*dirpos
);
50 /*********************************************************************************************/
52 /* Make an AROS error-code (<dos/dos.h>) out of a unix error-code. */
55 { ENOMEM
, ERROR_NO_FREE_STORE
},
56 { ENOENT
, ERROR_OBJECT_NOT_FOUND
},
57 { EEXIST
, ERROR_OBJECT_EXISTS
},
58 { EACCES
, ERROR_WRITE_PROTECTED
}, /* AROS distinguishes between different
59 kinds of privelege violation. Therefore
60 a routine using err_u2a(emulbase) should check
61 for ERROR_WRITE_PROTECTED and replace
62 it by a different constant, if
64 { ENOTDIR
, ERROR_DIR_NOT_FOUND
},
65 { ENOSPC
, ERROR_DISK_FULL
},
66 { ENOTEMPTY
, ERROR_DIRECTORY_NOT_EMPTY
},
67 { EISDIR
, ERROR_OBJECT_WRONG_TYPE
},
68 { ETXTBSY
, ERROR_OBJECT_IN_USE
},
69 { ENAMETOOLONG
, ERROR_OBJECT_TOO_LARGE
},
70 { EROFS
, ERROR_WRITE_PROTECTED
},
74 static LONG
errno_u2a(int err
)
78 for (i
= 0; i
< sizeof(u2a
)/sizeof(u2a
[0]); i
++)
87 static inline LONG
err_u2a(struct emulbase
*emulbase
)
89 return errno_u2a(*emulbase
->pdata
.errnoPtr
);
92 /*********************************************************************************************/
94 /* Make unix protection bits out of AROS protection bits. */
95 static mode_t
prot_a2u(ULONG protect
)
99 /* The following three flags are low-active! */
100 if (!(protect
& FIBF_EXECUTE
))
102 if (!(protect
& FIBF_WRITE
))
104 if (!(protect
& FIBF_READ
))
107 if ((protect
& FIBF_GRP_EXECUTE
))
109 if ((protect
& FIBF_GRP_WRITE
))
111 if ((protect
& FIBF_GRP_READ
))
114 if ((protect
& FIBF_OTR_EXECUTE
))
116 if ((protect
& FIBF_OTR_WRITE
))
118 if ((protect
& FIBF_OTR_READ
))
121 if ((protect
& FIBF_SCRIPT
))
127 /*********************************************************************************************/
129 /* Make AROS protection bits out of unix protection bits. */
130 static ULONG
prot_u2a(mode_t protect
)
134 /* The following three (AROS) flags are low-active! */
135 if (!(protect
& S_IRUSR
))
137 if (!(protect
& S_IWUSR
))
139 if (!(protect
& S_IXUSR
))
140 aprot
|= FIBF_EXECUTE
;
142 /* The following flags are high-active again. */
143 if ((protect
& S_IRGRP
))
144 aprot
|= FIBF_GRP_READ
;
145 if ((protect
& S_IWGRP
))
146 aprot
|= FIBF_GRP_WRITE
;
147 if ((protect
& S_IXGRP
))
148 aprot
|= FIBF_GRP_EXECUTE
;
150 if ((protect
& S_IROTH
))
151 aprot
|= FIBF_OTR_READ
;
152 if ((protect
& S_IWOTH
))
153 aprot
|= FIBF_OTR_WRITE
;
154 if ((protect
& S_IXOTH
))
155 aprot
|= FIBF_OTR_EXECUTE
;
157 if ((protect
& S_ISVTX
))
158 aprot
|= FIBF_SCRIPT
;
163 /*********************************************************************************************/
165 static void timestamp2datestamp(struct emulbase
*emulbase
, time_t *timestamp
, struct DateStamp
*datestamp
)
167 struct ClockData date
;
172 tm
= emulbase
->pdata
.SysIFace
->localtime(timestamp
);
177 date
.year
= tm
->tm_year
+ 1900;
178 date
.month
= tm
->tm_mon
+ 1;
179 date
.mday
= tm
->tm_mday
;
180 date
.hour
= tm
->tm_hour
;
181 date
.min
= tm
->tm_min
;
182 date
.sec
= tm
->tm_sec
;
184 ULONG secs
= Date2Amiga(&date
);
186 datestamp
->ds_Days
= secs
/ (60 * 60 * 24);
187 secs
%= (60 * 60 * 24);
188 datestamp
->ds_Minute
= secs
/ 60;
190 datestamp
->ds_Tick
= secs
* TICKS_PER_SECOND
;
193 /*********************************************************************************************/
195 static time_t datestamp2timestamp(struct emulbase
*emulbase
, struct DateStamp
*datestamp
)
197 ULONG secs
= datestamp
->ds_Days
* (60 * 60 * 24) +
198 datestamp
->ds_Minute
* 60 +
199 datestamp
->ds_Tick
/ TICKS_PER_SECOND
;
201 struct ClockData date
;
205 Amiga2Date(secs
, &date
);
207 tm
.tm_year
= date
.year
- 1900;
208 tm
.tm_mon
= date
.month
- 1;
209 tm
.tm_mday
= date
.mday
;
210 tm
.tm_hour
= date
.hour
;
211 tm
.tm_min
= date
.min
;
212 tm
.tm_sec
= date
.sec
;
214 ret
= emulbase
->pdata
.SysIFace
->mktime(&tm
);
220 /*********************************************************************************************/
222 #ifdef NO_CASE_SENSITIVITY
224 static void fixcase(struct emulbase
*emulbase
, char *pathname
)
226 struct LibCInterface
*iface
= emulbase
->pdata
.SysIFace
;
230 char *pathstart
, *pathend
;
234 pathstart
= pathname
;
236 res
= emulbase
->pdata
.SysIFace
->lstat((const char *)pathname
, &st
);
240 /* Pathname exists, no need to fix anything */
243 while((pathstart
= strchr(pathstart
, '/')))
247 pathend
= strchr(pathstart
, '/');
248 if (pathend
) *pathend
= '\0';
252 res
= emulbase
->pdata
.SysIFace
->lstat(pathname
, &st
);
258 pathstart
[-1] = '\0';
259 dir
= emulbase
->pdata
.SysIFace
->opendir(pathname
);
267 de
= emulbase
->pdata
.SysIFace
->readdir(dir
);
272 if (Stricmp(de
->d_name
, pathstart
) == 0)
275 strcpy(pathstart
, de
->d_name
);
279 iface
->closedir(dir
);
283 } /* if (stat((const char *)pathname, &st) != 0) */
285 if (pathend
) *pathend
= '/';
287 if (!dirfound
) break;
289 } /* while((pathpos = strchr(pathpos, '/))) */
294 #define fixcase(emulbase, pathname)
298 /*-------------------------------------------------------------------------------------------*/
300 static int inline nocase_lstat(struct emulbase
*emulbase
, char *file_name
, struct stat
*st
)
304 fixcase(emulbase
, file_name
);
305 ret
= emulbase
->pdata
.SysIFace
->lstat(file_name
, st
);
311 /*-------------------------------------------------------------------------------------------*/
313 static inline int nocase_unlink(struct emulbase
*emulbase
, char *pathname
)
317 fixcase(emulbase
, pathname
);
318 ret
= emulbase
->pdata
.SysIFace
->unlink((const char *)pathname
);
324 /*-------------------------------------------------------------------------------------------*/
326 static inline int nocase_mkdir(struct emulbase
*emulbase
, char *pathname
, mode_t mode
)
330 fixcase(emulbase
, pathname
);
331 ret
= emulbase
->pdata
.SysIFace
->mkdir(pathname
, mode
);
337 /*-------------------------------------------------------------------------------------------*/
339 static inline int nocase_rmdir(struct emulbase
*emulbase
, char *pathname
)
343 fixcase(emulbase
, pathname
);
344 ret
= emulbase
->pdata
.SysIFace
->rmdir(pathname
);
350 /*-------------------------------------------------------------------------------------------*/
352 static inline int nocase_link(struct emulbase
*emulbase
, char *oldpath
, char *newpath
)
356 fixcase(emulbase
, oldpath
);
357 fixcase(emulbase
, newpath
);
359 ret
= emulbase
->pdata
.SysIFace
->link(oldpath
, newpath
);
365 /*-------------------------------------------------------------------------------------------*/
367 static inline int nocase_symlink(struct emulbase
*emulbase
, char *oldpath
, char *newpath
)
369 fixcase(emulbase
, oldpath
);
370 fixcase(emulbase
, newpath
);
372 return emulbase
->pdata
.SysIFace
->symlink(oldpath
, newpath
);
375 /*-------------------------------------------------------------------------------------------*/
377 static inline int nocase_rename(struct emulbase
*emulbase
, char *oldpath
, char *newpath
)
382 fixcase(emulbase
, oldpath
);
383 fixcase(emulbase
, newpath
);
385 /* AmigaDOS Rename does not allow overwriting */
386 ret
= emulbase
->pdata
.SysIFace
->lstat(newpath
, &st
);
389 return ERROR_OBJECT_EXISTS
;
391 ret
= emulbase
->pdata
.SysIFace
->rename(oldpath
, newpath
);
397 /*-------------------------------------------------------------------------------------------*/
399 static inline int nocase_chmod(struct emulbase
*emulbase
, char *path
, mode_t mode
)
403 fixcase(emulbase
, path
);
405 ret
= emulbase
->pdata
.SysIFace
->chmod(path
, mode
);
411 /*-------------------------------------------------------------------------------------------*/
413 static inline int nocase_readlink(struct emulbase
*emulbase
, char *path
, char *buffer
, SIPTR size
)
417 fixcase(emulbase
, path
);
419 ret
= emulbase
->pdata
.SysIFace
->readlink(path
, buffer
, size
);
425 static inline int nocase_utime(struct emulbase
*emulbase
, char *path
, const struct utimbuf
*times
)
429 fixcase(emulbase
, path
);
430 ret
= emulbase
->pdata
.SysIFace
->utime(path
, times
);
436 /*-------------------------------------------------------------------------------------------*/
438 LONG
DoOpen(struct emulbase
*emulbase
, struct filehandle
*fh
, LONG access
, LONG mode
, LONG protect
, BOOL AllowDir
)
441 LONG ret
= ERROR_OBJECT_WRONG_TYPE
;
444 DOPEN(bug("[emul] Opening host name: %s\n", fh
->hostname
));
448 r
= nocase_lstat(emulbase
, fh
->hostname
, &st
);
449 /* File name case is already adjusted here, so after this we can call UNIX functions directly */
453 /* Non-existing objects can be files opened for writing */
454 st
.st_mode
= S_IFREG
;
457 DOPEN(bug("[emul] lstat() returned %d, st_mode is 0x%08X\n", r
, st
.st_mode
));
459 if (S_ISREG(st
.st_mode
))
461 /* Object is a plain file */
462 int flags
= O_RDONLY
;
463 if (access
!= ACCESS_READ
)
476 r
= emulbase
->pdata
.SysIFace
->open(fh
->hostname
, flags
, 0770);
479 if (r
< 0 && err_u2a(emulbase
) == ERROR_WRITE_PROTECTED
)
481 /* Try again with read-only access. This is needed because AROS
482 * FS handlers should only pay attention to R/W protection flags
483 * when the corresponding operation is attempted on the file */
484 r
= emulbase
->pdata
.SysIFace
->open(fh
->hostname
, O_RDONLY
, 0770);
490 fh
->fd
= (void *)(IPTR
)r
;
494 ret
= err_u2a(emulbase
);
497 if (AllowDir
&& S_ISDIR(st
.st_mode
))
499 /* Object is a directory */
500 fh
->fd
= emulbase
->pdata
.SysIFace
->opendir(fh
->hostname
);
501 #ifndef HOST_OS_android
502 fh
->ph
.dirpos_first
= emulbase
->pdata
.SysIFace
->telldir(fh
->fd
);
508 fh
->type
= FHD_DIRECTORY
;
512 ret
= err_u2a(emulbase
);
515 if (S_ISLNK(st
.st_mode
))
516 /* Object is a softlink */
517 ret
= ERROR_IS_SOFT_LINK
;
524 void DoClose(struct emulbase
*emulbase
, struct filehandle
*current
)
528 switch(current
->type
)
531 /* Nothing will happen if type has FHD_STDIO set, this is intentional */
532 emulbase
->pdata
.SysIFace
->close((IPTR
)current
->fd
);
537 emulbase
->pdata
.SysIFace
->closedir(current
->fd
);
545 LONG
DoRead(struct emulbase
*emulbase
, struct filehandle
*fh
, APTR buff
, ULONG len
, SIPTR
*err
)
550 DREAD(bug("[emul] Reading %u bytes from fd %ld\n", len
, fh
->fd
));
552 /* Wait until the fd is ready to read. We reuse UnixIO capabilities for this. */
553 error
= Hidd_UnixIO_Wait(emulbase
->pdata
.unixio
, (long)fh
->fd
, vHidd_UnixIO_Read
);
556 *err
= errno_u2a(error
);
562 DREAD(bug("[emul] FD %ld ready for read\n", fh
->fd
));
564 if (fh
->type
& FHD_STDIO
)
567 struct pollfd pfd
= {(long)fh
->fd
, POLLIN
, 0};
570 * When reading from stdin, we have to read character-by-character until
571 * we read as many characters as we wanted, or there's nothing more to read.
572 * Without this read() can return an error. For example this happens on Darwin
573 * when the shell requests a single read of 208 bytes.
578 res2
= emulbase
->pdata
.SysIFace
->read((long)fh
->fd
, buff
++, 1);
587 res2
= emulbase
->pdata
.SysIFace
->poll(&pfd
, 1, 0);
597 /* It's not stdin. Read as much as we need to. */
598 res
= emulbase
->pdata
.SysIFace
->read((long)fh
->fd
, buff
, len
);
603 error
= err_u2a(emulbase
);
607 DREAD(bug("[emul] Result %d, error %ld\n", len
, error
));
613 LONG
DoWrite(struct emulbase
*emulbase
, struct filehandle
*fh
, CONST_APTR buff
, ULONG len
, SIPTR
*err
)
617 DWRITE(bug("[emul] Writing %u bytes to fd %ld\n", len
, fh
->fd
));
621 len
= emulbase
->pdata
.SysIFace
->write((IPTR
)fh
->fd
, buff
, len
);
624 error
= err_u2a(emulbase
);
632 SIPTR
DoSeek(struct emulbase
*emulbase
, struct filehandle
*fh
, SIPTR offset
, ULONG mode
, SIPTR
*err
)
635 LONG oldpos
= 0, newpos
;
638 DSEEK(bug("[emul] DoSeek(%d, %d, %d)\n", (int)fh
->fd
, offset
, mode
));
642 res
= oldpos
= LSeek((IPTR
)fh
->fd
, 0, SEEK_CUR
);
645 res
= emulbase
->pdata
.SysIFace
->fstat((int)(IPTR
)fh
->fd
, &st
);
648 DSEEK(bug("[emul] Original position: %lu\n", (unsigned long)oldpos
));
653 case OFFSET_BEGINNING
:
659 newpos
= offset
+ res
;
664 newpos
= offset
+ st
.st_size
;
668 if (newpos
> st
.st_size
)
674 res
= LSeek((IPTR
)fh
->fd
, offset
, mode
);
677 DSEEK(bug("[emul] New position: %lu\n", (unsigned long)res
));
685 *err
= ERROR_SEEK_ERROR
;
689 LONG
DoMkDir(struct emulbase
*emulbase
, struct filehandle
*fh
, ULONG protect
)
693 protect
= prot_a2u(protect
);
697 ret
= nocase_mkdir(emulbase
, fh
->hostname
, protect
);
700 fh
->type
= FHD_DIRECTORY
;
701 fh
->fd
= emulbase
->pdata
.SysIFace
->opendir(fh
->hostname
);
702 #ifndef HOST_OS_android
703 fh
->ph
.dirpos_first
= emulbase
->pdata
.SysIFace
->telldir(fh
->fd
);
708 if ((ret
== -1) || (fh
->fd
== NULL
))
709 ret
= err_u2a(emulbase
);
716 LONG
DoDelete(struct emulbase
*emulbase
, char *name
)
723 ret
= nocase_lstat(emulbase
, name
, &st
);
727 if (S_ISDIR(st
.st_mode
))
729 ret
= emulbase
->pdata
.SysIFace
->rmdir(name
);
734 ret
= emulbase
->pdata
.SysIFace
->unlink(name
);
740 ret
= err_u2a(emulbase
);
747 LONG
DoChMod(struct emulbase
*emulbase
, char *filename
, ULONG prot
)
753 ret
= nocase_chmod(emulbase
, filename
, prot_a2u(prot
));
755 ret
= err_u2a(emulbase
);
762 LONG
DoHardLink(struct emulbase
*emulbase
, char *fn
, char *oldfile
)
768 error
= nocase_link(emulbase
, oldfile
, fn
);
770 error
= err_u2a(emulbase
);
777 LONG
DoSymLink(struct emulbase
*emulbase
, char *dest
, char *src
)
783 error
= nocase_symlink(emulbase
, dest
, src
);
785 error
= err_u2a(emulbase
);
792 int DoReadLink(struct emulbase
*emulbase
, char *filename
, char *buffer
, ULONG size
, LONG
*err
)
798 res
= nocase_readlink(emulbase
, filename
, buffer
, size
);
800 *err
= err_u2a(emulbase
);
801 else if (res
== size
)
802 /* Buffer was too small */
810 LONG
DoRename(struct emulbase
*emulbase
, char *filename
, char *newfilename
)
816 error
= nocase_rename(emulbase
, filename
, newfilename
);
818 error
= err_u2a(emulbase
);
825 LONG
DoSetDate(struct emulbase
*emulbase
, char *name
, struct DateStamp
*date
)
827 struct utimbuf times
;
832 times
.actime
= datestamp2timestamp(emulbase
, date
);
833 times
.modtime
= times
.actime
;
835 res
= nocase_utime(emulbase
, name
, ×
);
837 res
= err_u2a(emulbase
);
844 SIPTR
DoSetSize(struct emulbase
*emulbase
, struct filehandle
*fh
, SIPTR offset
, ULONG mode
, SIPTR
*err
)
852 case OFFSET_BEGINNING
:
857 absolute
= LSeek((IPTR
)fh
->fd
, 0, SEEK_CUR
);
861 error
= err_u2a(emulbase
);
867 absolute
= LSeek((IPTR
)fh
->fd
, 0, SEEK_END
);
871 error
= err_u2a(emulbase
);
877 error
= ERROR_UNKNOWN
;
882 error
= FTruncate((IPTR
)fh
->fd
, absolute
);
885 error
= err_u2a(emulbase
);
894 LONG
DoStatFS(struct emulbase
*emulbase
, char *path
, struct InfoData
*id
)
901 err
= emulbase
->pdata
.SysIFace
->statfs(path
, &buf
);
904 err
= err_u2a(emulbase
);
910 id
->id_NumSoftErrors
= 0;
911 id
->id_DiskState
= ID_VALIDATED
;
912 id
->id_NumBlocks
= buf
.f_blocks
;
913 id
->id_NumBlocksUsed
= buf
.f_blocks
- buf
.f_bavail
;
914 id
->id_BytesPerBlock
= buf
.f_bsize
;
920 LONG
DoRewindDir(struct emulbase
*emulbase
, struct filehandle
*fh
)
924 emulbase
->pdata
.SysIFace
->rewinddir(fh
->fd
);
929 /* Directory search position has been reset */
932 /* rewinddir() never fails */
936 static LONG
stat_entry(struct emulbase
*emulbase
, struct filehandle
*fh
, STRPTR FoundName
, struct stat
*st
)
938 STRPTR filename
, name
;
942 DEXAM(bug("[emul] stat_entry(): filehandle's path: %s\n", fh
->hostname
));
945 DEXAM(bug("[emul] ...containing object: %s\n", FoundName
));
946 plen
= strlen(fh
->hostname
);
947 flen
= strlen(FoundName
);
948 name
= AllocVecPooled(emulbase
->mempool
, plen
+ flen
+ 2);
950 return ERROR_NO_FREE_STORE
;
952 strcpy(name
, fh
->hostname
);
953 filename
= name
+ plen
;
955 strcpy(filename
, FoundName
);
959 DEXAM(bug("[emul] Full name: %s\n", name
));
963 err
= emulbase
->pdata
.SysIFace
->lstat(name
, st
);
966 err
= err_u2a(emulbase
);
972 DEXAM(bug("[emul] Freeing full name\n"));
973 FreeVecPooled(emulbase
->mempool
, name
);
978 LONG
DoExamineEntry(struct emulbase
*emulbase
, struct filehandle
*fh
, char *EntryName
,
979 struct ExAllData
*ead
, ULONG size
, ULONG type
)
981 STRPTR next
, end
, last
, name
;
985 DEXAM(bug("[emul] DoExamineEntry(0x%p, %s, 0x%p, %u, %u)\n", fh
, EntryName
, ead
, size
, type
));
987 /* Return an error, if supplied type is not supported. */
989 return ERROR_BAD_NUMBER
;
991 /* Check, if the supplied buffer is large enough. */
992 next
=(STRPTR
)ead
+sizes
[type
];
993 end
=(STRPTR
)ead
+size
;
994 DEXAM(bug("[emul] ead 0x%p, next 0x%p, end 0x%p\n", ead
, next
, end
));
996 if(next
>end
) /* > is correct. Not >= */
997 return ERROR_BUFFER_OVERFLOW
;
999 err
= stat_entry(emulbase
, fh
, EntryName
, &st
);
1003 DEXAM(KrnPrintf("[emul] File mode %o, size %u\n", st
.st_mode
, st
.st_size
));
1004 DEXAM(KrnPrintf("[emul] Filling in information\n"));
1005 DEXAM(KrnPrintf("[emul] ead 0x%p, next 0x%p, end 0x%p, size %u, type %u\n", ead
, next
, end
, size
, type
));
1011 ead
->ed_OwnerUID
= st
.st_uid
;
1012 ead
->ed_OwnerGID
= st
.st_gid
;
1014 ead
->ed_Comment
=NULL
;
1017 struct DateStamp stamp
;
1019 timestamp2datestamp(emulbase
, &st
.st_mtime
, &stamp
);
1020 ead
->ed_Days
= stamp
.ds_Days
;
1021 ead
->ed_Mins
= stamp
.ds_Minute
;
1022 ead
->ed_Ticks
= stamp
.ds_Tick
;
1025 ead
->ed_Prot
= prot_u2a(st
.st_mode
);
1027 ead
->ed_Size
= st
.st_size
;
1029 if (S_ISDIR(st
.st_mode
)) {
1030 if (EntryName
|| fh
->name
[0])
1031 ead
->ed_Type
= ST_USERDIR
;
1033 ead
->ed_Type
= ST_ROOT
;
1034 } else if (S_ISLNK(st
.st_mode
))
1035 ead
->ed_Type
= ST_SOFTLINK
;
1037 ead
->ed_Type
= ST_FILE
;
1042 else if (*fh
->name
) {
1050 last
= fh
->volumename
;
1056 return ERROR_BUFFER_OVERFLOW
;
1057 if(!(*next
++=*last
++))
1061 ead
->ed_Next
=(struct ExAllData
*)(((IPTR
)next
+AROS_PTRALIGN
-1)&~(AROS_PTRALIGN
-1));
1066 /*********************************************************************************************/
1068 LONG
DoExamineNext(struct emulbase
*emulbase
, struct filehandle
*fh
,
1069 struct FileInfoBlock
*FIB
)
1077 /* This operation does not make any sense on a file */
1078 if (fh
->type
!= FHD_DIRECTORY
)
1079 return ERROR_OBJECT_WRONG_TYPE
;
1084 * First of all we have to go to the position where Examine() or
1085 * ExNext() stopped the previous time so we can read the next entry!
1086 * On Android this is handled by ReadDir() artificially tracking
1087 * current search position in the filehandle.
1089 #ifndef HOST_OS_android
1090 emulbase
->pdata
.SysIFace
->seekdir(fh
->fd
, FIB
->fib_DiskKey
);
1094 /* hm, let's read the data now! */
1095 dir
= ReadDir(emulbase
, fh
, &FIB
->fib_DiskKey
);
1100 return ERROR_NO_MORE_ENTRIES
;
1102 err
= stat_entry(emulbase
, fh
, dir
->d_name
, &st
);
1105 DEXAM(bug("stat_entry() failed for %s\n", dir
->d_name
));
1109 DEXAM(KrnPrintf("[emul] File mode %o, size %u\n", st
.st_mode
, st
.st_size
));
1111 FIB
->fib_OwnerUID
= st
.st_uid
;
1112 FIB
->fib_OwnerGID
= st
.st_gid
;
1113 FIB
->fib_Comment
[0] = '\0'; /* no comments available yet! */
1114 timestamp2datestamp(emulbase
, &st
.st_mtime
, &FIB
->fib_Date
);
1115 FIB
->fib_Protection
= prot_u2a(st
.st_mode
);
1116 FIB
->fib_Size
= st
.st_size
;
1118 if (S_ISDIR(st
.st_mode
))
1120 FIB
->fib_DirEntryType
= ST_USERDIR
; /* S_ISDIR(st.st_mode)?(*fh->name?ST_USERDIR:ST_ROOT):0*/
1122 else if(S_ISLNK(st
.st_mode
))
1124 FIB
->fib_DirEntryType
= ST_SOFTLINK
;
1128 FIB
->fib_DirEntryType
= ST_FILE
;
1131 DEXAM(bug("[emul] DirentryType %d\n", FIB
->fib_DirEntryType
));
1133 /* fast copying of the filename */
1135 dest
= &FIB
->fib_FileName
[1];
1137 for (i
=0; i
<MAXFILENAMELENGTH
-1;i
++)
1139 if(! (*dest
++=*src
++) )
1144 FIB
->fib_FileName
[0] = i
;
1149 /*********************************************************************************************/
1151 LONG
DoExamineAll(struct emulbase
*emulbase
, struct filehandle
*fh
, struct ExAllData
*ead
,
1152 struct ExAllControl
*eac
, ULONG size
, ULONG type
, struct DosLibrary
*DOSBase
)
1154 struct ExAllData
*last
=NULL
;
1155 STRPTR end
=(STRPTR
)ead
+size
;
1158 #ifndef HOST_OS_android
1162 eac
->eac_Entries
= 0;
1163 if(fh
->type
!=FHD_DIRECTORY
)
1164 return ERROR_OBJECT_WRONG_TYPE
;
1166 DEXAM(bug("[emul] examine_all()\n"));
1169 #ifndef HOST_OS_android
1172 if (eac
->eac_LastKey
== 0)
1174 /* Theoretically this doesn't work if opendir/telldir "handle"
1175 can be 0 for a dir entry which is not the first one! */
1177 eac
->eac_LastKey
= fh
->ph
.dirpos_first
;
1180 emulbase
->pdata
.SysIFace
->seekdir(fh
->fd
, eac
->eac_LastKey
);
1190 #ifndef HOST_OS_android
1191 oldpos
= eac
->eac_LastKey
;
1193 //oldpos = emulbase->pdata.SysIFace->telldir(fh->fd);
1197 *emulbase
->pdata
.errnoPtr
= 0;
1198 dir
= ReadDir(emulbase
, fh
, &eac
->eac_LastKey
);
1201 error
= err_u2a(emulbase
);
1208 DEXAM(bug("[emul] Found entry %s\n", dir
->d_name
));
1210 if (eac
->eac_MatchString
&& !MatchPatternNoCase(eac
->eac_MatchString
, dir
->d_name
)) {
1211 DEXAM(bug("[emul] Entry does not match, skipping\n"));
1215 error
= DoExamineEntry(emulbase
, fh
, dir
->d_name
, ead
, end
-(STRPTR
)ead
, type
);
1219 if ((eac
->eac_MatchFunc
) && !CALLHOOKPKT(eac
->eac_MatchFunc
, ead
, &type
))
1229 if ((error
==ERROR_BUFFER_OVERFLOW
) && last
)
1231 #ifdef HOST_OS_android
1234 eac
->eac_LastKey
= oldpos
;
1237 //emulbase->pdata.SysIFace->seekdir(fh->fd, oldpos);
1241 /* Examination will continue from the current position */
1246 error
= ERROR_NO_MORE_ENTRIES
;
1247 /* Reading the whole directory has been completed, so reset position */
1248 DoRewindDir(emulbase
, fh
);
1253 char *GetHomeDir(struct emulbase
*emulbase
, char *sp
)
1256 char *newunixpath
= NULL
;
1258 #ifndef HOST_OS_android
1259 BOOL do_endpwent
= FALSE
;
1264 /* "~<name>" means home of user <name> */
1265 if ((sp
[1] == '\0') || (sp
[1] == '/'))
1268 home
= emulbase
->pdata
.SysIFace
->getenv("HOME");
1271 #ifndef HOST_OS_android
1277 for(sp_end
= sp
+ 1; sp_end
[0] != '\0' && sp_end
[0] != '/'; sp_end
++);
1278 cmplen
= sp_end
- sp
- 1;
1282 pwd
= emulbase
->pdata
.SysIFace
->getpwent();
1288 if(memcmp(pwd
->pw_name
, sp
+ 1, cmplen
) == 0)
1290 if (pwd
->pw_name
[cmplen
] == '\0')
1303 int hlen
= strlen(home
);
1304 int splen
= strlen(sp_end
);
1306 newunixpath
= AllocVecPooled(emulbase
->mempool
, hlen
+ splen
+ 1);
1309 char *s
= newunixpath
;
1311 CopyMem(home
, s
, hlen
);
1313 CopyMem(sp_end
, s
, splen
);
1319 #ifndef HOST_OS_android
1322 emulbase
->pdata
.SysIFace
->endpwent();
1332 ULONG
GetCurrentDir(struct emulbase
*emulbase
, char *path
, ULONG len
)
1336 DMOUNT(bug("[emul] GetCurrentDir(0x%p, %u)\n", path
, len
));
1340 res
= emulbase
->pdata
.SysIFace
->getcwd(path
, len
);
1345 DMOUNT(bug("[emul] getcwd() returned %s\n", res
));
1346 return res
? TRUE
: FALSE
;
1349 BOOL
CheckDir(struct emulbase
*emulbase
, char *path
)
1354 DMOUNT(bug("[emul] CheckDir(%s)\n", path
));
1358 res
= emulbase
->pdata
.SysIFace
->stat(path
, &st
);
1363 DMOUNT(bug("[emul] Result: %d, mode: %o\n", res
, st
.st_mode
));
1364 if ((!res
) && S_ISDIR(st
.st_mode
))