home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 13 / AACD13.ISO / AACD / Online / Samba / source / amiga / amiga.c < prev    next >
C/C++ Source or Header  |  2000-05-24  |  160KB  |  8,101 lines

  1. /*
  2.  * $Id: amiga.c 1.14 2000/05/24 19:50:17 olsen Exp olsen $
  3.  *
  4.  * :ts=4
  5.  *
  6.  * AmigaOS wrapper routines for Samba 2.0.0, using the AmiTCP V4 API
  7.  * and the SAS/C V6.58 compiler.
  8.  *
  9.  * Copyright (C) 1999-2000 by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. /******************************************************************************/
  27.  
  28. #include <bsdsocket/socketbasetags.h>
  29. #include <libraries/usergroup.h>
  30.  
  31. #include <intuition/intuition.h>
  32. #include <libraries/locale.h>
  33. #include <exec/execbase.h>
  34. #include <exec/memory.h>
  35. #include <dos/dosextens.h>
  36. #include <dos/dostags.h>
  37. #include <devices/timer.h>
  38. #include <utility/date.h>
  39.  
  40. #include <clib/usergroup_protos.h>
  41. #include <clib/socket_protos.h>
  42.  
  43. #include <clib/intuition_protos.h>
  44. #include <clib/utility_protos.h>
  45. #include <clib/locale_protos.h>
  46. #include <clib/timer_protos.h>
  47. #include <clib/alib_protos.h>
  48. #include <clib/exec_protos.h>
  49. #include <clib/dos_protos.h>
  50.  
  51. #include <sys/socket.h>
  52. #include <sys/ioctl.h>
  53. #include <sys/time.h>
  54. #include <sys/dir.h>
  55.  
  56. #include <net/if.h>
  57.  
  58. #include <constructor.h>
  59. #include <stdarg.h>
  60. #include <stdlib.h>
  61. #include <string.h>
  62. #include <unistd.h>
  63. #include <signal.h>
  64. #include <utime.h>
  65. #include <errno.h>
  66. #include <stdio.h>
  67. #include <fcntl.h>
  68. #include <inetd.h>
  69. #include <stat.h>
  70. #include <ios1.h>
  71. #include <dos.h>
  72.  
  73. #include <pragmas/usergroup_pragmas.h>
  74. #include <pragmas/socket_pragmas.h>
  75.  
  76. #include <pragmas/exec_sysbase_pragmas.h>
  77. #include <pragmas/intuition_pragmas.h>
  78. #include <pragmas/utility_pragmas.h>
  79. #include <pragmas/locale_pragmas.h>
  80. #include <pragmas/timer_pragmas.h>
  81. #include <pragmas/dos_pragmas.h>
  82.  
  83. /******************************************************************************/
  84.  
  85. /* This is for the "iface_struct" definition. */
  86. #include "interfaces.h"
  87.  
  88. /******************************************************************************/
  89.  
  90. /*#define DEBUG*/
  91. #include "Assert.h"
  92.  
  93. /******************************************************************************/
  94.  
  95. STATIC VOID ReportProblem(const char *fmt, ...);
  96. STATIC VOID ForbidDOSCleanup(VOID);
  97. STATIC VOID PermitDOS(VOID);
  98. STATIC VOID ForbidDOS(VOID);
  99. STATIC VOID UnblockDescriptorCleanup(VOID);
  100. STATIC BOOL IsDescriptorNonblocking(int fd);
  101. STATIC VOID BlockDescriptor(int fd);
  102. STATIC VOID UnblockDescriptor(int fd);
  103. STATIC VOID SaveDescriptorCleanup(VOID);
  104. STATIC VOID RestoreDescriptor(struct UFB *ufb);
  105. STATIC BOOL SaveDescriptor(struct UFB *ufb);
  106. STATIC VOID UnmangleName(char **namePtr, struct MangleInfo *mi);
  107. STATIC int MangleName(char ** namePtr,struct MangleInfo * mi);
  108. STATIC VOID CloseUnlinkUnlockCleanup(VOID);
  109. STATIC VOID OpenDirCleanup(VOID);
  110. STATIC int TranslateRelativePath(char **namePtr, char *replace, int maxReplaceLen);
  111. STATIC VOID MapDescriptorSets(const fd_set *input_fds, int num_input_fds, fd_set *socket_fds, int *max_socket_fd_ptr, fd_set *file_fds, int *max_file_fd_ptr);
  112. STATIC VOID RemapDescriptorSets(const fd_set *socket_fds, int max_socket_fd, const fd_set *file_fds, int max_file_fd, fd_set *output_fds, int num_output_fds);
  113. STATIC VOID ConvertFileInfoToStat(struct MsgPort *port, struct FileInfoBlock *fib, struct stat *st);
  114. STATIC BOOL do_match(STRPTR str, STRPTR regexp);
  115. STATIC VOID nstrcpy_blank(const size_t maxSize, char *to, const char *from);
  116. STATIC BOOL SetFileSocket(FILE *stream, int sockfd);
  117. STATIC VOID DaemonInit(VOID);
  118. STATIC struct tm *ConvertTime(ULONG seconds);
  119. STATIC VOID MapIoErrToErrno(VOID);
  120. STATIC int MapFileNameAmigaToUnix(const char *amiga, char *unix, int maxUnixLen);
  121. STATIC VOID FlushSTDOUT(VOID);
  122. STATIC VOID CleanupSambaSemaphore(VOID);
  123. STATIC BOOL SetupSambaSemaphore(VOID);
  124. STATIC VOID RemoveLockedRegionNode(struct UFB *ufb, LONG start, LONG stop);
  125. STATIC VOID DeleteLockedRegionNode(struct LockedRegionNode *lrn);
  126. STATIC LONG CreateLockedRegionNode(struct LockedRegionNode **resultPtr);
  127. STATIC VOID DeleteFileLockNode(struct FileLockNode *fln);
  128. STATIC LONG CreateFileLockNode(struct UFB *ufb, struct FileLockNode **resultPtr);
  129. STATIC LONG FindFileLockNodeByFileHandle(BPTR fileHandle, struct FileLockNode **resultPtr);
  130. STATIC VOID FindFileLockNodeByDrawerAndName(BPTR parentDir, STRPTR fileName, struct FileLockNode **resultPtr);
  131. STATIC VOID CleanupFileLocks(int fd);
  132. STATIC int HandleFileLocking(int cmd, struct flock *l, struct UFB *ufb);
  133. STATIC struct LockedRegionNode *FindCollidingRegion(struct FileLockNode *fln, LONG start, LONG stop, BOOL shared);
  134.  
  135. /******************************************************************************/
  136.  
  137. int amiga_sigmask(int signum);
  138. int amiga_sigblock(int sigmask);
  139. int amiga_sigsetmask(int sigmask);
  140. int amiga_unlink(char *name);
  141. int amiga_open(char *name, int mode, int prot);
  142. int amiga_chdir(char *path);
  143. DIR *amiga_opendir(char *dirName);
  144. VOID amiga_closedir(DIR *dir);
  145. struct dirent *amiga_readdir(DIR *dir);
  146. int amiga_mkdir(char *name, int mode);
  147. int amiga_rmdir(char *name);
  148. int amiga_creat(char *name, int prot);
  149. FILE *amiga_fopen(char *name, char *mode);
  150. int amiga_rename(char *old, char *new);
  151. char *amiga_getcwd(char *buf, size_t size);
  152. int amiga_ftruncate(int fd, off_t size);
  153. int amiga_accept(int sockfd, struct sockaddr *cliaddr, int *addrlen);
  154. int amiga_bind(int sockfd, struct sockaddr *name, int namelen);
  155. int amiga_close(int fd);
  156. int amiga_connect(int sockfd, struct sockaddr *name, int namelen);
  157. int amiga_getpeername(int sockfd, struct sockaddr *name, int *namelen);
  158. int amiga_getsockopt(int sockfd, int level, int optname, VOID *optval, int *optlen);
  159. int amiga_ioctl(int fd, unsigned long request, char *arg);
  160. int amiga_listen(int sockfd, int backlog);
  161. int amiga_read(int fd, VOID *data, unsigned int size);
  162. int amiga_recvfrom(int sockfd, VOID *buff, int len, int flags, struct sockaddr *from, int *fromlen);
  163. int amiga_select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *timeout);
  164. int amiga_sendto(int sockfd, VOID *buff, int len, int flags, struct sockaddr *to, int tolen);
  165. int amiga_setsockopt(int sockfd, int level, int optname, VOID *optval, int optlen);
  166. int amiga_socket(int domain, int type, int protocol);
  167. int amiga_write(int fd, VOID *data, unsigned int size);
  168. int amiga_stat(char *name, struct stat *st);
  169. int amiga_lstat(char *name, struct stat *statstruct);
  170. int amiga_fstat(int fd, struct stat *st);
  171. int amiga_chmod(char *name, int mode);
  172. int amiga_dup(int fd);
  173. int amiga_dup2(int old_fd, int new_fd);
  174. int amiga_chown(char *name, uid_t uid, gid_t gid);
  175. int amiga_setegid(gid_t g);
  176. int amiga_seteuid(uid_t u);
  177. int amiga_gettimeofday(struct timeval *tv);
  178. int amiga_utime(char *name, struct utimbuf *time);
  179. VOID amiga_sleep(unsigned int seconds);
  180. char *amiga_crypt(char *key, char *salt);
  181. char *amiga_getpass(char *prompt);
  182. int amiga_setgid(gid_t id);
  183. int amiga_setgroups(int ngroups, gid_t *groups);
  184. gid_t amiga_getgid(VOID);
  185. struct group *amiga_getgrgid(gid_t gid);
  186. struct group *amiga_getgrnam(char *name);
  187. int amiga_getgroups(int ngroups, gid_t *groups);
  188. struct hostent *amiga_gethostbyaddr(char *addr, int len, int type);
  189. struct hostent *amiga_gethostbyname(char *name);
  190. struct netent *amiga_getnetbyname(char *name);
  191. int amiga_gethostname(char *hostname, int size);
  192. struct passwd *amiga_getpwnam(char *name);
  193. struct passwd *amiga_getpwuid(uid_t uid);
  194. uid_t amiga_getuid(VOID);
  195. gid_t amiga_getegid(VOID);
  196. uid_t amiga_geteuid(VOID);
  197. int amiga_initgroups(char *name, gid_t basegroup);
  198. int amiga_setuid(uid_t id);
  199. int amiga_umask(int mask);
  200. unsigned long amiga_inet_addr(char *addr);
  201. char *amiga_inet_ntoa(struct in_addr in);
  202. int amiga_getopt(int argc, char *argv[], char *opts);
  203. int amiga_system(char *cmd);
  204. int amiga_fork(VOID);
  205. VOID __tzset(VOID);
  206. time_t time(time_t *timeptr);
  207. struct tm *gmtime(const time_t *t);
  208. struct tm *localtime(const time_t *t);
  209. int amiga_strcasecmp(char *a, char *b);
  210. int amiga_strncasecmp(char *a, char *b, int len);
  211. VOID (*amiga_signal(int which,VOID (* action)(int)))(int);
  212. VOID amiga_alarm(int seconds);
  213. int amiga_waitpid(pid_t pid, int *status, int options);
  214. long amiga_setsid(VOID);
  215. int amiga_setreuid(uid_t real, uid_t eff);
  216. int amiga_setregid(gid_t real, gid_t eff);
  217. int amiga_fcntl(int fd, int cmd, unsigned long arg);
  218. int amiga_getsockname(int sockfd, struct sockaddr *name, int *namelen);
  219. int amiga_statfs(char *name, struct statfs *f);
  220. int amiga_execl(char *path, char *arg, ...);
  221. char *amiga_strerror(int error);
  222. int amiga_access(char *name, int modes);
  223. off_t amiga_lseek(int fd, off_t offset, int mode);
  224. int amiga_chroot(char *name);
  225. int amiga_kill(pid_t pid, int sig);
  226. pid_t amiga_getpid(VOID);
  227. int amiga_fgetc(FILE *in);
  228. char *amiga_fgets(char *str, int n, FILE *in);
  229. int amiga_fputs(const char *str, FILE *out);
  230. int amiga_puts(const char *str);
  231. int amiga_vfprintf(FILE *out, const char *fmt, va_list args);
  232. int amiga_fprintf(FILE *out, const char *fmt, ...);
  233. int amiga_printf(const char *fmt, ...);
  234. size_t amiga_fwrite(const void *data, size_t blockSize, size_t numBlocks, FILE *out);
  235. size_t amiga_fread(void *data, size_t blockSize, size_t numBlocks, FILE *in);
  236. int amiga_fclose(FILE *stream);
  237. int amiga_fflush(FILE *stream);
  238. int amiga_fseek(FILE *stream, long int offset, int mode);
  239. long int amiga_ftell(FILE *stream);
  240. int amiga_setvbuf(FILE *fp, char *buff, int type, size_t size);
  241. int amiga_fputc(int c,FILE *stream);
  242. VOID amiga_setbuf(FILE *stream,char *buffer);
  243.  
  244. /******************************************************************************/
  245.  
  246. VOID __regargs __chkabort(VOID);
  247. VOID _CXOVF(VOID);
  248. VOID __regargs _CXBRK(VOID);
  249.  
  250. /******************************************************************************/
  251.  
  252. /* These are in the Samba runtime library. */
  253. extern int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
  254. extern int snprintf (char *str, size_t count, const char *fmt, ...);
  255.  
  256. /******************************************************************************/
  257.  
  258. #define ZERO    ((BPTR)0L)
  259. #define ERROR    (-1)
  260. #define OK        (0)
  261. #define SAME    (0)
  262. #define NO        !
  263. #define NOT        !
  264. #define DONT    !
  265. #define CANNOT    !
  266. #define BUSY    (NULL)
  267. #define NO_FLAG    (0)
  268.  
  269. /******************************************************************************/
  270.  
  271. #define FLAG_IS_SET(v,f)    (((v) & (f)) == (f))
  272. #define FLAG_IS_CLEAR(v,f)    (((v) & (f)) == 0)
  273.  
  274. #define SET_FLAG(v,f)        (v |=  (f))
  275. #define CLEAR_FLAG(v,f)        (v &= ~(f))
  276.  
  277. /******************************************************************************/
  278.  
  279. #define STRING_IS_EMPTY(s)    (s[0] == '\0')
  280. #define NUM_ENTRIES(t)        (sizeof(t) / sizeof(t[0]))
  281.  
  282. /******************************************************************************/
  283.  
  284. #define FIB_IS_FILE(fib)    ((fib)->fib_DirEntryType < 0)
  285. #define FIB_IS_DRAWER(fib)    ((fib)->fib_DirEntryType >= 0 && (fib)->fib_DirEntryType != ST_SOFTLINK)
  286.  
  287. /******************************************************************************/
  288.  
  289. #define UFB_IS_SOCKET        0x0800
  290. #define UFB_IS_NON_BLOCKING    0x1000
  291. #define UFB_UNLINK            0x2000
  292. #define UFB_LOCKED            0x4000
  293.  
  294. #define UNIX_TIME_OFFSET    252482400
  295.  
  296. #define MAX_BSTR_LEN        256
  297. #define MAX_FILENAME_LEN    512
  298. #define MAX_FFS_NAME_LEN    30
  299.  
  300. /******************************************************************************/
  301.  
  302. long __oslibversion = 37;
  303.  
  304. /******************************************************************************/
  305.  
  306. extern struct Library * SysBase;
  307. extern struct Library * DOSBase;
  308. extern struct Library * UtilityBase;
  309.  
  310. /******************************************************************************/
  311.  
  312. STATIC struct Device * TimerBase;
  313. STATIC struct MsgPort * TimerPort;
  314. STATIC struct timerequest * TimerRequest;
  315. STATIC LONG MinutesWest;
  316.  
  317. /******************************************************************************/
  318.  
  319. STATIC struct Library * SocketBase;
  320. STATIC struct Library * UserGroupBase;
  321.  
  322. /******************************************************************************/
  323.  
  324. #if defined(_M68020) && defined(_M68881)
  325. #define MACHINE_TYPE "['020+FPU]"
  326. #elif defined(_M68020)
  327. #define MACHINE_TYPE "['020]"
  328. #else
  329. #define MACHINE_TYPE "[68k]"
  330. #endif
  331.  
  332. /******************************************************************************/
  333.  
  334. #include "Amiga_Samba_rev.h"
  335. char * VersionTag = VERSTAG " " MACHINE_TYPE " Samba version 2.0.0 ported by Olaf `Olsen' Barthel <olsen@sourcery.han.de>";
  336.  
  337. /******************************************************************************/
  338.  
  339. /* This is for backwards compatibility with Kickstart 2.04 and
  340.  * avoids a deadlock when trying to get a shared lock on
  341.  * a semaphore already held in exclusive mode by the same Task.
  342.  */
  343. STATIC VOID
  344. SafeObtainSemaphoreShared(struct SignalSemaphore * semaphore)
  345. {
  346.     /* Do it right with Kickstart 3.x. */
  347.     if(SysBase->lib_Version >= 39)
  348.     {
  349.         ObtainSemaphoreShared(semaphore);
  350.     }
  351.     else
  352.     {
  353.         /* Try to get the shared semaphore */
  354.         if(CANNOT AttemptSemaphoreShared(semaphore))
  355.         {
  356.             /* Check if we can get the exclusive version */
  357.             if(CANNOT AttemptSemaphore(semaphore))
  358.             {
  359.                 /* Oh well, wait for the shared lock */
  360.                 ObtainSemaphoreShared(semaphore);
  361.             }
  362.         }
  363.     }
  364. }
  365.  
  366. /******************************************************************************/
  367.  
  368. STATIC BOOL AllowBreak = TRUE;
  369.  
  370. STATIC BOOL
  371. CheckAbort(VOID)
  372. {
  373.     BOOL result;
  374.  
  375.     result = (BOOL)(AllowBreak && FLAG_IS_SET(SetSignal(0,SIGBREAKF_CTRL_C),SIGBREAKF_CTRL_C));
  376.  
  377.     return(result);
  378. }
  379.  
  380. VOID __regargs
  381. __chkabort(VOID)
  382. {
  383.     if(CheckAbort())
  384.         raise(SIGINT);
  385. }
  386.  
  387. int
  388. amiga_sigmask(int signum)
  389. {
  390.     int result = 0;
  391.  
  392.     ENTER();
  393.  
  394.     SHOWVALUE(signum);
  395.  
  396.     if(signum == SIGTERM || signum == SIGINT)
  397.         result = (1<<SIGINT);
  398.  
  399.     RETURN(result);
  400.     return(result);
  401. }
  402.  
  403. int
  404. amiga_sigblock(int sigmask)
  405. {
  406.     BOOL oldAllowBreak = AllowBreak;
  407.     int result = 0;
  408.  
  409.     ENTER();
  410.  
  411.     SHOWVALUE(sigmask);
  412.  
  413.     if(DONT AllowBreak)
  414.         result = (1<<SIGINT);
  415.  
  416.     if(FLAG_IS_SET(sigmask,(1<<SIGINT)))
  417.     {
  418.         AllowBreak = FALSE;
  419.  
  420.         if(oldAllowBreak != AllowBreak)
  421.         {
  422.             SocketBaseTags(
  423.                 SBTM_SETVAL(SBTC_BREAKMASK),NO_FLAG,
  424.             TAG_END);
  425.         }
  426.     }
  427.  
  428.     RETURN(result);
  429.     return(result);
  430. }
  431.  
  432. int
  433. amiga_sigsetmask(int sigmask)
  434. {
  435.     BOOL oldAllowBreak = AllowBreak;
  436.     int result = 0;
  437.  
  438.     ENTER();
  439.  
  440.     SHOWVALUE(sigmask);
  441.  
  442.     AllowBreak = FLAG_IS_CLEAR(sigmask,(1<<SIGINT));
  443.     if(oldAllowBreak != AllowBreak)
  444.     {
  445.         ULONG mask;
  446.  
  447.         if(AllowBreak)
  448.             mask = SIGBREAKF_CTRL_C;
  449.         else
  450.             mask = NO_FLAG;
  451.  
  452.         SocketBaseTags(
  453.             SBTM_SETVAL(SBTC_BREAKMASK),mask,
  454.         TAG_END);
  455.     }
  456.  
  457.     RETURN(result);
  458.     return(result);
  459. }
  460.  
  461. /******************************************************************************/
  462.  
  463. STATIC VOID
  464. ReportProblem(const char *fmt,...)
  465. {
  466.     extern const STRPTR _ProgramName;
  467.     BOOL useRequester = TRUE;
  468.     va_list varArgs;
  469.  
  470.     ASSERT(fmt != NULL);
  471.  
  472.     va_start(varArgs,fmt);
  473.  
  474.     /* Launched from Workbench? */
  475.     if(WBenchMsg == NULL)
  476.     {
  477.         if(DOSBase->lib_Version >= 37)
  478.         {
  479.             BPTR stream;
  480.  
  481.             /* Make a copy of the current terminal
  482.              * output stream. This avoids sending
  483.              * an error message through a redirected
  484.              * standard output stream, the output
  485.              * will go straight to the terminal.
  486.              */
  487.             stream = Open("CONSOLE:",MODE_NEWFILE);
  488.             if(stream != ZERO)
  489.             {
  490.                 struct FileHandle * fh = BADDR(stream);
  491.  
  492.                 /* Check if the output was redirected
  493.                  * to "NIL:"; if not, print the error
  494.                  * error message.
  495.                  */
  496.                 if(fh->fh_Type != NULL)
  497.                 {
  498.                     FPrintf(stream,"%s: ",_ProgramName);
  499.                     VFPrintf(stream,(STRPTR)fmt,(APTR)varArgs);
  500.                     FPrintf(stream,"\a\n");
  501.  
  502.                     useRequester = FALSE;
  503.                 }
  504.  
  505.                 Close(stream);
  506.             }
  507.         }
  508.     }
  509.  
  510.     /* Oh well, don't use the Shell for output. Put up a
  511.      * requester.
  512.      */
  513.     if(useRequester)
  514.     {
  515.         struct Library * IntuitionBase;
  516.  
  517.         IntuitionBase = OpenLibrary("intuition.library",37);
  518.         if(IntuitionBase != NULL)
  519.         {
  520.             struct Window * reqWindow;
  521.             struct EasyStruct es;
  522.             char title[100];
  523.  
  524.             snprintf(title,sizeof(title)-1,"Amiga Samba Error (%s)",FilePart(_ProgramName));
  525.             title[sizeof(title)-1] = '\0';
  526.  
  527.             memset(&es,0,sizeof(es));
  528.  
  529.             es.es_StructSize    = sizeof(es);
  530.             es.es_Title            = (STRPTR)title;
  531.             es.es_TextFormat    = (STRPTR)fmt;
  532.             es.es_GadgetFormat    = "Ok";
  533.  
  534.             reqWindow = BuildEasyRequestArgs(NULL,&es,0,(APTR)varArgs);
  535.             if(reqWindow != NULL)
  536.             {
  537.                 struct timerequest * timeRequest = NULL;
  538.                 struct MsgPort * timePort;
  539.                 BOOL timerOpen = FALSE;
  540.                 ULONG windowSignal;
  541.                 ULONG timerSignal;
  542.                 ULONG signals;
  543.                 BOOL done;
  544.  
  545.                 timePort = CreateMsgPort();
  546.                 if(timePort != NULL)
  547.                 {
  548.                     timeRequest = CreateIORequest(timePort,sizeof(*timeRequest));
  549.                     if(timeRequest != NULL)
  550.                     {
  551.                         if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timeRequest,0) == OK)
  552.                             timerOpen = TRUE;
  553.                     }
  554.                 }
  555.  
  556.                 windowSignal = (1UL << reqWindow->UserPort->mp_SigBit);
  557.  
  558.                 if(timerOpen)
  559.                 {
  560.                     timerSignal = (1UL << timePort->mp_SigBit);
  561.  
  562.                     timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  563.                     timeRequest->tr_time.tv_secs    = 30;
  564.                     timeRequest->tr_time.tv_micro    = 0;
  565.  
  566.                     SendIO((struct IORequest *)timeRequest);
  567.                 }
  568.                 else
  569.                 {
  570.                     timerSignal = 0;
  571.                 }
  572.  
  573.                 DisplayBeep(reqWindow->WScreen);
  574.  
  575.                 done = FALSE;
  576.                 do
  577.                 {
  578.                     signals = Wait(windowSignal | timerSignal);
  579.  
  580.                     if(FLAG_IS_SET(signals,windowSignal))
  581.                     {
  582.                         if(SysReqHandler(reqWindow,NULL,FALSE) >= 0)
  583.                             done = TRUE;
  584.                     }
  585.  
  586.                     if(FLAG_IS_SET(signals,timerSignal))
  587.                     {
  588.                         done = TRUE;
  589.                     }
  590.                 }
  591.                 while(NOT done);
  592.  
  593.                 if(timerOpen)
  594.                 {
  595.                     if(CheckIO((struct IORequest *)timeRequest) == BUSY)
  596.                         AbortIO((struct IORequest *)timeRequest);
  597.  
  598.                     WaitIO((struct IORequest *)timeRequest);
  599.  
  600.                     CloseDevice((struct IORequest *)timeRequest);
  601.                 }
  602.  
  603.                 DeleteIORequest((struct IORequest *)timeRequest);
  604.                 DeleteMsgPort(timePort);
  605.  
  606.                 FreeSysRequest(reqWindow);
  607.             }
  608.  
  609.             CloseLibrary(IntuitionBase);
  610.         }
  611.     }
  612.  
  613.     va_end(varArgs);
  614. }
  615.  
  616. /******************************************************************************/
  617.  
  618. STATIC APTR OldWindowPtr;
  619. STATIC LONG ForbidCount;
  620.  
  621. STATIC VOID
  622. ForbidDOSCleanup(VOID)
  623. {
  624.     if(ForbidCount > 0)
  625.     {
  626.         struct Process * pr = (struct Process *)FindTask(NULL);
  627.  
  628.         pr->pr_WindowPtr = OldWindowPtr;
  629.  
  630.         ForbidCount = 0;
  631.     }
  632. }
  633.  
  634. STATIC VOID
  635. PermitDOS(VOID)
  636. {
  637.     ASSERT(ForbidCount > 0);
  638.  
  639.     if(--ForbidCount == 0)
  640.     {
  641.         struct Process * pr = (struct Process *)FindTask(NULL);
  642.  
  643.         pr->pr_WindowPtr = OldWindowPtr;
  644.     }
  645. }
  646.  
  647. STATIC VOID
  648. ForbidDOS(VOID)
  649. {
  650.     if(ForbidCount++ == 0)
  651.     {
  652.         struct Process * pr = (struct Process *)FindTask(NULL);
  653.  
  654.         OldWindowPtr = pr->pr_WindowPtr;
  655.         pr->pr_WindowPtr = (APTR)-1;
  656.     }
  657. }
  658.  
  659. /******************************************************************************/
  660.  
  661. #define SINGLE_CHARACTER_MODE    (1)
  662. #define BUFFERED_MODE            (0)
  663.  
  664. STATIC int MaxNonblockingDescriptor = -1;
  665.  
  666. STATIC VOID
  667. UnblockDescriptorCleanup(VOID)
  668. {
  669.     struct UFB * ufb;
  670.     int fd;
  671.  
  672.     /* We look for descriptors we switched into
  673.      * non-blocking mode and reset them back
  674.      * to blocking mode.
  675.      */
  676.     for(fd = 0 ; fd <= MaxNonblockingDescriptor ; fd++)
  677.     {
  678.         ufb = chkufb(fd);
  679.         if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  680.         {
  681.             SetMode((BPTR)ufb->ufbfh,BUFFERED_MODE);
  682.  
  683.             CLEAR_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  684.         }
  685.     }
  686. }
  687.  
  688. STATIC BOOL
  689. IsDescriptorNonblocking(int fd)
  690. {
  691.     struct UFB * ufb;
  692.     BOOL result = FALSE;
  693.  
  694.     /* Verify if a descriptor was switched into non-blocking mode. */
  695.     ufb = chkufb(fd);
  696.     if(ufb != NULL)
  697.         result = FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  698.  
  699.     return(result);
  700. }
  701.  
  702. STATIC VOID
  703. BlockDescriptor(int fd)
  704. {
  705.     struct UFB * ufb;
  706.  
  707.     /* This resets a file descriptor to blocking mode,
  708.      * once it has been set to blocking mode.
  709.      */
  710.     ufb = chkufb(fd);
  711.     if(ufb != NULL)
  712.     {
  713.         if(FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  714.         {
  715.             SetMode((BPTR)ufb->ufbfh,BUFFERED_MODE);
  716.  
  717.             CLEAR_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  718.         }
  719.     }
  720. }
  721.  
  722. STATIC VOID
  723. UnblockDescriptor(int fd)
  724. {
  725.     struct UFB * ufb;
  726.  
  727.     ufb = chkufb(fd);
  728.     if(ufb != NULL)
  729.     {
  730.         /* Make sure we got a file and it's not already
  731.          * in non-blocking mode.
  732.          */
  733.         if(FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET) && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  734.         {
  735.             /* Try to flip it into single character mode,
  736.              * which we treat as "non-blocking" mode.
  737.              */
  738.             if(SetMode((BPTR)ufb->ufbfh,SINGLE_CHARACTER_MODE))
  739.             {
  740.                 SET_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  741.  
  742.                 /* Remember which one we switched. */
  743.                 if(MaxNonblockingDescriptor < fd)
  744.                     MaxNonblockingDescriptor = fd;
  745.             }
  746.         }
  747.     }
  748. }
  749.  
  750. /******************************************************************************/
  751.  
  752. struct SavedDescriptorNode
  753. {
  754.     struct MinNode    sdn_MinNode;
  755.     struct UFB *    sdn_UFB;
  756.     BPTR            sdn_FileHandle;
  757. };
  758.  
  759. STATIC BOOL DescriptorListInitialized = FALSE;
  760. STATIC struct List DescriptorList;
  761.  
  762. STATIC VOID
  763. SaveDescriptorCleanup(VOID)
  764. {
  765.     /* This routine restores all file descriptors
  766.      * we used to map to sockets to use proper file
  767.      * handles.
  768.      */
  769.     if(DescriptorListInitialized)
  770.     {
  771.         struct SavedDescriptorNode * sdn;
  772.  
  773.         for(sdn = (struct SavedDescriptorNode *)DescriptorList.lh_Head ;
  774.             sdn->sdn_MinNode.mln_Succ != NULL ;
  775.             sdn = (struct SavedDescriptorNode *)sdn->sdn_MinNode.mln_Succ)
  776.         {
  777.             /* Make sure that if this file is bound to
  778.              * a socket, the socket is closed.
  779.              */
  780.             if(FLAG_IS_SET(sdn->sdn_UFB->ufbflg,UFB_IS_SOCKET))
  781.             {
  782.                 CloseSocket(sdn->sdn_UFB->ufbfh);
  783.  
  784.                 CLEAR_FLAG(sdn->sdn_UFB->ufbflg,UFB_IS_SOCKET);
  785.             }
  786.  
  787.             sdn->sdn_UFB->ufbfh = sdn->sdn_FileHandle;
  788.         }
  789.     }
  790. }
  791.  
  792. STATIC VOID
  793. RestoreDescriptor(struct UFB * ufb)
  794. {
  795.     ASSERT(ufb != NULL);
  796.  
  797.     /* This routine restores one particular file descriptor
  798.      * which was used as a socket to refer to a proper
  799.      * file handle.
  800.      */
  801.     if(DescriptorListInitialized)
  802.     {
  803.         struct SavedDescriptorNode * sdn;
  804.  
  805.         for(sdn = (struct SavedDescriptorNode *)DescriptorList.lh_Head ;
  806.             sdn->sdn_MinNode.mln_Succ != NULL ;
  807.             sdn = (struct SavedDescriptorNode *)sdn->sdn_MinNode.mln_Succ)
  808.         {
  809.             if(sdn->sdn_UFB == ufb)
  810.             {
  811.                 sdn->sdn_UFB->ufbfh = sdn->sdn_FileHandle;
  812.  
  813.                 Remove((struct Node *)sdn);
  814.                 free(sdn);
  815.  
  816.                 break;
  817.             }
  818.         }
  819.     }
  820. }
  821.  
  822. STATIC BOOL
  823. SaveDescriptor(struct UFB * ufb)
  824. {
  825.     struct SavedDescriptorNode * sdn;
  826.     BOOL result = FALSE;
  827.  
  828.     ASSERT(ufb != NULL);
  829.  
  830.     /* Set up the descriptor list, unless it's already
  831.      * initialized.
  832.      */
  833.     if(NOT DescriptorListInitialized)
  834.     {
  835.         NewList(&DescriptorList);
  836.         DescriptorListInitialized = TRUE;
  837.     }
  838.  
  839.     sdn = malloc(sizeof(*sdn));
  840.     if(sdn != NULL)
  841.     {
  842.         memset(sdn,0,sizeof(*sdn));
  843.  
  844.         /* Remember the file buffer and the file
  845.          * handle attached to the descriptor.
  846.          */
  847.         sdn->sdn_UFB        = ufb;
  848.         sdn->sdn_FileHandle    = ufb->ufbfh;
  849.  
  850.         AddHead(&DescriptorList,(struct Node *)sdn);
  851.  
  852.         result = TRUE;
  853.     }
  854.  
  855.     return(result);
  856. }
  857.  
  858. /******************************************************************************/
  859.  
  860. STATIC BOOL InitialCurrentDirInitialized = FALSE;
  861. STATIC BPTR InitialCurrentDir;
  862. STATIC BPTR ChangedCurrentDir;
  863.  
  864. CBMLIB_DESTRUCTOR(CloseLibsAndDevs)
  865. {
  866.     ENTER();
  867.  
  868.     /* Return to the directory we were in
  869.      * when we started.
  870.      */
  871.     if(InitialCurrentDirInitialized)
  872.     {
  873.         CurrentDir(InitialCurrentDir);
  874.         InitialCurrentDirInitialized = FALSE;
  875.     }
  876.  
  877.     /* If the current directory was changed, unlock it. */
  878.     if(ChangedCurrentDir != ZERO)
  879.     {
  880.         UnLock(ChangedCurrentDir);
  881.         ChangedCurrentDir = ZERO;
  882.     }
  883.  
  884.     CleanupSambaSemaphore();
  885.  
  886.     if(TimerRequest != NULL)
  887.     {
  888.         if(TimerRequest->tr_node.io_Device != NULL)
  889.             CloseDevice((struct IORequest *)TimerRequest);
  890.  
  891.         DeleteIORequest((struct IORequest *)TimerRequest);
  892.         TimerRequest = NULL;
  893.     }
  894.  
  895.     if(TimerPort != NULL)
  896.     {
  897.         DeleteMsgPort(TimerPort);
  898.         TimerPort = NULL;
  899.     }
  900.  
  901.     TimerBase = NULL;
  902.  
  903.     if(SocketBase != NULL)
  904.     {
  905.         CloseLibrary(SocketBase);
  906.         SocketBase = NULL;
  907.     }
  908.  
  909.     if(UserGroupBase != NULL)
  910.     {
  911.         CloseLibrary(UserGroupBase);
  912.         UserGroupBase = NULL;
  913.     }
  914.  
  915.     LEAVE();
  916. }
  917.  
  918. CBMLIB_CONSTRUCTOR(OpenLibsAndDevs)
  919. {
  920.     extern STRPTR _ProgramName;
  921.     BOOL sambaSemaphoreCreated;
  922.     struct LocaleBase * LocaleBase;
  923.     char *timerError = "";
  924.     BPTR sambaLock;
  925.     int result = ERROR;
  926.  
  927.     SETPROGRAMNAME(_ProgramName);
  928.     SETDEBUGLEVEL(0);
  929.  
  930.     ENTER();
  931.  
  932.     SocketBase = OpenLibrary("bsdsocket.library",4);
  933.     UserGroupBase = OpenLibrary("usergroup.library",1);
  934.  
  935.     if(SysBase->lib_Version >= 37)
  936.     {
  937.         TimerPort = CreateMsgPort();
  938.         if(TimerPort != NULL)
  939.         {
  940.             TimerRequest = (struct timerequest *)CreateIORequest(TimerPort,sizeof(*TimerRequest));
  941.             if(TimerRequest != NULL)
  942.             {
  943.                 if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerRequest,NULL) == OK)
  944.                     TimerBase = TimerRequest->tr_node.io_Device;
  945.                 else
  946.                     timerError = "opening \"timer.device\"";
  947.             }
  948.             else
  949.             {
  950.                 timerError = "creating timer I/O request";
  951.             }
  952.         }
  953.         else
  954.         {
  955.             timerError = "creating timer message port";
  956.         }
  957.     }
  958.  
  959.     /* Try to determine this machine's time zone. */
  960.     LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38);
  961.     if(LocaleBase != NULL)
  962.     {
  963.         struct Locale * locale;
  964.  
  965.         locale = OpenLocale(NULL);
  966.         MinutesWest = locale->loc_GMTOffset;
  967.         CloseLocale(locale);
  968.  
  969.         CloseLibrary((struct Library *)LocaleBase);
  970.     }
  971.  
  972.     ForbidDOS();
  973.  
  974.     /* Try to get a lock on the "Samba:" directory,
  975.      * just to make sure the assignment is in place.
  976.      */
  977.     sambaLock = Lock("Samba:",SHARED_LOCK);
  978.     if(sambaLock != ZERO)
  979.         UnLock(sambaLock);
  980.  
  981.     PermitDOS();
  982.  
  983.     /* Initialize the global process ID database. */
  984.     sambaSemaphoreCreated = SetupSambaSemaphore();
  985.  
  986.     if(SocketBase != NULL && UserGroupBase != NULL && TimerBase != NULL &&
  987.        sambaLock != ZERO && sambaSemaphoreCreated)
  988.     {
  989.         STATIC long h_errno = 0;
  990.         struct timeval now;
  991.         int error;
  992.  
  993.         error = SocketBaseTags(
  994.             SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))),    &errno,
  995.             SBTM_SETVAL(SBTC_HERRNOLONGPTR),            &h_errno,
  996.             SBTM_SETVAL(SBTC_LOGTAGPTR),                _ProgramName,
  997.             SBTM_SETVAL(SBTC_BREAKMASK),                SIGBREAKF_CTRL_C,
  998.         TAG_END);
  999.         if(error != OK)
  1000.         {
  1001.             ReportProblem("Error initializing socket data (error=%ld).",error);
  1002.             goto out;
  1003.         }
  1004.  
  1005.         error = ug_SetupContextTags(_ProgramName,
  1006.             UGT_ERRNOPTR(sizeof(errno)),&errno,
  1007.         TAG_END);
  1008.         if(error != OK)
  1009.         {
  1010.             ReportProblem("Error initializing user group data (error=%ld).",error);
  1011.             goto out;
  1012.         }
  1013.  
  1014.         /* Use a new random number seed. */
  1015.         GetSysTime((APTR)&now);
  1016.         srand(now.tv_secs);
  1017.     }
  1018.     else
  1019.     {
  1020.         if(SocketBase == NULL)
  1021.             ReportProblem("Error opening \"bsdsocket.library\" V4.");
  1022.         else if (UserGroupBase == NULL)
  1023.             ReportProblem("Error opening \"usergroup.library\" V1.");
  1024.         else if (TimerBase == NULL)
  1025.             ReportProblem("Error %s.",timerError);
  1026.         else if (sambaLock == ZERO)
  1027.             ReportProblem("Error finding \"Samba:\" assignment.");
  1028.         else if (NOT sambaSemaphoreCreated)
  1029.             ReportProblem("Error creating Samba semaphore.");
  1030.  
  1031.         goto out;
  1032.     }
  1033.  
  1034.     /* Initialize the current time zone variable. */
  1035.     __tzset();
  1036.  
  1037.     result = OK;
  1038.  
  1039. out:
  1040.  
  1041.     RETURN(result);
  1042.     return(result);
  1043. }
  1044.  
  1045. /******************************************************************************/
  1046.  
  1047. DESTRUCTOR_P(SocketExit,501)
  1048. {
  1049.     ENTER();
  1050.  
  1051.     SaveDescriptorCleanup();
  1052.     UnblockDescriptorCleanup();
  1053.     CloseUnlinkUnlockCleanup();
  1054.     ForbidDOSCleanup();
  1055.  
  1056.     LEAVE();
  1057. }
  1058.  
  1059. /******************************************************************************/
  1060.  
  1061. CONSTRUCTOR_P(DaemonInit,501)
  1062. {
  1063.     ENTER();
  1064.  
  1065.     DaemonInit();
  1066.  
  1067.     RETURN(0);
  1068.     return(0);
  1069. }
  1070.  
  1071. /******************************************************************************/
  1072.  
  1073. struct MangleInfo
  1074. {
  1075.     char    mi_Substitute[MAX_FILENAME_LEN];
  1076.     char *    mi_OldName;
  1077. };
  1078.  
  1079. STATIC VOID
  1080. UnmangleName(char ** namePtr,struct MangleInfo * mi)
  1081. {
  1082.     /* Reset the name pointer to its previous position. */
  1083.     (*namePtr) = mi->mi_OldName;
  1084. }
  1085.  
  1086. STATIC int
  1087. MangleName(char ** namePtr,struct MangleInfo * mi)
  1088. {
  1089.     char * name = (*namePtr);
  1090.     int result = ERROR;
  1091.  
  1092.     ENTER();
  1093.  
  1094.     if(TranslateRelativePath(&name,mi->mi_Substitute,sizeof(mi->mi_Substitute)) == OK)
  1095.     {
  1096.         char * replace = mi->mi_Substitute;
  1097.         int len,i;
  1098.  
  1099.         len = strlen(name);
  1100.  
  1101.         /* If there is one, strip the trailing slash. */
  1102.         if(len > 1 && name[len-1] == '/')
  1103.         {
  1104.             if(name != replace)
  1105.             {
  1106.                 strcpy(replace,name);
  1107.                 name = replace;
  1108.             }
  1109.  
  1110.             name[--len] = '\0';
  1111.         }
  1112.  
  1113.         if(strcmp(name,".") == SAME)
  1114.         {
  1115.             /* Convert to current directory. */
  1116.             name = "";
  1117.         }
  1118.         else if (strcmp(name,"..") == SAME)
  1119.         {
  1120.             /* Convert to parent directory. */
  1121.             name = "/";
  1122.         }
  1123.         else if (strncmp(name,"./",2) == SAME)
  1124.         {
  1125.             /* Retain just the name. */
  1126.             name += 2;
  1127.         }
  1128.         else if (strncmp(name,"../",3) == SAME)
  1129.         {
  1130.             /* Convert to parent directory. */
  1131.             name += 2;
  1132.         }
  1133.         else if (strncmp(name,"/",1) == SAME)
  1134.         {
  1135.             /* Ok, so this is an absolute path. We first
  1136.              * check for a few special cases, the first
  1137.              * being a reference to "/tmp".
  1138.              */
  1139.             if(Strnicmp(name,"/tmp",4) == SAME && (name[4] == '/' || name[4] == '\0'))
  1140.             {
  1141.                 if(name[4] == '/')
  1142.                 {
  1143.                     /* Convert "/tmp/foo" to "T:foo". */
  1144.                     strcpy(replace,"T:");
  1145.                     memmove(&replace[2],&name[5],strlen(&name[5])+1);
  1146.                 }
  1147.                 else
  1148.                 {
  1149.                     /* Convert "/tmp" to "T:". */
  1150.                     strcpy(replace,"T:");
  1151.                 }
  1152.  
  1153.                 name = replace;
  1154.             }
  1155.             else if(Strnicmp(name,"/dev/",5) == SAME)
  1156.             {
  1157.                 /* Except for "/dev/null" all references to
  1158.                  * files in "/dev" are redirected to nonexistant
  1159.                  * files. Note that this relies upon the fact
  1160.                  * that "NIL:" is not a true device.
  1161.                  */
  1162.                 if(Stricmp(name,"/dev/null") == SAME)
  1163.                     name = "NIL:";
  1164.                 else
  1165.                     name = "NIL:this_file_never_opens";
  1166.             }
  1167.             else
  1168.             {
  1169.                 int i,rest = 0,len = 0;
  1170.  
  1171.                 /* Find out how long the first component
  1172.                  * of the absolute path is.
  1173.                  */
  1174.                 for(i = 1 ; i <= strlen(name) ; i++)
  1175.                 {
  1176.                     if(name[i] == '/' || name[i] == '\0')
  1177.                     {
  1178.                         len = i-1;
  1179.  
  1180.                         /* Is there anything following
  1181.                          * the path name?
  1182.                          */
  1183.                         if(name[i] == '/')
  1184.                             rest = i+1;
  1185.  
  1186.                         break;
  1187.                     }
  1188.                 }
  1189.  
  1190.                 /* Copy the first component and
  1191.                  * attach a colon. "/foo" becomes
  1192.                  * "foo:" (without the trailing NUL
  1193.                  * byte, this will get attached
  1194.                  * later).
  1195.                  */
  1196.                 memmove(replace,&name[1],len);
  1197.                 replace[len++] = ':';
  1198.  
  1199.                 /* Now add the finishing touches. "/foo/bar" finally
  1200.                  * becomes "foo:bar" and "/foo" becomes "foo:" with the
  1201.                  * trailing NUL byte attached.
  1202.                  */
  1203.                 if(rest > 0)
  1204.                     memmove(&replace[len],&name[rest],strlen(&name[rest])+1);
  1205.                 else
  1206.                     replace[len] = '\0';
  1207.  
  1208.                 name = replace;
  1209.             }
  1210.         }
  1211.  
  1212.         /* Convert any "./" or "../" embedded in the name
  1213.          * if necessary.
  1214.          */
  1215.         for(i = 0 ; i < strlen(name) ; i++)
  1216.         {
  1217.             if(strncmp(&name[i],"./",2) == SAME ||
  1218.                strncmp(&name[i],"../",3) == SAME)
  1219.             {
  1220.                 char * from    = name;
  1221.                 char * to    = replace;
  1222.  
  1223.                 name = replace;
  1224.  
  1225.                 while((*from) != '\0')
  1226.                 {
  1227.                     if((*from) == '.')
  1228.                     {
  1229.                         if(from[1] == '/' || from[1] == '\0')
  1230.                         {
  1231.                             /* "."  -> "" (done)
  1232.                              * "./" -> "" (continue)
  1233.                              */
  1234.                             if(from[1] == '\0')
  1235.                                 break;
  1236.                             else
  1237.                                 from += 2;
  1238.                         }
  1239.                         else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0'))
  1240.                         {
  1241.                             /* ".."  -> "/" (done)
  1242.                              * "../" -> "/" (continue)
  1243.                              */
  1244.                             (*to++) = '/';
  1245.  
  1246.                             if(from[2] == '\0')
  1247.                                 break;
  1248.                             else
  1249.                                 from += 3;
  1250.                         }
  1251.                         else
  1252.                         {
  1253.                             (*to++) = (*from++);
  1254.                         }
  1255.                     }
  1256.                     else
  1257.                     {
  1258.                         (*to++) = (*from++);
  1259.                     }
  1260.                 }
  1261.  
  1262.                 (*to) = '\0';
  1263.  
  1264.                 break;
  1265.             }
  1266.         }
  1267.  
  1268.         /* Reduce any "//" embedded in the name if
  1269.          * necessary.
  1270.          */
  1271.         for(i = 0 ; i < strlen(name)-1 ; i++)
  1272.         {
  1273.             if(name[i] == '/' && name[i+1] == '/')
  1274.             {
  1275.                 int position,len;
  1276.  
  1277.                 if(name != replace)
  1278.                 {
  1279.                     strcpy(replace,name);
  1280.                     name = replace;
  1281.                 }
  1282.  
  1283.                 len = strlen(name);
  1284.  
  1285.                 position = len - 1;
  1286.                 while(position > 1 && name[position] != ':')
  1287.                 {
  1288.                     /* "foo/bar//baz" -> "foo/baz" */
  1289.                     if(name[position] == '/' && name[position-1] == '/')
  1290.                     {
  1291.                         int componentLen;
  1292.  
  1293.                         /* Move in front of the name component preceding the "//". */
  1294.                         componentLen = 0;
  1295.                         for(i = position - 2 ; i > 0 && name[i] != ':' && name[i] != '/' ; i--)
  1296.                             componentLen++;
  1297.  
  1298.                         if(componentLen > 0)
  1299.                         {
  1300.                             memmove(&name[position - (componentLen + 1)],&name[position + 1],len - (position + 1));
  1301.  
  1302.                             len -= componentLen + 2;
  1303.                             name[len] = '\0';
  1304.  
  1305.                             position -= componentLen + 1;
  1306.                         }
  1307.                     }
  1308.  
  1309.                     position--;
  1310.                 }
  1311.  
  1312.                 break;
  1313.             }
  1314.         }
  1315.  
  1316.         D(("original name |%s|",(*namePtr)));
  1317.         D((" mangled name |%s|",name));
  1318.  
  1319.         /* Look for extra colon characters
  1320.          * embedded in the name (as in "foo:bar:baz"
  1321.          * or "foo/bar:baz") which really don't
  1322.          * belong here.
  1323.          */
  1324.         len = strlen(name);
  1325.         for(i = 0 ; i < len ; i++)
  1326.         {
  1327.             if(name[i] == ':' || name[i] == '/')
  1328.             {
  1329.                 int j;
  1330.  
  1331.                 for(j = i+1 ; j < len ; j++)
  1332.                 {
  1333.                     if(name[j] == ':')
  1334.                     {
  1335.                         errno = EINVAL; /* invalid name */
  1336.                         goto out;
  1337.                     }
  1338.                 }
  1339.  
  1340.                 break;
  1341.             }
  1342.         }
  1343.  
  1344.         /* Now check if the file name is longer than the
  1345.          * maximum supported by the ROM file system. This
  1346.          * is to avoid name space clashes.
  1347.          */
  1348.         if(strlen(FilePart((STRPTR)name)) > MAX_FFS_NAME_LEN)
  1349.         {
  1350.             LONG error = OK;
  1351.             BPTR fileLock;
  1352.  
  1353.             /* This is a tricky issue: the filing system we are talking
  1354.              * to may be able to handle more than 30 characters, but then
  1355.              * it may be not, it's impossible to tell. We adopt the following
  1356.              * strategy: we try to access the named file and compare its
  1357.              * name against the one reported by the file system. If the name
  1358.              * reported by the file system is shorter than the one provided,
  1359.              * but matches it otherwise, we will assume that trouble is underway
  1360.              * and back out backwards.
  1361.              */
  1362.  
  1363.             ForbidDOS();
  1364.  
  1365.             fileLock = Lock((STRPTR)name,SHARED_LOCK);
  1366.             if(fileLock != ZERO)
  1367.             {
  1368.                 struct FileInfoBlock __aligned fib;
  1369.  
  1370.                 if(Examine(fileLock,&fib))
  1371.                 {
  1372.                     STRPTR file_name = FilePart((STRPTR)name);
  1373.                     int len;
  1374.  
  1375.                     /* Now check if the name reported by the
  1376.                      * filing system is shorter than the
  1377.                      * one we asked for, but matches otherwise.
  1378.                      */
  1379.                     len = strlen(fib.fib_FileName);
  1380.                     if(strlen(file_name) > len && Strnicmp(file_name,fib.fib_FileName,len) == SAME)
  1381.                     {
  1382.                         /* The name is too long to handle. */
  1383.                         error = ERROR_LINE_TOO_LONG;
  1384.                     }
  1385.                 }
  1386.                 else
  1387.                 {
  1388.                     error = IoErr();
  1389.                 }
  1390.  
  1391.                 UnLock(fileLock);
  1392.             }
  1393.             else
  1394.             {
  1395.                 error = IoErr();
  1396.             }
  1397.  
  1398.             PermitDOS();
  1399.  
  1400.             /* We don't complain if the file does
  1401.              * not exist, but if it is currently in
  1402.              * use, on a volume that's not currently
  1403.              * mounted, etc. we will complain.
  1404.              */
  1405.             if(error != OK && error != ERROR_OBJECT_NOT_FOUND)
  1406.             {
  1407.                 SetIoErr(error);
  1408.                 MapIoErrToErrno();
  1409.  
  1410.                 goto out;
  1411.             }
  1412.         }
  1413.  
  1414.         mi->mi_OldName = (*namePtr);
  1415.         (*namePtr) = name;
  1416.  
  1417.         result = OK;
  1418.     }
  1419.  
  1420. out:
  1421.  
  1422.     RETURN(result);
  1423.     return(result);
  1424. }
  1425.  
  1426. /******************************************************************************/
  1427.  
  1428. STATIC int MaxOpenDescriptor = -1;
  1429.  
  1430. STATIC VOID
  1431. CloseUnlinkUnlockCleanup(VOID)
  1432. {
  1433.     struct UFB * ufb;
  1434.     int fd;
  1435.  
  1436.     ForbidDOS();
  1437.  
  1438.     /* Don't let anybody stop us. */
  1439.     signal(SIGINT,SIG_IGN);
  1440.     signal(SIGTERM,SIG_IGN);
  1441.  
  1442.     /* We look for descriptors we marked for
  1443.      * deletion.
  1444.      */
  1445.     for(fd = 0 ; fd <= MaxOpenDescriptor ; fd++)
  1446.     {
  1447.         CleanupFileLocks(fd);
  1448.  
  1449.         ufb = chkufb(fd);
  1450.         if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_UNLINK))
  1451.         {
  1452.             char fileName[MAX_FILENAME_LEN];
  1453.             BOOL removeIt;
  1454.  
  1455.             removeIt = NameFromFH((BPTR)ufb->ufbfh,fileName,sizeof(fileName));
  1456.  
  1457.             CLEAR_FLAG(ufb->ufbflg,UFB_UNLINK);
  1458.  
  1459.             close(fd);
  1460.  
  1461.             if(removeIt)
  1462.                 DeleteFile(fileName);
  1463.         }
  1464.     }
  1465.  
  1466.     PermitDOS();
  1467. }
  1468.  
  1469. int
  1470. amiga_unlink(char *name)
  1471. {
  1472.     struct MangleInfo mi;
  1473.     BPTR fileLock;
  1474.     int result = ERROR;
  1475.  
  1476.     chkabort();
  1477.  
  1478.     ASSERT(name != NULL);
  1479.  
  1480.     ENTER();
  1481.     SHOWSTRING(name);
  1482.  
  1483.     if(MangleName(&name,&mi) == OK)
  1484.     {
  1485.         LONG error = OK;
  1486.  
  1487.         ForbidDOS();
  1488.  
  1489.         fileLock = Lock(name,SHARED_LOCK);
  1490.         if(fileLock != ZERO)
  1491.         {
  1492.             struct FileInfoBlock __aligned fib;
  1493.  
  1494.             if(Examine(fileLock,&fib))
  1495.             {
  1496.                 UnLock(fileLock);
  1497.                 fileLock = ZERO;
  1498.  
  1499.                 /* Make sure that we get to remove
  1500.                  * a file, as the name implies.
  1501.                  */
  1502.                 if(FIB_IS_FILE(&fib))
  1503.                 {
  1504.                     if(DeleteFile(name))
  1505.                         result = OK;
  1506.                     else
  1507.                         error = IoErr();
  1508.                 }
  1509.                 else
  1510.                 {
  1511.                     errno = EISDIR;
  1512.                 }
  1513.             }
  1514.             else
  1515.             {
  1516.                 error = IoErr();
  1517.             }
  1518.  
  1519.             UnLock(fileLock);
  1520.         }
  1521.         else
  1522.         {
  1523.             error = IoErr();
  1524.         }
  1525.  
  1526.         PermitDOS();
  1527.  
  1528.         /* Check if we couldn't delete the file in
  1529.          * question because there still is a file
  1530.          * handle attached to it. If we can find that
  1531.          * file, we will mark it for deletion lateron
  1532.          * when the file is closed.
  1533.          */
  1534.         if(result != OK && error == ERROR_OBJECT_IN_USE)
  1535.         {
  1536.             char parentDirName[MAX_FILENAME_LEN];
  1537.             BOOL foundParentDirName;
  1538.             BPTR fileParentDir;
  1539.             int i;
  1540.  
  1541.             ASSERT(strlen(name) < sizeof(parentDirName));
  1542.  
  1543.             strcpy(parentDirName,name);
  1544.             foundParentDirName = FALSE;
  1545.  
  1546.             for(i = strlen(parentDirName)-1 ; i >= 0 ; i--)
  1547.             {
  1548.                 if(parentDirName[i] == ':')
  1549.                 {
  1550.                     if(parentDirName[i+1] != '\0')
  1551.                     {
  1552.                         parentDirName[i+1] = '\0';
  1553.                         foundParentDirName = TRUE;
  1554.                     }
  1555.  
  1556.                     break;
  1557.                 }
  1558.                 else if (parentDirName[i] == '/')
  1559.                 {
  1560.                     parentDirName[i] = '\0';
  1561.                     foundParentDirName = TRUE;
  1562.                     break;
  1563.                 }
  1564.             }
  1565.  
  1566.             /* Did we find this file's parent directory name? */
  1567.             if(foundParentDirName)
  1568.             {
  1569.                 D(("locking |%s|",parentDirName));
  1570.  
  1571.                 /* Get a lock on the file's parent directory. */
  1572.                 fileParentDir = Lock(parentDirName,SHARED_LOCK);
  1573.                 if(fileParentDir != ZERO)
  1574.                 {
  1575.                     BPTR descriptorParentDir;
  1576.                     BOOL gotIt = FALSE;
  1577.                     struct UFB * ufb;
  1578.                     int fd;
  1579.  
  1580.                     for(fd = 0 ; fd <= MaxOpenDescriptor ; fd++)
  1581.                     {
  1582.                         ufb = chkufb(fd);
  1583.                         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  1584.                         {
  1585.                             /* And also get a lock on the file
  1586.                              * descriptor's parent directory.
  1587.                              */
  1588.                             descriptorParentDir = ParentOfFH((BPTR)ufb->ufbfh);
  1589.                             if(descriptorParentDir != ZERO)
  1590.                             {
  1591.                                 /* Are the two pointing to the same drawer? */
  1592.                                 if(SameLock(fileParentDir,descriptorParentDir) == LOCK_SAME)
  1593.                                 {
  1594.                                     struct FileInfoBlock __aligned fib;
  1595.  
  1596.                                     if(ExamineFH((BPTR)ufb->ufbfh,&fib))
  1597.                                     {
  1598.                                         /* Check if the two share the same name. */
  1599.                                         if(Stricmp(fib.fib_FileName,FilePart(name)) == SAME)
  1600.                                         {
  1601.                                             /* Mark this file for deletion. */
  1602.                                             SET_FLAG(ufb->ufbflg,UFB_UNLINK);
  1603.  
  1604.                                             gotIt = TRUE;
  1605.                                             error = OK;
  1606.                                             result = OK;
  1607.                                         }
  1608.                                     }
  1609.                                     else
  1610.                                     {
  1611.                                         SHOWMSG("couldn't examine the descriptor");
  1612.                                     }
  1613.                                 }
  1614.                                 else
  1615.                                 {
  1616.                                     SHOWMSG("file and descriptor don't live in the same drawer");
  1617.                                 }
  1618.  
  1619.                                 UnLock(descriptorParentDir);
  1620.                             }
  1621.                             else
  1622.                             {
  1623.                                 SHOWMSG("the descriptor doesn't have a parent directory (huh?!?)");
  1624.                             }
  1625.                         }
  1626.  
  1627.                         if(gotIt)
  1628.                             break;
  1629.                     }
  1630.  
  1631.                     UnLock(fileParentDir);
  1632.                 }
  1633.                 else
  1634.                 {
  1635.                     D(("couldn't get a lock on |%s|",parentDirName));
  1636.                 }
  1637.             }
  1638.             else
  1639.             {
  1640.                 D(("didn't find parent dir name of |%s|",name));
  1641.             }
  1642.         }
  1643.  
  1644.         /* Take care of the AmigaDOS error
  1645.          * code, if there is any.
  1646.          */
  1647.         if(result != OK && error != OK)
  1648.         {
  1649.             SetIoErr(error);
  1650.             MapIoErrToErrno();
  1651.         }
  1652.  
  1653.         UnmangleName(&name,&mi);
  1654.     }
  1655.  
  1656.     RETURN(result);
  1657.     return(result);
  1658. }
  1659.  
  1660. int
  1661. amiga_open(char *name,int mode,int prot)
  1662. {
  1663.     struct MangleInfo mi;
  1664.     int result = ERROR;
  1665.  
  1666.     chkabort();
  1667.  
  1668.     ASSERT(name != NULL);
  1669.  
  1670.     ENTER();
  1671.     SHOWSTRING(name);
  1672.     SHOWVALUE(mode);
  1673.     SHOWVALUE(prot);
  1674.  
  1675.     if(MangleName(&name,&mi) == OK)
  1676.     {
  1677.         /* Clear the "no delay" flag since the SAS/C
  1678.          * runtime library does not support it.
  1679.          */
  1680.         CLEAR_FLAG(mode,O_NONBLOCK);
  1681.  
  1682.         ForbidDOS();
  1683.  
  1684.         result = open(name,mode,prot);
  1685.         if(result != ERROR && MaxOpenDescriptor < result)
  1686.             MaxOpenDescriptor = result;
  1687.  
  1688.         PermitDOS();
  1689.  
  1690.         UnmangleName(&name,&mi);
  1691.     }
  1692.  
  1693.     RETURN(result);
  1694.     return(result);
  1695. }
  1696.  
  1697. /******************************************************************************/
  1698.  
  1699. STATIC char CurrentDirName[MAX_FILENAME_LEN] = "";
  1700.  
  1701. int
  1702. amiga_chdir(char *path)
  1703. {
  1704.     BOOL isAbsolutePath;
  1705.     struct MangleInfo mi;
  1706.     int result = ERROR;
  1707.  
  1708.     chkabort();
  1709.  
  1710.     ASSERT(path != NULL);
  1711.  
  1712.     ENTER();
  1713.     SHOWSTRING(path);
  1714.  
  1715.     /* Is this an absolute path? */
  1716.     isAbsolutePath = (BOOL)(path[0] == '/');
  1717.  
  1718.     if(MangleName(&path,&mi) == OK)
  1719.     {
  1720.         BPTR drawerLock;
  1721.  
  1722.         D(("chdir(\"%s\")",path));
  1723.  
  1724.         ForbidDOS();
  1725.  
  1726.         drawerLock = Lock(path,SHARED_LOCK);
  1727.         if(drawerLock != ZERO)
  1728.         {
  1729.             struct FileInfoBlock __aligned fib;
  1730.  
  1731.             if(Examine(drawerLock,&fib))
  1732.             {
  1733.                 /* We can only move into drawers. */
  1734.                 if(FIB_IS_DRAWER(&fib))
  1735.                 {
  1736.                     /* If necessary, get the name of
  1737.                      * the drawer to move into.
  1738.                      */
  1739.                     if(NOT isAbsolutePath)
  1740.                     {
  1741.                         UBYTE localName[MAX_FILENAME_LEN];
  1742.  
  1743.                         if(NameFromLock(drawerLock,localName,sizeof(localName)))
  1744.                             result = MapFileNameAmigaToUnix(localName,CurrentDirName,sizeof(CurrentDirName));
  1745.                         else
  1746.                             MapIoErrToErrno();
  1747.                     }
  1748.                     else
  1749.                     {
  1750.                         result = OK;
  1751.                     }
  1752.  
  1753.                     /* If everything went well,
  1754.                      * move into the drawer.
  1755.                      */
  1756.                     if(result == OK)
  1757.                     {
  1758.                         BPTR oldDrawer;
  1759.  
  1760.                         oldDrawer = CurrentDir(drawerLock);
  1761.  
  1762.                         /* Unlock the old drawer we came from
  1763.                          * unless we want to return to it
  1764.                          * when the program exits.
  1765.                          */
  1766.                         if(InitialCurrentDirInitialized)
  1767.                         {
  1768.                             UnLock(oldDrawer);
  1769.                         }
  1770.                         else
  1771.                         {
  1772.                             InitialCurrentDir = oldDrawer;
  1773.                             InitialCurrentDirInitialized = TRUE;
  1774.                         }
  1775.  
  1776.                         /* Make sure that this drawer is going
  1777.                          * to be unlocked when the program exits.
  1778.                          */
  1779.                         ChangedCurrentDir = drawerLock;
  1780.                     }
  1781.                 }
  1782.                 else
  1783.                 {
  1784.                     errno = ENOTDIR;
  1785.                 }
  1786.             }
  1787.             else
  1788.             {
  1789.                 MapIoErrToErrno();
  1790.             }
  1791.  
  1792.             if(result != OK)
  1793.                 UnLock(drawerLock);
  1794.         }
  1795.         else
  1796.         {
  1797.             MapIoErrToErrno();
  1798.         }
  1799.  
  1800.         PermitDOS();
  1801.  
  1802.         UnmangleName(&path,&mi);
  1803.  
  1804.         if(result == OK && isAbsolutePath)
  1805.             strcpy(CurrentDirName,path);
  1806.     }
  1807.  
  1808.     RETURN(result);
  1809.     return(result);
  1810. }
  1811.  
  1812. /******************************************************************************/
  1813.  
  1814. struct OpenDirNode
  1815. {
  1816.     struct MinNode            odn_MinNode;
  1817.     BPTR                    odn_FileLock;
  1818.     struct FileInfoBlock    odn_FIB;
  1819.     struct List                odn_VolumeList;
  1820.     DIR                        odn_DIR;
  1821.     BOOL                    odn_ReadingVolumes;
  1822.     struct dirent            odn_DirectoryEntry;
  1823.     struct Node *            odn_NextNode;
  1824.     ULONG                    odn_NextDirEntryIndex;
  1825.     LONG                    odn_ParentDirKey;
  1826. };
  1827.  
  1828. STATIC struct List OpenDirList;
  1829. STATIC BOOL OpenDirListInitialized = FALSE;
  1830.  
  1831. STATIC ULONG RootBlocks = 0;
  1832. STATIC ULONG RootBlocksUsed = 0;
  1833.  
  1834. STATIC VOID
  1835. OpenDirCleanup(VOID)
  1836. {
  1837.     struct OpenDirNode * odn;
  1838.  
  1839.     /* Unlock all directories still being scanned
  1840.      * when exit() was called.
  1841.      */
  1842.     for(odn = (struct OpenDirNode *)OpenDirList.lh_Head ;
  1843.         odn->odn_MinNode.mln_Succ != NULL ;
  1844.         odn = (struct OpenDirNode *)odn->odn_MinNode.mln_Succ)
  1845.     {
  1846.         UnLock(odn->odn_FileLock);
  1847.     }
  1848. }
  1849.  
  1850. DIR *
  1851. amiga_opendir(char *dirName)
  1852. {
  1853.     char localDirName[MAX_FILENAME_LEN];
  1854.     DIR *result = NULL;
  1855.  
  1856.     chkabort();
  1857.  
  1858.     ASSERT(dirName != NULL);
  1859.  
  1860.     ENTER();
  1861.  
  1862.     SHOWSTRING(dirName);
  1863.  
  1864.     /* Make sure that the directory list is
  1865.      * set up properly.
  1866.      */
  1867.     if(NOT OpenDirListInitialized)
  1868.     {
  1869.         NewList(&OpenDirList);
  1870.         OpenDirListInitialized = TRUE;
  1871.         atexit(OpenDirCleanup);
  1872.     }
  1873.  
  1874.     if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  1875.     {
  1876.         /* Check if we are to scan the virtual root directory. */
  1877.         if(strcmp(dirName,"/") == SAME)
  1878.         {
  1879.             struct OpenDirNode * odn;
  1880.  
  1881.             odn = malloc(sizeof(*odn));
  1882.             if(odn != NULL)
  1883.             {
  1884.                 struct DosList * dol;
  1885.  
  1886.                 RootBlocks = RootBlocksUsed = 0;
  1887.  
  1888.                 memset(odn,0,sizeof(*odn));
  1889.                 odn->odn_ReadingVolumes = TRUE;
  1890.                 odn->odn_DIR.dd_buf = (char *)odn;
  1891.                 NewList(&odn->odn_VolumeList);
  1892.  
  1893.                 AddHead(&OpenDirList,(struct Node *)odn);
  1894.  
  1895.                 result = &odn->odn_DIR;
  1896.  
  1897.                 /* Now collect all volumes in the system. */
  1898.                 dol = NextDosEntry(LockDosList(LDF_VOLUMES|LDF_READ),
  1899.                                                LDF_VOLUMES|LDF_READ);
  1900.                 while(dol != NULL)
  1901.                 {
  1902.                     /* Does the volume refer to a medium that is right
  1903.                      * now present in the drive?
  1904.                      */
  1905.                     if(dol->dol_Task != NULL)
  1906.                     {
  1907.                         struct InfoData __aligned id;
  1908.  
  1909.                         /* Is there a disk present? */
  1910.                         if(DoPkt(dol->dol_Task,ACTION_DISK_INFO,MKBADDR(&id),    0,0,0,0))
  1911.                         {
  1912.                             STRPTR name = BADDR(dol->dol_Name);
  1913.                             struct Node * node;
  1914.  
  1915.                             /* Collect the number of blocks used and
  1916.                              * available in our fake root directory.
  1917.                              * Not that it matters much...
  1918.                              */
  1919.                             if(id.id_BytesPerBlock == 512)
  1920.                             {
  1921.                                 RootBlocks        += id.id_NumBlocks;
  1922.                                 RootBlocksUsed    += id.id_NumBlocksUsed;
  1923.                             }
  1924.                             else
  1925.                             {
  1926.                                 RootBlocks        += (id.id_NumBlocks * id.id_BytesPerBlock) / 512;
  1927.                                 RootBlocksUsed    += (id.id_NumBlocksUsed * id.id_BytesPerBlock) / 512;
  1928.                             }
  1929.  
  1930.                             node = malloc(sizeof(*node) + ((int)name[0])+1);
  1931.                             if(node != NULL)
  1932.                             {
  1933.                                 /* Copy the name of the volume. */
  1934.                                 node->ln_Name = (char *)(node + 1);
  1935.                                 strncpy(node->ln_Name,&name[1],name[0]);
  1936.                                 node->ln_Name[ name[0] ] = '\0';
  1937.  
  1938.                                 AddTail(&odn->odn_VolumeList,node);
  1939.  
  1940.                                 if(odn->odn_NextNode == NULL)
  1941.                                     odn->odn_NextNode = node;
  1942.                             }
  1943.                         }
  1944.                     }
  1945.  
  1946.                     dol = NextDosEntry(dol,LDF_VOLUMES|LDF_READ);
  1947.                 }
  1948.  
  1949.                 UnLockDosList(LDF_VOLUMES|LDF_READ);
  1950.             }
  1951.             else
  1952.             {
  1953.                 errno = ENOMEM;
  1954.             }
  1955.         }
  1956.         else
  1957.         {
  1958.             struct MangleInfo mi;
  1959.  
  1960.             if(MangleName(&dirName,&mi) == OK)
  1961.             {
  1962.                 BPTR fileLock;
  1963.  
  1964.                 ForbidDOS();
  1965.  
  1966.                 fileLock = Lock(dirName,SHARED_LOCK);
  1967.                 if(fileLock != ZERO)
  1968.                 {
  1969.                     struct OpenDirNode * odn;
  1970.  
  1971.                     odn = malloc(sizeof(*odn));
  1972.                     if(odn != NULL)
  1973.                     {
  1974.                         BPTR parentDir;
  1975.  
  1976.                         memset(odn,0,sizeof(*odn));
  1977.  
  1978.                         parentDir = ParentDir(fileLock);
  1979.                         if(parentDir != ZERO)
  1980.                         {
  1981.                             if(Examine(parentDir,&odn->odn_FIB))
  1982.                                 odn->odn_ParentDirKey = odn->odn_FIB.fib_DiskKey;
  1983.  
  1984.                             UnLock(parentDir);
  1985.                         }
  1986.  
  1987.                         if(Examine(fileLock,&odn->odn_FIB))
  1988.                         {
  1989.                             /* Make sure that we are
  1990.                              * trying to read a drawer
  1991.                              * and not a file.
  1992.                              */
  1993.                             if(FIB_IS_DRAWER(&odn->odn_FIB))
  1994.                             {
  1995.                                 odn->odn_DIR.dd_buf = (char *)odn;
  1996.                                 odn->odn_FileLock = fileLock;
  1997.                                 NewList(&odn->odn_VolumeList);
  1998.  
  1999.                                 /* The lock has been "swallowed"
  2000.                                  * by the dir node; make sure that
  2001.                                  * we don't unlock it.
  2002.                                  */
  2003.                                 fileLock = ZERO;
  2004.  
  2005.                                 AddHead(&OpenDirList,(struct Node *)odn);
  2006.                                 result = &odn->odn_DIR;
  2007.                             }
  2008.                             else
  2009.                             {
  2010.                                 errno = ENOTDIR;
  2011.                             }
  2012.                         }
  2013.                         else
  2014.                         {
  2015.                             MapIoErrToErrno();
  2016.                         }
  2017.  
  2018.                         if(result == NULL)
  2019.                             free(odn);
  2020.                     }
  2021.                     else
  2022.                     {
  2023.                         errno = ENOMEM;
  2024.                     }
  2025.  
  2026.                     UnLock(fileLock);
  2027.                 }
  2028.                 else
  2029.                 {
  2030.                     MapIoErrToErrno();
  2031.                 }
  2032.  
  2033.                 PermitDOS();
  2034.  
  2035.                 UnmangleName(&dirName,&mi);
  2036.             }
  2037.         }
  2038.     }
  2039.  
  2040.     RETURN(result);
  2041.     return(result);
  2042. }
  2043.  
  2044. VOID
  2045. amiga_closedir(DIR *dir)
  2046. {
  2047.     if(dir != NULL)
  2048.     {
  2049.         struct OpenDirNode * odn = (struct OpenDirNode *)dir->dd_buf;
  2050.  
  2051.         if(odn != NULL)
  2052.         {
  2053.             struct Node * node;
  2054.  
  2055.             Remove((struct Node *)odn);
  2056.  
  2057.             while((node = RemHead(&odn->odn_VolumeList)) != NULL)
  2058.                 free(node);
  2059.  
  2060.             UnLock(odn->odn_FileLock);
  2061.             free(odn);
  2062.         }
  2063.     }
  2064.  
  2065.     chkabort();
  2066. }
  2067.  
  2068. struct dirent *
  2069. amiga_readdir(DIR *dir)
  2070. {
  2071.     struct dirent * result = NULL;
  2072.  
  2073.     chkabort();
  2074.  
  2075.     if(dir != NULL)
  2076.     {
  2077.         struct OpenDirNode * odn = (struct OpenDirNode *)dir->dd_buf;
  2078.  
  2079.         if(odn != NULL)
  2080.         {
  2081.             struct dirent * d = &odn->odn_DirectoryEntry;
  2082.  
  2083.             if(odn->odn_ReadingVolumes)
  2084.             {
  2085.                 /* The first directory entry points
  2086.                  * back to the directory itself.
  2087.                  */
  2088.                 if(odn->odn_NextDirEntryIndex == 0)
  2089.                 {
  2090.                     strcpy(d->d_name,".");
  2091.  
  2092.                     d->d_ino    = ++odn->odn_NextDirEntryIndex;
  2093.                     d->d_namlen    = strlen(d->d_name);
  2094.  
  2095.                     result = d;
  2096.                 }
  2097.                 else
  2098.                 {
  2099.                     /* Return the next volume in the list. */
  2100.                     if(odn->odn_NextNode != NULL && odn->odn_NextNode->ln_Succ != NULL)
  2101.                     {
  2102.                         ASSERT(sizeof(d->d_name) >= strlen(odn->odn_NextNode->ln_Name));
  2103.  
  2104.                         strcpy(d->d_name,odn->odn_NextNode->ln_Name);
  2105.  
  2106.                         odn->odn_NextNode = odn->odn_NextNode->ln_Succ;
  2107.  
  2108.                         d->d_ino    = odn->odn_NextDirEntryIndex++;
  2109.                         d->d_namlen    = strlen(d->d_name);
  2110.  
  2111.                         result = d;
  2112.                     }
  2113.                     else
  2114.                     {
  2115.                         errno = 0;
  2116.                     }
  2117.                 }
  2118.             }
  2119.             else
  2120.             {
  2121.                 if(odn->odn_NextDirEntryIndex == 0)
  2122.                 {
  2123.                     /* The first directory entry points
  2124.                      * back to the directory itself.
  2125.                      */
  2126.                     strcpy(d->d_name,".");
  2127.  
  2128.                     d->d_ino    = odn->odn_FIB.fib_DiskKey;
  2129.                     d->d_namlen    = strlen(d->d_name);
  2130.  
  2131.                     odn->odn_NextDirEntryIndex++;
  2132.                     result = d;
  2133.                 }
  2134.                 else if(odn->odn_NextDirEntryIndex == 1)
  2135.                 {
  2136.                     /* The second directory entry points
  2137.                      * to the parent directory.
  2138.                      */
  2139.                     strcpy(d->d_name,"..");
  2140.  
  2141.                     d->d_ino    = odn->odn_ParentDirKey;
  2142.                     d->d_namlen    = strlen(d->d_name);
  2143.  
  2144.                     odn->odn_NextDirEntryIndex++;
  2145.                     result = d;
  2146.                 }
  2147.                 else
  2148.                 {
  2149.                     ForbidDOS();
  2150.  
  2151.                     /* All other iterations pick up the
  2152.                      * next following directory entry.
  2153.                      */
  2154.                     if(ExNext(odn->odn_FileLock,&odn->odn_FIB))
  2155.                     {
  2156.                         ASSERT(sizeof(d->d_name) >= strlen(odn->odn_FIB.fib_FileName));
  2157.  
  2158.                         strcpy(d->d_name,odn->odn_FIB.fib_FileName);
  2159.  
  2160.                         d->d_ino    = odn->odn_FIB.fib_DiskKey;
  2161.                         d->d_namlen    = strlen(d->d_name);
  2162.  
  2163.                         result = d;
  2164.                     }
  2165.                     else
  2166.                     {
  2167.                         LONG error = IoErr();
  2168.  
  2169.                         if(error == ERROR_NO_MORE_ENTRIES)
  2170.                         {
  2171.                             errno = 0;
  2172.                         }
  2173.                         else
  2174.                         {
  2175.                             SetIoErr(error);
  2176.                             MapIoErrToErrno();
  2177.                         }
  2178.                     }
  2179.  
  2180.                     PermitDOS();
  2181.                 }
  2182.             }
  2183.         }
  2184.     }
  2185.  
  2186.     if(result != NULL)
  2187.         SHOWSTRING(result->d_name);
  2188.  
  2189.     return(result);
  2190. }
  2191.  
  2192. /******************************************************************************/
  2193.  
  2194. STATIC int
  2195. TranslateRelativePath(char **namePtr,char *replace,int maxReplaceLen)
  2196. {
  2197.     int result = ERROR;
  2198.     char * name;
  2199.  
  2200.     ASSERT(namePtr != NULL && (*namePtr) != NULL && replace != NULL);
  2201.  
  2202.     /* If we have a current directory all references should
  2203.      * be made relative to, do just that. Absolute paths
  2204.      * are not modified, though.
  2205.      */
  2206.     name = (*namePtr);
  2207.     if(NOT STRING_IS_EMPTY(CurrentDirName) && name[0] != '/')
  2208.     {
  2209.         int totalLen;
  2210.  
  2211.         SHOWMSG("Changing the directory name");
  2212.  
  2213.         /* Skip current dir modifiers, we just want the name. */
  2214.         if(strncmp(name,"./",2) == SAME)
  2215.             name += 2;
  2216.         else if (strcmp(name,".") == SAME)
  2217.             name = "";
  2218.  
  2219.         /* Get the current directory name and get
  2220.          * ready to attach the file name at the end.
  2221.          */
  2222.         totalLen = strlen(CurrentDirName);
  2223.  
  2224.         if(CurrentDirName[strlen(CurrentDirName)-1] != '/' &&
  2225.            CurrentDirName[strlen(CurrentDirName)-1] != ':' &&
  2226.            NOT STRING_IS_EMPTY(name))
  2227.         {
  2228.             totalLen++;
  2229.         }
  2230.  
  2231.         totalLen += strlen(name);
  2232.  
  2233.         /* Check if the complete string will fit. */
  2234.         if(totalLen < maxReplaceLen)
  2235.         {
  2236.             /* Put the file name together. */
  2237.             strcpy(replace,CurrentDirName);
  2238.             if(CurrentDirName[strlen(CurrentDirName)-1] != '/' && NOT STRING_IS_EMPTY(name))
  2239.                 strcat(replace,"/");
  2240.  
  2241.             strcat(replace,name);
  2242.  
  2243.             (*namePtr) = replace;
  2244.             SHOWSTRING(*namePtr);
  2245.  
  2246.             result = OK;
  2247.         }
  2248.         else
  2249.         {
  2250.             errno = ENAMETOOLONG;
  2251.         }
  2252.     }
  2253.     else
  2254.     {
  2255.         result = OK;
  2256.     }
  2257.  
  2258.     return(result);
  2259. }
  2260.  
  2261. /******************************************************************************/
  2262.  
  2263. int
  2264. amiga_mkdir(char *name,int mode)
  2265. {
  2266.     struct MangleInfo mi;
  2267.     BPTR dirLock;
  2268.     int result = ERROR;
  2269.  
  2270.     chkabort();
  2271.  
  2272.     ASSERT(name != NULL);
  2273.  
  2274.     ENTER();
  2275.     SHOWSTRING(name);
  2276.     SHOWVALUE(mode);
  2277.  
  2278.     if(MangleName(&name,&mi) == OK)
  2279.     {
  2280.         ForbidDOS();
  2281.  
  2282.         dirLock = CreateDir((STRPTR)name);
  2283.         if(dirLock != ZERO)
  2284.         {
  2285.             UnLock(dirLock);
  2286.             result = OK;
  2287.         }
  2288.         else
  2289.         {
  2290.             MapIoErrToErrno();
  2291.         }
  2292.  
  2293.         PermitDOS();
  2294.  
  2295.         UnmangleName(&name,&mi);
  2296.     }
  2297.  
  2298.     if(result == OK)
  2299.         result = amiga_chmod(name,mode);
  2300.  
  2301.     RETURN(result);
  2302.     return(result);
  2303. }
  2304.  
  2305. /******************************************************************************/
  2306.  
  2307. int
  2308. amiga_rmdir(char *name)
  2309. {
  2310.     struct MangleInfo mi;
  2311.     BPTR fileLock;
  2312.     int result = ERROR;
  2313.  
  2314.     chkabort();
  2315.  
  2316.     ENTER();
  2317.     SHOWSTRING(name);
  2318.  
  2319.     if(MangleName(&name,&mi) == OK)
  2320.     {
  2321.         ForbidDOS();
  2322.  
  2323.         fileLock = Lock(name,SHARED_LOCK);
  2324.         if(fileLock != ZERO)
  2325.         {
  2326.             struct FileInfoBlock __aligned fib;
  2327.  
  2328.             if(Examine(fileLock,&fib))
  2329.             {
  2330.                 UnLock(fileLock);
  2331.                 fileLock = ZERO;
  2332.  
  2333.                 /* Make sure that we get to remove a drawer,
  2334.                  * as the function name implies.
  2335.                  */
  2336.                 if(FIB_IS_DRAWER(&fib))
  2337.                 {
  2338.                     if(DeleteFile(name))
  2339.                         result = OK;
  2340.                     else
  2341.                         MapIoErrToErrno();
  2342.                 }
  2343.                 else
  2344.                 {
  2345.                     errno = ENOTDIR;
  2346.                 }
  2347.             }
  2348.             else
  2349.             {
  2350.                 MapIoErrToErrno();
  2351.             }
  2352.  
  2353.             UnLock(fileLock);
  2354.         }
  2355.         else
  2356.         {
  2357.             MapIoErrToErrno();
  2358.         }
  2359.  
  2360.         PermitDOS();
  2361.  
  2362.         UnmangleName(&name,&mi);
  2363.     }
  2364.  
  2365.     RETURN(result);
  2366.     return(result);
  2367. }
  2368.  
  2369. /******************************************************************************/
  2370.  
  2371. int
  2372. amiga_creat(char *name,int prot)
  2373. {
  2374.     struct MangleInfo mi;
  2375.     int result = ERROR;
  2376.  
  2377.     chkabort();
  2378.  
  2379.     ASSERT(name != NULL);
  2380.  
  2381.     ENTER();
  2382.     SHOWSTRING(name);
  2383.     SHOWVALUE(prot);
  2384.  
  2385.     if(MangleName(&name,&mi) == OK)
  2386.     {
  2387.         ForbidDOS();
  2388.         result = creat(name,prot);
  2389.         PermitDOS();
  2390.  
  2391.         UnmangleName(&name,&mi);
  2392.     }
  2393.  
  2394.     RETURN(result);
  2395.     return(result);
  2396. }
  2397.  
  2398. /******************************************************************************/
  2399.  
  2400. FILE *
  2401. amiga_fopen(char *name,char *mode)
  2402. {
  2403.     struct MangleInfo mi;
  2404.     FILE *result = NULL;
  2405.  
  2406.     chkabort();
  2407.  
  2408.     ASSERT(name != NULL && mode != NULL);
  2409.  
  2410.     ENTER();
  2411.     SHOWSTRING(name);
  2412.     SHOWSTRING(mode);
  2413.  
  2414.     if(MangleName(&name,&mi) == OK)
  2415.     {
  2416.         ForbidDOS();
  2417.         result = fopen(name,mode);
  2418.         PermitDOS();
  2419.  
  2420.         UnmangleName(&name,&mi);
  2421.     }
  2422.  
  2423.     RETURN(result);
  2424.     return(result);
  2425. }
  2426.  
  2427. /******************************************************************************/
  2428.  
  2429. int
  2430. amiga_rename(char *old,char *new)
  2431. {
  2432.     struct MangleInfo old_mi;
  2433.     struct MangleInfo new_mi;
  2434.     int result = ERROR;
  2435.  
  2436.     chkabort();
  2437.  
  2438.     ASSERT(old != NULL && new != NULL);
  2439.  
  2440.     ENTER();
  2441.     SHOWSTRING(old);
  2442.     SHOWSTRING(new);
  2443.  
  2444.     /* rename() causes the link named <from> to be renamed as <to>. If <to> exists,
  2445.      * it is first removed. Both <from> and <to> must be of the same type (that is,
  2446.      * both directories or both non-directories), and must reside on the same
  2447.      * file system.
  2448.      */
  2449.  
  2450.     if(MangleName(&old,&old_mi) == OK)
  2451.     {
  2452.         if(MangleName(&new,&new_mi) == OK)
  2453.         {
  2454.             ForbidDOS();
  2455.  
  2456.             D(("rename |%s| to |%s|",old,new));
  2457.  
  2458.             if(CANNOT Rename(old,new))
  2459.             {
  2460.                 LONG error = IoErr();
  2461.  
  2462.                 SHOWVALUE(error);
  2463.  
  2464.                 if(error == ERROR_OBJECT_EXISTS)
  2465.                 {
  2466.                     BPTR oldLock = Lock(old,SHARED_LOCK);
  2467.                     BPTR newLock = Lock(new,SHARED_LOCK);
  2468.  
  2469.                     if(oldLock != ZERO && newLock != ZERO && SameLock(oldLock,newLock) == LOCK_SAME)
  2470.                     {
  2471.                         result = OK;
  2472.                         error = OK;
  2473.  
  2474.                         SHOWMSG("Ok; same name");
  2475.  
  2476.                         UnLock(oldLock);
  2477.                         UnLock(newLock);
  2478.                     }
  2479.                     else
  2480.                     {
  2481.                         UnLock(oldLock);
  2482.                         UnLock(newLock);
  2483.  
  2484.                         if(DeleteFile(new))
  2485.                         {
  2486.                             if(Rename(old,new))
  2487.                             {
  2488.                                 result = OK;
  2489.                                 error = OK;
  2490.  
  2491.                                 SHOWMSG("Ok; after removing");
  2492.                             }
  2493.                             else
  2494.                             {
  2495.                                 error = IoErr();
  2496.                             }
  2497.                         }
  2498.                         else
  2499.                         {
  2500.                             error = IoErr();
  2501.                         }
  2502.                     }
  2503.                 }
  2504.  
  2505.                 if(error != OK)
  2506.                 {
  2507.                     SHOWVALUE(error);
  2508.  
  2509.                     SetIoErr(error);
  2510.                     MapIoErrToErrno();
  2511.                 }
  2512.             }
  2513.             else
  2514.             {
  2515.                 SHOWMSG("Ok");
  2516.  
  2517.                 result = OK;
  2518.             }
  2519.  
  2520.             PermitDOS();
  2521.  
  2522.             UnmangleName(&new,&new_mi);
  2523.         }
  2524.         else
  2525.         {
  2526.             SHOWMSG("MangleName new_mi failed");
  2527.         }
  2528.  
  2529.         UnmangleName(&old,&old_mi);
  2530.     }
  2531.     else
  2532.     {
  2533.         SHOWMSG("MangleName old_mi failed");
  2534.     }
  2535.  
  2536.     RETURN(result);
  2537.     return(result);
  2538. }
  2539.  
  2540. /******************************************************************************/
  2541.  
  2542. char *
  2543. amiga_getcwd(char *buf, size_t size)
  2544. {
  2545.     char *result = NULL;
  2546.  
  2547.     chkabort();
  2548.  
  2549.     ASSERT(buf != NULL);
  2550.  
  2551.     ENTER();
  2552.     SHOWVALUE(buf);
  2553.     SHOWVALUE(size);
  2554.  
  2555.     if(CurrentDirName[0] == '/')
  2556.     {
  2557.         strncpy(buf,CurrentDirName,size-1);
  2558.         buf[size-1] = '\0';
  2559.         result = buf;
  2560.     }
  2561.     else
  2562.     {
  2563.         BPTR oldDir;
  2564.  
  2565.         ForbidDOS();
  2566.  
  2567.         oldDir = CurrentDir(ZERO);
  2568.  
  2569.         if(NameFromLock(oldDir,buf,size))
  2570.         {
  2571.             if(MapFileNameAmigaToUnix(buf,buf,size) == OK)
  2572.                 result = buf;
  2573.         }
  2574.         else
  2575.         {
  2576.             MapIoErrToErrno();
  2577.         }
  2578.  
  2579.         CurrentDir(oldDir);
  2580.  
  2581.         PermitDOS();
  2582.     }
  2583.  
  2584.     SHOWSTRING(result);
  2585.  
  2586.     RETURN(result);
  2587.     return(result);
  2588. }
  2589.  
  2590. /******************************************************************************/
  2591.  
  2592. #define SET_FILESIZE_ERROR (-1)
  2593.  
  2594. int
  2595. amiga_ftruncate(int fd,off_t size)
  2596. {
  2597.     struct UFB * ufb;
  2598.     int result = ERROR;
  2599.  
  2600.     chkabort();
  2601.  
  2602.     ENTER();
  2603.     SHOWVALUE(fd);
  2604.     SHOWVALUE(size);
  2605.  
  2606.     ufb = chkufb(fd);
  2607.     if(ufb != NULL)
  2608.     {
  2609.         ForbidDOS();
  2610.  
  2611.         if(SetFileSize((BPTR)ufb->ufbfh,size,OFFSET_BEGINNING) != SET_FILESIZE_ERROR)
  2612.             result = OK;
  2613.         else
  2614.             MapIoErrToErrno();
  2615.  
  2616.         PermitDOS();
  2617.     }
  2618.     else
  2619.     {
  2620.         errno = EBADF;
  2621.     }
  2622.  
  2623.     RETURN(result);
  2624.     return(result);
  2625. }
  2626.  
  2627. /******************************************************************************/
  2628.  
  2629. int
  2630. amiga_accept(int sockfd,struct sockaddr *cliaddr,int *addrlen)
  2631. {
  2632.     struct UFB * ufb;
  2633.     int result = ERROR;
  2634.  
  2635.     chkabort();
  2636.  
  2637.     ASSERT(cliaddr != NULL && addrlen != NULL);
  2638.  
  2639.     ENTER();
  2640.     SHOWVALUE(sockfd);
  2641.     SHOWVALUE(cliaddr);
  2642.     SHOWVALUE(addrlen);
  2643.  
  2644.     ufb = chkufb(sockfd);
  2645.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2646.         result = accept(ufb->ufbfh,cliaddr,(LONG *)addrlen);
  2647.     else
  2648.         errno = ENOTSOCK;
  2649.  
  2650.     RETURN(result);
  2651.     return(result);
  2652. }
  2653.  
  2654. /******************************************************************************/
  2655.  
  2656. int
  2657. amiga_bind(int sockfd,struct sockaddr *name,int namelen)
  2658. {
  2659.     struct UFB * ufb;
  2660.     int result = ERROR;
  2661.  
  2662.     chkabort();
  2663.  
  2664.     ASSERT(name != NULL);
  2665.  
  2666.     ENTER();
  2667.     SHOWVALUE(sockfd);
  2668.     SHOWVALUE(name);
  2669.     SHOWVALUE(namelen);
  2670.  
  2671.     ufb = chkufb(sockfd);
  2672.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2673.         result = bind(ufb->ufbfh,name,namelen);
  2674.     else
  2675.         errno = ENOTSOCK;
  2676.  
  2677.     RETURN(result);
  2678.     return(result);
  2679. }
  2680.  
  2681. /******************************************************************************/
  2682.  
  2683. int
  2684. amiga_close(int fd)
  2685. {
  2686.     struct UFB * ufb;
  2687.     int result = ERROR;
  2688.  
  2689.     chkabort();
  2690.  
  2691.     ENTER();
  2692.     SHOWVALUE(fd);
  2693.  
  2694.     ufb = chkufb(fd);
  2695.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2696.     {
  2697.         result = CloseSocket(ufb->ufbfh);
  2698.         CLEAR_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  2699.  
  2700.         /* Make sure that the descriptor looks like a file again. */
  2701.         RestoreDescriptor(ufb);
  2702.  
  2703.         close(fd);
  2704.     }
  2705.     else
  2706.     {
  2707.         if(ufb != NULL)
  2708.         {
  2709.             /* Don't close the stdio streams! */
  2710.             if(fd == 0 || fd == 1 || fd == 2)
  2711.             {
  2712.                 D(("Attempt to muck with fd #%ld!",fd));
  2713.  
  2714.                 errno = EBADF;
  2715.             }
  2716.             else
  2717.             {
  2718.                 char fileName[MAX_FILENAME_LEN];
  2719.                 BOOL removeIt = FALSE;
  2720.  
  2721.                 if(FLAG_IS_SET(ufb->ufbflg,UFB_UNLINK))
  2722.                 {
  2723.                     removeIt = NameFromFH((BPTR)ufb->ufbfh,fileName,sizeof(fileName));
  2724.  
  2725.                     CLEAR_FLAG(ufb->ufbflg,UFB_UNLINK);
  2726.                 }
  2727.  
  2728.                 CleanupFileLocks(fd);
  2729.  
  2730.                 result = close(fd);
  2731.  
  2732.                 if(removeIt)
  2733.                     DeleteFile(fileName);
  2734.             }
  2735.         }
  2736.         else
  2737.         {
  2738.             errno = EBADF;
  2739.         }
  2740.     }
  2741.  
  2742.     RETURN(result);
  2743.     return(result);
  2744. }
  2745.  
  2746. /******************************************************************************/
  2747.  
  2748. int
  2749. amiga_connect(int sockfd,struct sockaddr *name,int namelen)
  2750. {
  2751.     struct UFB * ufb;
  2752.     int result = ERROR;
  2753.  
  2754.     chkabort();
  2755.  
  2756.     ASSERT(name != NULL && namelen > 0);
  2757.  
  2758.     ENTER();
  2759.     SHOWVALUE(sockfd);
  2760.     SHOWVALUE(name);
  2761.     SHOWVALUE(namelen);
  2762.  
  2763.     ufb = chkufb(sockfd);
  2764.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2765.         result = connect(ufb->ufbfh,name,namelen);
  2766.     else
  2767.         errno = ENOTSOCK;
  2768.  
  2769.     RETURN(result);
  2770.     return(result);
  2771. }
  2772.  
  2773. /******************************************************************************/
  2774.  
  2775. int
  2776. amiga_getpeername(int sockfd,struct sockaddr *name,int *namelen)
  2777. {
  2778.     struct UFB * ufb;
  2779.     int result = ERROR;
  2780.  
  2781.     chkabort();
  2782.  
  2783.     ASSERT(name != NULL && namelen != NULL);
  2784.  
  2785.     ENTER();
  2786.     SHOWVALUE(sockfd);
  2787.     SHOWVALUE(name);
  2788.     SHOWVALUE(namelen);
  2789.  
  2790.     ufb = chkufb(sockfd);
  2791.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2792.         result = getpeername(ufb->ufbfh,name,(LONG *)namelen);
  2793.     else
  2794.         errno = ENOTSOCK;
  2795.  
  2796.     RETURN(result);
  2797.     return(result);
  2798. }
  2799.  
  2800. /******************************************************************************/
  2801.  
  2802. int
  2803. amiga_getsockopt(int sockfd,int level,int optname,VOID *optval,int *optlen)
  2804. {
  2805.     struct UFB * ufb;
  2806.     int result = ERROR;
  2807.  
  2808.     chkabort();
  2809.  
  2810.     ASSERT(optval != NULL && optlen != NULL);
  2811.  
  2812.     ENTER();
  2813.     SHOWVALUE(sockfd);
  2814.     SHOWVALUE(level);
  2815.     SHOWVALUE(optname);
  2816.     SHOWVALUE(optval);
  2817.     SHOWVALUE(optlen);
  2818.  
  2819.     ufb = chkufb(sockfd);
  2820.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2821.         result = getsockopt(ufb->ufbfh,level,optname,optval,(LONG *)optlen);
  2822.     else
  2823.         errno = ENOTSOCK;
  2824.  
  2825.     RETURN(result);
  2826.     return(result);
  2827. }
  2828.  
  2829. /******************************************************************************/
  2830.  
  2831. int
  2832. amiga_ioctl(int fd,unsigned long request,char *arg)
  2833. {
  2834.     struct UFB * ufb;
  2835.     int result = ERROR;
  2836.  
  2837.     chkabort();
  2838.  
  2839.     ASSERT(arg != NULL);
  2840.  
  2841.     ENTER();
  2842.     SHOWVALUE(fd);
  2843.     SHOWVALUE(request);
  2844.     SHOWVALUE(arg);
  2845.  
  2846.     ufb = chkufb(fd);
  2847.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2848.         result = IoctlSocket(ufb->ufbfh,request,arg);
  2849.     else
  2850.         errno = ENOTSOCK;
  2851.  
  2852.     RETURN(result);
  2853.     return(result);
  2854. }
  2855.  
  2856. /******************************************************************************/
  2857.  
  2858. int
  2859. amiga_listen(int sockfd,int backlog)
  2860. {
  2861.     struct UFB * ufb;
  2862.     int result = ERROR;
  2863.  
  2864.     chkabort();
  2865.  
  2866.     ENTER();
  2867.     SHOWVALUE(sockfd);
  2868.     SHOWVALUE(backlog);
  2869.  
  2870.     ufb = chkufb(sockfd);
  2871.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2872.         result = listen(ufb->ufbfh,backlog);
  2873.     else
  2874.         errno = ENOTSOCK;
  2875.  
  2876.     RETURN(result);
  2877.     return(result);
  2878. }
  2879.  
  2880. /******************************************************************************/
  2881.  
  2882. int
  2883. amiga_read(int fd,VOID *data,unsigned int size)
  2884. {
  2885.     struct UFB * ufb;
  2886.     int result;
  2887.  
  2888.     chkabort();
  2889.  
  2890.     ASSERT(data != NULL);
  2891.  
  2892.     ENTER();
  2893.     SHOWVALUE(fd);
  2894.     SHOWVALUE(data);
  2895.     SHOWVALUE(size);
  2896.  
  2897.     ufb = chkufb(fd);
  2898.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2899.     {
  2900.         SHOWMSG("input from socket");
  2901.         result = recv(ufb->ufbfh,data,size,0);
  2902.     }
  2903.     else
  2904.     {
  2905.         SHOWMSG("input from file");
  2906.         ForbidDOS();
  2907.         result = read(fd,data,size);
  2908.         PermitDOS();
  2909.     }
  2910.  
  2911.     RETURN(result);
  2912.     return(result);
  2913. }
  2914.  
  2915. /******************************************************************************/
  2916.  
  2917. int
  2918. amiga_recvfrom(int sockfd,VOID *buff,int len,int flags,struct sockaddr *from,int *fromlen)
  2919. {
  2920.     struct UFB * ufb;
  2921.     int result = ERROR;
  2922.  
  2923.     chkabort();
  2924.  
  2925.     ASSERT(buff != NULL && from != NULL && fromlen != NULL);
  2926.  
  2927.     ENTER();
  2928.     SHOWVALUE(sockfd);
  2929.     SHOWVALUE(buff);
  2930.     SHOWVALUE(len);
  2931.     SHOWVALUE(flags);
  2932.     SHOWVALUE(from);
  2933.     SHOWVALUE(fromlen);
  2934.  
  2935.     ufb = chkufb(sockfd);
  2936.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2937.         result = recvfrom(ufb->ufbfh,buff,len,flags,from,(LONG *)fromlen);
  2938.     else
  2939.         errno = ENOTSOCK;
  2940.  
  2941.     RETURN(result);
  2942.     return(result);
  2943. }
  2944.  
  2945. /******************************************************************************/
  2946.  
  2947. STATIC VOID
  2948. MapDescriptorSets(
  2949.     const fd_set *    input_fds,
  2950.     int                num_input_fds,
  2951.     fd_set *        socket_fds,
  2952.     int *            max_socket_fd_ptr,
  2953.     fd_set *        file_fds,
  2954.     int *            max_file_fd_ptr)
  2955. {
  2956.     FD_ZERO(socket_fds);
  2957.     FD_ZERO(file_fds);
  2958.  
  2959.     /* This routine maps file descriptor sets
  2960.      * from one format to another. We map
  2961.      * socket descriptors and regular file
  2962.      * descriptor sets.
  2963.      */
  2964.     if(input_fds != NULL && num_input_fds > 0)
  2965.     {
  2966.         int max_socket_fd = (*max_socket_fd_ptr);
  2967.         int max_file_fd = (*max_file_fd_ptr);
  2968.         struct UFB * ufb;
  2969.         int i;
  2970.  
  2971.         for(i = 0 ; i < num_input_fds ; i++)
  2972.         {
  2973.             if(FD_ISSET(i,input_fds))
  2974.             {
  2975.                 D(("fd to wait on #%ld",i));
  2976.  
  2977.                 ufb = chkufb(i);
  2978.                 if(ufb != NULL)
  2979.                 {
  2980.                     /* Is this a socket descriptor? */
  2981.                     if(FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2982.                     {
  2983.                         D(("fd #%ld is a socket.\n",i));
  2984.  
  2985.                         FD_SET(ufb->ufbfh,socket_fds);
  2986.  
  2987.                         if(max_socket_fd < ufb->ufbfh)
  2988.                             max_socket_fd = ufb->ufbfh;
  2989.                     }
  2990.                     else
  2991.                     {
  2992.                         D(("fd #%ld is a file.\n",i));
  2993.  
  2994.                         /* We only watch files bound to
  2995.                          * console streams.
  2996.                          */
  2997.                         if(IsInteractive((BPTR)ufb->ufbfh))
  2998.                         {
  2999.                             FD_SET(i,file_fds);
  3000.  
  3001.                             if(max_file_fd < i)
  3002.                                 max_file_fd = i;
  3003.                         }
  3004.                     }
  3005.                 }
  3006.             }
  3007.         }
  3008.  
  3009.         (*max_socket_fd_ptr)    = max_socket_fd;
  3010.         (*max_file_fd_ptr)        = max_file_fd;
  3011.     }
  3012. }
  3013.  
  3014. STATIC VOID
  3015. RemapDescriptorSets(
  3016.     const fd_set *    socket_fds,
  3017.     int                max_socket_fd,
  3018.     const fd_set *    file_fds,
  3019.     int                max_file_fd,
  3020.     fd_set *        output_fds,
  3021.     int                num_output_fds)
  3022. {
  3023.     /* This routine reverses the mapping established
  3024.      * above. We map the file and socket descriptor
  3025.      * sets back into the original set.
  3026.      */
  3027.     if(output_fds != NULL)
  3028.     {
  3029.         int fd;
  3030.  
  3031.         FD_ZERO(output_fds);
  3032.  
  3033.         for(fd = 0 ; fd <= max_socket_fd ; fd++)
  3034.         {
  3035.             if(FD_ISSET(fd,socket_fds))
  3036.             {
  3037.                 struct UFB * ufb;
  3038.                 int output_fd;
  3039.  
  3040.                 for(output_fd = 0 ; output_fd < num_output_fds ; output_fd++)
  3041.                 {
  3042.                     ufb = chkufb(output_fd);
  3043.                     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET) && ufb->ufbfh == fd)
  3044.                     {
  3045.                         D(("fd #%ld has data",output_fd));
  3046.                         FD_SET(output_fd,output_fds);
  3047.                         break;
  3048.                     }
  3049.                 }
  3050.             }
  3051.         }
  3052.  
  3053.         for(fd = 0 ; fd <= max_file_fd ; fd++)
  3054.         {
  3055.             if(FD_ISSET(fd,file_fds))
  3056.             {
  3057.                 D(("fd #%ld has data",fd));
  3058.                 FD_SET(fd,output_fds);
  3059.             }
  3060.         }
  3061.     }
  3062. }
  3063.  
  3064. int
  3065. amiga_select(int num_fds,fd_set *read_fds,fd_set *write_fds,fd_set *except_fds,struct timeval *timeout)
  3066. {
  3067.     fd_set socket_read_fds;
  3068.     fd_set socket_write_fds;
  3069.     fd_set socket_except_fds;
  3070.     int max_socket_fd;
  3071.     fd_set file_read_fds;
  3072.     fd_set file_write_fds;
  3073.     fd_set file_except_fds;
  3074.     struct UFB * ufb;
  3075.     int max_file_fd;
  3076.     int result = 0;
  3077.  
  3078.     chkabort();
  3079.  
  3080.     ENTER();
  3081.  
  3082.     if(num_fds > FD_SETSIZE)
  3083.     {
  3084.         D(("Warning: %ld descriptor sets to wait on requested; only %ld available.",num_fds,FD_SETSIZE));
  3085.         num_fds = FD_SETSIZE;
  3086.     }
  3087.  
  3088.     max_socket_fd = -1;
  3089.     max_file_fd = -1;
  3090.  
  3091.     MapDescriptorSets(read_fds,        num_fds,    &socket_read_fds,    &max_socket_fd,    &file_read_fds,        &max_file_fd);
  3092.     MapDescriptorSets(write_fds,    num_fds,    &socket_write_fds,    &max_socket_fd,    &file_write_fds,    &max_file_fd);
  3093.     MapDescriptorSets(except_fds,    num_fds,    &socket_except_fds,    &max_socket_fd,    &file_except_fds,    &max_file_fd);
  3094.  
  3095.     D(("number of socket fds to work on == %ld",max_socket_fd+1));
  3096.     D(("number of file   fds to work on == %ld",max_file_fd+1));
  3097.  
  3098.     /* Wait for socket input? */
  3099.     if(max_socket_fd != -1)
  3100.     {
  3101.         /* Wait for file input, too? */
  3102.         if(max_file_fd != -1 && (timeout == NULL || timeout->tv_secs > 0 || timeout->tv_micro > 0))
  3103.         {
  3104.             struct timeval stopWhen;
  3105.             struct timeval zero;
  3106.             BOOL gotSomething;
  3107.             ULONG breakMask;
  3108.             int i;
  3109.  
  3110.             /* We are going to poll all streams; for the timeout
  3111.              * feature to work, we absolutely must know when to
  3112.              * stop polling.
  3113.              *
  3114.              * Why aren't we using asynchronous DOS packets?
  3115.              * The answer is that once a packet is sent, you
  3116.              * cannot easily abort it. Polling is safer in
  3117.              * that respect. Yes, I know that ACTION_STACK
  3118.              * can be used to fake input to a console stream,
  3119.              * but I'd rather not rely upon it.
  3120.              */
  3121.             if(timeout != NULL)
  3122.             {
  3123.                 GetSysTime((APTR)&stopWhen);
  3124.                 AddTime((APTR)&stopWhen,(APTR)timeout);
  3125.             }
  3126.             else
  3127.             {
  3128.                 /* No timeout, poll until we are interrupted
  3129.                  * or get input from any of the files. It's
  3130.                  * not really necessary to initialize this
  3131.                  * timeval, but it keeps the compiler happy.
  3132.                  */
  3133.                 memset(&stopWhen,0,sizeof(stopWhen));
  3134.             }
  3135.  
  3136.             while(TRUE)
  3137.             {
  3138.                 /* Check for break signal. */
  3139.                 chkabort();
  3140.  
  3141.                 /* Delay for a tick to avoid busy-waiting. */
  3142.                 Delay(1);
  3143.  
  3144.                 /* This tells WaitSelect() to poll the sockets for input. */
  3145.                 zero.tv_secs    = 0;
  3146.                 zero.tv_micro    = 0;
  3147.  
  3148.                 /* Signals to stop on; we want to stop when a break signal arrives. */
  3149.                 if(AllowBreak)
  3150.                     breakMask = SIGBREAKF_CTRL_C;
  3151.                 else
  3152.                     breakMask = 0;
  3153.  
  3154.                 /* Check for socket input. */
  3155.                 result = WaitSelect(max_socket_fd+1,&socket_read_fds,&socket_write_fds,&socket_except_fds,&zero,&breakMask);
  3156.  
  3157.                 /* Stop if a break signal arrives. */
  3158.                 if((result < 0 && errno == EINTR) || FLAG_IS_SET(breakMask,SIGBREAKF_CTRL_C))
  3159.                     raise(SIGINT);
  3160.  
  3161.                 /* Stop if the return value from WaitSelect is negative. */
  3162.                 if(result < 0)
  3163.                     break;
  3164.  
  3165.                 /* Did we get any socket input? */
  3166.                 gotSomething = (BOOL)(result > 0);
  3167.                 if(NOT gotSomething)
  3168.                 {
  3169.                     /* Check all files for input. We also poll
  3170.                      * them for input, but each with a little
  3171.                      * delay of about 1/50 of a second. We stop
  3172.                      * as soon as we find one file that has
  3173.                      * input in it.
  3174.                      */
  3175.                     for(i = 0 ; i <= max_file_fd ; i++)
  3176.                     {
  3177.                         if(FD_ISSET(i,&file_read_fds) ||
  3178.                            FD_ISSET(i,&file_write_fds) ||
  3179.                            FD_ISSET(i,&file_except_fds))
  3180.                         {
  3181.                             ufb = chkufb(i);
  3182.                             if(ufb != NULL)
  3183.                             {
  3184.                                 if(WaitForChar((BPTR)ufb->ufbfh,1))
  3185.                                 {
  3186.                                     gotSomething = TRUE;
  3187.                                     break;
  3188.                                 }
  3189.                             }
  3190.                         }
  3191.                     }
  3192.                 }
  3193.  
  3194.                 /* Did we get any input at all? */
  3195.                 if(gotSomething)
  3196.                 {
  3197.                     BOOL gotInput;
  3198.  
  3199.                     /* Now retest all files and remember
  3200.                      * those that had input.
  3201.                      */
  3202.                     for(i = 0 ; i <= max_file_fd ; i++)
  3203.                     {
  3204.                         gotInput = FALSE;
  3205.  
  3206.                         if(FD_ISSET(i,&file_read_fds) ||
  3207.                            FD_ISSET(i,&file_write_fds) ||
  3208.                            FD_ISSET(i,&file_except_fds))
  3209.                         {
  3210.                             ufb = chkufb(i);
  3211.                             if(ufb != NULL)
  3212.                             {
  3213.                                 /* Does this one have input? */
  3214.                                 gotInput = WaitForChar((BPTR)ufb->ufbfh,1);
  3215.                             }
  3216.                         }
  3217.  
  3218.                         if(gotInput)
  3219.                         {
  3220.                             /* Mark one more descriptor as
  3221.                              * having input.
  3222.                              */
  3223.                             result++;
  3224.                         }
  3225.                         else
  3226.                         {
  3227.                             /* Mark this descriptor as
  3228.                              * not having any input.
  3229.                              */
  3230.                             FD_CLR(i,&file_read_fds);
  3231.                             FD_CLR(i,&file_write_fds);
  3232.                             FD_CLR(i,&file_except_fds);
  3233.                         }
  3234.                     }
  3235.                 }
  3236.  
  3237.                 /* Did we get any input? If so, stop polling. */
  3238.                 if(result > 0)
  3239.                     break;
  3240.  
  3241.                 /* If a timeout was set, check if we are already
  3242.                  * beyond the point of time when we should have
  3243.                  * stopped polling.
  3244.                  */
  3245.                 if(timeout != NULL)
  3246.                 {
  3247.                     struct timeval now;
  3248.  
  3249.                     GetSysTime((APTR)&now);
  3250.  
  3251.                     if((-CmpTime((APTR)&now,(APTR)&stopWhen)) >= 0)
  3252.                         break;
  3253.                 }
  3254.             }
  3255.         }
  3256.         else
  3257.         {
  3258.             ULONG breakMask;
  3259.  
  3260.             if(AllowBreak)
  3261.                 breakMask = SIGBREAKF_CTRL_C;
  3262.             else
  3263.                 breakMask = 0;
  3264.  
  3265.             result = WaitSelect(max_socket_fd+1,&socket_read_fds,&socket_write_fds,&socket_except_fds,timeout,&breakMask);
  3266.             if((result < 0 && errno == EINTR) || FLAG_IS_SET(breakMask,SIGBREAKF_CTRL_C))
  3267.                 raise(SIGINT);
  3268.         }
  3269.     }
  3270.     else
  3271.     {
  3272.         /* Wait for file input? */
  3273.         if(max_file_fd != -1 && (timeout == NULL || timeout->tv_secs > 0 || timeout->tv_micro > 0))
  3274.         {
  3275.             struct timeval stopWhen;
  3276.             BOOL gotSomething;
  3277.             int i;
  3278.  
  3279.             if(timeout != NULL)
  3280.             {
  3281.                 GetSysTime((APTR)&stopWhen);
  3282.                 AddTime((APTR)&stopWhen,(APTR)timeout);
  3283.             }
  3284.             else
  3285.             {
  3286.                 memset(&stopWhen,0,sizeof(stopWhen));
  3287.             }
  3288.  
  3289.             while(TRUE)
  3290.             {
  3291.                 chkabort();
  3292.  
  3293.                 Delay(1);
  3294.  
  3295.                 gotSomething = FALSE;
  3296.                 for(i = 0 ; i <= max_file_fd ; i++)
  3297.                 {
  3298.                     if(FD_ISSET(i,&file_read_fds) ||
  3299.                        FD_ISSET(i,&file_write_fds) ||
  3300.                        FD_ISSET(i,&file_except_fds))
  3301.                     {
  3302.                         ufb = chkufb(i);
  3303.                         if(ufb != NULL)
  3304.                         {
  3305.                             if(WaitForChar((BPTR)ufb->ufbfh,1))
  3306.                             {
  3307.                                 gotSomething = TRUE;
  3308.                                 break;
  3309.                             }
  3310.                         }
  3311.                     }
  3312.                 }
  3313.  
  3314.                 if(gotSomething)
  3315.                 {
  3316.                     BOOL gotInput;
  3317.  
  3318.                     for(i = 0 ; i <= max_file_fd ; i++)
  3319.                     {
  3320.                         gotInput = FALSE;
  3321.  
  3322.                         if(FD_ISSET(i,&file_read_fds) ||
  3323.                            FD_ISSET(i,&file_write_fds) ||
  3324.                            FD_ISSET(i,&file_except_fds))
  3325.                         {
  3326.                             ufb = chkufb(i);
  3327.                             if(ufb != NULL)
  3328.                             {
  3329.                                 /* Does this one have input? */
  3330.                                 gotInput = WaitForChar((BPTR)ufb->ufbfh,1);
  3331.                             }
  3332.                         }
  3333.  
  3334.                         if(gotInput)
  3335.                         {
  3336.                             result++;
  3337.                         }
  3338.                         else
  3339.                         {
  3340.                             FD_CLR(i,&file_read_fds);
  3341.                             FD_CLR(i,&file_write_fds);
  3342.                             FD_CLR(i,&file_except_fds);
  3343.                         }
  3344.                     }
  3345.                 }
  3346.  
  3347.                 if(result > 0)
  3348.                     break;
  3349.  
  3350.                 if(timeout != NULL)
  3351.                 {
  3352.                     struct timeval now;
  3353.  
  3354.                     GetSysTime((APTR)&now);
  3355.  
  3356.                     if((-CmpTime((APTR)&now,(APTR)&stopWhen)) >= 0)
  3357.                         break;
  3358.                 }
  3359.             }
  3360.         }
  3361.     }
  3362.  
  3363.     /* The descriptor sets remain unchanged in
  3364.      * case of error.
  3365.      */
  3366.     if(result >= 0)
  3367.     {
  3368.         RemapDescriptorSets(&socket_read_fds,    max_socket_fd,    &file_read_fds,        max_file_fd,    read_fds,    num_fds);
  3369.         RemapDescriptorSets(&socket_write_fds,    max_socket_fd,    &file_write_fds,    max_file_fd,    write_fds,    num_fds);
  3370.         RemapDescriptorSets(&socket_except_fds,    max_socket_fd,    &file_except_fds,    max_file_fd,    except_fds,    num_fds);
  3371.     }
  3372.  
  3373.     RETURN(result);
  3374.     return(result);
  3375. }
  3376.  
  3377. /******************************************************************************/
  3378.  
  3379. int
  3380. amiga_sendto(int sockfd,VOID *buff,int len,int flags,struct sockaddr *to,int tolen)
  3381. {
  3382.     struct UFB * ufb;
  3383.     int result = ERROR;
  3384.  
  3385.     chkabort();
  3386.  
  3387.     ASSERT(buff != NULL && to != NULL);
  3388.  
  3389.     ENTER();
  3390.     SHOWVALUE(sockfd);
  3391.     SHOWVALUE(buff);
  3392.     SHOWVALUE(len);
  3393.     SHOWVALUE(flags);
  3394.     SHOWVALUE(to);
  3395.     SHOWVALUE(tolen);
  3396.  
  3397.     ufb = chkufb(sockfd);
  3398.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3399.         result = sendto(ufb->ufbfh,buff,len,flags,to,tolen);
  3400.     else
  3401.         errno = ENOTSOCK;
  3402.  
  3403.     RETURN(result);
  3404.     return(result);
  3405. }
  3406.  
  3407. /******************************************************************************/
  3408.  
  3409. int
  3410. amiga_setsockopt(int sockfd,int level,int optname,VOID *optval,int optlen)
  3411. {
  3412.     struct UFB * ufb;
  3413.     int result = ERROR;
  3414.  
  3415.     chkabort();
  3416.  
  3417.     ASSERT(optval != NULL);
  3418.  
  3419.     ENTER();
  3420.     SHOWVALUE(sockfd);
  3421.     SHOWVALUE(level);
  3422.     SHOWVALUE(optname);
  3423.     SHOWVALUE(optval);
  3424.     SHOWVALUE(optlen);
  3425.  
  3426.     ufb = chkufb(sockfd);
  3427.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3428.         result = setsockopt(ufb->ufbfh,level,optname,optval,optlen);
  3429.     else
  3430.         errno = ENOTSOCK;
  3431.  
  3432.     RETURN(result);
  3433.     return(result);
  3434. }
  3435.  
  3436. /******************************************************************************/
  3437.  
  3438. int
  3439. amiga_socket(int domain,int type,int protocol)
  3440. {
  3441.     int result = ERROR;
  3442.     int fd;
  3443.  
  3444.     chkabort();
  3445.  
  3446.     ENTER();
  3447.     SHOWVALUE(domain);
  3448.     SHOWVALUE(type);
  3449.     SHOWVALUE(protocol);
  3450.  
  3451.     /* We open a regular file that is guaranteed to
  3452.      * open in any case and then attach a socket
  3453.      * in place of the original file handle.
  3454.      */
  3455.     fd = open("NIL:",O_RDWR,0777);
  3456.     if(fd != -1)
  3457.     {
  3458.         struct UFB * ufb;
  3459.  
  3460.         ufb = chkufb(fd);
  3461.         if(ufb != NULL)
  3462.         {
  3463.             /* Save the original file handle value. */
  3464.             if(SaveDescriptor(ufb))
  3465.             {
  3466.                 int sockfd;
  3467.  
  3468.                 /* Now create the real socket. */
  3469.                 sockfd = socket(domain,type,protocol);
  3470.                 if(sockfd != -1)
  3471.                 {
  3472.                     /* Put the socket in place of the file handle. */
  3473.                     SET_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  3474.                     ufb->ufbfh = sockfd;
  3475.  
  3476.                     result = fd;
  3477.                 }
  3478.                 else
  3479.                 {
  3480.                     close(fd);
  3481.                 }
  3482.             }
  3483.             else
  3484.             {
  3485.                 close(fd);
  3486.                 errno = ENOMEM;
  3487.             }
  3488.         }
  3489.         else
  3490.         {
  3491.             close(fd);
  3492.             errno = EBADF;
  3493.         }
  3494.     }
  3495.  
  3496.     RETURN(result);
  3497.     return(result);
  3498. }
  3499.  
  3500. /******************************************************************************/
  3501.  
  3502. int
  3503. amiga_write(int fd,VOID *data,unsigned int size)
  3504. {
  3505.     struct UFB * ufb;
  3506.     int result;
  3507.  
  3508.     chkabort();
  3509.  
  3510.     ASSERT(data != NULL);
  3511.  
  3512.     ENTER();
  3513.     SHOWVALUE(fd);
  3514.     SHOWVALUE(data);
  3515.     SHOWVALUE(size);
  3516.  
  3517.     ufb = chkufb(fd);
  3518.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3519.     {
  3520.         result = send(ufb->ufbfh,data,size,0);
  3521.     }
  3522.     else
  3523.     {
  3524.         ForbidDOS();
  3525.         result = write(fd,data,size);
  3526.         PermitDOS();
  3527.     }
  3528.  
  3529.     RETURN(result);
  3530.     return(result);
  3531. }
  3532.  
  3533. /******************************************************************************/
  3534.  
  3535. STATIC VOID
  3536. ConvertFileInfoToStat(
  3537.     struct MsgPort * port,
  3538.     struct FileInfoBlock * fib,
  3539.     struct stat * st)
  3540. {
  3541.     ULONG flags;
  3542.     int mode;
  3543.     long time;
  3544.  
  3545.     /* This routine converts the contents of a FileInfoBlock
  3546.      * into information to fill a Unix-like stat data structure
  3547.      * with.
  3548.      */
  3549.     flags = fib->fib_Protection ^ (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
  3550.  
  3551.     if(FIB_IS_DRAWER(fib))
  3552.         mode = S_IFDIR;
  3553.     else
  3554.         mode = S_IFREG;
  3555.  
  3556.     if(FLAG_IS_SET(flags,FIBF_READ))
  3557.         SET_FLAG(mode,S_IRUSR);
  3558.  
  3559.     if(FLAG_IS_SET(flags,FIBF_WRITE) && FLAG_IS_SET(flags,FIBF_DELETE))
  3560.         SET_FLAG(mode,S_IWUSR);
  3561.  
  3562.     if(FLAG_IS_SET(flags,FIBF_EXECUTE))
  3563.         SET_FLAG(mode,S_IXUSR);
  3564.  
  3565.  
  3566.     if(FLAG_IS_SET(flags,FIBF_GRP_READ))
  3567.         SET_FLAG(mode,S_IRGRP);
  3568.  
  3569.     if(FLAG_IS_SET(flags,FIBF_GRP_WRITE) && FLAG_IS_SET(flags,FIBF_GRP_DELETE))
  3570.         SET_FLAG(mode,S_IWGRP);
  3571.  
  3572.     if(FLAG_IS_SET(flags,FIBF_GRP_EXECUTE))
  3573.         SET_FLAG(mode,S_IXGRP);
  3574.  
  3575.  
  3576.     if(FLAG_IS_SET(flags,FIBF_OTR_READ))
  3577.         SET_FLAG(mode,S_IROTH);
  3578.  
  3579.     if(FLAG_IS_SET(flags,FIBF_OTR_WRITE) && FLAG_IS_SET(flags,FIBF_OTR_DELETE))
  3580.         SET_FLAG(mode,S_IWOTH);
  3581.  
  3582.     if(FLAG_IS_SET(flags,FIBF_OTR_EXECUTE))
  3583.         SET_FLAG(mode,S_IXOTH);
  3584.  
  3585.     time = fib->fib_Date.ds_Days * 24*60*60 +
  3586.            fib->fib_Date.ds_Minute * 60 +
  3587.           (fib->fib_Date.ds_Tick / TICKS_PER_SECOND);
  3588.  
  3589.     memset(st,0,sizeof(*st));
  3590.  
  3591.     st->st_dev        = (u_long)port;
  3592.     st->st_ino        = fib->fib_DiskKey;
  3593.     st->st_mode        = mode;
  3594.     st->st_mtime    = UNIX_TIME_OFFSET + time + 60*MinutesWest;    /* translate from local time to UTC */
  3595.     st->st_atime    = st->st_mtime;
  3596.     st->st_ctime    = st->st_mtime;
  3597.     st->st_uid        = fib->fib_OwnerUID;
  3598.     st->st_gid        = fib->fib_OwnerGID;
  3599.  
  3600.     if(FIB_IS_FILE(fib))
  3601.     {
  3602.         st->st_nlink = 1;
  3603.         st->st_size  = fib->fib_Size;
  3604.     }
  3605.     else
  3606.     {
  3607.         st->st_nlink = 2;
  3608.     }
  3609. }
  3610.  
  3611. int
  3612. amiga_stat(char *name, struct stat *st)
  3613. {
  3614.     char localName[MAX_FILENAME_LEN];
  3615.     struct MangleInfo mi;
  3616.     int result = ERROR;
  3617.  
  3618.     chkabort();
  3619.  
  3620.     ASSERT(name != NULL && st != NULL);
  3621.  
  3622.     ENTER();
  3623.     SHOWSTRING(name);
  3624.     SHOWVALUE(st);
  3625.  
  3626.     if(TranslateRelativePath(&name,localName,sizeof(localName)) == OK)
  3627.     {
  3628.         char * originalName = name;
  3629.  
  3630.         if(MangleName(&name,&mi) == OK)
  3631.         {
  3632.             int len;
  3633.  
  3634.             SHOWSTRING(name);
  3635.             SHOWSTRING(originalName);
  3636.  
  3637.             len = strlen(name);
  3638.             if((strcmp(originalName,"/") == SAME) || (len > 1 && name[len-2] == ':' && name[len-1] == '/'))
  3639.             {
  3640.                 struct timeval now;
  3641.  
  3642.                 SHOWMSG("this is the virtual root directory");
  3643.  
  3644.                 /* This must be our virtual root directory.
  3645.                  * Make something up.
  3646.                  */
  3647.                 memset(st,0,sizeof(*st));
  3648.                 GetSysTime((APTR)&now);
  3649.  
  3650.                 /* Nobody may write to this "directory". */
  3651.                 st->st_dev        = (u_long)"Virtual Root Directory";
  3652.                 st->st_ino        = 1;
  3653.                 st->st_mode        = S_IFDIR|S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  3654.                 st->st_nlink    = 2;
  3655.                 st->st_mtime    = UNIX_TIME_OFFSET + now.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  3656.                 st->st_atime    = st->st_mtime;
  3657.                 st->st_ctime    = st->st_mtime;
  3658.  
  3659.                 result = OK;
  3660.             }
  3661.             else
  3662.             {
  3663.                 BPTR fileLock;
  3664.  
  3665.                 SHOWMSG("this is a drawer or a file");
  3666.  
  3667.                 ForbidDOS();
  3668.  
  3669.                 fileLock = Lock((STRPTR)name,SHARED_LOCK);
  3670.                 if(fileLock != ZERO)
  3671.                 {
  3672.                     struct FileInfoBlock __aligned fib;
  3673.  
  3674.                     if(Examine(fileLock,&fib))
  3675.                     {
  3676.                         BPTR parentDir;
  3677.  
  3678.                         /* Check if this is the root directory. */
  3679.                         parentDir = ParentDir(fileLock);
  3680.                         if(parentDir != ZERO)
  3681.                         {
  3682.                             /* This is not the root directory. */
  3683.                             UnLock(parentDir);
  3684.                         }
  3685.                         else
  3686.                         {
  3687.                             /* So this is the root directory. Make sure
  3688.                              * that we return proper protection bits for
  3689.                              * it, i.e. that the directory is always
  3690.                              * readable, writable, etc. This may be
  3691.                              * necessary since on the Amiga, root
  3692.                              * directories cannot have any protection
  3693.                              * bits set. Note that the "deletable"
  3694.                              * bits don't make much sense, but then
  3695.                              * these bits work together with the
  3696.                              * writable bits. The lowest four bits
  3697.                              * remain zero, which enables them all.
  3698.                              */
  3699.                             fib.fib_Protection = FIBF_OTR_READ |
  3700.                                                  FIBF_OTR_WRITE |
  3701.                                                  FIBF_OTR_EXECUTE |
  3702.                                                  FIBF_OTR_DELETE |
  3703.                                                  FIBF_GRP_READ |
  3704.                                                  FIBF_GRP_WRITE |
  3705.                                                  FIBF_GRP_EXECUTE |
  3706.                                                  FIBF_GRP_DELETE;
  3707.                         }
  3708.  
  3709.                         ConvertFileInfoToStat(((struct FileLock *)BADDR(fileLock))->fl_Task,&fib,st);
  3710.  
  3711.                         result = OK;
  3712.                     }
  3713.                     else
  3714.                     {
  3715.                         MapIoErrToErrno();
  3716.                     }
  3717.  
  3718.                     UnLock(fileLock);
  3719.                 }
  3720.                 else
  3721.                 {
  3722.                     LONG error = IoErr();
  3723.  
  3724.                     if(error == ERROR_OBJECT_IN_USE)
  3725.                     {
  3726.                         char parentName[MAX_FILENAME_LEN];
  3727.                         BPTR parentLock;
  3728.  
  3729.                         strcpy(parentName,name);
  3730.                         (*PathPart(parentName) = '\0');
  3731.  
  3732.                         parentLock = Lock(parentName,SHARED_LOCK);
  3733.                         if(parentLock != ZERO)
  3734.                         {
  3735.                             struct FileInfoBlock __aligned fib;
  3736.  
  3737.                             if(Examine(parentLock,&fib))
  3738.                             {
  3739.                                 STRPTR onlyFileName = FilePart(name);
  3740.  
  3741.                                 while(ExNext(parentLock,&fib))
  3742.                                 {
  3743.                                     if(Stricmp(fib.fib_FileName,onlyFileName) == SAME)
  3744.                                     {
  3745.                                         ConvertFileInfoToStat(((struct FileLock *)BADDR(parentLock))->fl_Task,&fib,st);
  3746.  
  3747.                                         result = OK;
  3748.                                         error = OK;
  3749.                                         break;
  3750.                                     }
  3751.                                 }
  3752.                             }
  3753.  
  3754.                             UnLock(parentLock);
  3755.                         }
  3756.                     }
  3757.  
  3758.                     if(error != OK)
  3759.                     {
  3760.                         SetIoErr(error);
  3761.  
  3762.                         MapIoErrToErrno();
  3763.                     }
  3764.                 }
  3765.  
  3766.                 PermitDOS();
  3767.             }
  3768.  
  3769.             if(result == OK)
  3770.             {
  3771.                 SHOWVALUE(st->st_dev);
  3772.                 SHOWVALUE(st->st_ino);
  3773.                 SHOWVALUE(st->st_size);
  3774.                 SHOWVALUE(st->st_nlink);
  3775.                 SHOWVALUE(st->st_mode);
  3776.                 SHOWVALUE(st->st_mtime);
  3777.                 SHOWVALUE(st->st_atime);
  3778.                 SHOWVALUE(st->st_ctime);
  3779.                 SHOWVALUE(st->st_uid);
  3780.                 SHOWVALUE(st->st_gid);
  3781.             }
  3782.             else
  3783.             {
  3784.                 SHOWVALUE(errno);
  3785.             }
  3786.  
  3787.             UnmangleName(&name,&mi);
  3788.         }
  3789.     }
  3790.  
  3791.     RETURN(result);
  3792.     return(result);
  3793. }
  3794.  
  3795. int
  3796. amiga_lstat(char *name, struct stat *statstruct)
  3797. {
  3798.     int result;
  3799.  
  3800.     chkabort();
  3801.  
  3802.     ENTER();
  3803.     SHOWSTRING(name);
  3804.     SHOWVALUE(statstruct);
  3805.  
  3806.     result = amiga_stat(name,statstruct);
  3807.  
  3808.     RETURN(result);
  3809.     return(result);
  3810. }
  3811.  
  3812. int
  3813. amiga_fstat(int fd,struct stat * st)
  3814. {
  3815.     struct UFB * ufb;
  3816.     int result = ERROR;
  3817.  
  3818.     chkabort();
  3819.  
  3820.     ASSERT(st != NULL);
  3821.  
  3822.     ENTER();
  3823.     SHOWVALUE(fd);
  3824.     SHOWVALUE(st);
  3825.  
  3826.     ufb = chkufb(fd);
  3827.     if(ufb != NULL)
  3828.     {
  3829.         if(FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3830.         {
  3831.             long value;
  3832.             long size = sizeof(value);
  3833.  
  3834.             memset(st,0,sizeof(*st));
  3835.  
  3836.             st->st_dev    = (u_long)SocketBase;
  3837.             st->st_mode    = S_IFSOCK | S_IRUSR | S_IWUSR;
  3838.             st->st_uid    = geteuid();
  3839.             st->st_gid    = getegid();
  3840.  
  3841.             if(getsockopt(fd,SOL_SOCKET,SO_SNDBUF,&value,&size) == 0)
  3842.                 st->st_blksize = value;
  3843.  
  3844.             result = OK;
  3845.         }
  3846.         else
  3847.         {
  3848.             struct FileHandle * fileHandle = BADDR(ufb->ufbfh);
  3849.  
  3850.             /* Make sure that this stream doesn't
  3851.              * really refer to "NIL:".
  3852.              */
  3853.             if(fileHandle->fh_Type != NULL)
  3854.             {
  3855.                 struct FileInfoBlock __aligned fib;
  3856.  
  3857.                 ForbidDOS();
  3858.  
  3859.                 if(ExamineFH(ufb->ufbfh,&fib))
  3860.                 {
  3861.                     ConvertFileInfoToStat(fileHandle->fh_Type,&fib,st);
  3862.  
  3863.                     result = OK;
  3864.                 }
  3865.                 else
  3866.                 {
  3867.                     MapIoErrToErrno();
  3868.                 }
  3869.  
  3870.                 PermitDOS();
  3871.             }
  3872.             else
  3873.             {
  3874.                 struct timeval tv;
  3875.  
  3876.                 /* Make up some phony data for a NIL: file handle. */
  3877.                 memset(st,0,sizeof(*st));
  3878.  
  3879.                 GetSysTime((APTR)&tv);
  3880.  
  3881.                 st->st_dev        = (u_long)0;
  3882.                 st->st_mode        = S_IFREG | S_IRUSR | S_IWUSR;
  3883.                 st->st_mtime    = UNIX_TIME_OFFSET + tv.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  3884.                 st->st_atime    = st->st_mtime;
  3885.                 st->st_ctime    = st->st_mtime;
  3886.  
  3887.                 result = OK;
  3888.             }
  3889.         }
  3890.     }
  3891.     else
  3892.     {
  3893.         errno = EBADF;
  3894.     }
  3895.  
  3896.     RETURN(result);
  3897.     return(result);
  3898. }
  3899.  
  3900. /******************************************************************************/
  3901.  
  3902. int
  3903. amiga_chmod(char *name,int mode)
  3904. {
  3905.     struct MangleInfo mi;
  3906.     ULONG flags = 0;
  3907.     int result = ERROR;
  3908.  
  3909.     chkabort();
  3910.  
  3911.     ASSERT(name != NULL);
  3912.  
  3913.     ENTER();
  3914.     SHOWSTRING(name);
  3915.     SHOWVALUE(mode);
  3916.  
  3917.     /* Convert the file access modes into
  3918.      * Amiga typical protection bits.
  3919.      */
  3920.     if(FLAG_IS_SET(mode,S_IRUSR))
  3921.         SET_FLAG(flags,FIBF_READ);
  3922.  
  3923.     if(FLAG_IS_SET(mode,S_IWUSR))
  3924.     {
  3925.         SET_FLAG(flags,FIBF_WRITE);
  3926.         SET_FLAG(flags,FIBF_DELETE);
  3927.     }
  3928.  
  3929.     if(FLAG_IS_SET(mode,S_IXUSR))
  3930.         SET_FLAG(flags,FIBF_EXECUTE);
  3931.  
  3932.  
  3933.     if(FLAG_IS_SET(mode,S_IRGRP))
  3934.         SET_FLAG(flags,FIBF_GRP_READ);
  3935.  
  3936.     if(FLAG_IS_SET(mode,S_IWGRP))
  3937.     {
  3938.         SET_FLAG(flags,FIBF_GRP_WRITE);
  3939.         SET_FLAG(flags,FIBF_GRP_DELETE);
  3940.     }
  3941.  
  3942.     if(FLAG_IS_SET(mode,S_IXGRP))
  3943.         SET_FLAG(flags,FIBF_GRP_EXECUTE);
  3944.  
  3945.  
  3946.     if(FLAG_IS_SET(mode,S_IROTH))
  3947.         SET_FLAG(flags,FIBF_OTR_READ);
  3948.  
  3949.     if(FLAG_IS_SET(mode,S_IWOTH))
  3950.     {
  3951.         SET_FLAG(flags,FIBF_OTR_WRITE);
  3952.         SET_FLAG(flags,FIBF_OTR_DELETE);
  3953.     }
  3954.  
  3955.     if(FLAG_IS_SET(mode,S_IXOTH))
  3956.         SET_FLAG(flags,FIBF_OTR_EXECUTE);
  3957.  
  3958.     flags ^= (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
  3959.  
  3960.     if(MangleName(&name,&mi) == OK)
  3961.     {
  3962.         ForbidDOS();
  3963.  
  3964.         if(SetProtection(name,flags))
  3965.         {
  3966.             result = OK;
  3967.         }
  3968.         else
  3969.         {
  3970.             LONG error = IoErr();
  3971.  
  3972.             /* Note sure about this one; is it really that important
  3973.              * that the file attribute change succeeds? This is a definite
  3974.              * FIXME.
  3975.              */
  3976.             if(error == ERROR_OBJECT_IN_USE)
  3977.             {
  3978.                 result = OK;
  3979.             }
  3980.             else
  3981.             {
  3982.                 SetIoErr(error);
  3983.  
  3984.                 MapIoErrToErrno();
  3985.             }
  3986.         }
  3987.  
  3988.         PermitDOS();
  3989.  
  3990.         UnmangleName(&name,&mi);
  3991.     }
  3992.  
  3993.     RETURN(result);
  3994.     return(result);
  3995. }
  3996.  
  3997. /******************************************************************************/
  3998.  
  3999. int
  4000. amiga_dup(int fd)
  4001. {
  4002.     struct UFB * ufb;
  4003.     int result = ERROR;
  4004.  
  4005.     chkabort();
  4006.  
  4007.     ENTER();
  4008.     SHOWVALUE(fd);
  4009.  
  4010.     ufb = chkufb(fd);
  4011.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  4012.     {
  4013.         fd = open("NIL:",O_RDWR,0777);
  4014.         if(fd != -1)
  4015.         {
  4016.             struct UFB * ufb2;
  4017.  
  4018.             ufb2 = chkufb(fd);
  4019.             if(ufb2 != NULL)
  4020.             {
  4021.                 if(SaveDescriptor(ufb2))
  4022.                 {
  4023.                     int sockfd;
  4024.  
  4025.                     sockfd = Dup2Socket(ufb->ufbfh,-1);
  4026.                     if(sockfd != -1)
  4027.                     {
  4028.                         SET_FLAG(ufb2->ufbflg,UFB_IS_SOCKET);
  4029.                         ufb2->ufbfh = sockfd;
  4030.  
  4031.                         result = fd;
  4032.                     }
  4033.                     else
  4034.                     {
  4035.                         close(fd);
  4036.                     }
  4037.                 }
  4038.                 else
  4039.                 {
  4040.                     close(fd);
  4041.                     errno = ENOMEM;
  4042.                 }
  4043.             }
  4044.             else
  4045.             {
  4046.                 close(fd);
  4047.                 errno = EBADF;
  4048.             }
  4049.         }
  4050.     }
  4051.     else
  4052.     {
  4053.         errno = ENOTSOCK;
  4054.     }
  4055.  
  4056.     RETURN(result);
  4057.     return(result);
  4058. }
  4059.  
  4060. /******************************************************************************/
  4061.  
  4062. int
  4063. amiga_dup2(int old_fd,int new_fd)
  4064. {
  4065.     struct UFB * old_ufb;
  4066.     struct UFB * new_ufb;
  4067.     int result = ERROR;
  4068.  
  4069.     chkabort();
  4070.  
  4071.     ENTER();
  4072.     SHOWVALUE(old_fd);
  4073.     SHOWVALUE(new_fd);
  4074.  
  4075.     old_ufb = chkufb(old_fd);
  4076.     new_ufb = chkufb(new_fd);
  4077.  
  4078.     if(old_ufb != NULL && FLAG_IS_SET(old_ufb->ufbflg,UFB_IS_SOCKET) && new_ufb != NULL)
  4079.     {
  4080.         int sockfd;
  4081.  
  4082.         if(FLAG_IS_SET(new_ufb->ufbflg,UFB_IS_SOCKET))
  4083.         {
  4084.             CloseSocket(new_ufb->ufbfh);
  4085.             sockfd = Dup2Socket(old_ufb->ufbfh,new_ufb->ufbfh);
  4086.         }
  4087.         else
  4088.         {
  4089.             if(SaveDescriptor(new_ufb))
  4090.             {
  4091.                 sockfd = Dup2Socket(old_ufb->ufbfh,-1);
  4092.             }
  4093.             else
  4094.             {
  4095.                 sockfd = -1;
  4096.                 errno = ENOMEM;
  4097.             }
  4098.         }
  4099.  
  4100.         if(sockfd != -1)
  4101.         {
  4102.             SET_FLAG(new_ufb->ufbflg,UFB_IS_SOCKET);
  4103.             new_ufb->ufbfh = sockfd;
  4104.  
  4105.             result = new_fd;
  4106.         }
  4107.     }
  4108.     else
  4109.     {
  4110.         errno = ENOTSOCK;
  4111.     }
  4112.  
  4113.     RETURN(result);
  4114.     return(result);
  4115. }
  4116.  
  4117. /******************************************************************************/
  4118.  
  4119. int
  4120. amiga_chown(char *name,uid_t uid,gid_t gid)
  4121. {
  4122.     struct MangleInfo mi;
  4123.     int result = ERROR;
  4124.  
  4125.     chkabort();
  4126.  
  4127.     ASSERT(name != NULL);
  4128.  
  4129.     ENTER();
  4130.     SHOWSTRING(name);
  4131.     SHOWVALUE(uid);
  4132.     SHOWVALUE(gid);
  4133.  
  4134.     if(MangleName(&name,&mi) == OK)
  4135.     {
  4136.         /* AmigaDOS 3.0 and up have a SetOwner() call. */
  4137.         if(DOSBase->lib_Version >= 39)
  4138.         {
  4139.             if(SetOwner(name,(((LONG)uid) << 16) | gid))
  4140.                 result = OK;
  4141.             else
  4142.                 MapIoErrToErrno();
  4143.         }
  4144.         else
  4145.         {
  4146.             struct DevProc * dvp;
  4147.  
  4148.             /* For 2.04 and 2.1 we'll have to do this
  4149.              * manually...
  4150.              */
  4151.             dvp = GetDeviceProc(name,NULL);
  4152.             if(dvp != NULL)
  4153.             {
  4154.                 char __aligned newName[MAX_BSTR_LEN];
  4155.  
  4156.                 newName[0] = strlen(name);
  4157.                 strncpy(&newName[1],name,newName[0]);
  4158.  
  4159.                 /* This is almost identical in operation to ACTION_SET_PROTECTION. */
  4160.                 if(DoPkt(dvp->dvp_Port,ACTION_SET_OWNER,dvp->dvp_Lock,MKBADDR(newName),(((LONG)uid) << 16) | gid,0,0))
  4161.                     result = OK;
  4162.                 else
  4163.                     MapIoErrToErrno();
  4164.  
  4165.                 FreeDeviceProc(dvp);
  4166.             }
  4167.             else
  4168.             {
  4169.                 MapIoErrToErrno();
  4170.             }
  4171.         }
  4172.  
  4173.         UnmangleName(&name,&mi);
  4174.     }
  4175.  
  4176.     RETURN(result);
  4177.     return(result);
  4178. }
  4179.  
  4180. /******************************************************************************/
  4181.  
  4182. int
  4183. amiga_setegid(gid_t g)
  4184. {
  4185.     int result;
  4186.  
  4187.     chkabort();
  4188.  
  4189.     ENTER();
  4190.     SHOWVALUE(g);
  4191.  
  4192.     result = setregid(-1,g);
  4193.  
  4194.     RETURN(result);
  4195.     return(result);
  4196. }
  4197.  
  4198. /******************************************************************************/
  4199.  
  4200. int
  4201. amiga_seteuid(uid_t u)
  4202. {
  4203.     int result;
  4204.  
  4205.     chkabort();
  4206.  
  4207.     ENTER();
  4208.     SHOWVALUE(u);
  4209.     result = setreuid(-1,u);
  4210.  
  4211.     RETURN(result);
  4212.     return(result);
  4213. }
  4214.  
  4215. /******************************************************************************/
  4216.  
  4217. int
  4218. amiga_gettimeofday(struct timeval *tv)
  4219. {
  4220.     chkabort();
  4221.  
  4222.     ENTER();
  4223.     SHOWVALUE(tv);
  4224.  
  4225.     if(tv != NULL)
  4226.     {
  4227.         GetSysTime((APTR)tv);
  4228.         tv->tv_secs += UNIX_TIME_OFFSET + 60*MinutesWest;    /* translate from local time to UTC */
  4229.  
  4230.         SHOWVALUE(tv->tv_secs);
  4231.         SHOWVALUE(tv->tv_micro);
  4232.     }
  4233.  
  4234.     RETURN(0);
  4235.     return(0);
  4236. }
  4237.  
  4238. /******************************************************************************/
  4239.  
  4240. int
  4241. amiga_utime(char *name,struct utimbuf *time)
  4242. {
  4243.     struct MangleInfo mi;
  4244.     struct DateStamp ds;
  4245.     int result = ERROR;
  4246.  
  4247.     chkabort();
  4248.  
  4249.     ASSERT(name != NULL);
  4250.  
  4251.     ENTER();
  4252.     SHOWSTRING(name);
  4253.     SHOWVALUE(time);
  4254.  
  4255.     /* Use the current time? */
  4256.     if(time == NULL)
  4257.     {
  4258.         DateStamp(&ds);
  4259.     }
  4260.     else
  4261.     {
  4262.         ULONG seconds;
  4263.  
  4264.         /* Convert the time given. */
  4265.         if(time->modtime < (UNIX_TIME_OFFSET + 60*MinutesWest))
  4266.             seconds = 0;
  4267.         else
  4268.             seconds = time->modtime - (UNIX_TIME_OFFSET + 60*MinutesWest);    /* translate from UTC to local time */
  4269.  
  4270.         ds.ds_Days        = (seconds / (24*60*60));
  4271.         ds.ds_Minute    = (seconds % (24*60*60)) / 60;
  4272.         ds.ds_Tick        = (seconds               % 60) * TICKS_PER_SECOND;
  4273.     }
  4274.  
  4275.     if(MangleName(&name,&mi) == OK)
  4276.     {
  4277.         ForbidDOS();
  4278.  
  4279.         if(SetFileDate((STRPTR)name,&ds))
  4280.         {
  4281.             result = OK;
  4282.         }
  4283.         else
  4284.         {
  4285.             LONG error = IoErr();
  4286.  
  4287.             /* Note sure about this one; is it really that important
  4288.              * that the file date change succeeds? This is a definite
  4289.              * FIXME.
  4290.              */
  4291.             if(error == ERROR_OBJECT_IN_USE)
  4292.             {
  4293.                 result = OK;
  4294.             }
  4295.             else
  4296.             {
  4297.                 SetIoErr(error);
  4298.  
  4299.                 MapIoErrToErrno();
  4300.             }
  4301.         }
  4302.  
  4303.         PermitDOS();
  4304.  
  4305.         UnmangleName(&name,&mi);
  4306.     }
  4307.  
  4308.     RETURN(result);
  4309.     return(result);
  4310. }
  4311.  
  4312. /******************************************************************************/
  4313.  
  4314. VOID
  4315. amiga_sleep(unsigned int seconds)
  4316. {
  4317.     chkabort();
  4318.  
  4319.     ENTER();
  4320.     SHOWVALUE(seconds);
  4321.  
  4322.     if(seconds > 0)
  4323.     {
  4324.         ULONG timerSignal = (1UL << TimerPort->mp_SigBit);
  4325.         ULONG signalsReceived;
  4326.         ULONG signalsToWaitFor;
  4327.  
  4328.         TimerRequest->tr_node.io_Command    = TR_ADDREQUEST;
  4329.         TimerRequest->tr_time.tv_secs        = seconds;
  4330.         TimerRequest->tr_time.tv_micro        = 0;
  4331.  
  4332.         SetSignal(0,timerSignal);
  4333.         SendIO((struct IORequest *)TimerRequest);
  4334.  
  4335.         signalsToWaitFor = timerSignal;
  4336.         if(AllowBreak)
  4337.             signalsToWaitFor |= SIGBREAKF_CTRL_C;
  4338.  
  4339.         signalsReceived = Wait(signalsToWaitFor);
  4340.  
  4341.         /* Did we get a break signal while we were sleeping? */
  4342.         if(FLAG_IS_SET(signalsReceived,SIGBREAKF_CTRL_C))
  4343.         {
  4344.             if(CheckIO((struct IORequest *)TimerRequest) == BUSY)
  4345.                 AbortIO((struct IORequest *)TimerRequest);
  4346.  
  4347.             WaitIO((struct IORequest *)TimerRequest);
  4348.  
  4349.             /* And pull the brakes... */
  4350.             raise(SIGINT);
  4351.         }
  4352.  
  4353.         /* Proper termination. */
  4354.         if(FLAG_IS_SET(signalsReceived,timerSignal))
  4355.         {
  4356.             WaitIO((struct IORequest *)TimerRequest);
  4357.         }
  4358.     }
  4359.  
  4360.     LEAVE();
  4361. }
  4362.  
  4363. /******************************************************************************/
  4364.  
  4365. char *
  4366. amiga_crypt(char *key,char *salt)
  4367. {
  4368.     char *result;
  4369.  
  4370.     chkabort();
  4371.  
  4372.     ASSERT(key != NULL && salt != NULL);
  4373.  
  4374.     ENTER();
  4375.     SHOWSTRING(key);
  4376.     SHOWVALUE(salt);
  4377.     result = crypt(key,salt);
  4378.  
  4379.     RETURN(result);
  4380.     return(result);
  4381. }
  4382.  
  4383. /******************************************************************************/
  4384.  
  4385. char *
  4386. amiga_getpass(char *prompt)
  4387. {
  4388.     char *result;
  4389.  
  4390.     chkabort();
  4391.  
  4392.     ENTER();
  4393.     SHOWSTRING(prompt);
  4394.     result = getpass(prompt);
  4395.  
  4396.     RETURN(result);
  4397.     return(result);
  4398. }
  4399.  
  4400. /******************************************************************************/
  4401.  
  4402. int
  4403. amiga_setgid(gid_t id)
  4404. {
  4405.     int result;
  4406.  
  4407.     chkabort();
  4408.  
  4409.     ENTER();
  4410.     SHOWVALUE(id);
  4411.     result = setgid(id);
  4412.  
  4413.     RETURN(result);
  4414.     return(result);
  4415. }
  4416.  
  4417. /******************************************************************************/
  4418.  
  4419. int
  4420. amiga_setgroups(int ngroups,gid_t *groups)
  4421. {
  4422.     int result;
  4423.  
  4424.     chkabort();
  4425.  
  4426.     ASSERT(groups != NULL);
  4427.  
  4428.     ENTER();
  4429.     SHOWVALUE(ngroups);
  4430.     SHOWVALUE(groups);
  4431.  
  4432.     result = setgroups(ngroups,groups);
  4433.  
  4434.     RETURN(result);
  4435.     return(result);
  4436. }
  4437.  
  4438. /******************************************************************************/
  4439.  
  4440. gid_t
  4441. amiga_getgid(VOID)
  4442. {
  4443.     int result;
  4444.  
  4445.     chkabort();
  4446.  
  4447.     ENTER();
  4448.     result = getgid();
  4449.  
  4450.     RETURN(result);
  4451.     return(result);
  4452. }
  4453.  
  4454. /******************************************************************************/
  4455.  
  4456. struct group *
  4457. amiga_getgrgid(gid_t gid)
  4458. {
  4459.     struct group *result;
  4460.  
  4461.     chkabort();
  4462.  
  4463.     ENTER();
  4464.     SHOWVALUE(gid);
  4465.  
  4466.     result = getgrgid(gid);
  4467.  
  4468.     RETURN(result);
  4469.     return(result);
  4470. }
  4471.  
  4472. /******************************************************************************/
  4473.  
  4474. struct group *
  4475. amiga_getgrnam(char * name)
  4476. {
  4477.     struct group *result;
  4478.  
  4479.     chkabort();
  4480.  
  4481.     ASSERT(name != NULL);
  4482.  
  4483.     ENTER();
  4484.     SHOWSTRING(name);
  4485.  
  4486.     result = getgrnam(name);
  4487.  
  4488.     RETURN(result);
  4489.     return(result);
  4490. }
  4491.  
  4492. /******************************************************************************/
  4493.  
  4494. int
  4495. amiga_getgroups(int ngroups, gid_t *groups)
  4496. {
  4497.     int result;
  4498.  
  4499.     chkabort();
  4500.  
  4501.     ASSERT(groups != NULL);
  4502.  
  4503.     ENTER();
  4504.     SHOWVALUE(ngroups);
  4505.     SHOWVALUE(groups);
  4506.  
  4507.     result = getgroups(ngroups,groups);
  4508.  
  4509.     RETURN(result);
  4510.     return(result);
  4511. }
  4512.  
  4513. /******************************************************************************/
  4514.  
  4515. struct hostent *
  4516. amiga_gethostbyaddr(char *addr, int len, int type)
  4517. {
  4518.     struct hostent *result;
  4519.  
  4520.     chkabort();
  4521.  
  4522.     ASSERT(addr != NULL);
  4523.  
  4524.     ENTER();
  4525.     SHOWVALUE(addr);
  4526.     SHOWVALUE(len);
  4527.     SHOWVALUE(type);
  4528.  
  4529.     result = gethostbyaddr(addr,len,type);
  4530.  
  4531.     RETURN(result);
  4532.     return(result);
  4533. }
  4534.  
  4535. /******************************************************************************/
  4536.  
  4537. struct hostent *
  4538. amiga_gethostbyname(char *name)
  4539. {
  4540.     struct hostent *result;
  4541.  
  4542.     chkabort();
  4543.  
  4544.     ASSERT(name != NULL);
  4545.  
  4546.     ENTER();
  4547.     SHOWSTRING(name);
  4548.  
  4549.     result = gethostbyname(name);
  4550.  
  4551.     RETURN(result);
  4552.     return(result);
  4553. }
  4554.  
  4555. /******************************************************************************/
  4556.  
  4557. struct netent *
  4558. amiga_getnetbyname(char *name)
  4559. {
  4560.     struct netent *result;
  4561.  
  4562.     chkabort();
  4563.  
  4564.     ASSERT(name != NULL);
  4565.  
  4566.     ENTER();
  4567.     SHOWSTRING(name);
  4568.  
  4569.     result = getnetbyname(name);
  4570.  
  4571.     RETURN(result);
  4572.     return(result);
  4573. }
  4574.  
  4575. /******************************************************************************/
  4576.  
  4577. int
  4578. amiga_gethostname(char *hostname,int size)
  4579. {
  4580.     int result;
  4581.  
  4582.     chkabort();
  4583.  
  4584.     ASSERT(hostname != NULL);
  4585.  
  4586.     ENTER();
  4587.     SHOWVALUE(hostname);
  4588.     SHOWVALUE(size);
  4589.  
  4590.     result = gethostname(hostname,size);
  4591.  
  4592.     if(result == 0)
  4593.         SHOWSTRING(hostname);
  4594.  
  4595.     RETURN(result);
  4596.     return(result);
  4597. }
  4598.  
  4599. /******************************************************************************/
  4600.  
  4601. struct passwd *
  4602. amiga_getpwnam(char *name)
  4603. {
  4604.     struct passwd *result;
  4605.  
  4606.     chkabort();
  4607.  
  4608.     ASSERT(name != NULL);
  4609.  
  4610.     ENTER();
  4611.     SHOWSTRING(name);
  4612.  
  4613.     result = getpwnam(name);
  4614.  
  4615.     RETURN(result);
  4616.     return(result);
  4617. }
  4618.  
  4619. /******************************************************************************/
  4620.  
  4621. struct passwd *
  4622. amiga_getpwuid(uid_t uid)
  4623. {
  4624.     struct passwd *result;
  4625.  
  4626.     chkabort();
  4627.  
  4628.     ENTER();
  4629.     SHOWVALUE(uid);
  4630.  
  4631.     result = getpwuid(uid);
  4632.  
  4633.     RETURN(result);
  4634.     return(result);
  4635. }
  4636.  
  4637. /******************************************************************************/
  4638.  
  4639. uid_t
  4640. amiga_getuid(VOID)
  4641. {
  4642.     uid_t result;
  4643.  
  4644.     chkabort();
  4645.  
  4646.     ENTER();
  4647.  
  4648.     result = getuid();
  4649.  
  4650.     RETURN(result);
  4651.     return(result);
  4652. }
  4653.  
  4654. /******************************************************************************/
  4655.  
  4656. gid_t
  4657. amiga_getegid(VOID)
  4658. {
  4659.     gid_t result;
  4660.  
  4661.     chkabort();
  4662.  
  4663.     ENTER();
  4664.     result = getegid();
  4665.  
  4666.     RETURN(result);
  4667.     return(result);
  4668. }
  4669.  
  4670. /******************************************************************************/
  4671.  
  4672. uid_t
  4673. amiga_geteuid(VOID)
  4674. {
  4675.     uid_t result;
  4676.  
  4677.     chkabort();
  4678.  
  4679.     ENTER();
  4680.  
  4681.     result = geteuid();
  4682.  
  4683.     RETURN(result);
  4684.     return(result);
  4685. }
  4686.  
  4687. /******************************************************************************/
  4688.  
  4689. int
  4690. amiga_initgroups(char *name, gid_t basegroup)
  4691. {
  4692.     int result;
  4693.  
  4694.     chkabort();
  4695.  
  4696.     ASSERT(name != NULL);
  4697.  
  4698.     ENTER();
  4699.     SHOWSTRING(name);
  4700.     SHOWVALUE(basegroup);
  4701.  
  4702.     result = initgroups(name,basegroup);
  4703.  
  4704.     RETURN(result);
  4705.     return(result);
  4706. }
  4707.  
  4708. /******************************************************************************/
  4709.  
  4710. int
  4711. amiga_setuid(uid_t id)
  4712. {
  4713.     int result;
  4714.  
  4715.     chkabort();
  4716.  
  4717.     ENTER();
  4718.     SHOWVALUE(id);
  4719.  
  4720.     result = setuid(id);
  4721.  
  4722.     RETURN(result);
  4723.     return(result);
  4724. }
  4725.  
  4726. /******************************************************************************/
  4727.  
  4728. int
  4729. amiga_umask(int mask)
  4730. {
  4731.     int result;
  4732.  
  4733.     chkabort();
  4734.  
  4735.     ENTER();
  4736.     SHOWVALUE(mask);
  4737.  
  4738.     result = umask(mask);
  4739.  
  4740.     RETURN(result);
  4741.     return(result);
  4742. }
  4743.  
  4744. /******************************************************************************/
  4745.  
  4746. unsigned long
  4747. amiga_inet_addr(char *addr)
  4748. {
  4749.     unsigned long result;
  4750.  
  4751.     chkabort();
  4752.  
  4753.     ASSERT(addr != NULL);
  4754.  
  4755.     ENTER();
  4756.     SHOWSTRING(addr);
  4757.  
  4758.     result = inet_addr(addr);
  4759.  
  4760.     RETURN(result);
  4761.     return(result);
  4762. }
  4763.  
  4764. /******************************************************************************/
  4765.  
  4766. char *
  4767. amiga_inet_ntoa(struct in_addr in)
  4768. {
  4769.     char *result;
  4770.  
  4771.     chkabort();
  4772.  
  4773.     ENTER();
  4774.     SHOWVALUE(in.s_addr);
  4775.  
  4776.     result = Inet_NtoA(in.s_addr);
  4777.     SHOWSTRING(result);
  4778.  
  4779.     RETURN(result);
  4780.     return(result);
  4781. }
  4782.  
  4783. /******************************************************************************/
  4784.  
  4785. int    opterr = 1;
  4786. int    optind = 1;
  4787. int    optopt;
  4788. char * optarg;
  4789.  
  4790. int
  4791. amiga_getopt(int argc, char * argv[], char *opts)
  4792. {
  4793.     STATIC int sp = 1;
  4794.     int c;
  4795.     char *cp;
  4796.  
  4797.     ASSERT(argc > 0 && argv != NULL && opts != NULL);
  4798.  
  4799.     if(sp == 1)
  4800.     {
  4801.         if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
  4802.         {
  4803.             return(EOF);
  4804.         }
  4805.         else if(strcmp(argv[optind], "--") == NULL)
  4806.         {
  4807.             optind++;
  4808.             return(EOF);
  4809.         }
  4810.     }
  4811.  
  4812.     optopt = c = argv[optind][sp];
  4813.     if(c == ':' || (cp=index(opts, c)) == NULL)
  4814.     {
  4815.         if(opterr)
  4816.             fprintf(stderr, "%s%s%c\n", argv[0], ": illegal option -- ", c);
  4817.  
  4818.         if(argv[optind][++sp] == '\0')
  4819.         {
  4820.             optind++;
  4821.             sp = 1;
  4822.         }
  4823.  
  4824.         return('?');
  4825.     }
  4826.  
  4827.     if(*++cp == ':')
  4828.     {
  4829.         if(argv[optind][sp+1] != '\0')
  4830.         {
  4831.             optarg = &argv[optind++][sp+1];
  4832.         }
  4833.         else if(++optind >= argc)
  4834.         {
  4835.             if(opterr)
  4836.                 fprintf(stderr, "%s%s%c\n", argv[0], ": option requires an argument -- ", c);
  4837.  
  4838.             sp = 1;
  4839.             return('?');
  4840.         }
  4841.         else
  4842.         {
  4843.             optarg = argv[optind++];
  4844.         }
  4845.  
  4846.         sp = 1;
  4847.     }
  4848.     else
  4849.     {
  4850.         if(argv[optind][++sp] == '\0')
  4851.         {
  4852.             sp = 1;
  4853.             optind++;
  4854.         }
  4855.  
  4856.         optarg = NULL;
  4857.     }
  4858.  
  4859.     return(c);
  4860. }
  4861.  
  4862. /******************************************************************************/
  4863.  
  4864. /* This comes from util/lib.c */
  4865. STATIC BOOL
  4866. do_match(STRPTR str, STRPTR regexp)
  4867. {
  4868.     STRPTR p;
  4869.  
  4870.     for(p = regexp; (*p) != '\0' && (*str) != '\0' ; NULL)
  4871.     {
  4872.         switch(*p)
  4873.         {
  4874.             case '?':
  4875.  
  4876.                 str++;
  4877.                 p++;
  4878.  
  4879.                 break;
  4880.  
  4881.             /* Look for a character matching the one after the '*' */
  4882.             case '*':
  4883.  
  4884.                 p++;
  4885.  
  4886.                 if((*p) == '\0')
  4887.                     return(TRUE); /* Automatic match */
  4888.  
  4889.                 while((*str) != '\0')
  4890.                 {
  4891.                     while((*str) != '\0' && ToUpper(*p) != ToUpper(*str))
  4892.                         str++;
  4893.  
  4894.                     if(do_match(str,p))
  4895.                         return(TRUE);
  4896.  
  4897.                     if((*str) == '\0')
  4898.                         return(FALSE);
  4899.                     else
  4900.                         str++;
  4901.                 }
  4902.  
  4903.                 return(FALSE);
  4904.  
  4905.             default:
  4906.  
  4907.                 if(ToUpper(*str++) != ToUpper(*p++))
  4908.                     return(FALSE);
  4909.  
  4910.                 break;
  4911.         }
  4912.     }
  4913.  
  4914.     if((*p) == '\0' && (*str) == '\0')
  4915.         return(TRUE);
  4916.  
  4917.     if((*p) == '\0' && str[0] == '.' && str[1] == '\0')
  4918.         return(TRUE);
  4919.  
  4920.     if((*str) == '\0' && (*p) == '?')
  4921.     {
  4922.         while((*p) == '?')
  4923.             p++;
  4924.  
  4925.         return((BOOL)((*p) == '\0'));
  4926.     }
  4927.  
  4928.     if((*str) == '\0' && ((*p) == '*' && p[1] == '\0'))
  4929.         return(TRUE);
  4930.  
  4931.     return(FALSE);
  4932. }
  4933.  
  4934. STATIC VOID
  4935. nstrcpy_blank(const size_t maxSize,char *to,const char *from)
  4936. {
  4937.     size_t len = 0;
  4938.  
  4939.     while((*from) != '\0' && (*from) != ' ' && len < maxSize-1)
  4940.     {
  4941.         (*to++) = (*from++);
  4942.         len++;
  4943.     }
  4944.  
  4945.     (*to) = '\0';
  4946. }
  4947.  
  4948. STATIC VOID
  4949. fill_volume_list(struct List * list)
  4950. {
  4951.     struct DosList * dol;
  4952.  
  4953.     dol = NextDosEntry(LockDosList(LDF_VOLUMES|LDF_READ),
  4954.                                    LDF_VOLUMES|LDF_READ);
  4955.     while(dol != NULL)
  4956.     {
  4957.         /* Does the volume refer to a medium that is right
  4958.          * now present in the drive?
  4959.          */
  4960.         if(dol->dol_Task != NULL)
  4961.         {
  4962.             struct InfoData __aligned id;
  4963.  
  4964.             /* Is there a disk present? */
  4965.             if(DoPkt(dol->dol_Task,ACTION_DISK_INFO,MKBADDR(&id),    0,0,0,0))
  4966.             {
  4967.                 STRPTR name = BADDR(dol->dol_Name);
  4968.                 struct Node * node;
  4969.  
  4970.                 node = malloc(sizeof(*node) + ((int)name[0])+1);
  4971.                 if(node != NULL)
  4972.                 {
  4973.                     /* Copy the name of the volume. */
  4974.                     node->ln_Name = (char *)(node + 1);
  4975.                     strncpy(node->ln_Name,&name[1],name[0]);
  4976.                     node->ln_Name[ name[0] ] = '\0';
  4977.  
  4978.                     AddTail(list,node);
  4979.                 }
  4980.             }
  4981.         }
  4982.  
  4983.         dol = NextDosEntry(dol,LDF_VOLUMES|LDF_READ);
  4984.     }
  4985.  
  4986.     UnLockDosList(LDF_VOLUMES|LDF_READ);
  4987. }
  4988.  
  4989. STATIC int
  4990. deep_scan_drawer(char * drawerName,char * whichPattern,FILE * out)
  4991. {
  4992.     char * originalDrawerName;
  4993.     struct MangleInfo mi;
  4994.     int result = ERROR;
  4995.  
  4996.     originalDrawerName = drawerName;
  4997.     if(MangleName(&drawerName,&mi) == OK)
  4998.     {
  4999.         BPTR dirLock;
  5000.  
  5001.         dirLock = Lock(drawerName,SHARED_LOCK);
  5002.         if(dirLock != ZERO)
  5003.         {
  5004.             struct FileInfoBlock __aligned fib;
  5005.  
  5006.             if(Examine(dirLock,&fib))
  5007.             {
  5008.                 struct AnchorPath * ap;
  5009.  
  5010.                 ap = malloc(sizeof(*ap) + MAX_FILENAME_LEN);
  5011.                 if(ap != NULL)
  5012.                 {
  5013.                     BOOL stopped = FALSE;
  5014.                     BPTR oldDir;
  5015.                     LONG error;
  5016.  
  5017.                     oldDir = CurrentDir(dirLock);
  5018.  
  5019.                     memset(ap,0,sizeof(*ap) + MAX_FILENAME_LEN);
  5020.                     ap->ap_Strlen        = MAX_FILENAME_LEN;
  5021.                     ap->ap_BreakBits    = SIGBREAKF_CTRL_C;
  5022.  
  5023.                     if((error = MatchFirst("",ap)) == OK)
  5024.                     {
  5025.                         BOOL check;
  5026.  
  5027.                         do
  5028.                         {
  5029.                             D(("checking |%s|",ap->ap_Buf));
  5030.  
  5031.                             check = TRUE;
  5032.  
  5033.                             if(FIB_IS_FILE(&ap->ap_Info))
  5034.                             {
  5035.                                 SHOWMSG("this is a file");
  5036.                             }
  5037.                             else
  5038.                             {
  5039.                                 SHOWMSG("this is a drawer");
  5040.  
  5041.                                 if(FLAG_IS_CLEAR(ap->ap_Flags,APF_DIDDIR))
  5042.                                 {
  5043.                                     SET_FLAG(ap->ap_Flags,APF_DODIR);
  5044.                                 }
  5045.                                 else
  5046.                                 {
  5047.                                     CLEAR_FLAG(ap->ap_Flags,APF_DIDDIR);
  5048.                                     check = FALSE;
  5049.                                 }
  5050.                             }
  5051.  
  5052.                             if(check)
  5053.                             {
  5054.                                 SHOWSTRING(ap->ap_Info.fib_FileName);
  5055.  
  5056.                                 if(do_match(ap->ap_Info.fib_FileName,whichPattern))
  5057.                                 {
  5058.                                     D(("Output |%s/%s|",originalDrawerName,ap->ap_Buf));
  5059.                                     if(fprintf(out,"%s/%s\n",originalDrawerName,ap->ap_Buf) < 0)
  5060.                                     {
  5061.                                         stopped = TRUE;
  5062.                                         break;
  5063.                                     }
  5064.                                 }
  5065.                                 else
  5066.                                 {
  5067.                                     SHOWMSG("but its name does not match");
  5068.                                 }
  5069.                             }
  5070.                         }
  5071.                         while((error = MatchNext(ap)) == OK);
  5072.                     }
  5073.  
  5074.                     MatchEnd(ap);
  5075.  
  5076.                     CurrentDir(oldDir);
  5077.  
  5078.                     if(NOT stopped)
  5079.                     {
  5080.                         if(error == ERROR_NO_MORE_ENTRIES)
  5081.                         {
  5082.                             result = OK;
  5083.                         }
  5084.                         else if(error == ERROR_BREAK)
  5085.                         {
  5086.                             /* Don't do anything; we are going
  5087.                              * to delete the file anyway.
  5088.                              */
  5089.                         }
  5090.                         else
  5091.                         {
  5092.                             SetIoErr(error);
  5093.                             MapIoErrToErrno();
  5094.                         }
  5095.                     }
  5096.  
  5097.                     free(ap);
  5098.                 }
  5099.                 else
  5100.                 {
  5101.                     errno = ENOMEM;
  5102.                 }
  5103.             }
  5104.             else
  5105.             {
  5106.                 MapIoErrToErrno();
  5107.             }
  5108.  
  5109.             UnLock(dirLock);
  5110.         }
  5111.         else
  5112.         {
  5113.             MapIoErrToErrno();
  5114.         }
  5115.  
  5116.         UnmangleName(&drawerName,&mi);
  5117.     }
  5118.  
  5119.     return(result);
  5120. }
  5121.  
  5122. int
  5123. amiga_system(char *cmd)
  5124. {
  5125.     char redirectionFileBuffer[MAX_FILENAME_LEN];
  5126.     char *redirectionFile = redirectionFileBuffer;
  5127.     struct MangleInfo mi;
  5128.     int result = ERROR;
  5129.     char *stop;
  5130.     char *options;
  5131.     char *cmdName;
  5132.     int cmdLen,i;
  5133.     int quoteCount;
  5134.  
  5135.     chkabort();
  5136.  
  5137.     ASSERT(cmd != NULL);
  5138.  
  5139.     ENTER();
  5140.     SHOWSTRING(cmd);
  5141.  
  5142.     /* Handle two special cases for the smb client program,
  5143.      * which for reasons unknown to me resorts to calling
  5144.      * the Unix "ls" and "find" programs to collect lists
  5145.      * of files.
  5146.      *
  5147.      * The commands to watch for take the following forms:
  5148.      *
  5149.      *    /bin/ls file_to_list > output_filename
  5150.      *    find directory_to_list -name "pattern_to_list" -print > output_filename
  5151.      */
  5152.     stop = cmd;
  5153.     while((*stop) != ' ' && (*stop) != '\0')
  5154.         stop++;
  5155.  
  5156.     /* This will point behind the command name,
  5157.      * to the beginning of the list of options,
  5158.      * if any.
  5159.      */
  5160.     options = stop;
  5161.     while((*options) == ' ')
  5162.         options++;
  5163.  
  5164.     /* Now go and isolate the command name. */
  5165.     cmdName = cmd;
  5166.     cmdLen = stop-cmd;
  5167.     for(i = cmdLen - 1 ; i >= 0 ; i--)
  5168.     {
  5169.         if(cmd[i] == '/' || cmd[i] == ':')
  5170.         {
  5171.             cmdName = &cmd[i+1];
  5172.  
  5173.             stop = cmdName;
  5174.             while((*stop) != ' ' && (*stop) != '\0')
  5175.                 stop++;
  5176.  
  5177.             cmdLen = stop-cmdName;
  5178.  
  5179.             break;
  5180.         }
  5181.     }
  5182.  
  5183.     /* We have isolated the command name, now
  5184.      * find the redirection file name.
  5185.      */
  5186.     quoteCount = 0;
  5187.     strcpy(redirectionFile,"");
  5188.     for(i = 0 ; i < strlen(cmd) ; i++)
  5189.     {
  5190.         if(cmd[i] == '\"')
  5191.             quoteCount = (1-quoteCount);
  5192.  
  5193.         if(cmd[i] == '>' && quoteCount == 0)
  5194.         {
  5195.             char * from;
  5196.  
  5197.             from = &cmd[i+1];
  5198.             while((*from) == ' ')
  5199.                 from++;
  5200.  
  5201.             /* Note that we rely upon the
  5202.              * redirection file name not to contain
  5203.              * quote or escape characters.
  5204.              */
  5205.             nstrcpy_blank(sizeof(redirectionFileBuffer),redirectionFile,from);
  5206.             break;
  5207.         }
  5208.     }
  5209.  
  5210.     /* Now check which command we got. */
  5211.     if(cmdLen == 2 && Strnicmp(cmdName,"ls",2) == SAME)
  5212.     {
  5213.         char localDirName[MAX_FILENAME_LEN];
  5214.         char * dirName;
  5215.  
  5216.         dirName = ".";
  5217.  
  5218.         if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  5219.         {
  5220.             char whichPatternBuffer[MAX_FILENAME_LEN];
  5221.             char *whichPattern = whichPatternBuffer;
  5222.             BOOL oldAllowBreak = AllowBreak;
  5223.  
  5224.             /* We don't want to be interrupted. */
  5225.             AllowBreak = FALSE;
  5226.  
  5227.             /* Now find the pattern to use. */
  5228.             nstrcpy_blank(sizeof(whichPatternBuffer),whichPattern,options);
  5229.  
  5230.             SHOWMSG("doing `ls'");
  5231.             SHOWSTRING(whichPattern);
  5232.             SHOWSTRING(redirectionFile);
  5233.  
  5234.             /* What happens next is that the contents of the
  5235.              * current directory are scanned. All names
  5236.              * that match the given pattern are stored in the
  5237.              * redirection file.
  5238.              */
  5239.  
  5240.             if(MangleName(&redirectionFile,&mi) == OK)
  5241.             {
  5242.                 FILE * out;
  5243.  
  5244.                 ForbidDOS();
  5245.  
  5246.                 out = fopen(redirectionFile,"wb");
  5247.                 if(out != NULL)
  5248.                 {
  5249.                     SHOWSTRING(localDirName);
  5250.  
  5251.                     if(strcmp(localDirName,"/") == SAME)
  5252.                     {
  5253.                         struct List list;
  5254.                         struct Node * node;
  5255.  
  5256.                         SHOWMSG("listing volumes");
  5257.  
  5258.                         NewList(&list);
  5259.  
  5260.                         fill_volume_list(&list);
  5261.  
  5262.                         while((node = RemHead(&list)) != NULL)
  5263.                         {
  5264.                             D(("checking '%s'",node->ln_Name));
  5265.  
  5266.                             if(do_match(node->ln_Name,whichPattern))
  5267.                             {
  5268.                                 SHOWMSG(">>> matches");
  5269.  
  5270.                                 if(fprintf(out,"%s\n",node->ln_Name) < 0)
  5271.                                     break;
  5272.                             }
  5273.                             else
  5274.                             {
  5275.                                 SHOWMSG(">>> does not match");
  5276.                             }
  5277.  
  5278.                             free(node);
  5279.                         }
  5280.  
  5281.                         while((node = RemHead(&list)) != NULL)
  5282.                             free(node);
  5283.                     }
  5284.                     else
  5285.                     {
  5286.                         BPTR dirLock;
  5287.  
  5288.                         SHOWMSG("listing drawers");
  5289.  
  5290.                         dirLock = Lock("",SHARED_LOCK);
  5291.                         if(dirLock != ZERO)
  5292.                         {
  5293.                             struct FileInfoBlock __aligned fib;
  5294.  
  5295.                             if(Examine(dirLock,&fib))
  5296.                             {
  5297.                                 BOOL stopped = FALSE;
  5298.  
  5299.                                 while(ExNext(dirLock,&fib))
  5300.                                 {
  5301.                                     D(("checking '%s'",fib.fib_FileName));
  5302.  
  5303.                                     if(do_match(fib.fib_FileName,whichPattern))
  5304.                                     {
  5305.                                         SHOWMSG(">>> matches");
  5306.  
  5307.                                         if(fprintf(out,"%s\n",fib.fib_FileName) < 0)
  5308.                                         {
  5309.                                             stopped = TRUE;
  5310.                                             break;
  5311.                                         }
  5312.                                     }
  5313.                                     else
  5314.                                     {
  5315.                                         SHOWMSG(">>> does not match");
  5316.                                     }
  5317.                                 }
  5318.  
  5319.                                 if(NOT stopped)
  5320.                                 {
  5321.                                     LONG error = IoErr();
  5322.  
  5323.                                     if(error == ERROR_NO_MORE_ENTRIES)
  5324.                                     {
  5325.                                         result = OK;
  5326.                                     }
  5327.                                     else
  5328.                                     {
  5329.                                         SetIoErr(error);
  5330.                                         MapIoErrToErrno();
  5331.                                     }
  5332.                                 }
  5333.                             }
  5334.                             else
  5335.                             {
  5336.                                 MapIoErrToErrno();
  5337.                             }
  5338.  
  5339.                             UnLock(dirLock);
  5340.                         }
  5341.                         else
  5342.                         {
  5343.                             MapIoErrToErrno();
  5344.                         }
  5345.                     }
  5346.  
  5347.                     fclose(out);
  5348.  
  5349.                     if(result != OK)
  5350.                         DeleteFile(redirectionFile);
  5351.                 }
  5352.  
  5353.                 PermitDOS();
  5354.  
  5355.                 UnmangleName(&cmd,&mi);
  5356.             }
  5357.  
  5358.             AllowBreak = oldAllowBreak;
  5359.         }
  5360.     }
  5361.     else if (cmdLen == 4 && Strnicmp(cmdName,"find",4) == SAME)
  5362.     {
  5363.         char whichDrawerBuffer[MAX_FILENAME_LEN];
  5364.         char * whichDrawer = whichDrawerBuffer;
  5365.         char whichPattern[MAX_FILENAME_LEN];
  5366.         const int _nameLen = strlen("-name");
  5367.         BOOL oldAllowBreak = AllowBreak;
  5368.         struct List list;
  5369.         struct Node * node;
  5370.  
  5371.         NewList(&list);
  5372.  
  5373.         /* We don't want to be interrupted. */
  5374.         AllowBreak = FALSE;
  5375.  
  5376.         /* Now find the drawer to examine. */
  5377.         nstrcpy_blank(sizeof(whichDrawerBuffer),whichDrawer,options);
  5378.  
  5379.         /* Find the pattern to search for. */
  5380.         strcpy(whichPattern,"");
  5381.         for(i = 0 ; i < strlen(options) ; i++)
  5382.         {
  5383.             if(Strnicmp(&options[i],"-name",_nameLen) == SAME)
  5384.             {
  5385.                 const int maxLen = sizeof(whichPattern)-1;
  5386.                 int whichPatternLen;
  5387.                 int escapeCount;
  5388.                 int quoteCount;
  5389.                 char * from;
  5390.                 char * to;
  5391.  
  5392.                 /* `from' should now point straight at the
  5393.                  * search pattern, which is probably enclosed
  5394.                  * in quote characters.
  5395.                  */
  5396.                 from = &options[i+_nameLen];
  5397.                 while((*from) == ' ')
  5398.                     from++;
  5399.  
  5400.                 to = whichPattern;
  5401.                 whichPatternLen = 0;
  5402.                 quoteCount = 0;
  5403.                 escapeCount = 0;
  5404.                 while((*from) != '\0' && whichPatternLen < maxLen)
  5405.                 {
  5406.                     if(escapeCount != 0)
  5407.                     {
  5408.                         (*to++) = (*from++);
  5409.                         whichPatternLen++;
  5410.                         escapeCount = 0;
  5411.                     }
  5412.                     else if((*from) == '\\')
  5413.                     {
  5414.                         escapeCount = (1-escapeCount);
  5415.                         from++;
  5416.                     }
  5417.                     else if ((*from) == '\"')
  5418.                     {
  5419.                         quoteCount = (1-quoteCount);
  5420.                         from++;
  5421.                     }
  5422.                     else
  5423.                     {
  5424.                         if((*from) == ' ' && quoteCount == 0)
  5425.                         {
  5426.                             break;
  5427.                         }
  5428.                         else
  5429.                         {
  5430.                             (*to++) = (*from++);
  5431.                             whichPatternLen++;
  5432.                         }
  5433.                     }
  5434.                 }
  5435.  
  5436.                 (*to) = '\0';
  5437.             }
  5438.         }
  5439.  
  5440.         SHOWMSG("doing `find'");
  5441.         SHOWSTRING(whichDrawer);
  5442.         SHOWSTRING(whichPattern);
  5443.         SHOWSTRING(redirectionFile);
  5444.  
  5445.         /* Things are a little bit more complicated here. The
  5446.          * "find" program scans recursively through a directory
  5447.          * tree. We emulate this behaviour by having the MatchFirst/MatchNext
  5448.          * routines iterate through the directory tree. The
  5449.          * name of every file found is matched against the given
  5450.          * pattern and, if necessary, written to the redirection
  5451.          * file. Note that matching is performed only on the
  5452.          * file name, not on the entire path.
  5453.          */
  5454.  
  5455.         if(MangleName(&redirectionFile,&mi) == OK)
  5456.         {
  5457.             FILE * out;
  5458.  
  5459.             ForbidDOS();
  5460.  
  5461.             out = fopen(redirectionFile,"wb");
  5462.             if(out != NULL)
  5463.             {
  5464.                 char localDirName[MAX_FILENAME_LEN];
  5465.                 char * dirName;
  5466.  
  5467.                 dirName = whichDrawer;
  5468.  
  5469.                 if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  5470.                 {
  5471.                     D(("listing path '%s'",dirName));
  5472.  
  5473.                     if(strcmp(dirName,"/") == SAME)
  5474.                     {
  5475.                         SHOWMSG("checking all 'drawers' in the fake root");
  5476.  
  5477.                         fill_volume_list(&list);
  5478.  
  5479.                         while((node = RemHead(&list)) != NULL)
  5480.                         {
  5481.                             strcpy(localDirName,"/");
  5482.                             strcat(localDirName,node->ln_Name);
  5483.                             free(node);
  5484.  
  5485.                             D(("checking '%s'",localDirName));
  5486.  
  5487.                             result = deep_scan_drawer(localDirName,whichPattern,out);
  5488.                             if(result != OK)
  5489.                                 break;
  5490.                         }
  5491.  
  5492.                         while((node = RemHead(&list)) != NULL)
  5493.                             free(node);
  5494.                     }
  5495.                     else
  5496.                     {
  5497.                         SHOWMSG("checking only a local drawer");
  5498.  
  5499.                         result = deep_scan_drawer(dirName,whichPattern,out);
  5500.                     }
  5501.                 }
  5502.  
  5503.                 fclose(out);
  5504.  
  5505.                 if(result != OK)
  5506.                     DeleteFile(redirectionFile);
  5507.             }
  5508.  
  5509.             PermitDOS();
  5510.  
  5511.             UnmangleName(&cmd,&mi);
  5512.         }
  5513.  
  5514.         AllowBreak = oldAllowBreak;
  5515.     }
  5516.     else
  5517.     {
  5518.         if(MangleName(&cmd,&mi) == OK)
  5519.         {
  5520.             ForbidDOS();
  5521.             result = system(cmd);
  5522.             PermitDOS();
  5523.  
  5524.             UnmangleName(&cmd,&mi);
  5525.         }
  5526.     }
  5527.  
  5528.     RETURN(result);
  5529.     return(result);
  5530. }
  5531.  
  5532. /******************************************************************************/
  5533.  
  5534. int
  5535. amiga_fork(VOID)    /* dummy */
  5536. {
  5537.     int result;
  5538.  
  5539.     chkabort();
  5540.  
  5541.     ENTER();
  5542.  
  5543.     result = ERROR;
  5544.     errno = ENOSYS;
  5545.  
  5546.     RETURN(result);
  5547.     return(result);
  5548. }
  5549.  
  5550. /******************************************************************************/
  5551.  
  5552. STATIC BOOL
  5553. SetFileSocket(FILE *stream,int sockfd)
  5554. {
  5555.     struct UFB * ufb;
  5556.     BOOL success = FALSE;
  5557.  
  5558.     ASSERT(stream != NULL);
  5559.  
  5560.     ENTER();
  5561.  
  5562.     /* Check which buffer the file
  5563.      * is attached to.
  5564.      */
  5565.     ufb = chkufb(fileno(stream));
  5566.     if(ufb != NULL)
  5567.     {
  5568.         SHOWVALUE(ufb);
  5569.  
  5570.         /* Save the file handle. */
  5571.         if(SaveDescriptor(ufb))
  5572.         {
  5573.             /* And put the socket in its place. */
  5574.             ufb->ufbfh = sockfd;
  5575.             SET_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  5576.  
  5577.             success = TRUE;
  5578.         }
  5579.     }
  5580.     else
  5581.     {
  5582.         SHOWMSG("no ufb");
  5583.     }
  5584.  
  5585.     RETURN(success);
  5586.     return(success);
  5587. }
  5588.  
  5589. STATIC VOID
  5590. DaemonInit(VOID)
  5591. {
  5592.     struct DaemonMessage * dm;
  5593.     int sock;
  5594.  
  5595.     ENTER();
  5596.  
  5597.     /* This routine is called when the program starts up.
  5598.      * If it was launched by the INet super server, this
  5599.      * program will run as a daemon. We pick up its
  5600.      * socket input stream and attach it to our stdio
  5601.      * streams.
  5602.      */
  5603.     dm = (struct DaemonMessage *)((struct Process *)FindTask(NULL))->pr_ExitData;
  5604.     if(dm != NULL)
  5605.     {
  5606.         sock = ObtainSocket(dm->dm_ID,dm->dm_Family,dm->dm_Type,0);
  5607.         if(sock != -1)
  5608.         {
  5609.             BOOL success = FALSE;
  5610.             int sock_stdin;
  5611.             int sock_stdout;
  5612.             int sock_stderr;
  5613.  
  5614.             sock_stdin    = Dup2Socket(sock,-1);
  5615.             sock_stdout    = Dup2Socket(sock,-1);
  5616.             sock_stderr    = Dup2Socket(sock,-1);
  5617.  
  5618.             if(sock_stdin != -1 && sock_stdout != -1 && sock_stderr != -1)
  5619.             {
  5620.                 SHOWMSG("got all sockets");
  5621.  
  5622.                 D(("stdin  = sock %ld",sock_stdin));
  5623.                 D(("stdout = sock %ld",sock_stdout));
  5624.                 D(("stderr = sock %ld",sock_stderr));
  5625.  
  5626.                 if(SetFileSocket(stdin,sock_stdin) &&
  5627.                    SetFileSocket(stdout,sock_stdout) &&
  5628.                    SetFileSocket(stderr,sock_stderr))
  5629.                 {
  5630.                     SHOWMSG("and all streams are initialized");
  5631.  
  5632.                     success = TRUE;
  5633.                 }
  5634.                 else
  5635.                 {
  5636.                     SHOWMSG("failed to initialize streams");
  5637.                 }
  5638.             }
  5639.             else
  5640.             {
  5641.                 SHOWMSG("didn't get the sockets");
  5642.             }
  5643.  
  5644.             if(NO success)
  5645.             {
  5646.                 if(sock_stdin != -1)
  5647.                     CloseSocket(sock_stdin);
  5648.  
  5649.                 if(sock_stdout != -1)
  5650.                     CloseSocket(sock_stdout);
  5651.  
  5652.                 if(sock_stderr != -1)
  5653.                     CloseSocket(sock_stderr);
  5654.             }
  5655.         }
  5656.         else
  5657.         {
  5658.             SHOWMSG("no socket");
  5659.         }
  5660.     }
  5661.     else
  5662.     {
  5663.         SHOWMSG("No daemon message");
  5664.     }
  5665.  
  5666.     LEAVE();
  5667. }
  5668.  
  5669. /******************************************************************************/
  5670.  
  5671. VOID
  5672. __tzset(VOID)
  5673. {
  5674.     STATIC char TimeZoneName[20] = "";
  5675.  
  5676.     /* This routine sets up the internal
  5677.      * time zone variable according to
  5678.      * the local settings.
  5679.      */
  5680.     if(STRING_IS_EMPTY(TimeZoneName))
  5681.     {
  5682.         int hoursWest = MinutesWest / 60;
  5683.  
  5684.         if(hoursWest >= 0)
  5685.             sprintf(TimeZoneName,"GMT+%02d", hoursWest);
  5686.         else
  5687.             sprintf(TimeZoneName,"GMT-%02d",-hoursWest);
  5688.     }
  5689.  
  5690.     _TZ = TimeZoneName;
  5691. }
  5692.  
  5693. /******************************************************************************/
  5694.  
  5695. time_t
  5696. time(time_t *timeptr)
  5697. {
  5698.     time_t currentTime;
  5699.     struct timeval tv;
  5700.  
  5701.     chkabort();
  5702.  
  5703.     GetSysTime((APTR)&tv);
  5704.  
  5705.     currentTime = UNIX_TIME_OFFSET + tv.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  5706.  
  5707.     if(timeptr != NULL)
  5708.         (*timeptr) = currentTime;
  5709.  
  5710.     return(currentTime);
  5711. }
  5712.  
  5713. /******************************************************************************/
  5714.  
  5715. STATIC struct tm *
  5716. ConvertTime(ULONG seconds)
  5717. {
  5718.     STATIC struct tm tm;
  5719.     struct ClockData clockData;
  5720.     ULONG delta;
  5721.  
  5722.     chkabort();
  5723.  
  5724.     Amiga2Date(seconds,&clockData);
  5725.  
  5726.     tm.tm_sec    = clockData.sec;
  5727.     tm.tm_min    = clockData.min;
  5728.     tm.tm_hour    = clockData.hour;
  5729.     tm.tm_mday    = clockData.mday;
  5730.     tm.tm_mon    = clockData.month - 1;
  5731.     tm.tm_year    = clockData.year - 1900;
  5732.     tm.tm_wday    = clockData.wday;
  5733.     tm.tm_isdst    = 0;
  5734.  
  5735.     clockData.mday    = 1;
  5736.     clockData.month    = 1;
  5737.  
  5738.     delta = Date2Amiga(&clockData);
  5739.  
  5740.     tm.tm_yday = (seconds - delta) / (24*60*60);
  5741.  
  5742.     return(&tm);
  5743. }
  5744.  
  5745. struct tm *
  5746. gmtime(const time_t *t)
  5747. {
  5748.     struct tm * result;
  5749.     ULONG seconds;
  5750.  
  5751.     if((*t) < UNIX_TIME_OFFSET)
  5752.         seconds = 0;
  5753.     else
  5754.         seconds = (*t) - UNIX_TIME_OFFSET;
  5755.  
  5756.     result = ConvertTime(seconds);
  5757.  
  5758.     return(result);
  5759. }
  5760.  
  5761. struct tm *
  5762. localtime(const time_t *t)
  5763. {
  5764.     struct tm * result;
  5765.     ULONG seconds;
  5766.  
  5767.     if((*t) < (UNIX_TIME_OFFSET + 60*MinutesWest))
  5768.         seconds = 0;
  5769.     else
  5770.         seconds = (*t) - (UNIX_TIME_OFFSET + 60*MinutesWest);    /* translate from UTC to local time */
  5771.  
  5772.     result = ConvertTime(seconds);
  5773.  
  5774.     return(result);
  5775. }
  5776.  
  5777. /******************************************************************************/
  5778.  
  5779. int
  5780. amiga_strcasecmp(char *a,char *b)
  5781. {
  5782.     int result;
  5783.  
  5784.     ASSERT(a != NULL && b != NULL);
  5785.  
  5786.     result = Stricmp((STRPTR)a,b);
  5787.  
  5788.     return(result);
  5789. }
  5790.  
  5791. int
  5792. amiga_strncasecmp(char *a,char *b,int len)
  5793. {
  5794.     int result;
  5795.  
  5796.     ASSERT(a != NULL && b != NULL);
  5797.  
  5798.     result = Strnicmp(a,b,len);
  5799.  
  5800.     return(result);
  5801. }
  5802.  
  5803. /******************************************************************************/
  5804.  
  5805. VOID
  5806. (*amiga_signal(int which,VOID (* action)(int)))(int)
  5807. {
  5808.     VOID (* result)(int);
  5809.  
  5810.     chkabort();
  5811.  
  5812.     ENTER();
  5813.  
  5814.     if(SIGABRT <= which && which <= SIGTERM)
  5815.         result = signal(which,action);
  5816.     else
  5817.         result = SIG_DFL;
  5818.  
  5819.     RETURN(result);
  5820.     return(result);
  5821. }
  5822.  
  5823. /******************************************************************************/
  5824.  
  5825. VOID
  5826. amiga_alarm(int seconds)    /* dummy */
  5827. {
  5828.     chkabort();
  5829.  
  5830.     ENTER();
  5831.  
  5832.     LEAVE();
  5833. }
  5834.  
  5835. /******************************************************************************/
  5836.  
  5837. int
  5838. amiga_waitpid(pid_t pid,int *status,int options)    /* dummy */
  5839. {
  5840.     int result;
  5841.  
  5842.     chkabort();
  5843.  
  5844.     ENTER();
  5845.  
  5846.     result = ERROR;
  5847.     errno = ENOSYS;
  5848.  
  5849.     RETURN(result);
  5850.     return(result);
  5851. }
  5852.  
  5853. /******************************************************************************/
  5854.  
  5855. long
  5856. amiga_setsid(VOID)
  5857. {
  5858.     long result;
  5859.  
  5860.     chkabort();
  5861.  
  5862.     ENTER();
  5863.  
  5864.     result = (long)setsid();
  5865.  
  5866.     RETURN(result);
  5867.     return(result);
  5868. }
  5869.  
  5870. /******************************************************************************/
  5871.  
  5872. int
  5873. amiga_setreuid(uid_t real, uid_t eff)
  5874. {
  5875.     int result;
  5876.  
  5877.     chkabort();
  5878.  
  5879.     ENTER();
  5880.  
  5881.     result = setreuid(real,eff);
  5882.  
  5883.     RETURN(result);
  5884.     return(result);
  5885. }
  5886.  
  5887. /******************************************************************************/
  5888.  
  5889. int
  5890. amiga_setregid(gid_t real, gid_t eff)
  5891. {
  5892.     int result;
  5893.  
  5894.     chkabort();
  5895.  
  5896.     ENTER();
  5897.  
  5898.     result = setregid(real,eff);
  5899.  
  5900.     RETURN(result);
  5901.     return(result);
  5902. }
  5903.  
  5904. /******************************************************************************/
  5905.  
  5906. int
  5907. amiga_getsockname(int sockfd,struct sockaddr *name,int *namelen)
  5908. {
  5909.     struct UFB * ufb;
  5910.     int result = ERROR;
  5911.  
  5912.     chkabort();
  5913.  
  5914.     ASSERT(name != NULL && namelen != NULL);
  5915.  
  5916.     ENTER();
  5917.  
  5918.     ufb = chkufb(sockfd);
  5919.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  5920.         result = getsockname(ufb->ufbfh,name,(LONG *)namelen);
  5921.     else
  5922.         errno = ENOTSOCK;
  5923.  
  5924.     RETURN(result);
  5925.     return(result);
  5926. }
  5927.  
  5928. /******************************************************************************/
  5929.  
  5930. int
  5931. amiga_statfs(char *name,struct statfs *f)
  5932. {
  5933.     char localName[MAX_FILENAME_LEN];
  5934.     int result = ERROR;
  5935.  
  5936.     chkabort();
  5937.  
  5938.     ASSERT(name != NULL && f != NULL);
  5939.  
  5940.     ENTER();
  5941.  
  5942.     SHOWSTRING(name);
  5943.     SHOWVALUE(f);
  5944.  
  5945.     if(TranslateRelativePath(&name,localName,sizeof(localName)) == OK)
  5946.     {
  5947.         /* Make up something for the virtual root directory. */
  5948.         if(strcmp(name,"/") == SAME)
  5949.         {
  5950.             memset(f,0,sizeof(*f));
  5951.  
  5952.             f->f_fsize = 512;
  5953.  
  5954.             /* Try to reuse the data from our last scan. */
  5955.             if(RootBlocks > 0 && RootBlocksUsed > 0)
  5956.             {
  5957.                 f->f_blocks    = RootBlocks;
  5958.                 f->f_bfree    = RootBlocks - RootBlocksUsed;
  5959.             }
  5960.             else
  5961.             {
  5962.                 f->f_blocks    = 0x7FFFFFFF/f->f_fsize;
  5963.                 f->f_bfree    = f->f_blocks - 1;
  5964.             }
  5965.  
  5966.             f->f_bsize    = f->f_fsize;
  5967.             f->f_bavail    = f->f_bfree;
  5968.  
  5969.             SHOWVALUE(f->f_fsize);
  5970.             SHOWVALUE(f->f_bsize);
  5971.             SHOWVALUE(f->f_blocks);
  5972.             SHOWVALUE(f->f_bfree);
  5973.             SHOWVALUE(f->f_bavail);
  5974.  
  5975.             result = OK;
  5976.         }
  5977.         else
  5978.         {
  5979.             struct MangleInfo mi;
  5980.             BPTR fileLock;
  5981.  
  5982.             if(MangleName(&name,&mi) == OK)
  5983.             {
  5984.                 ForbidDOS();
  5985.  
  5986.                 fileLock = Lock(name,SHARED_LOCK);
  5987.                 if(fileLock != ZERO)
  5988.                 {
  5989.                     struct InfoData __aligned id;
  5990.  
  5991.                     if(Info(fileLock,&id))
  5992.                     {
  5993.                         memset(f,0,sizeof(*f));
  5994.  
  5995.                         /* Make sure that these never drop to zero. */
  5996.                         if(id.id_NumBlocks == 0)
  5997.                             id.id_NumBlocks = 1;
  5998.  
  5999.                         if(id.id_BytesPerBlock == 0)
  6000.                             id.id_BytesPerBlock = 512;
  6001.  
  6002.                         f->f_fsize    = id.id_BytesPerBlock;                        /* fundamental file system block size */
  6003.                         f->f_blocks    = id.id_NumBlocks;                            /* total data blocks in file system */
  6004.                         f->f_bfree    = id.id_NumBlocks - id.id_NumBlocksUsed;    /* free blocks in fs */
  6005.                         f->f_bsize    = f->f_fsize;                                /* optimal transfer block size */
  6006.                         f->f_bavail    = f->f_bfree;                                /* free blocks avail to non-superuser */
  6007.  
  6008.                         SHOWVALUE(f->f_fsize);
  6009.                         SHOWVALUE(f->f_bsize);
  6010.                         SHOWVALUE(f->f_blocks);
  6011.                         SHOWVALUE(f->f_bfree);
  6012.                         SHOWVALUE(f->f_bavail);
  6013.  
  6014.                         result = OK;
  6015.                     }
  6016.                     else
  6017.                     {
  6018.                         MapIoErrToErrno();
  6019.                     }
  6020.  
  6021.                     UnLock(fileLock);
  6022.                 }
  6023.                 else
  6024.                 {
  6025.                     MapIoErrToErrno();
  6026.                 }
  6027.  
  6028.                 PermitDOS();
  6029.  
  6030.                 UnmangleName(&name,&mi);
  6031.             }
  6032.         }
  6033.     }
  6034.  
  6035.     RETURN(result);
  6036.     return(result);
  6037. }
  6038.  
  6039. /******************************************************************************/
  6040.  
  6041. int
  6042. amiga_execl(char *path,char *arg,...)    /* dummy */
  6043. {
  6044.     int result;
  6045.  
  6046.     chkabort();
  6047.  
  6048.     ENTER();
  6049.  
  6050.     result = ERROR;
  6051.     errno = ENOSYS;
  6052.  
  6053.     RETURN(result);
  6054.     return(result);
  6055. }
  6056.  
  6057. /******************************************************************************/
  6058.  
  6059. char *
  6060. amiga_strerror(int error)
  6061. {
  6062.     struct TagItem tags[2];
  6063.     char *result;
  6064.  
  6065.     chkabort();
  6066.  
  6067.     ENTER();
  6068.  
  6069.     tags[0].ti_Tag    = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
  6070.     tags[0].ti_Data    = error;
  6071.     tags[1].ti_Tag    = TAG_END;
  6072.  
  6073.     SocketBaseTagList(tags);
  6074.  
  6075.     result = (char *)tags[0].ti_Data;
  6076.  
  6077.     RETURN(result);
  6078.     return(result);
  6079. }
  6080.  
  6081. /******************************************************************************/
  6082.  
  6083. int
  6084. amiga_access(char *name,int modes)
  6085. {
  6086.     struct MangleInfo mi;
  6087.     int result = ERROR;
  6088.  
  6089.     chkabort();
  6090.  
  6091.     ASSERT(name != NULL);
  6092.  
  6093.     ENTER();
  6094.  
  6095.     if(MangleName(&name,&mi) == OK)
  6096.     {
  6097.         ForbidDOS();
  6098.         result = access(name,modes);
  6099.         PermitDOS();
  6100.  
  6101.         UnmangleName(&name,&mi);
  6102.     }
  6103.  
  6104.     RETURN(result);
  6105.     return(result);
  6106. }
  6107.  
  6108. /******************************************************************************/
  6109.  
  6110. STATIC VOID
  6111. MapIoErrToErrno(VOID)
  6112. {
  6113.     /* This routine maps AmigaDOS error codes to
  6114.      * Unix error codes, as far as this is possible.
  6115.      * This table contains AmigaDOS error codes
  6116.      * the emulated routines won't generate. I have
  6117.      * included them for the sake of completeness.
  6118.      */
  6119.     struct { LONG IoErr; LONG errno; } MapTable[] =
  6120.     {
  6121.         ERROR_NO_FREE_STORE,            ENOMEM,
  6122.         ERROR_TASK_TABLE_FULL,            ENOMEM,
  6123.         ERROR_BAD_TEMPLATE,                EINVAL,
  6124.         ERROR_BAD_NUMBER,                EINVAL,
  6125.         ERROR_REQUIRED_ARG_MISSING,        EINVAL,
  6126.         ERROR_KEY_NEEDS_ARG,            EINVAL,
  6127.         ERROR_TOO_MANY_ARGS,            EINVAL,
  6128.         ERROR_UNMATCHED_QUOTES,            EINVAL,
  6129.         ERROR_LINE_TOO_LONG,            ENAMETOOLONG,
  6130.         ERROR_FILE_NOT_OBJECT,            ENOEXEC,
  6131.         ERROR_INVALID_RESIDENT_LIBRARY,    EIO,
  6132.         ERROR_NO_DEFAULT_DIR,            EIO,
  6133.         ERROR_OBJECT_IN_USE,            EBUSY,
  6134.         ERROR_OBJECT_EXISTS,            EBUSY,
  6135.         ERROR_DIR_NOT_FOUND,            ENOENT,
  6136.         ERROR_OBJECT_NOT_FOUND,            ENOENT,
  6137.         ERROR_BAD_STREAM_NAME,            EINVAL,
  6138.         ERROR_OBJECT_TOO_LARGE,            EFBIG,
  6139.         ERROR_ACTION_NOT_KNOWN,            ENOSYS,
  6140.         ERROR_INVALID_COMPONENT_NAME,    EINVAL,
  6141.         ERROR_INVALID_LOCK,                EBADF,
  6142.         ERROR_OBJECT_WRONG_TYPE,        EFTYPE,
  6143.         ERROR_DISK_NOT_VALIDATED,        EROFS,
  6144.         ERROR_DISK_WRITE_PROTECTED,        EROFS,
  6145.         ERROR_RENAME_ACROSS_DEVICES,    EXDEV,
  6146.         ERROR_DIRECTORY_NOT_EMPTY,        ENOTEMPTY,
  6147.         ERROR_TOO_MANY_LEVELS,            ENAMETOOLONG,
  6148.         ERROR_DEVICE_NOT_MOUNTED,        ENXIO,
  6149.         ERROR_SEEK_ERROR,                EIO,
  6150.         ERROR_COMMENT_TOO_BIG,            ENAMETOOLONG,
  6151.         ERROR_DISK_FULL,                ENOSPC,
  6152.         ERROR_DELETE_PROTECTED,            EACCES,
  6153.         ERROR_WRITE_PROTECTED,            EACCES,
  6154.         ERROR_READ_PROTECTED,            EACCES,
  6155.         ERROR_NOT_A_DOS_DISK,            EFTYPE,
  6156.         ERROR_NO_DISK,                    EACCES,
  6157.         ERROR_NO_MORE_ENTRIES,            EIO,
  6158.         ERROR_IS_SOFT_LINK,                EFTYPE,
  6159.         ERROR_OBJECT_LINKED,            EIO,
  6160.         ERROR_BAD_HUNK,                    ENOEXEC,
  6161.         ERROR_NOT_IMPLEMENTED,            ENOSYS,
  6162.         ERROR_RECORD_NOT_LOCKED,        EIO,
  6163.         ERROR_LOCK_COLLISION,            EACCES,
  6164.         ERROR_LOCK_TIMEOUT,                EIO,
  6165.         ERROR_UNLOCK_ERROR,                EIO,
  6166.         ERROR_BUFFER_OVERFLOW,            EIO,
  6167.         ERROR_BREAK,                    EINTR,
  6168.         ERROR_NOT_EXECUTABLE,            ENOEXEC
  6169.     };
  6170.  
  6171.     LONG ioErr = IoErr();
  6172.     int i;
  6173.  
  6174.     /* If nothing else matches, we can always
  6175.      * flag it as an I/O error.
  6176.      */
  6177.     errno = EIO;
  6178.  
  6179.     for(i = 0 ; i < NUM_ENTRIES(MapTable) ; i++)
  6180.     {
  6181.         if(MapTable[i].IoErr == ioErr)
  6182.         {
  6183.             errno = MapTable[i].errno;
  6184.             break;
  6185.         }
  6186.     }
  6187. }
  6188.  
  6189. /******************************************************************************/
  6190.  
  6191. off_t
  6192. amiga_lseek(int fd,off_t offset,int mode)
  6193. {
  6194.     struct UFB * ufb;
  6195.     off_t result = ERROR;
  6196.  
  6197.     ENTER();
  6198.     SHOWVALUE(fd);
  6199.     SHOWVALUE(offset);
  6200.     SHOWVALUE(mode);
  6201.  
  6202.     ForbidDOS();
  6203.  
  6204.     /* Make sure that we operate on a file. */
  6205.     ufb = chkufb(fd);
  6206.     if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6207.         result = lseek(fd,offset,mode);
  6208.     else
  6209.         errno = EBADF;
  6210.  
  6211.     PermitDOS();
  6212.  
  6213.     RETURN(result);
  6214.     return(result);
  6215. }
  6216.  
  6217. /******************************************************************************/
  6218.  
  6219. int
  6220. amiga_chroot(char *name)    /* dummy */
  6221. {
  6222.     int result = OK;
  6223.  
  6224.     ENTER();
  6225.  
  6226.     SHOWSTRING(name);
  6227.  
  6228.     RETURN(result);
  6229.     return(result);
  6230. }
  6231.  
  6232. /******************************************************************************/
  6233.  
  6234. STATIC int
  6235. MapFileNameAmigaToUnix(
  6236.     const char *    amiga,
  6237.     char *            unix,
  6238.     int                maxUnixLen)
  6239. {
  6240.     int len,destLen;
  6241.     int result = ERROR;
  6242.  
  6243.     /* This routine makes a Unix file
  6244.      * name generated from an AmigaDOS
  6245.      * file name. This involves a slight
  6246.      * change of syntax...
  6247.      */
  6248.     D(("amiga name |%s|",amiga));
  6249.  
  6250.     len = destLen = strlen(amiga);
  6251.     if(amiga[0] == '/')
  6252.     {
  6253.         destLen = 2 + len;
  6254.     }
  6255.     else
  6256.     {
  6257.         int i;
  6258.  
  6259.         for(i = 0 ; i < len ; i++)
  6260.         {
  6261.             if(amiga[i] == ':')
  6262.             {
  6263.                 if(amiga[i+1] != '\0')
  6264.                     destLen = 1 + len;
  6265.  
  6266.                 break;
  6267.             }
  6268.         }
  6269.     }
  6270.  
  6271.     if(destLen < maxUnixLen)
  6272.     {
  6273.         if(amiga[0] == '/')
  6274.         {
  6275.             /* `/foo\0' -> `../foo\0' */
  6276.             memmove(&unix[2],amiga,len+1);
  6277.             strncpy(unix,"..",2);
  6278.         }
  6279.         else
  6280.         {
  6281.             BOOL done = FALSE;
  6282.             int i;
  6283.  
  6284.             for(i = 0 ; i < len ; i++)
  6285.             {
  6286.                 if(amiga[i] == ':')
  6287.                 {
  6288.                     if(amiga[i+1] == '\0')
  6289.                     {
  6290.                         /* `foo:\0' -> `/foo\0' */
  6291.                         memmove(&unix[1],amiga,i);
  6292.                         unix[0] = '/';
  6293.                         unix[i+1] = '\0';
  6294.                     }
  6295.                     else
  6296.                     {
  6297.                         /* `foo:bar\0' -> `/foo/bar\0' */
  6298.                         memmove(&unix[1],amiga,len+1);
  6299.                         unix[0] = '/';
  6300.                         unix[i+1] = '/';
  6301.                     }
  6302.  
  6303.                     done = TRUE;
  6304.                     break;
  6305.                 }
  6306.             }
  6307.  
  6308.             if(NOT done && unix != amiga)
  6309.                 strcpy(unix,amiga);
  6310.         }
  6311.  
  6312.         D(("unix name |%s|",unix));
  6313.  
  6314.         result = OK;
  6315.     }
  6316.     else
  6317.     {
  6318.         SHOWMSG("unix name is too long to fit");
  6319.  
  6320.         errno = ENAMETOOLONG;
  6321.     }
  6322.  
  6323.     return(result);
  6324. }
  6325.  
  6326. /******************************************************************************/
  6327.  
  6328. STATIC VOID
  6329. FlushSTDOUT(VOID)
  6330. {
  6331.     /* Flush the standard output streams so that
  6332.      * any following output will be printed after
  6333.      * any buffered stdio output.
  6334.      */
  6335.     if(WBenchMsg == NULL)
  6336.     {
  6337.         struct UFB * ufb;
  6338.  
  6339.         /* Don't let anybody stop us. */
  6340.         signal(SIGINT,SIG_IGN);
  6341.         signal(SIGTERM,SIG_IGN);
  6342.  
  6343.         ufb = chkufb(fileno(stdout));
  6344.         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6345.             fflush(stdout);
  6346.  
  6347.         ufb = chkufb(fileno(stderr));
  6348.         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6349.             fflush(stderr);
  6350.     }
  6351. }
  6352.  
  6353. VOID
  6354. _CXOVF(VOID)
  6355. {
  6356.     /* This routine is called when a stack overflow occurs. */
  6357.     FlushSTDOUT();
  6358.     ReportProblem("Stack overflow");
  6359.  
  6360.     exit(RETURN_ERROR);
  6361. }
  6362.  
  6363. VOID __regargs
  6364. _CXBRK(VOID)
  6365. {
  6366.     extern STRPTR _ProgramName;
  6367.  
  6368.     FlushSTDOUT();
  6369.  
  6370.     /* This routine is called when the program is interrupted. */
  6371.     if(DOSBase->lib_Version >= 37)
  6372.     {
  6373.         PrintFault(ERROR_BREAK,_ProgramName);
  6374.     }
  6375.     else
  6376.     {
  6377.         const char *famousLastWords = ": *** Break";
  6378.         BPTR output = Output();
  6379.  
  6380.         Write(output,(APTR)famousLastWords,strlen(famousLastWords));
  6381.         Write(output,_ProgramName,strlen(_ProgramName));
  6382.         Write(output,"\n",1);
  6383.     }
  6384.  
  6385.     exit(RETURN_WARN);
  6386. }
  6387.  
  6388. /******************************************************************************/
  6389.  
  6390. STATIC STRPTR SambaSemaphoreName = "Amiga Samba";
  6391.  
  6392. struct SambaClientNode
  6393. {
  6394.     struct MinNode    scn_MinNode;
  6395.     struct Task *    scn_Task;
  6396.     pid_t            scn_PID;
  6397. };
  6398.  
  6399. struct SambaSemaphore
  6400. {
  6401.     struct SignalSemaphore    ss_Semaphore;
  6402.     struct List                ss_ClientList;
  6403.     pid_t                    ss_PID;
  6404.     struct List                ss_FileLockList;
  6405. };
  6406.  
  6407. STATIC struct SambaSemaphore *    SambaSemaphore;
  6408. STATIC struct SambaClientNode *    ThisClient;
  6409.  
  6410. STATIC VOID
  6411. CleanupSambaSemaphore(VOID)
  6412. {
  6413.     if(ThisClient != NULL)
  6414.     {
  6415.         /* Unregister the program. */
  6416.         ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6417.         Remove((struct Node *)ThisClient);
  6418.         ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6419.  
  6420.         FreeVec(ThisClient);
  6421.         ThisClient = NULL;
  6422.     }
  6423. }
  6424.  
  6425. STATIC BOOL
  6426. SetupSambaSemaphore(VOID)
  6427. {
  6428.     BOOL success = FALSE;
  6429.  
  6430.     /* We have to have the timer open to serialize the process IDs properly. */
  6431.     if(TimerBase != NULL)
  6432.     {
  6433.         Forbid();
  6434.  
  6435.         /* Try to find the global rendezvous semaphore. */
  6436.         SambaSemaphore = (struct SambaSemaphore *)FindSemaphore(SambaSemaphoreName);
  6437.         if(SambaSemaphore == NULL)
  6438.         {
  6439.             /* Couldn't find it. So, we create it... */
  6440.             SambaSemaphore = AllocMem(sizeof(*SambaSemaphore) + strlen(SambaSemaphoreName)+1,MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6441.             if(SambaSemaphore != NULL)
  6442.             {
  6443.                 /* Set up the name. */
  6444.                 SambaSemaphore->ss_Semaphore.ss_Link.ln_Name = (char *)(SambaSemaphore+1);
  6445.                 strcpy(SambaSemaphore->ss_Semaphore.ss_Link.ln_Name,SambaSemaphoreName);
  6446.  
  6447.                 /* Set the base value for all process IDs. */
  6448.                 SambaSemaphore->ss_PID = 936;
  6449.  
  6450.                 /* Clear the client list tasks are going to be registered with. */
  6451.                 NewList(&SambaSemaphore->ss_ClientList);
  6452.  
  6453.                 /* Clear the list we will use for keeping
  6454.                  * track of file segment locks.
  6455.                  */
  6456.                 NewList(&SambaSemaphore->ss_FileLockList);
  6457.  
  6458.                 AddSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6459.             }
  6460.         }
  6461.  
  6462.         Permit();
  6463.     }
  6464.  
  6465.     /* If possible, register this task. */
  6466.     if(SambaSemaphore != NULL)
  6467.     {
  6468.         struct SambaClientNode * scn;
  6469.  
  6470.         scn = AllocVec(sizeof(*scn),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6471.         if(scn != NULL)
  6472.         {
  6473.             /* That's me. */
  6474.             scn->scn_Task = FindTask(NULL);
  6475.  
  6476.             ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6477.  
  6478.             /* Register this program with a new process ID. */
  6479.             scn->scn_PID = SambaSemaphore->ss_PID++;
  6480.             AddTail(&SambaSemaphore->ss_ClientList,(struct Node *)scn);
  6481.  
  6482.             ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6483.  
  6484.             ThisClient = scn;
  6485.  
  6486.             success = TRUE;
  6487.         }
  6488.     }
  6489.  
  6490.     return(success);
  6491. }
  6492.  
  6493. int
  6494. amiga_kill(pid_t pid,int sig)
  6495. {
  6496.     struct SambaClientNode * scn;
  6497.     struct Task * found = NULL;
  6498.     int result = ERROR;
  6499.  
  6500.     chkabort();
  6501.  
  6502.     ENTER();
  6503.  
  6504.     ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6505.  
  6506.     /* Try to find the Samba program that responds
  6507.      * to the given process ID.
  6508.      */
  6509.     for(scn = (struct SambaClientNode *)SambaSemaphore->ss_ClientList.lh_Head ;
  6510.         scn->scn_MinNode.mln_Succ != NULL ;
  6511.         scn = (struct SambaClientNode *)scn->scn_MinNode.mln_Succ)
  6512.     {
  6513.         if(scn->scn_PID == pid)
  6514.         {
  6515.             found = scn->scn_Task;
  6516.             break;
  6517.         }
  6518.     }
  6519.  
  6520.     /* Did we find one? */
  6521.     if(found != NULL)
  6522.     {
  6523.         /* Kill the task or just do nothing? */
  6524.         if(sig == SIGTERM)
  6525.             Signal(found,SIGBREAKF_CTRL_C);
  6526.  
  6527.         result = OK;
  6528.     }
  6529.     else
  6530.     {
  6531.         errno = ESRCH;
  6532.     }
  6533.  
  6534.     ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6535.  
  6536.     RETURN(result);
  6537.     return(result);
  6538. }
  6539.  
  6540. pid_t
  6541. amiga_getpid(VOID)
  6542. {
  6543.     pid_t result;
  6544.  
  6545.     chkabort();
  6546.  
  6547.     ENTER();
  6548.  
  6549.     /* Return this program's process ID. */
  6550.     result = ThisClient->scn_PID;
  6551.  
  6552.     RETURN(result);
  6553.     return(result);
  6554. }
  6555.  
  6556. /******************************************************************************/
  6557.  
  6558. struct LockedRegionNode
  6559. {
  6560.     struct MinNode    lrn_MinNode;
  6561.     LONG            lrn_Start;
  6562.     LONG            lrn_Stop;
  6563.     pid_t            lrn_Owner;
  6564.     BOOL            lrn_Shared;
  6565. };
  6566.  
  6567. struct FileLockNode
  6568. {
  6569.     struct MinNode    fln_MinNode;
  6570.     struct List        fln_LockedRegionList;
  6571.     BPTR            fln_FileParentDir;
  6572.     UBYTE            fln_FileName[1];
  6573. };
  6574.  
  6575. STATIC VOID
  6576. RemoveLockedRegionNode(struct UFB * ufb,LONG start,LONG stop)
  6577. {
  6578.     if(FLAG_IS_SET(ufb->ufbflg,UFB_LOCKED))
  6579.     {
  6580.         BPTR fileHandle = (BPTR)ufb->ufbfh;
  6581.         struct FileLockNode * whichLock;
  6582.  
  6583.         /* Find the locked file this descriptor
  6584.          * buffer belongs to.
  6585.          */
  6586.         if(FindFileLockNodeByFileHandle(fileHandle,&whichLock) == OK && whichLock != NULL)
  6587.         {
  6588.             struct LockedRegionNode * lrn;
  6589.  
  6590.             /* Find the region to unlock and remove it. */
  6591.             for(lrn = (struct LockedRegionNode *)whichLock->fln_LockedRegionList.lh_Head ;
  6592.                 lrn->lrn_MinNode.mln_Succ != NULL ;
  6593.                 lrn = (struct LockedRegionNode *)lrn->lrn_MinNode.mln_Succ)
  6594.             {
  6595.                 if(lrn->lrn_Owner == ThisClient->scn_PID &&
  6596.                    lrn->lrn_Start == start &&
  6597.                    lrn->lrn_Stop  == stop)
  6598.                 {
  6599.                     SHOWMSG("unlocking all regions on this file");
  6600.  
  6601.                     Remove((struct Node *)lrn);
  6602.                     DeleteLockedRegionNode(lrn);
  6603.                     break;
  6604.                 }
  6605.             }
  6606.  
  6607.             /* Check if there are any locked regions left.
  6608.              * If not, mark the entire file as unlocked.
  6609.              */
  6610.             if(IsListEmpty(&whichLock->fln_LockedRegionList))
  6611.             {
  6612.                 SHOWMSG("no more regions are locked; removing the file lock node");
  6613.  
  6614.                 Remove((struct Node *)whichLock);
  6615.  
  6616.                 DeleteFileLockNode(whichLock);
  6617.  
  6618.                 CLEAR_FLAG(ufb->ufbflg,UFB_LOCKED);
  6619.             }
  6620.         }
  6621.     }
  6622. }
  6623.  
  6624. STATIC VOID
  6625. DeleteLockedRegionNode(struct LockedRegionNode * lrn)
  6626. {
  6627.     if(lrn != NULL)
  6628.         FreeMem(lrn,sizeof(*lrn));
  6629. }
  6630.  
  6631. STATIC LONG
  6632. CreateLockedRegionNode(struct LockedRegionNode ** resultPtr)
  6633. {
  6634.     struct LockedRegionNode * lrn;
  6635.     LONG error;
  6636.  
  6637.     lrn = AllocMem(sizeof(*lrn),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6638.     if(lrn != NULL)
  6639.     {
  6640.         lrn->lrn_Owner = ThisClient->scn_PID;
  6641.  
  6642.         error = OK;
  6643.     }
  6644.     else
  6645.     {
  6646.         error = ERROR_NO_FREE_STORE;
  6647.     }
  6648.  
  6649.     (*resultPtr) = lrn;
  6650.  
  6651.     return(error);
  6652. }
  6653.  
  6654. STATIC VOID
  6655. DeleteFileLockNode(struct FileLockNode * fln)
  6656. {
  6657.     if(fln != NULL)
  6658.     {
  6659.         UnLock(fln->fln_FileParentDir);
  6660.         FreeVec(fln);
  6661.     }
  6662. }
  6663.  
  6664. STATIC LONG
  6665. CreateFileLockNode(struct UFB * ufb,struct FileLockNode ** resultPtr)
  6666. {
  6667.     struct FileLockNode * result = NULL;
  6668.     BPTR fileHandle = (BPTR)ufb->ufbfh;
  6669.     struct FileInfoBlock __aligned fib;
  6670.     LONG error = OK;
  6671.  
  6672.     /* We store a lock on the file's parent directory
  6673.      * and the name of the file for later use in
  6674.      * comparisons.
  6675.      */
  6676.     if(ExamineFH(fileHandle,&fib))
  6677.     {
  6678.         struct FileLockNode * fln;
  6679.  
  6680.         fln = AllocVec(sizeof(*fln) + strlen(fib.fib_FileName),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6681.         if(fln != NULL)
  6682.         {
  6683.             fln->fln_FileParentDir = ParentOfFH(fileHandle);
  6684.             if(fln->fln_FileParentDir != ZERO)
  6685.             {
  6686.                 strcpy(fln->fln_FileName,fib.fib_FileName);
  6687.  
  6688.                 NewList(&fln->fln_LockedRegionList);
  6689.  
  6690.                 result = fln;
  6691.                 fln = NULL;
  6692.             }
  6693.             else
  6694.             {
  6695.                 error = IoErr();
  6696.             }
  6697.  
  6698.             DeleteFileLockNode(fln);
  6699.         }
  6700.         else
  6701.         {
  6702.             error = ERROR_NO_FREE_STORE;
  6703.         }
  6704.     }
  6705.     else
  6706.     {
  6707.         error = IoErr();
  6708.     }
  6709.  
  6710.     (*resultPtr) = result;
  6711.  
  6712.     return(error);
  6713. }
  6714.  
  6715. STATIC LONG
  6716. FindFileLockNodeByFileHandle(BPTR fileHandle,struct FileLockNode ** resultPtr)
  6717. {
  6718.     struct FileLockNode * result = NULL;
  6719.     BPTR parentDir;
  6720.     LONG error;
  6721.  
  6722.     /* Determine the file's parent directory and
  6723.      * name. These will be compared against the
  6724.      * global file lock data.
  6725.      */
  6726.     parentDir = ParentOfFH(fileHandle);
  6727.     if(parentDir != ZERO)
  6728.     {
  6729.         struct FileInfoBlock __aligned this_fib;
  6730.  
  6731.         if(ExamineFH(fileHandle,&this_fib))
  6732.         {
  6733.             struct FileLockNode * fln;
  6734.  
  6735.             #if DEBUG
  6736.             {
  6737.                 char name[MAX_FILENAME_LEN];
  6738.  
  6739.                 if(NameFromFH(fileHandle,name,sizeof(name)))
  6740.                     D(("Looking for a lock on file |%s|",name));
  6741.             }
  6742.             #endif /* DEBUG */
  6743.  
  6744.             error = OK;
  6745.  
  6746.             for(fln = (struct FileLockNode *)SambaSemaphore->ss_FileLockList.lh_Head ;
  6747.                 fln->fln_MinNode.mln_Succ != NULL ;
  6748.                 fln = (struct FileLockNode *)fln->fln_MinNode.mln_Succ)
  6749.             {
  6750.                 /* To be identical, the files must reside in the
  6751.                  * same directories and bear the same names.
  6752.                  */
  6753.                 if(SameLock(fln->fln_FileParentDir,parentDir) == LOCK_SAME)
  6754.                 {
  6755.                     if(Stricmp(fln->fln_FileName,this_fib.fib_FileName) == SAME)
  6756.                     {
  6757.                         result = fln;
  6758.                         error = OK;
  6759.  
  6760.                         break;
  6761.                     }
  6762.                 }
  6763.             }
  6764.         }
  6765.         else
  6766.         {
  6767.             error = IoErr();
  6768.         }
  6769.  
  6770.         if(result != NULL)
  6771.             SHOWMSG("found one");
  6772.         else
  6773.             SHOWMSG("didn't find one");
  6774.  
  6775.         UnLock(parentDir);
  6776.     }
  6777.     else
  6778.     {
  6779.         error = IoErr();
  6780.     }
  6781.  
  6782.     (*resultPtr) = result;
  6783.  
  6784.     return(error);
  6785. }
  6786.  
  6787. STATIC VOID
  6788. FindFileLockNodeByDrawerAndName(BPTR dirLock,STRPTR fileName,struct FileLockNode ** resultPtr)
  6789. {
  6790.     struct FileLockNode * result = NULL;
  6791.     struct FileLockNode * fln;
  6792.  
  6793.     /* This is a somewhat simplied version of FindFileLockNodeByFileHandle()
  6794.      * which works with preset drawer and name data.
  6795.      */
  6796.  
  6797.     #if DEBUG
  6798.     {
  6799.         char name[MAX_FILENAME_LEN];
  6800.  
  6801.         if(NameFromLock(dirLock,name,sizeof(name)))
  6802.         {
  6803.             if(AddPart(name,fileName,sizeof(name)))
  6804.                 D(("Looking for a lock on file |%s|",name));
  6805.         }
  6806.     }
  6807.     #endif /* DEBUG */
  6808.  
  6809.     for(fln = (struct FileLockNode *)SambaSemaphore->ss_FileLockList.lh_Head ;
  6810.         fln->fln_MinNode.mln_Succ != NULL ;
  6811.         fln = (struct FileLockNode *)fln->fln_MinNode.mln_Succ)
  6812.     {
  6813.         if(SameLock(fln->fln_FileParentDir,dirLock) == LOCK_SAME)
  6814.         {
  6815.             if(Stricmp(fln->fln_FileName,fileName) == SAME)
  6816.             {
  6817.                 result = fln;
  6818.  
  6819.                 break;
  6820.             }
  6821.         }
  6822.     }
  6823.  
  6824.     if(result != NULL)
  6825.         SHOWMSG("found one");
  6826.     else
  6827.         SHOWMSG("didn't find one");
  6828.  
  6829.     (*resultPtr) = result;
  6830. }
  6831.  
  6832. STATIC struct LockedRegionNode *
  6833. FindCollidingRegion(struct FileLockNode * fln,LONG start,LONG stop,BOOL shared)
  6834. {
  6835.     struct LockedRegionNode * result = NULL;
  6836.     struct LockedRegionNode * lrn;
  6837.  
  6838.     /* This routine looks for a locked region that overlaps
  6839.      * with the specified region. It returns a pointer to the
  6840.      * region that would collide with the specified region if
  6841.      * a new lock were to be added.
  6842.      */
  6843.     for(lrn = (struct LockedRegionNode *)fln->fln_LockedRegionList.lh_Head ;
  6844.         lrn->lrn_MinNode.mln_Succ != NULL ;
  6845.         lrn = (struct LockedRegionNode *)lrn->lrn_MinNode.mln_Succ)
  6846.     {
  6847.         /* Do the regions overlap? */
  6848.         if(lrn->lrn_Start <= stop && start <= lrn->lrn_Stop)
  6849.         {
  6850.             /* Two shared regions may always overlap.
  6851.              * How about the rest?
  6852.              */
  6853.             if(NOT shared || NOT lrn->lrn_Shared)
  6854.             {
  6855.                 /* The lock owner may add as many exclusive
  6856.                  * or shared locks to the same region as
  6857.                  * necessary.
  6858.                  */
  6859.                 if(lrn->lrn_Owner == ThisClient->scn_PID)
  6860.                     continue;
  6861.  
  6862.                 /* So we found a region that would
  6863.                  * cause a collision.
  6864.                  */
  6865.                 result = lrn;
  6866.                 break;
  6867.             }
  6868.         }
  6869.     }
  6870.  
  6871.     return(result);
  6872. }
  6873.  
  6874. STATIC VOID
  6875. CleanupFileLocks(int fd)
  6876. {
  6877.     struct UFB * ufb;
  6878.  
  6879.     /* This routine removes all locked regions from a file
  6880.      * before it is eventually closed.
  6881.      */
  6882.  
  6883.     ufb = chkufb(fd);
  6884.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_LOCKED))
  6885.     {
  6886.         BPTR fileHandle = (BPTR)ufb->ufbfh;
  6887.         struct FileLockNode * whichLock;
  6888.  
  6889.         ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6890.  
  6891.         if(FindFileLockNodeByFileHandle(fileHandle,&whichLock) == OK && whichLock != NULL)
  6892.         {
  6893.             struct LockedRegionNode * lrn_this;
  6894.             struct LockedRegionNode * lrn_next;
  6895.  
  6896.             SHOWMSG("unlocking all regions on this file");
  6897.  
  6898.             for(lrn_this = (struct LockedRegionNode *)whichLock->fln_LockedRegionList.lh_Head ;
  6899.                (lrn_next = (struct LockedRegionNode *)lrn_this->lrn_MinNode.mln_Succ) != NULL ;
  6900.                 lrn_this = lrn_next)
  6901.             {
  6902.                 if(lrn_this->lrn_Owner == ThisClient->scn_PID)
  6903.                 {
  6904.                     Remove((struct Node *)lrn_this);
  6905.                     DeleteLockedRegionNode(lrn_this);
  6906.                 }
  6907.             }
  6908.  
  6909.             if(IsListEmpty(&whichLock->fln_LockedRegionList))
  6910.             {
  6911.                 SHOWMSG("no more regions are locked; removing the file lock node");
  6912.  
  6913.                 Remove((struct Node *)whichLock);
  6914.  
  6915.                 DeleteFileLockNode(whichLock);
  6916.             }
  6917.         }
  6918.  
  6919.         CLEAR_FLAG(ufb->ufbflg,UFB_LOCKED);
  6920.  
  6921.         ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6922.     }
  6923. }
  6924.  
  6925. #define SEEK_ERROR (-1)
  6926.  
  6927. STATIC int
  6928. HandleFileLocking(int cmd,struct flock * l,struct UFB * ufb)
  6929. {
  6930.     int result = ERROR;
  6931.  
  6932.     /* This routine implements advisory file segment locking
  6933.      * similar to 4.4BSD, but not quite the same. The functionality
  6934.      * is a subset, somewhat similar to the functionality offered
  6935.      * by the AmigaDOS LockRecord() and UnlockRecord() functions.
  6936.      * This means for example that every unlock request must
  6937.      * match the size and position of the corresponding locking
  6938.      * request.
  6939.      *
  6940.      * This implementation was chosen because not every Amiga
  6941.      * filing system implements record locking and Samba
  6942.      * absolutely requires this functionality to work.
  6943.      */
  6944.     if(l != NULL && ufb != NULL)
  6945.     {
  6946.         /* Can we make sense of the input parameters? */
  6947.         if(F_RDLCK <= l->l_type && l->l_type <= F_WRLCK &&
  6948.           (l->l_whence == SEEK_SET || l->l_whence == SEEK_CUR || l->l_whence == SEEK_END))
  6949.         {
  6950.             struct LockedRegionNode * lrn = NULL;
  6951.             struct FileLockNode * fln = NULL;
  6952.             LONG error;
  6953.  
  6954.             if((cmd == F_SETLK || cmd == F_SETLKW) && (l->l_type != F_UNLCK))
  6955.             {
  6956.                 SHOWMSG("this is a lock request");
  6957.                 error = CreateFileLockNode(ufb,&fln);
  6958.                 if(error == OK)
  6959.                     error = CreateLockedRegionNode(&lrn);
  6960.             }
  6961.             else
  6962.             {
  6963.                 SHOWMSG("this is not a lock request");
  6964.                 error = OK;
  6965.             }
  6966.  
  6967.             if(error == OK)
  6968.             {
  6969.                 struct FileInfoBlock __aligned fib;
  6970.                 BPTR fileHandle = (BPTR)ufb->ufbfh;
  6971.                 BOOL dataIsValid = TRUE;
  6972.                 LONG currentPosition;
  6973.                 LONG start = 0;
  6974.                 LONG len = 0;
  6975.  
  6976.                 /* Now calculate the position of the
  6977.                  * first byte to lock and the number
  6978.                  * of bytes to lock.
  6979.                  */
  6980.                 switch(l->l_whence)
  6981.                 {
  6982.                     case SEEK_SET:
  6983.  
  6984.                         start = l->l_start;
  6985.  
  6986.                         if(l->l_len == 0)
  6987.                         {
  6988.                             if(ExamineFH(fileHandle,&fib))
  6989.                                 len = fib.fib_Size - start;
  6990.                             else
  6991.                                 dataIsValid = FALSE;
  6992.                         }
  6993.                         else
  6994.                         {
  6995.                             len = l->l_len;
  6996.                         }
  6997.  
  6998.                         break;
  6999.  
  7000.                     case SEEK_CUR:
  7001.  
  7002.                         currentPosition = Seek(fileHandle,0,OFFSET_CURRENT);
  7003.                         if(currentPosition != SEEK_ERROR)
  7004.                         {
  7005.                             start = currentPosition + l->l_start;
  7006.  
  7007.                             if(l->l_len == 0)
  7008.                             {
  7009.                                 if(ExamineFH(fileHandle,&fib))
  7010.                                     len = fib.fib_Size - start;
  7011.                                 else
  7012.                                     dataIsValid = FALSE;
  7013.                             }
  7014.                             else
  7015.                             {
  7016.                                 len = l->l_len;
  7017.                             }
  7018.                         }
  7019.                         else
  7020.                         {
  7021.                             dataIsValid = FALSE;
  7022.                         }
  7023.  
  7024.                         break;
  7025.  
  7026.                     case SEEK_END:
  7027.                     default:
  7028.  
  7029.                         if(ExamineFH(fileHandle,&fib))
  7030.                         {
  7031.                             start = fib.fib_Size + l->l_start;
  7032.  
  7033.                             if(l->l_len == 0)
  7034.                                 len = fib.fib_Size - start;
  7035.                             else
  7036.                                 len = l->l_len;
  7037.                         }
  7038.                         else
  7039.                         {
  7040.                             dataIsValid = FALSE;
  7041.                         }
  7042.  
  7043.                         break;
  7044.                 }
  7045.  
  7046.                 SHOWVALUE(start);
  7047.                 SHOWVALUE(len);
  7048.  
  7049.                 /* Did we get everything we needed? */
  7050.                 if(dataIsValid)
  7051.                 {
  7052.                     if(start >= 0 && len >= 0)
  7053.                     {
  7054.                         if(len > 0)
  7055.                         {
  7056.                             if(l->l_type == F_UNLCK)
  7057.                             {
  7058.                                 D(("unlocking %ld..%ld",start,start+len-1));
  7059.  
  7060.                                 ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7061.  
  7062.                                 RemoveLockedRegionNode(ufb,start,start+len-1);
  7063.  
  7064.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7065.  
  7066.                                 result = OK;
  7067.                             }
  7068.                             else if(cmd == F_SETLKW)
  7069.                             {
  7070.                                 BPTR parentDir;
  7071.  
  7072.                                 D(("  locking %ld..%ld",start,start+len-1));
  7073.  
  7074.                                 parentDir = ParentOfFH(fileHandle);
  7075.                                 if(parentDir != ZERO)
  7076.                                 {
  7077.                                     struct FileInfoBlock __aligned fib;
  7078.  
  7079.                                     if(ExamineFH(fileHandle,&fib))
  7080.                                     {
  7081.                                         BOOL shared = (BOOL)(l->l_type == F_RDLCK);
  7082.                                         struct FileLockNode * existing_fln;
  7083.                                         BOOL stopped = FALSE;
  7084.                                         BOOL locked;
  7085.  
  7086.                                         if(shared)
  7087.                                             D(("this is a shared lock; waiting for completion"));
  7088.                                         else
  7089.                                             D(("this is an exclusive lock; waiting for completion"));
  7090.  
  7091.                                         lrn->lrn_Start    = start;
  7092.                                         lrn->lrn_Stop    = start+len-1;
  7093.                                         lrn->lrn_Shared    = shared;
  7094.  
  7095.                                         /* Retry until we manage to lock the record. */
  7096.                                         locked = FALSE;
  7097.                                         do
  7098.                                         {
  7099.                                             ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7100.  
  7101.                                             FindFileLockNodeByDrawerAndName(parentDir,fib.fib_FileName,&existing_fln);
  7102.                                             if(existing_fln != NULL)
  7103.                                             {
  7104.                                                 SHOWMSG("that file is already locked by someone");
  7105.  
  7106.                                                 if(FindCollidingRegion(existing_fln,start,start+len-1,shared) == NULL)
  7107.                                                 {
  7108.                                                     SHOWMSG("but the locks don't collide");
  7109.  
  7110.                                                     AddTail(&existing_fln->fln_LockedRegionList,(struct Node *)lrn);
  7111.                                                     lrn = NULL;
  7112.  
  7113.                                                     locked = TRUE;
  7114.                                                 }
  7115.                                                 else
  7116.                                                 {
  7117.                                                     SHOWMSG("and the locks collide");
  7118.                                                 }
  7119.                                             }
  7120.                                             else
  7121.                                             {
  7122.                                                 SHOWMSG("nobody has any locks on this file");
  7123.  
  7124.                                                 AddTail(&SambaSemaphore->ss_FileLockList,(struct Node *)fln);
  7125.                                                 AddTail(&fln->fln_LockedRegionList,(struct Node *)lrn);
  7126.  
  7127.                                                 fln = NULL;
  7128.                                                 lrn = NULL;
  7129.  
  7130.                                                 locked = TRUE;
  7131.                                             }
  7132.  
  7133.                                             ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7134.  
  7135.                                             if(NOT locked)
  7136.                                             {
  7137.                                                 const int randMax = RAND_MAX / 65536;
  7138.                                                 LONG numRandomTicks;
  7139.  
  7140.                                                 if(CheckAbort())
  7141.                                                 {
  7142.                                                     stopped = TRUE;
  7143.                                                     break;
  7144.                                                 }
  7145.  
  7146.                                                 /* Wait a little before retrying
  7147.                                                  * the locking operation. We add
  7148.                                                  * a little randomness here to
  7149.                                                  * reduce the likelihood of two
  7150.                                                  * competing processes trying to
  7151.                                                  * lock the same file at the
  7152.                                                  * same time.
  7153.                                                  */
  7154.  
  7155.                                                 numRandomTicks = ((TICKS_PER_SECOND / 2) * (rand() / 65536)) / randMax;
  7156.  
  7157.                                                 if(numRandomTicks > 0)
  7158.                                                     Delay(numRandomTicks);
  7159.                                             }
  7160.                                         }
  7161.                                         while(NOT locked);
  7162.  
  7163.                                         if(stopped)
  7164.                                         {
  7165.                                             SHOWMSG("lock polling loop stopped");
  7166.  
  7167.                                             DeleteFileLockNode(fln);
  7168.                                             fln = NULL;
  7169.  
  7170.                                             DeleteLockedRegionNode(lrn);
  7171.                                             lrn = NULL;
  7172.  
  7173.                                             UnLock(parentDir);
  7174.                                             parentDir = ZERO;
  7175.  
  7176.                                             errno = EINTR;
  7177.  
  7178.                                             raise(SIGINT);
  7179.                                         }
  7180.  
  7181.                                         if(locked)
  7182.                                         {
  7183.                                             SHOWMSG("the file now has a lock set");
  7184.                                             SET_FLAG(ufb->ufbflg,UFB_LOCKED);
  7185.                                             result = OK;
  7186.                                         }
  7187.                                     }
  7188.                                     else
  7189.                                     {
  7190.                                         SHOWMSG("couldn't read this file's name");
  7191.                                         MapIoErrToErrno();
  7192.                                     }
  7193.  
  7194.                                     UnLock(parentDir);
  7195.                                 }
  7196.                                 else
  7197.                                 {
  7198.                                     SHOWMSG("couldn't get a lock on the file's parent directory");
  7199.                                     MapIoErrToErrno();
  7200.                                 }
  7201.                             }
  7202.                             else if(cmd == F_SETLK)
  7203.                             {
  7204.                                 BOOL shared = (BOOL)(l->l_type == F_RDLCK);
  7205.                                 struct FileLockNode * existing_fln;
  7206.                                 BOOL locked = FALSE;
  7207.  
  7208.                                 if(shared)
  7209.                                     D(("this is a shared lock"));
  7210.                                 else
  7211.                                     D(("this is an exclusive lock"));
  7212.  
  7213.                                 lrn->lrn_Start    = start;
  7214.                                 lrn->lrn_Stop    = start+len-1;
  7215.                                 lrn->lrn_Shared    = shared;
  7216.  
  7217.                                 ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7218.  
  7219.                                 if(FindFileLockNodeByFileHandle(fileHandle,&existing_fln) == OK)
  7220.                                 {
  7221.                                     if(existing_fln != NULL)
  7222.                                     {
  7223.                                         SHOWMSG("that file is already locked by someone else");
  7224.  
  7225.                                         if(FindCollidingRegion(existing_fln,start,start+len-1,shared) == NULL)
  7226.                                         {
  7227.                                             SHOWMSG("but the locks don't collide");
  7228.  
  7229.                                             AddTail(&existing_fln->fln_LockedRegionList,(struct Node *)lrn);
  7230.                                             lrn = NULL;
  7231.  
  7232.                                             locked = TRUE;
  7233.                                         }
  7234.                                         else
  7235.                                         {
  7236.                                             SHOWMSG("and the locks collide");
  7237.                                         }
  7238.                                     }
  7239.                                     else
  7240.                                     {
  7241.                                         SHOWMSG("nobody has any locks on this file");
  7242.  
  7243.                                         AddTail(&SambaSemaphore->ss_FileLockList,(struct Node *)fln);
  7244.                                         AddTail(&fln->fln_LockedRegionList,(struct Node *)lrn);
  7245.  
  7246.                                         fln = NULL;
  7247.                                         lrn = NULL;
  7248.  
  7249.                                         locked = TRUE;
  7250.                                     }
  7251.                                 }
  7252.  
  7253.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7254.  
  7255.                                 if(locked)
  7256.                                 {
  7257.                                     SHOWMSG("the file now has a lock set");
  7258.  
  7259.                                     SET_FLAG(ufb->ufbflg,UFB_LOCKED);
  7260.  
  7261.                                     result = OK;
  7262.                                 }
  7263.                                 else
  7264.                                 {
  7265.                                     errno = EACCES;
  7266.                                 }
  7267.                             }
  7268.                             else if (cmd == F_GETLK)
  7269.                             {
  7270.                                 struct FileLockNode * fln;
  7271.                                 LONG error;
  7272.  
  7273.                                 SafeObtainSemaphoreShared((struct SignalSemaphore *)SambaSemaphore);
  7274.  
  7275.                                 SHOWMSG("checking for possible lock collision");
  7276.  
  7277.                                 error = FindFileLockNodeByFileHandle(fileHandle,&fln);
  7278.                                 if(error == OK)
  7279.                                 {
  7280.                                     if(fln != NULL)
  7281.                                     {
  7282.                                         struct LockedRegionNode * lrn;
  7283.                                         BOOL shared;
  7284.  
  7285.                                         SHOWMSG("somebody has locked this file");
  7286.  
  7287.                                         shared = (BOOL)(l->l_type == F_RDLCK);
  7288.  
  7289.                                         lrn = FindCollidingRegion(fln,start,start+len-1,shared);
  7290.                                         if(lrn != NULL)
  7291.                                         {
  7292.                                             SHOWMSG("there is a possible lock collision");
  7293.  
  7294.                                             l->l_type    = (lrn->lrn_Shared ? F_RDLCK : F_WRLCK);
  7295.                                             l->l_whence    = SEEK_SET;
  7296.                                             l->l_start    = lrn->lrn_Start;
  7297.                                             l->l_len    = lrn->lrn_Stop - lrn->lrn_Start + 1;
  7298.                                             l->l_pid    = lrn->lrn_Owner;
  7299.                                         }
  7300.                                         else
  7301.                                         {
  7302.                                             SHOWMSG("there is no lock collision");
  7303.  
  7304.                                             l->l_type = F_UNLCK;
  7305.                                         }
  7306.                                     }
  7307.                                     else
  7308.                                     {
  7309.                                         SHOWMSG("nobody has locked this file");
  7310.  
  7311.                                         l->l_type = F_UNLCK;
  7312.                                     }
  7313.  
  7314.                                     result = OK;
  7315.                                 }
  7316.                                 else
  7317.                                 {
  7318.                                     SetIoErr(error);
  7319.  
  7320.                                     MapIoErrToErrno();
  7321.                                 }
  7322.  
  7323.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7324.                             }
  7325.                         }
  7326.                         else
  7327.                         {
  7328.                             SHOWMSG("zero length lock/unlock");
  7329.                             result = OK;
  7330.                         }
  7331.                     }
  7332.                     else
  7333.                     {
  7334.                         SHOWMSG("invalid start/len");
  7335.                         SHOWVALUE(start);
  7336.                         SHOWVALUE(len);
  7337.                         errno = EINVAL;
  7338.                     }
  7339.                 }
  7340.                 else
  7341.                 {
  7342.                     SHOWMSG("couldn't determine start/len");
  7343.                     MapIoErrToErrno();
  7344.                 }
  7345.             }
  7346.             else
  7347.             {
  7348.                 SHOWMSG("couldn't get the bookkeeping memory needed");
  7349.                 MapIoErrToErrno();
  7350.             }
  7351.  
  7352.             DeleteFileLockNode(fln);
  7353.             DeleteLockedRegionNode(lrn);
  7354.         }
  7355.         else
  7356.         {
  7357.             SHOWMSG("invalid lock type or seek offset");
  7358.             SHOWVALUE(l->l_type);
  7359.             SHOWVALUE(l->l_whence);
  7360.             errno = EINVAL;
  7361.         }
  7362.     }
  7363.     else
  7364.     {
  7365.         SHOWMSG("no flock or no ufb");
  7366.         SHOWVALUE(l);
  7367.         SHOWVALUE(ufb);
  7368.  
  7369.         errno = EINVAL;
  7370.     }
  7371.  
  7372.     RETURN(result);
  7373.     return(result);
  7374. }
  7375.  
  7376. int
  7377. amiga_fcntl(int fd,int cmd,unsigned long arg)
  7378. {
  7379.     struct UFB * ufb;
  7380.     struct flock * l;
  7381.     int result = ERROR;
  7382.  
  7383.     chkabort();
  7384.  
  7385.     ENTER();
  7386.  
  7387.     /* Don't try to lock data in a socket... */
  7388.     ufb = chkufb(fd);
  7389.     if(ufb == NULL || FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7390.         ufb = NULL;
  7391.  
  7392.     l = (struct flock *)arg;
  7393.  
  7394.     switch(cmd)
  7395.     {
  7396.         /* Get the first lock that blocks the lock description pointed to
  7397.          * by the third argument, arg, taken as a pointer to a struct
  7398.          * flock (see above).  The information retrieved overwrites the
  7399.          * information passed to fcntl in the flock structure.  If no
  7400.          * lock is found that would prevent this lock from being created,
  7401.          * the structure is left unchanged by this function call except
  7402.          * for the lock type which is set to F_UNLCK.
  7403.          */
  7404.         case F_GETLK:
  7405.  
  7406.             SHOWMSG("F_GETLK");
  7407.             result = HandleFileLocking(cmd,l,ufb);
  7408.             break;
  7409.  
  7410.         /* Set or clear a file segment lock according to the lock de-
  7411.          * scription pointed to by the third argument, arg, taken as a
  7412.          * pointer to a struct flock (see above).    F_SETLK is used to es-
  7413.          * tablish shared (or read) locks (F_RDLCK) or exclusive (or
  7414.          * write) locks, (F_WRLCK), as well as remove either type of lock
  7415.          * (F_UNLCK). If a shared or exclusive lock cannot be set, fcntl
  7416.          * returns immediately with EACCES.
  7417.          */
  7418.         case F_SETLK:
  7419.  
  7420.             SHOWMSG("F_SETLK");
  7421.             result = HandleFileLocking(cmd,l,ufb);
  7422.             break;
  7423.  
  7424.         /* This command is the same as F_SETLK except that if a shared or
  7425.          * exclusive lock is blocked by other locks, the process waits
  7426.          * until the request can be satisfied.  If a signal that is to be
  7427.          * caught is received while fcntl is waiting for a region, the
  7428.          * fcntl will be interrupted if the signal handler has not speci-
  7429.          * fied the SA_RESTART (see sigaction(2)).
  7430.          */
  7431.         case F_SETLKW:
  7432.  
  7433.             SHOWMSG("F_SETLKW");
  7434.             result = HandleFileLocking(cmd,l,ufb);
  7435.             break;
  7436.  
  7437.         /* Get descriptor status flags, as described below (arg is ig-
  7438.          * noted).
  7439.          */
  7440.         case F_GETFL:
  7441.  
  7442.             SHOWMSG("F_GETFL");
  7443.             result = IsDescriptorNonblocking(fd) ? O_NONBLOCK : 0;
  7444.             break;
  7445.  
  7446.         /* Set descriptor status flags to arg. */
  7447.         case F_SETFL:
  7448.  
  7449.             SHOWMSG("F_SETFL");
  7450.             if(FLAG_IS_SET(arg,O_NONBLOCK))
  7451.                 BlockDescriptor(fd);
  7452.             else
  7453.                 UnblockDescriptor(fd);
  7454.  
  7455.             result = OK;
  7456.             break;
  7457.  
  7458.         default:
  7459.  
  7460.             D(("Unknown command %ld",cmd));
  7461.             errno = ENOSYS;
  7462.             break;
  7463.     }
  7464.  
  7465.     RETURN(result);
  7466.     return(result);
  7467. }
  7468.  
  7469. /******************************************************************************/
  7470.  
  7471. int
  7472. amiga_fgetc(FILE *in)
  7473. {
  7474.     struct UFB * ufb;
  7475.     int result = ERROR;
  7476.  
  7477.     PUSH_ASSERTS();
  7478.  
  7479.     chkabort();
  7480.  
  7481.     ufb = chkufb(fileno(in));
  7482.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7483.     {
  7484.         UBYTE c;
  7485.  
  7486.         ENTER();
  7487.         SHOWMSG("input from socket");
  7488.  
  7489.         if(recv(ufb->ufbfh,&c,1,0) == 1)
  7490.             result = c;
  7491.     }
  7492.     else
  7493.     {
  7494.         result = fgetc(in);
  7495.     }
  7496.  
  7497.     RETURN(result);
  7498.     POP();
  7499.     return(result);
  7500. }
  7501.  
  7502. char *
  7503. amiga_fgets(char *str,int n,FILE * in)
  7504. {
  7505.     struct UFB * ufb;
  7506.     char *result;
  7507.  
  7508.     ENTER();
  7509.  
  7510.     ufb = chkufb(fileno(in));
  7511.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7512.     {
  7513.         char *s = str;
  7514.         LONG rc;
  7515.         UBYTE c;
  7516.  
  7517.         SHOWMSG("input from socket");
  7518.         result = str;
  7519.  
  7520.         while(--n > 0)
  7521.         {
  7522.             chkabort();
  7523.  
  7524.             rc = recv(ufb->ufbfh,&c,1,0);
  7525.             if(rc == 1)
  7526.             {
  7527.                 (*str++) = c;
  7528.  
  7529.                 if(c == '\n')
  7530.                     break;
  7531.             }
  7532.             else
  7533.             {
  7534.                 /* End of stream or nothing read? */
  7535.                 if(rc < 0 || str == s)
  7536.                     result = NULL;
  7537.  
  7538.                 break;
  7539.             }
  7540.         }
  7541.  
  7542.         if(result != NULL)
  7543.             (*str) = '\0';
  7544.     }
  7545.     else
  7546.     {
  7547.         result = fgets(str,n,in);
  7548.     }
  7549.  
  7550.     RETURN(result);
  7551.     return(result);
  7552. }
  7553.  
  7554. int
  7555. amiga_fputs(const char *str,FILE *out)
  7556. {
  7557.     struct UFB * ufb;
  7558.     int result;
  7559.  
  7560.     chkabort();
  7561.  
  7562.     ENTER();
  7563.  
  7564.     ufb = chkufb(fileno(out));
  7565.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7566.     {
  7567.         SHOWMSG("output to socket");
  7568.  
  7569.         if(NOT STRING_IS_EMPTY(str))
  7570.             result = send(ufb->ufbfh,str,strlen(str),0);
  7571.         else
  7572.             result = OK;
  7573.  
  7574.         if(result == OK)
  7575.             result = send(ufb->ufbfh,"\n",1,0);
  7576.     }
  7577.     else
  7578.     {
  7579.         result = fputs(str,out);
  7580.     }
  7581.  
  7582.     RETURN(result);
  7583.     return(result);
  7584. }
  7585.  
  7586. int
  7587. amiga_puts(const char *str)
  7588. {
  7589.     int result;
  7590.  
  7591.     result = amiga_fputs(str,stdout);
  7592.  
  7593.     return(result);
  7594. }
  7595.  
  7596. int
  7597. amiga_vfprintf(FILE *out,const char *fmt,va_list args)
  7598. {
  7599.     struct UFB * ufb;
  7600.     int result;
  7601.  
  7602.     chkabort();
  7603.  
  7604.     ENTER();
  7605.  
  7606.     ufb = chkufb(fileno(out));
  7607.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7608.     {
  7609.         char buffer[1024];
  7610.  
  7611.         SHOWMSG("output to socket");
  7612.  
  7613.         vsnprintf(buffer,sizeof(buffer)-1,fmt,args);
  7614.         buffer[sizeof(buffer)-1] = '\0';
  7615.  
  7616.         if(NOT STRING_IS_EMPTY(buffer))
  7617.             result = send(ufb->ufbfh,buffer,strlen(buffer),0);
  7618.         else
  7619.             result = 0;
  7620.     }
  7621.     else
  7622.     {
  7623.         result = vfprintf(out,fmt,args);
  7624.     }
  7625.  
  7626.     RETURN(result);
  7627.     return(result);
  7628. }
  7629.  
  7630. int
  7631. amiga_fprintf(FILE *out,const char *fmt,...)
  7632. {
  7633.     va_list args;
  7634.     int result;
  7635.  
  7636.     va_start(args,fmt);
  7637.     result = amiga_vfprintf(out,fmt,args);
  7638.     va_end(args);
  7639.  
  7640.     return(result);
  7641. }
  7642.  
  7643. int
  7644. amiga_printf(const char *fmt,...)
  7645. {
  7646.     va_list args;
  7647.     int result;
  7648.  
  7649.     va_start(args,fmt);
  7650.     result = amiga_vfprintf(stdout,fmt,args);
  7651.     va_end(args);
  7652.  
  7653.     return(result);
  7654. }
  7655.  
  7656. size_t
  7657. amiga_fwrite(const void *data,size_t blockSize,size_t numBlocks,FILE *out)
  7658. {
  7659.     struct UFB * ufb;
  7660.     size_t result;
  7661.  
  7662.     chkabort();
  7663.  
  7664.     ENTER();
  7665.  
  7666.     ufb = chkufb(fileno(out));
  7667.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7668.     {
  7669.         SHOWMSG("output to socket");
  7670.  
  7671.         result = send(ufb->ufbfh,(APTR)data,blockSize * numBlocks,0);
  7672.         if(result > 0)
  7673.             result = (result/blockSize);
  7674.     }
  7675.     else
  7676.     {
  7677.         result = fwrite(data,blockSize,numBlocks,out);
  7678.     }
  7679.  
  7680.     RETURN(result);
  7681.     return(result);
  7682. }
  7683.  
  7684. size_t
  7685. amiga_fread(void *data,size_t blockSize,size_t numBlocks,FILE *in)
  7686. {
  7687.     struct UFB * ufb;
  7688.     size_t result;
  7689.  
  7690.     chkabort();
  7691.  
  7692.     ENTER();
  7693.  
  7694.     ufb = chkufb(fileno(in));
  7695.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7696.     {
  7697.         SHOWMSG("input from socket");
  7698.  
  7699.         result = recv(ufb->ufbfh,(APTR)data,blockSize * numBlocks,0);
  7700.         if(result > 0)
  7701.             result = (result/blockSize);
  7702.     }
  7703.     else
  7704.     {
  7705.         result = fread(data,blockSize,numBlocks,in);
  7706.     }
  7707.  
  7708.     RETURN(result);
  7709.     return(result);
  7710. }
  7711.  
  7712. int
  7713. amiga_fclose(FILE * stream)
  7714. {
  7715.     struct UFB * ufb;
  7716.     int result;
  7717.  
  7718.     chkabort();
  7719.  
  7720.     ENTER();
  7721.  
  7722.     ufb = chkufb(fileno(stream));
  7723.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7724.         result = OK;
  7725.     else
  7726.         result = fclose(stream);
  7727.  
  7728.     RETURN(result);
  7729.     return(result);
  7730. }
  7731.  
  7732. int
  7733. amiga_fflush(FILE * stream)
  7734. {
  7735.     struct UFB * ufb;
  7736.     int result;
  7737.  
  7738.     chkabort();
  7739.  
  7740.     ENTER();
  7741.  
  7742.     ufb = chkufb(fileno(stream));
  7743.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7744.         result = OK;
  7745.     else
  7746.         result = fflush(stream);
  7747.  
  7748.     RETURN(result);
  7749.     return(result);
  7750. }
  7751.  
  7752. int
  7753. amiga_fseek(FILE * stream,long int offset,int mode)
  7754. {
  7755.     struct UFB * ufb;
  7756.     int result;
  7757.  
  7758.     chkabort();
  7759.  
  7760.     ENTER();
  7761.  
  7762.     ufb = chkufb(fileno(stream));
  7763.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7764.         result = OK;
  7765.     else
  7766.         result = fseek(stream,offset,mode);
  7767.  
  7768.     RETURN(result);
  7769.     return(result);
  7770. }
  7771.  
  7772. long int
  7773. amiga_ftell(FILE * stream)
  7774. {
  7775.     struct UFB * ufb;
  7776.     long int result;
  7777.  
  7778.     chkabort();
  7779.  
  7780.     ENTER();
  7781.  
  7782.     ufb = chkufb(fileno(stream));
  7783.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7784.         result = 0;
  7785.     else
  7786.         result = ftell(stream);
  7787.  
  7788.     RETURN(result);
  7789.     return(result);
  7790. }
  7791.  
  7792. /******************************************************************************/
  7793.  
  7794. int
  7795. amiga_setvbuf(FILE *stream,char *buff,int type,size_t size)
  7796. {
  7797.     struct UFB * ufb;
  7798.     int result;
  7799.  
  7800.     chkabort();
  7801.  
  7802.     ENTER();
  7803.  
  7804.     ufb = chkufb(fileno(stream));
  7805.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7806.         result = OK;
  7807.     else
  7808.         result = setvbuf(stream,buff,type,size);
  7809.  
  7810.     RETURN(result);
  7811.     return(result);
  7812. }
  7813.  
  7814. /******************************************************************************/
  7815.  
  7816. int
  7817. amiga_fputc(int c,FILE *stream)
  7818. {
  7819.     struct UFB * ufb;
  7820.     int result = ERROR;
  7821.  
  7822.     chkabort();
  7823.  
  7824.     ENTER();
  7825.  
  7826.     ufb = chkufb(fileno(stream));
  7827.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7828.     {
  7829.         UBYTE oneByte = c;
  7830.  
  7831.         if(send(ufb->ufbfh,&oneByte,1,0) > 0)
  7832.             result = OK;
  7833.     }
  7834.     else
  7835.     {
  7836.         result = fputc(c,stream);
  7837.     }
  7838.  
  7839.     RETURN(result);
  7840.     return(result);
  7841. }
  7842.  
  7843. /******************************************************************************/
  7844.  
  7845. VOID
  7846. amiga_setbuf(FILE *stream,char *buffer)
  7847. {
  7848.     struct UFB * ufb;
  7849.  
  7850.     chkabort();
  7851.  
  7852.     ENTER();
  7853.  
  7854.     ufb = chkufb(fileno(stream));
  7855.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7856.     {
  7857.         /* Do nothing */
  7858.     }
  7859.     else
  7860.     {
  7861.         setbuf(stream,buffer);
  7862.     }
  7863.  
  7864.     LEAVE();
  7865. }
  7866.  
  7867. /******************************************************************************/
  7868.  
  7869. int
  7870. amiga_recv(int fd,void *buff,size_t nbytes,int flags)
  7871. {
  7872.     struct UFB * ufb;
  7873.     int result = ERROR;
  7874.  
  7875.     ENTER();
  7876.  
  7877.     ufb = chkufb(fd);
  7878.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7879.         result = recv(ufb->ufbfh,buff,nbytes,flags);
  7880.     else
  7881.         errno = EBADF;
  7882.  
  7883.     RETURN(result);
  7884.     return(result);
  7885. }
  7886.  
  7887. /******************************************************************************/
  7888.  
  7889. int
  7890. amiga_send(int fd,void *buff,size_t nbytes,int flags)
  7891. {
  7892.     struct UFB * ufb;
  7893.     int result = ERROR;
  7894.  
  7895.     ENTER();
  7896.  
  7897.     ufb = chkufb(fd);
  7898.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7899.         result = send(ufb->ufbfh,buff,nbytes,flags);
  7900.     else
  7901.         errno = EBADF;
  7902.  
  7903.     RETURN(result);
  7904.     return(result);
  7905. }
  7906.  
  7907. /******************************************************************************/
  7908.  
  7909. int
  7910. amiga_smbrun(char *cmd,char *outfile,BOOL shared)
  7911. {
  7912.     struct MangleInfo mi_cmd;
  7913.     struct MangleInfo mi_outfile;
  7914.     int result = ERROR;
  7915.  
  7916.     ENTER();
  7917.  
  7918.     ForbidDOS();
  7919.  
  7920.     if(outfile == NULL)
  7921.         outfile = "/dev/null";
  7922.  
  7923.     if(MangleName(&cmd,&mi_cmd) == OK)
  7924.     {
  7925.         if(MangleName(&outfile,&mi_outfile) == OK)
  7926.         {
  7927.             BPTR in;
  7928.  
  7929.             in = Open("NIL:",MODE_OLDFILE);
  7930.             if(in != ZERO)
  7931.             {
  7932.                 BPTR out;
  7933.  
  7934.                 out = Open(outfile,MODE_NEWFILE);
  7935.                 if(out != ZERO)
  7936.                 {
  7937.                     if(SystemTags(cmd,
  7938.                         SYS_Input,        in,
  7939.                         SYS_Output,        out,
  7940.                         SYS_UserShell,    TRUE,
  7941.                         NP_WindowPtr,    NULL,
  7942.                     TAG_DONE) != -1)
  7943.                     {
  7944.                         result = OK;
  7945.                     }
  7946.                     else
  7947.                     {
  7948.                         MapIoErrToErrno();
  7949.                     }
  7950.  
  7951.                     Close(out);
  7952.                 }
  7953.                 else
  7954.                 {
  7955.                     MapIoErrToErrno();
  7956.                 }
  7957.  
  7958.                 Close(in);
  7959.             }
  7960.             else
  7961.             {
  7962.                 MapIoErrToErrno();
  7963.             }
  7964.  
  7965.             UnmangleName(&outfile,&mi_outfile);
  7966.         }
  7967.  
  7968.         UnmangleName(&cmd,&mi_cmd);
  7969.     }
  7970.  
  7971.     PermitDOS();
  7972.  
  7973.     RETURN(result);
  7974.     return(result);
  7975. }
  7976.  
  7977. /******************************************************************************/
  7978.  
  7979. #define IFBSIZE 1024
  7980. #define max(a,b) ( (a) > (b) ? (a) : (b) )
  7981.  
  7982. int
  7983. amiga_get_interfaces(struct iface_struct * ifaces,int max_interfaces)
  7984. {
  7985.     struct ifreq * ifr_end;
  7986.     struct ifreq * ifr;
  7987.     struct ifconf * ifc;
  7988.     struct ifreq ifr_copy;
  7989.     int sockfd = -1;
  7990.     int result = -1;
  7991.     int total = 0;
  7992.     int len;
  7993.  
  7994.     /* Make room for the interface information. I hope
  7995.      * that 1024 bytes will be sufficient.
  7996.      */
  7997.     ifc = malloc(sizeof(*ifc) + IFBSIZE);
  7998.     if(ifc == NULL)
  7999.     {
  8000.         errno = ENOMEM;
  8001.         goto out;
  8002.     }
  8003.  
  8004.     sockfd = socket(AF_INET,SOCK_STREAM,0);
  8005.     if(sockfd < 0)
  8006.         goto out;
  8007.  
  8008.     /* Now attempt to copy the interface information into
  8009.      * the buffer. As of this writing, support for the
  8010.      * SIOCGIFCONF ioctl() action is undocumented in all
  8011.      * currently existing TCP/IP stacks. Nevertheless,
  8012.      * it appears to work.
  8013.      */
  8014.     ifc->ifc_len = IFBSIZE;
  8015.     ifc->ifc_buf = (char *)(ifc+1);
  8016.  
  8017.     if(IoctlSocket(sockfd,SIOCGIFCONF,(char *)ifc) != OK)
  8018.         goto out;
  8019.  
  8020.     len = ifc->ifc_len;
  8021.  
  8022.     ifr = (struct ifreq *)ifc->ifc_buf;
  8023.     ifr_end = (struct ifreq *)((char *)ifr + len);
  8024.  
  8025.     /* Now check each interface, extracting the interface
  8026.      * information.
  8027.      */
  8028.     while(ifr < ifr_end && total < max_interfaces)
  8029.     {
  8030.         ifr_copy = (*ifr);
  8031.  
  8032.         /* Try to obtain the address information. */
  8033.         if(IoctlSocket(sockfd,SIOCGIFADDR,(char *)&ifr_copy) == OK)
  8034.         {
  8035.             struct in_addr ipaddr;
  8036.  
  8037.             /* We need to remember this for later. */
  8038.             ipaddr = (*(struct sockaddr_in *)&ifr_copy.ifr_addr).sin_addr;
  8039.  
  8040.             /* And query the interface flags; in particular, we are interested
  8041.              * in whether this interface is currrently "up", i.e. "online".
  8042.              */
  8043.             if(IoctlSocket(sockfd,SIOCGIFFLAGS,(char *)&ifr_copy) == OK)
  8044.             {
  8045.                 if(ifr_copy.ifr_flags & IFF_UP)
  8046.                 {
  8047.                     /* And finally obtain the interface net mask. */
  8048.                     if(IoctlSocket(sockfd,SIOCGIFNETMASK,(char *)&ifr_copy) == OK)
  8049.                     {
  8050.                         struct in_addr nmask;
  8051.  
  8052.                         nmask = ((struct sockaddr_in *)&ifr_copy.ifr_addr)->sin_addr;
  8053.  
  8054.                         strncpy(ifaces[total].name, ifr_copy.ifr_name, sizeof(ifaces[total].name)-1);
  8055.                         ifaces[total].name[sizeof(ifaces[total].name)-1] = '\0';
  8056.  
  8057.                         ifaces[total].ip = ipaddr;
  8058.                         ifaces[total].netmask = nmask;
  8059.  
  8060.                         total++;
  8061.                     }
  8062.                 }
  8063.             }
  8064.         }
  8065.  
  8066.         len = max(sizeof(struct sockaddr),ifr->ifr_addr.sa_len);
  8067.         ifr = (struct ifreq *)(((char *)ifr) + sizeof(ifr->ifr_name) + len);
  8068.     }
  8069.  
  8070.     result = total;
  8071.  
  8072.  out:
  8073.  
  8074.     if(ifc != NULL)
  8075.         free(ifc);
  8076.  
  8077.     if(sockfd != -1)
  8078.         CloseSocket(sockfd);
  8079.  
  8080.     return(result);
  8081. }
  8082.  
  8083. /******************************************************************************/
  8084.  
  8085. FILE *
  8086. amiga_popen(const char * command,const char * mode)
  8087. {
  8088.     /* For now, nothing happens here. */
  8089.  
  8090.     errno = EPIPE;
  8091.  
  8092.     return(NULL);
  8093. }
  8094.  
  8095. int
  8096. amiga_pclose(FILE * fp)
  8097. {
  8098.     /* Almost twice as much happens here. */
  8099.     return(OK);
  8100. }
  8101.