Adam GoodeImplement fstat643e1012 years agoHistory
399 lines · 9.1 KB · C
RawDownload
/*    Copyright 2015 Wolfgang Thaller.     This file is part of Retro68.     Retro68 is free software: you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation, either version 3 of the License, or    (at your option) any later version.     Retro68 is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.     Under Section 7 of GPL version 3, you are granted additional    permissions described in the GCC Runtime Library Exception, version    3.1, as published by the Free Software Foundation.     You should have received a copy of the GNU General Public License and    a copy of the GCC Runtime Library Exception along with this program;    see the files COPYING and COPYING.RUNTIME respectively.  If not, see    <http://www.gnu.org/licenses/>.*/ #include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <sys/time.h>#include <reent.h>#include <errno.h>#include <fcntl.h>#include <string.h>#include <stdlib.h> #include <MacMemory.h>#include <Processes.h>#include <Files.h>#include <TextUtils.h>#include <Errors.h> void *_sbrk_r(struct _reent *reent, ptrdiff_t increment){    Debugger();    return NewPtrClear(increment);} __attribute__((weak))void _exit(int status){    //if(status != 0)    //    Debugger();    ExitToShell();    for(;;)        ;} ssize_t _consolewrite(int fd, const void *buf, size_t count);ssize_t _consoleread(int fd, void *buf, size_t count); const int kMacRefNumOffset = 10; static int OSErrToErrno(OSErr err) {    switch (err) {    case noErr:        return 0;     case nsvErr:        return ENODEV;     case fnfErr:    case dirNFErr:        return ENOENT;     case bdNamErr:    case paramErr:        return EINVAL;     case ioErr:    default:        return EIO;    }}  ssize_t _write_r(struct _reent *reent, int fd, const void *buf, size_t count){    long cnt = count;    if(fd >= kMacRefNumOffset)    {        FSWrite(fd - kMacRefNumOffset, &cnt, buf);        return cnt;    }    else        return _consolewrite(fd,buf,count);} ssize_t _read_r(struct _reent *reent, int fd, void *buf, size_t count){    long cnt = count;    if(fd >= kMacRefNumOffset)    {        FSRead(fd - kMacRefNumOffset, &cnt, buf);        return cnt;    }    else        return _consoleread(fd,buf,count);} int _open_r(struct _reent *reent, const char* name, int flags, int mode){    Str255 pname;#if TARGET_API_MAC_CARBON    // Carbon has the new, sane version.    c2pstrcpy(pname,name);#else    // It is also available in various glue code libraries and    // in some versions of InterfaceLib, but it's confusing.    // Using the inplace variant, c2pstr, isn't much better than    // doing things by hand:    strncpy(&pname[1],name,255);    pname[0] = strlen(name);#endif    short ref;     SInt8 permission;    switch(flags & O_ACCMODE)    {        case O_RDONLY:            permission = fsRdPerm;            break;        case O_WRONLY:            permission = fsWrPerm;            break;        case O_RDWR:            permission = fsRdWrPerm;            break;    }     if(flags & O_CREAT)    {        HCreate(0,0,pname,'????','TEXT');    }     OSErr err = HOpenDF(0,0,pname,fsRdWrPerm,&ref);    if(err == paramErr)        err = HOpen(0,0,pname,fsRdWrPerm,&ref);     if(err)        return -1;    // TODO: errno     if(flags & O_TRUNC)    {        SetEOF(ref, 0);    }     return ref + kMacRefNumOffset;} int _close_r(struct _reent *reent, int fd){    if(fd >= kMacRefNumOffset) {        short refNum = fd - kMacRefNumOffset;        short vRefNum;        OSErr err = GetVRefNum(refNum, &vRefNum);        FSClose(refNum);        if (err == noErr)            FlushVol(NULL, vRefNum);    }    return 0;} int _fstat_r(struct _reent *reent, int fd, struct stat *buf){    const long long int epochDiffInSeconds = 2082844800LL;     if (buf == NULL) {        reent->_errno = EFAULT;        return -1;    }     memset(buf, 0, sizeof (struct stat));    buf->st_nlink = 1;    buf->st_uid = 42;    buf->st_gid = 42;    buf->st_blksize = 512;     if (fd < kMacRefNumOffset) {        // Console.        unsigned long secs;        GetDateTime(&secs);         buf->st_mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP;        buf->st_mtim.tv_sec = secs - epochDiffInSeconds;        buf->st_ctim.tv_sec = secs - epochDiffInSeconds;        buf->st_atim.tv_sec = secs - epochDiffInSeconds;        return 0;    }     CInfoPBRec p;    memset(&p, 0, sizeof (p));    p.hFileInfo.ioFRefNum = fd - kMacRefNumOffset;    OSErr err = PBGetCatInfoSync(&p);    if (err) {        reent->_errno = OSErrToErrno(err);        return -1;    }     ino_t inode;    mode_t mode;     long long mtim;    long long ctim;     int size = 0;    int phySize = 0;     if (p.hFileInfo.ioFlAttrib & 16) {        inode = p.dirInfo.ioDrDirID;        mode = S_IFDIR | S_IRUSR | S_IRUSR | S_IXUSR;        mtim = p.dirInfo.ioDrMdDat - epochDiffInSeconds;        ctim = p.dirInfo.ioDrCrDat - epochDiffInSeconds;    } else {        inode = p.hFileInfo.ioDirID;        mode = S_IFREG | S_IRUSR | S_IRUSR;        mtim = p.hFileInfo.ioFlMdDat - epochDiffInSeconds;        ctim = p.hFileInfo.ioFlCrDat - epochDiffInSeconds;        size = p.hFileInfo.ioFlLgLen;        phySize = p.hFileInfo.ioFlPyLen + p.hFileInfo.ioFlRPyLen;    }     HParamBlockRec h;    memset(&h, 0, sizeof (h));    h.volumeParam.ioVRefNum = p.hFileInfo.ioVRefNum;    err = PBHGetVInfoSync(&h);    if (err) {        reent->_errno = OSErrToErrno(err);        return -1;    }     buf->st_dev = h.volumeParam.ioVDrvInfo;    buf->st_ino = inode;    buf->st_mode = mode;    buf->st_size = size;    buf->st_mtim.tv_sec = mtim;    buf->st_ctim.tv_sec = ctim;    buf->st_blocks = (phySize / 512) + (phySize % 512 > 0);     return 0;} extern int _stat_r(struct _reent * reent, const char *fn, struct stat *buf){    return -1;} off_t _lseek_r(struct _reent *reent, int fd, off_t offset, int whence){    if(fd >= kMacRefNumOffset)    {        short posMode;        switch(whence)        {            case SEEK_SET:                posMode = fsFromStart;                break;            case SEEK_CUR:                posMode = fsFromMark;                break;            case SEEK_END:                posMode = fsFromLEOF;                break;        }         short ref = fd - kMacRefNumOffset;        SetFPos(ref, posMode, offset);        long finalPos;        GetFPos(ref, &finalPos);        return finalPos;    }    return (off_t) -1;} int _kill_r(struct _reent *reent, pid_t pid, int sig){    if(pid == 42)        _exit(42);    else        return -1;} pid_t _getpid_r(struct _reent *reent){    return 42;} int _fork_r(struct _reent *reent){    return -1;} int _execve_r(struct _reent *reent, const char *fn, char *const * argv, char *const *envp){    return -1;} int _fcntl_r(struct _reent *reent, int fd, int cmd, int arg){    return -1;} int _isatty_r(struct _reent *reent, int fd){    return fd < kMacRefNumOffset;} int _link_r(struct _reent *reent, const char *from, const char *to){    reent->_errno = EPERM;    return -1;} int _mkdir_r(struct _reent *reent, const char *fn, int mode){    return -1;} int _rename_r(struct _reent *reent, const char *from, const char *to){    return -1;} int _unlink_r(struct _reent *reent, const char *fn){    return -1;} _CLOCK_T_ _times_r(struct _reent *reent, struct tms *buf){    reent->_errno = EACCES;    return  -1;} int _wait_r(struct _reent *reent, int *wstatus){    reent->_errno = ECHILD;    return -1;                    /* Always fails */}   int _gettimeofday_r(struct _reent *reent, struct timeval *tp, void *__tz){    /* Classic MacOS's GetDateTime function returns an integer.     * TickCount() has a slightly higher resolution, but is independent of the real-time clock.     */    unsigned long secs;    GetDateTime(&secs);    unsigned long ticks = TickCount();     static unsigned long savedTicks = 0, savedSecs = 0;        if(!savedSecs)    {        savedTicks = ticks;        savedSecs = secs;    }    else    {        unsigned long elapsedTicks = ticks - savedTicks;        unsigned long elapsedSecs = secs - savedSecs;        unsigned long expectedTicks = elapsedSecs * 60 + elapsedSecs * 3 / 20;                if(expectedTicks > elapsedTicks)            savedTicks = ticks;        else            savedTicks += expectedTicks;        savedSecs = secs;    }     if(tp)    {        const int epochDifferenceInYears = 1970 - 1904;        const int epochDifferenceInDays =            365 * epochDifferenceInYears            + (epochDifferenceInYears + 3)/ 4;  // round up for leap years         tp->tv_sec = secs - 86400 * epochDifferenceInDays;        tp->tv_usec = (ticks - savedTicks) * 20000000 / 2003;    }     return 0;} extern int _getentropy_r (struct _reent *, void *, size_t){    errno = ENOSYS;    return -1;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t