2 Copyright © 1995-2011, 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_inline.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
++)
84 #ifdef PassThroughErrnos
85 return err
+ PassThroughErrnos
;
91 static inline LONG
err_u2a(struct emulbase
*emulbase
)
93 return errno_u2a(*emulbase
->pdata
.errnoPtr
);
96 /*********************************************************************************************/
98 /* Make unix protection bits out of AROS protection bits. */
99 static mode_t
prot_a2u(ULONG protect
)
103 /* The following three flags are low-active! */
104 if (!(protect
& FIBF_EXECUTE
))
106 if (!(protect
& FIBF_WRITE
))
108 if (!(protect
& FIBF_READ
))
111 if ((protect
& FIBF_GRP_EXECUTE
))
113 if ((protect
& FIBF_GRP_WRITE
))
115 if ((protect
& FIBF_GRP_READ
))
118 if ((protect
& FIBF_OTR_EXECUTE
))
120 if ((protect
& FIBF_OTR_WRITE
))
122 if ((protect
& FIBF_OTR_READ
))
125 if ((protect
& FIBF_SCRIPT
))
131 /*********************************************************************************************/
133 /* Make AROS protection bits out of unix protection bits. */
134 static ULONG
prot_u2a(mode_t protect
)
138 /* The following three (AROS) flags are low-active! */
139 if (!(protect
& S_IRUSR
))
141 if (!(protect
& S_IWUSR
))
143 if (!(protect
& S_IXUSR
))
144 aprot
|= FIBF_EXECUTE
;
146 /* The following flags are high-active again. */
147 if ((protect
& S_IRGRP
))
148 aprot
|= FIBF_GRP_READ
;
149 if ((protect
& S_IWGRP
))
150 aprot
|= FIBF_GRP_WRITE
;
151 if ((protect
& S_IXGRP
))
152 aprot
|= FIBF_GRP_EXECUTE
;
154 if ((protect
& S_IROTH
))
155 aprot
|= FIBF_OTR_READ
;
156 if ((protect
& S_IWOTH
))
157 aprot
|= FIBF_OTR_WRITE
;
158 if ((protect
& S_IXOTH
))
159 aprot
|= FIBF_OTR_EXECUTE
;
161 if ((protect
& S_ISVTX
))
162 aprot
|= FIBF_SCRIPT
;
167 /*********************************************************************************************/
169 static void timestamp2datestamp(struct emulbase
*emulbase
, time_t *timestamp
, struct DateStamp
*datestamp
)
171 struct ClockData date
;
176 tm
= emulbase
->pdata
.SysIFace
->localtime(timestamp
);
181 date
.year
= tm
->tm_year
+ 1900;
182 date
.month
= tm
->tm_mon
+ 1;
183 date
.mday
= tm
->tm_mday
;
184 date
.hour
= tm
->tm_hour
;
185 date
.min
= tm
->tm_min
;
186 date
.sec
= tm
->tm_sec
;
188 ULONG secs
= Date2Amiga(&date
);
190 datestamp
->ds_Days
= secs
/ (60 * 60 * 24);
191 secs
%= (60 * 60 * 24);
192 datestamp
->ds_Minute
= secs
/ 60;
194 datestamp
->ds_Tick
= secs
* TICKS_PER_SECOND
;
197 /*********************************************************************************************/
199 static time_t datestamp2timestamp(struct emulbase
*emulbase
, struct DateStamp
*datestamp
)
201 ULONG secs
= datestamp
->ds_Days
* (60 * 60 * 24) +
202 datestamp
->ds_Minute
* 60 +
203 datestamp
->ds_Tick
/ TICKS_PER_SECOND
;
205 struct ClockData date
;
209 Amiga2Date(secs
, &date
);
211 tm
.tm_year
= date
.year
- 1900;
212 tm
.tm_mon
= date
.month
- 1;
213 tm
.tm_mday
= date
.mday
;
214 tm
.tm_hour
= date
.hour
;
215 tm
.tm_min
= date
.min
;
216 tm
.tm_sec
= date
.sec
;
218 ret
= emulbase
->pdata
.SysIFace
->mktime(&tm
);
224 /*********************************************************************************************/
226 #ifdef NO_CASE_SENSITIVITY
228 static void fixcase(struct emulbase
*emulbase
, char *pathname
)
230 struct LibCInterface
*iface
= emulbase
->pdata
.SysIFace
;
234 char *pathstart
, *pathend
;
238 pathstart
= pathname
;
240 res
= emulbase
->pdata
.SysIFace
->lstat((const char *)pathname
, &st
);
244 /* Pathname exists, no need to fix anything */
247 while((pathstart
= strchr(pathstart
, '/')))
251 pathend
= strchr(pathstart
, '/');
252 if (pathend
) *pathend
= '\0';
256 res
= emulbase
->pdata
.SysIFace
->lstat(pathname
, &st
);
262 pathstart
[-1] = '\0';
263 dir
= emulbase
->pdata
.SysIFace
->opendir(pathname
);
271 de
= emulbase
->pdata
.SysIFace
->readdir(dir
);
276 if (Stricmp(de
->d_name
, pathstart
) == 0)
279 strcpy(pathstart
, de
->d_name
);
283 iface
->closedir(dir
);
287 } /* if (stat((const char *)pathname, &st) != 0) */
289 if (pathend
) *pathend
= '/';
291 if (!dirfound
) break;
293 } /* while((pathpos = strchr(pathpos, '/))) */
298 #define fixcase(emulbase, pathname)
302 /*-------------------------------------------------------------------------------------------*/
304 static int inline nocase_lstat(struct emulbase
*emulbase
, char *file_name
, struct stat
*st
)
308 fixcase(emulbase
, file_name
);
309 ret
= emulbase
->pdata
.SysIFace
->lstat(file_name
, st
);
315 /*-------------------------------------------------------------------------------------------*/
317 static inline int nocase_unlink(struct emulbase
*emulbase
, char *pathname
)
321 fixcase(emulbase
, pathname
);
322 ret
= emulbase
->pdata
.SysIFace
->unlink((const char *)pathname
);
328 /*-------------------------------------------------------------------------------------------*/
330 static inline int nocase_mkdir(struct emulbase
*emulbase
, char *pathname
, mode_t mode
)
334 fixcase(emulbase
, pathname
);
335 ret
= emulbase
->pdata
.SysIFace
->mkdir(pathname
, mode
);
341 /*-------------------------------------------------------------------------------------------*/
343 static inline int nocase_rmdir(struct emulbase
*emulbase
, char *pathname
)
347 fixcase(emulbase
, pathname
);
348 ret
= emulbase
->pdata
.SysIFace
->rmdir(pathname
);
354 /*-------------------------------------------------------------------------------------------*/
356 static inline int nocase_link(struct emulbase
*emulbase
, char *oldpath
, char *newpath
)
360 fixcase(emulbase
, oldpath
);
361 fixcase(emulbase
, newpath
);
363 ret
= emulbase
->pdata
.SysIFace
->link(oldpath
, newpath
);
369 /*-------------------------------------------------------------------------------------------*/
371 static inline int nocase_symlink(struct emulbase
*emulbase
, char *oldpath
, char *newpath
)
373 fixcase(emulbase
, oldpath
);
374 fixcase(emulbase
, newpath
);
376 return emulbase
->pdata
.SysIFace
->symlink(oldpath
, newpath
);
379 /*-------------------------------------------------------------------------------------------*/
381 static inline int nocase_rename(struct emulbase
*emulbase
, char *oldpath
, char *newpath
)
386 fixcase(emulbase
, oldpath
);
387 fixcase(emulbase
, newpath
);
389 /* AmigaDOS Rename does not allow overwriting */
390 ret
= emulbase
->pdata
.SysIFace
->lstat(newpath
, &st
);
393 return ERROR_OBJECT_EXISTS
;
395 ret
= emulbase
->pdata
.SysIFace
->rename(oldpath
, newpath
);
401 /*-------------------------------------------------------------------------------------------*/
403 static inline int nocase_chmod(struct emulbase
*emulbase
, char *path
, mode_t mode
)
407 fixcase(emulbase
, path
);
409 ret
= emulbase
->pdata
.SysIFace
->chmod(path
, mode
);
415 /*-------------------------------------------------------------------------------------------*/
417 static inline int nocase_readlink(struct emulbase
*emulbase
, char *path
, char *buffer
, SIPTR size
)
421 fixcase(emulbase
, path
);
423 ret
= emulbase
->pdata
.SysIFace
->readlink(path
, buffer
, size
);
429 static inline int nocase_utime(struct emulbase
*emulbase
, char *path
, const struct utimbuf
*times
)
433 fixcase(emulbase
, path
);
434 ret
= emulbase
->pdata
.SysIFace
->utime(path
, times
);
440 /*-------------------------------------------------------------------------------------------*/
442 LONG
DoOpen(struct emulbase
*emulbase
, struct filehandle
*fh
, LONG mode
, LONG protect
, BOOL AllowDir
)
445 LONG ret
= ERROR_OBJECT_WRONG_TYPE
;
448 DOPEN(bug("[emul] Opening host name: %s\n", fh
->hostname
));
452 r
= nocase_lstat(emulbase
, fh
->hostname
, &st
);
453 /* File name case is already adjusted here, so after this we can call UNIX functions directly */
457 /* Non-existing objects can be files opened for writing */
458 st
.st_mode
= S_IFREG
;
461 DOPEN(bug("[emul] lstat() returned %d, st_mode is 0x%08X\n", r
, st
.st_mode
));
463 if (S_ISREG(st
.st_mode
))
465 /* Object is a plain file */
478 r
= emulbase
->pdata
.SysIFace
->open(fh
->hostname
, flags
, 0770);
481 if (r
< 0 && err_u2a(emulbase
) == ERROR_WRITE_PROTECTED
)
483 /* Try again with read-only access. This is needed because AROS
484 * FS handlers should only pay attention to R/W protection flags
485 * when the corresponding operation is attempted on the file */
486 r
= emulbase
->pdata
.SysIFace
->open(fh
->hostname
, O_RDONLY
, 0770);
492 fh
->fd
= (void *)(IPTR
)r
;
496 ret
= err_u2a(emulbase
);
499 if (AllowDir
&& S_ISDIR(st
.st_mode
))
501 /* Object is a directory */
502 fh
->fd
= emulbase
->pdata
.SysIFace
->opendir(fh
->hostname
);
507 fh
->type
= FHD_DIRECTORY
;
511 ret
= err_u2a(emulbase
);
514 if (S_ISLNK(st
.st_mode
))
515 /* Object is a softlink */
516 ret
= ERROR_IS_SOFT_LINK
;
523 void DoClose(struct emulbase
*emulbase
, struct filehandle
*current
)
527 switch(current
->type
)
530 /* Nothing will happen if type has FHD_STDIO set, this is intentional */
531 emulbase
->pdata
.SysIFace
->close((IPTR
)current
->fd
);
536 emulbase
->pdata
.SysIFace
->closedir(current
->fd
);
544 LONG
DoRead(struct emulbase
*emulbase
, struct filehandle
*fh
, APTR buff
, ULONG len
, SIPTR
*err
)
549 DREAD(bug("[emul] Reading %u bytes from fd %ld\n", len
, fh
->fd
));
551 /* Wait until the fd is ready to read. We reuse UnixIO capabilities for this. */
552 error
= Hidd_UnixIO_Wait(emulbase
->pdata
.unixio
, (long)fh
->fd
, vHidd_UnixIO_Read
);
555 *err
= errno_u2a(error
);
561 DREAD(bug("[emul] FD %ld ready for read\n", fh
->fd
));
563 if (fh
->type
& FHD_STDIO
)
566 struct pollfd pfd
= {(long)fh
->fd
, POLLIN
, 0};
569 * When reading from stdin, we have to read character-by-character until
570 * we read as many characters as we wanted, or there's nothing more to read.
571 * Without this read() can return an error. For example this happens on Darwin
572 * when the shell requests a single read of 208 bytes.
577 res2
= emulbase
->pdata
.SysIFace
->read((long)fh
->fd
, buff
++, 1);
586 res2
= emulbase
->pdata
.SysIFace
->poll(&pfd
, 1, 0);
596 /* It's not stdin. Read as much as we need to. */
597 res
= emulbase
->pdata
.SysIFace
->read((long)fh
->fd
, buff
, len
);
602 error
= err_u2a(emulbase
);
606 DREAD(bug("[emul] Result %d, error %ld\n", len
, error
));
612 LONG
DoWrite(struct emulbase
*emulbase
, struct filehandle
*fh
, CONST_APTR buff
, ULONG len
, SIPTR
*err
)
616 DWRITE(bug("[emul] Writing %u bytes to fd %ld\n", len
, fh
->fd
));
620 len
= emulbase
->pdata
.SysIFace
->write((IPTR
)fh
->fd
, buff
, len
);
623 error
= err_u2a(emulbase
);
631 SIPTR
DoSeek(struct emulbase
*emulbase
, struct filehandle
*fh
, SIPTR offset
, ULONG mode
, SIPTR
*err
)
637 DSEEK(bug("[emul] DoSeek(%d, %d, %d)\n", (int)fh
->fd
, offset
, mode
));
640 case OFFSET_BEGINNING
:
654 res
= LSeek((IPTR
)fh
->fd
, 0, SEEK_CUR
);
657 DSEEK(bug("[emul] Original position: %llu\n", (unsigned long long)res
));
661 res
= LSeek((IPTR
)fh
->fd
, offset
, mode
);
664 DSEEK(bug("[emul] New position: %llu\n", (unsigned long long)res
));
670 error
= err_u2a(emulbase
);
679 LONG
DoMkDir(struct emulbase
*emulbase
, struct filehandle
*fh
, ULONG protect
)
683 protect
= prot_a2u(protect
);
687 ret
= nocase_mkdir(emulbase
, fh
->hostname
, protect
);
690 fh
->type
= FHD_DIRECTORY
;
691 fh
->fd
= emulbase
->pdata
.SysIFace
->opendir(fh
->hostname
);
695 if ((ret
== -1) || (fh
->fd
== NULL
))
696 ret
= err_u2a(emulbase
);
703 LONG
DoDelete(struct emulbase
*emulbase
, char *name
)
710 ret
= nocase_lstat(emulbase
, name
, &st
);
714 if (S_ISDIR(st
.st_mode
))
716 ret
= emulbase
->pdata
.SysIFace
->rmdir(name
);
721 ret
= emulbase
->pdata
.SysIFace
->unlink(name
);
727 ret
= err_u2a(emulbase
);
734 LONG
DoChMod(struct emulbase
*emulbase
, char *filename
, ULONG prot
)
740 ret
= nocase_chmod(emulbase
, filename
, prot_a2u(prot
));
742 ret
= err_u2a(emulbase
);
749 LONG
DoHardLink(struct emulbase
*emulbase
, char *fn
, char *oldfile
)
755 error
= nocase_link(emulbase
, oldfile
, fn
);
757 error
= err_u2a(emulbase
);
764 LONG
DoSymLink(struct emulbase
*emulbase
, char *dest
, char *src
)
770 error
= nocase_symlink(emulbase
, dest
, src
);
772 error
= err_u2a(emulbase
);
779 int DoReadLink(struct emulbase
*emulbase
, char *filename
, char *buffer
, ULONG size
, LONG
*err
)
785 res
= nocase_readlink(emulbase
, filename
, buffer
, size
);
787 *err
= err_u2a(emulbase
);
788 else if (res
== size
)
789 /* Buffer was too small */
797 LONG
DoRename(struct emulbase
*emulbase
, char *filename
, char *newfilename
)
803 error
= nocase_rename(emulbase
, filename
, newfilename
);
805 error
= err_u2a(emulbase
);
812 LONG
DoSetDate(struct emulbase
*emulbase
, char *name
, struct DateStamp
*date
)
814 struct utimbuf times
;
819 times
.actime
= datestamp2timestamp(emulbase
, date
);
820 times
.modtime
= times
.actime
;
822 res
= nocase_utime(emulbase
, name
, ×
);
824 res
= err_u2a(emulbase
);
831 SIPTR
DoSetSize(struct emulbase
*emulbase
, struct filehandle
*fh
, SIPTR offset
, ULONG mode
, SIPTR
*err
)
839 case OFFSET_BEGINNING
:
844 absolute
= LSeek((IPTR
)fh
->fd
, 0, SEEK_CUR
);
848 error
= err_u2a(emulbase
);
854 absolute
= LSeek((IPTR
)fh
->fd
, 0, SEEK_END
);
858 error
= err_u2a(emulbase
);
864 error
= ERROR_UNKNOWN
;
869 error
= FTruncate((IPTR
)fh
->fd
, absolute
);
872 error
= err_u2a(emulbase
);
881 LONG
DoStatFS(struct emulbase
*emulbase
, char *path
, struct InfoData
*id
)
888 err
= emulbase
->pdata
.SysIFace
->statfs(path
, &buf
);
891 err
= err_u2a(emulbase
);
897 id
->id_NumSoftErrors
= 0;
898 id
->id_DiskState
= ID_VALIDATED
;
899 id
->id_NumBlocks
= buf
.f_blocks
;
900 id
->id_NumBlocksUsed
= buf
.f_blocks
- buf
.f_bavail
;
901 id
->id_BytesPerBlock
= buf
.f_bsize
;
907 LONG
DoRewindDir(struct emulbase
*emulbase
, struct filehandle
*fh
)
911 emulbase
->pdata
.SysIFace
->rewinddir(fh
->fd
);
916 /* Directory search position has been reset */
919 /* rewinddir() never fails */
923 static LONG
stat_entry(struct emulbase
*emulbase
, struct filehandle
*fh
, STRPTR FoundName
, struct stat
*st
)
925 STRPTR filename
, name
;
929 DEXAM(bug("[emul] stat_entry(): filehandle's path: %s\n", fh
->hostname
));
932 DEXAM(bug("[emul] ...containing object: %s\n", FoundName
));
933 plen
= strlen(fh
->hostname
);
934 flen
= strlen(FoundName
);
935 name
= AllocVecPooled(emulbase
->mempool
, plen
+ flen
+ 2);
937 return ERROR_NO_FREE_STORE
;
939 strcpy(name
, fh
->hostname
);
940 filename
= name
+ plen
;
942 strcpy(filename
, FoundName
);
946 DEXAM(bug("[emul] Full name: %s\n", name
));
950 err
= emulbase
->pdata
.SysIFace
->lstat(name
, st
);
953 err
= err_u2a(emulbase
);
959 DEXAM(bug("[emul] Freeing full name\n"));
960 FreeVecPooled(emulbase
->mempool
, name
);
965 LONG
DoExamineEntry(struct emulbase
*emulbase
, struct filehandle
*fh
, char *EntryName
,
966 struct ExAllData
*ead
, ULONG size
, ULONG type
)
968 STRPTR next
, end
, last
, name
;
972 DEXAM(bug("[emul] DoExamineEntry(0x%p, %s, 0x%p, %u, %u)\n", fh
, EntryName
, ead
, size
, type
));
974 /* Return an error, if supplied type is not supported. */
976 return ERROR_BAD_NUMBER
;
978 /* Check, if the supplied buffer is large enough. */
979 next
=(STRPTR
)ead
+sizes
[type
];
980 end
=(STRPTR
)ead
+size
;
981 DEXAM(bug("[emul] ead 0x%p, next 0x%p, end 0x%p\n", ead
, next
, end
));
983 if(next
>end
) /* > is correct. Not >= */
984 return ERROR_BUFFER_OVERFLOW
;
986 err
= stat_entry(emulbase
, fh
, EntryName
, &st
);
990 DEXAM(KrnPrintf("[emul] File mode %o, size %u\n", st
.st_mode
, st
.st_size
));
991 DEXAM(KrnPrintf("[emul] Filling in information\n"));
992 DEXAM(KrnPrintf("[emul] ead 0x%p, next 0x%p, end 0x%p, size %u, type %u\n", ead
, next
, end
, size
, type
));
998 ead
->ed_OwnerUID
= st
.st_uid
;
999 ead
->ed_OwnerGID
= st
.st_gid
;
1001 ead
->ed_Comment
=NULL
;
1004 struct DateStamp stamp
;
1006 timestamp2datestamp(emulbase
, &st
.st_mtime
, &stamp
);
1007 ead
->ed_Days
= stamp
.ds_Days
;
1008 ead
->ed_Mins
= stamp
.ds_Minute
;
1009 ead
->ed_Ticks
= stamp
.ds_Tick
;
1012 ead
->ed_Prot
= prot_u2a(st
.st_mode
);
1014 ead
->ed_Size
= st
.st_size
;
1016 if (S_ISDIR(st
.st_mode
)) {
1017 if (EntryName
|| fh
->name
[0])
1018 ead
->ed_Type
= ST_USERDIR
;
1020 ead
->ed_Type
= ST_ROOT
;
1021 } else if (S_ISLNK(st
.st_mode
))
1022 ead
->ed_Type
= ST_SOFTLINK
;
1024 ead
->ed_Type
= ST_FILE
;
1029 else if (*fh
->name
) {
1037 last
= fh
->volumename
;
1043 return ERROR_BUFFER_OVERFLOW
;
1044 if(!(*next
++=*last
++))
1048 ead
->ed_Next
=(struct ExAllData
*)(((IPTR
)next
+AROS_PTRALIGN
-1)&~(AROS_PTRALIGN
-1));
1053 /*********************************************************************************************/
1055 LONG
DoExamineNext(struct emulbase
*emulbase
, struct filehandle
*fh
,
1056 struct FileInfoBlock
*FIB
)
1064 /* This operation does not make any sense on a file */
1065 if (fh
->type
!= FHD_DIRECTORY
)
1066 return ERROR_OBJECT_WRONG_TYPE
;
1071 * First of all we have to go to the position where Examine() or
1072 * ExNext() stopped the previous time so we can read the next entry!
1073 * On Android this is handled by ReadDir() artificially tracking
1074 * current search position in the filehandle.
1076 #ifndef HOST_OS_android
1077 emulbase
->pdata
.SysIFace
->seekdir(fh
->fd
, FIB
->fib_DiskKey
);
1081 /* hm, let's read the data now! */
1082 dir
= ReadDir(emulbase
, fh
, &FIB
->fib_DiskKey
);
1087 return ERROR_NO_MORE_ENTRIES
;
1089 err
= stat_entry(emulbase
, fh
, dir
->d_name
, &st
);
1092 DEXAM(bug("stat_entry() failed for %s\n", dir
->d_name
));
1096 DEXAM(KrnPrintf("[emul] File mode %o, size %u\n", st
.st_mode
, st
.st_size
));
1098 FIB
->fib_OwnerUID
= st
.st_uid
;
1099 FIB
->fib_OwnerGID
= st
.st_gid
;
1100 FIB
->fib_Comment
[0] = '\0'; /* no comments available yet! */
1101 timestamp2datestamp(emulbase
, &st
.st_mtime
, &FIB
->fib_Date
);
1102 FIB
->fib_Protection
= prot_u2a(st
.st_mode
);
1103 FIB
->fib_Size
= st
.st_size
;
1105 if (S_ISDIR(st
.st_mode
))
1107 FIB
->fib_DirEntryType
= ST_USERDIR
; /* S_ISDIR(st.st_mode)?(*fh->name?ST_USERDIR:ST_ROOT):0*/
1109 else if(S_ISLNK(st
.st_mode
))
1111 FIB
->fib_DirEntryType
= ST_SOFTLINK
;
1115 FIB
->fib_DirEntryType
= ST_FILE
;
1118 DEXAM(bug("[emul] DirentryType %d\n", FIB
->fib_DirEntryType
));
1120 /* fast copying of the filename */
1122 dest
= &FIB
->fib_FileName
[1];
1124 for (i
=0; i
<MAXFILENAMELENGTH
-1;i
++)
1126 if(! (*dest
++=*src
++) )
1131 FIB
->fib_FileName
[0] = i
;
1136 /*********************************************************************************************/
1138 LONG
DoExamineAll(struct emulbase
*emulbase
, struct filehandle
*fh
, struct ExAllData
*ead
,
1139 struct ExAllControl
*eac
, ULONG size
, ULONG type
, struct DosLibrary
*DOSBase
)
1141 struct ExAllData
*last
=NULL
;
1142 STRPTR end
=(STRPTR
)ead
+size
;
1145 #ifndef HOST_OS_android
1149 eac
->eac_Entries
= 0;
1150 if(fh
->type
!=FHD_DIRECTORY
)
1151 return ERROR_OBJECT_WRONG_TYPE
;
1153 DEXAM(bug("[emul] examine_all()\n"));
1159 #ifndef HOST_OS_android
1160 oldpos
= emulbase
->pdata
.SysIFace
->telldir(fh
->fd
);
1164 *emulbase
->pdata
.errnoPtr
= 0;
1165 dir
= ReadDir(emulbase
, fh
, &eac
->eac_LastKey
);
1168 error
= err_u2a(emulbase
);
1175 DEXAM(bug("[emul] Found entry %s\n", dir
->d_name
));
1177 if (eac
->eac_MatchString
&& !MatchPatternNoCase(eac
->eac_MatchString
, dir
->d_name
)) {
1178 DEXAM(bug("[emul] Entry does not match, skipping\n"));
1182 error
= DoExamineEntry(emulbase
, fh
, dir
->d_name
, ead
, end
-(STRPTR
)ead
, type
);
1186 if ((eac
->eac_MatchFunc
) && !CALLHOOKPKT(eac
->eac_MatchFunc
, ead
, &type
))
1196 if ((error
==ERROR_BUFFER_OVERFLOW
) && last
)
1198 #ifdef HOST_OS_android
1203 emulbase
->pdata
.SysIFace
->seekdir(fh
->fd
, oldpos
);
1208 /* Examination will continue from the current position */
1213 error
= ERROR_NO_MORE_ENTRIES
;
1214 /* Reading the whole directory has been completed, so reset position */
1215 DoRewindDir(emulbase
, fh
);
1220 char *GetHomeDir(struct emulbase
*emulbase
, char *sp
)
1223 char *newunixpath
= NULL
;
1225 #ifndef HOST_OS_android
1226 BOOL do_endpwent
= FALSE
;
1231 /* "~<name>" means home of user <name> */
1232 if ((sp
[1] == '\0') || (sp
[1] == '/'))
1235 home
= emulbase
->pdata
.SysIFace
->getenv("HOME");
1238 #ifndef HOST_OS_android
1244 for(sp_end
= sp
+ 1; sp_end
[0] != '\0' && sp_end
[0] != '/'; sp_end
++);
1245 cmplen
= sp_end
- sp
- 1;
1249 pwd
= emulbase
->pdata
.SysIFace
->getpwent();
1255 if(memcmp(pwd
->pw_name
, sp
+ 1, cmplen
) == 0)
1257 if (pwd
->pw_name
[cmplen
] == '\0')
1270 int hlen
= strlen(home
);
1271 int splen
= strlen(sp_end
);
1273 newunixpath
= AllocVecPooled(emulbase
->mempool
, hlen
+ splen
+ 1);
1276 char *s
= newunixpath
;
1278 CopyMem(home
, s
, hlen
);
1280 CopyMem(sp_end
, s
, splen
);
1286 #ifndef HOST_OS_android
1289 emulbase
->pdata
.SysIFace
->endpwent();
1299 ULONG
GetCurrentDir(struct emulbase
*emulbase
, char *path
, ULONG len
)
1303 DMOUNT(bug("[emul] GetCurrentDir(0x%p, %u)\n", path
, len
));
1307 res
= emulbase
->pdata
.SysIFace
->getcwd(path
, len
);
1312 DMOUNT(bug("[emul] getcwd() returned %s\n", res
));
1313 return res
? TRUE
: FALSE
;
1316 BOOL
CheckDir(struct emulbase
*emulbase
, char *path
)
1321 DMOUNT(bug("[emul] CheckDir(%s)\n", path
));
1325 res
= emulbase
->pdata
.SysIFace
->stat(path
, &st
);
1330 DMOUNT(bug("[emul] Result: %d, mode: %o\n", res
, st
.st_mode
));
1331 if ((!res
) && S_ISDIR(st
.st_mode
))