MWCC/command_line/CmdLine/Src/OSLib/Posix.c

962 lines
21 KiB
C

#include "oslib.h"
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <time.h>
#include <utime.h>
#include <fcntl.h>
#include <unistd.h>
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] == OS_PATHSEP) \
(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, char ***pArgv) {
return 0;
}
int OS_TermProgram(void) {
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] != OS_PATHSEP)
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 == OS_PATHSEP)
fnlen = 0;
else
fnlen++;
++pthlen;
if (fnlen > 63 || pthlen > 255)
return ENAMETOOLONG;
++scan;
}
return 0;
}
int OS_IsFullPath(const char *path) {
return path[0] == OS_PATHSEP;
}
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 != OS_PATHSEP)
++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 != OS_PATHSEP);
}
from = brk;
} else {
while (from < brk) {
*(to++) = *(from++);
}
}
}
if (to == bptr || from[-1] == OS_PATHSEP)
*(to++) = OS_PATHSEP;
*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(const char *src, char *dst) {
int idx;
if (strlen(src) > 255)
return ENAMETOOLONG;
if (!dst)
dst = (char *) src;
for (idx = 0; src[idx]; idx++) {
if (src[idx] == '\\')
dst[idx] = OS_PATHSEP;
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] != OS_PATHSEP) {
ptr[1] = OS_PATHSEP;
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] == OS_PATHSEP)
ptr--;
if ((st.st_mode & S_IFMT) == S_IFDIR) {
if (isfile)
*isfile = 0;
ptr[0] = OS_PATHSEP;
ptr++;
} else {
if (isfile)
*isfile = 1;
}
*ptr = 0;
} else {
if (errno != ENOENT)
return errno;
if (isfile)
*isfile = 1;
}
ptr = strrchr(tmp, OS_PATHSEP) + 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, OS_PATHSEP))
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 == OS_PATHSEP)
*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] != OS_PATHSEP) ? 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(void) {
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(&sectm);
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;
}
Boolean OS_IsMultiByte(const char *str1, const char *str2) {
return 0;
}