client.c: Changed shadowed variable.
[kai/samba.git] / source3 / lib / util.c
index 6402b9a049d03e7963306ccc6c7809050a91c5ee..611794c4a8603ca73b3a4c078b0408214cd749ba 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Samba utility functions
-   Copyright (C) Andrew Tridgell 1992-1995
+   Copyright (C) Andrew Tridgell 1992-1997
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
 */
 
 #include "includes.h"
-#include "loadparm.h"
 
 pstring scope = "";
 
@@ -39,16 +38,15 @@ FILE *dbf = NULL;
 /* the client file descriptor */
 int Client = -1;
 
-/* info on the client */
-struct from_host Client_info=
-{"UNKNOWN","0.0.0.0",NULL};
-
 /* the last IP received from */
 struct in_addr lastip;
 
 /* the last port received from */
 int lastport=0;
 
+/* this is used by the chaining code */
+int chain_size = 0;
+
 int trans_num = 0;
 
 /*
@@ -56,7 +54,7 @@ int trans_num = 0;
 */
 int case_default = CASE_LOWER;
 
-pstring debugf = "/tmp/log.samba";
+pstring debugf = "";
 int syslog_level;
 
 /* the following control case operations - they are put here so the
@@ -70,16 +68,20 @@ BOOL case_mangle;
 fstring remote_machine="";
 fstring local_machine="";
 fstring remote_arch="UNKNOWN";
+static enum remote_arch_types ra_type = RA_UNKNOWN;
 fstring remote_proto="UNKNOWN";
 pstring myhostname="";
 pstring user_socket_options="";   
 pstring sesssetup_user="";
+pstring myname = "";
+fstring myworkgroup = "";
+char **my_netbios_names;
 
-
-static char *filename_dos(char *path,char *buf);
+int smb_read_error = 0;
 
 static BOOL stdout_logging = False;
 
+static char *filename_dos(char *path,char *buf);
 
 /*******************************************************************
   get ready for syslog stuff
@@ -90,7 +92,11 @@ void setup_logging(char *pname,BOOL interactive)
   if (!interactive) {
     char *p = strrchr(pname,'/');
     if (p) pname = p+1;
+#ifdef LOG_DAEMON
     openlog(pname, LOG_PID, LOG_DAEMON);
+#else /* LOG_DAEMON - for old systems that have no facility codes. */
+    openlog(pname, LOG_PID);
+#endif /* LOG_DAEMON */
   }
 #endif
   if (interactive) {
@@ -119,6 +125,7 @@ void reopen_logs(void)
 
       if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
        {
+         int oldumask = umask(022);
          strcpy(debugf,fname);
          if (dbf) fclose(dbf);
          if (append_log)
@@ -126,6 +133,7 @@ void reopen_logs(void)
          else
            dbf = fopen(debugf,"w");
          if (dbf) setbuf(dbf,NULL);
+         umask(oldumask);
        }
     }
   else
@@ -201,7 +209,9 @@ va_dcl
     {
       if (!dbf) 
        {
+         int oldumask = umask(022);
          dbf = fopen(debugf,"w");
+         umask(oldumask);
          if (dbf)
            setbuf(dbf,NULL);
          else
@@ -266,6 +276,21 @@ va_dcl
   return(0);
 }
 
+/****************************************************************************
+  find a suitable temporary directory. The result should be copied immediately
+  as it may be overwritten by a subsequent call
+  ****************************************************************************/
+char *tmpdir(void)
+{
+  char *p;
+  if ((p = getenv("TMPDIR"))) {
+    return p;
+  }
+  return "/tmp";
+}
+
+
+
 /****************************************************************************
 determine if a file descriptor is in fact a socket
 ****************************************************************************/
@@ -473,6 +498,12 @@ struct
 #endif
 #ifdef SO_RCVLOWAT
   {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},
+#endif
+#ifdef SO_SNDTIMEO
+  {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},
+#endif
+#ifdef SO_RCVTIMEO
+  {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},
 #endif
   {NULL,0,0,0,0}};
 
@@ -588,7 +619,7 @@ char *StrCpy(char *dest,char *src)
 /****************************************************************************
 line strncpy but always null terminates. Make sure there is room!
 ****************************************************************************/
-char *StrnCpy(char *dest,const char *src,int n)
+char *StrnCpy(char *dest,char *src,int n)
 {
   char *d = dest;
   if (!dest) return(NULL);
@@ -729,12 +760,17 @@ time_t file_modtime(char *fname)
 BOOL directory_exist(char *dname,struct stat *st)
 {
   struct stat st2;
+  BOOL ret;
+
   if (!st) st = &st2;
 
   if (sys_stat(dname,st) != 0) 
     return(False);
 
-  return(S_ISDIR(st->st_mode));
+  ret = S_ISDIR(st->st_mode);
+  if(!ret)
+    errno = ENOTDIR;
+  return ret;
 }
 
 /*******************************************************************
@@ -773,10 +809,63 @@ char *attrib_string(int mode)
 ********************************************************************/
 int StrCaseCmp(char *s, char *t)
 {
-  for (; tolower(*s) == tolower(*t); ++s, ++t)
-    if (!*s) return 0;
+  /* compare until we run out of string, either t or s, or find a difference */
+  /* We *must* use toupper rather than tolower here due to the
+     asynchronous upper to lower mapping.
+   */
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+  if(lp_client_code_page() == KANJI_CODEPAGE)
+  {
+    /* Win95 treats full width ascii characters as case sensitive. */
+    int diff;
+    for (;;)
+    {
+      if (!*s || !*t)
+           return toupper (*s) - toupper (*t);
+      else if (is_sj_alph (*s) && is_sj_alph (*t))
+      {
+        diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+        if (diff)
+          return diff;
+        s += 2;
+        t += 2;
+      }
+      else if (is_shift_jis (*s) && is_shift_jis (*t))
+      {
+        diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+        if (diff)
+          return diff;
+        diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+        if (diff)
+          return diff;
+        s += 2;
+        t += 2;
+      }
+      else if (is_shift_jis (*s))
+        return 1;
+      else if (is_shift_jis (*t))
+        return -1;
+      else 
+      {
+        diff = toupper (*s) - toupper (*t);
+        if (diff)
+          return diff;
+        s++;
+        t++;
+      }
+    }
+  }
+  else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+  {
+    while (*s && *t && toupper(*s) == toupper(*t))
+    {
+      s++;
+      t++;
+    }
 
-  return tolower(*s) - tolower(*t);
+    return(toupper(*s) - toupper(*t));
+  }
 }
 
 /*******************************************************************
@@ -784,19 +873,79 @@ int StrCaseCmp(char *s, char *t)
 ********************************************************************/
 int StrnCaseCmp(char *s, char *t, int n)
 {
-  while (n-- && *s && *t) {
-    if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t));
-    s++; t++;
+  /* compare until we run out of string, either t or s, or chars */
+  /* We *must* use toupper rather than tolower here due to the
+     asynchronous upper to lower mapping.
+   */
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+  if(lp_client_code_page() == KANJI_CODEPAGE)
+  {
+    /* Win95 treats full width ascii characters as case sensitive. */
+    int diff;
+    for (;n > 0;)
+    {
+      if (!*s || !*t)
+        return toupper (*s) - toupper (*t);
+      else if (is_sj_alph (*s) && is_sj_alph (*t))
+      {
+        diff = sj_toupper2 (*(s+1)) - sj_toupper2 (*(t+1));
+        if (diff)
+          return diff;
+        s += 2;
+        t += 2;
+        n -= 2;
+      }
+      else if (is_shift_jis (*s) && is_shift_jis (*t))
+      {
+        diff = ((int) (unsigned char) *s) - ((int) (unsigned char) *t);
+        if (diff)
+          return diff;
+        diff = ((int) (unsigned char) *(s+1)) - ((int) (unsigned char) *(t+1));
+        if (diff)
+          return diff;
+        s += 2;
+        t += 2;
+        n -= 2;
+      }
+      else if (is_shift_jis (*s))
+        return 1;
+      else if (is_shift_jis (*t))
+        return -1;
+      else 
+      {
+        diff = toupper (*s) - toupper (*t);
+        if (diff)
+          return diff;
+        s++;
+        t++;
+        n--;
+      }
+    }
+    return 0;
   }
-  if (n) return(tolower(*s) - tolower(*t));
+  else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+  {
+    while (n-- && *s && *t && toupper(*s) == toupper(*t))
+    {
+      s++;
+      t++;
+    }
 
-  return(0);
+    /* not run out of chars - strings are different lengths */
+    if (n) 
+      return(toupper(*s) - toupper(*t));
+
+    /* identical up to where we run out of chars, 
+       and strings are same length */
+    return(0);
+  }
 }
 
 /*******************************************************************
   compare 2 strings 
 ********************************************************************/
-BOOL strequal(char *s1,char *s2)
+BOOL strequal(char *s1, char *s2)
 {
   if (s1 == s2) return(True);
   if (!s1 || !s2) return(False);
@@ -833,23 +982,36 @@ BOOL strcsequal(char *s1,char *s2)
 void strlower(char *s)
 {
   while (*s)
+  {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+    if(lp_client_code_page() == KANJI_CODEPAGE)
+    {
+      /* Win95 treats full width ascii characters as case sensitive. */
+      if (is_shift_jis (*s))
+      {
+        if (is_sj_upper (s[0], s[1]))
+          s[1] = sj_tolower2 (s[1]);
+        s += 2;
+      }
+      else if (is_kana (*s))
+      {
+        s++;
+      }
+      else
+      {
+        if (isupper(*s))
+          *s = tolower(*s);
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (isupper(*s))
-               *s = tolower(*s);
-           s++;
-       }
-#else
       if (isupper(*s))
-         *s = tolower(*s);
+        *s = tolower(*s);
       s++;
-#endif /* KANJI */
     }
+  }
 }
 
 /*******************************************************************
@@ -858,23 +1020,36 @@ void strlower(char *s)
 void strupper(char *s)
 {
   while (*s)
+  {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+    if(lp_client_code_page() == KANJI_CODEPAGE)
+    {
+      /* Win95 treats full width ascii characters as case sensitive. */
+      if (is_shift_jis (*s))
+      {
+        if (is_sj_lower (s[0], s[1]))
+          s[1] = sj_toupper2 (s[1]);
+        s += 2;
+      }
+      else if (is_kana (*s))
+      {
+        s++;
+      }
+      else
+      {
+        if (islower(*s))
+          *s = toupper(*s);
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (islower(*s))
-               *s = toupper(*s);
-           s++;
-       }
-#else
       if (islower(*s))
-       *s = toupper(*s);
+        *s = toupper(*s);
       s++;
-#endif
     }
+  }
 }
 
 /*******************************************************************
@@ -906,23 +1081,30 @@ BOOL strisnormal(char *s)
 void string_replace(char *s,char oldc,char newc)
 {
   while (*s)
+  {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+    if(lp_client_code_page() == KANJI_CODEPAGE)
+    {
+      /* Win95 treats full width ascii characters as case sensitive. */
+      if (is_shift_jis (*s))
+        s += 2;
+      else if (is_kana (*s))
+        s++;
+      else
+      {
+        if (oldc == *s)
+          *s = newc;
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (oldc == *s)
-               *s = newc;
-           s++;
-       }
-#else
       if (oldc == *s)
-       *s = newc;
+        *s = newc;
       s++;
-#endif /* KANJI */
     }
+  }
 }
 
 /****************************************************************************
@@ -932,13 +1114,10 @@ void unix_format(char *fname)
 {
   pstring namecopy;
   string_replace(fname,'\\','/');
-#ifndef KANJI
-  dos2unix_format(fname, True);
-#endif /* KANJI */
 
   if (*fname == '/')
     {
-      strcpy(namecopy,fname);
+      pstrcpy(namecopy,fname);
       strcpy(fname,".");
       strcat(fname,namecopy);
     }  
@@ -949,9 +1128,6 @@ void unix_format(char *fname)
 ****************************************************************************/
 void dos_format(char *fname)
 {
-#ifndef KANJI
-  unix2dos_format(fname, True);
-#endif /* KANJI */
   string_replace(fname,'/','\\');
 }
 
@@ -962,6 +1138,7 @@ void dos_format(char *fname)
 void show_msg(char *buf)
 {
   int i;
+  int j;
   int bcc=0;
   if (DEBUGLEVEL < 5)
     return;
@@ -987,10 +1164,29 @@ void show_msg(char *buf)
   DEBUG(5,("smb_bcc=%d\n",bcc));
   if (DEBUGLEVEL < 10)
     return;
-  for (i=0;i<MIN(bcc,128);i++)
-    DEBUG(10,("%X ",CVAL(smb_buf(buf),i)));
+  for (i = 0; i < MIN(bcc, 256); i += 16)
+  {
+    for (j = 0; j < 16 && i+j < MIN(bcc,256); j++)
+    {
+
+      DEBUG(10,("%2X ",CVAL(smb_buf(buf),i+j)));
+      if (j == 7) DEBUG(10, ("  "));
+
+    }
+    DEBUG(10,("  "));  
+
+    for (j = 0; j < 16 && i+j < MIN(bcc,256); j++)
+    {
+      unsigned char c = CVAL(smb_buf(buf),i+j);
+      if (c < 32 || c > 128) c = '.';
+      DEBUG(10,("%c",c));
+
+      if (j == 7) DEBUG(10, ("  "));
+    }
+
   DEBUG(10,("\n"));  
 }
+}
 
 /*******************************************************************
   return the length of an smb packet
@@ -1074,7 +1270,7 @@ return the SMB offset into an SMB buffer
 ********************************************************************/
 int smb_offset(char *p,char *buf)
 {
-  return(PTR_DIFF(p,buf+4));
+  return(PTR_DIFF(p,buf+4) + chain_size);
 }
 
 
@@ -1132,7 +1328,7 @@ void dos_clean_name(char *s)
       pstring s1;
 
       *p = 0;
-      strcpy(s1,p+3);
+      pstrcpy(s1,p+3);
 
       if ((p=strrchr(s,'\\')) != NULL)
        *p = 0;
@@ -1158,12 +1354,19 @@ void unix_clean_name(char *s)
   /* remove any double slashes */
   string_sub(s, "//","/");
 
+  /* Remove leading ./ characters */
+  if(strncmp(s, "./", 2) == 0) {
+    trim_string(s, "./", NULL);
+    if(*s == 0)
+      strcpy(s,"./");
+  }
+
   while ((p = strstr(s,"/../")) != NULL)
     {
       pstring s1;
 
       *p = 0;
-      strcpy(s1,p+3);
+      pstrcpy(s1,p+3);
 
       if ((p=strrchr(s,'/')) != NULL)
        *p = 0;
@@ -1190,24 +1393,10 @@ int ChDir(char *path)
   DEBUG(3,("chdir to %s\n",path));
   res = sys_chdir(path);
   if (!res)
-    strcpy(LastDir,path);
+    pstrcpy(LastDir,path);
   return(res);
 }
 
-
-/*******************************************************************
-  return the absolute current directory path. A dumb version.
-********************************************************************/
-static char *Dumb_GetWd(char *s)
-{
-#ifdef USE_GETCWD
-    return ((char *)getcwd(s,sizeof(pstring)));
-#else
-    return ((char *)getwd(s));
-#endif
-}
-
-
 /* number of list structures for a caching GetWd function. */
 #define MAX_GETWDCACHE (50)
 
@@ -1234,7 +1423,7 @@ char *GetWd(char *str)
   *s = 0;
 
   if (!use_getwd_cache)
-    return(Dumb_GetWd(str));
+    return(sys_getwd(str));
 
   /* init the cache */
   if (!getwd_cache_init)
@@ -1253,7 +1442,7 @@ char *GetWd(char *str)
   if (stat(".",&st) == -1) 
     {
       DEBUG(0,("Very strange, couldn't stat \".\"\n"));
-      return(Dumb_GetWd(str));
+      return(sys_getwd(str));
     }
 
 
@@ -1297,9 +1486,9 @@ char *GetWd(char *str)
       The very slow getcwd, which spawns a process on some systems, or the
       not quite so bad getwd. */
 
-  if (!Dumb_GetWd(s))
+  if (!sys_getwd(s))
     {
-      DEBUG(0,("Getwd failed, errno %d\n",errno));
+      DEBUG(0,("Getwd failed, errno %s\n",strerror(errno)));
       return (NULL);
     }
 
@@ -1352,6 +1541,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
          DEBUG(3,("Illegal file name? (%s)\n",s));
          return(False);
        }
+
+      if (strlen(s) == 0)
+        strcpy(s,"./");
+
       return(True);
     }
   
@@ -1360,7 +1553,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
   /* remove any double slashes */
   string_sub(s,"//","/");
 
-  strcpy(basename,s);
+  pstrcpy(basename,s);
   p = strrchr(basename,'/');
 
   if (!p)
@@ -1430,12 +1623,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
     if (relative)
       {
        if (newname[l] == '/')
-         strcpy(s,newname + l + 1);
+         pstrcpy(s,newname + l + 1);
        else
-         strcpy(s,newname+l);
+         pstrcpy(s,newname+l);
       }
     else
-      strcpy(s,newname);
+      pstrcpy(s,newname);
   }
 
   ChDir(wd);
@@ -1459,10 +1652,10 @@ static void expand_one(char *Mask,int len)
       int lfill = (len+1) - strlen(Mask);
       int l1= (p1 - Mask);
       pstring tmp;
-      strcpy(tmp,Mask);  
+      pstrcpy(tmp,Mask);  
       memset(tmp+l1,'?',lfill);
-      strcpy(tmp + l1 + lfill,Mask + l1 + 1);  
-      strcpy(Mask,tmp);      
+      pstrcpy(tmp + l1 + lfill,Mask + l1 + 1); 
+      pstrcpy(Mask,tmp);      
     }
 }
 
@@ -1486,20 +1679,20 @@ void expand_mask(char *Mask,BOOL doext)
 
   filename_dos(Mask,filepart);
 
-  strcpy(mbeg,filepart);
+  pstrcpy(mbeg,filepart);
   if ((p1 = strchr(mbeg,'.')) != NULL)
     {
       hasdot = True;
       *p1 = 0;
       p1++;
-      strcpy(mext,p1);
+      pstrcpy(mext,p1);
     }
   else
     {
       strcpy(mext,"");
       if (strlen(mbeg) > 8)
        {
-         strcpy(mext,mbeg + 8);
+         pstrcpy(mext,mbeg + 8);
          mbeg[8] = 0;
        }
     }
@@ -1517,7 +1710,7 @@ void expand_mask(char *Mask,BOOL doext)
   if (*mext)
     expand_one(mext,3);
 
-  strcpy(Mask,dirpart);
+  pstrcpy(Mask,dirpart);
   if (*dirpart || absolute) strcat(Mask,"\\");
   strcat(Mask,mbeg);
   strcat(Mask,".");
@@ -1533,21 +1726,30 @@ does a string have any uppercase chars in it?
 BOOL strhasupper(char *s)
 {
   while (*s) 
+  {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+    if(lp_client_code_page() == KANJI_CODEPAGE)
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (isupper(*s)) return(True);
-           s++;
-       }
-#else 
-      if (isupper(*s)) return(True);
+      /* Win95 treats full width ascii characters as case sensitive. */
+      if (is_shift_jis (*s))
+        s += 2;
+      else if (is_kana (*s))
+        s++;
+      else
+      {
+        if (isupper(*s))
+          return(True);
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+    {
+      if (isupper(*s))
+        return(True);
       s++;
-#endif /* KANJI */
     }
+  }
   return(False);
 }
 
@@ -1557,21 +1759,38 @@ does a string have any lowercase chars in it?
 BOOL strhaslower(char *s)
 {
   while (*s) 
+  {
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+    if(lp_client_code_page() == KANJI_CODEPAGE)
     {
-#ifdef KANJI
-       if (is_shift_jis (*s)) {
-           s += 2;
-       } else if (is_kana (*s)) {
-           s++;
-       } else {
-           if (islower(*s)) return(True);
-           s++;
-       }
-#else 
-      if (islower(*s)) return(True);
+      /* Win95 treats full width ascii characters as case sensitive. */
+      if (is_shift_jis (*s))
+      {
+        if (is_sj_upper (s[0], s[1]))
+          return(True);
+        if (is_sj_lower (s[0], s[1]))
+          return (True);
+        s += 2;
+      }
+      else if (is_kana (*s))
+      {
+        s++;
+      }
+      else
+      {
+        if (islower(*s))
+          return(True);
+        s++;
+      }
+    }
+    else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+    {
+      if (islower(*s))
+        return(True);
       s++;
-#endif /* KANJI */
     }
+  }
   return(False);
 }
 
@@ -1581,12 +1800,33 @@ find the number of chars in a string
 int count_chars(char *s,char c)
 {
   int count=0;
-  while (*s) 
+
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+  if(lp_client_code_page() == KANJI_CODEPAGE)
+  {
+    /* Win95 treats full width ascii characters as case sensitive. */
+    while (*s) 
+    {
+      if (is_shift_jis (*s))
+        s += 2;
+      else 
+      {
+        if (*s == c)
+          count++;
+        s++;
+      }
+    }
+  }
+  else
+#endif /* KANJI_WIN95_COMPATIBILITY */
+  {
+    while (*s) 
     {
       if (*s == c)
-       count++;
+        count++;
       s++;
     }
+  }
   return(count);
 }
 
@@ -1599,7 +1839,7 @@ void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode
   char *p;
   pstring mask2;
 
-  strcpy(mask2,mask);
+  pstrcpy(mask2,mask);
 
   if ((mode & aDIR) != 0)
     size = 0;
@@ -1651,6 +1891,35 @@ void close_low_fds(void)
   }
 }
 
+/****************************************************************************
+Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+else
+if SYSV use O_NDELAY
+if BSD use FNDELAY
+****************************************************************************/
+int set_blocking(int fd, BOOL set)
+{
+  int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+  if((val = fcntl(fd, F_GETFL, 0)) == -1)
+       return -1;
+  if(set) /* Turn blocking on - ie. clear nonblock flag */
+       val &= ~FLAG_TO_SET;
+  else
+    val |= FLAG_TO_SET;
+  return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
+
 
 /****************************************************************************
 write to a socket
@@ -1682,7 +1951,7 @@ int read_udp_socket(int fd,char *buf,int len)
   bzero((char *)&lastip,sizeof(lastip));
   ret = recvfrom(fd,buf,len,0,&sock,&socklen);
   if (ret <= 0) {
-    DEBUG(2,("read socket failed. ERRNO=%d\n",errno));
+    DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
     return(0);
   }
 
@@ -1692,103 +1961,44 @@ int read_udp_socket(int fd,char *buf,int len)
   return(ret);
 }
 
-/****************************************************************************
-Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
-else
-if SYSV use O_NDELAY
-if BSD use FNDELAY
-****************************************************************************/
-int set_blocking(int fd, BOOL set)
-{
-int val;
-#ifdef O_NONBLOCK
-#define FLAG_TO_SET O_NONBLOCK
-#else
-#ifdef SYSV
-#define FLAG_TO_SET O_NDELAY
-#else /* BSD */
-#define FLAG_TO_SET FNDELAY
-#endif
-#endif
-
-  if((val = fcntl(fd, F_GETFL, 0))==-1)
-       return -1;
-  if(set) /* Turn blocking on - ie. clear nonblock flag */
-       val &= ~FLAG_TO_SET;
-  else
-    val |= FLAG_TO_SET;
-  return fcntl( fd, F_SETFL, val);
-#undef FLAG_TO_SET
-}
-
-
-/****************************************************************************
-Calculate the difference in timeout values. Return 1 if val1 > val2,
-0 if val1 == val2, -1 if val1 < val2. Stores result in retval. retval
-may be == val1 or val2
-****************************************************************************/
-static int tval_sub( struct timeval *retval, struct timeval *val1, struct timeval *val2)
-{
-  int usecdiff = val1->tv_usec - val2->tv_usec;
-  int secdiff = val1->tv_sec - val2->tv_sec;
-  if(usecdiff < 0) {
-    usecdiff = 1000000 + usecdiff;
-    secdiff--;
-  }
-  retval->tv_sec = secdiff;
-  retval->tv_usec = usecdiff;
-  if(secdiff < 0)
-    return -1;
-  if(secdiff > 0)
-    return 1;
-  return (usecdiff < 0 ) ? -1 : ((usecdiff > 0 ) ? 1 : 0);
-}
-
 /****************************************************************************
 read data from a device with a timout in msec.
 mincount = if timeout, minimum to read before returning
 maxcount = number to be read.
 ****************************************************************************/
-int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL exact)
+int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out)
 {
   fd_set fds;
   int selrtn;
   int readret;
   int nread = 0;
-  struct timeval timeout, tval1, tval2, tvaldiff;
-  int error_limit = 5;
+  struct timeval timeout;
 
   /* just checking .... */
   if (maxcnt <= 0) return(0);
 
-  if(time_out == -2)
-    time_out = DEFAULT_PIPE_TIMEOUT;
+  smb_read_error = 0;
 
   /* Blocking read */
-  if(time_out < 0) {
+  if (time_out <= 0) {
     if (mincnt == 0) mincnt = maxcnt;
 
-    while (nread < mincnt)
-      {
-       readret = read(fd, buf + nread, maxcnt - nread);
-       if (readret <= 0) return(nread);
-       nread += readret;
+    while (nread < mincnt) {
+      readret = read(fd, buf + nread, maxcnt - nread);
+      if (readret == 0) {
+       smb_read_error = READ_EOF;
+       return -1;
       }
+
+      if (readret == -1) {
+       smb_read_error = READ_ERROR;
+       return -1;
+      }
+      nread += readret;
+    }
     return(nread);
   }
   
-  /* Non blocking read */
-  if(time_out == 0) {
-    set_blocking(fd, False);
-    nread = read_data(fd, buf, mincnt);
-    if (nread < maxcnt)
-      nread += read(fd,buf+nread,maxcnt-nread);
-    if(nread == -1 && errno == EWOULDBLOCK)
-      nread = 0;
-    set_blocking(fd,True);
-    return nread;
-  }
-
   /* Most difficult - timeout read */
   /* If this is ever called on a disk file and 
         mincnt is greater then the filesize then
@@ -1799,69 +2009,40 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out,BOOL
   timeout.tv_sec = time_out / 1000;
   timeout.tv_usec = 1000 * (time_out % 1000);
 
-  /* As most UNIXes don't modify the value of timeout
-     when they return from select we need to get the timeofday (in usec)
-     now, and also after the select returns so we know
-     how much time has elapsed */
-
-  if (exact)
-    GetTimeOfDay( &tval1);
-  nread = 0; /* Number of bytes we have read */
-
-  for(;;) 
+  for (nread=0; nread<mincnt; ) 
     {      
       FD_ZERO(&fds);
       FD_SET(fd,&fds);
       
       selrtn = sys_select(&fds,&timeout);
-      
+
       /* Check if error */
       if(selrtn == -1) {
+       /* something is wrong. Maybe the socket is dead? */
+       smb_read_error = READ_ERROR;
        return -1;
       }
       
       /* Did we timeout ? */
       if (selrtn == 0) {
-       if (nread < mincnt) return -1;
-       break; /* Yes */
+       smb_read_error = READ_TIMEOUT;
+       return -1;
       }
       
       readret = read(fd, buf+nread, maxcnt-nread);
-      if (readret == 0 && nread < mincnt) {
-       /* error_limit should not really be needed, but some systems
-          do strange things ...  I don't want to just continue
-          indefinately in case we get an infinite loop */
-       if (error_limit--) continue;
-       return(-1);
+      if (readret == 0) {
+       /* we got EOF on the file descriptor */
+       smb_read_error = READ_EOF;
+       return -1;
       }
 
-      if (readret < 0) {
-       /* force a particular error number for
-          portability */
-       DEBUG(5,("read gave error %s\n",strerror(errno)));
+      if (readret == -1) {
+       /* the descriptor is probably dead */
+       smb_read_error = READ_ERROR;
        return -1;
       }
       
       nread += readret;
-      
-      /* If we have read more than mincnt then return */
-      if (nread >= mincnt)
-       break;
-
-      /* We need to do another select - but first reduce the
-        time_out by the amount of time already elapsed - if
-        this is less than zero then return */
-      if (exact) {
-       GetTimeOfDay(&tval2);
-       (void)tval_sub( &tvaldiff, &tval2, &tval1);
-      
-       if (tval_sub(&timeout, &timeout, &tvaldiff) <= 0) 
-         break; /* We timed out */
-      }
-      
-      /* Save the time of day as we need to do the select 
-        again (saves a system call) */
-      tval1 = tval2;
     }
 
   /* Return the number we got */
@@ -1928,12 +2109,19 @@ int read_data(int fd,char *buffer,int N)
   int  ret;
   int total=0;  
  
+  smb_read_error = 0;
+
   while (total < N)
     {
       ret = read(fd,buffer + total,N - total);
-
-      if (ret <= 0)
-       return total;
+      if (ret == 0) {
+       smb_read_error = READ_EOF;
+       return 0;
+      }
+      if (ret == -1) {
+       smb_read_error = READ_ERROR;
+       return -1;
+      }
       total += ret;
     }
   return total;
@@ -1952,8 +2140,8 @@ int write_data(int fd,char *buffer,int N)
     {
       ret = write(fd,buffer + total,N - total);
 
-      if (ret <= 0)
-       return total;
+      if (ret == -1) return -1;
+      if (ret == 0) return total;
 
       total += ret;
     }
@@ -2057,30 +2245,19 @@ int read_smb_length(int fd,char *inbuf,int timeout)
   while (!ok)
     {
       if (timeout > 0)
-       ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 4);
-      else     
+       ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4);
+      else 
        ok = (read_data(fd,buffer,4) == 4);
 
       if (!ok)
-       {
-         if (timeout>0)
-           {
-             DEBUG(10,("select timeout (%d)\n", timeout));
-             return(-1);
-           }
-         else
-           {
-             DEBUG(6,("couldn't read from client\n"));
-             exit(1);
-           }
-       }
+       return(-1);
 
       len = smb_len(buffer);
       msg_type = CVAL(buffer,0);
 
       if (msg_type == 0x85) 
        {
-         DEBUG(5,( "Got keepalive packet\n"));
+         DEBUG(5,("Got keepalive packet\n"));
          ok = False;
        }
     }
@@ -2093,13 +2270,15 @@ int read_smb_length(int fd,char *inbuf,int timeout)
 
 
 /****************************************************************************
-  read an smb from a fd and return it's length
+  read an smb from a fd. Note that the buffer *MUST* be of size
+  BUFFER_SIZE+SAFETY_MARGIN.
 The timeout is in milli seconds
 ****************************************************************************/
-BOOL receive_smb(int fd,char *buffer,int timeout)
+BOOL receive_smb(int fd,char *buffer, int timeout)
 {
-  int len;
-  BOOL ok;
+  int len,ret;
+
+  smb_read_error = 0;
 
   bzero(buffer,smb_size + 100);
 
@@ -2108,22 +2287,216 @@ BOOL receive_smb(int fd,char *buffer,int timeout)
     return(False);
 
   if (len > BUFFER_SIZE) {
-    DEBUG(0,("Invalid packet length! (%d bytes)\n",len));
+    DEBUG(0,("Invalid packet length! (%d bytes).\n",len));
     if (len > BUFFER_SIZE + (SAFETY_MARGIN/2))
       exit(1);
   }
 
-  ok = (read_data(fd,buffer+4,len) == len);
-
-  if (!ok)
-    {
-      close_sockets();
-      exit(1);
-    }
+  ret = read_data(fd,buffer+4,len);
+  if (ret != len) {
+    smb_read_error = READ_ERROR;
+    return False;
+  }
 
   return(True);
 }
 
+/****************************************************************************
+  read a message from a udp fd.
+The timeout is in milli seconds
+****************************************************************************/
+BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout)
+{
+  struct sockaddr_in from;
+  int fromlen = sizeof(from);
+  int32 msg_len = 0;
+
+  if(timeout != 0)
+  {
+    struct timeval to;
+    fd_set fds;
+    int selrtn;
+
+    FD_ZERO(&fds);
+    FD_SET(fd,&fds);
+
+    to.tv_sec = timeout / 1000;
+    to.tv_usec = (timeout % 1000) * 1000;
+
+    selrtn = sys_select(&fds,&to);
+
+    /* Check if error */
+    if(selrtn == -1) 
+    {
+      /* something is wrong. Maybe the socket is dead? */
+      smb_read_error = READ_ERROR;
+      return False;
+    } 
+    
+    /* Did we timeout ? */
+    if (selrtn == 0) 
+    {
+      smb_read_error = READ_TIMEOUT;
+      return False;
+    }
+  }
+
+  /*
+   * Read a loopback udp message.
+   */
+  msg_len = recvfrom(fd, &buffer[UDP_CMD_HEADER_LEN], 
+                     buffer_len - UDP_CMD_HEADER_LEN, 0,
+                     (struct sockaddr *)&from, &fromlen);
+
+  if(msg_len < 0)
+  {
+    DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno)));
+    return False;
+  }
+
+  /* Validate message length. */
+  if(msg_len > (buffer_len - UDP_CMD_HEADER_LEN))
+  {
+    DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n",
+              msg_len, 
+              buffer_len  - UDP_CMD_HEADER_LEN));
+    return False;
+  }
+
+  /* Validate message from address (must be localhost). */
+  if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+  {
+    DEBUG(0,("receive_local_message: invalid 'from' address \
+(was %x should be 127.0.0.1\n", from.sin_addr.s_addr));
+   return False;
+  }
+
+  /* Setup the message header */
+  SIVAL(buffer,UDP_CMD_LEN_OFFSET,msg_len);
+  SSVAL(buffer,UDP_CMD_PORT_OFFSET,ntohs(from.sin_port));
+
+  return True;
+}
+
+/****************************************************************************
+ structure to hold a linked list of local udp messages.
+ for processing.
+****************************************************************************/
+
+typedef struct _udp_message_list {
+   struct _udp_message_list *msg_next;
+   char *msg_buf;
+   int msg_len;
+} udp_message_list;
+
+static udp_message_list *udp_msg_head = NULL;
+
+/****************************************************************************
+ Function to push a linked list of local udp messages ready
+ for processing.
+****************************************************************************/
+BOOL push_local_message(char *buf, int msg_len)
+{
+  udp_message_list *msg = (udp_message_list *)malloc(sizeof(udp_message_list));
+
+  if(msg == NULL)
+  {
+    DEBUG(0,("push_local_message: malloc fail (1)\n"));
+    return False;
+  }
+
+  msg->msg_buf = (char *)malloc(msg_len);
+  if(msg->msg_buf == NULL)
+  {
+    DEBUG(0,("push_local_message: malloc fail (2)\n"));
+    free((char *)msg);
+    return False;
+  }
+
+  memcpy(msg->msg_buf, buf, msg_len);
+  msg->msg_len = msg_len;
+
+  msg->msg_next = udp_msg_head;
+  udp_msg_head = msg;
+
+  return True;
+}
+
+/****************************************************************************
+  Do a select on an two fd's - with timeout. 
+
+  If a local udp message has been pushed onto the
+  queue (this can only happen during oplock break
+  processing) return this first.
+
+  If the first smbfd is ready then read an smb from it.
+  if the second (loopback UDP) fd is ready then read a message
+  from it and setup the buffer header to identify the length
+  and from address.
+  Returns False on timeout or error.
+  Else returns True.
+
+The timeout is in milli seconds
+****************************************************************************/
+BOOL receive_message_or_smb(int smbfd, int oplock_fd, 
+                           char *buffer, int buffer_len, 
+                           int timeout, BOOL *got_smb)
+{
+  fd_set fds;
+  int selrtn;
+  struct timeval to;
+
+  *got_smb = False;
+
+  /*
+   * Check to see if we already have a message on the udp queue.
+   * If so - copy and return it.
+   */
+
+  if(udp_msg_head)
+  {
+    udp_message_list *msg = udp_msg_head;
+    memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
+    udp_msg_head = msg->msg_next;
+
+    /* Free the message we just copied. */
+    free((char *)msg->msg_buf);
+    free((char *)msg);
+    return True;
+  }
+
+  FD_ZERO(&fds);
+  FD_SET(smbfd,&fds);
+  FD_SET(oplock_fd,&fds);
+
+  to.tv_sec = timeout / 1000;
+  to.tv_usec = (timeout % 1000) * 1000;
+
+  selrtn = sys_select(&fds,timeout>0?&to:NULL);
+
+  /* Check if error */
+  if(selrtn == -1) {
+    /* something is wrong. Maybe the socket is dead? */
+    smb_read_error = READ_ERROR;
+    return False;
+  } 
+    
+  /* Did we timeout ? */
+  if (selrtn == 0) {
+    smb_read_error = READ_TIMEOUT;
+    return False;
+  }
+
+  if (FD_ISSET(smbfd,&fds))
+  {
+    *got_smb = True;
+    return receive_smb(smbfd, buffer, 0);
+  }
+  else
+  {
+    return receive_local_message(oplock_fd, buffer, buffer_len, 0);
+  }
+}
 
 /****************************************************************************
   send an smb to a fd 
@@ -2232,8 +2605,8 @@ BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
   ret = (sendto(out_fd,buf,len,0,(struct sockaddr *)&sock_out,sizeof(sock_out)) >= 0);
 
   if (!ret)
-    DEBUG(0,("Packet send to %s(%d) failed ERRNO=%d\n",
-            inet_ntoa(ip),port,errno));
+    DEBUG(0,("Packet send to %s(%d) failed ERRNO=%s\n",
+            inet_ntoa(ip),port,strerror(errno)));
 
   close(out_fd);
   return(ret);
@@ -2311,7 +2684,12 @@ BOOL string_init(char **dest,char *src)
     }
   else
     {
-      *dest = (char *)malloc(l+1);
+      (*dest) = (char *)malloc(l+1);
+      if ((*dest) == NULL) {
+             DEBUG(0,("Out of memory in string_init\n"));
+             return False;
+      }
+
       strcpy(*dest,src);
     }
   return(True);
@@ -2480,35 +2858,35 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
 
   if (strequal(p1,"*")) return(True);
 
-  DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+  DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
 
   if (trans2) {
-    strcpy(ebase,p1);
-    strcpy(sbase,p2);
+    fstrcpy(ebase,p1);
+    fstrcpy(sbase,p2);
   } else {
     if ((p=strrchr(p1,'.'))) {
       *p = 0;
-      strcpy(ebase,p1);
-      strcpy(eext,p+1);
+      fstrcpy(ebase,p1);
+      fstrcpy(eext,p+1);
     } else {
-      strcpy(ebase,p1);
+      fstrcpy(ebase,p1);
       eext[0] = 0;
     }
 
   if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
     *p = 0;
-    strcpy(sbase,p2);
-    strcpy(sext,p+1);
+    fstrcpy(sbase,p2);
+    fstrcpy(sext,p+1);
   } else {
-    strcpy(sbase,p2);
-    strcpy(sext,"");
+    fstrcpy(sbase,p2);
+    fstrcpy(sext,"");
   }
   }
 
   matched = do_match(sbase,ebase,case_sig) && 
     (trans2 || do_match(sext,eext,case_sig));
 
-  DEBUG(5,("mask_match returning %d\n", matched));
+  DEBUG(8,("mask_match returning %d\n", matched));
 
   return matched;
 }
@@ -2527,7 +2905,7 @@ void become_daemon(void)
   /* detach from the terminal */
 #ifdef USE_SETSID
   setsid();
-#else
+#else /* USE_SETSID */
 #ifdef TIOCNOTTY
   {
     int i = open("/dev/tty", O_RDWR);
@@ -2537,9 +2915,11 @@ void become_daemon(void)
        close(i);
       }
   }
-#endif
-#endif
-#endif
+#endif /* TIOCNOTTY */
+#endif /* USE_SETSID */
+  /* Close fd's 0,1,2. Needed if started by rsh */
+  close_low_fds();
+#endif /* NO_FORK_DEBUG */
 }
 
 
@@ -2788,7 +3168,7 @@ void Abort(void )
 /****************************************************************************
 get my own name and IP
 ****************************************************************************/
-BOOL get_myname(char *myname,struct in_addr *ip)
+BOOL get_myname(char *my_name,struct in_addr *ip)
 {
   struct hostent *hp;
   pstring hostname;
@@ -2809,13 +3189,13 @@ BOOL get_myname(char *myname,struct in_addr *ip)
       return False;
     }
 
-  if (myname)
+  if (my_name)
     {
       /* split off any parts after an initial . */
       char *p = strchr(hostname,'.');
       if (p) *p = 0;
 
-      strcpy(myname,hostname);
+      fstrcpy(my_name,hostname);
     }
 
   if (ip)
@@ -2830,7 +3210,7 @@ true if two IP addresses are equal
 ****************************************************************************/
 BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
 {
-  unsigned long a1,a2;
+  uint32 a1,a2;
   a1 = ntohl(ip1.s_addr);
   a2 = ntohl(ip2.s_addr);
   return(a1 == a2);
@@ -2840,7 +3220,7 @@ BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
 /****************************************************************************
 open a socket of the specified type, port and address for incoming data
 ****************************************************************************/
-int open_socket_in(int type, int port, int dlevel)
+int open_socket_in(int type, int port, int dlevel,uint32 socket_addr)
 {
   struct hostent *hp;
   struct sockaddr_in sock;
@@ -2865,7 +3245,7 @@ int open_socket_in(int type, int port, int dlevel)
 #endif
   sock.sin_port = htons( port );
   sock.sin_family = hp->h_addrtype;
-  sock.sin_addr.s_addr = INADDR_ANY;
+  sock.sin_addr.s_addr = socket_addr;
   res = socket(hp->h_addrtype, type, 0);
   if (res == -1) 
     { DEBUG(0,("socket failed\n")); return -1; }
@@ -2880,15 +3260,15 @@ int open_socket_in(int type, int port, int dlevel)
     { 
       if (port) {
        if (port == SMB_PORT || port == NMB_PORT)
-         DEBUG(dlevel,("bind failed on port %d (%s)\n",
-                       port,strerror(errno))); 
+         DEBUG(dlevel,("bind failed on port %d socket_addr=%x (%s)\n",
+                       port,socket_addr,strerror(errno))); 
        close(res); 
 
        if (dlevel > 0 && port < 1000)
          port = 7999;
 
        if (port >= 1000 && port < 9000)
-         return(open_socket_in(type,port+1,dlevel));
+         return(open_socket_in(type,port+1,dlevel,socket_addr));
       }
 
       return(-1); 
@@ -2902,10 +3282,12 @@ int open_socket_in(int type, int port, int dlevel)
 /****************************************************************************
   create an outgoing socket
   **************************************************************************/
-int open_socket_out(int type, struct in_addr *addr, int port )
+int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
 {
   struct sockaddr_in sock_out;
-  int res;
+  int res,ret;
+  int connect_loop = 250; /* 250 milliseconds */
+  int loops = (timeout * 1000) / connect_loop;
 
   /* create a socket to write to */
   res = socket(PF_INET, type, 0);
@@ -2920,15 +3302,45 @@ int open_socket_out(int type, struct in_addr *addr, int port )
   sock_out.sin_port = htons( port );
   sock_out.sin_family = PF_INET;
 
+  /* set it non-blocking */
+  set_blocking(res,False);
+
   DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
   
   /* and connect it to the destination */
-  if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))<0) {
-    DEBUG(0,("connect error: %s\n",strerror(errno))); 
-    close(res); 
-    return(-1);
+connect_again:
+  ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
+
+  /* Some systems return EAGAIN when they mean EINPROGRESS */
+  if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+        errno == EAGAIN) && loops--) {
+    msleep(connect_loop);
+    goto connect_again;
+  }
+
+  if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+         errno == EAGAIN)) {
+      DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
+      close(res);
+      return -1;
   }
 
+#ifdef EISCONN
+  if (ret < 0 && errno == EISCONN) {
+    errno = 0;
+    ret = 0;
+  }
+#endif
+
+  if (ret < 0) {
+    DEBUG(1,("error connecting to %s:%d (%s)\n",
+            inet_ntoa(*addr),port,strerror(errno)));
+    return -1;
+  }
+
+  /* set it blocking again */
+  set_blocking(res,True);
+
   return res;
 }
 
@@ -2977,27 +3389,38 @@ int interpret_security(char *str,int def)
 /****************************************************************************
 interpret an internet address or name into an IP address in 4 byte form
 ****************************************************************************/
-unsigned long interpret_addr(char *str)
+uint32 interpret_addr(char *str)
 {
   struct hostent *hp;
-  unsigned long res;
+  uint32 res;
+  int i;
+  BOOL pure_address = True;
 
   if (strcmp(str,"0.0.0.0") == 0) return(0);
   if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
 
+  for (i=0; pure_address && str[i]; i++)
+    if (!(isdigit(str[i]) || str[i] == '.')) 
+      pure_address = False;
+
   /* if it's in the form of an IP address then get the lib to interpret it */
-  if (isdigit(str[0])) {
+  if (pure_address) {
     res = inet_addr(str);
   } else {
-    /* otherwise assume it's a network name of some sort and use Get_Hostbyname */
+    /* otherwise assume it's a network name of some sort and use 
+       Get_Hostbyname */
     if ((hp = Get_Hostbyname(str)) == 0) {
       DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str));
       return 0;
     }
+    if(hp->h_addr == NULL) {
+      DEBUG(3,("Get_Hostbyname: host address is invalid for host %s.\n",str));
+      return 0;
+    }
     putip((char *)&res,(char *)hp->h_addr);
   }
 
-  if (res == (unsigned long)-1) return(0);
+  if (res == (uint32)-1) return(0);
 
   return(res);
 }
@@ -3008,7 +3431,7 @@ unsigned long interpret_addr(char *str)
 struct in_addr *interpret_addr2(char *str)
 {
   static struct in_addr ret;
-  unsigned long a = interpret_addr(str);
+  uint32 a = interpret_addr(str);
   ret.s_addr = a;
   return(&ret);
 }
@@ -3018,60 +3441,184 @@ struct in_addr *interpret_addr2(char *str)
   ******************************************************************/
 BOOL zero_ip(struct in_addr ip)
 {
-  unsigned long a;
+  uint32 a;
   putip((char *)&a,(char *)&ip);
   return(a == 0);
 }
 
+
 /*******************************************************************
-sub strings with useful parameters
-********************************************************************/
-void standard_sub_basic(char *s)
+ matchname - determine if host name matches IP address 
+ ******************************************************************/
+static BOOL matchname(char *remotehost,struct in_addr  addr)
+{
+  struct hostent *hp;
+  int     i;
+  
+  if ((hp = Get_Hostbyname(remotehost)) == 0) {
+    DEBUG(0,("Get_Hostbyname(%s): lookup failure", remotehost));
+    return False;
+  } 
+
+  /*
+   * Make sure that gethostbyname() returns the "correct" host name.
+   * Unfortunately, gethostbyname("localhost") sometimes yields
+   * "localhost.domain". Since the latter host name comes from the
+   * local DNS, we just have to trust it (all bets are off if the local
+   * DNS is perverted). We always check the address list, though.
+   */
+  
+  if (strcasecmp(remotehost, hp->h_name)
+      && strcasecmp(remotehost, "localhost")) {
+    DEBUG(0,("host name/name mismatch: %s != %s",
+            remotehost, hp->h_name));
+    return False;
+  }
+       
+  /* Look up the host address in the address list we just got. */
+  for (i = 0; hp->h_addr_list[i]; i++) {
+    if (memcmp(hp->h_addr_list[i], (caddr_t) & addr, sizeof(addr)) == 0)
+      return True;
+  }
+
+  /*
+   * The host name does not map to the original host address. Perhaps
+   * someone has compromised a name server. More likely someone botched
+   * it, but that could be dangerous, too.
+   */
+  
+  DEBUG(0,("host name/address mismatch: %s != %s",
+          inet_ntoa(addr), hp->h_name));
+  return False;
+}
+
+/*******************************************************************
+ Reset the 'done' variables so after a client process is created
+ from a fork call these calls will be re-done. This should be
+ expanded if more variables need reseting.
+ ******************************************************************/
+
+static BOOL global_client_name_done = False;
+static BOOL global_client_addr_done = False;
+
+void reset_globals_after_fork()
 {
-  if (!strchr(s,'%')) return;
+  global_client_name_done = False;
+  global_client_addr_done = False;
+}
+/*******************************************************************
+ return the DNS name of the client 
+ ******************************************************************/
+char *client_name(void)
+{
+  extern int Client;
+  struct sockaddr sa;
+  struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+  int     length = sizeof(sa);
+  static pstring name_buf;
+  struct hostent *hp;
+
+  if (global_client_name_done) 
+    return name_buf;
+
+  strcpy(name_buf,"UNKNOWN");
+
+  if (getpeername(Client, &sa, &length) < 0) {
+    DEBUG(0,("getpeername failed\n"));
+    return name_buf;
+  }
+
+  /* Look up the remote host name. */
+  if ((hp = gethostbyaddr((char *) &sockin->sin_addr,
+                         sizeof(sockin->sin_addr),
+                         AF_INET)) == 0) {
+    DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr()));
+    StrnCpy(name_buf,client_addr(),sizeof(name_buf) - 1);
+  } else {
+    StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
+    if (!matchname(name_buf, sockin->sin_addr)) {
+      DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr()));
+      strcpy(name_buf,"UNKNOWN");
+    }
+  }
+  global_client_name_done = True;
+  return name_buf;
+}
 
-  string_sub(s,"%R",remote_proto);
-  string_sub(s,"%a",remote_arch);
-  string_sub(s,"%m",remote_machine);
-  string_sub(s,"%L",local_machine);
+/*******************************************************************
+ return the IP addr of the client as a string 
+ ******************************************************************/
+char *client_addr(void)
+{
+  extern int Client;
+  struct sockaddr sa;
+  struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
+  int     length = sizeof(sa);
+  static fstring addr_buf;
 
-  if (!strchr(s,'%')) return;
+  if (global_client_addr_done) 
+    return addr_buf;
 
-  string_sub(s,"%v",VERSION);
-  string_sub(s,"%h",myhostname);
-  string_sub(s,"%U",sesssetup_user);
+  strcpy(addr_buf,"0.0.0.0");
 
-  if (!strchr(s,'%')) return;
+  if (getpeername(Client, &sa, &length) < 0) {
+    DEBUG(0,("getpeername failed\n"));
+    return addr_buf;
+  }
 
-  string_sub(s,"%I",Client_info.addr);
-  string_sub(s,"%M",Client_info.name);
-  string_sub(s,"%T",timestring());
+  fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
 
-  if (!strchr(s,'%')) return;
+  global_client_addr_done = True;
+  return addr_buf;
+}
 
+/*******************************************************************
+sub strings with useful parameters
+Rewritten by Stefaan A Eeckels <Stefaan.Eeckels@ecc.lu> and
+Paul Rippin <pr3245@nopc.eurostat.cec.be>
+********************************************************************/
+void standard_sub_basic(char *str)
   {
+  char *s, *p;
     char pidstr[10];
-    sprintf(pidstr,"%d",(int)getpid());
-    string_sub(s,"%d",pidstr);
-  }
-
-  if (!strchr(s,'%')) return;
+  struct passwd *pass;
 
+  for (s = str ; (p = strchr(s,'%')) != NULL ; s = p )
+  {
+    switch (*(p+1))
   {
-    struct passwd *pass = Get_Pwnam(sesssetup_user,False);
-    if (pass) {
-      string_sub(s,"%G",gidtoname(pass->pw_gid));
+      case 'G' : if ((pass = Get_Pwnam(sesssetup_user,False))!=NULL)
+                   string_sub(p,"%G",gidtoname(pass->pw_gid));
+                 else
+                   p += 2;
+                 break;
+      case 'I' : string_sub(p,"%I",client_addr()); break;
+      case 'L' : string_sub(p,"%L",local_machine); break;
+      case 'M' : string_sub(p,"%M",client_name()); break;
+      case 'R' : string_sub(p,"%R",remote_proto); break;
+      case 'T' : string_sub(p,"%T",timestring()); break;
+      case 'U' : string_sub(p,"%U",sesssetup_user); break;
+      case 'a' : string_sub(p,"%a",remote_arch); break;
+      case 'd' : sprintf(pidstr,"%d",(int)getpid());
+                 string_sub(p,"%d",pidstr);
+                 break;
+      case 'h' : string_sub(p,"%h",myhostname); break;
+      case 'm' : string_sub(p,"%m",remote_machine); break;
+      case 'v' : string_sub(p,"%v",VERSION); break;
+      case '\0' : p++; break; /* don't run off end if last character is % */
+      default  : p+=2; break;
     }
   }
+  return;
 }
 
-
 /*******************************************************************
 are two IPs on the same subnet?
 ********************************************************************/
 BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask)
 {
-  unsigned long net1,net2,nmask;
+  uint32 net1,net2,nmask;
 
   nmask = ntohl(mask.s_addr);
   net1  = ntohl(ip1.s_addr);
@@ -3118,7 +3665,7 @@ struct hostent *Get_Hostbyname(char *name)
       return(NULL);
     }
 
-  ret = gethostbyname(name2);
+  ret = sys_gethostbyname(name2);
   if (ret != NULL)
     {
       free(name2);
@@ -3127,7 +3674,7 @@ struct hostent *Get_Hostbyname(char *name)
 
   /* try with all lowercase */
   strlower(name2);
-  ret = gethostbyname(name2);
+  ret = sys_gethostbyname(name2);
   if (ret != NULL)
     {
       free(name2);
@@ -3136,7 +3683,7 @@ struct hostent *Get_Hostbyname(char *name)
 
   /* try with all uppercase */
   strupper(name2);
-  ret = gethostbyname(name2);
+  ret = sys_gethostbyname(name2);
   if (ret != NULL)
     {
       free(name2);
@@ -3165,7 +3712,7 @@ BOOL process_exists(int pid)
     fstring s;
     if (!tested) {
       tested = True;
-      sprintf(s,"/proc/%05d",getpid());
+      sprintf(s,"/proc/%05d",(int)getpid());
       ok = file_exist(s,NULL);
     }
     if (ok) {
@@ -3174,11 +3721,8 @@ BOOL process_exists(int pid)
     }
   }
 
-  /* a best guess for non root access */
-  if (geteuid() != 0) return(True);
-
-  /* otherwise use kill */
-  return(pid == getpid() || kill(pid,0) == 0);
+  /* CGH 8/16/96 - added ESRCH test */
+  return(pid == getpid() || kill(pid,0) == 0 || errno != ESRCH);
 #endif
 }
 
@@ -3210,16 +3754,20 @@ char *gidtoname(int gid)
 /*******************************************************************
 block sigs
 ********************************************************************/
-void BlockSignals(BOOL block)
+void BlockSignals(BOOL block,int signum)
 {
 #ifdef USE_SIGBLOCK
-  int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV)
-                   |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)|
-                   sigmask(SIGINT));
+  int block_mask = sigmask(signum);
+  static int oldmask = 0;
   if (block) 
-    sigblock(block_mask);
+    oldmask = sigblock(block_mask);
   else
-    sigunblock(block_mask);
+    sigsetmask(oldmask);
+#elif defined(USE_SIGPROCMASK)
+  sigset_t set;
+  sigemptyset(&set);
+  sigaddset(&set,signum);
+  sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
 #endif
 }
 
@@ -3229,7 +3777,7 @@ my own panic function - not suitable for general use
 ********************************************************************/
 void ajt_panic(void)
 {
-  system("/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT");
+  system("/usr/bin/X11/xedit -display ljus:0 /tmp/ERROR_FAULT");
 }
 #endif
 
@@ -3255,15 +3803,6 @@ char *readdirname(void *p)
 
   dname = ptr->d_name;
 
-#ifdef KANJI
-  {
-    static pstring buf;
-    strcpy(buf, dname);
-    unix_to_dos(buf, True);
-    dname = buf;
-  }
-#endif
-
 #ifdef NEXT2
   if (telldir(p) < 0) return(NULL);
 #endif
@@ -3279,12 +3818,527 @@ char *readdirname(void *p)
        broken_readdir = True;
       }
     if (broken_readdir)
-      return(dname-2);
+      dname = dname - 2;
   }
 #endif
 
+  {
+    static pstring buf;
+    pstrcpy(buf, dname);
+    unix_to_dos(buf, True);
+    dname = buf;
+  }
+
   return(dname);
 }
 
+/*******************************************************************
+ Utility function used to decide if the last component 
+ of a path matches a (possibly wildcarded) entry in a namelist.
+********************************************************************/
+
+BOOL is_in_path(char *name, name_compare_entry *namelist)
+{
+  pstring last_component;
+  char *p;
+
+  DEBUG(8, ("is_in_path: %s\n", name));
+
+  /* if we have no list it's obviously not in the path */
+  if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) 
+  {
+    DEBUG(8,("is_in_path: no name list.\n"));
+    return False;
+  }
+
+  /* Get the last component of the unix name. */
+  p = strrchr(name, '/');
+  strncpy(last_component, p ? p : name, sizeof(last_component)-1);
+  last_component[sizeof(last_component)-1] = '\0'; 
+
+  for(; namelist->name != NULL; namelist++)
+  {
+    if(namelist->is_wild)
+    {
+      /* look for a wildcard match. */
+      if (mask_match(last_component, namelist->name, case_sensitive, False))
+      {
+         DEBUG(8,("is_in_path: mask match succeeded\n"));
+         return True;
+      }
+    }
+    else
+    {
+      if((case_sensitive && (strcmp(last_component, namelist->name) == 0))||
+       (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0)))
+        {
+         DEBUG(8,("is_in_path: match succeeded\n"));
+         return True;
+        }
+    }
+  }
+  DEBUG(8,("is_in_path: match not found\n"));
+  return False;
+}
+
+/*******************************************************************
+ Strip a '/' separated list into an array of 
+ name_compare_enties structures suitable for 
+ passing to is_in_path(). We do this for
+ speed so we can pre-parse all the names in the list 
+ and don't do it for each call to is_in_path().
+ namelist is modified here and is assumed to be 
+ a copy owned by the caller.
+ We also check if the entry contains a wildcard to
+ remove a potentially expensive call to mask_match
+ if possible.
+********************************************************************/
+void set_namearray(name_compare_entry **ppname_array, char *namelist)
+{
+  char *name_end;
+  char *nameptr = namelist;
+  int num_entries = 0;
+  int i;
+
+  (*ppname_array) = NULL;
+
+  if((nameptr == NULL ) || ((nameptr != NULL) && (*nameptr == '\0'))) 
+    return;
 
+  /* We need to make two passes over the string. The
+     first to count the number of elements, the second
+     to split it.
+   */
+  while(*nameptr) 
+    {
+      if ( *nameptr == '/' ) 
+        {
+          /* cope with multiple (useless) /s) */
+          nameptr++;
+          continue;
+        }
+      /* find the next / */
+      name_end = strchr(nameptr, '/');
+
+      /* oops - the last check for a / didn't find one. */
+      if (name_end == NULL)
+        break;
+
+      /* next segment please */
+      nameptr = name_end + 1;
+      num_entries++;
+    }
+
+  if(num_entries == 0)
+    return;
+
+  if(( (*ppname_array) = (name_compare_entry *)malloc( 
+           (num_entries + 1) * sizeof(name_compare_entry))) == NULL)
+        {
+    DEBUG(0,("set_namearray: malloc fail\n"));
+    return;
+        }
+
+  /* Now copy out the names */
+  nameptr = namelist;
+  i = 0;
+  while(*nameptr)
+             {
+      if ( *nameptr == '/' ) 
+      {
+          /* cope with multiple (useless) /s) */
+          nameptr++;
+          continue;
+      }
+      /* find the next / */
+      if ((name_end = strchr(nameptr, '/')) != NULL) 
+      {
+          *name_end = 0;
+         }
+
+      /* oops - the last check for a / didn't find one. */
+      if(name_end == NULL) 
+        break;
+
+      (*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) ||
+                                (strchr( nameptr, '*')!=NULL));
+      if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
+      {
+        DEBUG(0,("set_namearray: malloc fail (1)\n"));
+        return;
+      }
+
+      /* next segment please */
+      nameptr = name_end + 1;
+      i++;
+    }
+  
+  (*ppname_array)[i].name = NULL;
+
+  return;
+}
+
+/****************************************************************************
+routine to free a namearray.
+****************************************************************************/
+
+void free_namearray(name_compare_entry *name_array)
+{
+  if(name_array == 0)
+    return;
+
+  if(name_array->name != NULL)
+    free(name_array->name);
+
+  free((char *)name_array);
+}
+
+/****************************************************************************
+routine to do file locking
+****************************************************************************/
+BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
+{
+#if HAVE_FCNTL_LOCK
+  struct flock lock;
+  int ret;
+
+#if 1
+  uint32 mask = 0xC0000000;
+
+  /* make sure the count is reasonable, we might kill the lockd otherwise */
+  count &= ~mask;
+
+  /* the offset is often strange - remove 2 of its bits if either of
+     the top two bits are set. Shift the top ones by two bits. This
+     still allows OLE2 apps to operate, but should stop lockd from
+     dieing */
+  if ((offset & mask) != 0)
+    offset = (offset & ~mask) | ((offset & mask) >> 2);
+#else
+  uint32 mask = ((unsigned)1<<31);
+
+  /* interpret negative counts as large numbers */
+  if (count < 0)
+    count &= ~mask;
+
+  /* no negative offsets */
+  offset &= ~mask;
+
+  /* count + offset must be in range */
+  while ((offset < 0 || (offset + count < 0)) && mask)
+    {
+      offset &= ~mask;
+      mask = mask >> 1;
+    }
+#endif
+
+
+  DEBUG(8,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
+
+  lock.l_type = type;
+  lock.l_whence = SEEK_SET;
+  lock.l_start = (int)offset;
+  lock.l_len = (int)count;
+  lock.l_pid = 0;
+
+  errno = 0;
+
+  ret = fcntl(fd,op,&lock);
+
+  if (errno != 0)
+    DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
+
+  /* a lock query */
+  if (op == F_GETLK)
+    {
+      if ((ret != -1) &&
+         (lock.l_type != F_UNLCK) && 
+         (lock.l_pid != 0) && 
+         (lock.l_pid != getpid()))
+       {
+         DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
+         return(True);
+       }
+
+      /* it must be not locked or locked by me */
+      return(False);
+    }
+
+  /* a lock set or unset */
+  if (ret == -1)
+    {
+      DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
+              offset,count,op,type,strerror(errno)));
+
+      /* perhaps it doesn't support this sort of locking?? */
+      if (errno == EINVAL)
+       {
+         DEBUG(3,("locking not supported? returning True\n"));
+         return(True);
+       }
+
+      return(False);
+    }
+
+  /* everything went OK */
+  DEBUG(8,("Lock call successful\n"));
+
+  return(True);
+#else
+  return(False);
+#endif
+}
+
+/*******************************************************************
+lock a file - returning a open file descriptor or -1 on failure
+The timeout is in seconds. 0 means no timeout
+********************************************************************/
+int file_lock(char *name,int timeout)
+{  
+  int fd = open(name,O_RDWR|O_CREAT,0666);
+  time_t t=0;
+  if (fd < 0) return(-1);
+
+#if HAVE_FCNTL_LOCK
+  if (timeout) t = time(NULL);
+  while (!timeout || (time(NULL)-t < timeout)) {
+    if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);    
+    msleep(LOCK_RETRY_TIMEOUT);
+  }
+  return(-1);
+#else
+  return(fd);
+#endif
+}
+
+/*******************************************************************
+unlock a file locked by file_lock
+********************************************************************/
+void file_unlock(int fd)
+{
+  if (fd<0) return;
+#if HAVE_FCNTL_LOCK
+  fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
+#endif
+  close(fd);
+}
+
+/*******************************************************************
+is the name specified one of my netbios names
+returns true is it is equal, false otherwise
+********************************************************************/
+BOOL is_myname(char *s)
+{
+  int n;
+  BOOL ret = False;
+
+  for (n=0; my_netbios_names[n]; n++) {
+    if (strequal(my_netbios_names[n], s))
+      ret=True;
+  }
+  DEBUG(8, ("is_myname(\"%s\") returns %d\n", s, ret));
+  return(ret);
+}
+
+/*******************************************************************
+set the horrid remote_arch string based on an enum.
+********************************************************************/
+void set_remote_arch(enum remote_arch_types type)
+{
+  ra_type = type;
+  switch( type )
+  {
+  case RA_WFWG:
+    strcpy(remote_arch, "WfWg");
+    return;
+  case RA_OS2:
+    strcpy(remote_arch, "OS2");
+    return;
+  case RA_WIN95:
+    strcpy(remote_arch, "Win95");
+    return;
+  case RA_WINNT:
+    strcpy(remote_arch, "WinNT");
+    return;
+  case RA_SAMBA:
+    strcpy(remote_arch,"Samba");
+    return;
+  default:
+    ra_type = RA_UNKNOWN;
+    strcpy(remote_arch, "UNKNOWN");
+    break;
+  }
+}
+
+/*******************************************************************
+ Get the remote_arch type.
+********************************************************************/
+enum remote_arch_types get_remote_arch()
+{
+  return ra_type;
+}
+
+
+/*******************************************************************
+skip past some unicode strings in a buffer
+********************************************************************/
+char *skip_unicode_string(char *buf,int n)
+{
+  while (n--)
+  {
+    while (*buf)
+      buf += 2;
+    buf += 2;
+  }
+  return(buf);
+}
+
+/*******************************************************************
+Return a ascii version of a unicode string
+Hack alert: uses fixed buffer and only handles ascii strings
+********************************************************************/
+#define MAXUNI 1024
+char *unistr(char *buf)
+{
+       static char lbufs[8][MAXUNI];
+       static int nexti;
+       char *lbuf = lbufs[nexti];
+       char *p;
+       nexti = (nexti+1)%8;
+       for (p = lbuf; *buf && p -lbuf < MAXUNI-2; p++, buf += 2)
+               *p = *buf;
+       *p = 0;
+       return lbuf;
+}
+
+/*******************************************************************
+strncpy for unicode strings
+********************************************************************/
+int unistrncpy(char *dst, char *src, int len)
+{
+       int num_wchars = 0;
+
+       while (*src && len > 0)
+       {
+               *dst++ = *src++;
+               *dst++ = *src++;
+               len--;
+               num_wchars++;
+       }
+       *dst++ = 0;
+       *dst++ = 0;
+
+       return num_wchars;
+}
+
+
+/*******************************************************************
+strcpy for unicode strings.  returns length (in num of wide chars)
+********************************************************************/
+int unistrcpy(char *dst, char *src)
+{
+       int num_wchars = 0;
+
+       while (*src)
+       {
+               *dst++ = *src++;
+               *dst++ = *src++;
+               num_wchars++;
+       }
+       *dst++ = 0;
+       *dst++ = 0;
+
+       return num_wchars;
+}
+
+
+/*******************************************************************
+safe string copy into a fstring
+********************************************************************/
+void fstrcpy(char *dest, char *src)
+{
+    int maxlength = sizeof(fstring) - 1;
+    if (!dest) {
+        DEBUG(0,("ERROR: NULL dest in fstrcpy\n"));
+        return;
+    }
+
+    if (!src) {
+        *dest = 0;
+        return;
+    }  
+      
+    while (maxlength-- && *src)
+        *dest++ = *src++;
+    *dest = 0;
+    if (*src) {
+        DEBUG(0,("ERROR: string overflow by %d in fstrcpy\n",
+             strlen(src)));
+    }    
+}   
+
+/*******************************************************************
+safe string copy into a pstring
+********************************************************************/
+void pstrcpy(char *dest, char *src)
+{
+    int maxlength = sizeof(pstring) - 1;
+    if (!dest) {
+        DEBUG(0,("ERROR: NULL dest in pstrcpy\n"));
+        return;
+    }
+   
+    if (!src) {
+        *dest = 0;
+        return;
+    }
+   
+    while (maxlength-- && *src)
+        *dest++ = *src++;
+    *dest = 0;
+    if (*src) {
+        DEBUG(0,("ERROR: string overflow by %d in pstrcpy\n",
+             strlen(src)));
+    }
+}  
+
+
+/*******************************************************************
+align a pointer to a multiple of 4 bytes
+********************************************************************/
+char *align4(char *q, char *base)
+{
+       if ((q - base) & 3)
+       {
+               q += 4 - ((q - base) & 3);
+       }
+       return q;
+}
+
+/*******************************************************************
+align a pointer to a multiple of 2 bytes
+********************************************************************/
+char *align2(char *q, char *base)
+{
+       if ((q - base) & 1)
+       {
+               q++;
+       }
+       return q;
+}
+
+/*******************************************************************
+align a pointer to a multiple of align_offset bytes.  looks like it
+will work for offsets of 0, 2 and 4...
+********************************************************************/
+char *align_offset(char *q, char *base, int align_offset_len)
+{
+       if (align_offset_len != 0 && ((q - base) & (align_offset_len-1)))
+       {
+               q += align_offset_len - ((q - base) & (align_offset_len));
+       }
+       return q;
+}