#
# Patch given file with DATA hunks and print to STDOUT.
#
# This patch:
#   * Fixes missing ifreq.ifr_hwaddr on at least some versions of
#       Solaris.
#       osname=solaris, osvers=2.11, archname=i86pc-solaris-64
#       uname='sunos ouzel 5.11 omnios-r151034-0d278a0cc5 i86pc i386 i86pc '
#   * Explicitly casts some places for g++.
#   * Include Windows.h if exists, and stdint.h and typedef mode_t.
#   * Include gettimeofday() if Windows.h exists.
#   * Add cast to silence warning.
#   * Define getpid() for native Win32.
#   * Includes for native Win32.
#   * Stops reseeding RNG after first pass on Win32.
#   * Adds comments re thread safety.
#   * Add simple srand()/rand() replacement.
#   * Roll adjustment overflow to clock_seq.
#   * Make get_clock() thread locals into global statics.
#   * Handle missing Win32 getuid().
#
use strict;
use warnings;
use Text::Patch 'patch';

my $in = $ARGV[0];

my ($txt, $patch);
{
    local $/;
    open my $fh, '<', $in or die "open: $in: $!";
    $txt   = <$fh>;
    $patch = <DATA>;
}

#print $txt,"\n";
#exit;

my $out = patch( $txt, $patch, STYLE => 'Unified' );

print $out;
exit 0;

__END__
--- usrcP/uuid/gen_uuid.c	Tue Jan  2 14:54:10 2024
+++ ulib/uuid/gen_uuid.c	Tue Jan  2 17:24:50 2024
@@ -40,6 +40,7 @@
 #define _DEFAULT_SOURCE	  /* since glibc 2.20 _SVID_SOURCE is deprecated */
 
 #include "config.h"
+#include <uuid/uuid_types.h>
 
 #include <stdio.h>
 #ifdef HAVE_UNISTD_H
@@ -93,12 +94,38 @@
 #include <sys/resource.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#include <Windows.h>
+#endif
+
+#ifdef USE_WIN32_NATIVE
+#include <io.h>
+#include <stdint.h>
+#include <process.h>
+#define getpid() _getpid()
+#define ftruncate(a,b) _chsize(a,b)
+typedef myuint32_t mode_t;
+#endif
+
 #include "uuidP.h"
 #include "uuidd.h"
 
 #ifdef HAVE_SRANDOM
 #define srand(x) 	srandom(x)
 #define rand() 		random()
+#else
+static int rand_state = 0;
+static void mysrand(int seed) {
+  rand_state = seed;
+}
+static int myrand(void) {
+  int const a = 1103515245;
+  int const c = 12345;
+  rand_state = a * rand_state + c;
+  return (rand_state >> 16) & 0x7FFF;
+}
+#define srand(x) mysrand(x)
+#define rand()   myrand()
 #endif
 
 #ifdef TLS
@@ -112,9 +139,42 @@
 THREAD_LOCAL unsigned short jrand_seed[3];
 #endif
 
-static int myget_random_fd(void)
+#ifdef USE_WIN32_NATIVE
+int gettimeofday(struct timeval * tp, struct timezone * tzp)
 {
+    // Note: SYSTEMTIME has 1ms resolution.
+    //       FILETIME has 100nsec resolution.
+    //       struct timeval has 1usec resolution.
+    //       struct timespec has 1nsec resolution.
+    //
+    // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
+    // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
+    // until 00:00:00 January 1, 1970 
+    //
+    static const myuint64_t EPOCH = ((myuint64_t) 116444736000000000ULL);
+
+    //SYSTEMTIME  system_time;
+    FILETIME    file_time;
+    myuint64_t  time;
+
+    //GetSystemTime( &system_time );
+    //SystemTimeToFileTime( &system_time, &file_time );
+    GetSystemTimeAsFileTime( &file_time );
+    time =  ((myuint64_t)file_time.dwLowDateTime )      ;
+    time += ((myuint64_t)file_time.dwHighDateTime) << 32;
+
+    tp->tv_sec  = (long) ((time - EPOCH) / 10000000L);
+    //tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
+    tp->tv_usec = (long) (((time - EPOCH) % 10000000L) / 10);
+    return 0;
+}
+#endif
+
+static int myget_random_fd()
+{
 	struct timeval	tv;
+  /* This static is problematic if
+	   unserialized access permitted. (JRM) */
 	static int	fd = -2;
 	int		i;
 
@@ -129,18 +189,25 @@
 			if (i >= 0)
 				fcntl(fd, F_SETFD, i | FD_CLOEXEC);
 		}
-#endif
 		srand(((unsigned)getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
+#else
+		fd = -1;
+		/* No easy substitute for getuid(). (JRM) */
+		/* Note: PerlProc_getuid() always returns 0 on Win32. (JRM) */
+		srand(((unsigned)getpid() << 16) ^ 0xdeadbeef ^ tv.tv_sec ^ tv.tv_usec);
+#endif
 #ifdef DO_JRAND_MIX
 		jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF);
 		jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF);
 		jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16;
 #endif
 	}
+
 	/* Crank the random number generator a few times */
 	gettimeofday(&tv, 0);
 	for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
 		rand();
+
 	return fd;
 }
 
@@ -153,7 +220,7 @@
 {
 	int i, n = nbytes, fd;
 	int lose_counter = 0;
-	unsigned char *cp = buf;
+	unsigned char *cp = (unsigned char*)buf;
 
 #ifdef HAVE_GETRANDOM
 	i = getrandom(buf, nbytes, 0);
@@ -184,7 +251,7 @@
 	 * We do this all the time, but this is the only source of
 	 * randomness if /dev/random/urandom is out to lunch.
 	 */
-	for (cp = buf, i = 0; i < nbytes; i++)
+	for (cp = (unsigned char*)buf, i = 0; i < nbytes; i++)
 		*cp++ ^= (rand() >> 7) & 0xFF;
 #ifdef DO_JRAND_MIX
 	{
@@ -192,7 +259,7 @@
 
 		memcpy(tmp_seed, jrand_seed, sizeof(tmp_seed));
 		jrand_seed[2] = jrand_seed[2] ^ syscall(__NR_gettid);
-		for (cp = buf, i = 0; i < nbytes; i++)
+		for (cp = (unsigned char*)buf, i = 0; i < nbytes; i++)
 			*cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF;
 		memcpy(jrand_seed, tmp_seed,
 		       sizeof(jrand_seed) - sizeof(unsigned short));
@@ -254,11 +321,17 @@
 	for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
 		ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
 		strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
-#ifdef SIOCGIFHWADDR
+#if defined(SIOCGIFHWADDR) && ( defined(ifr_hwaddr) || defined(ifr_addr) )
 		if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
 			continue;
+#ifdef ifr_hwaddr
 		a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
 #else
+#ifdef ifr_addr
+		a = (unsigned char *) &ifr.ifr_addr.sa_data;
+#endif /* ifr_addr */
+#endif /* ifr_hwaddr */
+#else
 #ifdef SIOCGENADDR
 		if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
 			continue;
@@ -298,11 +371,14 @@
 static int myget_clock(myuint32_t *clock_high, myuint32_t *clock_low,
 		     myuint16_t *ret_clock_seq, int *num)
 {
-	THREAD_LOCAL int		adjustment = 0;
-	THREAD_LOCAL struct timeval	last = {0, 0};
-	THREAD_LOCAL int		state_fd = -2;
-	THREAD_LOCAL FILE		*state_f;
-	THREAD_LOCAL myuint16_t		clock_seq;
+  /* Abandoned THREAD_LOCAL on all of these. It caused threads to
+     appear to be independent generators. We are serialized at
+     library entrance anyway. (JRM) */
+	static int		adjustment = 0;
+	static struct timeval	last = {0, 0};
+	static int		state_fd = -2;
+	static FILE		*state_f;
+	static myuint16_t		clock_seq;
 	struct timeval 			tv;
 #ifndef _WIN32
 	struct flock			fl;
@@ -340,6 +416,9 @@
 			break;
 		}
 	}
+#else
+  if (state_fd >= 0)
+    rewind(state_f);
 #endif
 	if (state_fd >= 0) {
 		unsigned int cl;
@@ -362,23 +441,27 @@
 		last.tv_sec--;
 	}
 
-try_again:
-	gettimeofday(&tv, 0);
-	if ((tv.tv_sec < last.tv_sec) ||
-	    ((tv.tv_sec == last.tv_sec) &&
-	     (tv.tv_usec < last.tv_usec))) {
-		clock_seq = (clock_seq+1) & 0x3FFF;
-		adjustment = 0;
-		last = tv;
-	} else if ((tv.tv_sec == last.tv_sec) &&
-	    (tv.tv_usec == last.tv_usec)) {
-		if (adjustment >= MAX_ADJUSTMENT)
-			goto try_again;
-		adjustment++;
-	} else {
-		adjustment = 0;
-		last = tv;
-	}
+  /* Now rolling adjustment overflows into clock_seq
+     instead of trying again. (JRM) */
+  gettimeofday(&tv, 0);
+  if ((tv.tv_sec < last.tv_sec) || ((tv.tv_sec == last.tv_sec) && (tv.tv_usec < last.tv_usec))) {
+    clock_seq = (clock_seq+1) & 0x3FFF;
+    adjustment = 0;
+    last = tv;
+  }
+  else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec)) {
+    if (adjustment >= MAX_ADJUSTMENT) {
+      clock_seq = (clock_seq+1) & 0x3FFF;
+      adjustment = 0;
+    }
+    else {
+      adjustment++;
+    }
+  }
+  else {
+    adjustment = 0;
+    last = tv;
+  }
 
 	clock_reg = tv.tv_usec*10 + adjustment;
 	clock_reg += ((myuint64_t) tv.tv_sec)*10000000;
@@ -413,8 +496,9 @@
 #endif
 	}
 
+
 	*clock_high = clock_reg >> 32;
-	*clock_low = clock_reg;
+	*clock_low = (myuint32_t)clock_reg;
 	*ret_clock_seq = clock_seq;
 	return 0;
 }
@@ -494,6 +578,8 @@
 	struct sockaddr_un srv_addr;
 	struct stat st;
 	pid_t pid;
+	/* These statics are not audited since
+	   we dont build uuidd anyway. (JRM) */
 	static const char *uuidd_path = UUIDD_PATH;
 	static int access_ret = -2;
 	static int start_attempts = 0;
@@ -566,6 +652,10 @@
 
 void myuuid__generate_time(myuuid_t out, int *num)
 {
+	/* Another race. Worst case, if node_id cannot be found, threads may
+	   have different initial random node data. Once all race participants
+	   complete the course, all should be same. Only relevant in an
+	   initial thundering herd scenario. (JRM) */
 	static unsigned char node_id[6];
 	static int has_init = 0;
 	struct myuuid uu;
@@ -593,6 +683,7 @@
 
 void myuuid_generate_time(myuuid_t out)
 {
+#ifdef USE_UUIDD
 #ifdef TLS
 	THREAD_LOCAL int		num = 0;
 	THREAD_LOCAL struct myuuid	uu;
@@ -629,7 +720,8 @@
 #else
 	if (myget_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0)
 		return;
-#endif
+#endif /* TLS */
+#endif /* USE_UUIDD */
 
 	myuuid__generate_time(out, 0);
 }

