]> sourceware.org Git - newlib-cygwin.git/commitdiff
Add miscfuncs.h to files as needed throughout.
authorChristopher Faylor <me@cgf.cx>
Mon, 7 Apr 2008 16:15:45 +0000 (16:15 +0000)
committerChristopher Faylor <me@cgf.cx>
Mon, 7 Apr 2008 16:15:45 +0000 (16:15 +0000)
* mount.cc: New file.
* path.cc: Move mount-specific stuff into mount.cc.  Move common stuff into
miscfuncs.cc.  Remove unneeded includes.
* miscfuncs.cc: Move some common path functions here.
* miscfuncs.h: New file.
* winsup.h: Move miscelleneous functions to miscfuncs.h.
* dcrt0.cc: Remove unneeded includes.
* Makefile.in (DLL_OFILES): Add mount.o.
* include/cygwin/config.h: Fix a minor typo.

26 files changed:
winsup/cygwin/ChangeLog
winsup/cygwin/Makefile.in
winsup/cygwin/autoload.cc
winsup/cygwin/cygthread.cc
winsup/cygwin/dcrt0.cc
winsup/cygwin/environ.h
winsup/cygwin/exceptions.cc
winsup/cygwin/fhandler_console.cc
winsup/cygwin/fhandler_fifo.cc
winsup/cygwin/fhandler_proc.cc
winsup/cygwin/include/cygwin/config.h
winsup/cygwin/miscfuncs.cc
winsup/cygwin/mmap.cc
winsup/cygwin/mount.cc [new file with mode: 0644]
winsup/cygwin/net.cc
winsup/cygwin/path.cc
winsup/cygwin/path.h
winsup/cygwin/pinfo.cc
winsup/cygwin/sched.cc
winsup/cygwin/shared.cc
winsup/cygwin/sigproc.cc
winsup/cygwin/sync.cc
winsup/cygwin/syscalls.cc
winsup/cygwin/thread.cc
winsup/cygwin/tty.cc
winsup/cygwin/winsup.h

index abbf9da829af78970a62cbd13b4f0da50dede7f5..51e038aefdc8acae79253ba17cef4e504c915fdc 100644 (file)
@@ -1,3 +1,17 @@
+2008-04-07  Christopher Faylor  <me+cygwin@cgf.cx>
+
+       Add miscfuncs.h to files as needed throughout.
+       * mount.cc: New file.
+       * path.cc: Move mount-specific stuff into mount.cc.  Move common stuff
+       into miscfuncs.cc.  Remove unneeded includes.
+       * miscfuncs.cc: Move some common path functions here.
+       * miscfuncs.h: New file.
+       * winsup.h: Move miscelleneous functions to miscfuncs.h.
+       * dcrt0.cc: Remove unneeded includes.
+       * Makefile.in (DLL_OFILES): Add mount.o.
+
+       * include/cygwin/config.h: Fix a minor typo.
+
 2008-04-07  Corinna Vinschen  <corinna@vinschen.de>
 
        * postinstall: Set IFS to LF only.  Change while loop in subshell to 
index 1ecd851ae6bfcf77f02d4bee73285bf1a305cb82..77178d8581220226fd7db9b61bac2c292ab390ed 100644 (file)
@@ -136,8 +136,8 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \
        fhandler_termios.o fhandler_tty.o fhandler_virtual.o fhandler_windows.o \
        fhandler_zero.o flock.o fnmatch.o fork.o fts.o ftw.o getopt.o glob.o \
        grp.o heap.o hookapi.o inet_addr.o inet_network.o init.o ioctl.o ipc.o \
-       localtime.o lsearch.o malloc_wrapper.o minires-os-if.o \
-       minires.o miscfuncs.o mktemp.o mmap.o msg.o net.o netdb.o nftw.o ntea.o \
+       localtime.o lsearch.o malloc_wrapper.o minires-os-if.o minires.o \
+       miscfuncs.o mktemp.o mmap.o msg.o mount.o net.o netdb.o nftw.o ntea.o \
        passwd.o path.o pinfo.o pipe.o poll.o posix_ipc.o pthread.o random.o \
        regcomp.o regerror.o regexec.o regfree.o registry.o resource.o rexec.o \
        rcmd.o scandir.o sched.o sec_acl.o sec_auth.o sec_helper.o security.o \
index 621ecbd6c50d87a86070dc60f85622cde6cbf677..844d7b853008516fc7888282796d47961138018e 100644 (file)
@@ -9,9 +9,12 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #define USE_SYS_TYPES_FD_SET
 #include <winsock2.h>
 
+bool NO_COPY wsock_started;
+
 /* Macro for defining "auto-load" functions.
  * Note that this is self-modifying code *gasp*.
  * The first invocation of a routine will trigger the loading of
@@ -243,7 +246,6 @@ std_dll_init ()
 }
 
 /* Initialization function for winsock stuff. */
-bool NO_COPY wsock_started = 0;
 WSADATA NO_COPY wsadata;
 __attribute__ ((used, noinline, regparm(1))) static long long
 wsock_init ()
index b9e075a162462b852f41428091e5a6a6d916d1f6..104908289085e7f9c829e0e30ed3c4d69d3b56ae 100644 (file)
@@ -7,6 +7,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <windows.h>
 #include <stdlib.h>
 #include "exceptions.h"
index 5464cce57c2ef11a39a55161a0090b0226ea1cef..468d0ab39e79814cbaeea8e113770cf002e82be8 100644 (file)
@@ -10,23 +10,16 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <unistd.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include "glob.h"
-#include "exceptions.h"
 #include <ctype.h>
-#include <limits.h>
-#include <winnls.h>
-#include <wingdi.h>
-#include <winuser.h>
 #include "sigproc.h"
 #include "pinfo.h"
 #include "cygerrno.h"
 #define NEED_VFORK
 #include "perprocess.h"
-#include "security.h"
 #include "path.h"
 #include "fhandler.h"
 #include "dtable.h"
@@ -36,9 +29,7 @@ details. */
 #include "shared_info.h"
 #include "cygwin_version.h"
 #include "dll_init.h"
-#include "sync.h"
 #include "heap.h"
-#include "environ.h"
 #include "tls_pbuf.h"
 
 #define MAX_AT_FILE_LEVEL 10
@@ -116,9 +107,9 @@ extern "C"
 #ifdef DEBUGGING
   int pinger;
 #endif
-  int NO_COPY __api_fatal_exit_val = 1;
 };
 
+int NO_COPY __api_fatal_exit_val = 1;
 char *old_title;
 char title_buf[TITLESIZE + 1];
 
index 02407fe658d6f824906df35c471af9a70976a802..78305a8b0f121d551fdfb1fb13592f60cc1f2f70 100644 (file)
@@ -40,7 +40,7 @@ char * __stdcall getwinenveq (const char *name, size_t len, int)
   __attribute__ ((regparm (3)));
 
 void __stdcall update_envptrs ();
-extern char **__cygwin_environ, ***main_environ;
+extern "C" char **__cygwin_environ, ***main_environ;
 extern "C" char __stdcall **cur_environ ();
 char ** __stdcall build_env (const char * const *envp, PWCHAR &envblock,
                             int &envc, bool need_envblock)
index b461e77bab5d3e65c8b08508f1fa40aa258fd8bf..af28ef060577ccd9a43310b3ce665c6962b93af2 100644 (file)
@@ -10,6 +10,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <wingdi.h>
 #include <winuser.h>
 #include <imagehlp.h>
index 7f6909e9d6eb219b8acb05ce1611e96809087cf4..02cbb6ecd63b7046b13fa167cf1c32bb298327b8 100644 (file)
@@ -10,6 +10,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <sys/termios.h>
 #include <stdio.h>
 #include <stdlib.h>
index e27954c45fa2ad8c92971d4f0f876d65d0f16f58..1f5a82b1814bf897378d3cd9b231041b47f5abff 100644 (file)
@@ -9,6 +9,7 @@
    details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
index 482d77849c5490d19d6d887010d7209b46edd2b1..36452c370be02075ca48b624aa2412ec4529b10c 100644 (file)
@@ -9,6 +9,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/cygwin.h>
index dafd35125bf2b703f56420ad55cc2c79e6d59f3c..11f90ada2c2666cdc3240d99aed9665e515048f9 100644 (file)
@@ -1,7 +1,7 @@
 /* cygwin/config.h header file for Cygwin.
 
    This wraps Cygwin configuration setting which were in newlib's
-   sys/config.h before.  THis way we can manaage our configuration
+   sys/config.h before.  This way we can manaage our configuration
    setting without bothering newlib.
 
    Copyright 2003 Red Hat, Inc.
index dc09c1f7ee7e9e94cc60e0adfe6c0df47ce66156..aff357d1ae93ca0a808c76859a631c4a7b1b4950 100644 (file)
@@ -10,8 +10,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
-#include "cygerrno.h"
-#include <sys/errno.h>
+#include "miscfuncs.h"
 #include <sys/uio.h>
 #include <assert.h>
 #include <alloca.h>
@@ -20,7 +19,6 @@ details. */
 #include <wingdi.h>
 #include <winuser.h>
 #include <winnls.h>
-#include "cygthread.h"
 #include "cygtls.h"
 #include "ntdll.h"
 
@@ -500,3 +498,51 @@ create_pipe (PHANDLE hr,PHANDLE hw, LPSECURITY_ATTRIBUTES sa, DWORD n)
       break;
   return false;
 }
+
+/* backslashify: Convert all forward slashes in src path to back slashes
+   in dst path.  Add a trailing slash to dst when trailing_slash_p arg
+   is set to 1. */
+
+void
+backslashify (const char *src, char *dst, bool trailing_slash_p)
+{
+  const char *start = src;
+
+  while (*src)
+    {
+      if (*src == '/')
+       *dst++ = '\\';
+      else
+       *dst++ = *src;
+      ++src;
+    }
+  if (trailing_slash_p
+      && src > start
+      && !isdirsep (src[-1]))
+    *dst++ = '\\';
+  *dst++ = 0;
+}
+
+/* slashify: Convert all back slashes in src path to forward slashes
+   in dst path.  Add a trailing slash to dst when trailing_slash_p arg
+   is set to 1. */
+
+void
+slashify (const char *src, char *dst, bool trailing_slash_p)
+{
+  const char *start = src;
+
+  while (*src)
+    {
+      if (*src == '\\')
+       *dst++ = '/';
+      else
+       *dst++ = *src;
+      ++src;
+    }
+  if (trailing_slash_p
+      && src > start
+      && !isdirsep (src[-1]))
+    *dst++ = '/';
+  *dst++ = 0;
+}
index 375327d19bf2e780137877b189b63bf3a74f86ec..db809202647259eae81737b4f0f78026abbab24a 100644 (file)
@@ -10,6 +10,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <unistd.h>
 #include <stdlib.h>
 #include <stddef.h>
diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc
new file mode 100644 (file)
index 0000000..ba6f42b
--- /dev/null
@@ -0,0 +1,1610 @@
+/* path.cc: path support.
+
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006, 2007, 2008 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include "miscfuncs.h"
+#include <mntent.h>
+#include <ctype.h>
+#include <wingdi.h>
+#include <winuser.h>
+#include <winnetwk.h>
+#include <shlobj.h>
+#include <cygwin/version.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "shared_info.h"
+#include "registry.h"
+#include "cygtls.h"
+#include "tls_pbuf.h"
+#include <ntdll.h>
+#include <wchar.h>
+
+/* Determine if path prefix matches current cygdrive */
+#define iscygdrive(path) \
+  (path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len))
+
+#define iscygdrive_device(path) \
+  (isalpha (path[mount_table->cygdrive_len]) && \
+   (path[mount_table->cygdrive_len + 1] == '/' || \
+    !path[mount_table->cygdrive_len + 1]))
+
+#define isproc(path) \
+  (path_prefix_p (proc, (path), proc_len))
+
+/* is_unc_share: Return non-zero if PATH begins with //UNC/SHARE */
+
+static inline bool __stdcall
+is_unc_share (const char *path)
+{
+  const char *p;
+  return (isdirsep (path[0])
+        && isdirsep (path[1])
+        && (isalnum (path[2]) || path[2] == '.')
+        && ((p = strpbrk (path + 3, "\\/")) != NULL)
+        && isalnum (p[1]));
+}
+
+/* Return true if src_path is a valid, internally supported device name.
+   In that case, win32_path gets the corresponding NT device name and
+   dev is appropriately filled with device information. */
+
+static bool
+win32_device_name (const char *src_path, char *win32_path, device& dev)
+{
+  dev.parse (src_path);
+  if (dev == FH_FS || dev == FH_DEV)
+    return false;
+  strcpy (win32_path, dev.native);
+  return true;
+}
+
+/* init: Initialize the mount table.  */
+
+void
+mount_info::init ()
+{
+  nmounts = 0;
+
+  if (from_fstab (false) | from_fstab (true))  /* The single | is correct! */
+    return;
+
+  /* FIXME: Remove fetching from registry before releasing 1.7.0. */
+
+  /* Fetch the mount table and cygdrive-related information from
+     the registry.  */
+  system_printf ("Fallback to fetching mounts from registry");
+  from_registry ();
+}
+
+static void
+set_flags (unsigned *flags, unsigned val)
+{
+  *flags = val;
+  if (!(*flags & PATH_BINARY))
+    {
+      *flags |= PATH_TEXT;
+      debug_printf ("flags: text (%p)", *flags & (PATH_TEXT | PATH_BINARY));
+    }
+  else
+    {
+      *flags |= PATH_BINARY;
+      debug_printf ("flags: binary (%p)", *flags & (PATH_TEXT | PATH_BINARY));
+    }
+}
+
+static char dot_special_chars[] =
+    "."
+    "\001" "\002" "\003" "\004" "\005" "\006" "\007" "\010"
+    "\011" "\012" "\013" "\014" "\015" "\016" "\017" "\020"
+    "\021" "\022" "\023" "\024" "\025" "\026" "\027" "\030"
+    "\031" "\032" "\033" "\034" "\035" "\036" "\037" ":"
+    "\\"   "*"    "?"    "%"     "\""   "<"    ">"    "|"
+    "A"    "B"    "C"    "D"    "E"    "F"    "G"    "H"
+    "I"    "J"    "K"    "L"    "M"    "N"    "O"    "P"
+    "Q"    "R"    "S"    "T"    "U"    "V"    "W"    "X"
+    "Y"    "Z";
+static char *special_chars = dot_special_chars + 1;
+static char special_introducers[] =
+    "anpcl";
+
+static char
+special_char (const char *s, const char *valid_chars = special_chars)
+{
+  if (*s != '%' || strlen (s) < 3)
+    return 0;
+
+  char *p;
+  char hex[] = {s[1], s[2], '\0'};
+  unsigned char c = strtoul (hex, &p, 16);
+  p = strechr (valid_chars, c);
+  return *p;
+}
+
+/* Determines if name is "special".  Assumes that name is empty or "absolute" */
+static int
+special_name (const char *s, int inc = 1)
+{
+  if (!*s)
+    return false;
+
+  s += inc;
+
+  if (strcmp (s, ".") == 0 || strcmp (s, "..") == 0)
+    return false;
+
+  int n;
+  const char *p = NULL;
+  if (ascii_strncasematch (s, "conin$", n = 5)
+      || ascii_strncasematch (s, "conout$", n = 7)
+      || ascii_strncasematch (s, "nul", n = 3)
+      || ascii_strncasematch (s, "aux", 3)
+      || ascii_strncasematch (s, "prn", 3)
+      || ascii_strncasematch (s, "con", 3))
+    p = s + n;
+  else if (ascii_strncasematch (s, "com", 3)
+          || ascii_strncasematch (s, "lpt", 3))
+    strtoul (s + 3, (char **) &p, 10);
+  if (p && (*p == '\0' || *p == '.'))
+    return -1;
+
+  return (strchr (s, '\0')[-1] == '.')
+        || (strpbrk (s, special_chars) && !ascii_strncasematch (s, "%2f", 3));
+}
+
+bool
+fnunmunge (char *dst, const char *src)
+{
+  bool converted = false;
+  char c;
+
+  if ((c = special_char (src, special_introducers)))
+    {
+      __small_sprintf (dst, "%c%s", c, src + 3);
+      if (special_name (dst, 0))
+       {
+         *dst++ = c;
+         src += 3;
+       }
+    }
+
+  while (*src)
+    if (!(c = special_char (src, dot_special_chars)))
+      *dst++ = *src++;
+    else
+      {
+       converted = true;
+       *dst++ = c;
+       src += 3;
+      }
+
+  *dst = *src;
+  return converted;
+}
+
+static bool
+copy1 (char *&d, const char *&src, int& left)
+{
+  left--;
+  if (left || !*src)
+    *d++ = *src++;
+  else
+    return true;
+  return false;
+}
+
+static bool
+copyenc (char *&d, const char *&src, int& left)
+{
+  char buf[16];
+  int n = __small_sprintf (buf, "%%%02x", (unsigned char) *src++);
+  left -= n;
+  if (left <= 0)
+    return true;
+  strcpy (d, buf);
+  d += n;
+  return false;
+}
+
+int
+mount_item::fnmunge (char *dst, const char *src, int& left)
+{
+  int name_type;
+  if (!(name_type = special_name (src)))
+    {
+      if ((int) strlen (src) >= left)
+       return ENAMETOOLONG;
+      else
+       strcpy (dst, src);
+    }
+  else
+    {
+      char *d = dst;
+      if (copy1 (d, src, left))
+         return ENAMETOOLONG;
+      if (name_type < 0 && copyenc (d, src, left))
+       return ENAMETOOLONG;
+
+      while (*src)
+       if (!strchr (special_chars, *src) || (*src == '%' && !special_char (src)))
+         {
+           if (copy1 (d, src, left))
+             return ENAMETOOLONG;
+         }
+       else if (copyenc (d, src, left))
+         return ENAMETOOLONG;
+
+      char dot[] = ".";
+      const char *p = dot;
+      if (*--d != '.')
+       d++;
+      else if (copyenc (d, p, left))
+       return ENAMETOOLONG;
+
+      *d = *src;
+    }
+
+  backslashify (dst, dst, 0);
+  return 0;
+}
+
+int
+mount_item::build_win32 (char *dst, const char *src, unsigned *outflags, unsigned chroot_pathlen)
+{
+  int n, err = 0;
+  const char *real_native_path;
+  int real_posix_pathlen;
+  set_flags (outflags, (unsigned) flags);
+  if (!cygheap->root.exists () || posix_pathlen != 1 || posix_path[0] != '/')
+    {
+      n = native_pathlen;
+      real_native_path = native_path;
+      real_posix_pathlen = chroot_pathlen ?: posix_pathlen;
+    }
+  else
+    {
+      n = cygheap->root.native_length ();
+      real_native_path = cygheap->root.native_path ();
+      real_posix_pathlen = posix_pathlen;
+    }
+  memcpy (dst, real_native_path, n + 1);
+  const char *p = src + real_posix_pathlen;
+  if (*p == '/')
+    /* nothing */;
+  else if ((!(flags & MOUNT_ENC) && isdrive (dst) && !dst[2]) || *p)
+    dst[n++] = '\\';
+  //if (!*p || !(flags & MOUNT_ENC))
+    //{
+      if ((n + strlen (p)) >= NT_MAX_PATH)
+       err = ENAMETOOLONG;
+      else
+       backslashify (p, dst + n, 0);
+#if 0
+    }
+  else
+    {
+      int left = NT_MAX_PATH - n;
+      while (*p)
+       {
+         char slash = 0;
+         char *s = strchr (p + 1, '/');
+         if (s)
+           {
+             slash = *s;
+             *s = '\0';
+           }
+         err = fnmunge (dst += n, p, left);
+         if (!s || err)
+           break;
+         n = strlen (dst);
+         *s = slash;
+         p = s;
+       }
+    }
+#endif
+  return err;
+}
+
+/* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
+   the result in win32_path.
+
+   If win32_path != NULL, the relative path, if possible to keep, is
+   stored in win32_path.  If the relative path isn't possible to keep,
+   the full path is stored.
+
+   If full_win32_path != NULL, the full path is stored there.
+
+   The result is zero for success, or an errno value.
+
+   {,full_}win32_path must have sufficient space (i.e. NT_MAX_PATH bytes).  */
+
+int
+mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
+                               unsigned *flags)
+{
+  bool chroot_ok = !cygheap->root.exists ();
+  while (sys_mount_table_counter < cygwin_shared->sys_mount_table_counter)
+    {
+      int current = cygwin_shared->sys_mount_table_counter;
+      init ();
+      sys_mount_table_counter = current;
+    }
+  MALLOC_CHECK;
+
+  dev.devn = FH_FS;
+
+  *flags = 0;
+  debug_printf ("conv_to_win32_path (%s)", src_path);
+
+  int i, rc;
+  mount_item *mi = NULL;       /* initialized to avoid compiler warning */
+
+  /* The path is already normalized, without ../../ stuff, we need to have this
+     so that we can move from one mounted directory to another with relative
+     stuff.
+
+     eg mounting c:/foo /foo
+     d:/bar /bar
+
+     cd /bar
+     ls ../foo
+
+     should look in c:/foo, not d:/foo.
+
+     converting normalizex UNIX path to a DOS-style path, looking up the
+     appropriate drive in the mount table.  */
+
+  /* See if this is a cygwin "device" */
+  if (win32_device_name (src_path, dst, dev))
+    {
+      *flags = MOUNT_BINARY;   /* FIXME: Is this a sensible default for devices? */
+      rc = 0;
+      goto out_no_chroot_check;
+    }
+
+  MALLOC_CHECK;
+  /* If the path is on a network drive or a //./ resp.//?/ path prefix,
+     bypass the mount table.  If it's // or //MACHINE, use the netdrive
+     device. */
+  if (src_path[1] == '/')
+    {
+      if (!strchr (src_path + 2, '/'))
+       {
+         dev = *netdrive_dev;
+         set_flags (flags, PATH_BINARY);
+       }
+      backslashify (src_path, dst, 0);
+      /* Go through chroot check */
+      goto out;
+    }
+  if (isproc (src_path))
+    {
+      dev = *proc_dev;
+      dev.devn = fhandler_proc::get_proc_fhandler (src_path);
+      if (dev.devn == FH_BAD)
+       return ENOENT;
+      set_flags (flags, PATH_BINARY);
+      strcpy (dst, src_path);
+      goto out;
+    }
+  /* Check if the cygdrive prefix was specified.  If so, just strip
+     off the prefix and transform it into an MS-DOS path. */
+  else if (iscygdrive (src_path))
+    {
+      int n = mount_table->cygdrive_len - 1;
+      int unit;
+
+      if (!src_path[n])
+       {
+         unit = 0;
+         dst[0] = '\0';
+         if (mount_table->cygdrive_len > 1)
+           dev = *cygdrive_dev;
+       }
+      else if (cygdrive_win32_path (src_path, dst, unit))
+       {
+         set_flags (flags, (unsigned) cygdrive_flags);
+         goto out;
+       }
+      else if (mount_table->cygdrive_len > 1)
+       return ENOENT;
+    }
+
+  int chroot_pathlen;
+  chroot_pathlen = 0;
+  /* Check the mount table for prefix matches. */
+  for (i = 0; i < nmounts; i++)
+    {
+      const char *path;
+      int len;
+
+      mi = mount + posix_sorted[i];
+      if (!cygheap->root.exists ()
+         || (mi->posix_pathlen == 1 && mi->posix_path[0] == '/'))
+       {
+         path = mi->posix_path;
+         len = mi->posix_pathlen;
+       }
+      else if (cygheap->root.posix_ok (mi->posix_path))
+       {
+         path = cygheap->root.unchroot (mi->posix_path);
+         chroot_pathlen = len = strlen (path);
+       }
+      else
+       {
+         chroot_pathlen = 0;
+         continue;
+       }
+
+      if (path_prefix_p (path, src_path, len))
+       break;
+    }
+
+  if (i < nmounts)
+    {
+      int err = mi->build_win32 (dst, src_path, flags, chroot_pathlen);
+      if (err)
+       return err;
+      chroot_ok = true;
+    }
+  else
+    {
+      int offset = 0;
+      if (src_path[1] != '/' && src_path[1] != ':')
+       offset = cygheap->cwd.get_drive (dst);
+      backslashify (src_path, dst + offset, 0);
+    }
+ out:
+  MALLOC_CHECK;
+  if (chroot_ok || cygheap->root.ischroot_native (dst))
+    rc = 0;
+  else
+    {
+      debug_printf ("attempt to access outside of chroot '%s - %s'",
+                   cygheap->root.posix_path (), cygheap->root.native_path ());
+      rc = ENOENT;
+    }
+
+ out_no_chroot_check:
+  debug_printf ("src_path %s, dst %s, flags %p, rc %d", src_path, dst, *flags, rc);
+  return rc;
+}
+
+int
+mount_info::get_mounts_here (const char *parent_dir, int parent_dir_len,
+                            PUNICODE_STRING mount_points,
+                            PUNICODE_STRING cygd)
+{
+  int n_mounts = 0;
+
+  for (int i = 0; i < nmounts; i++)
+    {
+      mount_item *mi = mount + posix_sorted[i];
+      char *last_slash = strrchr (mi->posix_path, '/');
+      if (!last_slash)
+       continue;
+      if (last_slash == mi->posix_path)
+       {
+         if (parent_dir_len == 1 && mi->posix_pathlen > 1)
+           RtlCreateUnicodeStringFromAsciiz (&mount_points[n_mounts++],
+                                             last_slash + 1);
+       }
+      else if (parent_dir_len == last_slash - mi->posix_path
+              && strncasematch (parent_dir, mi->posix_path, parent_dir_len))
+       RtlCreateUnicodeStringFromAsciiz (&mount_points[n_mounts++],
+                                         last_slash + 1);
+    }
+  RtlCreateUnicodeStringFromAsciiz (cygd, cygdrive + 1);
+  cygd->Length -= 2;   // Strip trailing slash
+  return n_mounts;
+}
+
+/* cygdrive_posix_path: Build POSIX path used as the
+   mount point for cygdrives created when there is no other way to
+   obtain a POSIX path from a Win32 one. */
+
+void
+mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
+{
+  int len = cygdrive_len;
+
+  memcpy (dst, cygdrive, len + 1);
+
+  /* Now finish the path off with the drive letter to be used.
+     The cygdrive prefix always ends with a trailing slash so
+     the drive letter is added after the path. */
+  dst[len++] = cyg_tolower (src[0]);
+  if (!src[2] || (isdirsep (src[2]) && !src[3]))
+    dst[len++] = '\000';
+  else
+    {
+      int n;
+      dst[len++] = '/';
+      if (isdirsep (src[2]))
+       n = 3;
+      else
+       n = 2;
+      strcpy (dst + len, src + n);
+    }
+  slashify (dst, dst, trailing_slash_p);
+}
+
+int
+mount_info::cygdrive_win32_path (const char *src, char *dst, int& unit)
+{
+  int res;
+  const char *p = src + cygdrive_len;
+  if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
+    {
+      unit = -1; /* FIXME: should be zero, maybe? */
+      dst[0] = '\0';
+      res = 0;
+    }
+  else
+    {
+      dst[0] = cyg_tolower (*p);
+      dst[1] = ':';
+      strcpy (dst + 2, p + 1);
+      backslashify (dst, dst, !dst[2]);
+      unit = dst[0];
+      res = 1;
+    }
+  debug_printf ("src '%s', dst '%s'", src, dst);
+  return res;
+}
+
+/* conv_to_posix_path: Ensure src_path is a POSIX path.
+
+   The result is zero for success, or an errno value.
+   posix_path must have sufficient space (i.e. NT_MAX_PATH bytes).
+   If keep_rel_p is non-zero, relative paths stay that way.  */
+
+/* TODO: Change conv_to_posix_path to work with native paths. */
+
+/* src_path is a wide Win32 path. */
+int
+mount_info::conv_to_posix_path (PWCHAR src_path, char *posix_path,
+                               int keep_rel_p)
+{
+  bool changed = false;
+  if (!wcsncmp (src_path, L"\\\\?\\", 4))
+    {
+      src_path += 4;
+      if (!wcsncmp (src_path, L"UNC\\", 4))
+       {
+         src_path += 2;
+         src_path[0] = L'\\';
+         changed = true;
+       }
+    }
+  tmp_pathbuf tp;
+  char *buf = tp.c_get ();
+  sys_wcstombs (buf, NT_MAX_PATH, src_path);
+  int ret = conv_to_posix_path (buf, posix_path, keep_rel_p);
+  if (changed)
+    src_path[0] = L'C';
+  return ret;
+}
+
+int
+mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
+                               int keep_rel_p)
+{
+  int src_path_len = strlen (src_path);
+  int relative_path_p = !isabspath (src_path);
+  int trailing_slash_p;
+
+  if (src_path_len <= 1)
+    trailing_slash_p = 0;
+  else
+    {
+      const char *lastchar = src_path + src_path_len - 1;
+      trailing_slash_p = isdirsep (*lastchar) && lastchar[-1] != ':';
+    }
+
+  debug_printf ("conv_to_posix_path (%s, %s, %s)", src_path,
+               keep_rel_p ? "keep-rel" : "no-keep-rel",
+               trailing_slash_p ? "add-slash" : "no-add-slash");
+  MALLOC_CHECK;
+
+  if (src_path_len >= NT_MAX_PATH)
+    {
+      debug_printf ("ENAMETOOLONG");
+      return ENAMETOOLONG;
+    }
+
+  /* FIXME: For now, if the path is relative and it's supposed to stay
+     that way, skip mount table processing. */
+
+  if (keep_rel_p && relative_path_p)
+    {
+      slashify (src_path, posix_path, 0);
+      debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
+      return 0;
+    }
+
+  tmp_pathbuf tp;
+  char *pathbuf = tp.c_get ();
+  char *tail;
+  int rc = normalize_win32_path (src_path, pathbuf, tail);
+  if (rc != 0)
+    {
+      debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
+      return rc;
+    }
+
+  int pathbuflen = tail - pathbuf;
+  for (int i = 0; i < nmounts; ++i)
+    {
+      mount_item &mi = mount[native_sorted[i]];
+      if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
+       continue;
+
+      if (cygheap->root.exists () && !cygheap->root.posix_ok (mi.posix_path))
+       continue;
+
+      /* SRC_PATH is in the mount table. */
+      int nextchar;
+      const char *p = pathbuf + mi.native_pathlen;
+
+      if (!*p || !p[1])
+       nextchar = 0;
+      else if (isdirsep (*p))
+       nextchar = -1;
+      else
+       nextchar = 1;
+
+      int addslash = nextchar > 0 ? 1 : 0;
+      if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= NT_MAX_PATH)
+       return ENAMETOOLONG;
+      strcpy (posix_path, mi.posix_path);
+      if (addslash)
+       strcat (posix_path, "/");
+      if (nextchar)
+       slashify (p,
+                 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
+                 trailing_slash_p);
+
+      if (cygheap->root.exists ())
+       {
+         const char *p = cygheap->root.unchroot (posix_path);
+         memmove (posix_path, p, strlen (p) + 1);
+       }
+#if 0
+      if (mi.flags & MOUNT_ENC)
+       {
+         char *tmpbuf = tp.c_get ();
+         if (fnunmunge (tmpbuf, posix_path))
+           strcpy (posix_path, tmpbuf);
+       }
+#endif
+      goto out;
+    }
+
+  if (!cygheap->root.exists ())
+    /* nothing */;
+  else if (!cygheap->root.ischroot_native (pathbuf))
+    return ENOENT;
+  else
+    {
+      const char *p = pathbuf + cygheap->root.native_length ();
+      if (*p)
+       slashify (p, posix_path, trailing_slash_p);
+      else
+       {
+         posix_path[0] = '/';
+         posix_path[1] = '\0';
+       }
+      goto out;
+    }
+
+  /* Not in the database.  This should [theoretically] only happen if either
+     the path begins with //, or / isn't mounted, or the path has a drive
+     letter not covered by the mount table.  If it's a relative path then the
+     caller must want an absolute path (otherwise we would have returned
+     above).  So we always return an absolute path at this point. */
+  if (isdrive (pathbuf))
+    cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p);
+  else
+    {
+      /* The use of src_path and not pathbuf here is intentional.
+        We couldn't translate the path, so just ensure no \'s are present. */
+      slashify (src_path, posix_path, trailing_slash_p);
+    }
+
+out:
+  debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
+  MALLOC_CHECK;
+  return 0;
+}
+
+/* Return flags associated with a mount point given the win32 path. */
+
+unsigned
+mount_info::set_flags_from_win32_path (const char *p)
+{
+  for (int i = 0; i < nmounts; i++)
+    {
+      mount_item &mi = mount[native_sorted[i]];
+      if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
+       return mi.flags;
+    }
+  return PATH_BINARY;
+}
+
+inline char *
+skip_ws (char *in)
+{
+  while (*in == ' ' || *in == '\t')
+    ++in;
+  return in;
+}
+
+inline char *
+find_ws (char *in)
+{
+  while (*in && *in != ' ' && *in != '\t')
+    ++in;
+  return in;
+}
+
+inline char *
+conv_fstab_spaces (char *field)
+{
+  register char *sp = field;
+  while (sp = strstr (sp, "\\040"))
+    {
+      *sp++ = ' ';
+      memmove (sp, sp + 3, strlen (sp + 3) + 1);
+    }
+  return field;
+}
+
+struct opt
+{   
+  const char *name;
+  unsigned val;
+  bool clear;
+} oopts[] =
+{
+  {"user", MOUNT_SYSTEM, 1},
+  {"nouser", MOUNT_SYSTEM, 0},
+  {"binary", MOUNT_BINARY, 0},
+  {"text", MOUNT_BINARY, 1},
+  {"exec", MOUNT_EXEC, 0},
+  {"notexec", MOUNT_NOTEXEC, 0},
+  {"cygexec", MOUNT_CYGWIN_EXEC, 0},
+  {"nosuid", 0, 0},
+  {"managed", MOUNT_ENC, 0}
+};
+
+static bool
+read_flags (char *options, unsigned &flags)
+{
+  while (*options)
+    {
+      char *p = strchr (options, ',');
+      if (p)
+        *p++ = '\0';
+      else
+        p = strchr (options, '\0');
+
+      for (opt *o = oopts;
+          o < (oopts + (sizeof (oopts) / sizeof (oopts[0])));
+          o++)
+        if (strcmp (options, o->name) == 0)
+          {
+            if (o->clear)
+              flags &= ~o->val;
+            else
+              flags |= o->val;
+            goto gotit;
+          }
+      system_printf ("invalid fstab option - '%s'", options);
+      return false;
+
+    gotit:
+      options = p;
+    }
+  return true;
+}
+
+bool
+mount_info::from_fstab_line (char *line, bool user)
+{
+  char *native_path, *posix_path, *fs_type;
+
+  /* First field: Native path. */
+  char *c = skip_ws (line);
+  if (!*c || *c == '#')
+    return true;
+  char *cend = find_ws (c);
+  *cend = '\0';
+  native_path = conv_fstab_spaces (c);
+  /* Second field: POSIX path. */
+  c = skip_ws (cend + 1);
+  if (!*c)
+    return true;
+  cend = find_ws (c);
+  *cend = '\0';
+  posix_path = conv_fstab_spaces (c);
+  /* Third field: FS type. */
+  c = skip_ws (cend + 1);
+  if (!*c)
+    return true;
+  cend = find_ws (c);
+  *cend = '\0';
+  fs_type = c;
+  /* Forth field: Flags. */
+  c = skip_ws (cend + 1);
+  if (!*c)
+    return true;
+  cend = find_ws (c);
+  *cend = '\0';
+  unsigned mount_flags = MOUNT_SYSTEM;
+  if (!read_flags (c, mount_flags))
+    return true;
+  if (user)
+    mount_flags &= ~MOUNT_SYSTEM;
+  if (!strcmp (fs_type, "cygdrive"))
+    {
+      cygdrive_flags = mount_flags | MOUNT_CYGDRIVE;
+      slashify (posix_path, cygdrive, 1);
+      cygdrive_len = strlen (cygdrive);
+    }
+  else
+    {
+      int res = mount_table->add_item (native_path, posix_path, mount_flags);
+      if (res && get_errno () == EMFILE)
+       return false;
+    }
+  return true;
+}
+
+bool
+mount_info::from_fstab (bool user)
+{
+  tmp_pathbuf tp;
+  PWCHAR path = tp.w_get ();
+  PWCHAR w;
+  
+  if (!GetModuleFileNameW (GetModuleHandleW (L"cygwin1.dll"),
+                          path, NT_MAX_PATH))
+    {
+      debug_printf ("GetModuleFileNameW, %E");
+      return false;
+    }
+  w = wcsrchr (path, L'\\');
+  if (w)
+    {
+      *w = L'\0';
+      w = wcsrchr (path, L'\\');
+    }
+  if (!w)
+    {
+      debug_printf ("Invalid DLL path");
+      return false;
+    }
+
+  if (!user)
+    {
+      /* Create a default root dir from the path the Cygwin DLL is in. */
+      *w = L'\0';
+      char *native_root = tp.c_get ();
+      sys_wcstombs (native_root, NT_MAX_PATH, path);
+      mount_table->add_item (native_root, "/", MOUNT_SYSTEM | MOUNT_BINARY);
+      /* Create a default cygdrive entry.  Note that this is a user entry.
+         This allows to override it with mount, unless the sysadmin created
+        a cygdrive entry in /etc/fstab. */
+      cygdrive_flags = MOUNT_BINARY | MOUNT_CYGDRIVE;
+      strcpy (cygdrive, "/cygdrive/");
+      cygdrive_len = strlen (cygdrive);
+    }
+
+  PWCHAR u = wcpcpy (w, L"\\etc\\fstab");
+  if (user)
+    sys_mbstowcs (wcpcpy (u, L"."), NT_MAX_PATH - (u - path),
+                 cygheap->user.name ());
+  debug_printf ("Try to read mounts from %W", path);
+  HANDLE h = CreateFileW (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih,
+                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (h == INVALID_HANDLE_VALUE)
+    {
+      debug_printf ("CreateFileW, %E");
+      return false;
+    }
+  char *const buf = reinterpret_cast<char *const> (path);
+  char *got = buf;
+  DWORD len = 0;
+  /* Using NT_MAX_PATH-1 leaves space to append two \0. */
+  while (ReadFile (h, got, (NT_MAX_PATH - 1) * sizeof (WCHAR) - (got - buf),
+                  &len, NULL))
+    {
+      char *end;
+
+      /* Set end marker. */
+      got[len] = got[len + 1] = '\0';
+      /* Set len to the absolute len of bytes in buf. */
+      len += got - buf;
+      /* Reset got to start reading at the start of the buffer again. */
+      got = buf;
+      while (got < buf + len && (end = strchr (got, '\n')))
+        {
+         end[end[-1] == '\r' ? -1 : 0] = '\0';
+         if (!from_fstab_line (got, user))
+           goto done;
+         got = end + 1;
+       }
+      if (len < (NT_MAX_PATH - 1) * sizeof (WCHAR))
+        break;
+      /* We have to read once more.  Move remaining bytes to the start of
+         the buffer and reposition got so that it points to the end of
+        the remaining bytes. */
+      len = buf + len - got;
+      memmove (buf, got, len);
+      got = buf + len;
+      buf[len] = buf[len + 1] = '\0';
+    }
+  if (got > buf)
+    from_fstab_line (got, user);
+done:
+  CloseHandle (h);
+  return true;
+}
+
+/* read_mounts: Given a specific regkey, read mounts from under its
+   key. */
+/* FIXME: Remove before releasing 1.7.0. */
+
+void
+mount_info::read_mounts (reg_key& r)
+{
+  tmp_pathbuf tp;
+  char *native_path = tp.c_get ();
+  /* FIXME: The POSIX path is stored as value name right now, which is
+     restricted to 256 bytes. */
+  char posix_path[CYG_MAX_PATH];
+  HKEY key = r.get_key ();
+  DWORD i, posix_path_size;
+  int res;
+
+  /* Loop through subkeys */
+  /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
+     shared area is currently statically allocated so we can't have an
+     arbitrarily large number of mounts. */
+  for (i = 0; ; i++)
+    {
+      int mount_flags;
+
+      posix_path_size = sizeof (posix_path);
+      /* FIXME: if maximum posix_path_size is 256, we're going to
+        run into problems if we ever try to store a mount point that's
+        over 256 but is under CYG_MAX_PATH. */
+      res = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
+                         NULL, NULL, NULL);
+
+      if (res == ERROR_NO_MORE_ITEMS)
+       break;
+      else if (res != ERROR_SUCCESS)
+       {
+         debug_printf ("RegEnumKeyEx failed, error %d!", res);
+         break;
+       }
+
+      /* Get a reg_key based on i. */
+      reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
+
+      /* Fetch info from the subkey. */
+      subkey.get_string ("native", native_path, NT_MAX_PATH, "");
+      mount_flags = subkey.get_int ("flags", 0);
+
+      /* Add mount_item corresponding to registry mount point. */
+      res = mount_table->add_item (native_path, posix_path, mount_flags);
+      if (res && get_errno () == EMFILE)
+       break; /* The number of entries exceeds MAX_MOUNTS */
+    }
+}
+
+/* from_registry: Build the entire mount table from the registry.  Also,
+   read in cygdrive-related information from its registry location. */
+/* FIXME: Remove before releasing 1.7.0. */
+
+void
+mount_info::from_registry ()
+{
+
+  /* Retrieve cygdrive-related information. */
+  read_cygdrive_info_from_registry ();
+
+  nmounts = 0;
+
+  /* First read mounts from user's table.
+     Then read mounts from system-wide mount table while deimpersonated . */
+  for (int i = 0; i < 2; i++)
+    {
+      if (i)
+       cygheap->user.deimpersonate ();
+      reg_key r (i, KEY_READ, CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
+      read_mounts (r);
+      if (i)
+       cygheap->user.reimpersonate ();
+    }
+}
+
+/* read_cygdrive_info_from_registry: Read the default prefix and flags
+   to use when creating cygdrives from the special user registry
+   location used to store cygdrive information. */
+/* FIXME: Remove before releasing 1.7.0. */
+
+void
+mount_info::read_cygdrive_info_from_registry ()
+{
+  /* First read cygdrive from user's registry.
+     If failed, then read cygdrive from system-wide registry
+     while deimpersonated. */
+  for (int i = 0; i < 2; i++)
+    {
+      if (i)
+       cygheap->user.deimpersonate ();
+      reg_key r (i, KEY_READ, CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
+      if (i)
+       cygheap->user.reimpersonate ();
+
+      if (r.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive),
+                       CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX) != ERROR_SUCCESS && i == 0)
+       continue;
+
+      /* Fetch user cygdrive_flags from registry; returns MOUNT_CYGDRIVE on error. */
+      cygdrive_flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS,
+                                 MOUNT_CYGDRIVE | MOUNT_BINARY);
+      /* Sanitize */
+      if (i == 0)
+       cygdrive_flags &= ~MOUNT_SYSTEM;
+      else
+       cygdrive_flags |= MOUNT_SYSTEM;
+      slashify (cygdrive, cygdrive, 1);
+      cygdrive_len = strlen (cygdrive);
+      break;
+    }
+}
+
+/* write_cygdrive_info: Store default prefix and flags
+   to use when creating cygdrives to the special user shared mem
+   location used to store cygdrive information. */
+
+int
+mount_info::write_cygdrive_info (const char *cygdrive_prefix, unsigned flags)
+{
+  /* Verify cygdrive prefix starts with a forward slash and if there's
+     another character, it's not a slash. */
+  if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
+      (!isslash (cygdrive_prefix[0])) ||
+      ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+  /* Don't allow to override a system cygdrive prefix. */
+  if (cygdrive_flags & MOUNT_SYSTEM)
+    {
+      set_errno (EPERM);
+      return -1;
+    }
+
+  slashify (cygdrive_prefix, cygdrive, 1);
+  cygdrive_flags = flags & ~MOUNT_SYSTEM;
+  cygdrive_len = strlen (cygdrive);
+
+  return 0;
+}
+
+int
+mount_info::get_cygdrive_info (char *user, char *system, char* user_flags,
+                              char* system_flags)
+{
+  if (user)
+    *user = '\0';
+  /* Get the user flags, if appropriate */
+  if (user_flags)
+    *user_flags = '\0';
+
+  if (system)
+    strcpy (system, cygdrive);
+
+  if (system_flags)
+    strcpy (system_flags,
+           (cygdrive_flags & MOUNT_BINARY) ? "binmode" : "textmode");
+
+  return 0;
+}
+
+static mount_item *mounts_for_sort;
+
+/* sort_by_posix_name: qsort callback to sort the mount entries.  Sort
+   user mounts ahead of system mounts to the same POSIX path. */
+/* FIXME: should the user should be able to choose whether to
+   prefer user or system mounts??? */
+static int
+sort_by_posix_name (const void *a, const void *b)
+{
+  mount_item *ap = mounts_for_sort + (*((int*) a));
+  mount_item *bp = mounts_for_sort + (*((int*) b));
+
+  /* Base weighting on longest posix path first so that the most
+     obvious path will be chosen. */
+  size_t alen = strlen (ap->posix_path);
+  size_t blen = strlen (bp->posix_path);
+
+  int res = blen - alen;
+
+  if (res)
+    return res;                /* Path lengths differed */
+
+  /* The two paths were the same length, so just determine normal
+     lexical sorted order. */
+  res = strcmp (ap->posix_path, bp->posix_path);
+
+  if (res == 0)
+   {
+     /* need to select between user and system mount to same POSIX path */
+     if (!(bp->flags & MOUNT_SYSTEM))  /* user mount */
+      return 1;
+     else
+      return -1;
+   }
+
+  return res;
+}
+
+/* sort_by_native_name: qsort callback to sort the mount entries.  Sort
+   user mounts ahead of system mounts to the same POSIX path. */
+/* FIXME: should the user should be able to choose whether to
+   prefer user or system mounts??? */
+static int
+sort_by_native_name (const void *a, const void *b)
+{
+  mount_item *ap = mounts_for_sort + (*((int*) a));
+  mount_item *bp = mounts_for_sort + (*((int*) b));
+
+  /* Base weighting on longest win32 path first so that the most
+     obvious path will be chosen. */
+  size_t alen = strlen (ap->native_path);
+  size_t blen = strlen (bp->native_path);
+
+  int res = blen - alen;
+
+  if (res)
+    return res;                /* Path lengths differed */
+
+  /* The two paths were the same length, so just determine normal
+     lexical sorted order. */
+  res = strcmp (ap->native_path, bp->native_path);
+
+  if (res == 0)
+   {
+     /* need to select between user and system mount to same POSIX path */
+     if (!(bp->flags & MOUNT_SYSTEM))  /* user mount */
+      return 1;
+     else
+      return -1;
+   }
+
+  return res;
+}
+
+void
+mount_info::sort ()
+{
+  for (int i = 0; i < nmounts; i++)
+    native_sorted[i] = posix_sorted[i] = i;
+  /* Sort them into reverse length order, otherwise we won't
+     be able to look for /foo in /.  */
+  mounts_for_sort = mount;     /* ouch. */
+  qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
+  qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
+}
+
+/* Add an entry to the mount table.
+   Returns 0 on success, -1 on failure and errno is set.
+
+   This is where all argument validation is done.  It may not make sense to
+   do this when called internally, but it's cleaner to keep it all here.  */
+
+int
+mount_info::add_item (const char *native, const char *posix,
+                     unsigned mountflags)
+{
+  tmp_pathbuf tp;
+  char *nativetmp = tp.c_get ();
+  /* FIXME: The POSIX path is stored as value name right now, which is
+     restricted to 256 bytes. */
+  char posixtmp[CYG_MAX_PATH];
+  char *nativetail, *posixtail, error[] = "error";
+  int nativeerr, posixerr;
+
+  /* Something's wrong if either path is NULL or empty, or if it's
+     not a UNC or absolute path. */
+
+  if (native == NULL || !isabspath (native) ||
+      !(is_unc_share (native) || isdrive (native)))
+    nativeerr = EINVAL;
+  else
+    nativeerr = normalize_win32_path (native, nativetmp, nativetail);
+
+  if (posix == NULL || !isabspath (posix) ||
+      is_unc_share (posix) || isdrive (posix))
+    posixerr = EINVAL;
+  else
+    posixerr = normalize_posix_path (posix, posixtmp, posixtail);
+
+  debug_printf ("%s[%s], %s[%s], %p",
+               native, nativeerr ? error : nativetmp,
+               posix, posixerr ? error : posixtmp, mountflags);
+
+  if (nativeerr || posixerr)
+    {
+      set_errno (nativeerr?:posixerr);
+      return -1;
+    }
+
+  /* Make sure both paths do not end in /. */
+  if (nativetail > nativetmp + 1 && nativetail[-1] == '\\')
+    nativetail[-1] = '\0';
+  if (posixtail > posixtmp + 1 && posixtail[-1] == '/')
+    posixtail[-1] = '\0';
+
+  /* Write over an existing mount item with the same POSIX path if
+     it exists and is from the same registry area. */
+  int i;
+  for (i = 0; i < nmounts; i++)
+    {
+      if (strcasematch (mount[i].posix_path, posixtmp))
+        {
+         /* Don't allow to override a system mount with a user mount. */
+         if ((mount[i].flags & MOUNT_SYSTEM) && !(mountflags & MOUNT_SYSTEM))
+           {
+             set_errno (EPERM);
+             return -1;
+           }
+         if ((mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM))
+           break;
+       }
+    }
+
+  if (i == nmounts && nmounts == MAX_MOUNTS)
+    {
+      set_errno (EMFILE);
+      return -1;
+    }
+
+  if (i == nmounts)
+    nmounts++;
+  mount[i].init (nativetmp, posixtmp, mountflags);
+  sort ();
+
+  return 0;
+}
+
+/* Delete a mount table entry where path is either a Win32 or POSIX
+   path. Since the mount table is really just a table of aliases,
+   deleting / is ok (although running without a slash mount is
+   strongly discouraged because some programs may run erratically
+   without one).  If MOUNT_SYSTEM is set in flags, remove from system
+   registry, otherwise remove the user registry mount.
+*/
+
+int
+mount_info::del_item (const char *path, unsigned flags)
+{
+  tmp_pathbuf tp;
+  char *pathtmp = tp.c_get ();
+  int posix_path_p = false;
+
+  /* Something's wrong if path is NULL or empty. */
+  if (path == NULL || *path == 0 || !isabspath (path))
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+
+  if (is_unc_share (path) || strpbrk (path, ":\\"))
+    backslashify (path, pathtmp, 0);
+  else
+    {
+      slashify (path, pathtmp, 0);
+      posix_path_p = true;
+    }
+  nofinalslash (pathtmp, pathtmp);
+
+  for (int i = 0; i < nmounts; i++)
+    {
+      int ent = native_sorted[i]; /* in the same order as getmntent() */
+      if (((posix_path_p)
+          ? strcasematch (mount[ent].posix_path, pathtmp)
+          : strcasematch (mount[ent].native_path, pathtmp)))
+       {
+         /* Don't allow to remove a system mount. */
+         if ((mount[ent].flags & MOUNT_SYSTEM))
+           {
+             set_errno (EPERM);
+             return -1;
+           }
+         nmounts--; /* One less mount table entry */
+         /* Fill in the hole if not at the end of the table */
+         if (ent < nmounts)
+           memmove (mount + ent, mount + ent + 1,
+                    sizeof (mount[ent]) * (nmounts - ent));
+         sort (); /* Resort the table */
+         return 0;
+       }
+    }
+  set_errno (EINVAL);
+  return -1;
+}
+
+/************************* mount_item class ****************************/
+
+static mntent *
+fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
+{
+  struct mntent& ret=_my_tls.locals.mntbuf;
+  bool append_bs = false;
+
+  /* Remove drivenum from list if we see a x: style path */
+  if (strlen (native_path) == 2 && native_path[1] == ':')
+    {
+      int drivenum = cyg_tolower (native_path[0]) - 'a';
+      if (drivenum >= 0 && drivenum <= 31)
+       _my_tls.locals.available_drives &= ~(1 << drivenum);
+      append_bs = true;
+    }
+
+  /* Pass back pointers to mount_table strings reserved for use by
+     getmntent rather than pointers to strings in the internal mount
+     table because the mount table might change, causing weird effects
+     from the getmntent user's point of view. */
+
+  strcpy (_my_tls.locals.mnt_fsname, native_path);
+  ret.mnt_fsname = _my_tls.locals.mnt_fsname;
+  strcpy (_my_tls.locals.mnt_dir, posix_path);
+  ret.mnt_dir = _my_tls.locals.mnt_dir;
+
+  /* Try to give a filesystem type that matches what a Linux application might
+     expect. Naturally, this is a moving target, but we can make some
+     reasonable guesses for popular types. */
+
+  fs_info mntinfo;
+  tmp_pathbuf tp;
+  UNICODE_STRING unat;
+  tp.u_get (&unat);
+  get_nt_native_path (native_path, unat, flags & MOUNT_ENC);
+  if (append_bs)
+    RtlAppendUnicodeToString (&unat, L"\\");
+  mntinfo.update (&unat, true);  /* this pulls from a cache, usually. */
+
+  if (mntinfo.is_samba())
+    strcpy (_my_tls.locals.mnt_type, (char *) "smbfs");
+  else if (mntinfo.is_nfs ())
+    strcpy (_my_tls.locals.mnt_type, (char *) "nfs");
+  else if (mntinfo.is_fat ())
+    strcpy (_my_tls.locals.mnt_type, (char *) "vfat");
+  else if (mntinfo.is_ntfs ())
+    strcpy (_my_tls.locals.mnt_type, (char *) "ntfs");
+  else if (mntinfo.is_netapp ())
+    strcpy (_my_tls.locals.mnt_type, (char *) "netapp");
+  else if (mntinfo.is_cdrom ())
+    strcpy (_my_tls.locals.mnt_type, (char *) "iso9660");
+  else
+    strcpy (_my_tls.locals.mnt_type, (char *) "unknown");
+
+  ret.mnt_type = _my_tls.locals.mnt_type;
+
+  /* mnt_opts is a string that details mount params such as
+     binary or textmode, or exec.  We don't print
+     `silent' here; it's a magic internal thing. */
+
+  if (!(flags & MOUNT_BINARY))
+    strcpy (_my_tls.locals.mnt_opts, (char *) "textmode");
+  else
+    strcpy (_my_tls.locals.mnt_opts, (char *) "binmode");
+
+  if (flags & MOUNT_CYGWIN_EXEC)
+    strcat (_my_tls.locals.mnt_opts, (char *) ",cygexec");
+  else if (flags & MOUNT_EXEC)
+    strcat (_my_tls.locals.mnt_opts, (char *) ",exec");
+  else if (flags & MOUNT_NOTEXEC)
+    strcat (_my_tls.locals.mnt_opts, (char *) ",noexec");
+  if (flags & MOUNT_ENC)
+    strcat (_my_tls.locals.mnt_opts, ",managed");
+
+  if ((flags & MOUNT_CYGDRIVE))                /* cygdrive */
+    strcat (_my_tls.locals.mnt_opts, (char *) ",noumount");
+
+  if (!(flags & MOUNT_SYSTEM))         /* user mount */
+    strcat (_my_tls.locals.mnt_opts, (char *) ",user");
+  else                                 /* system mount */
+    strcat (_my_tls.locals.mnt_opts, (char *) ",system");
+
+  ret.mnt_opts = _my_tls.locals.mnt_opts;
+
+  ret.mnt_freq = 1;
+  ret.mnt_passno = 1;
+  return &ret;
+}
+
+struct mntent *
+mount_item::getmntent ()
+{
+  return fillout_mntent (native_path, posix_path, flags);
+}
+
+static struct mntent *
+cygdrive_getmntent ()
+{
+  char native_path[4];
+  char posix_path[CYG_MAX_PATH];
+  DWORD mask = 1, drive = 'a';
+  struct mntent *ret = NULL;
+
+  while (_my_tls.locals.available_drives)
+    {
+      for (/* nothing */; drive <= 'z'; mask <<= 1, drive++)
+       if (_my_tls.locals.available_drives & mask)
+         break;
+
+      __small_sprintf (native_path, "%c:\\", drive);
+      if (GetFileAttributes (native_path) == INVALID_FILE_ATTRIBUTES)
+       {
+         _my_tls.locals.available_drives &= ~mask;
+         continue;
+       }
+      native_path[2] = '\0';
+      __small_sprintf (posix_path, "%s%c", mount_table->cygdrive, drive);
+      ret = fillout_mntent (native_path, posix_path, mount_table->cygdrive_flags);
+      break;
+    }
+
+  return ret;
+}
+
+struct mntent *
+mount_info::getmntent (int x)
+{
+  if (x < 0 || x >= nmounts)
+    return cygdrive_getmntent ();
+
+  return mount[native_sorted[x]].getmntent ();
+}
+
+/* Fill in the fields of a mount table entry.  */
+
+void
+mount_item::init (const char *native, const char *posix, unsigned mountflags)
+{
+  strcpy ((char *) native_path, native);
+  strcpy ((char *) posix_path, posix);
+
+  native_pathlen = strlen (native_path);
+  posix_pathlen = strlen (posix_path);
+
+  flags = mountflags;
+}
+
+/********************** Mount System Calls **************************/
+
+/* Mount table system calls.
+   Note that these are exported to the application.  */
+
+/* mount: Add a mount to the mount table in memory and to the registry
+   that will cause paths under win32_path to be translated to paths
+   under posix_path. */
+
+extern "C" int
+mount (const char *win32_path, const char *posix_path, unsigned flags)
+{
+  int res = -1;
+  flags &= ~MOUNT_SYSTEM;
+
+  myfault efault;
+  if (efault.faulted (EFAULT))
+    /* errno set */;
+  else if (!*posix_path)
+    set_errno (EINVAL);
+  else if (strpbrk (posix_path, "\\:"))
+    set_errno (EINVAL);
+  else if (flags & MOUNT_CYGDRIVE) /* normal mount */
+    {
+      /* When flags include MOUNT_CYGDRIVE, take this to mean that
+       we actually want to change the cygdrive prefix and flags
+       without actually mounting anything. */
+      res = mount_table->write_cygdrive_info (posix_path, flags);
+      win32_path = NULL;
+    }
+  else if (!*win32_path)
+    set_errno (EINVAL);
+  else
+    res = mount_table->add_item (win32_path, posix_path, flags);
+
+  syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
+  return res;
+}
+
+/* umount: The standard umount call only has a path parameter.  Since
+   it is not possible for this call to specify whether to remove the
+   mount from the user or global mount registry table, assume the user
+   table. */
+
+extern "C" int
+umount (const char *path)
+{
+  myfault efault;
+  if (efault.faulted (EFAULT))
+    return -1;
+  if (!*path)
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+  return cygwin_umount (path, 0);
+}
+
+/* cygwin_umount: This is like umount but takes an additional flags
+   parameter that specifies whether to umount from the user or system-wide
+   registry area. */
+
+extern "C" int
+cygwin_umount (const char *path, unsigned flags)
+{
+  int res = -1;
+
+  if (!(flags & MOUNT_CYGDRIVE))
+    res = mount_table->del_item (path, flags & ~MOUNT_SYSTEM);
+
+  syscall_printf ("%d = cygwin_umount (%s, %d)", res,  path, flags);
+  return res;
+}
+
+bool
+is_floppy (const char *dos)
+{
+  char dev[256];
+  if (!QueryDosDevice (dos, dev, 256))
+    return false;
+  return ascii_strncasematch (dev, "\\Device\\Floppy", 14);
+}
+
+extern "C" FILE *
+setmntent (const char *filep, const char *)
+{
+  _my_tls.locals.iteration = 0;
+  _my_tls.locals.available_drives = GetLogicalDrives ();
+  /* Filter floppy drives on A: and B: */
+  if ((_my_tls.locals.available_drives & 1) && is_floppy ("A:"))
+    _my_tls.locals.available_drives &= ~1;
+  if ((_my_tls.locals.available_drives & 2) && is_floppy ("B:"))
+    _my_tls.locals.available_drives &= ~2;
+  return (FILE *) filep;
+}
+
+extern "C" struct mntent *
+getmntent (FILE *)
+{
+  return mount_table->getmntent (_my_tls.locals.iteration++);
+}
+
+extern "C" int
+endmntent (FILE *)
+{
+  return 1;
+}
index ea3b4eabc9214e8f85df53afb8d7f7419734e6eb..053a288cf76fa08f3fa385da465d6d16ebd0b8b2 100644 (file)
@@ -14,6 +14,7 @@ details. */
 #define  __INSIDE_CYGWIN_NET__
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <ctype.h>
 #include <wchar.h>
 #include <sys/socket.h>
index e9c4870d0bf5240c42c71f6584d936d8c77fd23f..0b94890b1cf8c9c3d7da6707691e7b2f536a1ec0 100644 (file)
@@ -49,44 +49,29 @@ details. */
 */
 
 #include "winsup.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mount.h>
-#include <mntent.h>
-#include <unistd.h>
-#include <libgen.h>
+#include "miscfuncs.h"
 #include <ctype.h>
 #include <winioctl.h>
 #include <wingdi.h>
 #include <winuser.h>
-#include <winnls.h>
 #include <winnetwk.h>
 #include <shlobj.h>
 #include <sys/cygwin.h>
-#include <cygwin/version.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
 #include "fhandler.h"
-#include "sync.h"
-#include "sigproc.h"
-#include "pinfo.h"
 #include "dtable.h"
 #include "cygheap.h"
 #include "shared_info.h"
-#include "registry.h"
 #include "cygtls.h"
 #include "tls_pbuf.h"
 #include "environ.h"
 #include <assert.h>
 #include <ntdll.h>
 #include <wchar.h>
-#include <wctype.h>
 
 bool dos_file_warning = true;
-static int normalize_win32_path (const char *, char *, char *&);
-static void slashify (const char *, char *, int);
-static void backslashify (const char *, char *, int);
 
 struct symlink_info
 {
@@ -151,18 +136,6 @@ struct win_shortcut_hdr
     DWORD dummy[2];    /* Future extension probably. Always 0. */
   };
 
-/* Determine if path prefix matches current cygdrive */
-#define iscygdrive(path) \
-  (path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len))
-
-#define iscygdrive_device(path) \
-  (isalpha (path[mount_table->cygdrive_len]) && \
-   (path[mount_table->cygdrive_len + 1] == '/' || \
-    !path[mount_table->cygdrive_len + 1]))
-
-#define isproc(path) \
-  (path_prefix_p (proc, (path), proc_len))
-
 /* Return non-zero if PATH1 is a prefix of PATH2.
    Both are assumed to be of the same path style and / vs \ usage.
    Neither may be "".
@@ -240,13 +213,11 @@ has_dot_last_component (const char *dir, bool test_dot_dot)
                 && (last_comp[2] == '\0' || last_comp[2] == '/')));
 }
 
-#define isslash(c) ((c) == '/')
-
 /* Normalize a POSIX path.
    All duplicate /'s, except for 2 leading /'s, are deleted.
    The result is 0 for success, or an errno error value.  */
 
-static int
+int
 normalize_posix_path (const char *src, char *dst, char *&tail)
 {
   const char *in_src = src;
@@ -640,7 +611,7 @@ transform_chars (PUNICODE_STRING upath, USHORT start_idx, bool managed)
     *end |= 0xf000;
 }
 
-static PUNICODE_STRING
+PUNICODE_STRING
 get_nt_native_path (const char *path, UNICODE_STRING& upath, bool managed)
 {
   upath.Length = 0;
@@ -1364,40 +1335,13 @@ path_conv::is_binary ()
         && GetBinaryTypeW (get_wide_win32_path (bintest), &bin);
 }
 
-/* Return true if src_path is a valid, internally supported device name.
-   In that case, win32_path gets the corresponding NT device name and
-   dev is appropriately filled with device information. */
-
-static bool
-win32_device_name (const char *src_path, char *win32_path, device& dev)
-{
-  dev.parse (src_path);
-  if (dev == FH_FS || dev == FH_DEV)
-    return false;
-  strcpy (win32_path, dev.native);
-  return true;
-}
-
-/* is_unc_share: Return non-zero if PATH begins with //UNC/SHARE */
-
-static bool __stdcall
-is_unc_share (const char *path)
-{
-  const char *p;
-  return (isdirsep (path[0])
-        && isdirsep (path[1])
-        && (isalnum (path[2]) || path[2] == '.')
-        && ((p = strpbrk (path + 3, "\\/")) != NULL)
-        && isalnum (p[1]));
-}
-
 /* Normalize a Win32 path.
    /'s are converted to \'s in the process.
    All duplicate \'s, except for 2 leading \'s, are deleted.
 
    The result is 0 for success, or an errno error value.
    FIXME: A lot of this should be mergeable with the POSIX critter.  */
-static int
+int
 normalize_win32_path (const char *src, char *dst, char *&tail)
 {
   const char *src_start = src;
@@ -1503,54 +1447,6 @@ normalize_win32_path (const char *src, char *dst, char *&tail)
 
 /* Various utilities.  */
 
-/* slashify: Convert all back slashes in src path to forward slashes
-   in dst path.  Add a trailing slash to dst when trailing_slash_p arg
-   is set to 1. */
-
-static void
-slashify (const char *src, char *dst, int trailing_slash_p)
-{
-  const char *start = src;
-
-  while (*src)
-    {
-      if (*src == '\\')
-       *dst++ = '/';
-      else
-       *dst++ = *src;
-      ++src;
-    }
-  if (trailing_slash_p
-      && src > start
-      && !isdirsep (src[-1]))
-    *dst++ = '/';
-  *dst++ = 0;
-}
-
-/* backslashify: Convert all forward slashes in src path to back slashes
-   in dst path.  Add a trailing slash to dst when trailing_slash_p arg
-   is set to 1. */
-
-static void
-backslashify (const char *src, char *dst, int trailing_slash_p)
-{
-  const char *start = src;
-
-  while (*src)
-    {
-      if (*src == '/')
-       *dst++ = '\\';
-      else
-       *dst++ = *src;
-      ++src;
-    }
-  if (trailing_slash_p
-      && src > start
-      && !isdirsep (src[-1]))
-    *dst++ = '\\';
-  *dst++ = 0;
-}
-
 /* nofinalslash: Remove trailing / and \ from SRC (except for the
    first one).  It is ok for src == dst.  */
 
@@ -1631,1679 +1527,140 @@ conv_path_list (const char *src, char *dst, size_t size, int to_posix)
   return err;
 }
 
-/* init: Initialize the mount table.  */
-
-void
-mount_info::init ()
-{
-  nmounts = 0;
-
-  if (from_fstab (false) | from_fstab (true))  /* The single | is correct! */
-    return;
-
-  /* FIXME: Remove fetching from registry before releasing 1.7.0. */
-
-  /* Fetch the mount table and cygdrive-related information from
-     the registry.  */
-  system_printf ("Fallback to fetching mounts from registry");
-  from_registry ();
-}
-
-static void
-set_flags (unsigned *flags, unsigned val)
-{
-  *flags = val;
-  if (!(*flags & PATH_BINARY))
-    {
-      *flags |= PATH_TEXT;
-      debug_printf ("flags: text (%p)", *flags & (PATH_TEXT | PATH_BINARY));
-    }
-  else
-    {
-      *flags |= PATH_BINARY;
-      debug_printf ("flags: binary (%p)", *flags & (PATH_TEXT | PATH_BINARY));
-    }
-}
+/********************** Symbolic Link Support **************************/
 
-static char dot_special_chars[] =
-    "."
-    "\001" "\002" "\003" "\004" "\005" "\006" "\007" "\010"
-    "\011" "\012" "\013" "\014" "\015" "\016" "\017" "\020"
-    "\021" "\022" "\023" "\024" "\025" "\026" "\027" "\030"
-    "\031" "\032" "\033" "\034" "\035" "\036" "\037" ":"
-    "\\"   "*"    "?"    "%"     "\""   "<"    ">"    "|"
-    "A"    "B"    "C"    "D"    "E"    "F"    "G"    "H"
-    "I"    "J"    "K"    "L"    "M"    "N"    "O"    "P"
-    "Q"    "R"    "S"    "T"    "U"    "V"    "W"    "X"
-    "Y"    "Z";
-static char *special_chars = dot_special_chars + 1;
-static char special_introducers[] =
-    "anpcl";
-
-static char
-special_char (const char *s, const char *valid_chars = special_chars)
-{
-  if (*s != '%' || strlen (s) < 3)
-    return 0;
+/* Create a symlink from FROMPATH to TOPATH. */
 
-  char *p;
-  char hex[] = {s[1], s[2], '\0'};
-  unsigned char c = strtoul (hex, &p, 16);
-  p = strechr (valid_chars, c);
-  return *p;
-}
+/* If TRUE create symlinks as Windows shortcuts, if false create symlinks
+   as normal files with magic number and system bit set. */
+bool allow_winsymlinks = true;
 
-/* Determines if name is "special".  Assumes that name is empty or "absolute" */
-static int
-special_name (const char *s, int inc = 1)
+extern "C" int
+symlink (const char *oldpath, const char *newpath)
 {
-  if (!*s)
-    return false;
-
-  s += inc;
-
-  if (strcmp (s, ".") == 0 || strcmp (s, "..") == 0)
-    return false;
-
-  int n;
-  const char *p = NULL;
-  if (ascii_strncasematch (s, "conin$", n = 5)
-      || ascii_strncasematch (s, "conout$", n = 7)
-      || ascii_strncasematch (s, "nul", n = 3)
-      || ascii_strncasematch (s, "aux", 3)
-      || ascii_strncasematch (s, "prn", 3)
-      || ascii_strncasematch (s, "con", 3))
-    p = s + n;
-  else if (ascii_strncasematch (s, "com", 3)
-          || ascii_strncasematch (s, "lpt", 3))
-    strtoul (s + 3, (char **) &p, 10);
-  if (p && (*p == '\0' || *p == '.'))
-    return -1;
-
-  return (strchr (s, '\0')[-1] == '.')
-        || (strpbrk (s, special_chars) && !ascii_strncasematch (s, "%2f", 3));
+  return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
 }
 
-bool
-fnunmunge (char *dst, const char *src)
+int
+symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
+               bool isdevice)
 {
-  bool converted = false;
-  char c;
+  int res = -1;
+  size_t len;
+  path_conv win32_newpath, win32_oldpath;
+  char *buf, *cp;
+  SECURITY_ATTRIBUTES sa = sec_none_nih;
+  security_descriptor sd;
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
+  NTSTATUS status;
+  HANDLE fh;
+  FILE_BASIC_INFORMATION fbi;
+  tmp_pathbuf tp;
 
-  if ((c = special_char (src, special_introducers)))
+  /* POSIX says that empty 'newpath' is invalid input while empty
+     'oldpath' is valid -- it's symlink resolver job to verify if
+     symlink contents point to existing filesystem object */
+  myfault efault;
+  if (efault.faulted (EFAULT))
+    goto done;
+  if (!*oldpath || !*newpath)
     {
-      __small_sprintf (dst, "%c%s", c, src + 3);
-      if (special_name (dst, 0))
-       {
-         *dst++ = c;
-         src += 3;
-       }
+      set_errno (ENOENT);
+      goto done;
     }
 
-  while (*src)
-    if (!(c = special_char (src, dot_special_chars)))
-      *dst++ = *src++;
-    else
-      {
-       converted = true;
-       *dst++ = c;
-       src += 3;
-      }
-
-  *dst = *src;
-  return converted;
-}
-
-static bool
-copy1 (char *&d, const char *&src, int& left)
-{
-  left--;
-  if (left || !*src)
-    *d++ = *src++;
-  else
-    return true;
-  return false;
-}
-
-static bool
-copyenc (char *&d, const char *&src, int& left)
-{
-  char buf[16];
-  int n = __small_sprintf (buf, "%%%02x", (unsigned char) *src++);
-  left -= n;
-  if (left <= 0)
-    return true;
-  strcpy (d, buf);
-  d += n;
-  return false;
-}
-
-int
-mount_item::fnmunge (char *dst, const char *src, int& left)
-{
-  int name_type;
-  if (!(name_type = special_name (src)))
-    {
-      if ((int) strlen (src) >= left)
-       return ENAMETOOLONG;
-      else
-       strcpy (dst, src);
-    }
-  else
+  if (strlen (oldpath) > SYMLINK_MAX)
     {
-      char *d = dst;
-      if (copy1 (d, src, left))
-         return ENAMETOOLONG;
-      if (name_type < 0 && copyenc (d, src, left))
-       return ENAMETOOLONG;
-
-      while (*src)
-       if (!strchr (special_chars, *src) || (*src == '%' && !special_char (src)))
-         {
-           if (copy1 (d, src, left))
-             return ENAMETOOLONG;
-         }
-       else if (copyenc (d, src, left))
-         return ENAMETOOLONG;
-
-      char dot[] = ".";
-      const char *p = dot;
-      if (*--d != '.')
-       d++;
-      else if (copyenc (d, p, left))
-       return ENAMETOOLONG;
-
-      *d = *src;
+      set_errno (ENAMETOOLONG);
+      goto done;
     }
 
-  backslashify (dst, dst, 0);
-  return 0;
-}
-
-int
-mount_item::build_win32 (char *dst, const char *src, unsigned *outflags, unsigned chroot_pathlen)
-{
-  int n, err = 0;
-  const char *real_native_path;
-  int real_posix_pathlen;
-  set_flags (outflags, (unsigned) flags);
-  if (!cygheap->root.exists () || posix_pathlen != 1 || posix_path[0] != '/')
-    {
-      n = native_pathlen;
-      real_native_path = native_path;
-      real_posix_pathlen = chroot_pathlen ?: posix_pathlen;
-    }
-  else
+  len = strlen (newpath);
+  /* Trailing dirsep is a no-no. */
+  if (isdirsep (newpath[len - 1]))
     {
-      n = cygheap->root.native_length ();
-      real_native_path = cygheap->root.native_path ();
-      real_posix_pathlen = posix_pathlen;
-    }
-  memcpy (dst, real_native_path, n + 1);
-  const char *p = src + real_posix_pathlen;
-  if (*p == '/')
-    /* nothing */;
-  else if ((!(flags & MOUNT_ENC) && isdrive (dst) && !dst[2]) || *p)
-    dst[n++] = '\\';
-  //if (!*p || !(flags & MOUNT_ENC))
-    //{
-      if ((n + strlen (p)) >= NT_MAX_PATH)
-       err = ENAMETOOLONG;
-      else
-       backslashify (p, dst + n, 0);
-#if 0
+      set_errno (ENOENT);
+      goto done;
     }
-  else
+  /* We need the normalized full path below. */
+  win32_newpath.check (newpath, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
+  if (use_winsym && !win32_newpath.exists ())
     {
-      int left = NT_MAX_PATH - n;
-      while (*p)
-       {
-         char slash = 0;
-         char *s = strchr (p + 1, '/');
-         if (s)
-           {
-             slash = *s;
-             *s = '\0';
-           }
-         err = fnmunge (dst += n, p, left);
-         if (!s || err)
-           break;
-         n = strlen (dst);
-         *s = slash;
-         p = s;
-       }
+      char *newplnk = tp.c_get ();
+      stpcpy (stpcpy (newplnk, newpath), ".lnk");
+      win32_newpath.check (newplnk, PC_SYM_NOFOLLOW | PC_POSIX);
     }
-#endif
-  return err;
-}
-
-/* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
-   the result in win32_path.
-
-   If win32_path != NULL, the relative path, if possible to keep, is
-   stored in win32_path.  If the relative path isn't possible to keep,
-   the full path is stored.
-
-   If full_win32_path != NULL, the full path is stored there.
 
-   The result is zero for success, or an errno value.
-
-   {,full_}win32_path must have sufficient space (i.e. NT_MAX_PATH bytes).  */
-
-int
-mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
-                               unsigned *flags)
-{
-  bool chroot_ok = !cygheap->root.exists ();
-  while (sys_mount_table_counter < cygwin_shared->sys_mount_table_counter)
+  if (win32_newpath.error)
     {
-      int current = cygwin_shared->sys_mount_table_counter;
-      init ();
-      sys_mount_table_counter = current;
+      set_errno (win32_newpath.case_clash ? ECASECLASH : win32_newpath.error);
+      goto done;
     }
-  MALLOC_CHECK;
-
-  dev.devn = FH_FS;
-
-  *flags = 0;
-  debug_printf ("conv_to_win32_path (%s)", src_path);
-
-  int i, rc;
-  mount_item *mi = NULL;       /* initialized to avoid compiler warning */
-
-  /* The path is already normalized, without ../../ stuff, we need to have this
-     so that we can move from one mounted directory to another with relative
-     stuff.
 
-     eg mounting c:/foo /foo
-     d:/bar /bar
-
-     cd /bar
-     ls ../foo
-
-     should look in c:/foo, not d:/foo.
-
-     converting normalizex UNIX path to a DOS-style path, looking up the
-     appropriate drive in the mount table.  */
+  syscall_printf ("symlink (%s, %S)", oldpath,
+                 win32_newpath.get_nt_native_path ());
 
-  /* See if this is a cygwin "device" */
-  if (win32_device_name (src_path, dst, dev))
+  if ((!isdevice && win32_newpath.exists ())
+      || win32_newpath.is_auto_device ())
     {
-      *flags = MOUNT_BINARY;   /* FIXME: Is this a sensible default for devices? */
-      rc = 0;
-      goto out_no_chroot_check;
+      set_errno (EEXIST);
+      goto done;
     }
 
-  MALLOC_CHECK;
-  /* If the path is on a network drive or a //./ resp.//?/ path prefix,
-     bypass the mount table.  If it's // or //MACHINE, use the netdrive
-     device. */
-  if (src_path[1] == '/')
-    {
-      if (!strchr (src_path + 2, '/'))
-       {
-         dev = *netdrive_dev;
-         set_flags (flags, PATH_BINARY);
-       }
-      backslashify (src_path, dst, 0);
-      /* Go through chroot check */
-      goto out;
-    }
-  if (isproc (src_path))
-    {
-      dev = *proc_dev;
-      dev.devn = fhandler_proc::get_proc_fhandler (src_path);
-      if (dev.devn == FH_BAD)
-       return ENOENT;
-      set_flags (flags, PATH_BINARY);
-      strcpy (dst, src_path);
-      goto out;
-    }
-  /* Check if the cygdrive prefix was specified.  If so, just strip
-     off the prefix and transform it into an MS-DOS path. */
-  else if (iscygdrive (src_path))
+  if (use_winsym)
     {
-      int n = mount_table->cygdrive_len - 1;
-      int unit;
+      ITEMIDLIST *pidl = NULL;
+      size_t full_len = 0;
+      unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
+      char desc[MAX_PATH + 1], *relpath;
 
-      if (!src_path[n])
-       {
-         unit = 0;
-         dst[0] = '\0';
-         if (mount_table->cygdrive_len > 1)
-           dev = *cygdrive_dev;
-       }
-      else if (cygdrive_win32_path (src_path, dst, unit))
+      if (!isdevice)
        {
-         set_flags (flags, (unsigned) cygdrive_flags);
-         goto out;
-       }
-      else if (mount_table->cygdrive_len > 1)
-       return ENOENT;
-    }
+         /* First create an IDLIST to learn how big our shortcut is
+            going to be. */
+         IShellFolder *psl;
 
-  int chroot_pathlen;
-  chroot_pathlen = 0;
-  /* Check the mount table for prefix matches. */
-  for (i = 0; i < nmounts; i++)
-    {
-      const char *path;
-      int len;
+         /* The symlink target is relative to the directory in which
+            the symlink gets created, not relative to the cwd.  Therefore
+            we have to mangle the path quite a bit before calling path_conv. */
+         if (!isabspath (oldpath))
+           {
+             len = strrchr (win32_newpath.normalized_path, '/')
+                   - win32_newpath.normalized_path + 1;
+             char *absoldpath = tp.t_get ();
+             stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
+                     oldpath);
+             win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+           }
+         else
+           win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+         if (SUCCEEDED (SHGetDesktopFolder (&psl)))
+           {
+             WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
+             win32_oldpath.get_wide_win32_path (wc_path);
+             /* Amazing but true:  Even though the ParseDisplayName method
+                takes a wide char path name, it does not understand the
+                Win32 prefix for long pathnames!  So we have to tack off
+                the prefix and convert tyhe path to the "normal" syntax
+                for ParseDisplayName.  I have no idea if it's able to take
+                long path names at all since I can't test it right now. */
+             WCHAR *wc = wc_path + 4;
+             if (!wcscmp (wc, L"UNC\\"))
+               *(wc += 2) = L'\\';
+             HRESULT res;
+             if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
+                                                   &pidl, NULL)))
+               {
+                 ITEMIDLIST *p;
 
-      mi = mount + posix_sorted[i];
-      if (!cygheap->root.exists ()
-         || (mi->posix_pathlen == 1 && mi->posix_path[0] == '/'))
-       {
-         path = mi->posix_path;
-         len = mi->posix_pathlen;
-       }
-      else if (cygheap->root.posix_ok (mi->posix_path))
-       {
-         path = cygheap->root.unchroot (mi->posix_path);
-         chroot_pathlen = len = strlen (path);
-       }
-      else
-       {
-         chroot_pathlen = 0;
-         continue;
-       }
-
-      if (path_prefix_p (path, src_path, len))
-       break;
-    }
-
-  if (i < nmounts)
-    {
-      int err = mi->build_win32 (dst, src_path, flags, chroot_pathlen);
-      if (err)
-       return err;
-      chroot_ok = true;
-    }
-  else
-    {
-      int offset = 0;
-      if (src_path[1] != '/' && src_path[1] != ':')
-       offset = cygheap->cwd.get_drive (dst);
-      backslashify (src_path, dst + offset, 0);
-    }
- out:
-  MALLOC_CHECK;
-  if (chroot_ok || cygheap->root.ischroot_native (dst))
-    rc = 0;
-  else
-    {
-      debug_printf ("attempt to access outside of chroot '%s - %s'",
-                   cygheap->root.posix_path (), cygheap->root.native_path ());
-      rc = ENOENT;
-    }
-
- out_no_chroot_check:
-  debug_printf ("src_path %s, dst %s, flags %p, rc %d", src_path, dst, *flags, rc);
-  return rc;
-}
-
-int
-mount_info::get_mounts_here (const char *parent_dir, int parent_dir_len,
-                            PUNICODE_STRING mount_points,
-                            PUNICODE_STRING cygd)
-{
-  int n_mounts = 0;
-
-  for (int i = 0; i < nmounts; i++)
-    {
-      mount_item *mi = mount + posix_sorted[i];
-      char *last_slash = strrchr (mi->posix_path, '/');
-      if (!last_slash)
-       continue;
-      if (last_slash == mi->posix_path)
-       {
-         if (parent_dir_len == 1 && mi->posix_pathlen > 1)
-           RtlCreateUnicodeStringFromAsciiz (&mount_points[n_mounts++],
-                                             last_slash + 1);
-       }
-      else if (parent_dir_len == last_slash - mi->posix_path
-              && strncasematch (parent_dir, mi->posix_path, parent_dir_len))
-       RtlCreateUnicodeStringFromAsciiz (&mount_points[n_mounts++],
-                                         last_slash + 1);
-    }
-  RtlCreateUnicodeStringFromAsciiz (cygd, cygdrive + 1);
-  cygd->Length -= 2;   // Strip trailing slash
-  return n_mounts;
-}
-
-/* cygdrive_posix_path: Build POSIX path used as the
-   mount point for cygdrives created when there is no other way to
-   obtain a POSIX path from a Win32 one. */
-
-void
-mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
-{
-  int len = cygdrive_len;
-
-  memcpy (dst, cygdrive, len + 1);
-
-  /* Now finish the path off with the drive letter to be used.
-     The cygdrive prefix always ends with a trailing slash so
-     the drive letter is added after the path. */
-  dst[len++] = cyg_tolower (src[0]);
-  if (!src[2] || (isdirsep (src[2]) && !src[3]))
-    dst[len++] = '\000';
-  else
-    {
-      int n;
-      dst[len++] = '/';
-      if (isdirsep (src[2]))
-       n = 3;
-      else
-       n = 2;
-      strcpy (dst + len, src + n);
-    }
-  slashify (dst, dst, trailing_slash_p);
-}
-
-int
-mount_info::cygdrive_win32_path (const char *src, char *dst, int& unit)
-{
-  int res;
-  const char *p = src + cygdrive_len;
-  if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
-    {
-      unit = -1; /* FIXME: should be zero, maybe? */
-      dst[0] = '\0';
-      res = 0;
-    }
-  else
-    {
-      dst[0] = cyg_tolower (*p);
-      dst[1] = ':';
-      strcpy (dst + 2, p + 1);
-      backslashify (dst, dst, !dst[2]);
-      unit = dst[0];
-      res = 1;
-    }
-  debug_printf ("src '%s', dst '%s'", src, dst);
-  return res;
-}
-
-/* conv_to_posix_path: Ensure src_path is a POSIX path.
-
-   The result is zero for success, or an errno value.
-   posix_path must have sufficient space (i.e. NT_MAX_PATH bytes).
-   If keep_rel_p is non-zero, relative paths stay that way.  */
-
-/* TODO: Change conv_to_posix_path to work with native paths. */
-
-/* src_path is a wide Win32 path. */
-int
-mount_info::conv_to_posix_path (PWCHAR src_path, char *posix_path,
-                               int keep_rel_p)
-{
-  bool changed = false;
-  if (!wcsncmp (src_path, L"\\\\?\\", 4))
-    {
-      src_path += 4;
-      if (!wcsncmp (src_path, L"UNC\\", 4))
-       {
-         src_path += 2;
-         src_path[0] = L'\\';
-         changed = true;
-       }
-    }
-  tmp_pathbuf tp;
-  char *buf = tp.c_get ();
-  sys_wcstombs (buf, NT_MAX_PATH, src_path);
-  int ret = conv_to_posix_path (buf, posix_path, keep_rel_p);
-  if (changed)
-    src_path[0] = L'C';
-  return ret;
-}
-
-int
-mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
-                               int keep_rel_p)
-{
-  int src_path_len = strlen (src_path);
-  int relative_path_p = !isabspath (src_path);
-  int trailing_slash_p;
-
-  if (src_path_len <= 1)
-    trailing_slash_p = 0;
-  else
-    {
-      const char *lastchar = src_path + src_path_len - 1;
-      trailing_slash_p = isdirsep (*lastchar) && lastchar[-1] != ':';
-    }
-
-  debug_printf ("conv_to_posix_path (%s, %s, %s)", src_path,
-               keep_rel_p ? "keep-rel" : "no-keep-rel",
-               trailing_slash_p ? "add-slash" : "no-add-slash");
-  MALLOC_CHECK;
-
-  if (src_path_len >= NT_MAX_PATH)
-    {
-      debug_printf ("ENAMETOOLONG");
-      return ENAMETOOLONG;
-    }
-
-  /* FIXME: For now, if the path is relative and it's supposed to stay
-     that way, skip mount table processing. */
-
-  if (keep_rel_p && relative_path_p)
-    {
-      slashify (src_path, posix_path, 0);
-      debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
-      return 0;
-    }
-
-  tmp_pathbuf tp;
-  char *pathbuf = tp.c_get ();
-  char *tail;
-  int rc = normalize_win32_path (src_path, pathbuf, tail);
-  if (rc != 0)
-    {
-      debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
-      return rc;
-    }
-
-  int pathbuflen = tail - pathbuf;
-  for (int i = 0; i < nmounts; ++i)
-    {
-      mount_item &mi = mount[native_sorted[i]];
-      if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
-       continue;
-
-      if (cygheap->root.exists () && !cygheap->root.posix_ok (mi.posix_path))
-       continue;
-
-      /* SRC_PATH is in the mount table. */
-      int nextchar;
-      const char *p = pathbuf + mi.native_pathlen;
-
-      if (!*p || !p[1])
-       nextchar = 0;
-      else if (isdirsep (*p))
-       nextchar = -1;
-      else
-       nextchar = 1;
-
-      int addslash = nextchar > 0 ? 1 : 0;
-      if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= NT_MAX_PATH)
-       return ENAMETOOLONG;
-      strcpy (posix_path, mi.posix_path);
-      if (addslash)
-       strcat (posix_path, "/");
-      if (nextchar)
-       slashify (p,
-                 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
-                 trailing_slash_p);
-
-      if (cygheap->root.exists ())
-       {
-         const char *p = cygheap->root.unchroot (posix_path);
-         memmove (posix_path, p, strlen (p) + 1);
-       }
-#if 0
-      if (mi.flags & MOUNT_ENC)
-       {
-         char *tmpbuf = tp.c_get ();
-         if (fnunmunge (tmpbuf, posix_path))
-           strcpy (posix_path, tmpbuf);
-       }
-#endif
-      goto out;
-    }
-
-  if (!cygheap->root.exists ())
-    /* nothing */;
-  else if (!cygheap->root.ischroot_native (pathbuf))
-    return ENOENT;
-  else
-    {
-      const char *p = pathbuf + cygheap->root.native_length ();
-      if (*p)
-       slashify (p, posix_path, trailing_slash_p);
-      else
-       {
-         posix_path[0] = '/';
-         posix_path[1] = '\0';
-       }
-      goto out;
-    }
-
-  /* Not in the database.  This should [theoretically] only happen if either
-     the path begins with //, or / isn't mounted, or the path has a drive
-     letter not covered by the mount table.  If it's a relative path then the
-     caller must want an absolute path (otherwise we would have returned
-     above).  So we always return an absolute path at this point. */
-  if (isdrive (pathbuf))
-    cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p);
-  else
-    {
-      /* The use of src_path and not pathbuf here is intentional.
-        We couldn't translate the path, so just ensure no \'s are present. */
-      slashify (src_path, posix_path, trailing_slash_p);
-    }
-
-out:
-  debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
-  MALLOC_CHECK;
-  return 0;
-}
-
-/* Return flags associated with a mount point given the win32 path. */
-
-unsigned
-mount_info::set_flags_from_win32_path (const char *p)
-{
-  for (int i = 0; i < nmounts; i++)
-    {
-      mount_item &mi = mount[native_sorted[i]];
-      if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
-       return mi.flags;
-    }
-  return PATH_BINARY;
-}
-
-inline char *
-skip_ws (char *in)
-{
-  while (*in == ' ' || *in == '\t')
-    ++in;
-  return in;
-}
-
-inline char *
-find_ws (char *in)
-{
-  while (*in && *in != ' ' && *in != '\t')
-    ++in;
-  return in;
-}
-
-inline char *
-conv_fstab_spaces (char *field)
-{
-  register char *sp = field;
-  while (sp = strstr (sp, "\\040"))
-    {
-      *sp++ = ' ';
-      memmove (sp, sp + 3, strlen (sp + 3) + 1);
-    }
-  return field;
-}
-
-struct opt
-{   
-  const char *name;
-  unsigned val;
-  bool clear;
-} oopts[] =
-{
-  {"user", MOUNT_SYSTEM, 1},
-  {"nouser", MOUNT_SYSTEM, 0},
-  {"binary", MOUNT_BINARY, 0},
-  {"text", MOUNT_BINARY, 1},
-  {"exec", MOUNT_EXEC, 0},
-  {"notexec", MOUNT_NOTEXEC, 0},
-  {"cygexec", MOUNT_CYGWIN_EXEC, 0},
-  {"nosuid", 0, 0},
-  {"managed", MOUNT_ENC, 0}
-};
-
-static bool
-read_flags (char *options, unsigned &flags)
-{
-  while (*options)
-    {
-      char *p = strchr (options, ',');
-      if (p)
-        *p++ = '\0';
-      else
-        p = strchr (options, '\0');
-
-      for (opt *o = oopts;
-          o < (oopts + (sizeof (oopts) / sizeof (oopts[0])));
-          o++)
-        if (strcmp (options, o->name) == 0)
-          {
-            if (o->clear)
-              flags &= ~o->val;
-            else
-              flags |= o->val;
-            goto gotit;
-          }
-      system_printf ("invalid fstab option - '%s'", options);
-      return false;
-
-    gotit:
-      options = p;
-    }
-  return true;
-}
-
-bool
-mount_info::from_fstab_line (char *line, bool user)
-{
-  char *native_path, *posix_path, *fs_type;
-
-  /* First field: Native path. */
-  char *c = skip_ws (line);
-  if (!*c || *c == '#')
-    return true;
-  char *cend = find_ws (c);
-  *cend = '\0';
-  native_path = conv_fstab_spaces (c);
-  /* Second field: POSIX path. */
-  c = skip_ws (cend + 1);
-  if (!*c)
-    return true;
-  cend = find_ws (c);
-  *cend = '\0';
-  posix_path = conv_fstab_spaces (c);
-  /* Third field: FS type. */
-  c = skip_ws (cend + 1);
-  if (!*c)
-    return true;
-  cend = find_ws (c);
-  *cend = '\0';
-  fs_type = c;
-  /* Forth field: Flags. */
-  c = skip_ws (cend + 1);
-  if (!*c)
-    return true;
-  cend = find_ws (c);
-  *cend = '\0';
-  unsigned mount_flags = MOUNT_SYSTEM;
-  if (!read_flags (c, mount_flags))
-    return true;
-  if (user)
-    mount_flags &= ~MOUNT_SYSTEM;
-  if (!strcmp (fs_type, "cygdrive"))
-    {
-      cygdrive_flags = mount_flags | MOUNT_CYGDRIVE;
-      slashify (posix_path, cygdrive, 1);
-      cygdrive_len = strlen (cygdrive);
-    }
-  else
-    {
-      int res = mount_table->add_item (native_path, posix_path, mount_flags);
-      if (res && get_errno () == EMFILE)
-       return false;
-    }
-  return true;
-}
-
-bool
-mount_info::from_fstab (bool user)
-{
-  tmp_pathbuf tp;
-  PWCHAR path = tp.w_get ();
-  PWCHAR w;
-  
-  if (!GetModuleFileNameW (GetModuleHandleW (L"cygwin1.dll"),
-                          path, NT_MAX_PATH))
-    {
-      debug_printf ("GetModuleFileNameW, %E");
-      return false;
-    }
-  w = wcsrchr (path, L'\\');
-  if (w)
-    {
-      *w = L'\0';
-      w = wcsrchr (path, L'\\');
-    }
-  if (!w)
-    {
-      debug_printf ("Invalid DLL path");
-      return false;
-    }
-
-  if (!user)
-    {
-      /* Create a default root dir from the path the Cygwin DLL is in. */
-      *w = L'\0';
-      char *native_root = tp.c_get ();
-      sys_wcstombs (native_root, NT_MAX_PATH, path);
-      mount_table->add_item (native_root, "/", MOUNT_SYSTEM | MOUNT_BINARY);
-      /* Create a default cygdrive entry.  Note that this is a user entry.
-         This allows to override it with mount, unless the sysadmin created
-        a cygdrive entry in /etc/fstab. */
-      cygdrive_flags = MOUNT_BINARY | MOUNT_CYGDRIVE;
-      strcpy (cygdrive, "/cygdrive/");
-      cygdrive_len = strlen (cygdrive);
-    }
-
-  PWCHAR u = wcpcpy (w, L"\\etc\\fstab");
-  if (user)
-    sys_mbstowcs (wcpcpy (u, L"."), NT_MAX_PATH - (u - path),
-                 cygheap->user.name ());
-  debug_printf ("Try to read mounts from %W", path);
-  HANDLE h = CreateFileW (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih,
-                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-  if (h == INVALID_HANDLE_VALUE)
-    {
-      debug_printf ("CreateFileW, %E");
-      return false;
-    }
-  char *const buf = reinterpret_cast<char *const> (path);
-  char *got = buf;
-  DWORD len = 0;
-  /* Using NT_MAX_PATH-1 leaves space to append two \0. */
-  while (ReadFile (h, got, (NT_MAX_PATH - 1) * sizeof (WCHAR) - (got - buf),
-                  &len, NULL))
-    {
-      char *end;
-
-      /* Set end marker. */
-      got[len] = got[len + 1] = '\0';
-      /* Set len to the absolute len of bytes in buf. */
-      len += got - buf;
-      /* Reset got to start reading at the start of the buffer again. */
-      got = buf;
-      while (got < buf + len && (end = strchr (got, '\n')))
-        {
-         end[end[-1] == '\r' ? -1 : 0] = '\0';
-         if (!from_fstab_line (got, user))
-           goto done;
-         got = end + 1;
-       }
-      if (len < (NT_MAX_PATH - 1) * sizeof (WCHAR))
-        break;
-      /* We have to read once more.  Move remaining bytes to the start of
-         the buffer and reposition got so that it points to the end of
-        the remaining bytes. */
-      len = buf + len - got;
-      memmove (buf, got, len);
-      got = buf + len;
-      buf[len] = buf[len + 1] = '\0';
-    }
-  if (got > buf)
-    from_fstab_line (got, user);
-done:
-  CloseHandle (h);
-  return true;
-}
-
-/* read_mounts: Given a specific regkey, read mounts from under its
-   key. */
-/* FIXME: Remove before releasing 1.7.0. */
-
-void
-mount_info::read_mounts (reg_key& r)
-{
-  tmp_pathbuf tp;
-  char *native_path = tp.c_get ();
-  /* FIXME: The POSIX path is stored as value name right now, which is
-     restricted to 256 bytes. */
-  char posix_path[CYG_MAX_PATH];
-  HKEY key = r.get_key ();
-  DWORD i, posix_path_size;
-  int res;
-
-  /* Loop through subkeys */
-  /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
-     shared area is currently statically allocated so we can't have an
-     arbitrarily large number of mounts. */
-  for (i = 0; ; i++)
-    {
-      int mount_flags;
-
-      posix_path_size = sizeof (posix_path);
-      /* FIXME: if maximum posix_path_size is 256, we're going to
-        run into problems if we ever try to store a mount point that's
-        over 256 but is under CYG_MAX_PATH. */
-      res = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
-                         NULL, NULL, NULL);
-
-      if (res == ERROR_NO_MORE_ITEMS)
-       break;
-      else if (res != ERROR_SUCCESS)
-       {
-         debug_printf ("RegEnumKeyEx failed, error %d!", res);
-         break;
-       }
-
-      /* Get a reg_key based on i. */
-      reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
-
-      /* Fetch info from the subkey. */
-      subkey.get_string ("native", native_path, NT_MAX_PATH, "");
-      mount_flags = subkey.get_int ("flags", 0);
-
-      /* Add mount_item corresponding to registry mount point. */
-      res = mount_table->add_item (native_path, posix_path, mount_flags);
-      if (res && get_errno () == EMFILE)
-       break; /* The number of entries exceeds MAX_MOUNTS */
-    }
-}
-
-/* from_registry: Build the entire mount table from the registry.  Also,
-   read in cygdrive-related information from its registry location. */
-/* FIXME: Remove before releasing 1.7.0. */
-
-void
-mount_info::from_registry ()
-{
-
-  /* Retrieve cygdrive-related information. */
-  read_cygdrive_info_from_registry ();
-
-  nmounts = 0;
-
-  /* First read mounts from user's table.
-     Then read mounts from system-wide mount table while deimpersonated . */
-  for (int i = 0; i < 2; i++)
-    {
-      if (i)
-       cygheap->user.deimpersonate ();
-      reg_key r (i, KEY_READ, CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
-      read_mounts (r);
-      if (i)
-       cygheap->user.reimpersonate ();
-    }
-}
-
-/* read_cygdrive_info_from_registry: Read the default prefix and flags
-   to use when creating cygdrives from the special user registry
-   location used to store cygdrive information. */
-/* FIXME: Remove before releasing 1.7.0. */
-
-void
-mount_info::read_cygdrive_info_from_registry ()
-{
-  /* First read cygdrive from user's registry.
-     If failed, then read cygdrive from system-wide registry
-     while deimpersonated. */
-  for (int i = 0; i < 2; i++)
-    {
-      if (i)
-       cygheap->user.deimpersonate ();
-      reg_key r (i, KEY_READ, CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
-      if (i)
-       cygheap->user.reimpersonate ();
-
-      if (r.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive),
-                       CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX) != ERROR_SUCCESS && i == 0)
-       continue;
-
-      /* Fetch user cygdrive_flags from registry; returns MOUNT_CYGDRIVE on error. */
-      cygdrive_flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS,
-                                 MOUNT_CYGDRIVE | MOUNT_BINARY);
-      /* Sanitize */
-      if (i == 0)
-       cygdrive_flags &= ~MOUNT_SYSTEM;
-      else
-       cygdrive_flags |= MOUNT_SYSTEM;
-      slashify (cygdrive, cygdrive, 1);
-      cygdrive_len = strlen (cygdrive);
-      break;
-    }
-}
-
-/* write_cygdrive_info: Store default prefix and flags
-   to use when creating cygdrives to the special user shared mem
-   location used to store cygdrive information. */
-
-int
-mount_info::write_cygdrive_info (const char *cygdrive_prefix, unsigned flags)
-{
-  /* Verify cygdrive prefix starts with a forward slash and if there's
-     another character, it's not a slash. */
-  if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
-      (!isslash (cygdrive_prefix[0])) ||
-      ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
-    {
-      set_errno (EINVAL);
-      return -1;
-    }
-  /* Don't allow to override a system cygdrive prefix. */
-  if (cygdrive_flags & MOUNT_SYSTEM)
-    {
-      set_errno (EPERM);
-      return -1;
-    }
-
-  slashify (cygdrive_prefix, cygdrive, 1);
-  cygdrive_flags = flags & ~MOUNT_SYSTEM;
-  cygdrive_len = strlen (cygdrive);
-
-  return 0;
-}
-
-int
-mount_info::get_cygdrive_info (char *user, char *system, char* user_flags,
-                              char* system_flags)
-{
-  if (user)
-    *user = '\0';
-  /* Get the user flags, if appropriate */
-  if (user_flags)
-    *user_flags = '\0';
-
-  if (system)
-    strcpy (system, cygdrive);
-
-  if (system_flags)
-    strcpy (system_flags,
-           (cygdrive_flags & MOUNT_BINARY) ? "binmode" : "textmode");
-
-  return 0;
-}
-
-static mount_item *mounts_for_sort;
-
-/* sort_by_posix_name: qsort callback to sort the mount entries.  Sort
-   user mounts ahead of system mounts to the same POSIX path. */
-/* FIXME: should the user should be able to choose whether to
-   prefer user or system mounts??? */
-static int
-sort_by_posix_name (const void *a, const void *b)
-{
-  mount_item *ap = mounts_for_sort + (*((int*) a));
-  mount_item *bp = mounts_for_sort + (*((int*) b));
-
-  /* Base weighting on longest posix path first so that the most
-     obvious path will be chosen. */
-  size_t alen = strlen (ap->posix_path);
-  size_t blen = strlen (bp->posix_path);
-
-  int res = blen - alen;
-
-  if (res)
-    return res;                /* Path lengths differed */
-
-  /* The two paths were the same length, so just determine normal
-     lexical sorted order. */
-  res = strcmp (ap->posix_path, bp->posix_path);
-
-  if (res == 0)
-   {
-     /* need to select between user and system mount to same POSIX path */
-     if (!(bp->flags & MOUNT_SYSTEM))  /* user mount */
-      return 1;
-     else
-      return -1;
-   }
-
-  return res;
-}
-
-/* sort_by_native_name: qsort callback to sort the mount entries.  Sort
-   user mounts ahead of system mounts to the same POSIX path. */
-/* FIXME: should the user should be able to choose whether to
-   prefer user or system mounts??? */
-static int
-sort_by_native_name (const void *a, const void *b)
-{
-  mount_item *ap = mounts_for_sort + (*((int*) a));
-  mount_item *bp = mounts_for_sort + (*((int*) b));
-
-  /* Base weighting on longest win32 path first so that the most
-     obvious path will be chosen. */
-  size_t alen = strlen (ap->native_path);
-  size_t blen = strlen (bp->native_path);
-
-  int res = blen - alen;
-
-  if (res)
-    return res;                /* Path lengths differed */
-
-  /* The two paths were the same length, so just determine normal
-     lexical sorted order. */
-  res = strcmp (ap->native_path, bp->native_path);
-
-  if (res == 0)
-   {
-     /* need to select between user and system mount to same POSIX path */
-     if (!(bp->flags & MOUNT_SYSTEM))  /* user mount */
-      return 1;
-     else
-      return -1;
-   }
-
-  return res;
-}
-
-void
-mount_info::sort ()
-{
-  for (int i = 0; i < nmounts; i++)
-    native_sorted[i] = posix_sorted[i] = i;
-  /* Sort them into reverse length order, otherwise we won't
-     be able to look for /foo in /.  */
-  mounts_for_sort = mount;     /* ouch. */
-  qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
-  qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
-}
-
-/* Add an entry to the mount table.
-   Returns 0 on success, -1 on failure and errno is set.
-
-   This is where all argument validation is done.  It may not make sense to
-   do this when called internally, but it's cleaner to keep it all here.  */
-
-int
-mount_info::add_item (const char *native, const char *posix,
-                     unsigned mountflags)
-{
-  tmp_pathbuf tp;
-  char *nativetmp = tp.c_get ();
-  /* FIXME: The POSIX path is stored as value name right now, which is
-     restricted to 256 bytes. */
-  char posixtmp[CYG_MAX_PATH];
-  char *nativetail, *posixtail, error[] = "error";
-  int nativeerr, posixerr;
-
-  /* Something's wrong if either path is NULL or empty, or if it's
-     not a UNC or absolute path. */
-
-  if (native == NULL || !isabspath (native) ||
-      !(is_unc_share (native) || isdrive (native)))
-    nativeerr = EINVAL;
-  else
-    nativeerr = normalize_win32_path (native, nativetmp, nativetail);
-
-  if (posix == NULL || !isabspath (posix) ||
-      is_unc_share (posix) || isdrive (posix))
-    posixerr = EINVAL;
-  else
-    posixerr = normalize_posix_path (posix, posixtmp, posixtail);
-
-  debug_printf ("%s[%s], %s[%s], %p",
-               native, nativeerr ? error : nativetmp,
-               posix, posixerr ? error : posixtmp, mountflags);
-
-  if (nativeerr || posixerr)
-    {
-      set_errno (nativeerr?:posixerr);
-      return -1;
-    }
-
-  /* Make sure both paths do not end in /. */
-  if (nativetail > nativetmp + 1 && nativetail[-1] == '\\')
-    nativetail[-1] = '\0';
-  if (posixtail > posixtmp + 1 && posixtail[-1] == '/')
-    posixtail[-1] = '\0';
-
-  /* Write over an existing mount item with the same POSIX path if
-     it exists and is from the same registry area. */
-  int i;
-  for (i = 0; i < nmounts; i++)
-    {
-      if (strcasematch (mount[i].posix_path, posixtmp))
-        {
-         /* Don't allow to override a system mount with a user mount. */
-         if ((mount[i].flags & MOUNT_SYSTEM) && !(mountflags & MOUNT_SYSTEM))
-           {
-             set_errno (EPERM);
-             return -1;
-           }
-         if ((mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM))
-           break;
-       }
-    }
-
-  if (i == nmounts && nmounts == MAX_MOUNTS)
-    {
-      set_errno (EMFILE);
-      return -1;
-    }
-
-  if (i == nmounts)
-    nmounts++;
-  mount[i].init (nativetmp, posixtmp, mountflags);
-  sort ();
-
-  return 0;
-}
-
-/* Delete a mount table entry where path is either a Win32 or POSIX
-   path. Since the mount table is really just a table of aliases,
-   deleting / is ok (although running without a slash mount is
-   strongly discouraged because some programs may run erratically
-   without one).  If MOUNT_SYSTEM is set in flags, remove from system
-   registry, otherwise remove the user registry mount.
-*/
-
-int
-mount_info::del_item (const char *path, unsigned flags)
-{
-  tmp_pathbuf tp;
-  char *pathtmp = tp.c_get ();
-  int posix_path_p = false;
-
-  /* Something's wrong if path is NULL or empty. */
-  if (path == NULL || *path == 0 || !isabspath (path))
-    {
-      set_errno (EINVAL);
-      return -1;
-    }
-
-  if (is_unc_share (path) || strpbrk (path, ":\\"))
-    backslashify (path, pathtmp, 0);
-  else
-    {
-      slashify (path, pathtmp, 0);
-      posix_path_p = true;
-    }
-  nofinalslash (pathtmp, pathtmp);
-
-  for (int i = 0; i < nmounts; i++)
-    {
-      int ent = native_sorted[i]; /* in the same order as getmntent() */
-      if (((posix_path_p)
-          ? strcasematch (mount[ent].posix_path, pathtmp)
-          : strcasematch (mount[ent].native_path, pathtmp)))
-       {
-         /* Don't allow to remove a system mount. */
-         if ((mount[ent].flags & MOUNT_SYSTEM))
-           {
-             set_errno (EPERM);
-             return -1;
-           }
-         nmounts--; /* One less mount table entry */
-         /* Fill in the hole if not at the end of the table */
-         if (ent < nmounts)
-           memmove (mount + ent, mount + ent + 1,
-                    sizeof (mount[ent]) * (nmounts - ent));
-         sort (); /* Resort the table */
-         return 0;
-       }
-    }
-  set_errno (EINVAL);
-  return -1;
-}
-
-/************************* mount_item class ****************************/
-
-static mntent *
-fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
-{
-  struct mntent& ret=_my_tls.locals.mntbuf;
-  bool append_bs = false;
-
-  /* Remove drivenum from list if we see a x: style path */
-  if (strlen (native_path) == 2 && native_path[1] == ':')
-    {
-      int drivenum = cyg_tolower (native_path[0]) - 'a';
-      if (drivenum >= 0 && drivenum <= 31)
-       _my_tls.locals.available_drives &= ~(1 << drivenum);
-      append_bs = true;
-    }
-
-  /* Pass back pointers to mount_table strings reserved for use by
-     getmntent rather than pointers to strings in the internal mount
-     table because the mount table might change, causing weird effects
-     from the getmntent user's point of view. */
-
-  strcpy (_my_tls.locals.mnt_fsname, native_path);
-  ret.mnt_fsname = _my_tls.locals.mnt_fsname;
-  strcpy (_my_tls.locals.mnt_dir, posix_path);
-  ret.mnt_dir = _my_tls.locals.mnt_dir;
-
-  /* Try to give a filesystem type that matches what a Linux application might
-     expect. Naturally, this is a moving target, but we can make some
-     reasonable guesses for popular types. */
-
-  fs_info mntinfo;
-  tmp_pathbuf tp;
-  UNICODE_STRING unat;
-  tp.u_get (&unat);
-  get_nt_native_path (native_path, unat, flags & MOUNT_ENC);
-  if (append_bs)
-    RtlAppendUnicodeToString (&unat, L"\\");
-  mntinfo.update (&unat, true);  /* this pulls from a cache, usually. */
-
-  if (mntinfo.is_samba())
-    strcpy (_my_tls.locals.mnt_type, (char *) "smbfs");
-  else if (mntinfo.is_nfs ())
-    strcpy (_my_tls.locals.mnt_type, (char *) "nfs");
-  else if (mntinfo.is_fat ())
-    strcpy (_my_tls.locals.mnt_type, (char *) "vfat");
-  else if (mntinfo.is_ntfs ())
-    strcpy (_my_tls.locals.mnt_type, (char *) "ntfs");
-  else if (mntinfo.is_netapp ())
-    strcpy (_my_tls.locals.mnt_type, (char *) "netapp");
-  else if (mntinfo.is_cdrom ())
-    strcpy (_my_tls.locals.mnt_type, (char *) "iso9660");
-  else
-    strcpy (_my_tls.locals.mnt_type, (char *) "unknown");
-
-  ret.mnt_type = _my_tls.locals.mnt_type;
-
-  /* mnt_opts is a string that details mount params such as
-     binary or textmode, or exec.  We don't print
-     `silent' here; it's a magic internal thing. */
-
-  if (!(flags & MOUNT_BINARY))
-    strcpy (_my_tls.locals.mnt_opts, (char *) "textmode");
-  else
-    strcpy (_my_tls.locals.mnt_opts, (char *) "binmode");
-
-  if (flags & MOUNT_CYGWIN_EXEC)
-    strcat (_my_tls.locals.mnt_opts, (char *) ",cygexec");
-  else if (flags & MOUNT_EXEC)
-    strcat (_my_tls.locals.mnt_opts, (char *) ",exec");
-  else if (flags & MOUNT_NOTEXEC)
-    strcat (_my_tls.locals.mnt_opts, (char *) ",noexec");
-  if (flags & MOUNT_ENC)
-    strcat (_my_tls.locals.mnt_opts, ",managed");
-
-  if ((flags & MOUNT_CYGDRIVE))                /* cygdrive */
-    strcat (_my_tls.locals.mnt_opts, (char *) ",noumount");
-
-  if (!(flags & MOUNT_SYSTEM))         /* user mount */
-    strcat (_my_tls.locals.mnt_opts, (char *) ",user");
-  else                                 /* system mount */
-    strcat (_my_tls.locals.mnt_opts, (char *) ",system");
-
-  ret.mnt_opts = _my_tls.locals.mnt_opts;
-
-  ret.mnt_freq = 1;
-  ret.mnt_passno = 1;
-  return &ret;
-}
-
-struct mntent *
-mount_item::getmntent ()
-{
-  return fillout_mntent (native_path, posix_path, flags);
-}
-
-static struct mntent *
-cygdrive_getmntent ()
-{
-  char native_path[4];
-  char posix_path[CYG_MAX_PATH];
-  DWORD mask = 1, drive = 'a';
-  struct mntent *ret = NULL;
-
-  while (_my_tls.locals.available_drives)
-    {
-      for (/* nothing */; drive <= 'z'; mask <<= 1, drive++)
-       if (_my_tls.locals.available_drives & mask)
-         break;
-
-      __small_sprintf (native_path, "%c:\\", drive);
-      if (GetFileAttributes (native_path) == INVALID_FILE_ATTRIBUTES)
-       {
-         _my_tls.locals.available_drives &= ~mask;
-         continue;
-       }
-      native_path[2] = '\0';
-      __small_sprintf (posix_path, "%s%c", mount_table->cygdrive, drive);
-      ret = fillout_mntent (native_path, posix_path, mount_table->cygdrive_flags);
-      break;
-    }
-
-  return ret;
-}
-
-struct mntent *
-mount_info::getmntent (int x)
-{
-  if (x < 0 || x >= nmounts)
-    return cygdrive_getmntent ();
-
-  return mount[native_sorted[x]].getmntent ();
-}
-
-/* Fill in the fields of a mount table entry.  */
-
-void
-mount_item::init (const char *native, const char *posix, unsigned mountflags)
-{
-  strcpy ((char *) native_path, native);
-  strcpy ((char *) posix_path, posix);
-
-  native_pathlen = strlen (native_path);
-  posix_pathlen = strlen (posix_path);
-
-  flags = mountflags;
-}
-
-/********************** Mount System Calls **************************/
-
-/* Mount table system calls.
-   Note that these are exported to the application.  */
-
-/* mount: Add a mount to the mount table in memory and to the registry
-   that will cause paths under win32_path to be translated to paths
-   under posix_path. */
-
-extern "C" int
-mount (const char *win32_path, const char *posix_path, unsigned flags)
-{
-  int res = -1;
-  flags &= ~MOUNT_SYSTEM;
-
-  myfault efault;
-  if (efault.faulted (EFAULT))
-    /* errno set */;
-  else if (!*posix_path)
-    set_errno (EINVAL);
-  else if (strpbrk (posix_path, "\\:"))
-    set_errno (EINVAL);
-  else if (flags & MOUNT_CYGDRIVE) /* normal mount */
-    {
-      /* When flags include MOUNT_CYGDRIVE, take this to mean that
-       we actually want to change the cygdrive prefix and flags
-       without actually mounting anything. */
-      res = mount_table->write_cygdrive_info (posix_path, flags);
-      win32_path = NULL;
-    }
-  else if (!*win32_path)
-    set_errno (EINVAL);
-  else
-    res = mount_table->add_item (win32_path, posix_path, flags);
-
-  syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
-  return res;
-}
-
-/* umount: The standard umount call only has a path parameter.  Since
-   it is not possible for this call to specify whether to remove the
-   mount from the user or global mount registry table, assume the user
-   table. */
-
-extern "C" int
-umount (const char *path)
-{
-  myfault efault;
-  if (efault.faulted (EFAULT))
-    return -1;
-  if (!*path)
-    {
-      set_errno (EINVAL);
-      return -1;
-    }
-  return cygwin_umount (path, 0);
-}
-
-/* cygwin_umount: This is like umount but takes an additional flags
-   parameter that specifies whether to umount from the user or system-wide
-   registry area. */
-
-extern "C" int
-cygwin_umount (const char *path, unsigned flags)
-{
-  int res = -1;
-
-  if (!(flags & MOUNT_CYGDRIVE))
-    res = mount_table->del_item (path, flags & ~MOUNT_SYSTEM);
-
-  syscall_printf ("%d = cygwin_umount (%s, %d)", res,  path, flags);
-  return res;
-}
-
-bool
-is_floppy (const char *dos)
-{
-  char dev[256];
-  if (!QueryDosDevice (dos, dev, 256))
-    return false;
-  return ascii_strncasematch (dev, "\\Device\\Floppy", 14);
-}
-
-extern "C" FILE *
-setmntent (const char *filep, const char *)
-{
-  _my_tls.locals.iteration = 0;
-  _my_tls.locals.available_drives = GetLogicalDrives ();
-  /* Filter floppy drives on A: and B: */
-  if ((_my_tls.locals.available_drives & 1) && is_floppy ("A:"))
-    _my_tls.locals.available_drives &= ~1;
-  if ((_my_tls.locals.available_drives & 2) && is_floppy ("B:"))
-    _my_tls.locals.available_drives &= ~2;
-  return (FILE *) filep;
-}
-
-extern "C" struct mntent *
-getmntent (FILE *)
-{
-  return mount_table->getmntent (_my_tls.locals.iteration++);
-}
-
-extern "C" int
-endmntent (FILE *)
-{
-  return 1;
-}
-
-/********************** Symbolic Link Support **************************/
-
-/* Create a symlink from FROMPATH to TOPATH. */
-
-/* If TRUE create symlinks as Windows shortcuts, if false create symlinks
-   as normal files with magic number and system bit set. */
-bool allow_winsymlinks = true;
-
-extern "C" int
-symlink (const char *oldpath, const char *newpath)
-{
-  return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
-}
-
-int
-symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
-               bool isdevice)
-{
-  int res = -1;
-  size_t len;
-  path_conv win32_newpath, win32_oldpath;
-  char *buf, *cp;
-  SECURITY_ATTRIBUTES sa = sec_none_nih;
-  security_descriptor sd;
-  OBJECT_ATTRIBUTES attr;
-  IO_STATUS_BLOCK io;
-  NTSTATUS status;
-  HANDLE fh;
-  FILE_BASIC_INFORMATION fbi;
-  tmp_pathbuf tp;
-
-  /* POSIX says that empty 'newpath' is invalid input while empty
-     'oldpath' is valid -- it's symlink resolver job to verify if
-     symlink contents point to existing filesystem object */
-  myfault efault;
-  if (efault.faulted (EFAULT))
-    goto done;
-  if (!*oldpath || !*newpath)
-    {
-      set_errno (ENOENT);
-      goto done;
-    }
-
-  if (strlen (oldpath) > SYMLINK_MAX)
-    {
-      set_errno (ENAMETOOLONG);
-      goto done;
-    }
-
-  len = strlen (newpath);
-  /* Trailing dirsep is a no-no. */
-  if (isdirsep (newpath[len - 1]))
-    {
-      set_errno (ENOENT);
-      goto done;
-    }
-  /* We need the normalized full path below. */
-  win32_newpath.check (newpath, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
-  if (use_winsym && !win32_newpath.exists ())
-    {
-      char *newplnk = tp.c_get ();
-      stpcpy (stpcpy (newplnk, newpath), ".lnk");
-      win32_newpath.check (newplnk, PC_SYM_NOFOLLOW | PC_POSIX);
-    }
-
-  if (win32_newpath.error)
-    {
-      set_errno (win32_newpath.case_clash ? ECASECLASH : win32_newpath.error);
-      goto done;
-    }
-
-  syscall_printf ("symlink (%s, %S)", oldpath,
-                 win32_newpath.get_nt_native_path ());
-
-  if ((!isdevice && win32_newpath.exists ())
-      || win32_newpath.is_auto_device ())
-    {
-      set_errno (EEXIST);
-      goto done;
-    }
-
-  if (use_winsym)
-    {
-      ITEMIDLIST *pidl = NULL;
-      size_t full_len = 0;
-      unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
-      char desc[MAX_PATH + 1], *relpath;
-
-      if (!isdevice)
-       {
-         /* First create an IDLIST to learn how big our shortcut is
-            going to be. */
-         IShellFolder *psl;
-
-         /* The symlink target is relative to the directory in which
-            the symlink gets created, not relative to the cwd.  Therefore
-            we have to mangle the path quite a bit before calling path_conv. */
-         if (!isabspath (oldpath))
-           {
-             len = strrchr (win32_newpath.normalized_path, '/')
-                   - win32_newpath.normalized_path + 1;
-             char *absoldpath = tp.t_get ();
-             stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
-                     oldpath);
-             win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
-           }
-         else
-           win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
-         if (SUCCEEDED (SHGetDesktopFolder (&psl)))
-           {
-             WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
-             win32_oldpath.get_wide_win32_path (wc_path);
-             /* Amazing but true:  Even though the ParseDisplayName method
-                takes a wide char path name, it does not understand the
-                Win32 prefix for long pathnames!  So we have to tack off
-                the prefix and convert tyhe path to the "normal" syntax
-                for ParseDisplayName.  I have no idea if it's able to take
-                long path names at all since I can't test it right now. */
-             WCHAR *wc = wc_path + 4;
-             if (!wcscmp (wc, L"UNC\\"))
-               *(wc += 2) = L'\\';
-             HRESULT res;
-             if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
-                                                   &pidl, NULL)))
-               {
-                 ITEMIDLIST *p;
-
-                 for (p = pidl; p->mkid.cb > 0;
-                      p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
-                   ;
-                 pidl_len = (char *) p - (char *) pidl + 2;
-               }
-             psl->Release ();
-           }
+                 for (p = pidl; p->mkid.cb > 0;
+                      p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
+                   ;
+                 pidl_len = (char *) p - (char *) pidl + 2;
+               }
+             psl->Release ();
+           }
        }
       /* Compute size of shortcut file. */
       full_len = sizeof (win_shortcut_hdr);
@@ -4239,7 +2596,7 @@ hash_path_name (__ino64_t hash, const char *name)
   return ret;
 }
 
-char *
+extern "C" char *
 getcwd (char *buf, size_t ulen)
 {
   char* res = NULL;
index f5bdbcfe7b23f852f573b529a129a16ae7b43530..e121280ce421289aad5c8acfc8e06d5d01c530b2 100644 (file)
@@ -331,6 +331,9 @@ bool fnunmunge (char *, const char *) __attribute__ ((regparm (2)));
 int path_prefix_p (const char *path1, const char *path2, int len1) __attribute__ ((regparm (3)));
 
 bool is_floppy (const char *);
+int normalize_win32_path (const char *, char *, char *&);
+int normalize_posix_path (const char *, char *, char *&);
+PUNICODE_STRING get_nt_native_path (const char *, UNICODE_STRING&, bool);
 
 /* FIXME: Move to own include file eventually */
 
index 6730e8a95763be09400fc1ab2de79d82fb3069bc..0ff3d09fdab018e12027302b03226f068bbe48ea 100644 (file)
@@ -10,6 +10,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <stdlib.h>
 #include <time.h>
 #include <limits.h>
index d7c80cd1baab42fb837307f606b8e02ebec27e0a..90133d8cb4157b375fd5ea02b9cf972ae7e88f21 100644 (file)
@@ -15,6 +15,7 @@
 #endif
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <limits.h>
 #include "cygerrno.h"
 #include <assert.h>
index 9afe9ff13fcf0faff9a2ea3251d90aec4529e1fd..431e5e3a2ab5d6e72f394fe9104d149337b38369 100644 (file)
@@ -10,6 +10,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
index becff92a30b471d42a07272851d6e27cf4c30d49..00c1a03fb0c12cc08be0712a9f634ea274ac900c 100644 (file)
@@ -12,6 +12,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <stdlib.h>
 #include <time.h>
 #include <sys/wait.h>
index e539e38936cceb7bf9e1ab3228678b507ed01ab3..18c971a453b86f0069528268941cbaa3afcb9714 100644 (file)
@@ -15,6 +15,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <stdlib.h>
 #include <time.h>
 #include <sys/wait.h>
index 2d16085b8bf88620ae5aa365e50b99b038c10925..16a632d3332f6e19cf583a5e254c0976d410e098 100644 (file)
@@ -24,6 +24,7 @@ details. */
 #define pwrite __FOO_pwrite
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <sys/stat.h>
 #include <sys/vfs.h> /* needed for statfs */
 #include <sys/statvfs.h> /* needed for statvfs */
index c961b6dec2cb00a479010c52afbf5c2754e64697..68cfa814391c4a1375abf5a576d73e5602855cd7 100644 (file)
@@ -28,6 +28,7 @@ details. */
 #endif
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <limits.h>
 #include "path.h"
 #include "cygerrno.h"
index 20d622f9f66bc6ba7fbfa09352ec87aa2c1056c2..61dc645cbb5017264ae4a597fe60dd2a1e4aece4 100644 (file)
@@ -10,6 +10,7 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <unistd.h>
 #include <utmp.h>
 #include <wingdi.h>
index 7e6e1cd19d4145cea06adca55f574ee112b8d47e..68a0c2b7b37a346f9261b38fc7248f47f1142778 100644 (file)
@@ -45,8 +45,8 @@ details. */
 #ifdef __cplusplus
 extern "C" {
 #endif
-extern __uid32_t getuid32 (void);
-extern __uid32_t geteuid32 (void);
+extern __uid32_t getuid32 ();
+extern __uid32_t geteuid32 ();
 extern int seteuid32 (__uid32_t);
 extern __gid32_t getegid32 (void);
 extern struct passwd *getpwuid32 (__uid32_t);
@@ -119,9 +119,6 @@ extern UINT active_codepage;
 
 void codepage_init (const char *buf);
 UINT get_cp ();
-bool is_cp_multibyte (UINT cp);
-const unsigned char *next_char (UINT cp, const unsigned char *str,
-                               const unsigned char *end);
 
 /* Used as type by sys_wcstombs_alloc and sys_mbstowcs_alloc.  For a
    description see there. */
@@ -296,14 +293,8 @@ void init_console_handler (bool);
 
 void init_global_security ();
 
-int __stdcall check_invalid_virtual_addr (const void *s, unsigned sz) __attribute__ ((regparm(2)));
-
-ssize_t check_iovec (const struct iovec *, int, bool) __attribute__ ((regparm(3)));
-#define check_iovec_for_read(a, b) check_iovec ((a), (b), false)
-#define check_iovec_for_write(a, b) check_iovec ((a), (b), true)
-
-#define set_winsock_errno() __set_winsock_errno (__FUNCTION__, __LINE__)
 void __set_winsock_errno (const char *fn, int ln) __attribute__ ((regparm(2)));
+#define set_winsock_errno() __set_winsock_errno (__FUNCTION__, __LINE__)
 
 extern bool wsock_started;
 
@@ -328,9 +319,6 @@ int __stdcall stat_worker (path_conv &pc, struct __stat64 *buf) __attribute__ ((
 
 __ino64_t __stdcall readdir_get_ino (const char *path, bool dot_dot) __attribute__ ((regparm (2)));
 
-extern "C" int low_priority_sleep (DWORD) __attribute__ ((regparm (1)));
-#define SLEEP_0_STAY_LOW INFINITE
-
 /* Returns the real page size, not the allocation size. */
 size_t getsystempagesize ();
 
@@ -343,13 +331,6 @@ enum mmap_region_status
   };
 mmap_region_status mmap_is_attached_or_noreserve (void *addr, size_t len);
 
-int winprio_to_nice (DWORD) __attribute__ ((regparm (1)));
-DWORD nice_to_winprio (int &) __attribute__ ((regparm (1)));
-
-bool __stdcall create_pipe (PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD)
-  __attribute__ ((regparm (3)));
-#define CreatePipe create_pipe
-
 inline bool flush_file_buffers (HANDLE h)
 {
   return (GetFileType (h) != FILE_TYPE_PIPE) ? FlushFileBuffers (h) : true;
This page took 0.111799 seconds and 5 git commands to generate.