Let ACTION_SET_FILE_SIZE return the new file size instead of DOSTRUE.
[AROS.git] / arch / all-unix / filesys / emul_handler / emul_host.c
blob51ebe5a6d6ee7df2ce3714aacb3dac1ae8a6e991
1 /*
2 Copyright © 1995-2011, 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_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. */
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 #ifdef PassThroughErrnos
85 return err + PassThroughErrnos;
86 #else
87 return ERROR_UNKNOWN;
88 #endif
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)
101 mode_t uprot = 0;
103 /* The following three flags are low-active! */
104 if (!(protect & FIBF_EXECUTE))
105 uprot |= S_IXUSR;
106 if (!(protect & FIBF_WRITE))
107 uprot |= S_IWUSR;
108 if (!(protect & FIBF_READ))
109 uprot |= S_IRUSR;
111 if ((protect & FIBF_GRP_EXECUTE))
112 uprot |= S_IXGRP;
113 if ((protect & FIBF_GRP_WRITE))
114 uprot |= S_IWGRP;
115 if ((protect & FIBF_GRP_READ))
116 uprot |= S_IRGRP;
118 if ((protect & FIBF_OTR_EXECUTE))
119 uprot |= S_IXOTH;
120 if ((protect & FIBF_OTR_WRITE))
121 uprot |= S_IWOTH;
122 if ((protect & FIBF_OTR_READ))
123 uprot |= S_IROTH;
125 if ((protect & FIBF_SCRIPT))
126 uprot |= S_ISVTX;
128 return uprot;
131 /*********************************************************************************************/
133 /* Make AROS protection bits out of unix protection bits. */
134 static ULONG prot_u2a(mode_t protect)
136 ULONG aprot = 0;
138 /* The following three (AROS) flags are low-active! */
139 if (!(protect & S_IRUSR))
140 aprot |= FIBF_READ;
141 if (!(protect & S_IWUSR))
142 aprot |= FIBF_WRITE;
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;
164 return aprot;
167 /*********************************************************************************************/
169 static void timestamp2datestamp(struct emulbase *emulbase, time_t *timestamp, struct DateStamp *datestamp)
171 struct ClockData date;
172 struct tm *tm;
174 HostLib_Lock();
176 tm = emulbase->pdata.SysIFace->localtime(timestamp);
177 AROS_HOST_BARRIER
179 HostLib_Unlock();
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;
193 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;
206 struct tm tm;
207 time_t ret;
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);
219 AROS_HOST_BARRIER
221 return ret;
224 /*********************************************************************************************/
226 #ifdef NO_CASE_SENSITIVITY
228 static void fixcase(struct emulbase *emulbase, char *pathname)
230 struct LibCInterface *iface = emulbase->pdata.SysIFace;
231 struct dirent *de;
232 struct stat st;
233 DIR *dir;
234 char *pathstart, *pathend;
235 BOOL dirfound;
236 int res;
238 pathstart = pathname;
240 res = emulbase->pdata.SysIFace->lstat((const char *)pathname, &st);
241 AROS_HOST_BARRIER
243 if (res == 0)
244 /* Pathname exists, no need to fix anything */
245 return;
247 while((pathstart = strchr(pathstart, '/')))
249 pathstart++;
251 pathend = strchr(pathstart, '/');
252 if (pathend) *pathend = '\0';
254 dirfound = TRUE;
256 res = emulbase->pdata.SysIFace->lstat(pathname, &st);
257 AROS_HOST_BARRIER
258 if (res != 0)
260 dirfound = FALSE;
262 pathstart[-1] = '\0';
263 dir = emulbase->pdata.SysIFace->opendir(pathname);
264 AROS_HOST_BARRIER
265 pathstart[-1] = '/';
267 if (dir)
269 while(1)
271 de = emulbase->pdata.SysIFace->readdir(dir);
272 AROS_HOST_BARRIER
273 if (!de)
274 break;
276 if (Stricmp(de->d_name, pathstart) == 0)
278 dirfound = TRUE;
279 strcpy(pathstart, de->d_name);
280 break;
283 iface->closedir(dir);
284 AROS_HOST_BARRIER
287 } /* if (stat((const char *)pathname, &st) != 0) */
289 if (pathend) *pathend = '/';
291 if (!dirfound) break;
293 } /* while((pathpos = strchr(pathpos, '/))) */
296 #else
298 #define fixcase(emulbase, pathname)
300 #endif
302 /*-------------------------------------------------------------------------------------------*/
304 static int inline nocase_lstat(struct emulbase *emulbase, char *file_name, struct stat *st)
306 int ret;
308 fixcase(emulbase, file_name);
309 ret = emulbase->pdata.SysIFace->lstat(file_name, st);
310 AROS_HOST_BARRIER
312 return ret;
315 /*-------------------------------------------------------------------------------------------*/
317 static inline int nocase_unlink(struct emulbase *emulbase, char *pathname)
319 int ret;
321 fixcase(emulbase, pathname);
322 ret = emulbase->pdata.SysIFace->unlink((const char *)pathname);
323 AROS_HOST_BARRIER
325 return ret;
328 /*-------------------------------------------------------------------------------------------*/
330 static inline int nocase_mkdir(struct emulbase *emulbase, char *pathname, mode_t mode)
332 int ret;
334 fixcase(emulbase, pathname);
335 ret = emulbase->pdata.SysIFace->mkdir(pathname, mode);
336 AROS_HOST_BARRIER
338 return ret;
341 /*-------------------------------------------------------------------------------------------*/
343 static inline int nocase_rmdir(struct emulbase *emulbase, char *pathname)
345 int ret;
347 fixcase(emulbase, pathname);
348 ret = emulbase->pdata.SysIFace->rmdir(pathname);
349 AROS_HOST_BARRIER
351 return ret;
354 /*-------------------------------------------------------------------------------------------*/
356 static inline int nocase_link(struct emulbase *emulbase, char *oldpath, char *newpath)
358 int ret;
360 fixcase(emulbase, oldpath);
361 fixcase(emulbase, newpath);
363 ret = emulbase->pdata.SysIFace->link(oldpath, newpath);
364 AROS_HOST_BARRIER
366 return ret;
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)
383 struct stat st;
384 int ret;
386 fixcase(emulbase, oldpath);
387 fixcase(emulbase, newpath);
389 /* AmigaDOS Rename does not allow overwriting */
390 ret = emulbase->pdata.SysIFace->lstat(newpath, &st);
391 AROS_HOST_BARRIER
392 if (ret == 0)
393 return ERROR_OBJECT_EXISTS;
395 ret = emulbase->pdata.SysIFace->rename(oldpath, newpath);
396 AROS_HOST_BARRIER
398 return ret;
401 /*-------------------------------------------------------------------------------------------*/
403 static inline int nocase_chmod(struct emulbase *emulbase, char *path, mode_t mode)
405 int ret;
407 fixcase(emulbase, path);
409 ret = emulbase->pdata.SysIFace->chmod(path, mode);
410 AROS_HOST_BARRIER
412 return ret;
415 /*-------------------------------------------------------------------------------------------*/
417 static inline int nocase_readlink(struct emulbase *emulbase, char *path, char *buffer, SIPTR size)
419 int ret;
421 fixcase(emulbase, path);
423 ret = emulbase->pdata.SysIFace->readlink(path, buffer, size);
424 AROS_HOST_BARRIER
426 return ret;
429 static inline int nocase_utime(struct emulbase *emulbase, char *path, const struct utimbuf *times)
431 int ret;
433 fixcase(emulbase, path);
434 ret = emulbase->pdata.SysIFace->utime(path, times);
435 AROS_HOST_BARRIER
437 return ret;
440 /*-------------------------------------------------------------------------------------------*/
442 LONG DoOpen(struct emulbase *emulbase, struct filehandle *fh, LONG mode, LONG protect, BOOL AllowDir)
444 struct stat st;
445 LONG ret = ERROR_OBJECT_WRONG_TYPE;
446 int r;
448 DOPEN(bug("[emul] Opening host name: %s\n", fh->hostname));
450 HostLib_Lock();
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 */
455 if (r == -1)
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 */
466 int flags = O_RDWR;
468 switch (mode)
470 case MODE_NEWFILE:
471 flags |= O_TRUNC;
472 /* Fallthrough */
474 case MODE_READWRITE:
475 flags |= O_CREAT;
478 r = emulbase->pdata.SysIFace->open(fh->hostname, flags, 0770);
479 AROS_HOST_BARRIER
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);
487 AROS_HOST_BARRIER
489 if (r >= 0)
491 fh->type = FHD_FILE;
492 fh->fd = (void *)(IPTR)r;
493 ret = 0;
495 else
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);
503 AROS_HOST_BARRIER
505 if (fh->fd)
507 fh->type = FHD_DIRECTORY;
508 ret = 0;
510 else
511 ret = err_u2a(emulbase);
514 if (S_ISLNK(st.st_mode))
515 /* Object is a softlink */
516 ret = ERROR_IS_SOFT_LINK;
518 HostLib_Unlock();
520 return ret;
523 void DoClose(struct emulbase *emulbase, struct filehandle *current)
525 HostLib_Lock();
527 switch(current->type)
529 case FHD_FILE:
530 /* Nothing will happen if type has FHD_STDIO set, this is intentional */
531 emulbase->pdata.SysIFace->close((IPTR)current->fd);
532 AROS_HOST_BARRIER
533 break;
535 case FHD_DIRECTORY:
536 emulbase->pdata.SysIFace->closedir(current->fd);
537 AROS_HOST_BARRIER
538 break;
541 HostLib_Unlock();
544 LONG DoRead(struct emulbase *emulbase, struct filehandle *fh, APTR buff, ULONG len, SIPTR *err)
546 SIPTR error;
547 int res;
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);
553 if (error)
555 *err = errno_u2a(error);
556 return -1;
559 HostLib_Lock();
561 DREAD(bug("[emul] FD %ld ready for read\n", fh->fd));
563 if (fh->type & FHD_STDIO)
565 int res2;
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.
574 res = 0;
577 res2 = emulbase->pdata.SysIFace->read((long)fh->fd, buff++, 1);
578 AROS_HOST_BARRIER
580 if (res2 == -1)
581 break;
583 if (res++ == len)
584 break;
586 res2 = emulbase->pdata.SysIFace->poll(&pfd, 1, 0);
587 AROS_HOST_BARRIER
589 } while (res2 > 0);
591 if (res2 == -1)
592 res = -1;
594 else
596 /* It's not stdin. Read as much as we need to. */
597 res = emulbase->pdata.SysIFace->read((long)fh->fd, buff, len);
598 AROS_HOST_BARRIER
601 if (res == -1)
602 error = err_u2a(emulbase);
604 HostLib_Unlock();
606 DREAD(bug("[emul] Result %d, error %ld\n", len, error));
608 *err = error;
609 return res;
612 LONG DoWrite(struct emulbase *emulbase, struct filehandle *fh, CONST_APTR buff, ULONG len, SIPTR *err)
614 SIPTR error = 0;
616 DWRITE(bug("[emul] Writing %u bytes to fd %ld\n", len, fh->fd));
618 HostLib_Lock();
620 len = emulbase->pdata.SysIFace->write((IPTR)fh->fd, buff, len);
621 AROS_HOST_BARRIER
622 if (len == -1)
623 error = err_u2a(emulbase);
625 HostLib_Unlock();
627 *err = error;
628 return len;
631 SIPTR DoSeek(struct emulbase *emulbase, struct filehandle *fh, SIPTR offset, ULONG mode, SIPTR *err)
633 off_t res;
634 LONG oldpos = 0;
635 SIPTR error = 0;
637 DSEEK(bug("[emul] DoSeek(%d, %d, %d)\n", (int)fh->fd, offset, mode));
639 switch (mode) {
640 case OFFSET_BEGINNING:
641 mode = SEEK_SET;
642 break;
644 case OFFSET_CURRENT:
645 mode = SEEK_CUR;
646 break;
648 default:
649 mode = SEEK_END;
652 HostLib_Lock();
654 res = LSeek((IPTR)fh->fd, 0, SEEK_CUR);
655 AROS_HOST_BARRIER
657 DSEEK(bug("[emul] Original position: %llu\n", (unsigned long long)res));
658 if (res != -1)
660 oldpos = res;
661 res = LSeek((IPTR)fh->fd, offset, mode);
662 AROS_HOST_BARRIER
664 DSEEK(bug("[emul] New position: %llu\n", (unsigned long long)res));
667 if (res == -1)
669 oldpos = -1;
670 error = err_u2a(emulbase);
673 HostLib_Unlock();
675 *err = error;
676 return oldpos;
679 LONG DoMkDir(struct emulbase *emulbase, struct filehandle *fh, ULONG protect)
681 LONG ret;
683 protect = prot_a2u(protect);
685 HostLib_Lock();
687 ret = nocase_mkdir(emulbase, fh->hostname, protect);
688 if (!ret)
690 fh->type = FHD_DIRECTORY;
691 fh->fd = emulbase->pdata.SysIFace->opendir(fh->hostname);
692 AROS_HOST_BARRIER
695 if ((ret == -1) || (fh->fd == NULL))
696 ret = err_u2a(emulbase);
698 HostLib_Unlock();
700 return ret;
703 LONG DoDelete(struct emulbase *emulbase, char *name)
705 LONG ret;
706 struct stat st;
708 HostLib_Lock();
710 ret = nocase_lstat(emulbase, name, &st);
712 if (!ret)
714 if (S_ISDIR(st.st_mode))
716 ret = emulbase->pdata.SysIFace->rmdir(name);
717 AROS_HOST_BARRIER
719 else
721 ret = emulbase->pdata.SysIFace->unlink(name);
722 AROS_HOST_BARRIER
726 if (ret)
727 ret = err_u2a(emulbase);
729 HostLib_Unlock();
731 return ret;
734 LONG DoChMod(struct emulbase *emulbase, char *filename, ULONG prot)
736 LONG ret;
738 HostLib_Lock();
740 ret = nocase_chmod(emulbase, filename, prot_a2u(prot));
741 if (ret)
742 ret = err_u2a(emulbase);
744 HostLib_Unlock();
746 return ret;
749 LONG DoHardLink(struct emulbase *emulbase, char *fn, char *oldfile)
751 LONG error;
753 HostLib_Lock();
755 error = nocase_link(emulbase, oldfile, fn);
756 if (error)
757 error = err_u2a(emulbase);
759 HostLib_Unlock();
761 return error;
764 LONG DoSymLink(struct emulbase *emulbase, char *dest, char *src)
766 LONG error;
768 HostLib_Lock();
770 error = nocase_symlink(emulbase, dest, src);
771 if (error)
772 error = err_u2a(emulbase);
774 HostLib_Unlock();
776 return error;
779 int DoReadLink(struct emulbase *emulbase, char *filename, char *buffer, ULONG size, LONG *err)
781 int res;
783 HostLib_Lock();
785 res = nocase_readlink(emulbase, filename, buffer, size);
786 if (res == -1)
787 *err = err_u2a(emulbase);
788 else if (res == size)
789 /* Buffer was too small */
790 res = -2;
792 HostLib_Unlock();
794 return res;
797 LONG DoRename(struct emulbase *emulbase, char *filename, char *newfilename)
799 LONG error;
801 HostLib_Lock();
803 error = nocase_rename(emulbase, filename, newfilename);
804 if (error)
805 error = err_u2a(emulbase);
807 HostLib_Unlock();
809 return error;
812 LONG DoSetDate(struct emulbase *emulbase, char *name, struct DateStamp *date)
814 struct utimbuf times;
815 LONG res;
817 HostLib_Lock();
819 times.actime = datestamp2timestamp(emulbase, date);
820 times.modtime = times.actime;
822 res = nocase_utime(emulbase, name, &times);
823 if (res < 0)
824 res = err_u2a(emulbase);
826 HostLib_Unlock();
828 return res;
831 SIPTR DoSetSize(struct emulbase *emulbase, struct filehandle *fh, SIPTR offset, ULONG mode, SIPTR *err)
833 SIPTR absolute = 0;
834 SIPTR error = 0;
836 HostLib_Lock();
838 switch (mode) {
839 case OFFSET_BEGINNING:
840 absolute = 0;
841 break;
843 case OFFSET_CURRENT:
844 absolute = LSeek((IPTR)fh->fd, 0, SEEK_CUR);
845 AROS_HOST_BARRIER
847 if (absolute == -1)
848 error = err_u2a(emulbase);
849 else
850 absolute += offset;
851 break;
853 case OFFSET_END:
854 absolute = LSeek((IPTR)fh->fd, 0, SEEK_END);
855 AROS_HOST_BARRIER
857 if (absolute == -1)
858 error = err_u2a(emulbase);
859 else
860 absolute -= offset;
861 break;
863 default:
864 error = ERROR_UNKNOWN;
867 if (!error)
869 error = FTruncate((IPTR)fh->fd, absolute);
870 AROS_HOST_BARRIER
871 if (error)
872 error = err_u2a(emulbase);
875 HostLib_Unlock();
877 *err = error;
878 return absolute;
881 LONG DoStatFS(struct emulbase *emulbase, char *path, struct InfoData *id)
883 struct statfs buf;
884 LONG err;
886 HostLib_Lock();
888 err = emulbase->pdata.SysIFace->statfs(path, &buf);
889 AROS_HOST_BARRIER
890 if (err)
891 err = err_u2a(emulbase);
893 HostLib_Unlock();
895 if (!err)
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;
904 return err;
907 LONG DoRewindDir(struct emulbase *emulbase, struct filehandle *fh)
909 HostLib_Lock();
911 emulbase->pdata.SysIFace->rewinddir(fh->fd);
912 AROS_HOST_BARRIER
914 HostLib_Unlock();
916 /* Directory search position has been reset */
917 fh->ph.dirpos = 0;
919 /* rewinddir() never fails */
920 return 0;
923 static LONG stat_entry(struct emulbase *emulbase, struct filehandle *fh, STRPTR FoundName, struct stat *st)
925 STRPTR filename, name;
926 ULONG plen, flen;
927 LONG err = 0;
929 DEXAM(bug("[emul] stat_entry(): filehandle's path: %s\n", fh->hostname));
930 if (FoundName)
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);
936 if (NULL == name)
937 return ERROR_NO_FREE_STORE;
939 strcpy(name, fh->hostname);
940 filename = name + plen;
941 *filename++ = '/';
942 strcpy(filename, FoundName);
943 } else
944 name = fh->hostname;
946 DEXAM(bug("[emul] Full name: %s\n", name));
948 HostLib_Lock();
950 err = emulbase->pdata.SysIFace->lstat(name, st);
951 AROS_HOST_BARRIER
952 if (err)
953 err = err_u2a(emulbase);
955 HostLib_Unlock();
957 if (FoundName)
959 DEXAM(bug("[emul] Freeing full name\n"));
960 FreeVecPooled(emulbase->mempool, name);
962 return err;
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;
969 struct stat st;
970 LONG err;
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. */
975 if(type>ED_OWNER)
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);
987 if (err)
988 return err;
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));
994 switch(type)
996 default:
997 case ED_OWNER:
998 ead->ed_OwnerUID = st.st_uid;
999 ead->ed_OwnerGID = st.st_gid;
1000 case ED_COMMENT:
1001 ead->ed_Comment=NULL;
1002 case ED_DATE:
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;
1011 case ED_PROTECTION:
1012 ead->ed_Prot = prot_u2a(st.st_mode);
1013 case ED_SIZE:
1014 ead->ed_Size = st.st_size;
1015 case ED_TYPE:
1016 if (S_ISDIR(st.st_mode)) {
1017 if (EntryName || fh->name[0])
1018 ead->ed_Type = ST_USERDIR;
1019 else
1020 ead->ed_Type = ST_ROOT;
1021 } else if (S_ISLNK(st.st_mode))
1022 ead->ed_Type = ST_SOFTLINK;
1023 else
1024 ead->ed_Type = ST_FILE;
1026 case ED_NAME:
1027 if (EntryName)
1028 last = EntryName;
1029 else if (*fh->name) {
1030 name = fh->name;
1031 last = name;
1032 while(*name) {
1033 if(*name++ == '/')
1034 last = name;
1036 } else
1037 last = fh->volumename;
1039 ead->ed_Name=next;
1040 for(;;)
1042 if(next>=end)
1043 return ERROR_BUFFER_OVERFLOW;
1044 if(!(*next++=*last++))
1045 break;
1047 case 0:
1048 ead->ed_Next=(struct ExAllData *)(((IPTR)next+AROS_PTRALIGN-1)&~(AROS_PTRALIGN-1));
1049 return 0;
1053 /*********************************************************************************************/
1055 LONG DoExamineNext(struct emulbase *emulbase, struct filehandle *fh,
1056 struct FileInfoBlock *FIB)
1058 int i;
1059 struct stat st;
1060 struct dirent *dir;
1061 char *src, *dest;
1062 LONG err;
1064 /* This operation does not make any sense on a file */
1065 if (fh->type != FHD_DIRECTORY)
1066 return ERROR_OBJECT_WRONG_TYPE;
1068 HostLib_Lock();
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);
1078 AROS_HOST_BARRIER
1079 #endif
1081 /* hm, let's read the data now! */
1082 dir = ReadDir(emulbase, fh, &FIB->fib_DiskKey);
1084 HostLib_Unlock();
1086 if (!dir)
1087 return ERROR_NO_MORE_ENTRIES;
1089 err = stat_entry(emulbase, fh, dir->d_name, &st);
1090 if (err)
1092 DEXAM(bug("stat_entry() failed for %s\n", dir->d_name));
1093 return err;
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;
1113 else
1115 FIB->fib_DirEntryType = ST_FILE;
1118 DEXAM(bug("[emul] DirentryType %d\n", FIB->fib_DirEntryType));
1120 /* fast copying of the filename */
1121 src = dir->d_name;
1122 dest = &FIB->fib_FileName[1];
1124 for (i =0; i<MAXFILENAMELENGTH-1;i++)
1126 if(! (*dest++=*src++) )
1128 break;
1131 FIB->fib_FileName[0] = i;
1133 return 0;
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;
1143 struct dirent *dir;
1144 LONG error;
1145 #ifndef HOST_OS_android
1146 SIPTR oldpos;
1147 #endif
1149 eac->eac_Entries = 0;
1150 if(fh->type!=FHD_DIRECTORY)
1151 return ERROR_OBJECT_WRONG_TYPE;
1153 DEXAM(bug("[emul] examine_all()\n"));
1155 for(;;)
1157 HostLib_Lock();
1159 #ifndef HOST_OS_android
1160 oldpos = emulbase->pdata.SysIFace->telldir(fh->fd);
1161 AROS_HOST_BARRIER
1162 #endif
1164 *emulbase->pdata.errnoPtr = 0;
1165 dir = ReadDir(emulbase, fh, &eac->eac_LastKey);
1167 if (!dir)
1168 error = err_u2a(emulbase);
1170 HostLib_Unlock();
1172 if (!dir)
1173 break;
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"));
1179 continue;
1182 error = DoExamineEntry(emulbase, fh, dir->d_name, ead, end-(STRPTR)ead, type);
1183 if(error)
1184 break;
1186 if ((eac->eac_MatchFunc) && !CALLHOOKPKT(eac->eac_MatchFunc, ead, &type))
1187 continue;
1189 eac->eac_Entries++;
1190 last=ead;
1191 ead=ead->ed_Next;
1193 if (last!=NULL)
1194 last->ed_Next=NULL;
1196 if ((error==ERROR_BUFFER_OVERFLOW) && last)
1198 #ifdef HOST_OS_android
1199 eac->eac_LastKey--;
1200 #else
1201 HostLib_Lock();
1203 emulbase->pdata.SysIFace->seekdir(fh->fd, oldpos);
1204 AROS_HOST_BARRIER
1206 HostLib_Unlock();
1207 #endif
1208 /* Examination will continue from the current position */
1209 return 0;
1212 if(!error)
1213 error = ERROR_NO_MORE_ENTRIES;
1214 /* Reading the whole directory has been completed, so reset position */
1215 DoRewindDir(emulbase, fh);
1217 return error;
1220 char *GetHomeDir(struct emulbase *emulbase, char *sp)
1222 char *home = NULL;
1223 char *newunixpath = NULL;
1224 char *sp_end;
1225 #ifndef HOST_OS_android
1226 BOOL do_endpwent = FALSE;
1227 #endif
1229 HostLib_Lock();
1231 /* "~<name>" means home of user <name> */
1232 if ((sp[1] == '\0') || (sp[1] == '/'))
1234 sp_end = sp + 1;
1235 home = emulbase->pdata.SysIFace->getenv("HOME");
1236 AROS_HOST_BARRIER
1238 #ifndef HOST_OS_android
1239 else
1241 struct passwd *pwd;
1242 WORD cmplen;
1244 for(sp_end = sp + 1; sp_end[0] != '\0' && sp_end[0] != '/'; sp_end++);
1245 cmplen = sp_end - sp - 1;
1247 while(1)
1249 pwd = emulbase->pdata.SysIFace->getpwent();
1250 AROS_HOST_BARRIER
1252 if (!pwd)
1253 break;
1255 if(memcmp(pwd->pw_name, sp + 1, cmplen) == 0)
1257 if (pwd->pw_name[cmplen] == '\0')
1259 home = pwd->pw_dir;
1260 break;
1264 do_endpwent = TRUE;
1266 #endif
1268 if (home)
1270 int hlen = strlen(home);
1271 int splen = strlen(sp_end);
1273 newunixpath = AllocVecPooled(emulbase->mempool, hlen + splen + 1);
1274 if (newunixpath)
1276 char *s = newunixpath;
1278 CopyMem(home, s, hlen);
1279 s += hlen;
1280 CopyMem(sp_end, s, splen);
1281 s += splen;
1282 *s = 0;
1286 #ifndef HOST_OS_android
1287 if (do_endpwent)
1289 emulbase->pdata.SysIFace->endpwent();
1290 AROS_HOST_BARRIER
1292 #endif
1294 HostLib_Unlock();
1296 return newunixpath;
1299 ULONG GetCurrentDir(struct emulbase *emulbase, char *path, ULONG len)
1301 char *res;
1303 DMOUNT(bug("[emul] GetCurrentDir(0x%p, %u)\n", path, len));
1305 HostLib_Lock();
1307 res = emulbase->pdata.SysIFace->getcwd(path, len);
1308 AROS_HOST_BARRIER
1310 HostLib_Unlock();
1312 DMOUNT(bug("[emul] getcwd() returned %s\n", res));
1313 return res ? TRUE : FALSE;
1316 BOOL CheckDir(struct emulbase *emulbase, char *path)
1318 int res;
1319 struct stat st;
1321 DMOUNT(bug("[emul] CheckDir(%s)\n", path));
1323 HostLib_Lock();
1325 res = emulbase->pdata.SysIFace->stat(path, &st);
1326 AROS_HOST_BARRIER
1328 HostLib_Unlock();
1330 DMOUNT(bug("[emul] Result: %d, mode: %o\n", res, st.st_mode));
1331 if ((!res) && S_ISDIR(st.st_mode))
1332 return FALSE;
1334 return TRUE;