Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / arch / all-unix / filesys / emul_handler / emul_host.c
blobb868e1aa4a99f7a0b5974abcbe9ab9649669c7e3
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include "unix_hints.h"
8 #ifdef HOST_LONG_ALIGNED
9 #pragma pack(4)
10 #endif
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <unistd.h>
16 #include <sys/types.h>
18 #pragma pack()
20 /* This prevents redefinition of struct timeval */
21 #define _AROS_TYPES_TIMEVAL_S_H_
23 #define DEBUG 0
24 #define DASYNC(x)
25 #define DEXAM(x)
26 #define DMOUNT(x)
27 #define DOPEN(x)
28 #define DREAD(x)
29 #define DWRITE(x)
30 #define DSEEK(x)
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. */
53 static LONG u2a[][2]=
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
63 necessary. */
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 },
71 { 0 , 0 }
74 static LONG errno_u2a(int err)
76 ULONG i;
78 for (i = 0; i < sizeof(u2a)/sizeof(u2a[0]); i++)
80 if (u2a[i][0] == err)
81 return u2a[i][1];
84 return ERROR_UNKNOWN;
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)
97 mode_t uprot = 0;
99 /* The following three flags are low-active! */
100 if (!(protect & FIBF_EXECUTE))
101 uprot |= S_IXUSR;
102 if (!(protect & FIBF_WRITE))
103 uprot |= S_IWUSR;
104 if (!(protect & FIBF_READ))
105 uprot |= S_IRUSR;
107 if ((protect & FIBF_GRP_EXECUTE))
108 uprot |= S_IXGRP;
109 if ((protect & FIBF_GRP_WRITE))
110 uprot |= S_IWGRP;
111 if ((protect & FIBF_GRP_READ))
112 uprot |= S_IRGRP;
114 if ((protect & FIBF_OTR_EXECUTE))
115 uprot |= S_IXOTH;
116 if ((protect & FIBF_OTR_WRITE))
117 uprot |= S_IWOTH;
118 if ((protect & FIBF_OTR_READ))
119 uprot |= S_IROTH;
121 if ((protect & FIBF_SCRIPT))
122 uprot |= S_ISVTX;
124 return uprot;
127 /*********************************************************************************************/
129 /* Make AROS protection bits out of unix protection bits. */
130 static ULONG prot_u2a(mode_t protect)
132 ULONG aprot = 0;
134 /* The following three (AROS) flags are low-active! */
135 if (!(protect & S_IRUSR))
136 aprot |= FIBF_READ;
137 if (!(protect & S_IWUSR))
138 aprot |= FIBF_WRITE;
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;
160 return aprot;
163 /*********************************************************************************************/
165 static void timestamp2datestamp(struct emulbase *emulbase, time_t *timestamp, struct DateStamp *datestamp)
167 struct ClockData date;
168 struct tm *tm;
170 HostLib_Lock();
172 tm = emulbase->pdata.SysIFace->localtime(timestamp);
173 AROS_HOST_BARRIER
175 HostLib_Unlock();
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;
189 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;
202 struct tm tm;
203 time_t ret;
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);
215 AROS_HOST_BARRIER
217 return ret;
220 /*********************************************************************************************/
222 #ifdef NO_CASE_SENSITIVITY
224 static void fixcase(struct emulbase *emulbase, char *pathname)
226 struct LibCInterface *iface = emulbase->pdata.SysIFace;
227 struct dirent *de;
228 struct stat st;
229 DIR *dir;
230 char *pathstart, *pathend;
231 BOOL dirfound;
232 int res;
234 pathstart = pathname;
236 res = emulbase->pdata.SysIFace->lstat((const char *)pathname, &st);
237 AROS_HOST_BARRIER
239 if (res == 0)
240 /* Pathname exists, no need to fix anything */
241 return;
243 while((pathstart = strchr(pathstart, '/')))
245 pathstart++;
247 pathend = strchr(pathstart, '/');
248 if (pathend) *pathend = '\0';
250 dirfound = TRUE;
252 res = emulbase->pdata.SysIFace->lstat(pathname, &st);
253 AROS_HOST_BARRIER
254 if (res != 0)
256 dirfound = FALSE;
258 pathstart[-1] = '\0';
259 dir = emulbase->pdata.SysIFace->opendir(pathname);
260 AROS_HOST_BARRIER
261 pathstart[-1] = '/';
263 if (dir)
265 while(1)
267 de = emulbase->pdata.SysIFace->readdir(dir);
268 AROS_HOST_BARRIER
269 if (!de)
270 break;
272 if (Stricmp(de->d_name, pathstart) == 0)
274 dirfound = TRUE;
275 strcpy(pathstart, de->d_name);
276 break;
279 iface->closedir(dir);
280 AROS_HOST_BARRIER
283 } /* if (stat((const char *)pathname, &st) != 0) */
285 if (pathend) *pathend = '/';
287 if (!dirfound) break;
289 } /* while((pathpos = strchr(pathpos, '/))) */
292 #else
294 #define fixcase(emulbase, pathname)
296 #endif
298 /*-------------------------------------------------------------------------------------------*/
300 static int inline nocase_lstat(struct emulbase *emulbase, char *file_name, struct stat *st)
302 int ret;
304 fixcase(emulbase, file_name);
305 ret = emulbase->pdata.SysIFace->lstat(file_name, st);
306 AROS_HOST_BARRIER
308 return ret;
311 /*-------------------------------------------------------------------------------------------*/
313 static inline int nocase_unlink(struct emulbase *emulbase, char *pathname)
315 int ret;
317 fixcase(emulbase, pathname);
318 ret = emulbase->pdata.SysIFace->unlink((const char *)pathname);
319 AROS_HOST_BARRIER
321 return ret;
324 /*-------------------------------------------------------------------------------------------*/
326 static inline int nocase_mkdir(struct emulbase *emulbase, char *pathname, mode_t mode)
328 int ret;
330 fixcase(emulbase, pathname);
331 ret = emulbase->pdata.SysIFace->mkdir(pathname, mode);
332 AROS_HOST_BARRIER
334 return ret;
337 /*-------------------------------------------------------------------------------------------*/
339 static inline int nocase_rmdir(struct emulbase *emulbase, char *pathname)
341 int ret;
343 fixcase(emulbase, pathname);
344 ret = emulbase->pdata.SysIFace->rmdir(pathname);
345 AROS_HOST_BARRIER
347 return ret;
350 /*-------------------------------------------------------------------------------------------*/
352 static inline int nocase_link(struct emulbase *emulbase, char *oldpath, char *newpath)
354 int ret;
356 fixcase(emulbase, oldpath);
357 fixcase(emulbase, newpath);
359 ret = emulbase->pdata.SysIFace->link(oldpath, newpath);
360 AROS_HOST_BARRIER
362 return ret;
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)
379 struct stat st;
380 int ret;
382 fixcase(emulbase, oldpath);
383 fixcase(emulbase, newpath);
385 /* AmigaDOS Rename does not allow overwriting */
386 ret = emulbase->pdata.SysIFace->lstat(newpath, &st);
387 AROS_HOST_BARRIER
388 if (ret == 0)
389 return ERROR_OBJECT_EXISTS;
391 ret = emulbase->pdata.SysIFace->rename(oldpath, newpath);
392 AROS_HOST_BARRIER
394 return ret;
397 /*-------------------------------------------------------------------------------------------*/
399 static inline int nocase_chmod(struct emulbase *emulbase, char *path, mode_t mode)
401 int ret;
403 fixcase(emulbase, path);
405 ret = emulbase->pdata.SysIFace->chmod(path, mode);
406 AROS_HOST_BARRIER
408 return ret;
411 /*-------------------------------------------------------------------------------------------*/
413 static inline int nocase_readlink(struct emulbase *emulbase, char *path, char *buffer, SIPTR size)
415 int ret;
417 fixcase(emulbase, path);
419 ret = emulbase->pdata.SysIFace->readlink(path, buffer, size);
420 AROS_HOST_BARRIER
422 return ret;
425 static inline int nocase_utime(struct emulbase *emulbase, char *path, const struct utimbuf *times)
427 int ret;
429 fixcase(emulbase, path);
430 ret = emulbase->pdata.SysIFace->utime(path, times);
431 AROS_HOST_BARRIER
433 return ret;
436 /*-------------------------------------------------------------------------------------------*/
438 LONG DoOpen(struct emulbase *emulbase, struct filehandle *fh, LONG access, LONG mode, LONG protect, BOOL AllowDir)
440 struct stat st;
441 LONG ret = ERROR_OBJECT_WRONG_TYPE;
442 int r;
444 DOPEN(bug("[emul] Opening host name: %s\n", fh->hostname));
446 HostLib_Lock();
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 */
451 if (r == -1)
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)
464 flags = O_RDWR;
466 switch (mode)
468 case MODE_NEWFILE:
469 flags |= O_TRUNC;
470 /* Fallthrough */
472 case MODE_READWRITE:
473 flags |= O_CREAT;
476 r = emulbase->pdata.SysIFace->open(fh->hostname, flags, 0770);
477 AROS_HOST_BARRIER
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);
485 AROS_HOST_BARRIER
487 if (r >= 0)
489 fh->type = FHD_FILE;
490 fh->fd = (void *)(IPTR)r;
491 ret = 0;
493 else
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);
503 #endif
504 AROS_HOST_BARRIER
506 if (fh->fd)
508 fh->type = FHD_DIRECTORY;
509 ret = 0;
511 else
512 ret = err_u2a(emulbase);
515 if (S_ISLNK(st.st_mode))
516 /* Object is a softlink */
517 ret = ERROR_IS_SOFT_LINK;
519 HostLib_Unlock();
521 return ret;
524 void DoClose(struct emulbase *emulbase, struct filehandle *current)
526 HostLib_Lock();
528 switch(current->type)
530 case FHD_FILE:
531 /* Nothing will happen if type has FHD_STDIO set, this is intentional */
532 emulbase->pdata.SysIFace->close((IPTR)current->fd);
533 AROS_HOST_BARRIER
534 break;
536 case FHD_DIRECTORY:
537 emulbase->pdata.SysIFace->closedir(current->fd);
538 AROS_HOST_BARRIER
539 break;
542 HostLib_Unlock();
545 LONG DoRead(struct emulbase *emulbase, struct filehandle *fh, APTR buff, ULONG len, SIPTR *err)
547 SIPTR error;
548 int res;
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);
554 if (error)
556 *err = errno_u2a(error);
557 return -1;
560 HostLib_Lock();
562 DREAD(bug("[emul] FD %ld ready for read\n", fh->fd));
564 if (fh->type & FHD_STDIO)
566 int res2;
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.
575 res = 0;
578 res2 = emulbase->pdata.SysIFace->read((long)fh->fd, buff++, 1);
579 AROS_HOST_BARRIER
581 if (res2 == -1)
582 break;
584 if (res++ == len)
585 break;
587 res2 = emulbase->pdata.SysIFace->poll(&pfd, 1, 0);
588 AROS_HOST_BARRIER
590 } while (res2 > 0);
592 if (res2 == -1)
593 res = -1;
595 else
597 /* It's not stdin. Read as much as we need to. */
598 res = emulbase->pdata.SysIFace->read((long)fh->fd, buff, len);
599 AROS_HOST_BARRIER
602 if (res == -1)
603 error = err_u2a(emulbase);
605 HostLib_Unlock();
607 DREAD(bug("[emul] Result %d, error %ld\n", len, error));
609 *err = error;
610 return res;
613 LONG DoWrite(struct emulbase *emulbase, struct filehandle *fh, CONST_APTR buff, ULONG len, SIPTR *err)
615 SIPTR error = 0;
617 DWRITE(bug("[emul] Writing %u bytes to fd %ld\n", len, fh->fd));
619 HostLib_Lock();
621 len = emulbase->pdata.SysIFace->write((IPTR)fh->fd, buff, len);
622 AROS_HOST_BARRIER
623 if (len == -1)
624 error = err_u2a(emulbase);
626 HostLib_Unlock();
628 *err = error;
629 return len;
632 SIPTR DoSeek(struct emulbase *emulbase, struct filehandle *fh, SIPTR offset, ULONG mode, SIPTR *err)
634 off_t res;
635 LONG oldpos = 0, newpos;
636 struct stat st;
638 DSEEK(bug("[emul] DoSeek(%d, %d, %d)\n", (int)fh->fd, offset, mode));
640 HostLib_Lock();
642 res = oldpos = LSeek((IPTR)fh->fd, 0, SEEK_CUR);
643 AROS_HOST_BARRIER
644 if (res != -1)
645 res = emulbase->pdata.SysIFace->fstat((int)(IPTR)fh->fd, &st);
646 AROS_HOST_BARRIER
648 DSEEK(bug("[emul] Original position: %lu\n", (unsigned long)oldpos));
650 if (res != -1)
652 switch (mode) {
653 case OFFSET_BEGINNING:
654 newpos = offset;
655 mode = SEEK_SET;
656 break;
658 case OFFSET_CURRENT:
659 newpos = offset + res;
660 mode = SEEK_CUR;
661 break;
663 default:
664 newpos = offset + st.st_size;
665 mode = SEEK_END;
668 if (newpos > st.st_size)
669 res = -1;
672 if (res != -1)
674 res = LSeek((IPTR)fh->fd, offset, mode);
675 AROS_HOST_BARRIER
677 DSEEK(bug("[emul] New position: %lu\n", (unsigned long)res));
680 if (res == -1)
681 oldpos = -1;
683 HostLib_Unlock();
685 *err = ERROR_SEEK_ERROR;
686 return oldpos;
689 LONG DoMkDir(struct emulbase *emulbase, struct filehandle *fh, ULONG protect)
691 LONG ret;
693 protect = prot_a2u(protect);
695 HostLib_Lock();
697 ret = nocase_mkdir(emulbase, fh->hostname, protect);
698 if (!ret)
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);
704 #endif
705 AROS_HOST_BARRIER
708 if ((ret == -1) || (fh->fd == NULL))
709 ret = err_u2a(emulbase);
711 HostLib_Unlock();
713 return ret;
716 LONG DoDelete(struct emulbase *emulbase, char *name)
718 LONG ret;
719 struct stat st;
721 HostLib_Lock();
723 ret = nocase_lstat(emulbase, name, &st);
725 if (!ret)
727 if (S_ISDIR(st.st_mode))
729 ret = emulbase->pdata.SysIFace->rmdir(name);
730 AROS_HOST_BARRIER
732 else
734 ret = emulbase->pdata.SysIFace->unlink(name);
735 AROS_HOST_BARRIER
739 if (ret)
740 ret = err_u2a(emulbase);
742 HostLib_Unlock();
744 return ret;
747 LONG DoChMod(struct emulbase *emulbase, char *filename, ULONG prot)
749 LONG ret;
751 HostLib_Lock();
753 ret = nocase_chmod(emulbase, filename, prot_a2u(prot));
754 if (ret)
755 ret = err_u2a(emulbase);
757 HostLib_Unlock();
759 return ret;
762 LONG DoHardLink(struct emulbase *emulbase, char *fn, char *oldfile)
764 LONG error;
766 HostLib_Lock();
768 error = nocase_link(emulbase, oldfile, fn);
769 if (error)
770 error = err_u2a(emulbase);
772 HostLib_Unlock();
774 return error;
777 LONG DoSymLink(struct emulbase *emulbase, char *dest, char *src)
779 LONG error;
781 HostLib_Lock();
783 error = nocase_symlink(emulbase, dest, src);
784 if (error)
785 error = err_u2a(emulbase);
787 HostLib_Unlock();
789 return error;
792 int DoReadLink(struct emulbase *emulbase, char *filename, char *buffer, ULONG size, LONG *err)
794 int res;
796 HostLib_Lock();
798 res = nocase_readlink(emulbase, filename, buffer, size);
799 if (res == -1)
800 *err = err_u2a(emulbase);
801 else if (res == size)
802 /* Buffer was too small */
803 res = -2;
805 HostLib_Unlock();
807 return res;
810 LONG DoRename(struct emulbase *emulbase, char *filename, char *newfilename)
812 LONG error;
814 HostLib_Lock();
816 error = nocase_rename(emulbase, filename, newfilename);
817 if (error)
818 error = err_u2a(emulbase);
820 HostLib_Unlock();
822 return error;
825 LONG DoSetDate(struct emulbase *emulbase, char *name, struct DateStamp *date)
827 struct utimbuf times;
828 LONG res;
830 HostLib_Lock();
832 times.actime = datestamp2timestamp(emulbase, date);
833 times.modtime = times.actime;
835 res = nocase_utime(emulbase, name, &times);
836 if (res < 0)
837 res = err_u2a(emulbase);
839 HostLib_Unlock();
841 return res;
844 SIPTR DoSetSize(struct emulbase *emulbase, struct filehandle *fh, SIPTR offset, ULONG mode, SIPTR *err)
846 SIPTR absolute = 0;
847 SIPTR error = 0;
849 HostLib_Lock();
851 switch (mode) {
852 case OFFSET_BEGINNING:
853 absolute = 0;
854 break;
856 case OFFSET_CURRENT:
857 absolute = LSeek((IPTR)fh->fd, 0, SEEK_CUR);
858 AROS_HOST_BARRIER
860 if (absolute == -1)
861 error = err_u2a(emulbase);
862 else
863 absolute += offset;
864 break;
866 case OFFSET_END:
867 absolute = LSeek((IPTR)fh->fd, 0, SEEK_END);
868 AROS_HOST_BARRIER
870 if (absolute == -1)
871 error = err_u2a(emulbase);
872 else
873 absolute -= offset;
874 break;
876 default:
877 error = ERROR_UNKNOWN;
880 if (!error)
882 error = FTruncate((IPTR)fh->fd, absolute);
883 AROS_HOST_BARRIER
884 if (error)
885 error = err_u2a(emulbase);
888 HostLib_Unlock();
890 *err = error;
891 return absolute;
894 LONG DoStatFS(struct emulbase *emulbase, char *path, struct InfoData *id)
896 struct statfs buf;
897 LONG err;
899 HostLib_Lock();
901 err = emulbase->pdata.SysIFace->statfs(path, &buf);
902 AROS_HOST_BARRIER
903 if (err)
904 err = err_u2a(emulbase);
906 HostLib_Unlock();
908 if (!err)
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;
917 return err;
920 LONG DoRewindDir(struct emulbase *emulbase, struct filehandle *fh)
922 HostLib_Lock();
924 emulbase->pdata.SysIFace->rewinddir(fh->fd);
925 AROS_HOST_BARRIER
927 HostLib_Unlock();
929 /* Directory search position has been reset */
930 fh->ph.dirpos = 0;
932 /* rewinddir() never fails */
933 return 0;
936 static LONG stat_entry(struct emulbase *emulbase, struct filehandle *fh, STRPTR FoundName, struct stat *st)
938 STRPTR filename, name;
939 ULONG plen, flen;
940 LONG err = 0;
942 DEXAM(bug("[emul] stat_entry(): filehandle's path: %s\n", fh->hostname));
943 if (FoundName)
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);
949 if (NULL == name)
950 return ERROR_NO_FREE_STORE;
952 strcpy(name, fh->hostname);
953 filename = name + plen;
954 *filename++ = '/';
955 strcpy(filename, FoundName);
956 } else
957 name = fh->hostname;
959 DEXAM(bug("[emul] Full name: %s\n", name));
961 HostLib_Lock();
963 err = emulbase->pdata.SysIFace->lstat(name, st);
964 AROS_HOST_BARRIER
965 if (err)
966 err = err_u2a(emulbase);
968 HostLib_Unlock();
970 if (FoundName)
972 DEXAM(bug("[emul] Freeing full name\n"));
973 FreeVecPooled(emulbase->mempool, name);
975 return err;
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;
982 struct stat st;
983 LONG err;
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. */
988 if(type>ED_OWNER)
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);
1000 if (err)
1001 return err;
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));
1007 switch(type)
1009 default:
1010 case ED_OWNER:
1011 ead->ed_OwnerUID = st.st_uid;
1012 ead->ed_OwnerGID = st.st_gid;
1013 case ED_COMMENT:
1014 ead->ed_Comment=NULL;
1015 case ED_DATE:
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;
1024 case ED_PROTECTION:
1025 ead->ed_Prot = prot_u2a(st.st_mode);
1026 case ED_SIZE:
1027 ead->ed_Size = st.st_size;
1028 case ED_TYPE:
1029 if (S_ISDIR(st.st_mode)) {
1030 if (EntryName || fh->name[0])
1031 ead->ed_Type = ST_USERDIR;
1032 else
1033 ead->ed_Type = ST_ROOT;
1034 } else if (S_ISLNK(st.st_mode))
1035 ead->ed_Type = ST_SOFTLINK;
1036 else
1037 ead->ed_Type = ST_FILE;
1039 case ED_NAME:
1040 if (EntryName)
1041 last = EntryName;
1042 else if (*fh->name) {
1043 name = fh->name;
1044 last = name;
1045 while(*name) {
1046 if(*name++ == '/')
1047 last = name;
1049 } else
1050 last = fh->volumename;
1052 ead->ed_Name=next;
1053 for(;;)
1055 if(next>=end)
1056 return ERROR_BUFFER_OVERFLOW;
1057 if(!(*next++=*last++))
1058 break;
1060 case 0:
1061 ead->ed_Next=(struct ExAllData *)(((IPTR)next+AROS_PTRALIGN-1)&~(AROS_PTRALIGN-1));
1062 return 0;
1066 /*********************************************************************************************/
1068 LONG DoExamineNext(struct emulbase *emulbase, struct filehandle *fh,
1069 struct FileInfoBlock *FIB)
1071 int i;
1072 struct stat st;
1073 struct dirent *dir;
1074 char *src, *dest;
1075 LONG err;
1077 /* This operation does not make any sense on a file */
1078 if (fh->type != FHD_DIRECTORY)
1079 return ERROR_OBJECT_WRONG_TYPE;
1081 HostLib_Lock();
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);
1091 AROS_HOST_BARRIER
1092 #endif
1094 /* hm, let's read the data now! */
1095 dir = ReadDir(emulbase, fh, &FIB->fib_DiskKey);
1097 HostLib_Unlock();
1099 if (!dir)
1100 return ERROR_NO_MORE_ENTRIES;
1102 err = stat_entry(emulbase, fh, dir->d_name, &st);
1103 if (err)
1105 DEXAM(bug("stat_entry() failed for %s\n", dir->d_name));
1106 return err;
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;
1126 else
1128 FIB->fib_DirEntryType = ST_FILE;
1131 DEXAM(bug("[emul] DirentryType %d\n", FIB->fib_DirEntryType));
1133 /* fast copying of the filename */
1134 src = dir->d_name;
1135 dest = &FIB->fib_FileName[1];
1137 for (i =0; i<MAXFILENAMELENGTH-1;i++)
1139 if(! (*dest++=*src++) )
1141 break;
1144 FIB->fib_FileName[0] = i;
1146 return 0;
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;
1156 struct dirent *dir;
1157 LONG error = 0;
1158 #ifndef HOST_OS_android
1159 SIPTR oldpos;
1160 #endif
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
1170 HostLib_Lock();
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);
1181 AROS_HOST_BARRIER
1183 HostLib_Unlock();
1184 #endif
1186 for(;;)
1188 HostLib_Lock();
1190 #ifndef HOST_OS_android
1191 oldpos = eac->eac_LastKey;
1193 //oldpos = emulbase->pdata.SysIFace->telldir(fh->fd);
1194 //AROS_HOST_BARRIER
1195 #endif
1197 *emulbase->pdata.errnoPtr = 0;
1198 dir = ReadDir(emulbase, fh, &eac->eac_LastKey);
1200 if (!dir)
1201 error = err_u2a(emulbase);
1203 HostLib_Unlock();
1205 if (!dir)
1206 break;
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"));
1212 continue;
1215 error = DoExamineEntry(emulbase, fh, dir->d_name, ead, end-(STRPTR)ead, type);
1216 if(error)
1217 break;
1219 if ((eac->eac_MatchFunc) && !CALLHOOKPKT(eac->eac_MatchFunc, ead, &type))
1220 continue;
1222 eac->eac_Entries++;
1223 last=ead;
1224 ead=ead->ed_Next;
1226 if (last!=NULL)
1227 last->ed_Next=NULL;
1229 if ((error==ERROR_BUFFER_OVERFLOW) && last)
1231 #ifdef HOST_OS_android
1232 eac->eac_LastKey--;
1233 #else
1234 eac->eac_LastKey = oldpos;
1236 //HostLib_Lock();
1237 //emulbase->pdata.SysIFace->seekdir(fh->fd, oldpos);
1238 //AROS_HOST_BARRIER
1239 //HostLib_Unlock();
1240 #endif
1241 /* Examination will continue from the current position */
1242 return 0;
1245 if(!error)
1246 error = ERROR_NO_MORE_ENTRIES;
1247 /* Reading the whole directory has been completed, so reset position */
1248 DoRewindDir(emulbase, fh);
1250 return error;
1253 char *GetHomeDir(struct emulbase *emulbase, char *sp)
1255 char *home = NULL;
1256 char *newunixpath = NULL;
1257 char *sp_end;
1258 #ifndef HOST_OS_android
1259 BOOL do_endpwent = FALSE;
1260 #endif
1262 HostLib_Lock();
1264 /* "~<name>" means home of user <name> */
1265 if ((sp[1] == '\0') || (sp[1] == '/'))
1267 sp_end = sp + 1;
1268 home = emulbase->pdata.SysIFace->getenv("HOME");
1269 AROS_HOST_BARRIER
1271 #ifndef HOST_OS_android
1272 else
1274 struct passwd *pwd;
1275 WORD cmplen;
1277 for(sp_end = sp + 1; sp_end[0] != '\0' && sp_end[0] != '/'; sp_end++);
1278 cmplen = sp_end - sp - 1;
1280 while(1)
1282 pwd = emulbase->pdata.SysIFace->getpwent();
1283 AROS_HOST_BARRIER
1285 if (!pwd)
1286 break;
1288 if(memcmp(pwd->pw_name, sp + 1, cmplen) == 0)
1290 if (pwd->pw_name[cmplen] == '\0')
1292 home = pwd->pw_dir;
1293 break;
1297 do_endpwent = TRUE;
1299 #endif
1301 if (home)
1303 int hlen = strlen(home);
1304 int splen = strlen(sp_end);
1306 newunixpath = AllocVecPooled(emulbase->mempool, hlen + splen + 1);
1307 if (newunixpath)
1309 char *s = newunixpath;
1311 CopyMem(home, s, hlen);
1312 s += hlen;
1313 CopyMem(sp_end, s, splen);
1314 s += splen;
1315 *s = 0;
1319 #ifndef HOST_OS_android
1320 if (do_endpwent)
1322 emulbase->pdata.SysIFace->endpwent();
1323 AROS_HOST_BARRIER
1325 #endif
1327 HostLib_Unlock();
1329 return newunixpath;
1332 ULONG GetCurrentDir(struct emulbase *emulbase, char *path, ULONG len)
1334 char *res;
1336 DMOUNT(bug("[emul] GetCurrentDir(0x%p, %u)\n", path, len));
1338 HostLib_Lock();
1340 res = emulbase->pdata.SysIFace->getcwd(path, len);
1341 AROS_HOST_BARRIER
1343 HostLib_Unlock();
1345 DMOUNT(bug("[emul] getcwd() returned %s\n", res));
1346 return res ? TRUE : FALSE;
1349 BOOL CheckDir(struct emulbase *emulbase, char *path)
1351 int res;
1352 struct stat st;
1354 DMOUNT(bug("[emul] CheckDir(%s)\n", path));
1356 HostLib_Lock();
1358 res = emulbase->pdata.SysIFace->stat(path, &st);
1359 AROS_HOST_BARRIER
1361 HostLib_Unlock();
1363 DMOUNT(bug("[emul] Result: %d, mode: %o\n", res, st.st_mode));
1364 if ((!res) && S_ISDIR(st.st_mode))
1365 return FALSE;
1367 return TRUE;