home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / OSLib / Posix.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  27.8 KB  |  1,579 lines

  1.  
  2. /*
  3.  *    Operating system library for POSIX-type systems.
  4.  *
  5.  *    The define POSIX_FS must be defined.  Optionally, BEWORKS_FS
  6.  *    and QNX_FS may modify behavior.
  7.  *
  8.  *    This module handles interaction with the operating-system specific
  9.  *    intricacies with file manipulation, memory management, process
  10.  *    spawning, etc.
  11.  *
  12.  */
  13.  
  14. #if defined(MAC_FS) || defined(WIN32_FS)
  15. #error Wrong module!
  16. #endif
  17.  
  18. #undef DEBUG
  19.  
  20. #include "OSLib.h"
  21.  
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <sys/stat.h>
  25. #include <stdio.h>
  26. #include <unistd.h>
  27. #ifdef __WATCOMC__
  28. #include <process.h>
  29. #endif
  30. #include <signal.h>
  31. #include <string.h>
  32. #include <ctype.h>
  33. #include <fcntl.h>
  34.  
  35. #include <fcntl.h>
  36. #include <sys/wait.h>
  37. #include <sys/types.h>
  38. #include <dirent.h>
  39. #include <utime.h>
  40.  
  41. #include <stdlib.h>
  42. #include <assert.h>
  43.  
  44. #if defined(UNDER_UNIX)
  45. #include <sys/time.h>
  46. #include <sys/times.h>
  47. #endif
  48.  
  49. #if __linux__
  50. #include <sys/vfs.h>
  51. #endif
  52.  
  53. #if defined(UNDER_BEWORKS)
  54. #include <kernel/fs_attr.h>        /* file attributes */
  55. #include <kernel/image.h>        /* shared library add-ons */
  56. #include <kernel/OS.h>            /* OS utils, namely, areas */
  57. #define MMAP_BE        1
  58. #endif
  59.  
  60. #if defined(UNDER_QNX)
  61. #include <sys/mman.h>            /* only shared-memory mmap()ing */
  62. #define MMAP_QNX    1
  63. #endif
  64.  
  65. #if defined(UNDER_UNIX)
  66. #include <dlfcn.h>                /* shared libraries */
  67. #include <sys/mman.h>            /* memory mapping */
  68. #define MMAP_POSIX    1
  69. #endif
  70.  
  71. #define OS_DLERR    (-ENOENT)    /* generic shared lib error */
  72. static const char *lastdlerr = NULL;    /* buffer for message */
  73.  
  74. #if DEBUG
  75. #define ASSERT(x) assert(x)
  76. #else
  77. #define ASSERT(x)
  78. #endif
  79.  
  80. /*    get error text for an OSError */
  81. char
  82.            *
  83. OS_GetErrText(OSError err)
  84. {
  85.     if (err == OS_DLERR) {
  86.         if (lastdlerr == NULL) {    /* d'oh, never got error */
  87.             return "Shared library function failed";
  88.         } else
  89.             return (char *) lastdlerr;
  90.     } else
  91.         return strerror(err);
  92. }
  93.  
  94. /*********************/
  95.  
  96. /*    Initialize C program context  */
  97. OSError
  98. OS_InitProgram(int *argc, char ***argv)
  99. {
  100.     return OS_NOERR;
  101. }
  102.  
  103. /*    Terminate C program context  */
  104. OSError
  105. OS_TermProgram(void)
  106. {
  107.     return OS_NOERR;
  108. }
  109.  
  110. /*********************/
  111. #if 0
  112. #pragma mark -
  113. #endif
  114.  
  115.  
  116. static char intbuf[OS_PATHSIZE];
  117.  
  118. #define GETSPECSTR(sp,bf) if (OS_SpecToString(sp, bf, sizeof(bf))==NULL) return OS_FNTLERR
  119. #define GETPATHSPECSTR(sp,bf) if (OS_PathSpecToString(sp, bf, sizeof(bf))==NULL) return OS_FNTLERR
  120.  
  121. #if !defined(BEWORKS_FS)
  122. OSFileType  OS_TEXTTYPE = { 0666 };
  123. #else
  124. OSFileType  OS_TEXTTYPE = { 0666, "text/plain" };
  125. #endif
  126.  
  127. /*    create a new file, overwrite an old one if existing */
  128. OSError
  129. OS_Create(const OSSpec * spec, OSFileType * type)
  130. {
  131.     int         h;
  132.  
  133.     GETSPECSTR(spec, intbuf);
  134.     h = open(intbuf, O_CREAT | O_TRUNC, type->perm);
  135.     if (h < 0)
  136.         return errno;
  137.     else {
  138.         close(h);
  139.         // don't return error if this fails
  140.         // -- msdos fs can't change permissions and returns error here
  141.         OS_SetFileType(spec, type);
  142.         return OS_NOERR;
  143.     }
  144. }
  145.  
  146.  
  147. /*    tell if a file exists */
  148. OSError
  149. OS_Status(const OSSpec * spec)
  150. {
  151.     struct stat st;
  152.  
  153.     GETSPECSTR(spec, intbuf);
  154.     return stat(intbuf, &st) ? errno : OS_NOERR;
  155. }
  156.  
  157. /*  get type of a file */
  158.  
  159. #if !defined(BEWORKS_FS)
  160.  
  161. OSError
  162. OS_GetFileType(const OSSpec * spec, OSFileType * type)
  163. {
  164.     struct stat st;
  165.  
  166.     GETSPECSTR(spec, intbuf);
  167.     if (stat(intbuf, &st) < 0)
  168.         return errno;
  169.     else {
  170.         type->perm = st.st_mode;
  171.         return OS_NOERR;
  172.     }
  173. }
  174.  
  175. #else
  176.  
  177. OSError
  178. OS_GetFileType(const OSSpec * spec, OSFileType * type)
  179. {
  180.     struct stat st;
  181.     int         h;
  182.     char        attr[256];
  183.  
  184.     GETSPECSTR(spec, intbuf);
  185.     if ((h = open(intbuf, O_RDWR)) < 0)
  186.         return errno;
  187.  
  188.     if (fstat(h, &st) < 0)
  189.         return errno;
  190.  
  191.     if (fs_read_attr(h, "BEOS:TYPE", 'MIMS', 0,
  192.                      type->mime, sizeof(type->mime)) < 0)
  193.         return errno;
  194.  
  195.     close(h);
  196.  
  197.     type->perm = st.st_mode;
  198.     strcpy(type->mime, attr);
  199.     return OS_NOERR;
  200. }
  201.  
  202. #endif
  203.  
  204. /*  set type for a file */
  205.  
  206. #if !defined(BEWORKS_FS)
  207.  
  208. OSError
  209. OS_SetFileType(const OSSpec * spec, OSFileType * type)
  210. {
  211.     int         oldmask;
  212.     int         err;
  213.  
  214.     GETSPECSTR(spec, intbuf);
  215.     oldmask = umask(0);
  216.     err = chmod(intbuf, type->perm & (~oldmask));
  217.     umask(oldmask);
  218.  
  219.     return err < 0 ? errno : OS_NOERR;
  220. }
  221.  
  222. #else
  223.  
  224. OSError
  225. OS_SetFileType(const OSSpec * spec, OSFileType * type)
  226. {
  227.     int         oldmask;
  228.     int         err;
  229.     int         ref;
  230.  
  231.     GETSPECSTR(spec, intbuf);
  232.  
  233.     /*  may be blank  */
  234.     if (type->mime && *type->mime) {
  235.         if ((ref = open(intbuf, O_RDWR)) < 0)
  236.             return errno;
  237.  
  238.         fs_remove_attr(ref, "BEOS:TYPE");
  239.         if (fs_write_attr(ref, "BEOS:TYPE", 'MIMS', 0,
  240.                           type->mime, strlen(type->mime) + 1) < 0)
  241.             return errno;
  242.  
  243.         close(ref);
  244.     }
  245.  
  246.     oldmask = umask(0);
  247.     err = chmod(intbuf, type->perm & (~oldmask)) < 0;
  248.     umask(oldmask);
  249.  
  250.     return err ? errno : OS_NOERR;
  251. }
  252.  
  253. #endif
  254.  
  255. /*  get timestamps of a file */
  256. OSError
  257. OS_GetFileTime(const OSSpec * spec, OSTime * crtm, OSTime * chtm)
  258. {
  259.     struct stat st;
  260.  
  261.     GETSPECSTR(spec, intbuf);
  262.     if (stat(intbuf, &st) < 0)
  263.         return errno;
  264.     else {
  265.         if (crtm)
  266.             *crtm = st.st_ctime;
  267.         if (chtm)
  268.             *chtm = st.st_mtime;
  269.         return OS_NOERR;
  270.     }
  271. }
  272.  
  273. /*  set timestamps of a file */
  274. OSError
  275. OS_SetFileTime(const OSSpec * spec, OSTime * crtm, OSTime * chtm)
  276. {
  277.     struct utimbuf buf;
  278.     struct stat st;
  279.  
  280.     GETSPECSTR(spec, intbuf);
  281.  
  282.     if (stat(intbuf, &st) < 0)
  283.         return errno;
  284.  
  285. #warning "Can't set creation time"
  286.     buf.actime = chtm ? *chtm : st.st_atime;
  287.     buf.modtime = crtm ? *crtm : st.st_mtime;
  288.  
  289.     if (utime(intbuf, &buf) < 0)
  290.         return errno;
  291.     else
  292.         return OS_NOERR;
  293. }
  294.  
  295. /*    modify protection on a file */
  296. OSError
  297. OS_ModifyProtection(const OSSpec * spec, bool protect)
  298. {
  299.     struct stat st;
  300.  
  301.     GETSPECSTR(spec, intbuf);
  302.     if (stat(intbuf, &st) < 0)
  303.         return errno;
  304.  
  305.     if (chmod(intbuf, (st.st_mode & ~S_IREAD) | (protect ? 0 : S_IREAD)) < 0)
  306.         return errno;
  307.     else
  308.         return OS_NOERR;
  309. }
  310.  
  311. /*    get protection on a file */
  312. OSError
  313. OS_CheckProtection(const OSSpec *spec, bool *is_protected)
  314. {
  315.     struct stat st;
  316.  
  317.     GETSPECSTR(spec, intbuf);
  318.     if (stat(intbuf, &st) < 0)
  319.         return errno;
  320.  
  321.     *is_protected = (st.st_mode & ~S_IREAD) == 0;
  322.     return OS_NOERR;
  323. }
  324.  
  325.  
  326. /*    get disk space info */
  327. OSError
  328. OS_GetDiskStats(const OSPathSpec * spec,
  329.                 OSSize * blocksize, OSSize * total, OSSize * free)
  330. {
  331. #if __linux__
  332.     struct statfs stf;
  333.  
  334.     GETPATHSPECSTR(spec, intbuf);
  335.     if (statfs(intbuf, &stf) < 0)
  336.         return errno;
  337.  
  338.     *blocksize = stf.f_bsize;
  339.     *total = stf.f_blocks;
  340.     *free = stf.f_bfree;
  341.     return OS_NOERR;
  342. #else
  343. #error
  344. #endif
  345. }
  346.  
  347. /*************************************/
  348. #if 0
  349. #pragma mark -
  350. #endif
  351.  
  352.  
  353. /*    open an existing file */
  354. OSError
  355. OS_Open(const OSSpec * spec, OSOpenMode mode, OSRef * ref)
  356. {
  357.     static int  modetrans[] =
  358.         { O_RDONLY, O_WRONLY, O_RDWR, O_APPEND | O_WRONLY };
  359.  
  360.     GETSPECSTR(spec, intbuf);
  361.     *ref = open(intbuf, modetrans[mode]);
  362.     if (*ref < 0) {
  363.         *ref = -1;                /* don't let someone blithely close this handle */
  364.         return errno;
  365.     } else
  366.         return OS_NOERR;
  367. }
  368.  
  369. /*    write binary data, up to length bytes;
  370.     length==0 can extend file;
  371.     update length;
  372.     error indicates serious failure */
  373. OSError
  374. OS_Write(OSRef ref, void *buffer, OSSize * length)
  375. {
  376.     struct stat st;
  377.     size_t      pos;
  378.  
  379.     if (fstat(ref, &st) < 0)
  380.         return errno;
  381.  
  382.     pos = lseek(ref, 0, SEEK_CUR);
  383.     if (pos > st.st_size && *length == 0) {
  384.         lseek(ref, -1, SEEK_CUR);
  385.         if (write(ref, "\0", 1) != 1) {
  386.             *length = 0;
  387.             return errno;
  388.         }
  389.     }
  390.  
  391.     *length = write(ref, buffer, *length);
  392.     if ((signed) *length < 0) {
  393.         return errno;
  394.     } else
  395.         return OS_NOERR;
  396. }
  397.  
  398. /*    read binary data, up to length bytes;
  399.     update length;
  400.     error indicates serious failure.  */
  401. OSError
  402. OS_Read(OSRef ref, void *buffer, OSSize * length)
  403. {
  404.     *length = read(ref, buffer, *length);
  405.     if ((signed) *length < 0)
  406.         return errno;
  407.     else
  408.         return OS_NOERR;
  409. }
  410.  
  411. /*    seek a file;
  412.     illegal seek is revealed by next write or read;
  413.     error indicates serious failure.  */
  414. OSError
  415. OS_Seek(OSRef ref, OSSeekMode how, OSPos offset)
  416. {
  417.     static int  howtrans[] = { SEEK_CUR, SEEK_SET, SEEK_END };
  418.  
  419.     return lseek(ref, offset, howtrans[how]) < 0 ? errno : OS_NOERR;
  420. }
  421.  
  422. /*    tell file position */
  423. OSError
  424. OS_Tell(OSRef ref, OSPos * offset)
  425. {
  426.     *offset = lseek(ref, 0L, SEEK_CUR);
  427.     return (*offset < 0) ? errno : OS_NOERR;
  428. }
  429.  
  430. /*    close a file */
  431. OSError
  432. OS_Close(OSRef ref)
  433. {
  434.     if (ref == -1)
  435.         return EBADF;
  436.     else
  437.         return close(ref) ? errno : OS_NOERR;
  438. }
  439.  
  440. /*  get length of a file;
  441.     return error if directory or not found */
  442. OSError
  443. OS_GetSize(OSRef ref, OSSize * length)
  444. {
  445.     struct stat st;
  446.  
  447.     if (fstat(ref, &st) < 0)
  448.         return errno;
  449.     else {
  450.         *length = st.st_size;
  451.         return OS_NOERR;
  452.     }
  453. }
  454.  
  455.  
  456. /*  set length of a file;
  457.     return error if directory or not found */
  458. #if !defined(__WATCOMC__)
  459.  
  460. OSError
  461. OS_SetSize(OSRef ref, OSSize length)
  462. {
  463.     return ftruncate(ref, length) ? errno : OS_NOERR;
  464. }
  465.  
  466. #else
  467.  
  468. OSError
  469. OS_SetSize(OSRef ref, OSSize length)
  470. {
  471.     return chsize(ref, length) ? errno : OS_NOERR;
  472. }
  473.  
  474. #endif
  475.  
  476.  
  477.  
  478. /**********************************/
  479.  
  480. /*    delete a file */
  481. OSError
  482. OS_Delete(const OSSpec * spec)
  483. {
  484.     GETSPECSTR(spec, intbuf);
  485.     return unlink(intbuf) ? errno : OS_NOERR;
  486. }
  487.  
  488. /*    rename a file */
  489. OSError
  490. OS_Rename(const OSSpec * oldspec, const OSSpec * newspec)
  491. {
  492.     char        newbuf[OS_PATHSIZE];
  493.  
  494.     GETSPECSTR(newspec, newbuf);
  495.     GETSPECSTR(oldspec, intbuf);
  496.     return rename(intbuf, newbuf) ? errno : OS_NOERR;
  497. }
  498.  
  499. /*    make directory */
  500. OSError
  501. OS_Mkdir(const OSSpec * spec)
  502. {
  503.     GETSPECSTR(spec, intbuf);
  504.     return mkdir(intbuf, 0777) ? errno : OS_NOERR;
  505. }
  506.  
  507. /*    remove directory */
  508. OSError
  509. OS_Rmdir(const OSPathSpec * spec)
  510. {
  511.     GETPATHSPECSTR(spec, intbuf);
  512.     return rmdir(intbuf) ? errno : OS_NOERR;
  513. }
  514.  
  515. /*    change directory */
  516. OSError
  517. OS_Chdir(const OSPathSpec * spec)
  518. {
  519.     GETPATHSPECSTR(spec, intbuf);
  520.     return chdir(intbuf) ? errno : OS_NOERR;
  521. }
  522.  
  523. /*    get current working directory */
  524. OSError
  525. OS_GetCWD(OSPathSpec * spec)
  526. {
  527.     if (getcwd(spec->s, OS_PATHSIZE) == NULL)
  528.         return errno;
  529.     else {
  530.         char       *ptr = spec->s + strlen(spec->s);
  531.  
  532.         if (*(ptr - 1) != '/')
  533.             strcpy(ptr, "/");
  534.         return OS_NOERR;
  535.     }
  536. }
  537.  
  538. /*    spawn a subprocess */
  539. extern char **environ;
  540.  
  541. OSError
  542. OS_Execute(const OSSpec * spec, char **argv, char **envp,
  543.            const char *stdoutfile, const char *stderrfile, int *exitcode)
  544. {
  545.     int         svstdout, svstderr;
  546.     pid_t       kidpid;
  547.     int         status;
  548.  
  549.     /*  Unix magic:  file descriptors for stdout/stderr are always
  550.        1 and 2, and are always allocated in order starting from the
  551.        lowest unopened descriptor.  This code duplicates the current
  552.        stdout/stderr (as needed), and immediately opens new files,
  553.        which become the new stdout/stderr for the child.  
  554.  
  555.        dup2 duplicates a descriptor into a specific target
  556.        (probably not necessary, but safer) */
  557.  
  558.     if (stdoutfile) {
  559.         svstdout = dup(1);
  560.         close(1);
  561.         if (open(stdoutfile, O_WRONLY | O_CREAT | O_TRUNC, 0666) < 0) {
  562.             status = errno;
  563.             dup2(svstdout, 1);
  564.             close(svstdout);
  565.             return status;
  566.         }
  567.     }
  568.  
  569.     if (stderrfile) {
  570.         svstderr = dup(2);
  571.         close(2);
  572.         if (open(stderrfile, O_WRONLY | O_CREAT | O_TRUNC, 0666) < 0) {
  573.             status = errno;
  574.             dup2(svstderr, 2);
  575.             close(svstderr);
  576.             return status;
  577.         }
  578.     }
  579.  
  580.     kidpid = fork();
  581.     if (!kidpid) {                /* kid running */
  582.         if (execve(argv[0],
  583.                    (char *const *) argv,
  584.                    (char *const *) (envp && *envp ? envp : environ)) < 0)
  585.             exit(-1);            /* signal failure */
  586.  
  587.         /* can't get here */
  588.         return EINVAL;
  589.     } else {
  590.         OSError     err;
  591.  
  592.         if (stdoutfile) {
  593.             dup2(svstdout, 1);
  594.             close(svstdout);
  595.         }
  596.  
  597.         if (stderrfile) {
  598.             dup2(svstderr, 2);
  599.             close(svstderr);
  600.         }
  601.  
  602.         *exitcode = 0;
  603.  
  604.         err = waitpid(kidpid, &status, 0) <= 0 ? errno : OS_NOERR;
  605.  
  606.         if (WIFEXITED(status))
  607.             *exitcode = WEXITSTATUS(status);
  608.  
  609.         if (WIFSIGNALED(status))
  610.             *exitcode = -WTERMSIG(status);
  611.  
  612.         return err;
  613.     }
  614. }
  615.  
  616. /*************************************/
  617. #if 0
  618. #pragma mark -
  619. #endif
  620.  
  621.  
  622. /*    tell if a filepath is legal for filesystem;
  623.     call after OS_CanonPath if necessary */
  624. OSError
  625. OS_IsLegalPath(const char *path)
  626. {
  627.     const char *scan = path;
  628.     int         pthlen = 0, fnlen = 0;
  629.  
  630.     while (*scan) {
  631.         if (*scan == '/')
  632.             fnlen = 0;
  633.         else
  634.             fnlen++;
  635.  
  636.         pthlen++;
  637.  
  638.         if (fnlen > OS_MAXNAMELEN || pthlen > OS_MAXPATHLEN)
  639.             return OS_FNTLERR;
  640.  
  641.         scan++;
  642.     }
  643.     return OS_NOERR;
  644. }
  645.  
  646. /*    tell if a filepath represents a full path */
  647. int
  648. OS_IsFullPath(const char *path)
  649. {
  650.     return (*path == '/');
  651. }
  652.  
  653. #if !defined(QNX_FS) && !defined(BEWORKS_FS)
  654.  
  655. /*    skip a volume in a fullpath */
  656. const char *
  657. OS_GetDirPtr(const char *path)
  658. {
  659.     ASSERT(*path == '/');
  660.     return path;
  661. }
  662.  
  663. #elif defined(QNX_FS)
  664.  
  665. /*    skip a volume in a fullpath '/' or '//node/[path/]' */
  666. const char *
  667. OS_GetDirPtr(const char *path)
  668. {
  669.     const char *ptr;
  670.  
  671.     ASSERT(*path == '/');
  672.     if (*(path + 1) == '/' && *(path + 2) != '/') {    /*  network path?  */
  673.         ptr = strchr(path + 3, '/');
  674.         if (ptr == NULL)
  675.             ptr = path + strlen(path);    /* just "//1" */
  676.     } else
  677.         ptr = path;
  678.  
  679.     return ptr;
  680. }
  681.  
  682.  
  683. #elif defined(BEWORKS_FS)
  684.  
  685. /*    skip a volume in a fullpath '/[vol]' or '/' */
  686. const char *
  687. OS_GetDirPtr(const char *path)
  688. {
  689.     struct stat st, stdotdot;
  690.     char        vn[OS_VOLSIZE];
  691.     const char *ptr;
  692.  
  693.     ptr = strchr(path + 1, '/');
  694.     if (ptr != NULL && (ptr - path < OS_VOLSIZE)) {
  695.         strncpy(vn, path, ptr - path);
  696.         vn[ptr - path] = 0;
  697.  
  698.         /*  Compare devices of root and possible volume */
  699.         stat("/", &st);
  700.         if (stat(vn, &stdotdot) == 0) {
  701.             if (st.st_dev != stdotdot.st_dev)
  702.                 return ptr;
  703.         }
  704.     }
  705.     return path;
  706. }
  707.  
  708. #endif
  709.  
  710. /*    compact a full path; if dst is NULL, overwrite src in place */
  711. static int
  712. OS_CompactPath(char *src, char *dst)
  713. {
  714.     char        buf[OS_PATHSIZE], *bptr;
  715.     char       *to;
  716.     const char *from, *start;
  717.  
  718.     ASSERT(OS_IsFullPath(src));
  719.  
  720. #if !defined(BEWORKS_FS)
  721.     start = OS_GetDirPtr(src);
  722. #else
  723.     start = src;                /* it's okay to do /boot/../volume */
  724. #endif
  725.  
  726.     if (dst == NULL)
  727.         bptr = buf;
  728.     else
  729.         bptr = dst;
  730.  
  731.     strncpy(bptr, src, start - src);
  732.     bptr += (start - src);
  733.  
  734.     from = start;
  735.     to = bptr;
  736.  
  737.     while (*from) {
  738.         const char *brk;
  739.  
  740.         brk = from + 1;
  741.         while (*brk && *brk != '/')
  742.             brk++;
  743.  
  744.         if (brk - from == 1)    /* eliminate '//' */
  745.             from = brk;            /* skip path break */
  746.         else {
  747.             if (brk - from == 2 && from[1] == '.')
  748.                 from = brk;
  749.             else /* eliminate ".." and previous directory */ 
  750.                 if (brk - from == 3
  751.                     && from[1] == '.'
  752.                     && from[2] == '.') {
  753.                 if (to > bptr) {
  754.                     do
  755.                         to--;
  756.                     while (to >= bptr && *to != '/');
  757.                 }
  758.                 from = brk;
  759.             } else                /* copy */
  760.                 while (from < brk)
  761.                     *to++ = *from++;
  762.  
  763.         }
  764.     }
  765.  
  766.     if (to == bptr || *(from - 1) == '/')
  767.         *to++ = '/';            /* ended at directory */
  768.  
  769.     *to = 0;                    /* end string */
  770.  
  771. #if 0
  772.  
  773.     // Bad idea.  User might want "-I/" and then use "#include "boot/home/..."
  774.  
  775. #if defined(BEWORKS_FS)
  776.     /*
  777.        If this refers to "/", make it "/boot/"
  778.      */
  779.     if (*bptr == '/' && *(bptr + 1) == 0)
  780.         strcpy(bptr, "/boot/");
  781.  
  782. #endif
  783. #endif
  784.  
  785.     if (dst == NULL)
  786.         strcpy(src, buf);
  787.  
  788.     return OS_NOERR;
  789. }
  790.  
  791.  
  792. /*    compare paths */
  793. int
  794. OS_EqualPath(const char *a, const char *b)
  795. {
  796.     return (strcmp(a, b) == 0);
  797. }
  798.  
  799. /*************************************/
  800. #if 0
  801. #pragma mark -
  802. #endif
  803.  
  804. /*    canonicalize a filepath for host; if dst is NULL, overwrite src in place */
  805. OSError
  806. OS_CanonPath(char *src, char *dst)
  807. {
  808.     int idx, out;
  809.         
  810.     if (strlen(src) > OS_MAXPATHLEN)
  811.         return OS_FNTLERR;
  812.  
  813.     /*  We don't change the size of the string, so this is okay  */
  814.     if (dst == NULL)
  815.         dst = src;
  816.  
  817.     /*    Probably the only weird thing we'll see is DOS paths  */    
  818.     idx = out = 0;
  819.  
  820.     /*    assume C: is /C/ */
  821.     if (isalpha(src[0]) && src[1] == ':') {
  822.         dst[out++] = '/';
  823.         dst[out++] = toupper(src[0]);
  824.         dst[out++] = '/';
  825.         idx += 2;
  826.     }
  827.     while (src[idx])
  828.     {
  829.         if (src[idx] == '\\')
  830.             dst[out] = '/';
  831.         else
  832.             dst[out] = src[idx];
  833.         idx++;
  834.         out++;
  835.     }            
  836.     dst[out] = 0;
  837.             
  838.     return OS_NOERR;
  839. }
  840.  
  841.  
  842. /*    make OSSpec from a path; tell what kind it is */
  843. OSError
  844. OS_MakeSpec(const char *path, OSSpec *spec, bool *isfile)
  845. {
  846.     char tmp[OS_PATHSIZE];
  847.     struct stat st;
  848.     char *ptr;
  849.     int len;
  850.     OSError err;
  851.     
  852.     *spec->path.s = *spec->name.s = 0;
  853.     
  854.     if ((err=OS_CanonPath((char*)path, tmp))!=OS_NOERR)
  855.         return err;
  856.     
  857.     /*    Prepend cwd if needed */    
  858.     if (!OS_IsFullPath(tmp))
  859.     {
  860.         char *end;
  861.         char orig[OS_PATHSIZE];
  862.         
  863.         strcpy(orig, tmp);
  864.         if (getcwd(tmp, OS_PATHSIZE)==NULL)
  865.             return errno;
  866.         
  867.         end = tmp + strlen(tmp) - 1;
  868.         if (*end!='/')
  869.         {
  870.             *++end='/';
  871.             *++end=0;
  872.         }
  873.         
  874.         if (strlen(orig) + (end - tmp) >= OS_PATHSIZE)
  875.             return OS_FNTLERR;
  876.             
  877.         strcpy(end, orig);
  878.     }
  879.     else
  880.     {
  881.         if (strlen(tmp) >= OS_PATHSIZE)
  882.             return OS_FNTLERR;
  883.     }
  884.  
  885.     if ((err=OS_CompactPath(tmp, NULL))!=OS_NOERR)
  886.         return err;
  887.     
  888.     if ((err=OS_IsLegalPath(tmp))!=OS_NOERR)
  889.         return err;
  890.         
  891.     /*  Tell if it's a directory reference  */
  892.     if (stat(tmp, &st)==0)
  893.     {
  894.         ptr = tmp + strlen(tmp);
  895.         
  896.         if (*(ptr-1)=='/')
  897.             ptr--;
  898.             
  899.         if (S_ISDIR(st.st_mode))
  900.         {
  901.             if (isfile) 
  902.                 *isfile = false;
  903.             *ptr++ = '/';
  904.         }
  905.         else
  906.         {
  907.             if (isfile) 
  908.                 *isfile = true;
  909.         }
  910.                 
  911.         *ptr=0;
  912.         
  913.     }
  914.     else
  915.     if (errno != ENOENT)
  916.         return errno;
  917.     else
  918.         if (isfile)
  919.             *isfile = true;
  920.     
  921.     ptr = strrchr(tmp, '/')+1;
  922.     
  923.     len = ptr-tmp;
  924.     if (len >= OS_PATHSIZE)
  925.     {
  926.         *spec->path.s = 0;
  927.         return OS_FNTLERR;
  928.     }
  929.         
  930.     memcpy(spec->path.s, tmp, len);
  931.     spec->path.s[len] = 0;        // truncate
  932.     
  933.     len = strlen(ptr);
  934.     if (len >= OS_NAMESIZE)
  935.     {
  936.         *spec->name.s = 0;
  937.         return OS_FNTLERR;
  938.     }
  939.     memcpy(spec->name.s, ptr, len);
  940.     spec->name.s[len] = 0;
  941.  
  942.     return OS_NOERR;
  943. }
  944.  
  945. /*    make OSSpec from a path;
  946.     must resolve to a file */
  947. OSError
  948. OS_MakeFileSpec(const char *path, OSSpec * spec)
  949. {
  950.     bool        isfile;
  951.     OSError     err;
  952.  
  953.     err = OS_MakeSpec(path, spec, &isfile);
  954.     if (err != OS_NOERR)
  955.         return err;
  956.  
  957.     if (!isfile)
  958.         return OS_FIDERR;
  959.  
  960.     return OS_NOERR;
  961. }
  962.  
  963. /*    make OSPathSpec from a volume and dir */
  964. OSError
  965. OS_MakePathSpec(const char *vol, const char *dir, OSPathSpec * spec)
  966. {
  967.     bool        isfile;
  968.     OSSpec      tmp;
  969.     OSError     err;
  970.     char        path[OS_PATHSIZE];
  971.     int            len;
  972.     
  973.     if ((vol ? strlen(vol) : 0) + (dir ? strlen(dir) : 0) + 2 > sizeof(path))
  974.         return OS_FNTLERR;
  975.  
  976.     sprintf(path, "%s%s", vol ? vol : "", dir ? dir : "");
  977.  
  978.     err = OS_MakeSpec(path, &tmp, &isfile);
  979.     len = strlen(tmp.path.s);
  980.  
  981.     if (err != OS_NOERR) {
  982.             /* ensure that path is legal */
  983.         if (len+1 < OS_PATHSIZE)
  984.             memcpy(spec->s+len, "\\", 2);
  985.         else 
  986.             memcpy(spec->s+OS_PATHSIZE-2, "\\", 2);
  987.         return err;
  988.     } else {
  989.         memcpy(spec->s, tmp.path.s, len + 1);
  990.         spec->s[OS_PATHSIZE-1] = 0;
  991.     }
  992.  
  993.     if (isfile)
  994.         return OS_FNIDERR;
  995.  
  996.     return OS_NOERR;
  997. }
  998.  
  999. /*    make OSNameSpec from a filename */
  1000. OSError
  1001. OS_MakeNameSpec(const char *name, OSNameSpec * spec)
  1002. {
  1003.     if (strchr(name, '/') != NULL)
  1004.         return OS_FIDERR;
  1005.  
  1006.     if (strlen(name) > OS_MAXNAMELEN)
  1007.         return OS_FNTLERR;
  1008.  
  1009.     strcpy(spec->s, name);
  1010.  
  1011.     return OS_NOERR;
  1012. }
  1013.  
  1014.  
  1015. /*    return FS root spec */
  1016. OSError
  1017. OS_GetRootSpec(OSPathSpec * spec)
  1018. {
  1019.     strcpy(spec->s, "/");
  1020.     return OS_NOERR;
  1021. }
  1022.  
  1023.  
  1024. /********************************************/
  1025.  
  1026. /*
  1027.     For the OS_xxxToString functions, the string buffer
  1028.     and its maximum size are passed.  If the output is too
  1029.     big for the buffer, NULL is returned.  If the
  1030.     buffer is given as NULL, the buffer is malloc()ed.
  1031. */
  1032.  
  1033. /*    make a full pathname from OSSpec */
  1034. char       *
  1035. OS_SpecToString(const OSSpec * spec, char *path, int size)
  1036. {
  1037.     if (size == 0)
  1038.         size = OS_PATHSIZE;
  1039.  
  1040.     if (path == NULL && (path = (char *) malloc(size)) == NULL)
  1041.         return NULL;
  1042.     else {
  1043.         int         plen, nlen;
  1044.  
  1045.         plen = strlen(spec->path.s);
  1046.         nlen = strlen(spec->name.s);
  1047.         if (plen + nlen >= size) {
  1048.             if (plen >= size) {
  1049.                 nlen = 0;
  1050.                 plen = size - 1;
  1051.             } else
  1052.                 nlen = size - plen - 1;
  1053.         }
  1054.         memcpy(path, spec->path.s, plen);
  1055.         memcpy(path + plen, spec->name.s, nlen);
  1056.         path[plen + nlen] = 0;
  1057.         return path;
  1058.     }
  1059. }
  1060.  
  1061. /*    make a path from OSPathSpec */
  1062. char       *
  1063. OS_PathSpecToString(const OSPathSpec * pspec, char *path, int size)
  1064. {
  1065.     if (size == 0)
  1066.         size = OS_PATHSIZE;
  1067.  
  1068.     if (path == NULL && (path = (char *) malloc(size)) == NULL)
  1069.         return NULL;
  1070.     else {
  1071.         int         plen;
  1072.  
  1073.         plen = strlen(pspec->s);
  1074.         if (plen >= size)
  1075.             plen = size - 1;
  1076.         memcpy(path, pspec->s, plen);
  1077.         path[plen] = 0;
  1078.         return path;
  1079.     }
  1080. }
  1081.  
  1082. /*    make a name from OSNameSpec */
  1083. char       *
  1084. OS_NameSpecToString(const OSNameSpec * nspec, char *name, int size)
  1085. {
  1086.     if (size == 0)
  1087.         size = OS_NAMESIZE;
  1088.  
  1089.     if (name == NULL && (name = (char *) malloc(size)) == NULL)
  1090.         return NULL;
  1091.     else {
  1092.         int         nlen = strlen(nspec->s);
  1093.  
  1094.         if (nlen >= size)
  1095.             nlen = size - 1;
  1096.         memcpy(name, nspec->s, nlen);
  1097.         name[nlen] = 0;
  1098.         return name;
  1099.     }
  1100. }
  1101.  
  1102. /*    return the size of an OSPathSpec, for duplication purposes */
  1103. int
  1104. OS_SizeOfPathSpec(const OSPathSpec * spec)
  1105. {
  1106.     return (strlen(spec->s) + 1);
  1107. }
  1108.  
  1109. /*    return the size of an OSNameSpec, for duplication purposes */
  1110. int
  1111. OS_SizeOfNameSpec(const OSNameSpec * spec)
  1112. {
  1113.     return (strlen(spec->s) + 1);
  1114. }
  1115.  
  1116. /*    compare OSSpecs */
  1117. int
  1118. OS_EqualSpec(const OSSpec * a, const OSSpec * b)
  1119. {
  1120.     return OS_EqualPathSpec(&a->path, &b->path) &&
  1121.         OS_EqualNameSpec(&a->name, &b->name);
  1122. }
  1123.  
  1124. /*    compare OSPathSpecs */
  1125. int
  1126. OS_EqualPathSpec(const OSPathSpec * a, const OSPathSpec * b)
  1127. {
  1128.     return (strcmp(a->s, b->s) == 0);
  1129. }
  1130.  
  1131. /*    compare OSNameSpecs */
  1132. int
  1133. OS_EqualNameSpec(const OSNameSpec * a, const OSNameSpec * b)
  1134. {
  1135.     return (strcmp(a->s, b->s) == 0);
  1136. }
  1137.  
  1138. #if 0
  1139. #pragma mark -
  1140. #endif
  1141.  
  1142.  
  1143. /*    tell if OSSpec is a directory */
  1144. int
  1145. OS_IsDir(const OSSpec * spec)
  1146. {
  1147.     struct stat st;
  1148.  
  1149.     if (OS_SpecToString(spec, intbuf, sizeof(intbuf)) == NULL)
  1150.         return 0;
  1151.  
  1152.     if (stat(intbuf, &st) < 0)
  1153.         return 0;
  1154.     else
  1155.         return S_ISDIR(st.st_mode);
  1156. }
  1157.  
  1158. /*    tell if OSSpec is a file */
  1159. int
  1160. OS_IsFile(const OSSpec * spec)
  1161. {
  1162.     struct stat st;
  1163.  
  1164.     if (OS_SpecToString(spec, intbuf, sizeof(intbuf)) == NULL)
  1165.         return 0;
  1166.  
  1167.     if (stat(intbuf, &st) < 0)
  1168.         return 0;
  1169.     else
  1170.         return !S_ISDIR(st.st_mode);
  1171. }
  1172.  
  1173. /*    tell if OSSpec is a softlink */
  1174. int
  1175. OS_IsLink(const OSSpec * spec)
  1176. {
  1177.     struct stat st;
  1178.     char       *ptr;
  1179.  
  1180.     if (OS_SpecToString(spec, intbuf, sizeof(intbuf)) == NULL)
  1181.         return 0;
  1182.  
  1183.     ptr = intbuf + strlen(intbuf) - 1;
  1184.  
  1185.     if (*ptr == '/')
  1186.         *ptr = 0;
  1187.  
  1188.     if (lstat(intbuf, &st) < 0)
  1189.         return 0;
  1190.     else
  1191.         return S_ISLNK(st.st_mode);
  1192. }
  1193.  
  1194. /*    resolve a [soft] link / alias */
  1195. OSError
  1196. OS_ResolveLink(const OSSpec * link, OSSpec * target)
  1197. {
  1198.     char        fn[OS_NAMESIZE];
  1199.     char        path[OS_PATHSIZE];
  1200.     int         len;
  1201.  
  1202.     if (OS_SpecToString(link, intbuf, sizeof(intbuf)) == NULL)
  1203.         return OS_FNTLERR;
  1204.  
  1205.     /*  does not null-terminate string */
  1206.     len = readlink(intbuf, fn, sizeof(fn));
  1207.  
  1208.     if (len < 0)
  1209.         return errno;
  1210.     else
  1211.         fn[len] = 0;
  1212.  
  1213.     sprintf(path, "%s%s", (*fn != OS_PATHSEP) ? link->path.s : "", fn);
  1214.  
  1215.     return OS_MakeSpec(path, target, NULL);
  1216. }
  1217.  
  1218. /*************************************/
  1219. #if 0
  1220. #pragma mark -
  1221. #endif
  1222.  
  1223.  
  1224. /*    open a directory for reading */
  1225. OSError
  1226. OS_OpenDir(const OSPathSpec * spec, OSDirRef * ref)
  1227. {
  1228.     DIR        *dptr;
  1229.  
  1230.     GETPATHSPECSTR(spec, intbuf);
  1231.     dptr = opendir(intbuf);
  1232.     if (dptr == NULL)
  1233.     {
  1234.         *ref->path.s = 0;
  1235.         ref->dir = (DIR *) 0L;
  1236.         return errno;
  1237.     }
  1238.  
  1239.     ref->path = *spec;
  1240.     ref->dir = (DIR *) dptr;
  1241.     return OS_NOERR;
  1242. }
  1243.  
  1244. /*    read an entry from a directory;
  1245.     don't return "." or "..";
  1246.     return error when end-of-directory reached */
  1247. OSError
  1248. OS_ReadDir(OSDirRef * ref, OSSpec * spec, char *filename, bool * isfile)
  1249. {
  1250.     struct dirent *de;
  1251.     char        fn[OS_PATHSIZE];
  1252.     OSError     err;
  1253.     int         len;
  1254.  
  1255.     if (ref->dir == 0L)
  1256.         return OS_FNFERR;
  1257.  
  1258.     do {
  1259.         de = readdir((DIR *) ref->dir);
  1260.         if (de == NULL)
  1261.             return OS_FNFERR;
  1262.     } while (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0 ||
  1263.              strlen(ref->path.s) + strlen(de->d_name) >= OS_PATHSIZE);
  1264.  
  1265.     len = strlen(ref->path.s);
  1266.     strncpy(fn, ref->path.s, OS_PATHSIZE - 1);
  1267.     if (len < OS_PATHSIZE) {
  1268.         strncpy(fn + len, de->d_name, OS_PATHSIZE - 1 - len);
  1269.         fn[OS_PATHSIZE - 1] = 0;
  1270.     } else
  1271.         return OS_FNTLERR;
  1272.  
  1273.     strncpy(filename, de->d_name, OS_NAMESIZE - 1);
  1274.     filename[OS_NAMESIZE - 1] = 0;
  1275.  
  1276.     err = OS_MakeSpec(fn, spec, isfile);
  1277.  
  1278.     return err;
  1279. }
  1280.  
  1281. /*    close directory */
  1282. OSError
  1283. OS_CloseDir(OSDirRef * ref)
  1284. {
  1285.     if (ref->dir)
  1286.         return closedir((DIR *) ref->dir);
  1287.     else
  1288.         return OS_NOERR;
  1289. }
  1290.  
  1291.  
  1292. /*************************************/
  1293. #if 0
  1294. #pragma mark -
  1295. #endif
  1296.  
  1297. /*    return time in milliseconds */
  1298. unsigned long
  1299. OS_GetMilliseconds(void)
  1300. {
  1301. #if !defined(BUILDHOST_BEWORKS)
  1302.     struct tms  tms;
  1303.  
  1304.     return times(&tms) * 1000 / CLOCKS_PER_SEC;
  1305. #else
  1306.     return system_time() / 1000;
  1307. #endif
  1308. }
  1309.  
  1310. /*    return current time */
  1311. void
  1312. OS_GetTime(OSTime * tm)
  1313. {
  1314.     time(tm);
  1315. }
  1316.  
  1317. #if 0
  1318. #pragma mark -
  1319. #endif
  1320.  
  1321.  
  1322. /*    allocate a memory handle */
  1323.  
  1324. enum { OSMemDelta = 256 };
  1325.  
  1326. OSError
  1327. OS_NewHandle(OSSize size, OSHandle * hand)
  1328. {
  1329.     hand->addr = NULL;
  1330.     hand->used = size;
  1331.  
  1332.     /* allow easy growth; never allocate zero bytes */
  1333.     hand->size = (size + OSMemDelta) & ~(OSMemDelta - 1);
  1334.     hand->addr = (void *) malloc(hand->size);
  1335.     if (hand->addr == NULL)
  1336.         return OS_MEMERR;
  1337.     else
  1338.         return OS_NOERR;
  1339. }
  1340.  
  1341. /*    resize handle  */
  1342. OSError
  1343. OS_ResizeHandle(OSHandle * hand, OSSize size)
  1344. {
  1345.     /* never allocate zero bytes */
  1346.     OSSize      nsize = (size + OSMemDelta) & ~(OSMemDelta - 1);
  1347.     void       *naddr = (void *) realloc(hand->addr, nsize);
  1348.  
  1349.     if (naddr == NULL)
  1350.         return OS_MEMERR;
  1351.     else {
  1352.         hand->addr = naddr;
  1353.         hand->size = nsize;
  1354.         hand->used = size;
  1355.         return OS_NOERR;
  1356.     }
  1357. }
  1358.  
  1359. /*    lock handle  */
  1360. void       *
  1361. OS_LockHandle(OSHandle * hand)
  1362. {
  1363.     return hand->addr;
  1364. }
  1365.  
  1366. /*    unlock handle  */
  1367. void
  1368. OS_UnlockHandle(OSHandle * hand)
  1369. {
  1370. }
  1371.  
  1372. /*    free handle  */
  1373. OSError
  1374. OS_FreeHandle(OSHandle * hand)
  1375. {
  1376.     if (hand->addr == NULL)
  1377.         return OS_MEMERR;
  1378.  
  1379.     free(hand->addr);
  1380.     hand->used = hand->size = 0;
  1381.     hand->addr = NULL;
  1382.     return OS_NOERR;
  1383. }
  1384.  
  1385. /*    get handle size */
  1386. OSError
  1387. OS_GetHandleSize(OSHandle * hand, OSSize * size)
  1388. {
  1389.     if (hand->addr != NULL) {
  1390.         *size = (OSSize) hand->used;
  1391.         return OS_NOERR;
  1392.     } else {
  1393.         *size = 0;
  1394.         return OS_MEMERR;
  1395.     }
  1396. }
  1397.  
  1398. /*    invalidate handle */
  1399. void
  1400. OS_InvalidateHandle(OSHandle * hand)
  1401. {
  1402.     hand->addr = NULL;
  1403.     hand->used = 0;
  1404. }
  1405.  
  1406. /*    tell whether a handle is valid */
  1407. bool
  1408. OS_ValidHandle(OSHandle * hand)
  1409. {
  1410.     return hand != NULL && hand->addr != NULL;
  1411. }
  1412.  
  1413. /*************************************/
  1414. #if 0
  1415. #pragma mark -
  1416. #endif
  1417.  
  1418.  
  1419. /*************************************/
  1420. #if 0
  1421. #pragma mark -
  1422. #endif
  1423.  
  1424.  
  1425. /*    Shared library / DLL routines  */
  1426.  
  1427. #if defined(SHLIB_DL)
  1428.  
  1429. /*    open a shared library  */
  1430. OSError
  1431. OS_OpenLibrary(const OSSpec * spec, OSLibrary * lib)
  1432. {
  1433.     GETSPECSTR(spec, intbuf);
  1434.     *lib = dlopen(intbuf, RTLD_NOW);
  1435.     lastdlerr = dlerror();
  1436.     if (*lib == NULL)
  1437.         return OS_DLERR;
  1438.     else
  1439.         return OS_NOERR;
  1440. }
  1441.  
  1442. /*    find a symbol in the library */
  1443.  
  1444. /*    dlsym() may return NULL for a symbol defined to be NULL...
  1445.     only dlerror() can tell if an error really happened.
  1446.  */
  1447. OSError
  1448. OS_GetLibrarySymbol(OSLibrary lib, char *name, void **sym)
  1449. {
  1450.     *sym = dlsym(lib, name);
  1451.     lastdlerr = dlerror();
  1452.     if (*sym == NULL && lastdlerr != NULL)
  1453.         return OS_DLERR;
  1454.     else
  1455.         return OS_NOERR;
  1456. }
  1457.  
  1458. /*    close a shared library */
  1459. OSError
  1460. OS_CloseLibrary(OSLibrary lib)
  1461. {
  1462.     int         st;
  1463.  
  1464.     st = dlclose(lib);
  1465.     lastdlerr = dlerror();
  1466.     if (st < 0)
  1467.         return OS_DLERR;
  1468.     else
  1469.         return OS_NOERR;
  1470. }
  1471.  
  1472.  
  1473. /*****************************/
  1474. #if 0
  1475. #pragma mark -
  1476. #endif
  1477.  
  1478.  
  1479. #elif defined(SHLIB_BE)
  1480.  
  1481. /*    open a shared library  */
  1482. OSError
  1483. OS_OpenLibrary(const OSSpec * spec, OSLibrary * lib)
  1484. {
  1485.     GETSPECSTR(spec, intbuf);
  1486.     *lib = load_add_on(intbuf);
  1487.     if (*lib >= 0) {
  1488.         lastdlerr = NULL;
  1489.         return OS_NOERR;
  1490.     } else {
  1491.         lastdlerr = NULL;
  1492.         return OS_FNFERR;
  1493.     }
  1494. }
  1495.  
  1496. /*    find a symbol in the library */
  1497. OSError
  1498. OS_GetLibrarySymbol(OSLibrary lib, char *name, void **sym)
  1499. {
  1500.     status_t    st;
  1501.     static char dlerrbuf[OS_PATHSIZE + 64];
  1502.  
  1503.     st = get_image_symbol(lib, name, B_SYMBOL_TYPE_ANY, sym);
  1504.     if (st != B_NO_ERROR) {
  1505.         image_info  info;
  1506.  
  1507.         if (get_image_info(lib, &info) == B_NO_ERROR) {
  1508.             sprintf(dlerrbuf,
  1509.                     "Symbol '%s' not found in '%s'", name, info.name);
  1510.             lastdlerr = dlerrbuf;
  1511.         } else {
  1512.             sprintf(dlerrbuf,
  1513.                     "Symbol '%s' not found in shared library", name);
  1514.             lastdlerr = dlerrbuf;
  1515.         }
  1516.  
  1517.         *sym = NULL;
  1518.         return OS_DLERR;
  1519.     } else {
  1520.         lastdlerr = NULL;
  1521.         return OS_NOERR;
  1522.     }
  1523. }
  1524.  
  1525. /*    close a shared library */
  1526. OSError
  1527. OS_CloseLibrary(OSLibrary lib)
  1528. {
  1529.     status_t    st;
  1530.  
  1531.     st = unload_add_on(lib);
  1532.     if (st != B_NO_ERROR) {
  1533.         lastdlerr = "Error closing shared library";
  1534.         return OS_DLERR;
  1535.     } else {
  1536.         lastdlerr = NULL;
  1537.         return OS_NOERR;
  1538.     }
  1539. }
  1540.  
  1541.  
  1542. /************************************/
  1543.  
  1544. #if 0
  1545. #pragma mark -
  1546. #endif
  1547.  
  1548. #else
  1549.  
  1550. /*    No support for shared libraries */
  1551.  
  1552. /*    open a shared library  */
  1553. OSError
  1554. OS_OpenLibrary(const OSSpec * spec, OSLibrary * lib)
  1555. {
  1556.     *lib = NULL;
  1557.     lastdlerr = "No support for shared libraries";
  1558.     return OS_DLERR;
  1559. }
  1560.  
  1561. /*    find a symbol in the library */
  1562. OSError
  1563. OS_GetLibrarySymbol(OSLibrary lib, char *name, void **sym)
  1564. {
  1565.     *sym = NULL;
  1566.     lastdlerr = "No support for shared libraries";
  1567.     return OS_DLERR;
  1568. }
  1569.  
  1570. /*    close a shared library */
  1571. OSError
  1572. OS_CloseLibrary(OSLibrary lib)
  1573. {
  1574.     lastdlerr = "No support for shared libraries";
  1575.     return OS_DLERR;
  1576. }
  1577.  
  1578. #endif
  1579.