#include "oslib.h" #include #include #include #include #include #include #include #include enum { OSErrNeg2 = -2 }; static char *lastdlerr; static char intbuf[256]; enum { MAX_PATH = 256 }; #define CONVERT_SPEC(spec, pathbuf) \ do { \ int _plen = strlen((spec)->path.s); \ int _nlen = strlen((spec)->name.s); \ if (_plen + _nlen >= sizeof(pathbuf)) return 63; \ memcpy((pathbuf), (spec)->path.s, _plen); \ memcpy((pathbuf) + _plen, (spec)->name.s, _nlen + 1); \ } while (0) #define CONVERT_PATHSPEC(spec, pathbuf) \ do { \ int _plen = strlen((spec)->s); \ if (_plen >= sizeof(pathbuf)) return 63;\ memcpy((pathbuf), (spec)->s, _plen + 1);\ if (_plen > 1) { \ if ((pathbuf)[_plen - 1] == '/') \ (pathbuf)[_plen - 1] = 0; \ } \ } while (0) const char *OS_GetErrText(int err) { if (err == -2) { return !lastdlerr ? "Shared library function failed" : lastdlerr; } else { return strerror(err); } } int OS_InitProgram(int *pArgc, const char ***pArgv) { return 0; } int OS_TermProgram() { return 0; } uOSTypePair OS_TEXTTYPE = {0666}; int OS_Create(const OSSpec *spec, const uOSTypePair *type) { int h; int err; CONVERT_SPEC(spec, intbuf); h = open(intbuf, O_CREAT | O_TRUNC, type->perm); if (h < 0) return errno; close(h); err = OS_SetFileType(spec, type); return ((err == 0) || (err == EPERM)) ? 0 : err; } int OS_Status(const OSSpec *spec) { struct stat st; CONVERT_SPEC(spec, intbuf); if (stat(intbuf, &st)) return errno; else return 0; } int OS_GetFileType(const OSSpec *spec, uOSTypePair *type) { struct stat st; CONVERT_SPEC(spec, intbuf); if (stat(intbuf, &st) < 0) return errno; type->perm = st.st_mode; return 0; } int OS_SetFileType(const OSSpec *spec, const uOSTypePair *type) { int oldmask; int err; CONVERT_SPEC(spec, intbuf); oldmask = umask(0); err = chmod(intbuf, type->perm & ~oldmask); umask(oldmask); if (err < 0) return errno; return 0; } int OS_GetFileTime(const OSSpec *spec, time_t *crtm, time_t *chtm) { struct stat st; CONVERT_SPEC(spec, intbuf); if (stat(intbuf, &st) < 0) return errno; if (crtm) *crtm = st.st_ctimespec.tv_sec; if (chtm) *chtm = st.st_mtimespec.tv_sec; return 0; } int OS_SetFileTime(const OSSpec *spec, const time_t *crtm, const time_t *chtm) { struct utimbuf buf; struct stat st; CONVERT_SPEC(spec, intbuf); if (stat(intbuf, &st) < 0) return errno; buf.actime = chtm ? *chtm : st.st_atimespec.tv_sec; buf.modtime = crtm ? *crtm : st.st_mtimespec.tv_sec; if (utime(intbuf, &buf) < 0) return errno; return 0; } int OS_Open(const OSSpec *spec, OSOpenMode mode, int *ref) { static int modetrans[4] = { O_RDONLY, O_WRONLY, O_RDWR, O_RDONLY | O_APPEND }; CONVERT_SPEC(spec, intbuf); *ref = open(intbuf, modetrans[mode]); if (*ref < 0) { *ref = -1; return errno; } return 0; } int OS_Write(int ref, const void *buffer, UInt32 *length) { struct stat st; UInt32 pos; if (fstat(ref, &st) < 0) return errno; pos = lseek(ref, 0, SEEK_CUR); if (pos > st.st_size && !*length) { lseek(ref, -1, SEEK_CUR); if (write(ref, "", 1) != 1) { *length = 0; return errno; } } *length = write(ref, buffer, *length); if (((SInt32) *length) < 0) return errno; return 0; } int OS_Read(int ref, void *buffer, UInt32 *length) { *length = read(ref, buffer, *length); if (((SInt32) *length) < 0) return errno; return 0; } int OS_Seek(int ref, OSSeekMode how, SInt32 offset) { static int howtrans[3] = { SEEK_CUR, SEEK_SET, SEEK_END }; return (lseek(ref, offset, howtrans[how]) < 0) ? errno : 0; } int OS_Tell(int ref, SInt32 *offset) { *offset = lseek(ref, 0, SEEK_CUR); if (*offset < 0) return errno; else return 0; } int OS_Close(int ref) { if (ref == -1) return EBADF; if (close(ref)) return errno; else return 0; } int OS_GetSize(int ref, UInt32 *length) { struct stat st; if (fstat(ref, &st) < 0) { return errno; } else { *length = st.st_size; return 0; } } int OS_SetSize(int ref, UInt32 size) { if (ftruncate(ref, size)) return errno; else return 0; } int OS_Delete(const OSSpec *spec) { CONVERT_SPEC(spec, intbuf); if (unlink(intbuf)) return errno; else return 0; } int OS_Rename(const OSSpec *oldspec, const OSSpec *newspec) { char newbuf[256]; CONVERT_SPEC(newspec, newbuf); CONVERT_SPEC(oldspec, intbuf); return rename(intbuf, newbuf) ? errno : 0; } int OS_Mkdir(const OSSpec *spec) { CONVERT_SPEC(spec, intbuf); if (mkdir(intbuf, 0777)) return errno; else return 0; } int OS_Rmdir(const OSPathSpec *spec) { CONVERT_PATHSPEC(spec, intbuf); if (rmdir(intbuf)) return errno; else return 0; } int OS_Chdir(const OSPathSpec *spec) { CONVERT_PATHSPEC(spec, intbuf); if (chdir(intbuf)) return errno; else return 0; } int OS_GetCWD(OSPathSpec *spec) { char *ptr; if (!getcwd(spec->s, sizeof(spec->s))) return errno; ptr = &spec->s[strlen(spec->s)]; if (ptr[-1] != '/') strcpy(ptr, "/"); return 0; } extern char **environ; int OS_Execute(OSSpec *spec, char **argv, char **envp, const char *stdoutfile, const char *stderrfile, int *exitcode) { int svstdout; int svstderr; pid_t kidpid; int status; int err; // not in stabs but i think this exists...? if (stdoutfile) { svstdout = dup(1); close(1); if (open(stdoutfile, O_CREAT|O_TRUNC|O_WRONLY, 0666) < 0) { status = errno; dup2(svstdout, 1); close(svstdout); return status; } } if (stderrfile) { svstderr = dup(2); close(2); if (open(stderrfile, O_CREAT|O_TRUNC|O_WRONLY, 0666) < 0) { status = errno; dup2(svstderr, 2); close(svstderr); return status; } } kidpid = fork(); if (!kidpid) { if (execve(argv[0], argv, (envp && envp[0]) ? envp : environ) < 0) exit(-1); return EINVAL; } else { if (stdoutfile) { dup2(svstdout, 1); close(svstdout); } if (stderrfile) { dup2(svstderr, 2); close(svstderr); } *exitcode = 0; err = (waitpid(kidpid, &status, 0) <= 0) ? errno : 0; if (!(status & 0x7F)) *exitcode = status >> 8; if ((status & 0x7F) != 0x7F && (status & 0x7F) != 0) *exitcode = -(status & 0x7F); return err; } } int OS_IsLegalPath(const char *path) { const char *scan = path; int pthlen; int fnlen; pthlen = 0; fnlen = 0; while (*scan) { if (*scan == '/') fnlen = 0; else fnlen++; ++pthlen; if (fnlen > 63 || pthlen > 255) return ENAMETOOLONG; //if ((fnlen = (*scan == '/') ? 0 : (fnlen + 1)) > 63 || ++pthlen > 255) // return ENAMETOOLONG; ++scan; } return 0; } int OS_IsFullPath(const char *path) { return path[0] == '/'; } char *OS_GetDirPtr(char *path) { return path; } static int OS_CompactPath(char *src, char *dst) { char buf[256]; char *bptr; char *to; char *from; char *start; char *brk; start = OS_GetDirPtr(src); if (dst == NULL) bptr = buf; else bptr = dst; strncpy(bptr, src, start - src); bptr = bptr + (start - src); from = start; to = bptr; while (*from) { brk = from + 1; while (*brk && *brk != '/') ++brk; if ((brk - from) == 1) { from = brk; } else if ((brk - from) == 2 && from[1] == '.') { from = brk; } else if ((brk - from) == 3 && from[1] == '.' && from[2] == '.') { if (to > bptr) { do { to--; } while (to >= bptr && *to != '/'); } from = brk; } else { while (from < brk) { *(to++) = *(from++); } } } if (to == bptr || from[-1] == '/') *(to++) = '/'; *to = 0; if (!dst) strcpy(src, buf); return 0; } int OS_EqualPath(const char *a, const char *b) { return !strcmp(a, b); } int OS_CanonPath(char *src, char *dst) { int idx; if (strlen(src) > 255) return ENAMETOOLONG; if (!dst) dst = src; for (idx = 0; src[idx]; idx++) { if (src[idx] == '\\') dst[idx] = '/'; else dst[idx] = src[idx]; } dst[idx] = 0; return 0; } int OS_MakeSpec(const char *path, OSSpec *spec, Boolean *isfile) { char tmp[256]; struct stat st; char *ptr; int len; int err; char *end; char orig[256]; spec->name.s[0] = 0; spec->path.s[0] = 0; err = OS_CanonPath((char *) path, tmp); if (err) return err; if (!OS_IsFullPath(tmp)) { strcpy(orig, tmp); if (!getcwd(tmp, sizeof(tmp))) return errno; ptr = tmp + strlen(tmp) - 1; if (ptr[0] != '/') { ptr[1] = '/'; ptr[2] = 0; ptr += 2; } if (((ptr - tmp) + strlen(orig)) >= 256) return ENAMETOOLONG; strcpy(ptr, orig); } else { if (strlen(tmp) >= 256) return ENAMETOOLONG; } err = OS_CompactPath(tmp, 0); if (err) return err; err = OS_IsLegalPath(tmp); if (err) return err; if (!stat(tmp, &st)) { ptr = tmp + strlen(tmp); if (ptr[-1] == '/') ptr--; if ((st.st_mode & S_IFMT) == S_IFDIR) { if (isfile) *isfile = 0; ptr[0] = '/'; ptr++; } else { if (isfile) *isfile = 1; } *ptr = 0; } else { if (errno != ENOENT) return errno; if (isfile) *isfile = 1; } ptr = strrchr(tmp, '/') + 1; len = ptr - tmp; if (len >= 256) { spec->path.s[0] = 0; return ENAMETOOLONG; } memcpy(spec->path.s, tmp, len); spec->path.s[len] = 0; len = strlen(ptr); if (len >= 64) { spec->name.s[0] = 0; return ENAMETOOLONG; } memcpy(spec->name.s, ptr, len); spec->name.s[len] = 0; return 0; } int OS_MakeFileSpec(const char *path, OSSpec *spec) { Boolean isfile; int err; err = OS_MakeSpec(path, spec, &isfile); if (err) return err; else return (isfile != 0) ? 0 : EISDIR; } int OS_MakePathSpec(const char *vol, const char *dir, OSPathSpec *spec) { Boolean isfile; OSSpec tmp; int err; char path[256]; if (((vol ? strlen(vol) : 0) + (dir ? strlen(dir) : 0) + 2) > 256) return ENAMETOOLONG; sprintf(path, "%s%s%s", vol ? (strchr("/\\:", vol[0]) ? "" : "/") : "", vol ? vol : "", dir ? dir : "" ); err = OS_MakeSpec(path, &tmp, &isfile); strcpy(spec->s, tmp.path.s); if (err) return err; if (isfile) return !OS_Status(&tmp) ? ENOTDIR : ENOENT; return 0; } int OS_MakeNameSpec(const char *name, OSNameSpec *spec) { int len; len = strlen(name); spec->s[0] = 0; if (len > 63) return ENAMETOOLONG; if (strchr(name, '/')) return EISDIR; if (strlen(name) > 63) return ENAMETOOLONG; memcpy(spec->s, name, len + 1); return 0; } int OS_GetRootSpec(OSPathSpec *spec) { strcpy(spec->s, "/"); return 0; } char *OS_SpecToString(const OSSpec *spec, char *path, int size) { int plen; int nlen; if (!size) size = 256; if (!path) { path = malloc(size); if (!path) return 0; } plen = strlen(spec->path.s); nlen = strlen(spec->name.s); if ((plen + nlen) >= size) { if (plen >= size) { nlen = 0; plen = size - 1; } else { nlen = (size - plen) - 1; } } memcpy(path, spec->path.s, plen); memcpy(&path[plen], spec->name.s, nlen); path[plen + nlen] = 0; return path; } char *OS_PathSpecToString(const OSPathSpec *pspec, char *path, int size) { int plen; if (!size) size = 256; if (!path) { path = malloc(size); if (!path) return 0; } plen = strlen(pspec->s); if (plen >= size) plen = size - 1; memcpy(path, pspec->s, plen); path[plen] = 0; return path; } char *OS_NameSpecToString(const OSNameSpec *nspec, char *name, int size) { int nlen; if (!size) size = 64; if (!name) { name = malloc(size); if (!name) return 0; } nlen = strlen(nspec->s); if (nlen >= size) nlen = size - 1; memcpy(name, nspec->s, nlen); name[nlen] = 0; return name; } int OS_SizeOfPathSpec(const OSPathSpec *spec) { return strlen(spec->s) + 1; } int OS_SizeOfNameSpec(const OSNameSpec *spec) { return strlen(spec->s) + 1; } int OS_EqualSpec(const OSSpec *a, const OSSpec *b) { return OS_EqualPathSpec(&a->path, &b->path) && OS_EqualNameSpec(&a->name, &b->name); } int OS_EqualPathSpec(const OSPathSpec *a, const OSPathSpec *b) { return !strcmp(a->s, b->s); } int OS_EqualNameSpec(const OSNameSpec *a, const OSNameSpec *b) { return !strcmp(a->s, b->s); } int OS_IsDir(const OSSpec *spec) { struct stat st; if (!OS_SpecToString(spec, intbuf, sizeof(intbuf))) return 0; if (stat(intbuf, &st) < 0) return 0; return ((st.st_mode & S_IFMT) == S_IFDIR); } int OS_IsFile(const OSSpec *spec) { struct stat st; if (!OS_SpecToString(spec, intbuf, sizeof(intbuf))) return 0; if (stat(intbuf, &st) < 0) return 0; return ((st.st_mode & S_IFMT) != S_IFDIR); } int OS_IsLink(const OSSpec *spec) { struct stat st; char *ptr; if (!OS_SpecToString(spec, intbuf, sizeof(intbuf))) return 0; ptr = intbuf + strlen(intbuf) - 1; if (*ptr == '/') *ptr = 0; if (lstat(intbuf, &st) < 0) return 0; return ((st.st_mode & S_IFMT) == S_IFLNK); } int OS_ResolveLink(const OSSpec *link, OSSpec *target) { char fn[64]; char path[256]; int len; if (!OS_SpecToString(link, intbuf, sizeof(intbuf))) return ENAMETOOLONG; len = readlink(intbuf, fn, sizeof(fn)); if (len < 0) return errno; fn[len] = 0; sprintf(path, "%s%s", (fn[0] != '/') ? link->path.s : "", fn); return OS_MakeSpec(path, target, 0); } int OS_OpenDir(const OSPathSpec *spec, OSOpenedDir *ref) { DIR *dptr; CONVERT_PATHSPEC(spec, intbuf); dptr = opendir(intbuf); if (!dptr) { ref->dir = 0; return errno; } ref->spec = *spec; ref->dir = dptr; return 0; } int OS_ReadDir(OSOpenedDir *ref, OSSpec *spec, char *filename, Boolean *isfile) { struct dirent *de; char fn[256]; int err; int len; do { de = readdir(ref->dir); if (!de) return ENOENT; } while (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") || (strlen(ref->spec.s) + strlen(de->d_name) >= 256)); len = strlen(ref->spec.s); strncpy(fn, ref->spec.s, 255); if (len < 256) { strncpy(&fn[len], de->d_name, 255 - len); fn[255] = 0; } else { return ENAMETOOLONG; } strncpy(filename, de->d_name, 63); filename[63] = 0; return OS_MakeSpec(fn, spec, isfile); } int OS_CloseDir(OSOpenedDir *ref) { if (ref->dir) return closedir(ref->dir); else return 0; } UInt32 OS_GetMilliseconds() { struct tms tms; return times(&tms) * 1000 / CLOCKS_PER_SEC; } void OS_GetTime(time_t *p) { time(p); } int OS_NewHandle(UInt32 size, OSHandle *hand) { hand->addr = 0; hand->used = size; hand->size = (size + 256) & ~255; hand->addr = malloc(hand->size); return !hand->addr ? ENOMEM : 0; } int OS_ResizeHandle(OSHandle *hand, UInt32 size) { UInt32 nsize; void *naddr; nsize = (size + 256) & ~255; naddr = realloc(hand->addr, nsize); if (!naddr) return ENOMEM; hand->addr = naddr; hand->size = nsize; hand->used = size; return 0; } void *OS_LockHandle(OSHandle *hand) { return hand->addr; } void OS_UnlockHandle(OSHandle *hand) { } int OS_FreeHandle(OSHandle *hand) { if (!hand->addr) return ENOMEM; free(hand->addr); hand->size = 0; hand->used = 0; hand->addr = 0; return 0; } int OS_GetHandleSize(OSHandle *hand, UInt32 *size) { if (hand->addr) { *size = hand->used; return 0; } else { *size = 0; return ENOMEM; } } void OS_InvalidateHandle(OSHandle *hand) { hand->addr = 0; hand->used = 0; } Boolean OS_ValidHandle(OSHandle *hand) { return (hand && hand->addr); } OSErr OS_MacError(int err) { switch (err) { case 0: return noErr; case ENOENT /*2*/: return fnfErr; case EFAULT /*14*/: case EINVAL /*22*/: return paramErr; case ENOTDIR /*20*/: return dirNFErr; case EISDIR /*21*/: return notAFileErr; case ENAMETOOLONG /*63*/: return bdNamErr; case EBUSY /*16*/: return memLockedErr; case E2BIG /*7*/: case ENOMEM /*12*/: return memFullErr; case EACCES /*13*/: return permErr; case EIO /*5*/: return ioErr; case EEXIST /*17*/: return dupFNErr; case EMFILE /*24*/: return tmfoErr; case EFBIG /*27*/: return fsDataTooBigErr; case EBADF /*9*/: return rfNumErr; case EINTR /*4*/: return abortErr; default: return (OSErr) (0xFFFF8000 | err); } } void OS_TimeToMac(time_t sectm, UInt32 *secs) { struct tm *tmrec; int years; int ydays; tmrec = localtime(§m); years = tmrec->tm_year - 4; ydays = (years * 365) + ((years + 3) / 4) - ((years + 4) / 100) + ((years - 296) / 400); *secs = ((ydays + tmrec->tm_yday) * 86400) + (tmrec->tm_hour * 3600) + (tmrec->tm_min * 60) + (tmrec->tm_sec) + (tmrec->tm_isdst ? -3600 : 0); } void OS_MacToTime(UInt32 secs, time_t *sectm) { static int monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; struct tm tmrec; int month; memset(&tmrec, 0, sizeof(tmrec)); tmrec.tm_sec = secs % 60; // line 1523 tmrec.tm_min = (secs / 60) % 60; // line 1524 tmrec.tm_hour = (secs / 3600) % 24; // line 1525 tmrec.tm_yday = (secs / 86400) % 365; tmrec.tm_year = (secs / 31536000) + 4; // line 1533 tmrec.tm_yday -= ((((secs / 31536000) + 3) / 4) - (((secs / 31536000) + 4) / 100) + ((SInt32)((secs / 31536000) - 296) / 400)) ; if ((tmrec.tm_year % 4) && ((tmrec.tm_year % 100) || !(tmrec.tm_year % 400))) { monthdays[1] = 28; } else { monthdays[1] = 29; } if (tmrec.tm_yday >= (monthdays[1] + 62) && tmrec.tm_yday < (monthdays[1] + 245)) { tmrec.tm_hour++; if (tmrec.tm_hour >= 24) { tmrec.tm_yday++; tmrec.tm_hour -= 24; } } for (month = 0; tmrec.tm_yday >= monthdays[month]; month++) { tmrec.tm_yday -= monthdays[month]; } tmrec.tm_mon = month; tmrec.tm_mday = tmrec.tm_yday + 1; *sectm = mktime(&tmrec); } SInt16 OS_RefToMac(int ref) { return (ref < -1) ? (SInt16) 0 : (SInt16) (ref + 1); } int OS_MacToRef(SInt16 refnum) { return (refnum >= 0) ? (refnum - 1) : -1; } int OS_OpenLibrary(const char *a, void **lib) { *lib = 0; lastdlerr = "No support for shared libraries"; return OSErrNeg2; } int OS_GetLibrarySymbol(void *a, void *b, void **sym) { *sym = 0; lastdlerr = "No support for shared libraries"; return OSErrNeg2; } int OS_CloseLibrary(void *a) { lastdlerr = "No support for shared libraries"; return OSErrNeg2; } int OS_LoadMacResourceFork(const OSSpec *spec, void **file_data, SInt32 *file_len) { return ENOENT; } int OS_IsMultiByte(const char *str, int offset) { return 0; }