+# ifdef CYGWIN
+# ifdef WIN32_FILENAMES
+# define ABS_LENGTH(name) (win32_abs_start (name))
+static int win32_abs_start (const char * name);
+# else
+# define ABS_LENGTH(name) (IS_DIRECTORY_SEP (*name) ? \
+ (IS_DIRECTORY_SEP (name[1]) ? 2 : 1) : 0)
+# endif
+# define system_readlink cygwin_readlink
+# else
+# define ABS_LENGTH(name) (IS_DIRECTORY_SEP (*name) ? 1 : 0)
+# define system_readlink readlink
+# endif /* CYGWIN */
+#endif /* WIN32_NATIVE */
+
+#if defined (WIN32_NATIVE) || defined (CYGWIN)
+#include "syswindows.h"
+/* Emulate readlink on win32 - finds real name (i.e. correct case) of
+ a file. UNC servers and shares are lower-cased. Directories must be
+ given without trailing '/'. One day, this could read Win2K's
+ reparse points. */
+static int
+win32_readlink (const char * name, char * buf, int size)
+{
+ WIN32_FIND_DATA find_data;
+ HANDLE dir_handle = NULL;
+ int len = 0;
+ int err = 0;
+ const char* lastname;
+ int count = 0;
+ const char* tmp;
+ char* res = NULL;
+
+ assert (*name);
+
+ /* Sort of check we have a valid filename. */
+ /* #### can we have escaped shell operators in a Windows filename? */
+ if (strpbrk (name, "|<>\"") || strlen (name) >= MAX_PATH)
+ {
+ errno = EIO;
+ return -1;
+ }
+ /* #### can we have escaped wildcards in a Windows filename? */
+ else if (strpbrk (name, "*?"))
+ {
+ errno = EINVAL; /* this valid path can't be a symlink */
+ return -1;
+ }
+
+ /* Find start of filename */
+ lastname = name + strlen (name);
+ while (lastname > name && !IS_DIRECTORY_SEP (lastname[-1]))
+ --lastname;
+
+ /* Count slashes in unc path */
+ if (ABS_LENGTH (name) == 2)
+ for (tmp = name; *tmp; tmp++)
+ if (IS_DIRECTORY_SEP (*tmp))
+ count++;
+
+ if (count >= 2 && count < 4)
+ {
+ /* UNC server or share name: just copy lowercased name. */
+ res = find_data.cFileName;
+ for (tmp = lastname; *tmp; tmp++)
+ *res++ = tolower (*tmp);
+ *res = '\0';
+ }
+ else
+ dir_handle = FindFirstFile (name, &find_data);
+
+ if (res || dir_handle != INVALID_HANDLE_VALUE)
+ {
+ if ((len = strlen (find_data.cFileName)) < size)
+ {
+ if (strcmp (lastname, find_data.cFileName) == 0)
+ /* Signal that the name is already OK. */
+ err = EINVAL;
+ else
+ memcpy (buf, find_data.cFileName, len + 1);
+ }
+ else
+ err = ENAMETOOLONG;
+ if (!res) FindClose (dir_handle);
+ }
+ else
+ err = ENOENT;
+
+ errno = err;
+ return err ? -1 : len;
+}
+#endif /* WIN32_NATIVE || CYGWIN */
+
+#ifdef CYGWIN
+/* Call readlink and try to find out the correct case for the file. */
+static int
+cygwin_readlink (const char * name, char * buf, int size)
+{
+ int n = readlink (name, buf, size);
+ if (n < 0 && errno == EINVAL)
+ {
+ /* The file may exist, but isn't a symlink. Try to find the
+ right name. */
+ char* tmp = alloca (cygwin_posix_to_win32_path_list_buf_size (name));
+ cygwin_posix_to_win32_path_list (name, tmp);
+ n = win32_readlink (tmp, buf, size);
+ }
+ return n;
+}
+#endif /* CYGWIN */
+
+#ifdef WIN32_FILENAMES
+#ifndef ELOOP
+#define ELOOP 10062 /* = WSAELOOP in winsock.h */