summaryrefslogtreecommitdiff
path: root/source3/lib/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib/util.c')
-rw-r--r--source3/lib/util.c4510
1 files changed, 4510 insertions, 0 deletions
diff --git a/source3/lib/util.c b/source3/lib/util.c
new file mode 100644
index 0000000000..7bd6298c4c
--- /dev/null
+++ b/source3/lib/util.c
@@ -0,0 +1,4510 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1995
+
+ 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "loadparm.h"
+
+pstring scope = "";
+
+int DEBUGLEVEL = 1;
+
+BOOL passive = False;
+
+int Protocol = PROTOCOL_COREPLUS;
+
+int serverzone=0;
+
+/* a default finfo structure to ensure all fields are sensible */
+file_info def_finfo = {-1,0,0,0,0,0,0,""};
+
+/* these are some file handles where debug info will be stored */
+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;
+
+/* my IP, the broadcast IP and the Netmask */
+struct in_addr myip;
+struct in_addr bcast_ip;
+struct in_addr Netmask;
+
+int trans_num = 0;
+
+/*
+ case handling on filenames
+*/
+int case_default = CASE_LOWER;
+
+
+/* size of reads during a direct file to file transfer */
+int ReadSize = 16*1024;
+
+pstring debugf = "/tmp/log.samba";
+int syslog_level;
+
+/* the following control case operations - they are put here so the
+ client can link easily */
+BOOL case_sensitive;
+BOOL case_preserve;
+BOOL use_mangled_map = False;
+BOOL short_case_preserve;
+BOOL case_mangle;
+
+fstring remote_machine="";
+fstring local_machine="";
+fstring remote_arch="UNKNOWN";
+fstring remote_proto="UNKNOWN";
+pstring myhostname="";
+pstring user_socket_options="";
+pstring sesssetup_user="";
+
+
+static char *filename_dos(char *path,char *buf);
+
+static BOOL stdout_logging = False;
+
+
+/*******************************************************************
+ get ready for syslog stuff
+ ******************************************************************/
+void setup_logging(char *pname,BOOL interactive)
+{
+#ifdef SYSLOG
+ if (!interactive) {
+ char *p = strrchr(pname,'/');
+ if (p) pname = p+1;
+ openlog(pname, LOG_PID, LOG_DAEMON);
+ }
+#endif
+ if (interactive) {
+ stdout_logging = True;
+ dbf = stdout;
+ }
+}
+
+
+BOOL append_log=False;
+
+
+/****************************************************************************
+reopen the log files
+****************************************************************************/
+void reopen_logs(void)
+{
+ extern FILE *dbf;
+ pstring fname;
+
+ if (DEBUGLEVEL > 0)
+ {
+ strcpy(fname,debugf);
+ if (lp_loaded() && (*lp_logfile()))
+ strcpy(fname,lp_logfile());
+
+ if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL))
+ {
+ strcpy(debugf,fname);
+ if (dbf) fclose(dbf);
+ if (append_log)
+ dbf = fopen(debugf,"a");
+ else
+ dbf = fopen(debugf,"w");
+ if (dbf) setbuf(dbf,NULL);
+ }
+ }
+ else
+ {
+ if (dbf)
+ {
+ fclose(dbf);
+ dbf = NULL;
+ }
+ }
+}
+
+
+/*******************************************************************
+write an debug message on the debugfile. This is called by the DEBUG
+macro
+********************************************************************/
+#ifdef __STDC__
+int Debug1(char *format_str, ...)
+{
+#else
+int Debug1(va_alist)
+va_dcl
+{
+ char *format_str;
+#endif
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, format_str);
+#else
+ va_start(ap);
+ format_str = va_arg(ap,char *);
+#endif
+
+ if (stdout_logging) {
+ vfprintf(dbf,format_str,ap);
+ va_end(ap);
+ return(0);
+ }
+
+ {
+ static int debug_count=0;
+
+ debug_count++;
+ if (debug_count == 100) {
+ int maxlog = lp_max_log_size() * 1024;
+ if (dbf && maxlog > 0)
+ {
+ struct stat st;
+
+ if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) {
+ fclose(dbf); dbf = NULL;
+ reopen_logs();
+ if (dbf && file_size(debugf) > maxlog) {
+ pstring name;
+ fclose(dbf); dbf = NULL;
+ sprintf(name,"%s.old",debugf);
+ sys_rename(debugf,name);
+ reopen_logs();
+ }
+ }
+ }
+ debug_count=0;
+ }
+ }
+
+#ifdef SYSLOG
+ if (!lp_syslog_only())
+#endif
+ {
+ if (!dbf)
+ {
+ dbf = fopen(debugf,"w");
+ if (dbf)
+ setbuf(dbf,NULL);
+ else
+ return(0);
+ }
+ }
+
+#ifdef SYSLOG
+ if (syslog_level < lp_syslog())
+ {
+ /*
+ * map debug levels to syslog() priorities
+ * note that not all DEBUG(0, ...) calls are
+ * necessarily errors
+ */
+ static int priority_map[] = {
+ LOG_ERR, /* 0 */
+ LOG_WARNING, /* 1 */
+ LOG_NOTICE, /* 2 */
+ LOG_INFO, /* 3 */
+ };
+ int priority;
+ pstring msgbuf;
+
+ if (syslog_level >= sizeof(priority_map) / sizeof(priority_map[0]) ||
+ syslog_level < 0)
+ priority = LOG_DEBUG;
+ else
+ priority = priority_map[syslog_level];
+
+ vsprintf(msgbuf, format_str, ap);
+
+ msgbuf[255] = '\0';
+ syslog(priority, "%s", msgbuf);
+ }
+#endif
+
+#ifdef SYSLOG
+ if (!lp_syslog_only())
+#endif
+ {
+ vfprintf(dbf,format_str,ap);
+ fflush(dbf);
+ }
+
+ va_end(ap);
+ return(0);
+}
+
+/****************************************************************************
+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
+ unsigned long 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(5,("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(5,("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);
+}
+
+/*******************************************************************
+a gettimeofday wrapper
+********************************************************************/
+void GetTimeOfDay(struct timeval *tval)
+{
+#ifdef GETTIMEOFDAY1
+ gettimeofday(tval);
+#else
+ gettimeofday(tval,NULL);
+#endif
+}
+
+int extra_time_offset = 0;
+
+static int timediff = 0;
+
+/*******************************************************************
+init the time differences
+********************************************************************/
+void TimeInit(void)
+{
+ struct tm tm_utc,tm_local;
+ time_t t;
+
+ t = time(NULL);
+
+ tm_utc = *(gmtime(&t));
+ tm_local = *(localtime(&t));
+
+#ifdef HAVE_GMTOFF
+ timediff = -tm_local.tm_gmtoff;
+#else
+ timediff = mktime(&tm_utc) - mktime(&tm_local);
+#endif
+
+ if (serverzone == 0) {
+ serverzone = timediff - DSTDiff(t);
+ DEBUG(4,("Serverzone is %d\n",serverzone));
+ }
+}
+
+
+/*******************************************************************
+return the DST offset for a particular time
+We keep a table of DST offsets to prevent calling localtime() on each
+call of this function. This saves a LOT of time on many unixes.
+********************************************************************/
+int DSTDiff(time_t t)
+{
+ static struct dst_table {time_t start,end; BOOL is_dst;} *dst_table = NULL;
+ static int table_size = 0;
+ int i;
+ BOOL is_dst = False;
+
+ if (t == 0) t = time(NULL);
+
+#ifndef NO_ISDST
+ for (i=0;i<table_size;i++)
+ if (t >= dst_table[i].start && t <= dst_table[i].end) break;
+
+ if (i<table_size) {
+ is_dst = dst_table[i].is_dst;
+ } else {
+ time_t low,high;
+
+ dst_table = (struct dst_table *)Realloc(dst_table,
+ sizeof(dst_table[0])*(i+1));
+ if (!dst_table) {
+ table_size = 0;
+ return(0);
+ }
+
+ table_size++;
+
+ dst_table[i].is_dst = is_dst = (localtime(&t)->tm_isdst?True:False);;
+ dst_table[i].start = dst_table[i].end = t;
+
+ /* no entry will cover more than 6 months */
+ low = t - 3*30*24*60*60;
+ high = t + 3*30*24*60*60;
+
+ /* widen the new entry using two bisection searches */
+ while (low+60*60 < dst_table[i].start) {
+ t = low + (dst_table[i].start-low)/2;
+ if ((localtime(&t)->tm_isdst?True:False) == is_dst)
+ dst_table[i].start = t;
+ else
+ low = t;
+ }
+
+ while (high-60*60 > dst_table[i].end) {
+ t = high + (high-dst_table[i].end)/2;
+ if ((localtime(&t)->tm_isdst?True:False) == is_dst)
+ dst_table[i].end = t;
+ else
+ high = t;
+ }
+
+/*
+ DEBUG(1,("Added DST entry from %s ",
+ asctime(localtime(&dst_table[i].start))));
+ DEBUG(1,("to %s (%d)\n",asctime(localtime(&dst_table[i].end)),
+ dst_table[i].is_dst));
+*/
+ }
+#endif
+
+ return((is_dst?60*60:0) - (extra_time_offset*60));
+}
+
+/****************************************************************************
+return the difference between local and GMT time
+****************************************************************************/
+int TimeDiff(time_t t)
+{
+ static BOOL initialised = False;
+ if (!initialised) {initialised=True; TimeInit();}
+ return(timediff - DSTDiff(t));
+}
+
+/****************************************************************************
+try to optimise the localtime call, it can be quite expenive on some machines
+timemul is normally LOCAL_TO_GMT, GMT_TO_LOCAL or 0
+****************************************************************************/
+struct tm *LocalTime(time_t *t,int timemul)
+{
+ time_t t2 = *t;
+
+ if (timemul)
+ t2 += timemul * TimeDiff(t2);
+
+ return(gmtime(&t2));
+}
+
+
+/****************************************************************************
+determine if a file descriptor is in fact a socket
+****************************************************************************/
+BOOL is_a_socket(int fd)
+{
+ int v,l;
+ l = sizeof(int);
+ return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
+}
+
+
+static char *last_ptr=NULL;
+
+/****************************************************************************
+ Get the next token from a string, return False if none found
+ handles double-quotes.
+Based on a routine by GJC@VILLAGE.COM.
+Extensively modified by Andrew.Tridgell@anu.edu.au
+****************************************************************************/
+BOOL next_token(char **ptr,char *buff,char *sep)
+{
+ char *s;
+ BOOL quoted;
+
+ if (!ptr) ptr = &last_ptr;
+ if (!ptr) return(False);
+
+ s = *ptr;
+
+ /* default to simple separators */
+ if (!sep) sep = " \t\n\r";
+
+ /* find the first non sep char */
+ while(*s && strchr(sep,*s)) s++;
+
+ /* nothing left? */
+ if (! *s) return(False);
+
+ /* copy over the token */
+ for (quoted = False; *s && (quoted || !strchr(sep,*s)); s++)
+ {
+ if (*s == '\"')
+ quoted = !quoted;
+ else
+ *buff++ = *s;
+ }
+
+ *ptr = (*s) ? s+1 : s;
+ *buff = 0;
+ last_ptr = *ptr;
+
+ return(True);
+}
+
+/****************************************************************************
+Convert list of tokens to array; dependent on above routine.
+Uses last_ptr from above - bit of a hack.
+****************************************************************************/
+char **toktocliplist(int *ctok, char *sep)
+{
+ char *s=last_ptr;
+ int ictok=0;
+ char **ret, **iret;
+
+ if (!sep) sep = " \t\n\r";
+
+ while(*s && strchr(sep,*s)) s++;
+
+ /* nothing left? */
+ if (!*s) return(NULL);
+
+ do {
+ ictok++;
+ while(*s && (!strchr(sep,*s))) s++;
+ while(*s && strchr(sep,*s)) *s++=0;
+ } while(*s);
+
+ *ctok=ictok;
+ s=last_ptr;
+
+ if (!(ret=iret=malloc(ictok*sizeof(char *)))) return NULL;
+
+ while(ictok--) {
+ *iret++=s;
+ while(*s++);
+ while(!*s) s++;
+ }
+
+ return ret;
+}
+
+#ifndef HAVE_MEMMOVE
+/*******************************************************************
+safely copies memory, ensuring no overlap problems.
+this is only used if the machine does not have it's own memmove().
+this is not the fastest algorithm in town, but it will do for our
+needs.
+********************************************************************/
+void *MemMove(void *dest,void *src,int size)
+{
+ unsigned long d,s;
+ int i;
+ if (dest==src || !size) return(dest);
+
+ d = (unsigned long)dest;
+ s = (unsigned long)src;
+
+ if ((d >= (s+size)) || (s >= (d+size))) {
+ /* no overlap */
+ memcpy(dest,src,size);
+ return(dest);
+ }
+
+ if (d < s)
+ {
+ /* we can forward copy */
+ if (s-d >= sizeof(int) &&
+ !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=0;i<size;i++) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=0;i<size;i++) cdest[i] = csrc[i];
+ }
+ }
+ else
+ {
+ /* must backward copy */
+ if (d-s >= sizeof(int) &&
+ !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) {
+ /* do it all as words */
+ int *idest = (int *)dest;
+ int *isrc = (int *)src;
+ size /= sizeof(int);
+ for (i=size-1;i>=0;i--) idest[i] = isrc[i];
+ } else {
+ /* simplest */
+ char *cdest = (char *)dest;
+ char *csrc = (char *)src;
+ for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
+ }
+ }
+ return(dest);
+}
+#endif
+
+
+/****************************************************************************
+prompte a dptr (to make it recently used)
+****************************************************************************/
+void array_promote(char *array,int elsize,int element)
+{
+ char *p;
+ if (element == 0)
+ return;
+
+ p = (char *)malloc(elsize);
+
+ if (!p)
+ {
+ DEBUG(5,("Ahh! Can't malloc\n"));
+ return;
+ }
+ memcpy(p,array + element * elsize, elsize);
+ memmove(array + elsize,array,elsize*element);
+ memcpy(array,p,elsize);
+ free(p);
+}
+
+enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
+
+struct
+{
+ char *name;
+ int level;
+ int option;
+ int value;
+ int opttype;
+} socket_options[] = {
+ {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
+ {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
+ {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
+#ifdef TCP_NODELAY
+ {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
+#endif
+#ifdef IPTOS_LOWDELAY
+ {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
+#endif
+#ifdef IPTOS_THROUGHPUT
+ {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
+#endif
+#ifdef SO_SNDBUF
+ {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
+#endif
+#ifdef SO_RCVBUF
+ {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
+#endif
+#ifdef SO_SNDLOWAT
+ {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
+#endif
+#ifdef SO_RCVLOWAT
+ {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
+#endif
+ {NULL,0,0,0,0}};
+
+
+
+/****************************************************************************
+set user socket options
+****************************************************************************/
+void set_socket_options(int fd, char *options)
+{
+ string tok;
+
+ while (next_token(&options,tok," \t,"))
+ {
+ int ret=0,i;
+ int value = 1;
+ char *p;
+ BOOL got_value = False;
+
+ if ((p = strchr(tok,'=')))
+ {
+ *p = 0;
+ value = atoi(p+1);
+ got_value = True;
+ }
+
+ for (i=0;socket_options[i].name;i++)
+ if (strequal(socket_options[i].name,tok))
+ break;
+
+ if (!socket_options[i].name)
+ {
+ DEBUG(0,("Unknown socket option %s\n",tok));
+ continue;
+ }
+
+ switch (socket_options[i].opttype)
+ {
+ case OPT_BOOL:
+ case OPT_INT:
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,(char *)&value,sizeof(int));
+ break;
+
+ case OPT_ON:
+ if (got_value)
+ DEBUG(0,("syntax error - %s does not take a value\n",tok));
+
+ {
+ int on = socket_options[i].value;
+ ret = setsockopt(fd,socket_options[i].level,
+ socket_options[i].option,(char *)&on,sizeof(int));
+ }
+ break;
+ }
+
+ if (ret != 0)
+ DEBUG(0,("Failed to set socket option %s\n",tok));
+ }
+}
+
+
+
+/****************************************************************************
+ close the socket communication
+****************************************************************************/
+void close_sockets(void )
+{
+ close(Client);
+ Client = 0;
+}
+
+/****************************************************************************
+ return the date and time as a string
+****************************************************************************/
+char *timestring(void )
+{
+ static char TimeBuf[100];
+ time_t t;
+ t = time(NULL);
+#ifdef NO_STRFTIME
+ strcpy(TimeBuf, asctime(LocalTime(&t,GMT_TO_LOCAL)));
+#elif defined(CLIX) || defined(CONVEX)
+ strftime(TimeBuf,100,"%m/%d/%y %I:%M:%S %p",LocalTime(&t,GMT_TO_LOCAL));
+#elif defined(AMPM)
+ strftime(TimeBuf,100,"%D %r",LocalTime(&t,GMT_TO_LOCAL));
+#elif defined(TZ_TIME)
+ {
+ strftime(TimeBuf,100,"%D:%T",LocalTime(&t,0));
+ sprintf(TimeBuf+strlen(TimeBuf)," %+03d%02d",
+ -TimeDiff(t)/(60*60),-(TimeDiff(t)/60)%60);
+ }
+#else
+ strftime(TimeBuf,100,"%D %T",LocalTime(&t,GMT_TO_LOCAL));
+#endif
+ return(TimeBuf);
+}
+
+/****************************************************************************
+determine whether we are in the specified group
+****************************************************************************/
+BOOL in_group(gid_t group, int current_gid, int ngroups, int *groups)
+{
+ int i;
+
+ if (group == current_gid) return(True);
+
+ for (i=0;i<ngroups;i++)
+ if (group == groups[i])
+ return(True);
+
+ return(False);
+}
+
+/****************************************************************************
+this is a safer strcpy(), meant to prevent core dumps when nasty things happen
+****************************************************************************/
+char *StrCpy(char *dest,char *src)
+{
+ char *d = dest;
+
+#if AJT
+ /* I don't want to get lazy with these ... */
+ if (!dest || !src) {
+ DEBUG(0,("ERROR: NULL StrCpy() called!\n"));
+ ajt_panic();
+ }
+#endif
+
+ if (!dest) return(NULL);
+ if (!src) {
+ *dest = 0;
+ return(dest);
+ }
+ while ((*d++ = *src++)) ;
+ return(dest);
+}
+
+/****************************************************************************
+line strncpy but always null terminates. Make sure there is room!
+****************************************************************************/
+char *StrnCpy(char *dest,const char *src,int n)
+{
+ char *d = dest;
+ if (!dest) return(NULL);
+ if (!src) {
+ *dest = 0;
+ return(dest);
+ }
+ while (n-- && (*d++ = *src++)) ;
+ *d = 0;
+ return(dest);
+}
+
+
+/*******************************************************************
+copy an IP address from one buffer to another
+********************************************************************/
+void putip(void *dest,void *src)
+{
+ memcpy(dest,src,4);
+}
+
+
+/****************************************************************************
+interpret the weird netbios "name". Return the name type
+****************************************************************************/
+static int name_interpret(char *in,char *out)
+{
+ int ret;
+ int len = (*in++) / 2;
+
+ *out=0;
+
+ if (len > 30 || len<1) return(0);
+
+ while (len--)
+ {
+ if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
+ *out = 0;
+ return(0);
+ }
+ *out = ((in[0]-'A')<<4) + (in[1]-'A');
+ in += 2;
+ out++;
+ }
+ *out = 0;
+ ret = out[-1];
+
+#ifdef NETBIOS_SCOPE
+ /* Handle any scope names */
+ while(*in)
+ {
+ *out++ = '.'; /* Scope names are separated by periods */
+ len = *(unsigned char *)in++;
+ StrnCpy(out, in, len);
+ out += len;
+ *out=0;
+ in += len;
+ }
+#endif
+ return(ret);
+}
+
+/****************************************************************************
+mangle a name into netbios format
+****************************************************************************/
+int name_mangle(char *In,char *Out,char name_type)
+{
+ fstring name;
+ char buf[20];
+ char *in = (char *)&buf[0];
+ char *out = (char *)Out;
+ char *p, *label;
+ int i;
+
+ if (In[0] != '*') {
+ StrnCpy(name,In,sizeof(name)-1);
+ sprintf(buf,"%-15.15s%c",name,name_type);
+ } else {
+ buf[0]='*';
+ memset(&buf[1],0,16);
+ }
+
+ *out++ = 32;
+ for (i=0;i<16;i++) {
+ char c = toupper(in[i]);
+ out[i*2] = (c>>4) + 'A';
+ out[i*2+1] = (c & 0xF) + 'A';
+ }
+ out[32]=0;
+ out += 32;
+
+ label = scope;
+ while (*label)
+ {
+ p = strchr(label, '.');
+ if (p == 0)
+ p = label + strlen(label);
+ *out++ = p - label;
+ memcpy(out, label, p - label);
+ out += p - label;
+ label += p - label + (*p == '.');
+ }
+ *out = 0;
+ return(name_len(Out));
+}
+
+
+/*******************************************************************
+ check if a file exists
+********************************************************************/
+BOOL file_exist(char *fname,struct stat *sbuf)
+{
+ struct stat st;
+ if (!sbuf) sbuf = &st;
+
+ if (sys_stat(fname,sbuf) != 0)
+ return(False);
+
+ return(S_ISREG(sbuf->st_mode));
+}
+
+/*******************************************************************
+check a files mod time
+********************************************************************/
+time_t file_modtime(char *fname)
+{
+ struct stat st;
+
+ if (sys_stat(fname,&st) != 0)
+ return(0);
+
+ return(st.st_mtime);
+}
+
+/*******************************************************************
+ check if a directory exists
+********************************************************************/
+BOOL directory_exist(char *dname,struct stat *st)
+{
+ struct stat st2;
+ if (!st) st = &st2;
+
+ if (sys_stat(dname,st) != 0)
+ return(False);
+
+ return(S_ISDIR(st->st_mode));
+}
+
+/*******************************************************************
+returns the size in bytes of the named file
+********************************************************************/
+uint32 file_size(char *file_name)
+{
+ struct stat buf;
+ buf.st_size = 0;
+ sys_stat(file_name,&buf);
+ return(buf.st_size);
+}
+
+/****************************************************************************
+check if it's a null mtime
+****************************************************************************/
+static BOOL null_mtime(time_t mtime)
+{
+ if (mtime == 0 || mtime == 0xFFFFFFFF)
+ return(True);
+ return(False);
+}
+
+/*******************************************************************
+ create a 16 bit dos packed date
+********************************************************************/
+static uint16 make_dos_date1(time_t unixdate,struct tm *t)
+{
+ uint16 ret=0;
+ ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
+ ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
+ return(ret);
+}
+
+/*******************************************************************
+ create a 16 bit dos packed time
+********************************************************************/
+static uint16 make_dos_time1(time_t unixdate,struct tm *t)
+{
+ uint16 ret=0;
+ ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
+ ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
+ return(ret);
+}
+
+/*******************************************************************
+ create a 32 bit dos packed date/time from some parameters
+ This takes a GMT time and returns a packed localtime structure
+********************************************************************/
+static uint32 make_dos_date(time_t unixdate)
+{
+ struct tm *t;
+ uint32 ret=0;
+
+ t = LocalTime(&unixdate,GMT_TO_LOCAL);
+
+ ret = make_dos_date1(unixdate,t);
+ ret = ((ret&0xFFFF)<<16) | make_dos_time1(unixdate,t);
+
+ return(ret);
+}
+
+/*******************************************************************
+put a dos date into a buffer (time/date format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void put_dos_date(char *buf,int offset,time_t unixdate)
+{
+ uint32 x = make_dos_date(unixdate);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos date into a buffer (date/time format)
+This takes GMT time and puts local time in the buffer
+********************************************************************/
+void put_dos_date2(char *buf,int offset,time_t unixdate)
+{
+ uint32 x = make_dos_date(unixdate);
+ x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(buf,offset,x);
+}
+
+/*******************************************************************
+put a dos 32 bit "unix like" date into a buffer. This routine takes
+GMT and converts it to LOCAL time before putting it (most SMBs assume
+localtime for this sort of date)
+********************************************************************/
+void put_dos_date3(char *buf,int offset,time_t unixdate)
+{
+ if (!null_mtime(unixdate))
+ unixdate += GMT_TO_LOCAL*TimeDiff(unixdate);
+ SIVAL(buf,offset,unixdate);
+}
+
+/*******************************************************************
+ interpret a 32 bit dos packed date/time to some parameters
+********************************************************************/
+static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+{
+ uint32 p0,p1,p2,p3;
+
+ p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
+ p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
+
+ *second = 2*(p0 & 0x1F);
+ *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
+ *hour = (p1>>3)&0xFF;
+ *day = (p2&0x1F);
+ *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
+ *year = ((p3>>1)&0xFF) + 80;
+}
+
+/*******************************************************************
+ create a unix date (int GMT) from a dos date (which is actually in
+ localtime)
+********************************************************************/
+time_t make_unix_date(void *date_ptr)
+{
+ uint32 dos_date=0;
+ struct tm t;
+ time_t ret;
+
+ dos_date = IVAL(date_ptr,0);
+
+ if (dos_date == 0) return(0);
+
+ interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
+ &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
+ t.tm_wday = 1;
+ t.tm_yday = 1;
+ t.tm_isdst = -1;
+
+ /* mktime() also does the local to GMT time conversion for us. XXXXX
+ Do all unixes do this the same?? */
+ ret = mktime(&t);
+
+ return(ret);
+}
+
+/*******************************************************************
+like make_unix_date() but the words are reversed
+********************************************************************/
+time_t make_unix_date2(void *date_ptr)
+{
+ uint32 x,x2;
+
+ x = IVAL(date_ptr,0);
+ x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+ SIVAL(&x,0,x2);
+
+ return(make_unix_date((void *)&x));
+}
+
+/*******************************************************************
+ create a unix GMT date from a dos date in 32 bit "unix like" format
+these generally arrive as localtimes, with corresponding DST
+********************************************************************/
+time_t make_unix_date3(void *date_ptr)
+{
+ time_t t = IVAL(date_ptr,0);
+ if (!null_mtime(t))
+ t += LOCAL_TO_GMT*TimeDiff(t);
+ return(t);
+}
+
+/*******************************************************************
+return a string representing an attribute for a file
+********************************************************************/
+char *attrib_string(int mode)
+{
+ static char attrstr[10];
+
+ attrstr[0] = 0;
+
+ if (mode & aVOLID) strcat(attrstr,"V");
+ if (mode & aDIR) strcat(attrstr,"D");
+ if (mode & aARCH) strcat(attrstr,"A");
+ if (mode & aHIDDEN) strcat(attrstr,"H");
+ if (mode & aSYSTEM) strcat(attrstr,"S");
+ if (mode & aRONLY) strcat(attrstr,"R");
+
+ return(attrstr);
+}
+
+
+/*******************************************************************
+ case insensitive string compararison
+********************************************************************/
+int StrCaseCmp(char *s, char *t)
+{
+ for (; tolower(*s) == tolower(*t); ++s, ++t)
+ if (!*s) return 0;
+
+ return tolower(*s) - tolower(*t);
+}
+
+/*******************************************************************
+ case insensitive string compararison, length limited
+********************************************************************/
+int StrnCaseCmp(char *s, char *t, int n)
+{
+ while (n-- && *s && *t) {
+ if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t));
+ s++; t++;
+ }
+ if (n) return(tolower(*s) - tolower(*t));
+
+ return(0);
+}
+
+/*******************************************************************
+ compare 2 strings
+********************************************************************/
+BOOL strequal(char *s1,char *s2)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2) return(False);
+
+ return(StrCaseCmp(s1,s2)==0);
+}
+
+/*******************************************************************
+ compare 2 strings up to and including the nth char.
+ ******************************************************************/
+BOOL strnequal(char *s1,char *s2,int n)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2 || !n) return(False);
+
+ return(StrnCaseCmp(s1,s2,n)==0);
+}
+
+/*******************************************************************
+ compare 2 strings (case sensitive)
+********************************************************************/
+BOOL strcsequal(char *s1,char *s2)
+{
+ if (s1 == s2) return(True);
+ if (!s1 || !s2) return(False);
+
+ return(strcmp(s1,s2)==0);
+}
+
+
+/*******************************************************************
+ convert a string to lower case
+********************************************************************/
+void strlower(char *s)
+{
+ while (*s)
+ {
+#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++;
+#endif /* KANJI */
+ }
+}
+
+/*******************************************************************
+ convert a string to upper case
+********************************************************************/
+void strupper(char *s)
+{
+ while (*s)
+ {
+#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++;
+#endif
+ }
+}
+
+/*******************************************************************
+ convert a string to "normal" form
+********************************************************************/
+void strnorm(char *s)
+{
+ if (case_default == CASE_UPPER)
+ strupper(s);
+ else
+ strlower(s);
+}
+
+/*******************************************************************
+check if a string is in "normal" case
+********************************************************************/
+BOOL strisnormal(char *s)
+{
+ if (case_default == CASE_UPPER)
+ return(!strhaslower(s));
+
+ return(!strhasupper(s));
+}
+
+
+/****************************************************************************
+ string replace
+****************************************************************************/
+void string_replace(char *s,char oldc,char newc)
+{
+ while (*s)
+ {
+#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++;
+#endif /* KANJI */
+ }
+}
+
+/****************************************************************************
+ make a file into unix format
+****************************************************************************/
+void unix_format(char *fname)
+{
+ pstring namecopy;
+ string_replace(fname,'\\','/');
+#ifndef KANJI
+ dos2unix_format(fname, True);
+#endif /* KANJI */
+
+ if (*fname == '/')
+ {
+ strcpy(namecopy,fname);
+ strcpy(fname,".");
+ strcat(fname,namecopy);
+ }
+}
+
+/****************************************************************************
+ make a file into dos format
+****************************************************************************/
+void dos_format(char *fname)
+{
+#ifndef KANJI
+ unix2dos_format(fname, True);
+#endif /* KANJI */
+ string_replace(fname,'/','\\');
+}
+
+
+/*******************************************************************
+ show a smb message structure
+********************************************************************/
+void show_msg(char *buf)
+{
+ int i;
+ int bcc=0;
+ if (DEBUGLEVEL < 5)
+ return;
+
+ DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n",
+ smb_len(buf),
+ (int)CVAL(buf,smb_com),
+ (int)CVAL(buf,smb_rcls),
+ (int)CVAL(buf,smb_reh),
+ (int)SVAL(buf,smb_err),
+ (int)CVAL(buf,smb_flg),
+ (int)SVAL(buf,smb_flg2)));
+ DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n",
+ (int)SVAL(buf,smb_tid),
+ (int)SVAL(buf,smb_pid),
+ (int)SVAL(buf,smb_uid),
+ (int)SVAL(buf,smb_mid),
+ (int)CVAL(buf,smb_wct)));
+ for (i=0;i<(int)CVAL(buf,smb_wct);i++)
+ DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i,
+ SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i)));
+ bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct)));
+ 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)));
+ DEBUG(10,("\n"));
+}
+
+/*******************************************************************
+ return the length of an smb packet
+********************************************************************/
+int smb_len(char *buf)
+{
+ return( PVAL(buf,3) | (PVAL(buf,2)<<8) | ((PVAL(buf,1)&1)<<16) );
+}
+
+/*******************************************************************
+ set the length of an smb packet
+********************************************************************/
+void _smb_setlen(char *buf,int len)
+{
+ buf[0] = 0;
+ buf[1] = (len&0x10000)>>16;
+ buf[2] = (len&0xFF00)>>8;
+ buf[3] = len&0xFF;
+}
+
+/*******************************************************************
+ set the length and marker of an smb packet
+********************************************************************/
+void smb_setlen(char *buf,int len)
+{
+ _smb_setlen(buf,len);
+
+ CVAL(buf,4) = 0xFF;
+ CVAL(buf,5) = 'S';
+ CVAL(buf,6) = 'M';
+ CVAL(buf,7) = 'B';
+}
+
+/*******************************************************************
+ setup the word count and byte count for a smb message
+********************************************************************/
+int set_message(char *buf,int num_words,int num_bytes,BOOL zero)
+{
+ if (zero)
+ bzero(buf + smb_size,num_words*2 + num_bytes);
+ CVAL(buf,smb_wct) = num_words;
+ SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+ smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
+ return (smb_size + num_words*2 + num_bytes);
+}
+
+/*******************************************************************
+return the number of smb words
+********************************************************************/
+int smb_numwords(char *buf)
+{
+ return (CVAL(buf,smb_wct));
+}
+
+/*******************************************************************
+return the size of the smb_buf region of a message
+********************************************************************/
+int smb_buflen(char *buf)
+{
+ return(SVAL(buf,smb_vwv0 + smb_numwords(buf)*2));
+}
+
+/*******************************************************************
+ return a pointer to the smb_buf data area
+********************************************************************/
+int smb_buf_ofs(char *buf)
+{
+ return (smb_size + CVAL(buf,smb_wct)*2);
+}
+
+/*******************************************************************
+ return a pointer to the smb_buf data area
+********************************************************************/
+char *smb_buf(char *buf)
+{
+ return (buf + smb_buf_ofs(buf));
+}
+
+/*******************************************************************
+return the SMB offset into an SMB buffer
+********************************************************************/
+int smb_offset(char *p,char *buf)
+{
+ return(PTR_DIFF(p,buf+4));
+}
+
+
+/*******************************************************************
+skip past some strings in a buffer
+********************************************************************/
+char *skip_string(char *buf,int n)
+{
+ while (n--)
+ buf += strlen(buf) + 1;
+ return(buf);
+}
+
+/*******************************************************************
+trim the specified elements off the front and back of a string
+********************************************************************/
+BOOL trim_string(char *s,char *front,char *back)
+{
+ BOOL ret = False;
+ while (front && *front && strncmp(s,front,strlen(front)) == 0)
+ {
+ char *p = s;
+ ret = True;
+ while (1)
+ {
+ if (!(*p = p[strlen(front)]))
+ break;
+ p++;
+ }
+ }
+ while (back && *back && strlen(s) >= strlen(back) &&
+ (strncmp(s+strlen(s)-strlen(back),back,strlen(back))==0))
+ {
+ ret = True;
+ s[strlen(s)-strlen(back)] = 0;
+ }
+ return(ret);
+}
+
+
+/*******************************************************************
+reduce a file name, removing .. elements.
+********************************************************************/
+void dos_clean_name(char *s)
+{
+ char *p=NULL;
+
+ DEBUG(3,("dos_clean_name [%s]\n",s));
+
+ /* remove any double slashes */
+ string_sub(s, "\\\\", "\\");
+
+ while ((p = strstr(s,"\\..\\")) != NULL)
+ {
+ pstring s1;
+
+ *p = 0;
+ strcpy(s1,p+3);
+
+ if ((p=strrchr(s,'\\')) != NULL)
+ *p = 0;
+ else
+ *s = 0;
+ strcat(s,s1);
+ }
+
+ trim_string(s,NULL,"\\..");
+
+ string_sub(s, "\\.\\", "\\");
+}
+
+/*******************************************************************
+reduce a file name, removing .. elements.
+********************************************************************/
+void unix_clean_name(char *s)
+{
+ char *p=NULL;
+
+ DEBUG(3,("unix_clean_name [%s]\n",s));
+
+ /* remove any double slashes */
+ string_sub(s, "//","/");
+
+ while ((p = strstr(s,"/../")) != NULL)
+ {
+ pstring s1;
+
+ *p = 0;
+ strcpy(s1,p+3);
+
+ if ((p=strrchr(s,'/')) != NULL)
+ *p = 0;
+ else
+ *s = 0;
+ strcat(s,s1);
+ }
+
+ trim_string(s,NULL,"/..");
+}
+
+
+/*******************************************************************
+a wrapper for the normal chdir() function
+********************************************************************/
+int ChDir(char *path)
+{
+ int res;
+ static pstring LastDir="";
+
+ if (strcsequal(path,".")) return(0);
+
+ if (*path == '/' && strcsequal(LastDir,path)) return(0);
+ DEBUG(3,("chdir to %s\n",path));
+ res = sys_chdir(path);
+ if (!res)
+ strcpy(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)
+
+struct
+{
+ ino_t inode;
+ dev_t dev;
+ char *text;
+ BOOL valid;
+} ino_list[MAX_GETWDCACHE];
+
+BOOL use_getwd_cache=True;
+
+/*******************************************************************
+ return the absolute current directory path
+********************************************************************/
+char *GetWd(char *str)
+{
+ pstring s;
+ static BOOL getwd_cache_init = False;
+ struct stat st, st2;
+ int i;
+
+ *s = 0;
+
+ if (!use_getwd_cache)
+ return(Dumb_GetWd(str));
+
+ /* init the cache */
+ if (!getwd_cache_init)
+ {
+ getwd_cache_init = True;
+ for (i=0;i<MAX_GETWDCACHE;i++)
+ {
+ string_init(&ino_list[i].text,"");
+ ino_list[i].valid = False;
+ }
+ }
+
+ /* Get the inode of the current directory, if this doesn't work we're
+ in trouble :-) */
+
+ if (stat(".",&st) == -1)
+ {
+ DEBUG(0,("Very strange, couldn't stat \".\"\n"));
+ return(Dumb_GetWd(str));
+ }
+
+
+ for (i=0; i<MAX_GETWDCACHE; i++)
+ if (ino_list[i].valid)
+ {
+
+ /* If we have found an entry with a matching inode and dev number
+ then find the inode number for the directory in the cached string.
+ If this agrees with that returned by the stat for the current
+ directory then all is o.k. (but make sure it is a directory all
+ the same...) */
+
+ if (st.st_ino == ino_list[i].inode &&
+ st.st_dev == ino_list[i].dev)
+ {
+ if (stat(ino_list[i].text,&st2) == 0)
+ {
+ if (st.st_ino == st2.st_ino &&
+ st.st_dev == st2.st_dev &&
+ (st2.st_mode & S_IFMT) == S_IFDIR)
+ {
+ strcpy (str, ino_list[i].text);
+
+ /* promote it for future use */
+ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
+ return (str);
+ }
+ else
+ {
+ /* If the inode is different then something's changed,
+ scrub the entry and start from scratch. */
+ ino_list[i].valid = False;
+ }
+ }
+ }
+ }
+
+
+ /* We don't have the information to hand so rely on traditional methods.
+ The very slow getcwd, which spawns a process on some systems, or the
+ not quite so bad getwd. */
+
+ if (!Dumb_GetWd(s))
+ {
+ DEBUG(0,("Getwd failed, errno %d\n",errno));
+ return (NULL);
+ }
+
+ strcpy(str,s);
+
+ DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev));
+
+ /* add it to the cache */
+ i = MAX_GETWDCACHE - 1;
+ string_set(&ino_list[i].text,s);
+ ino_list[i].dev = st.st_dev;
+ ino_list[i].inode = st.st_ino;
+ ino_list[i].valid = True;
+
+ /* put it at the top of the list */
+ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
+
+ return (str);
+}
+
+
+
+/*******************************************************************
+reduce a file name, removing .. elements and checking that
+it is below dir in the heirachy. This uses GetWd() and so must be run
+on the system that has the referenced file system.
+
+widelinks are allowed if widelinks is true
+********************************************************************/
+BOOL reduce_name(char *s,char *dir,BOOL widelinks)
+{
+#ifndef REDUCE_PATHS
+ return True;
+#else
+ pstring dir2;
+ pstring wd;
+ pstring basename;
+ pstring newname;
+ char *p=NULL;
+ BOOL relative = (*s != '/');
+
+ *dir2 = *wd = *basename = *newname = 0;
+
+ if (widelinks)
+ {
+ unix_clean_name(s);
+ /* can't have a leading .. */
+ if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
+ {
+ DEBUG(3,("Illegal file name? (%s)\n",s));
+ return(False);
+ }
+ return(True);
+ }
+
+ DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
+
+ /* remove any double slashes */
+ string_sub(s,"//","/");
+
+ strcpy(basename,s);
+ p = strrchr(basename,'/');
+
+ if (!p)
+ return(True);
+
+ if (!GetWd(wd))
+ {
+ DEBUG(0,("couldn't getwd for %s %s\n",s,dir));
+ return(False);
+ }
+
+ if (ChDir(dir) != 0)
+ {
+ DEBUG(0,("couldn't chdir to %s\n",dir));
+ return(False);
+ }
+
+ if (!GetWd(dir2))
+ {
+ DEBUG(0,("couldn't getwd for %s\n",dir));
+ ChDir(wd);
+ return(False);
+ }
+
+
+ if (p && (p != basename))
+ {
+ *p = 0;
+ if (strcmp(p+1,".")==0)
+ p[1]=0;
+ if (strcmp(p+1,"..")==0)
+ *p = '/';
+ }
+
+ if (ChDir(basename) != 0)
+ {
+ ChDir(wd);
+ DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename));
+ return(False);
+ }
+
+ if (!GetWd(newname))
+ {
+ ChDir(wd);
+ DEBUG(2,("couldn't get wd for %s %s\n",s,dir2));
+ return(False);
+ }
+
+ if (p && (p != basename))
+ {
+ strcat(newname,"/");
+ strcat(newname,p+1);
+ }
+
+ {
+ int l = strlen(dir2);
+ if (dir2[l-1] == '/')
+ l--;
+
+ if (strncmp(newname,dir2,l) != 0)
+ {
+ ChDir(wd);
+ DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,l));
+ return(False);
+ }
+
+ if (relative)
+ {
+ if (newname[l] == '/')
+ strcpy(s,newname + l + 1);
+ else
+ strcpy(s,newname+l);
+ }
+ else
+ strcpy(s,newname);
+ }
+
+ ChDir(wd);
+
+ if (strlen(s) == 0)
+ strcpy(s,"./");
+
+ DEBUG(3,("reduced to %s\n",s));
+ return(True);
+#endif
+}
+
+/****************************************************************************
+expand some *s
+****************************************************************************/
+static void expand_one(char *Mask,int len)
+{
+ char *p1;
+ while ((p1 = strchr(Mask,'*')) != NULL)
+ {
+ int lfill = (len+1) - strlen(Mask);
+ int l1= (p1 - Mask);
+ pstring tmp;
+ strcpy(tmp,Mask);
+ memset(tmp+l1,'?',lfill);
+ strcpy(tmp + l1 + lfill,Mask + l1 + 1);
+ strcpy(Mask,tmp);
+ }
+}
+
+/****************************************************************************
+expand a wildcard expression, replacing *s with ?s
+****************************************************************************/
+void expand_mask(char *Mask,BOOL doext)
+{
+ pstring mbeg,mext;
+ pstring dirpart;
+ pstring filepart;
+ BOOL hasdot = False;
+ char *p1;
+ BOOL absolute = (*Mask == '\\');
+
+ *mbeg = *mext = *dirpart = *filepart = 0;
+
+ /* parse the directory and filename */
+ if (strchr(Mask,'\\'))
+ dirname_dos(Mask,dirpart);
+
+ filename_dos(Mask,filepart);
+
+ strcpy(mbeg,filepart);
+ if ((p1 = strchr(mbeg,'.')) != NULL)
+ {
+ hasdot = True;
+ *p1 = 0;
+ p1++;
+ strcpy(mext,p1);
+ }
+ else
+ {
+ strcpy(mext,"");
+ if (strlen(mbeg) > 8)
+ {
+ strcpy(mext,mbeg + 8);
+ mbeg[8] = 0;
+ }
+ }
+
+ if (*mbeg == 0)
+ strcpy(mbeg,"????????");
+ if ((*mext == 0) && doext && !hasdot)
+ strcpy(mext,"???");
+
+ if (strequal(mbeg,"*") && *mext==0)
+ strcpy(mext,"*");
+
+ /* expand *'s */
+ expand_one(mbeg,8);
+ if (*mext)
+ expand_one(mext,3);
+
+ strcpy(Mask,dirpart);
+ if (*dirpart || absolute) strcat(Mask,"\\");
+ strcat(Mask,mbeg);
+ strcat(Mask,".");
+ strcat(Mask,mext);
+
+ DEBUG(6,("Mask expanded to [%s]\n",Mask));
+}
+
+
+/****************************************************************************
+does a string have any uppercase chars in it?
+****************************************************************************/
+BOOL strhasupper(char *s)
+{
+ while (*s)
+ {
+#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);
+ s++;
+#endif /* KANJI */
+ }
+ return(False);
+}
+
+/****************************************************************************
+does a string have any lowercase chars in it?
+****************************************************************************/
+BOOL strhaslower(char *s)
+{
+ while (*s)
+ {
+#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);
+ s++;
+#endif /* KANJI */
+ }
+ return(False);
+}
+
+/****************************************************************************
+find the number of chars in a string
+****************************************************************************/
+int count_chars(char *s,char c)
+{
+ int count=0;
+ while (*s)
+ {
+ if (*s == c)
+ count++;
+ s++;
+ }
+ return(count);
+}
+
+
+/****************************************************************************
+ make a dir struct
+****************************************************************************/
+void make_dir_struct(char *buf,char *mask,char *fname,unsigned int size,int mode,time_t date)
+{
+ char *p;
+ pstring mask2;
+
+ strcpy(mask2,mask);
+
+ if ((mode & aDIR) != 0)
+ size = 0;
+
+ memset(buf+1,' ',11);
+ if ((p = strchr(mask2,'.')) != NULL)
+ {
+ *p = 0;
+ memcpy(buf+1,mask2,MIN(strlen(mask2),8));
+ memcpy(buf+9,p+1,MIN(strlen(p+1),3));
+ *p = '.';
+ }
+ else
+ memcpy(buf+1,mask2,MIN(strlen(mask2),11));
+
+ bzero(buf+21,DIR_STRUCT_SIZE-21);
+ CVAL(buf,21) = mode;
+ put_dos_date(buf,22,date);
+ SSVAL(buf,26,size & 0xFFFF);
+ SSVAL(buf,28,size >> 16);
+ StrnCpy(buf+30,fname,12);
+ if (!case_sensitive)
+ strupper(buf+30);
+ DEBUG(8,("put name [%s] into dir struct\n",buf+30));
+}
+
+
+/*******************************************************************
+close the low 3 fd's and open dev/null in their place
+********************************************************************/
+void close_low_fds(void)
+{
+ int fd;
+ int i;
+ close(0); close(1); close(2);
+ /* try and use up these file descriptors, so silly
+ library routines writing to stdout etc won't cause havoc */
+ for (i=0;i<3;i++) {
+ fd = open("/dev/null",O_RDWR,0);
+ if (fd < 0) fd = open("/dev/null",O_WRONLY,0);
+ if (fd < 0) {
+ DEBUG(0,("Can't open /dev/null\n"));
+ return;
+ }
+ if (fd != i) {
+ DEBUG(0,("Didn't get file descriptor %d\n",i));
+ return;
+ }
+ }
+}
+
+
+/****************************************************************************
+write to a socket
+****************************************************************************/
+int write_socket(int fd,char *buf,int len)
+{
+ int ret=0;
+
+ if (passive)
+ return(len);
+ DEBUG(6,("write_socket(%d,%d)\n",fd,len));
+ ret = write_data(fd,buf,len);
+
+ DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret));
+ return(ret);
+}
+
+/****************************************************************************
+read from a socket
+****************************************************************************/
+int read_udp_socket(int fd,char *buf,int len)
+{
+ int ret;
+ struct sockaddr sock;
+ int socklen;
+
+ socklen = sizeof(sock);
+ bzero((char *)&sock,socklen);
+ 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));
+ return(0);
+ }
+
+ lastip = *(struct in_addr *) &sock.sa_data[2];
+ lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port);
+
+ 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)
+{
+ fd_set fds;
+ int selrtn;
+ int readret;
+ int nread = 0;
+ struct timeval timeout, tval1, tval2, tvaldiff;
+ int error_limit = 5;
+
+ /* just checking .... */
+ if (maxcnt <= 0) return(0);
+
+ if(time_out == -2)
+ time_out = DEFAULT_PIPE_TIMEOUT;
+
+ /* Blocking read */
+ 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;
+ }
+ 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
+ system performance will suffer severely as
+ select always return true on disk files */
+
+ /* Set initial timeout */
+ 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(;;)
+ {
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ selrtn = sys_select(&fds,&timeout);
+
+ /* Check if error */
+ if(selrtn == -1) {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ if (nread < mincnt) return -1;
+ break; /* Yes */
+ }
+
+ 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) {
+ /* force a particular error number for
+ portability */
+ DEBUG(5,("read gave error %s\n",strerror(errno)));
+ errno = EBADF;
+ 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 */
+ return(nread);
+}
+
+/****************************************************************************
+read data from the client. Maxtime is in milliseconds
+****************************************************************************/
+int read_max_udp(int fd,char *buffer,int bufsize,int maxtime)
+{
+ fd_set fds;
+ int selrtn;
+ int nread;
+ struct timeval timeout;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ timeout.tv_sec = maxtime / 1000;
+ timeout.tv_usec = (maxtime % 1000) * 1000;
+
+ selrtn = sys_select(&fds,maxtime>0?&timeout:NULL);
+
+ if (!FD_ISSET(fd,&fds))
+ return 0;
+
+ nread = read_udp_socket(fd, buffer, bufsize);
+
+ /* return the number got */
+ return(nread);
+}
+
+/*******************************************************************
+find the difference in milliseconds between two struct timeval
+values
+********************************************************************/
+int TvalDiff(struct timeval *tvalold,struct timeval *tvalnew)
+{
+ return((tvalnew->tv_sec - tvalold->tv_sec)*1000 +
+ ((int)tvalnew->tv_usec - (int)tvalold->tv_usec)/1000);
+}
+
+/****************************************************************************
+send a keepalive packet (rfc1002)
+****************************************************************************/
+BOOL send_keepalive(int client)
+{
+ unsigned char buf[4];
+
+ buf[0] = 0x85;
+ buf[1] = buf[2] = buf[3] = 0;
+
+ return(write_data(client,(char *)buf,4) == 4);
+}
+
+
+
+/****************************************************************************
+ read data from the client, reading exactly N bytes.
+****************************************************************************/
+int read_data(int fd,char *buffer,int N)
+{
+ int ret;
+ int total=0;
+
+ while (total < N)
+ {
+ ret = read(fd,buffer + total,N - total);
+
+ /* this is for portability */
+ if (ret < 0)
+ errno = EBADF;
+
+ if (ret <= 0)
+ return total;
+ total += ret;
+ }
+ return total;
+}
+
+
+/****************************************************************************
+ write data to a fd
+****************************************************************************/
+int write_data(int fd,char *buffer,int N)
+{
+ int total=0;
+ int ret;
+
+ while (total < N)
+ {
+ ret = write(fd,buffer + total,N - total);
+
+ if (ret <= 0)
+ return total;
+
+ total += ret;
+ }
+ return total;
+}
+
+
+/* variables used by the read prediction module */
+int rp_fd = -1;
+int rp_offset = 0;
+int rp_length = 0;
+int rp_alloced = 0;
+int rp_predict_fd = -1;
+int rp_predict_offset = 0;
+int rp_predict_length = 0;
+int rp_timeout = 5;
+time_t rp_time = 0;
+char *rp_buffer = NULL;
+BOOL predict_skip=False;
+time_t smb_last_time=(time_t)0;
+
+/****************************************************************************
+handle read prediction on a file
+****************************************************************************/
+int read_predict(int fd,int offset,char *buf,char **ptr,int num)
+{
+ int ret = 0;
+ int possible = rp_length - (offset - rp_offset);
+
+ possible = MIN(possible,num);
+
+ /* give data if possible */
+ if (fd == rp_fd &&
+ offset >= rp_offset &&
+ possible>0 &&
+ smb_last_time-rp_time < rp_timeout)
+ {
+ ret = possible;
+ if (buf)
+ memcpy(buf,rp_buffer + (offset-rp_offset),possible);
+ else
+ *ptr = rp_buffer + (offset-rp_offset);
+ DEBUG(5,("read-prediction gave %d bytes of %d\n",ret,num));
+ }
+
+ if (ret == num) {
+ predict_skip = True;
+ } else {
+ predict_skip = False;
+
+ /* prepare the next prediction */
+ rp_predict_fd = fd;
+ rp_predict_offset = offset + num;
+ rp_predict_length = num;
+ }
+
+ if (ret < 0) ret = 0;
+
+ return(ret);
+}
+
+/****************************************************************************
+pre-read some data
+****************************************************************************/
+void do_read_prediction()
+{
+ if (predict_skip) return;
+
+ if (rp_predict_fd == -1)
+ return;
+
+ rp_fd = rp_predict_fd;
+ rp_offset = rp_predict_offset;
+ rp_length = 0;
+
+ rp_predict_fd = -1;
+
+ rp_predict_length = MIN(rp_predict_length,2*ReadSize);
+ rp_predict_length = MAX(rp_predict_length,1024);
+ rp_offset = (rp_offset/1024)*1024;
+ rp_predict_length = (rp_predict_length/1024)*1024;
+
+ if (rp_predict_length > rp_alloced)
+ {
+ rp_buffer = Realloc(rp_buffer,rp_predict_length);
+ rp_alloced = rp_predict_length;
+ if (!rp_buffer)
+ {
+ DEBUG(0,("can't allocate read-prediction buffer\n"));
+ rp_predict_fd = -1;
+ rp_fd = -1;
+ rp_alloced = 0;
+ return;
+ }
+ }
+
+ if (lseek(rp_fd,rp_offset,SEEK_SET) != rp_offset) {
+ rp_fd = -1;
+ rp_predict_fd = -1;
+ return;
+ }
+
+ rp_length = read(rp_fd,rp_buffer,rp_predict_length);
+ rp_time = time(NULL);
+ if (rp_length < 0)
+ rp_length = 0;
+}
+
+/****************************************************************************
+invalidate read-prediction on a fd
+****************************************************************************/
+void invalidate_read_prediction(int fd)
+{
+ if (rp_fd == fd)
+ rp_fd = -1;
+ if (rp_predict_fd == fd)
+ rp_predict_fd = -1;
+}
+
+
+/****************************************************************************
+transfer some data between two fd's
+****************************************************************************/
+int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align)
+{
+ static char *buf=NULL;
+ char *buf1,*abuf;
+ static int size = 0;
+ int total = 0;
+
+ DEBUG(4,("transfer_file %d (head=%d) called\n",n,headlen));
+
+ if ((size < ReadSize) && buf) {
+ free(buf);
+ buf = NULL;
+ }
+
+ size = MAX(ReadSize,1024);
+
+ while (!buf && size>0) {
+ buf = (char *)Realloc(buf,size+8);
+ if (!buf) size /= 2;
+ }
+ if (!buf) {
+ DEBUG(0,("Can't allocate transfer buffer!\n"));
+ exit(1);
+ }
+
+ abuf = buf + (align%8);
+
+ if (header)
+ n += headlen;
+
+ while (n > 0)
+ {
+ int s = MIN(n,size);
+ int ret,ret2=0;
+
+ ret = 0;
+
+ if (header && (headlen >= MIN(s,1024))) {
+ buf1 = header;
+ s = headlen;
+ ret = headlen;
+ headlen = 0;
+ header = NULL;
+ } else {
+ buf1 = abuf;
+ }
+
+ if (header && headlen > 0)
+ {
+ ret = MIN(headlen,size);
+ memcpy(buf1,header,ret);
+ headlen -= ret;
+ header += ret;
+ if (headlen <= 0) header = NULL;
+ }
+
+ if (s > ret)
+ ret += read(infd,buf1+ret,s-ret);
+
+ if (ret > 0)
+ {
+ ret2 = (outfd>=0?write_data(outfd,buf1,ret):ret);
+ if (ret2 > 0) total += ret2;
+ /* if we can't write then dump excess data */
+ if (ret2 != ret)
+ transfer_file(infd,-1,n-(ret+headlen),NULL,0,0);
+ }
+ if (ret <= 0 || ret2 != ret)
+ return(total);
+ n -= ret;
+ }
+ return(total);
+}
+
+
+/****************************************************************************
+read 4 bytes of a smb packet and return the smb length of the packet
+possibly store the result in the buffer
+****************************************************************************/
+int read_smb_length(int fd,char *inbuf,int timeout)
+{
+ char *buffer;
+ char buf[4];
+ int len=0, msg_type;
+ BOOL ok=False;
+
+ if (inbuf)
+ buffer = inbuf;
+ else
+ buffer = buf;
+
+ while (!ok)
+ {
+ if (timeout > 0)
+ ok = (read_with_timeout(fd,buffer,4,4,timeout,False) == 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);
+ }
+ }
+
+ len = smb_len(buffer);
+ msg_type = CVAL(buffer,0);
+
+ if (msg_type == 0x85)
+ {
+ DEBUG(5,( "Got keepalive packet\n"));
+ ok = False;
+ }
+ }
+
+ DEBUG(10,("got smb length of %d\n",len));
+
+ return(len);
+}
+
+
+
+/****************************************************************************
+ read an smb from a fd and return it's length
+The timeout is in milli seconds
+****************************************************************************/
+BOOL receive_smb(int fd,char *buffer,int timeout)
+{
+ int len;
+ BOOL ok;
+
+ bzero(buffer,smb_size + 100);
+
+ len = read_smb_length(fd,buffer,timeout);
+ if (len == -1)
+ return(False);
+
+ if (len > BUFFER_SIZE)
+ {
+ 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);
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+ send an smb to a fd
+****************************************************************************/
+BOOL send_smb(int fd,char *buffer)
+{
+ int len;
+ int ret,nwritten=0;
+ len = smb_len(buffer) + 4;
+
+ while (nwritten < len)
+ {
+ ret = write_socket(fd,buffer+nwritten,len - nwritten);
+ if (ret <= 0)
+ {
+ DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",len,ret));
+ close_sockets();
+ exit(1);
+ }
+ nwritten += ret;
+ }
+
+
+ return True;
+}
+
+
+/****************************************************************************
+find a pointer to a netbios name
+****************************************************************************/
+char *name_ptr(char *buf,int ofs)
+{
+ unsigned char c = *(unsigned char *)(buf+ofs);
+
+ if ((c & 0xC0) == 0xC0)
+ {
+ uint16 l;
+ char p[2];
+ memcpy(p,buf+ofs,2);
+ p[0] &= ~0xC0;
+ l = RSVAL(p,0);
+ DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
+ return(buf + l);
+ }
+ else
+ return(buf+ofs);
+}
+
+/****************************************************************************
+extract a netbios name from a buf
+****************************************************************************/
+int name_extract(char *buf,int ofs,char *name)
+{
+ char *p = name_ptr(buf,ofs);
+ int d = PTR_DIFF(p,buf+ofs);
+ strcpy(name,"");
+ if (d < -50 || d > 50) return(0);
+ return(name_interpret(p,name));
+}
+
+
+/****************************************************************************
+return the total storage length of a mangled name
+****************************************************************************/
+int name_len(char *s)
+{
+ char *s0=s;
+ unsigned char c = *(unsigned char *)s;
+ if ((c & 0xC0) == 0xC0)
+ return(2);
+ while (*s) s += (*s)+1;
+ return(PTR_DIFF(s,s0)+1);
+}
+
+/****************************************************************************
+send a single packet to a port on another machine
+****************************************************************************/
+BOOL send_one_packet(char *buf,int len,struct in_addr ip,int port,int type)
+{
+ BOOL ret;
+ int out_fd;
+ struct sockaddr_in sock_out;
+
+ if (passive)
+ return(True);
+
+ /* create a socket to write to */
+ out_fd = socket(AF_INET, type, 0);
+ if (out_fd == -1)
+ {
+ DEBUG(0,("socket failed"));
+ return False;
+ }
+
+ /* set the address and port */
+ bzero((char *)&sock_out,sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)&ip);
+ sock_out.sin_port = htons( port );
+ sock_out.sin_family = AF_INET;
+
+ if (DEBUGLEVEL > 0)
+ DEBUG(3,("sending a packet of len %d to (%s) on port %d of type %s\n",
+ len,inet_ntoa(ip),port,type==SOCK_DGRAM?"DGRAM":"STREAM"));
+
+ /* send it */
+ 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));
+
+ close(out_fd);
+ return(ret);
+}
+
+/*******************************************************************
+sleep for a specified number of milliseconds
+********************************************************************/
+void msleep(int t)
+{
+ int tdiff=0;
+ struct timeval tval,t1,t2;
+ fd_set fds;
+
+ GetTimeOfDay(&t1);
+ GetTimeOfDay(&t2);
+
+ while (tdiff < t) {
+ tval.tv_sec = (t-tdiff)/1000;
+ tval.tv_usec = 1000*((t-tdiff)%1000);
+
+ FD_ZERO(&fds);
+ errno = 0;
+ sys_select(&fds,&tval);
+
+ GetTimeOfDay(&t2);
+ tdiff = TvalDiff(&t1,&t2);
+ }
+}
+
+/****************************************************************************
+check if a string is part of a list
+****************************************************************************/
+BOOL in_list(char *s,char *list,BOOL casesensitive)
+{
+ pstring tok;
+ char *p=list;
+
+ if (!list) return(False);
+
+ while (next_token(&p,tok,LIST_SEP))
+ {
+ if (casesensitive) {
+ if (strcmp(tok,s) == 0)
+ return(True);
+ } else {
+ if (StrCaseCmp(tok,s) == 0)
+ return(True);
+ }
+ }
+ return(False);
+}
+
+/* this is used to prevent lots of mallocs of size 1 */
+static char *null_string = NULL;
+
+/****************************************************************************
+set a string value, allocing the space for the string
+****************************************************************************/
+BOOL string_init(char **dest,char *src)
+{
+ int l;
+ if (!src)
+ src = "";
+
+ l = strlen(src);
+
+ if (l == 0)
+ {
+ if (!null_string)
+ null_string = (char *)malloc(1);
+
+ *null_string = 0;
+ *dest = null_string;
+ }
+ else
+ {
+ *dest = (char *)malloc(l+1);
+ strcpy(*dest,src);
+ }
+ return(True);
+}
+
+/****************************************************************************
+free a string value
+****************************************************************************/
+void string_free(char **s)
+{
+ if (!s || !(*s)) return;
+ if (*s == null_string)
+ *s = NULL;
+ if (*s) free(*s);
+ *s = NULL;
+}
+
+/****************************************************************************
+set a string value, allocing the space for the string, and deallocating any
+existing space
+****************************************************************************/
+BOOL string_set(char **dest,char *src)
+{
+ string_free(dest);
+
+ return(string_init(dest,src));
+}
+
+/****************************************************************************
+substitute a string for a pattern in another string. Make sure there is
+enough room!
+
+This routine looks for pattern in s and replaces it with
+insert. It may do multiple replacements.
+
+return True if a substitution was done.
+****************************************************************************/
+BOOL string_sub(char *s,char *pattern,char *insert)
+{
+ BOOL ret = False;
+ char *p;
+ int ls,lp,li;
+
+ if (!insert || !pattern || !s) return(False);
+
+ ls = strlen(s);
+ lp = strlen(pattern);
+ li = strlen(insert);
+
+ if (!*pattern) return(False);
+
+ while (lp <= ls && (p = strstr(s,pattern)))
+ {
+ ret = True;
+ memmove(p+li,p+lp,ls + 1 - (PTR_DIFF(p,s) + lp));
+ memcpy(p,insert,li);
+ s = p + li;
+ ls = strlen(s);
+ }
+ return(ret);
+}
+
+
+
+/*********************************************************
+* Recursive routine that is called by mask_match.
+* Does the actual matching.
+*********************************************************/
+BOOL do_match(char *str, char *regexp, int case_sig)
+{
+ char *p;
+
+ for( p = regexp; *p && *str; ) {
+ switch(*p) {
+ case '?':
+ str++; p++;
+ break;
+
+ case '*':
+ /* Look for a character matching
+ the one after the '*' */
+ p++;
+ if(!*p)
+ return True; /* Automatic match */
+ while(*str) {
+ while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
+ str++;
+ if(do_match(str,p,case_sig))
+ return True;
+ if(!*str)
+ return False;
+ else
+ str++;
+ }
+ return False;
+
+ default:
+ if(case_sig) {
+ if(*str != *p)
+ return False;
+ } else {
+ if(toupper(*str) != toupper(*p))
+ return False;
+ }
+ str++, p++;
+ break;
+ }
+ }
+ if(!*p && !*str)
+ return True;
+
+ if (!*p && str[0] == '.' && str[1] == 0)
+ return(True);
+
+ if (!*str && *p == '?')
+ {
+ while (*p == '?') p++;
+ return(!*p);
+ }
+
+ if(!*str && (*p == '*' && p[1] == '\0'))
+ return True;
+ return False;
+}
+
+
+/*********************************************************
+* Routine to match a given string with a regexp - uses
+* simplified regexp that takes * and ? only. Case can be
+* significant or not.
+*********************************************************/
+BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
+{
+ char *p;
+ pstring p1, p2;
+ fstring ebase,eext,sbase,sext;
+
+ BOOL matched;
+
+ /* Make local copies of str and regexp */
+ StrnCpy(p1,regexp,sizeof(pstring)-1);
+ StrnCpy(p2,str,sizeof(pstring)-1);
+
+ if (!strchr(p2,'.')) {
+ strcat(p2,".");
+ }
+
+/*
+ if (!strchr(p1,'.')) {
+ strcat(p1,".");
+ }
+*/
+
+#if 0
+ if (strchr(p1,'.'))
+ {
+ string_sub(p1,"*.*","*");
+ string_sub(p1,".*","*");
+ }
+#endif
+
+ /* Remove any *? and ** as they are meaningless */
+ for(p = p1; *p; p++)
+ while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
+ (void)strcpy( &p[1], &p[2]);
+
+ if (strequal(p1,"*")) return(True);
+
+ DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
+
+ if (trans2) {
+ strcpy(ebase,p1);
+ strcpy(sbase,p2);
+ } else {
+ if ((p=strrchr(p1,'.'))) {
+ *p = 0;
+ strcpy(ebase,p1);
+ strcpy(eext,p+1);
+ } else {
+ strcpy(ebase,p1);
+ eext[0] = 0;
+ }
+
+ if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
+ *p = 0;
+ strcpy(sbase,p2);
+ strcpy(sext,p+1);
+ } else {
+ strcpy(sbase,p2);
+ strcpy(sext,"");
+ }
+ }
+
+ matched = do_match(sbase,ebase,case_sig) &&
+ (trans2 || do_match(sext,eext,case_sig));
+
+ DEBUG(5,("mask_match returning %d\n", matched));
+
+ return matched;
+}
+
+
+
+/****************************************************************************
+become a daemon, discarding the controlling terminal
+****************************************************************************/
+void become_daemon(void)
+{
+#ifndef NO_FORK_DEBUG
+ if (fork())
+ exit(0);
+
+ /* detach from the terminal */
+#ifdef USE_SETSID
+ setsid();
+#else
+#ifdef TIOCNOTTY
+ {
+ int i = open("/dev/tty", O_RDWR);
+ if (i >= 0)
+ {
+ ioctl(i, (int) TIOCNOTTY, (char *)0);
+ close(i);
+ }
+ }
+#endif
+#endif
+#endif
+}
+
+/****************************************************************************
+calculate the default netmask for an address
+****************************************************************************/
+static void default_netmask(struct in_addr *inm, struct in_addr *iad)
+{
+ unsigned long ad = ntohl(iad->s_addr);
+ unsigned long nm;
+ /*
+ ** Guess a netmask based on the class of the IP address given.
+ */
+ if ( (ad & 0x80000000) == 0 ) {
+ /* class A address */
+ nm = 0xFF000000;
+ } else if ( (ad & 0xC0000000) == 0x80000000 ) {
+ /* class B address */
+ nm = 0xFFFF0000;
+ } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
+ /* class C address */
+ nm = 0xFFFFFF00;
+ } else {
+ /* class D or E; netmask doesn't make much sense - guess 4 bits */
+ nm = 0xFFFFFFF0;
+ }
+ inm->s_addr = htonl(nm);
+}
+
+/****************************************************************************
+ get the broadcast address for our address
+(troyer@saifr00.ateng.az.honeywell.com)
+****************************************************************************/
+void get_broadcast(struct in_addr *if_ipaddr,
+ struct in_addr *if_bcast,
+ struct in_addr *if_nmask)
+{
+ BOOL found = False;
+#ifndef NO_GET_BROADCAST
+ int sock = -1; /* AF_INET raw socket desc */
+ char buff[1024];
+ struct ifreq *ifr=NULL;
+ int i;
+
+#if defined(EVEREST)
+ int n_interfaces;
+ struct ifconf ifc;
+ struct ifreq *ifreqs;
+#elif defined(USE_IFREQ)
+ struct ifreq ifreq;
+ struct strioctl strioctl;
+ struct ifconf *ifc;
+#else
+ struct ifconf ifc;
+#endif
+#endif
+
+ /* get a default netmask and broadcast */
+ default_netmask(if_nmask, if_ipaddr);
+
+#ifndef NO_GET_BROADCAST
+ /* Create a socket to the INET kernel. */
+#if USE_SOCKRAW
+ if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
+#else
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
+#endif
+ {
+ DEBUG(0,( "Unable to open socket to get broadcast address\n"));
+ return;
+ }
+
+ /* Get a list of the configured interfaces */
+#ifdef EVEREST
+ /* This is part of SCO Openserver 5: The ioctls are no longer part
+ if the lower level STREAMS interface glue. They are now real
+ ioctl calls */
+
+ if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
+ DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
+ } else {
+ DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
+
+ ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
+ ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
+
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
+ DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
+ else {
+ ifr = ifc.ifc_req;
+
+ for (i = 0; i < n_interfaces; ++i) {
+ if (if_ipaddr->s_addr ==
+ ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+ }
+#elif defined(USE_IFREQ)
+ ifc = (struct ifconf *)buff;
+ ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
+ strioctl.ic_cmd = SIOCGIFCONF;
+ strioctl.ic_dp = (char *)ifc;
+ strioctl.ic_len = sizeof(buff);
+ if (ioctl(sock, I_STR, &strioctl) < 0) {
+ DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = (struct ifreq *)ifc->ifc_req;
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+#elif defined(__FreeBSD__) || defined(NETBSD)
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = ifc.ifc_req;
+ /* Loop through interfaces, looking for given IP address */
+ i = ifc.ifc_len;
+ while (i > 0) {
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
+ ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
+ }
+ }
+#else
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
+ } else {
+ ifr = ifc.ifc_req;
+
+ /* Loop through interfaces, looking for given IP address */
+ for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
+#ifdef BSDI
+ if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
+#endif
+ if (if_ipaddr->s_addr ==
+ (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
+ found = True;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (!found) {
+ DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
+ } else {
+ /* Get the netmask address from the kernel */
+#ifdef USE_IFREQ
+ ifreq = *ifr;
+
+ strioctl.ic_cmd = SIOCGIFNETMASK;
+ strioctl.ic_dp = (char *)&ifreq;
+ strioctl.ic_len = sizeof(struct ifreq);
+ if (ioctl(sock, I_STR, &strioctl) < 0)
+ DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
+ else
+ *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+#else
+ if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
+ DEBUG(0,("SIOCGIFNETMASK failed\n"));
+ else
+ *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+#endif
+
+ DEBUG(2,("Netmask for %s = %s\n", ifr->ifr_name,
+ inet_ntoa(*if_nmask)));
+ }
+
+ /* Close up shop */
+ (void) close(sock);
+
+#endif
+
+ /* sanity check on the netmask */
+ {
+ unsigned long nm = ntohl(if_nmask->s_addr);
+ if ((nm >> 24) != 0xFF) {
+ DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
+ default_netmask(if_nmask, if_ipaddr);
+ }
+ }
+
+ /* derive the broadcast assuming a 1's broadcast, as this is what
+ all MS operating systems do, we have to comply even if the unix
+ box is setup differently */
+ {
+ unsigned long ad = ntohl(if_ipaddr->s_addr);
+ unsigned long nm = ntohl(if_nmask->s_addr);
+ unsigned long bc = (ad & nm) | (0xffffffff & ~nm);
+ if_bcast->s_addr = htonl(bc);
+ }
+
+ DEBUG(2,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
+} /* get_broadcast */
+
+
+/****************************************************************************
+put up a yes/no prompt
+****************************************************************************/
+BOOL yesno(char *p)
+{
+ pstring ans;
+ printf("%s",p);
+
+ if (!fgets(ans,sizeof(ans)-1,stdin))
+ return(False);
+
+ if (*ans == 'y' || *ans == 'Y')
+ return(True);
+
+ return(False);
+}
+
+/****************************************************************************
+read a line from a file with possible \ continuation chars.
+Blanks at the start or end of a line are stripped.
+The string will be allocated if s2 is NULL
+****************************************************************************/
+char *fgets_slash(char *s2,int maxlen,FILE *f)
+{
+ char *s=s2;
+ int len = 0;
+ int c;
+ BOOL start_of_line = True;
+
+ if (feof(f))
+ return(NULL);
+
+ if (!s2)
+ {
+ maxlen = MIN(maxlen,8);
+ s = (char *)Realloc(s,maxlen);
+ }
+
+ if (!s || maxlen < 2) return(NULL);
+
+ *s = 0;
+
+ while (len < maxlen-1)
+ {
+ c = getc(f);
+ switch (c)
+ {
+ case '\r':
+ break;
+ case '\n':
+ while (len > 0 && s[len-1] == ' ')
+ {
+ s[--len] = 0;
+ }
+ if (len > 0 && s[len-1] == '\\')
+ {
+ s[--len] = 0;
+ start_of_line = True;
+ break;
+ }
+ return(s);
+ case EOF:
+ if (len <= 0 && !s2)
+ free(s);
+ return(len>0?s:NULL);
+ case ' ':
+ if (start_of_line)
+ break;
+ default:
+ start_of_line = False;
+ s[len++] = c;
+ s[len] = 0;
+ }
+ if (!s2 && len > maxlen-3)
+ {
+ maxlen *= 2;
+ s = (char *)Realloc(s,maxlen);
+ if (!s) return(NULL);
+ }
+ }
+ return(s);
+}
+
+
+
+/****************************************************************************
+set the length of a file from a filedescriptor.
+Returns 0 on success, -1 on failure.
+****************************************************************************/
+int set_filelen(int fd, long len)
+{
+/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
+ extend a file with ftruncate. Provide alternate implementation
+ for this */
+
+#if FTRUNCATE_CAN_EXTEND
+ return ftruncate(fd, len);
+#else
+ struct stat st;
+ char c = 0;
+ long currpos = lseek(fd, 0L, SEEK_CUR);
+
+ if(currpos < 0)
+ return -1;
+ /* Do an fstat to see if the file is longer than
+ the requested size (call ftruncate),
+ or shorter, in which case seek to len - 1 and write 1
+ byte of zero */
+ if(fstat(fd, &st)<0)
+ return -1;
+
+#ifdef S_ISFIFO
+ if (S_ISFIFO(st.st_mode)) return 0;
+#endif
+
+ if(st.st_size == len)
+ return 0;
+ if(st.st_size > len)
+ return ftruncate(fd, len);
+
+ if(lseek(fd, len-1, SEEK_SET) != len -1)
+ return -1;
+ if(write(fd, &c, 1)!=1)
+ return -1;
+ /* Seek to where we were */
+ lseek(fd, currpos, SEEK_SET);
+ return 0;
+#endif
+}
+
+
+/****************************************************************************
+return the byte checksum of some data
+****************************************************************************/
+int byte_checksum(char *buf,int len)
+{
+ unsigned char *p = (unsigned char *)buf;
+ int ret = 0;
+ while (len--)
+ ret += *p++;
+ return(ret);
+}
+
+
+
+#ifdef HPUX
+/****************************************************************************
+this is a version of setbuffer() for those machines that only have setvbuf
+****************************************************************************/
+void setbuffer(FILE *f,char *buf,int bufsize)
+{
+ setvbuf(f,buf,_IOFBF,bufsize);
+}
+#endif
+
+
+/****************************************************************************
+parse out a directory name from a path name. Assumes dos style filenames.
+****************************************************************************/
+char *dirname_dos(char *path,char *buf)
+{
+ char *p = strrchr(path,'\\');
+
+ if (!p)
+ strcpy(buf,path);
+ else
+ {
+ *p = 0;
+ strcpy(buf,path);
+ *p = '\\';
+ }
+
+ return(buf);
+}
+
+
+/****************************************************************************
+parse out a filename from a path name. Assumes dos style filenames.
+****************************************************************************/
+static char *filename_dos(char *path,char *buf)
+{
+ char *p = strrchr(path,'\\');
+
+ if (!p)
+ strcpy(buf,path);
+ else
+ strcpy(buf,p+1);
+
+ return(buf);
+}
+
+
+
+/****************************************************************************
+expand a pointer to be a particular size
+****************************************************************************/
+void *Realloc(void *p,int size)
+{
+ void *ret=NULL;
+ if (!p)
+ ret = (void *)malloc(size);
+ else
+ ret = (void *)realloc(p,size);
+
+ if (!ret)
+ DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",size));
+
+ return(ret);
+}
+
+/****************************************************************************
+set the time on a file
+****************************************************************************/
+BOOL set_filetime(char *fname,time_t mtime)
+{
+ struct utimbuf times;
+
+ if (null_mtime(mtime)) return(True);
+
+ times.modtime = times.actime = mtime;
+
+ if (sys_utime(fname,&times)) {
+ DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
+ }
+
+ return(True);
+}
+
+
+#ifdef NOSTRDUP
+/****************************************************************************
+duplicate a string
+****************************************************************************/
+char *strdup(char *s)
+{
+ char *ret = NULL;
+ if (!s) return(NULL);
+ ret = (char *)malloc(strlen(s)+1);
+ if (!ret) return(NULL);
+ strcpy(ret,s);
+ return(ret);
+}
+#endif
+
+
+/****************************************************************************
+ Signal handler for SIGPIPE (write on a disconnected socket)
+****************************************************************************/
+void Abort(void )
+{
+ DEBUG(0,("Probably got SIGPIPE\nExiting\n"));
+ exit(2);
+}
+
+
+#ifdef REPLACE_STRLEN
+/****************************************************************************
+a replacement strlen() that returns int for solaris
+****************************************************************************/
+int Strlen(char *s)
+{
+ int ret=0;
+ if (!s) return(0);
+ while (*s++) ret++;
+ return(ret);
+}
+#endif
+
+
+/****************************************************************************
+return a time at the start of the current month
+****************************************************************************/
+time_t start_of_month(void)
+{
+ time_t t = time(NULL);
+ struct tm *t2;
+
+ t2 = gmtime(&t);
+
+ t2->tm_mday = 1;
+ t2->tm_hour = 0;
+ t2->tm_min = 0;
+ t2->tm_sec = 0;
+
+ return(mktime(t2));
+}
+
+
+/*******************************************************************
+ check for a sane unix date
+********************************************************************/
+BOOL sane_unix_date(time_t unixdate)
+{
+ struct tm t,today;
+ time_t t_today = time(NULL);
+
+ t = *(LocalTime(&unixdate,LOCAL_TO_GMT));
+ today = *(LocalTime(&t_today,LOCAL_TO_GMT));
+
+ if (t.tm_year < 80)
+ return(False);
+
+ if (t.tm_year > today.tm_year)
+ return(False);
+
+ if (t.tm_year == today.tm_year &&
+ t.tm_mon > today.tm_mon)
+ return(False);
+
+
+ if (t.tm_year == today.tm_year &&
+ t.tm_mon == today.tm_mon &&
+ t.tm_mday > (today.tm_mday+1))
+ return(False);
+
+ return(True);
+}
+
+
+
+#ifdef NO_FTRUNCATE
+ /*******************************************************************
+ftruncate for operating systems that don't have it
+********************************************************************/
+int ftruncate(int f,long l)
+{
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = l;
+ fl.l_type = F_WRLCK;
+ return fcntl(f, F_FREESP, &fl);
+}
+#endif
+
+
+
+/****************************************************************************
+get my own name and IP
+****************************************************************************/
+BOOL get_myname(char *myname,struct in_addr *ip)
+{
+ struct hostent *hp;
+ pstring hostname;
+
+ *hostname = 0;
+
+ /* get my host name */
+ if (gethostname(hostname, MAXHOSTNAMELEN) == -1)
+ {
+ DEBUG(0,("gethostname failed\n"));
+ return False;
+ }
+
+ /* get host info */
+ if ((hp = Get_Hostbyname(hostname)) == 0)
+ {
+ DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname));
+ return False;
+ }
+
+ if (myname)
+ {
+ /* split off any parts after an initial . */
+ char *p = strchr(hostname,'.');
+ if (p) *p = 0;
+
+ strcpy(myname,hostname);
+ }
+
+ if (ip)
+ putip((char *)ip,(char *)hp->h_addr);
+
+ return(True);
+}
+
+
+/****************************************************************************
+true if two IP addresses are equal
+****************************************************************************/
+BOOL ip_equal(struct in_addr ip1,struct in_addr ip2)
+{
+ unsigned long a1,a2;
+ a1 = ntohl(ip1.s_addr);
+ a2 = ntohl(ip2.s_addr);
+ return(a1 == a2);
+}
+
+
+/****************************************************************************
+open a socket of the specified type, port and address for incoming data
+****************************************************************************/
+int open_socket_in(int type, int port, int dlevel)
+{
+ struct hostent *hp;
+ struct sockaddr_in sock;
+ pstring host_name;
+ int res;
+
+ /* get my host name */
+#ifdef MAXHOSTNAMELEN
+ if (gethostname(host_name, MAXHOSTNAMELEN) == -1)
+#else
+ if (gethostname(host_name, sizeof(host_name)) == -1)
+#endif
+ { DEBUG(0,("gethostname failed\n")); return -1; }
+
+ /* get host info */
+ if ((hp = Get_Hostbyname(host_name)) == 0)
+ {
+ DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",host_name));
+ return -1;
+ }
+
+ bzero((char *)&sock,sizeof(sock));
+ memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
+#if defined(__FreeBSD__) || defined(NETBSD) /* XXX not the right ifdef */
+ sock.sin_len = sizeof(sock);
+#endif
+ sock.sin_port = htons( port );
+ sock.sin_family = hp->h_addrtype;
+ sock.sin_addr.s_addr = INADDR_ANY;
+ res = socket(hp->h_addrtype, type, 0);
+ if (res == -1)
+ { DEBUG(0,("socket failed\n")); return -1; }
+
+ {
+ int one=1;
+ setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
+ }
+
+ /* now we've got a socket - we need to bind it */
+ if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0)
+ {
+ if (port) {
+ if (port == 139 || port == 137)
+ DEBUG(dlevel,("bind failed on port %d (%s)\n",
+ port,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(-1);
+ }
+ DEBUG(3,("bind succeeded on port %d\n",port));
+
+ return res;
+}
+
+
+/****************************************************************************
+ create an outgoing socket
+ **************************************************************************/
+int open_socket_out(int type, struct in_addr *addr, int port )
+{
+ struct sockaddr_in sock_out;
+ int res;
+
+ /* create a socket to write to */
+ res = socket(PF_INET, type, 0);
+ if (res == -1)
+ { DEBUG(0,("socket error\n")); return -1; }
+
+ if (type != SOCK_STREAM) return(res);
+
+ bzero((char *)&sock_out,sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)addr);
+
+ sock_out.sin_port = htons( port );
+ sock_out.sin_family = PF_INET;
+
+ 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);
+ }
+
+ return res;
+}
+
+
+/****************************************************************************
+interpret a protocol description string, with a default
+****************************************************************************/
+int interpret_protocol(char *str,int def)
+{
+ if (strequal(str,"NT1"))
+ return(PROTOCOL_NT1);
+ if (strequal(str,"LANMAN2"))
+ return(PROTOCOL_LANMAN2);
+ if (strequal(str,"LANMAN1"))
+ return(PROTOCOL_LANMAN1);
+ if (strequal(str,"CORE"))
+ return(PROTOCOL_CORE);
+ if (strequal(str,"COREPLUS"))
+ return(PROTOCOL_COREPLUS);
+ if (strequal(str,"CORE+"))
+ return(PROTOCOL_COREPLUS);
+
+ DEBUG(0,("Unrecognised protocol level %s\n",str));
+
+ return(def);
+}
+
+/****************************************************************************
+interpret a security level
+****************************************************************************/
+int interpret_security(char *str,int def)
+{
+ if (strequal(str,"SERVER"))
+ return(SEC_SERVER);
+ if (strequal(str,"USER"))
+ return(SEC_USER);
+ if (strequal(str,"SHARE"))
+ return(SEC_SHARE);
+
+ DEBUG(0,("Unrecognised security level %s\n",str));
+
+ return(def);
+}
+
+
+/****************************************************************************
+interpret an internet address or name into an IP address in 4 byte form
+****************************************************************************/
+unsigned long interpret_addr(char *str)
+{
+ struct hostent *hp;
+ unsigned long res;
+
+ if (strcmp(str,"0.0.0.0") == 0) return(0);
+ if (strcmp(str,"255.255.255.255") == 0) return(0xFFFFFFFF);
+
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (isdigit(str[0])) {
+ res = inet_addr(str);
+ } else {
+ /* 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;
+ }
+ putip((char *)&res,(char *)hp->h_addr);
+ }
+
+ if (res == (unsigned long)-1) return(0);
+
+ return(res);
+}
+
+/*******************************************************************
+ a convenient addition to interpret_addr()
+ ******************************************************************/
+struct in_addr *interpret_addr2(char *str)
+{
+ static struct in_addr ret;
+ unsigned long a = interpret_addr(str);
+ putip((char *)&ret,(char *)&a);
+ return(&ret);
+}
+
+/*******************************************************************
+ check if an IP is the 0.0.0.0
+ ******************************************************************/
+BOOL zero_ip(struct in_addr ip)
+{
+ unsigned long a;
+ putip((char *)&a,(char *)&ip);
+ return(a == 0);
+}
+
+#define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
+
+/****************************************************************************
+interpret an 8 byte "filetime" structure to a time_t
+It's originally in "100ns units since jan 1st 1601"
+
+It appears to be kludge-GMT (at least for file listings). This means
+its the GMT you get by taking a localtime and adding the
+serverzone. This is NOT the same as GMT in some cases. This routine
+converts this to real GMT.
+****************************************************************************/
+time_t interpret_long_date(char *p)
+{
+ double d;
+ time_t ret;
+ uint32 tlow,thigh;
+ tlow = IVAL(p,0);
+ thigh = IVAL(p,4);
+
+ if (thigh == 0) return(0);
+
+ d = ((double)thigh)*4.0*(double)(1<<30);
+ d += (tlow&0xFFF00000);
+ d *= 1.0e-7;
+
+ /* now adjust by 369 years to make the secs since 1970 */
+ d -= TIME_FIXUP_CONSTANT;
+
+ if (d>=MAXINT)
+ return(0);
+
+ ret = (time_t)(d+0.5);
+
+ /* this takes us from kludge-GMT to real GMT */
+ ret += TimeDiff(ret) - serverzone;
+
+ return(ret);
+}
+
+
+/****************************************************************************
+put a 8 byte filetime from a time_t
+This takes real GMT as input and converts to kludge-GMT
+****************************************************************************/
+void put_long_date(char *p,time_t t)
+{
+ uint32 tlow,thigh;
+ double d;
+
+ if (t==0) {
+ SIVAL(p,0,0); SIVAL(p,4,0);
+ return;
+ }
+
+ /* this converts GMT to kludge-GMT */
+ t -= TimeDiff(t) - serverzone;
+
+ d = (double) (t);
+
+ d += TIME_FIXUP_CONSTANT;
+
+ d *= 1.0e7;
+
+ thigh = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
+ tlow = (uint32)(d - ((double)thigh)*4.0*(double)(1<<30));
+
+ SIVAL(p,0,tlow);
+ SIVAL(p,4,thigh);
+}
+
+/*******************************************************************
+sub strings with useful parameters
+********************************************************************/
+void standard_sub_basic(char *s)
+{
+ if (!strchr(s,'%')) return;
+
+ string_sub(s,"%R",remote_proto);
+ string_sub(s,"%a",remote_arch);
+ string_sub(s,"%m",remote_machine);
+ string_sub(s,"%L",local_machine);
+
+ if (!strchr(s,'%')) return;
+
+ string_sub(s,"%v",VERSION);
+ string_sub(s,"%h",myhostname);
+ string_sub(s,"%U",sesssetup_user);
+
+ if (!strchr(s,'%')) return;
+
+ string_sub(s,"%I",Client_info.addr);
+ string_sub(s,"%M",Client_info.name);
+ string_sub(s,"%T",timestring());
+
+ if (!strchr(s,'%')) return;
+
+ {
+ char pidstr[10];
+ sprintf(pidstr,"%d",(int)getpid());
+ string_sub(s,"%d",pidstr);
+ }
+
+ if (!strchr(s,'%')) return;
+
+ {
+ struct passwd *pass = Get_Pwnam(sesssetup_user,False);
+ if (pass) {
+ string_sub(s,"%G",gidtoname(pass->pw_gid));
+ }
+ }
+}
+
+
+/*******************************************************************
+write a string in unicoode format
+********************************************************************/
+int PutUniCode(char *dst,char *src)
+{
+ int ret = 0;
+ while (*src) {
+ dst[ret++] = src[0];
+ dst[ret++] = 0;
+ src++;
+ }
+ dst[ret++]=0;
+ dst[ret++]=0;
+ return(ret);
+}
+
+
+pstring smbrun_path = SMBRUN;
+
+/****************************************************************************
+run a command via system() using smbrun
+****************************************************************************/
+int smbrun(char *cmd,char *outfile)
+{
+ int ret;
+ pstring syscmd;
+
+ if (!file_exist(smbrun_path,NULL))
+ {
+ DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",smbrun_path));
+ return(1);
+ }
+
+ sprintf(syscmd,"%s \"(%s 2>&1) > %s\"",
+ smbrun_path,cmd,
+ outfile?outfile:"/dev/null");
+
+ DEBUG(5,("smbrun - running %s ",syscmd));
+ ret = system(syscmd);
+ DEBUG(5,("gave %d\n",ret));
+ return(ret);
+}
+
+
+/****************************************************************************
+a wrapper for gethostbyname() that tries with all lower and all upper case
+if the initial name fails
+****************************************************************************/
+struct hostent *Get_Hostbyname(char *name)
+{
+ char *name2 = strdup(name);
+ struct hostent *ret;
+
+ if (!name2)
+ {
+ DEBUG(0,("Memory allocation error in Get_Hostbyname! panic\n"));
+ exit(0);
+ }
+
+ if (!isalnum(*name2))
+ {
+ free(name2);
+ return(NULL);
+ }
+
+ ret = gethostbyname(name2);
+ if (ret != NULL)
+ {
+ free(name2);
+ return(ret);
+ }
+
+ /* try with all lowercase */
+ strlower(name2);
+ ret = gethostbyname(name2);
+ if (ret != NULL)
+ {
+ free(name2);
+ return(ret);
+ }
+
+ /* try with all uppercase */
+ strupper(name2);
+ ret = gethostbyname(name2);
+ if (ret != NULL)
+ {
+ free(name2);
+ return(ret);
+ }
+
+ /* nothing works :-( */
+ free(name2);
+ return(NULL);
+}
+
+
+/****************************************************************************
+check if a process exists. Does this work on all unixes?
+****************************************************************************/
+BOOL process_exists(int pid)
+{
+#ifdef LINUX
+ fstring s;
+ sprintf(s,"/proc/%d",pid);
+ return(directory_exist(s,NULL));
+#else
+ {
+ static BOOL tested=False;
+ static BOOL ok=False;
+ fstring s;
+ if (!tested) {
+ tested = True;
+ sprintf(s,"/proc/%05d",getpid());
+ ok = file_exist(s,NULL);
+ }
+ if (ok) {
+ sprintf(s,"/proc/%05d",pid);
+ return(file_exist(s,NULL));
+ }
+ }
+
+ /* a best guess for non root access */
+ if (geteuid() != 0) return(True);
+
+ /* otherwise use kill */
+ return(pid == getpid() || kill(pid,0) == 0);
+#endif
+}
+
+
+/*******************************************************************
+turn a uid into a user name
+********************************************************************/
+char *uidtoname(int uid)
+{
+ static char name[40];
+ struct passwd *pass = getpwuid(uid);
+ if (pass) return(pass->pw_name);
+ sprintf(name,"%d",uid);
+ return(name);
+}
+
+/*******************************************************************
+turn a gid into a group name
+********************************************************************/
+char *gidtoname(int gid)
+{
+ static char name[40];
+ struct group *grp = getgrgid(gid);
+ if (grp) return(grp->gr_name);
+ sprintf(name,"%d",gid);
+ return(name);
+}
+
+/*******************************************************************
+block sigs
+********************************************************************/
+void BlockSignals(BOOL block)
+{
+#ifdef USE_SIGBLOCK
+ int block_mask = (sigmask(SIGTERM)|sigmask(SIGQUIT)|sigmask(SIGSEGV)
+ |sigmask(SIGCHLD)|sigmask(SIGQUIT)|sigmask(SIGBUS)|
+ sigmask(SIGINT));
+ if (block)
+ sigblock(block_mask);
+ else
+ sigunblock(block_mask);
+#endif
+}
+
+#if AJT
+/*******************************************************************
+my own panic function - not suitable for general use
+********************************************************************/
+void ajt_panic(void)
+{
+ pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &";
+ smbrun(cmd,NULL);
+}
+#endif
+
+#ifdef USE_DIRECT
+#define DIRECT direct
+#else
+#define DIRECT dirent
+#endif
+
+/*******************************************************************
+a readdir wrapper which just returns the file name
+also return the inode number if requested
+********************************************************************/
+char *readdirname(void *p)
+{
+ struct DIRECT *ptr;
+ char *dname;
+
+ if (!p) return(NULL);
+
+ ptr = (struct DIRECT *)readdir(p);
+ if (!ptr) return(NULL);
+
+ 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
+
+#ifdef SUNOS5
+ /* this handles a broken compiler setup, causing a mixture
+ of BSD and SYSV headers and libraries */
+ {
+ static BOOL broken_readdir = False;
+ if (!broken_readdir && !(*(dname)) && strequal("..",dname-2))
+ {
+ DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n"));
+ broken_readdir = True;
+ }
+ if (broken_readdir)
+ return(dname-2);
+ }
+#endif
+
+ return(dname);
+}
+
+
+
+#if (defined(SecureWare) && defined(SCO))
+/* This is needed due to needing the nap() function but we don't want
+ to include the Xenix libraries since that will break other things...
+ BTW: system call # 0x0c28 is the same as calling nap() */
+long nap(long milliseconds) {
+ return syscall(0x0c28, milliseconds);
+}
+#endif
+
+#ifdef NO_INITGROUPS
+#include <sys/types.h>
+#include <limits.h>
+#include <grp.h>
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/****************************************************************************
+ some systems don't have an initgroups call
+****************************************************************************/
+int initgroups(char *name,gid_t id)
+{
+#ifdef NO_SETGROUPS
+ /* yikes! no SETGROUPS or INITGROUPS? how can this work? */
+ return(0);
+#else
+ gid_t grouplst[NGROUPS_MAX];
+ int i,j;
+ struct group *g;
+ char *gr;
+
+ grouplst[0] = id;
+ i = 1;
+ while (i < NGROUPS_MAX &&
+ ((g = (struct group *)getgrent()) != (struct group *)NULL))
+ {
+ if (g->gr_gid == id)
+ continue;
+ j = 0;
+ gr = g->gr_mem[0];
+ while (gr && (*gr != (char)NULL)) {
+ if (strcmp(name,gr) == 0) {
+ grouplst[i] = g->gr_gid;
+ i++;
+ gr = (char *)NULL;
+ break;
+ }
+ gr = g->gr_mem[++j];
+ }
+ }
+ endgrent();
+ return(setgroups(i,grouplst));
+#endif
+}
+#endif
+
+
+#if WRAP_MALLOC
+
+/* undo the wrapping temporarily */
+#undef malloc
+#undef realloc
+#undef free
+
+/****************************************************************************
+wrapper for malloc() to catch memory errors
+****************************************************************************/
+void *malloc_wrapped(int size,char *file,int line)
+{
+#ifdef xx_old_malloc
+ void *res = xx_old_malloc(size);
+#else
+ void *res = malloc(size);
+#endif
+ DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
+ file,line,
+ size,(unsigned int)res));
+ return(res);
+}
+
+/****************************************************************************
+wrapper for realloc() to catch memory errors
+****************************************************************************/
+void *realloc_wrapped(void *ptr,int size,char *file,int line)
+{
+#ifdef xx_old_realloc
+ void *res = xx_old_realloc(ptr,size);
+#else
+ void *res = realloc(ptr,size);
+#endif
+ DEBUG(3,("Realloc\n"));
+ DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
+ file,line,
+ (unsigned int)ptr));
+ DEBUG(3,("Malloc called from %s(%d) with size=%d gave ptr=0x%X\n",
+ file,line,
+ size,(unsigned int)res));
+ return(res);
+}
+
+/****************************************************************************
+wrapper for free() to catch memory errors
+****************************************************************************/
+void free_wrapped(void *ptr,char *file,int line)
+{
+#ifdef xx_old_free
+ xx_old_free(ptr);
+#else
+ free(ptr);
+#endif
+ DEBUG(3,("free called from %s(%d) with ptr=0x%X\n",
+ file,line,(unsigned int)ptr));
+ return;
+}
+
+/* and re-do the define for spots lower in this file */
+#define malloc(size) malloc_wrapped(size,__FILE__,__LINE__)
+#define realloc(ptr,size) realloc_wrapped(ptr,size,__FILE__,__LINE__)
+#define free(ptr) free_wrapped(ptr,__FILE__,__LINE__)
+
+#endif
+
+#ifdef REPLACE_STRSTR
+/****************************************************************************
+Mips version of strstr doesn't seem to work correctly.
+There is a #define in includes.h to redirect calls to this function.
+****************************************************************************/
+char *Strstr(char *s, char *p)
+{
+ int len = strlen(p);
+
+ while ( *s != '\0' ) {
+ if ( strncmp(s, p, len) == 0 )
+ return s;
+ s++;
+ }
+
+ return NULL;
+}
+#endif /* REPLACE_STRSTR */
+
+
+#ifdef REPLACE_MKTIME
+/*******************************************************************
+a mktime() replacement for those who don't have it - contributed by
+C.A. Lademann <cal@zls.com>
+********************************************************************/
+#define MINUTE 60
+#define HOUR 60*MINUTE
+#define DAY 24*HOUR
+#define YEAR 365*DAY
+time_t Mktime(struct tm *t)
+{
+ struct tm *u;
+ time_t epoch = 0;
+ int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ y, m, i;
+
+ if(t->tm_year < 70)
+ return((time_t)-1);
+
+ epoch = (t->tm_year - 70) * YEAR +
+ (t->tm_year / 4 - 70 / 4 - t->tm_year / 100) * DAY;
+
+ y = t->tm_year;
+ m = 0;
+
+ for(i = 0; i < t->tm_mon; i++) {
+ epoch += mon [m] * DAY;
+ if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+ epoch += DAY;
+
+ if(++m > 11) {
+ m = 0;
+ y++;
+ }
+ }
+
+ epoch += (t->tm_mday - 1) * DAY;
+ epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
+
+ if((u = localtime(&epoch)) != NULL) {
+ t->tm_sec = u->tm_sec;
+ t->tm_min = u->tm_min;
+ t->tm_hour = u->tm_hour;
+ t->tm_mday = u->tm_mday;
+ t->tm_mon = u->tm_mon;
+ t->tm_year = u->tm_year;
+ t->tm_wday = u->tm_wday;
+ t->tm_yday = u->tm_yday;
+ t->tm_isdst = u->tm_isdst;
+#ifndef NO_TM_NAME
+ memcpy(t->tm_name, u->tm_name, LTZNMAX);
+#endif
+ }
+
+ return(epoch);
+}
+#endif /* REPLACE_MKTIME */
+
+
+
+#ifdef REPLACE_RENAME
+/* Rename a file. (from libiberty in GNU binutils) */
+int
+rename (zfrom, zto)
+ const char *zfrom;
+ const char *zto;
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
+#endif
+
+
+#ifdef REPLACE_INNETGR
+/*
+ * Search for a match in a netgroup. This replaces it on broken systems.
+ */
+int InNetGr(group, host, user, dom)
+ char *group, *host, *user, *dom;
+{
+ char *hst, *usr, *dm;
+
+ setnetgrent(group);
+ while (getnetgrent(&hst, &usr, &dm))
+ if (((host == 0) || (hst == 0) || !strcmp(host, hst)) &&
+ ((user == 0) || (usr == 0) || !strcmp(user, usr)) &&
+ ((dom == 0) || (dm == 0) || !strcmp(dom, dm))) {
+ endnetgrent();
+ return (1);
+ }
+ endnetgrent();
+ return (0);
+}
+#endif
+
+
+#if WRAP_MEMCPY
+#undef memcpy
+/*******************************************************************
+a wrapper around memcpy for diagnostic purposes
+********************************************************************/
+void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line)
+{
+ if (l>64 && (((int)d)%4) != (((int)s)%4))
+ DEBUG(4,("Misaligned memcpy(0x%X,0x%X,%d) at %s(%d)\n",d,s,l,fname,line));
+#ifdef xx_old_memcpy
+ return(xx_old_memcpy(d,s,l));
+#else
+ return(memcpy(d,s,l));
+#endif
+}
+#define memcpy(d,s,l) memcpy_wrapped(d,s,l,__FILE__,__LINE__)
+#endif
+
+
+