/* * Operating system library for POSIX-type systems. * * The define POSIX_FS must be defined. Optionally, BEWORKS_FS * and QNX_FS may modify behavior. * * This module handles interaction with the operating-system specific * intricacies with file manipulation, memory management, process * spawning, etc. * */ #if defined(MAC_FS) || defined(WIN32_FS) #error Wrong module! #endif #undef DEBUG #include "OSLib.h" #include #include #include #include #include #ifdef __WATCOMC__ #include #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(UNDER_UNIX) #include #include #endif #if __linux__ #include #endif #if defined(UNDER_BEWORKS) #include /* file attributes */ #include /* shared library add-ons */ #include /* OS utils, namely, areas */ #define MMAP_BE 1 #endif #if defined(UNDER_QNX) #include /* only shared-memory mmap()ing */ #define MMAP_QNX 1 #endif #if defined(UNDER_UNIX) #include /* shared libraries */ #include /* memory mapping */ #define MMAP_POSIX 1 #endif #define OS_DLERR (-ENOENT) /* generic shared lib error */ static const char *lastdlerr = NULL; /* buffer for message */ #if DEBUG #define ASSERT(x) assert(x) #else #define ASSERT(x) #endif /* get error text for an OSError */ char * OS_GetErrText(OSError err) { if (err == OS_DLERR) { if (lastdlerr == NULL) { /* d'oh, never got error */ return "Shared library function failed"; } else return (char *) lastdlerr; } else return strerror(err); } /*********************/ /* Initialize C program context */ OSError OS_InitProgram(int *argc, char ***argv) { return OS_NOERR; } /* Terminate C program context */ OSError OS_TermProgram(void) { return OS_NOERR; } /*********************/ #if 0 #pragma mark - #endif static char intbuf[OS_PATHSIZE]; #define GETSPECSTR(sp,bf) if (OS_SpecToString(sp, bf, sizeof(bf))==NULL) return OS_FNTLERR #define GETPATHSPECSTR(sp,bf) if (OS_PathSpecToString(sp, bf, sizeof(bf))==NULL) return OS_FNTLERR #if !defined(BEWORKS_FS) OSFileType OS_TEXTTYPE = { 0666 }; #else OSFileType OS_TEXTTYPE = { 0666, "text/plain" }; #endif /* create a new file, overwrite an old one if existing */ OSError OS_Create(const OSSpec * spec, OSFileType * type) { int h; GETSPECSTR(spec, intbuf); h = open(intbuf, O_CREAT | O_TRUNC, type->perm); if (h < 0) return errno; else { close(h); // don't return error if this fails // -- msdos fs can't change permissions and returns error here OS_SetFileType(spec, type); return OS_NOERR; } } /* tell if a file exists */ OSError OS_Status(const OSSpec * spec) { struct stat st; GETSPECSTR(spec, intbuf); return stat(intbuf, &st) ? errno : OS_NOERR; } /* get type of a file */ #if !defined(BEWORKS_FS) OSError OS_GetFileType(const OSSpec * spec, OSFileType * type) { struct stat st; GETSPECSTR(spec, intbuf); if (stat(intbuf, &st) < 0) return errno; else { type->perm = st.st_mode; return OS_NOERR; } } #else OSError OS_GetFileType(const OSSpec * spec, OSFileType * type) { struct stat st; int h; char attr[256]; GETSPECSTR(spec, intbuf); if ((h = open(intbuf, O_RDWR)) < 0) return errno; if (fstat(h, &st) < 0) return errno; if (fs_read_attr(h, "BEOS:TYPE", 'MIMS', 0, type->mime, sizeof(type->mime)) < 0) return errno; close(h); type->perm = st.st_mode; strcpy(type->mime, attr); return OS_NOERR; } #endif /* set type for a file */ #if !defined(BEWORKS_FS) OSError OS_SetFileType(const OSSpec * spec, OSFileType * type) { int oldmask; int err; GETSPECSTR(spec, intbuf); oldmask = umask(0); err = chmod(intbuf, type->perm & (~oldmask)); umask(oldmask); return err < 0 ? errno : OS_NOERR; } #else OSError OS_SetFileType(const OSSpec * spec, OSFileType * type) { int oldmask; int err; int ref; GETSPECSTR(spec, intbuf); /* may be blank */ if (type->mime && *type->mime) { if ((ref = open(intbuf, O_RDWR)) < 0) return errno; fs_remove_attr(ref, "BEOS:TYPE"); if (fs_write_attr(ref, "BEOS:TYPE", 'MIMS', 0, type->mime, strlen(type->mime) + 1) < 0) return errno; close(ref); } oldmask = umask(0); err = chmod(intbuf, type->perm & (~oldmask)) < 0; umask(oldmask); return err ? errno : OS_NOERR; } #endif /* get timestamps of a file */ OSError OS_GetFileTime(const OSSpec * spec, OSTime * crtm, OSTime * chtm) { struct stat st; GETSPECSTR(spec, intbuf); if (stat(intbuf, &st) < 0) return errno; else { if (crtm) *crtm = st.st_ctime; if (chtm) *chtm = st.st_mtime; return OS_NOERR; } } /* set timestamps of a file */ OSError OS_SetFileTime(const OSSpec * spec, OSTime * crtm, OSTime * chtm) { struct utimbuf buf; struct stat st; GETSPECSTR(spec, intbuf); if (stat(intbuf, &st) < 0) return errno; #warning "Can't set creation time" buf.actime = chtm ? *chtm : st.st_atime; buf.modtime = crtm ? *crtm : st.st_mtime; if (utime(intbuf, &buf) < 0) return errno; else return OS_NOERR; } /* modify protection on a file */ OSError OS_ModifyProtection(const OSSpec * spec, bool protect) { struct stat st; GETSPECSTR(spec, intbuf); if (stat(intbuf, &st) < 0) return errno; if (chmod(intbuf, (st.st_mode & ~S_IREAD) | (protect ? 0 : S_IREAD)) < 0) return errno; else return OS_NOERR; } /* get protection on a file */ OSError OS_CheckProtection(const OSSpec *spec, bool *is_protected) { struct stat st; GETSPECSTR(spec, intbuf); if (stat(intbuf, &st) < 0) return errno; *is_protected = (st.st_mode & ~S_IREAD) == 0; return OS_NOERR; } /* get disk space info */ OSError OS_GetDiskStats(const OSPathSpec * spec, OSSize * blocksize, OSSize * total, OSSize * free) { #if __linux__ struct statfs stf; GETPATHSPECSTR(spec, intbuf); if (statfs(intbuf, &stf) < 0) return errno; *blocksize = stf.f_bsize; *total = stf.f_blocks; *free = stf.f_bfree; return OS_NOERR; #else #error #endif } /*************************************/ #if 0 #pragma mark - #endif /* open an existing file */ OSError OS_Open(const OSSpec * spec, OSOpenMode mode, OSRef * ref) { static int modetrans[] = { O_RDONLY, O_WRONLY, O_RDWR, O_APPEND | O_WRONLY }; GETSPECSTR(spec, intbuf); *ref = open(intbuf, modetrans[mode]); if (*ref < 0) { *ref = -1; /* don't let someone blithely close this handle */ return errno; } else return OS_NOERR; } /* write binary data, up to length bytes; length==0 can extend file; update length; error indicates serious failure */ OSError OS_Write(OSRef ref, void *buffer, OSSize * length) { struct stat st; size_t pos; if (fstat(ref, &st) < 0) return errno; pos = lseek(ref, 0, SEEK_CUR); if (pos > st.st_size && *length == 0) { lseek(ref, -1, SEEK_CUR); if (write(ref, "\0", 1) != 1) { *length = 0; return errno; } } *length = write(ref, buffer, *length); if ((signed) *length < 0) { return errno; } else return OS_NOERR; } /* read binary data, up to length bytes; update length; error indicates serious failure. */ OSError OS_Read(OSRef ref, void *buffer, OSSize * length) { *length = read(ref, buffer, *length); if ((signed) *length < 0) return errno; else return OS_NOERR; } /* seek a file; illegal seek is revealed by next write or read; error indicates serious failure. */ OSError OS_Seek(OSRef ref, OSSeekMode how, OSPos offset) { static int howtrans[] = { SEEK_CUR, SEEK_SET, SEEK_END }; return lseek(ref, offset, howtrans[how]) < 0 ? errno : OS_NOERR; } /* tell file position */ OSError OS_Tell(OSRef ref, OSPos * offset) { *offset = lseek(ref, 0L, SEEK_CUR); return (*offset < 0) ? errno : OS_NOERR; } /* close a file */ OSError OS_Close(OSRef ref) { if (ref == -1) return EBADF; else return close(ref) ? errno : OS_NOERR; } /* get length of a file; return error if directory or not found */ OSError OS_GetSize(OSRef ref, OSSize * length) { struct stat st; if (fstat(ref, &st) < 0) return errno; else { *length = st.st_size; return OS_NOERR; } } /* set length of a file; return error if directory or not found */ #if !defined(__WATCOMC__) OSError OS_SetSize(OSRef ref, OSSize length) { return ftruncate(ref, length) ? errno : OS_NOERR; } #else OSError OS_SetSize(OSRef ref, OSSize length) { return chsize(ref, length) ? errno : OS_NOERR; } #endif /**********************************/ /* delete a file */ OSError OS_Delete(const OSSpec * spec) { GETSPECSTR(spec, intbuf); return unlink(intbuf) ? errno : OS_NOERR; } /* rename a file */ OSError OS_Rename(const OSSpec * oldspec, const OSSpec * newspec) { char newbuf[OS_PATHSIZE]; GETSPECSTR(newspec, newbuf); GETSPECSTR(oldspec, intbuf); return rename(intbuf, newbuf) ? errno : OS_NOERR; } /* make directory */ OSError OS_Mkdir(const OSSpec * spec) { GETSPECSTR(spec, intbuf); return mkdir(intbuf, 0777) ? errno : OS_NOERR; } /* remove directory */ OSError OS_Rmdir(const OSPathSpec * spec) { GETPATHSPECSTR(spec, intbuf); return rmdir(intbuf) ? errno : OS_NOERR; } /* change directory */ OSError OS_Chdir(const OSPathSpec * spec) { GETPATHSPECSTR(spec, intbuf); return chdir(intbuf) ? errno : OS_NOERR; } /* get current working directory */ OSError OS_GetCWD(OSPathSpec * spec) { if (getcwd(spec->s, OS_PATHSIZE) == NULL) return errno; else { char *ptr = spec->s + strlen(spec->s); if (*(ptr - 1) != '/') strcpy(ptr, "/"); return OS_NOERR; } } /* spawn a subprocess */ extern char **environ; OSError OS_Execute(const OSSpec * spec, char **argv, char **envp, const char *stdoutfile, const char *stderrfile, int *exitcode) { int svstdout, svstderr; pid_t kidpid; int status; /* Unix magic: file descriptors for stdout/stderr are always 1 and 2, and are always allocated in order starting from the lowest unopened descriptor. This code duplicates the current stdout/stderr (as needed), and immediately opens new files, which become the new stdout/stderr for the child. dup2 duplicates a descriptor into a specific target (probably not necessary, but safer) */ if (stdoutfile) { svstdout = dup(1); close(1); if (open(stdoutfile, O_WRONLY | O_CREAT | O_TRUNC, 0666) < 0) { status = errno; dup2(svstdout, 1); close(svstdout); return status; } } if (stderrfile) { svstderr = dup(2); close(2); if (open(stderrfile, O_WRONLY | O_CREAT | O_TRUNC, 0666) < 0) { status = errno; dup2(svstderr, 2); close(svstderr); return status; } } kidpid = fork(); if (!kidpid) { /* kid running */ if (execve(argv[0], (char *const *) argv, (char *const *) (envp && *envp ? envp : environ)) < 0) exit(-1); /* signal failure */ /* can't get here */ return EINVAL; } else { OSError err; if (stdoutfile) { dup2(svstdout, 1); close(svstdout); } if (stderrfile) { dup2(svstderr, 2); close(svstderr); } *exitcode = 0; err = waitpid(kidpid, &status, 0) <= 0 ? errno : OS_NOERR; if (WIFEXITED(status)) *exitcode = WEXITSTATUS(status); if (WIFSIGNALED(status)) *exitcode = -WTERMSIG(status); return err; } } /*************************************/ #if 0 #pragma mark - #endif /* tell if a filepath is legal for filesystem; call after OS_CanonPath if necessary */ OSError OS_IsLegalPath(const char *path) { const char *scan = path; int pthlen = 0, fnlen = 0; while (*scan) { if (*scan == '/') fnlen = 0; else fnlen++; pthlen++; if (fnlen > OS_MAXNAMELEN || pthlen > OS_MAXPATHLEN) return OS_FNTLERR; scan++; } return OS_NOERR; } /* tell if a filepath represents a full path */ int OS_IsFullPath(const char *path) { return (*path == '/'); } #if !defined(QNX_FS) && !defined(BEWORKS_FS) /* skip a volume in a fullpath */ const char * OS_GetDirPtr(const char *path) { ASSERT(*path == '/'); return path; } #elif defined(QNX_FS) /* skip a volume in a fullpath '/' or '//node/[path/]' */ const char * OS_GetDirPtr(const char *path) { const char *ptr; ASSERT(*path == '/'); if (*(path + 1) == '/' && *(path + 2) != '/') { /* network path? */ ptr = strchr(path + 3, '/'); if (ptr == NULL) ptr = path + strlen(path); /* just "//1" */ } else ptr = path; return ptr; } #elif defined(BEWORKS_FS) /* skip a volume in a fullpath '/[vol]' or '/' */ const char * OS_GetDirPtr(const char *path) { struct stat st, stdotdot; char vn[OS_VOLSIZE]; const char *ptr; ptr = strchr(path + 1, '/'); if (ptr != NULL && (ptr - path < OS_VOLSIZE)) { strncpy(vn, path, ptr - path); vn[ptr - path] = 0; /* Compare devices of root and possible volume */ stat("/", &st); if (stat(vn, &stdotdot) == 0) { if (st.st_dev != stdotdot.st_dev) return ptr; } } return path; } #endif /* compact a full path; if dst is NULL, overwrite src in place */ static int OS_CompactPath(char *src, char *dst) { char buf[OS_PATHSIZE], *bptr; char *to; const char *from, *start; ASSERT(OS_IsFullPath(src)); #if !defined(BEWORKS_FS) start = OS_GetDirPtr(src); #else start = src; /* it's okay to do /boot/../volume */ #endif if (dst == NULL) bptr = buf; else bptr = dst; strncpy(bptr, src, start - src); bptr += (start - src); from = start; to = bptr; while (*from) { const char *brk; brk = from + 1; while (*brk && *brk != '/') brk++; if (brk - from == 1) /* eliminate '//' */ from = brk; /* skip path break */ else { if (brk - from == 2 && from[1] == '.') from = brk; else /* eliminate ".." and previous directory */ if (brk - from == 3 && from[1] == '.' && from[2] == '.') { if (to > bptr) { do to--; while (to >= bptr && *to != '/'); } from = brk; } else /* copy */ while (from < brk) *to++ = *from++; } } if (to == bptr || *(from - 1) == '/') *to++ = '/'; /* ended at directory */ *to = 0; /* end string */ #if 0 // Bad idea. User might want "-I/" and then use "#include "boot/home/..." #if defined(BEWORKS_FS) /* If this refers to "/", make it "/boot/" */ if (*bptr == '/' && *(bptr + 1) == 0) strcpy(bptr, "/boot/"); #endif #endif if (dst == NULL) strcpy(src, buf); return OS_NOERR; } /* compare paths */ int OS_EqualPath(const char *a, const char *b) { return (strcmp(a, b) == 0); } /*************************************/ #if 0 #pragma mark - #endif /* canonicalize a filepath for host; if dst is NULL, overwrite src in place */ OSError OS_CanonPath(char *src, char *dst) { int idx, out; if (strlen(src) > OS_MAXPATHLEN) return OS_FNTLERR; /* We don't change the size of the string, so this is okay */ if (dst == NULL) dst = src; /* Probably the only weird thing we'll see is DOS paths */ idx = out = 0; /* assume C: is /C/ */ if (isalpha(src[0]) && src[1] == ':') { dst[out++] = '/'; dst[out++] = toupper(src[0]); dst[out++] = '/'; idx += 2; } while (src[idx]) { if (src[idx] == '\\') dst[out] = '/'; else dst[out] = src[idx]; idx++; out++; } dst[out] = 0; return OS_NOERR; } /* make OSSpec from a path; tell what kind it is */ OSError OS_MakeSpec(const char *path, OSSpec *spec, bool *isfile) { char tmp[OS_PATHSIZE]; struct stat st; char *ptr; int len; OSError err; *spec->path.s = *spec->name.s = 0; if ((err=OS_CanonPath((char*)path, tmp))!=OS_NOERR) return err; /* Prepend cwd if needed */ if (!OS_IsFullPath(tmp)) { char *end; char orig[OS_PATHSIZE]; strcpy(orig, tmp); if (getcwd(tmp, OS_PATHSIZE)==NULL) return errno; end = tmp + strlen(tmp) - 1; if (*end!='/') { *++end='/'; *++end=0; } if (strlen(orig) + (end - tmp) >= OS_PATHSIZE) return OS_FNTLERR; strcpy(end, orig); } else { if (strlen(tmp) >= OS_PATHSIZE) return OS_FNTLERR; } if ((err=OS_CompactPath(tmp, NULL))!=OS_NOERR) return err; if ((err=OS_IsLegalPath(tmp))!=OS_NOERR) return err; /* Tell if it's a directory reference */ if (stat(tmp, &st)==0) { ptr = tmp + strlen(tmp); if (*(ptr-1)=='/') ptr--; if (S_ISDIR(st.st_mode)) { if (isfile) *isfile = false; *ptr++ = '/'; } else { if (isfile) *isfile = true; } *ptr=0; } else if (errno != ENOENT) return errno; else if (isfile) *isfile = true; ptr = strrchr(tmp, '/')+1; len = ptr-tmp; if (len >= OS_PATHSIZE) { *spec->path.s = 0; return OS_FNTLERR; } memcpy(spec->path.s, tmp, len); spec->path.s[len] = 0; // truncate len = strlen(ptr); if (len >= OS_NAMESIZE) { *spec->name.s = 0; return OS_FNTLERR; } memcpy(spec->name.s, ptr, len); spec->name.s[len] = 0; return OS_NOERR; } /* make OSSpec from a path; must resolve to a file */ OSError OS_MakeFileSpec(const char *path, OSSpec * spec) { bool isfile; OSError err; err = OS_MakeSpec(path, spec, &isfile); if (err != OS_NOERR) return err; if (!isfile) return OS_FIDERR; return OS_NOERR; } /* make OSPathSpec from a volume and dir */ OSError OS_MakePathSpec(const char *vol, const char *dir, OSPathSpec * spec) { bool isfile; OSSpec tmp; OSError err; char path[OS_PATHSIZE]; int len; if ((vol ? strlen(vol) : 0) + (dir ? strlen(dir) : 0) + 2 > sizeof(path)) return OS_FNTLERR; sprintf(path, "%s%s", vol ? vol : "", dir ? dir : ""); err = OS_MakeSpec(path, &tmp, &isfile); len = strlen(tmp.path.s); if (err != OS_NOERR) { /* ensure that path is legal */ if (len+1 < OS_PATHSIZE) memcpy(spec->s+len, "\\", 2); else memcpy(spec->s+OS_PATHSIZE-2, "\\", 2); return err; } else { memcpy(spec->s, tmp.path.s, len + 1); spec->s[OS_PATHSIZE-1] = 0; } if (isfile) return OS_FNIDERR; return OS_NOERR; } /* make OSNameSpec from a filename */ OSError OS_MakeNameSpec(const char *name, OSNameSpec * spec) { if (strchr(name, '/') != NULL) return OS_FIDERR; if (strlen(name) > OS_MAXNAMELEN) return OS_FNTLERR; strcpy(spec->s, name); return OS_NOERR; } /* return FS root spec */ OSError OS_GetRootSpec(OSPathSpec * spec) { strcpy(spec->s, "/"); return OS_NOERR; } /********************************************/ /* For the OS_xxxToString functions, the string buffer and its maximum size are passed. If the output is too big for the buffer, NULL is returned. If the buffer is given as NULL, the buffer is malloc()ed. */ /* make a full pathname from OSSpec */ char * OS_SpecToString(const OSSpec * spec, char *path, int size) { if (size == 0) size = OS_PATHSIZE; if (path == NULL && (path = (char *) malloc(size)) == NULL) return NULL; else { int plen, nlen; 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; } } /* make a path from OSPathSpec */ char * OS_PathSpecToString(const OSPathSpec * pspec, char *path, int size) { if (size == 0) size = OS_PATHSIZE; if (path == NULL && (path = (char *) malloc(size)) == NULL) return NULL; else { int plen; plen = strlen(pspec->s); if (plen >= size) plen = size - 1; memcpy(path, pspec->s, plen); path[plen] = 0; return path; } } /* make a name from OSNameSpec */ char * OS_NameSpecToString(const OSNameSpec * nspec, char *name, int size) { if (size == 0) size = OS_NAMESIZE; if (name == NULL && (name = (char *) malloc(size)) == NULL) return NULL; else { int nlen = strlen(nspec->s); if (nlen >= size) nlen = size - 1; memcpy(name, nspec->s, nlen); name[nlen] = 0; return name; } } /* return the size of an OSPathSpec, for duplication purposes */ int OS_SizeOfPathSpec(const OSPathSpec * spec) { return (strlen(spec->s) + 1); } /* return the size of an OSNameSpec, for duplication purposes */ int OS_SizeOfNameSpec(const OSNameSpec * spec) { return (strlen(spec->s) + 1); } /* compare OSSpecs */ int OS_EqualSpec(const OSSpec * a, const OSSpec * b) { return OS_EqualPathSpec(&a->path, &b->path) && OS_EqualNameSpec(&a->name, &b->name); } /* compare OSPathSpecs */ int OS_EqualPathSpec(const OSPathSpec * a, const OSPathSpec * b) { return (strcmp(a->s, b->s) == 0); } /* compare OSNameSpecs */ int OS_EqualNameSpec(const OSNameSpec * a, const OSNameSpec * b) { return (strcmp(a->s, b->s) == 0); } #if 0 #pragma mark - #endif /* tell if OSSpec is a directory */ int OS_IsDir(const OSSpec * spec) { struct stat st; if (OS_SpecToString(spec, intbuf, sizeof(intbuf)) == NULL) return 0; if (stat(intbuf, &st) < 0) return 0; else return S_ISDIR(st.st_mode); } /* tell if OSSpec is a file */ int OS_IsFile(const OSSpec * spec) { struct stat st; if (OS_SpecToString(spec, intbuf, sizeof(intbuf)) == NULL) return 0; if (stat(intbuf, &st) < 0) return 0; else return !S_ISDIR(st.st_mode); } /* tell if OSSpec is a softlink */ int OS_IsLink(const OSSpec * spec) { struct stat st; char *ptr; if (OS_SpecToString(spec, intbuf, sizeof(intbuf)) == NULL) return 0; ptr = intbuf + strlen(intbuf) - 1; if (*ptr == '/') *ptr = 0; if (lstat(intbuf, &st) < 0) return 0; else return S_ISLNK(st.st_mode); } /* resolve a [soft] link / alias */ OSError OS_ResolveLink(const OSSpec * link, OSSpec * target) { char fn[OS_NAMESIZE]; char path[OS_PATHSIZE]; int len; if (OS_SpecToString(link, intbuf, sizeof(intbuf)) == NULL) return OS_FNTLERR; /* does not null-terminate string */ len = readlink(intbuf, fn, sizeof(fn)); if (len < 0) return errno; else fn[len] = 0; sprintf(path, "%s%s", (*fn != OS_PATHSEP) ? link->path.s : "", fn); return OS_MakeSpec(path, target, NULL); } /*************************************/ #if 0 #pragma mark - #endif /* open a directory for reading */ OSError OS_OpenDir(const OSPathSpec * spec, OSDirRef * ref) { DIR *dptr; GETPATHSPECSTR(spec, intbuf); dptr = opendir(intbuf); if (dptr == NULL) { *ref->path.s = 0; ref->dir = (DIR *) 0L; return errno; } ref->path = *spec; ref->dir = (DIR *) dptr; return OS_NOERR; } /* read an entry from a directory; don't return "." or ".."; return error when end-of-directory reached */ OSError OS_ReadDir(OSDirRef * ref, OSSpec * spec, char *filename, bool * isfile) { struct dirent *de; char fn[OS_PATHSIZE]; OSError err; int len; if (ref->dir == 0L) return OS_FNFERR; do { de = readdir((DIR *) ref->dir); if (de == NULL) return OS_FNFERR; } while (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0 || strlen(ref->path.s) + strlen(de->d_name) >= OS_PATHSIZE); len = strlen(ref->path.s); strncpy(fn, ref->path.s, OS_PATHSIZE - 1); if (len < OS_PATHSIZE) { strncpy(fn + len, de->d_name, OS_PATHSIZE - 1 - len); fn[OS_PATHSIZE - 1] = 0; } else return OS_FNTLERR; strncpy(filename, de->d_name, OS_NAMESIZE - 1); filename[OS_NAMESIZE - 1] = 0; err = OS_MakeSpec(fn, spec, isfile); return err; } /* close directory */ OSError OS_CloseDir(OSDirRef * ref) { if (ref->dir) return closedir((DIR *) ref->dir); else return OS_NOERR; } /*************************************/ #if 0 #pragma mark - #endif /* return time in milliseconds */ unsigned long OS_GetMilliseconds(void) { #if !defined(BUILDHOST_BEWORKS) struct tms tms; return times(&tms) * 1000 / CLOCKS_PER_SEC; #else return system_time() / 1000; #endif } /* return current time */ void OS_GetTime(OSTime * tm) { time(tm); } #if 0 #pragma mark - #endif /* allocate a memory handle */ enum { OSMemDelta = 256 }; OSError OS_NewHandle(OSSize size, OSHandle * hand) { hand->addr = NULL; hand->used = size; /* allow easy growth; never allocate zero bytes */ hand->size = (size + OSMemDelta) & ~(OSMemDelta - 1); hand->addr = (void *) malloc(hand->size); if (hand->addr == NULL) return OS_MEMERR; else return OS_NOERR; } /* resize handle */ OSError OS_ResizeHandle(OSHandle * hand, OSSize size) { /* never allocate zero bytes */ OSSize nsize = (size + OSMemDelta) & ~(OSMemDelta - 1); void *naddr = (void *) realloc(hand->addr, nsize); if (naddr == NULL) return OS_MEMERR; else { hand->addr = naddr; hand->size = nsize; hand->used = size; return OS_NOERR; } } /* lock handle */ void * OS_LockHandle(OSHandle * hand) { return hand->addr; } /* unlock handle */ void OS_UnlockHandle(OSHandle * hand) { } /* free handle */ OSError OS_FreeHandle(OSHandle * hand) { if (hand->addr == NULL) return OS_MEMERR; free(hand->addr); hand->used = hand->size = 0; hand->addr = NULL; return OS_NOERR; } /* get handle size */ OSError OS_GetHandleSize(OSHandle * hand, OSSize * size) { if (hand->addr != NULL) { *size = (OSSize) hand->used; return OS_NOERR; } else { *size = 0; return OS_MEMERR; } } /* invalidate handle */ void OS_InvalidateHandle(OSHandle * hand) { hand->addr = NULL; hand->used = 0; } /* tell whether a handle is valid */ bool OS_ValidHandle(OSHandle * hand) { return hand != NULL && hand->addr != NULL; } /*************************************/ #if 0 #pragma mark - #endif /*************************************/ #if 0 #pragma mark - #endif /* Shared library / DLL routines */ #if defined(SHLIB_DL) /* open a shared library */ OSError OS_OpenLibrary(const OSSpec * spec, OSLibrary * lib) { GETSPECSTR(spec, intbuf); *lib = dlopen(intbuf, RTLD_NOW); lastdlerr = dlerror(); if (*lib == NULL) return OS_DLERR; else return OS_NOERR; } /* find a symbol in the library */ /* dlsym() may return NULL for a symbol defined to be NULL... only dlerror() can tell if an error really happened. */ OSError OS_GetLibrarySymbol(OSLibrary lib, char *name, void **sym) { *sym = dlsym(lib, name); lastdlerr = dlerror(); if (*sym == NULL && lastdlerr != NULL) return OS_DLERR; else return OS_NOERR; } /* close a shared library */ OSError OS_CloseLibrary(OSLibrary lib) { int st; st = dlclose(lib); lastdlerr = dlerror(); if (st < 0) return OS_DLERR; else return OS_NOERR; } /*****************************/ #if 0 #pragma mark - #endif #elif defined(SHLIB_BE) /* open a shared library */ OSError OS_OpenLibrary(const OSSpec * spec, OSLibrary * lib) { GETSPECSTR(spec, intbuf); *lib = load_add_on(intbuf); if (*lib >= 0) { lastdlerr = NULL; return OS_NOERR; } else { lastdlerr = NULL; return OS_FNFERR; } } /* find a symbol in the library */ OSError OS_GetLibrarySymbol(OSLibrary lib, char *name, void **sym) { status_t st; static char dlerrbuf[OS_PATHSIZE + 64]; st = get_image_symbol(lib, name, B_SYMBOL_TYPE_ANY, sym); if (st != B_NO_ERROR) { image_info info; if (get_image_info(lib, &info) == B_NO_ERROR) { sprintf(dlerrbuf, "Symbol '%s' not found in '%s'", name, info.name); lastdlerr = dlerrbuf; } else { sprintf(dlerrbuf, "Symbol '%s' not found in shared library", name); lastdlerr = dlerrbuf; } *sym = NULL; return OS_DLERR; } else { lastdlerr = NULL; return OS_NOERR; } } /* close a shared library */ OSError OS_CloseLibrary(OSLibrary lib) { status_t st; st = unload_add_on(lib); if (st != B_NO_ERROR) { lastdlerr = "Error closing shared library"; return OS_DLERR; } else { lastdlerr = NULL; return OS_NOERR; } } /************************************/ #if 0 #pragma mark - #endif #else /* No support for shared libraries */ /* open a shared library */ OSError OS_OpenLibrary(const OSSpec * spec, OSLibrary * lib) { *lib = NULL; lastdlerr = "No support for shared libraries"; return OS_DLERR; } /* find a symbol in the library */ OSError OS_GetLibrarySymbol(OSLibrary lib, char *name, void **sym) { *sym = NULL; lastdlerr = "No support for shared libraries"; return OS_DLERR; } /* close a shared library */ OSError OS_CloseLibrary(OSLibrary lib) { lastdlerr = "No support for shared libraries"; return OS_DLERR; } #endif