From c2e033e25d220b9aac43cbc73c4e4f6ec7d41d5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?=
 =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= <alexey.pawlow@gmail.com>
Date: Sun, 14 Apr 2019 21:45:06 +0300
Subject: [PATCH 05/N] - Move root to /usr. - Change sorting mount points. -
 By default mount without ACLs. - Can read /etc/fstab with short mount point
 format.

---
 winsup/cygwin/local_includes/mount.h |   3 +-
 winsup/cygwin/mm/cygheap.cc          |  12 +-
 winsup/cygwin/mount.cc               | 185 +++++++++++++++++++++++----
 winsup/cygwin/uinfo.cc               |   2 +-
 4 files changed, 174 insertions(+), 28 deletions(-)

diff --git a/winsup/cygwin/local_includes/mount.h b/winsup/cygwin/local_includes/mount.h
index 163b475..15e9a34 100644
--- a/winsup/cygwin/local_includes/mount.h
+++ b/winsup/cygwin/local_includes/mount.h
@@ -173,7 +173,6 @@ class mount_info
   mount_item mount[MAX_MOUNTS];
 
   static bool got_usr_bin;
-  static bool got_usr_lib;
   static int root_idx;
 
   /* cygdrive_prefix is used as the root of the path automatically
@@ -185,6 +184,8 @@ class mount_info
  private:
   int posix_sorted[MAX_MOUNTS];
   int native_sorted[MAX_MOUNTS];
+  int longest_posix_sorted[MAX_MOUNTS];
+  int shortest_native_sorted[MAX_MOUNTS];
 
  public:
   void init (bool);
diff --git a/winsup/cygwin/mm/cygheap.cc b/winsup/cygwin/mm/cygheap.cc
index 1c9b803..4a60995 100644
--- a/winsup/cygwin/mm/cygheap.cc
+++ b/winsup/cygwin/mm/cygheap.cc
@@ -220,14 +220,22 @@ init_cygheap::init_installation_root ()
 
   /* Strip off last path component ("\\cygwin1.dll") */
   PWCHAR w = wcsrchr (installation_root_buf, L'\\');
+#ifdef __MSYS__
+  /* Back two folders to get root as we have all stuff in usr subfolder */
+  for (int i=1; i >=0; --i)
+  {
+#endif
   if (w)
     {
       *w = L'\0';
       w = wcsrchr (installation_root_buf, L'\\');
     }
   if (!w)
-    api_fatal ("Can't initialize Cygwin installation root dir.\n"
+    api_fatal ("Can't initialize MSYS2 installation root dir.\n"
 	       "Invalid DLL path");
+#ifdef __MSYS__
+  }
+#endif
 
   /* Copy result into installation_dir before stripping off "bin" dir and
      revert to Win32 path.  This path is added to the Windows environment
@@ -252,6 +260,7 @@ init_cygheap::init_installation_root ()
   RtlInitUnicodeString (&installation_root, installation_root_buf);
   RtlInitUnicodeString (&installation_dir, installation_dir_buf);
 
+#ifndef __MSYS__
   for (int i = 1; i >= 0; --i)
     {
       reg_key r (i, KEY_WRITE, _WIDE (CYGWIN_INFO_INSTALLATIONS_NAME),
@@ -260,6 +269,7 @@ init_cygheap::init_installation_root ()
 				    installation_root_buf)))
 	break;
     }
+#endif
 }
 
 /* Initialize bucket_val.  The value is the max size of a block
diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc
index 1cfee5c..affb7e9 100644
--- a/winsup/cygwin/mount.cc
+++ b/winsup/cygwin/mount.cc
@@ -42,7 +42,6 @@ details. */
   (path_prefix_p (proc, (path), proc_len, false))
 
 bool NO_COPY mount_info::got_usr_bin;
-bool NO_COPY mount_info::got_usr_lib;
 int NO_COPY mount_info::root_idx = -1;
 
 /* is_native_path: Return non-zero if PATH starts with \??\[a-zA-Z] or
@@ -395,7 +394,6 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
 #define MINIMAL_WIN_NTFS_FLAGS (FILE_CASE_SENSITIVE_SEARCH \
 				| FILE_CASE_PRESERVED_NAMES \
 				| FILE_UNICODE_ON_DISK \
-				| FILE_PERSISTENT_ACLS \
 				| FILE_FILE_COMPRESSION \
 				| FILE_VOLUME_QUOTAS \
 				| FILE_SUPPORTS_SPARSE_FILES \
@@ -552,13 +550,13 @@ mount_info::create_root_entry (const PWCHAR root)
   sys_wcstombs (native_root, PATH_MAX, root);
   assert (*native_root != '\0');
   if (add_item (native_root, "/",
-		MOUNT_SYSTEM | MOUNT_IMMUTABLE | MOUNT_AUTOMATIC)
+		MOUNT_SYSTEM | MOUNT_IMMUTABLE | MOUNT_AUTOMATIC | MOUNT_NOACL)
       < 0)
     api_fatal ("add_item (\"%s\", \"/\", ...) failed, errno %d", native_root, errno);
   /* 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_NOPOSIX | MOUNT_CYGDRIVE;
+  cygdrive_flags = MOUNT_NOPOSIX | MOUNT_CYGDRIVE | MOUNT_NOACL;
   strcpy (cygdrive, CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX "/");
   cygdrive_len = strlen (cygdrive);
 }
@@ -578,22 +576,14 @@ mount_info::init (bool user_init)
   pathend = wcpcpy (pathend, L"\\etc\\fstab");
   from_fstab (user_init, path, pathend);
 
-  if (!user_init && (!got_usr_bin || !got_usr_lib))
+  if (!user_init && !got_usr_bin)
     {
       char native[PATH_MAX];
       if (root_idx < 0)
-	api_fatal ("root_idx %d, user_shared magic %y, nmounts %d", root_idx, user_shared->version, nmounts);
+        api_fatal ("root_idx %d, user_shared magic %y, nmounts %d", root_idx, user_shared->version, nmounts);
       char *p = stpcpy (native, mount[root_idx].native_path);
-      if (!got_usr_bin)
-      {
-	stpcpy (p, "\\bin");
-	add_item (native, "/usr/bin", MOUNT_SYSTEM | MOUNT_AUTOMATIC);
-      }
-      if (!got_usr_lib)
-      {
-	stpcpy (p, "\\lib");
-	add_item (native, "/usr/lib", MOUNT_SYSTEM | MOUNT_AUTOMATIC);
-      }
+      stpcpy (p, "\\usr\\bin");
+      add_item (native, "/bin", MOUNT_SYSTEM | MOUNT_AUTOMATIC | MOUNT_NOACL);
     }
 }
 
@@ -674,6 +664,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
   /* See if this is a cygwin "device" */
   if (win32_device_name (src_path, dst, dev))
     {
+      debug_printf ("win32_device_name (%s)", src_path);
       *flags = 0;
       rc = 0;
       goto out_no_chroot_check;
@@ -711,6 +702,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
     }
   if (isproc (src_path))
     {
+      debug_printf ("isproc (%s)", src_path);
       dev = *proc_dev;
       dev = fhandler_proc::get_proc_fhandler (src_path);
       if (dev == FH_NADA)
@@ -732,6 +724,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
      off the prefix and transform it into an MS-DOS path. */
   else if (iscygdrive (src_path))
     {
+      debug_printf ("iscygdrive (%s) mount_table->cygdrive %s", src_path, mount_table->cygdrive);
       int n = mount_table->cygdrive_len - 1;
       int unit;
 
@@ -743,11 +736,15 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
 	}
       else if (cygdrive_win32_path (src_path, dst, unit))
 	{
+	  debug_printf ("cygdrive_win32_path (%s)", src_path);
 	  *flags = cygdrive_flags;
 	  goto out;
 	}
       else if (mount_table->cygdrive_len > 1)
-	return ENOENT;
+      {
+		debug_printf ("mount_table->cygdrive_len > 1 (%s)", src_path);
+		return ENOENT;
+      }
     }
 
   int chroot_pathlen;
@@ -758,7 +755,9 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
       const char *path;
       int len;
 
-      mi = mount + posix_sorted[i];
+      mi = mount + shortest_native_sorted[i];
+      debug_printf (" mount[%d] .. checking %s -> %s ", i, mi->posix_path, mi->native_path);
+
       if (!cygheap->root.exists ()
 	  || (mi->posix_pathlen == 1 && mi->posix_path[0] == '/'))
 	{
@@ -998,7 +997,8 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
   int pathbuflen = tail - pathbuf;
   for (int i = 0; i < nmounts; ++i)
     {
-      mount_item &mi = mount[native_sorted[i]];
+      mount_item &mi = mount[longest_posix_sorted[i]];
+      debug_printf (" mount[%d] .. checking %s -> %s ", i, mi.posix_path, mi.native_path);
       if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen,
 			  mi.flags & MOUNT_NOPOSIX))
 	continue;
@@ -1211,8 +1211,17 @@ mount_info::from_fstab_line (char *line, bool user)
   if (!*c)
     return true;
   cend = find_ws (c);
-  *cend = '\0';
   posix_path = conv_fstab_spaces (c);
+  if (!*cend)
+   {
+     unsigned mount_flags = MOUNT_SYSTEM | MOUNT_NOPOSIX | MOUNT_NOACL;
+
+     int res = mount_table->add_item (native_path, posix_path, mount_flags);
+     if (res && get_errno () == EMFILE)
+       return false;
+     return true;
+   }
+  *cend = '\0';
   /* Third field: FS type. */
   c = skip_ws (cend + 1);
   if (!*c)
@@ -1441,16 +1450,145 @@ sort_by_native_name (const void *a, const void *b)
   return res;
 }
 
+/* sort_by_longest_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_longest_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 the conversion that would give the longest
+     posix path. */
+  ssize_t alen = (ssize_t) strlen (ap->posix_path) - (ssize_t) strlen (ap->native_path);
+  ssize_t blen = (ssize_t) strlen (bp->posix_path) - (ssize_t) 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->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_shortest_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_shortest_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 the conversion that would give the shortest
+     native path. */
+  ssize_t alen = (ssize_t) strlen (ap->native_path);
+  ssize_t blen = (ssize_t) strlen (bp->native_path);
+
+  int res = alen - blen;
+
+  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;
+}
+
+static int
+sort_posix_subdirs_before_parents (const void *a, const void *b)
+{
+    mount_item *ap = mounts_for_sort + (*((int*) a));
+    mount_item *bp = mounts_for_sort + (*((int*) b));
+
+    if (ap->posix_pathlen > bp->posix_pathlen)
+    {
+        if (!memcmp (bp->posix_path, ap->posix_path, bp->posix_pathlen))
+        {
+            // bp is a subdir of ap (bp must be moved in-front)
+            return -1;
+        }
+    }
+    else if (ap->posix_pathlen < bp->posix_pathlen)
+    {
+        if (!memcmp (ap->posix_path, bp->posix_path, ap->posix_pathlen))
+        {
+            // ap is a subdir of bp (good as we are)
+            return 1;
+        }
+    }
+    return 0;
+}
+
+#define DISABLE_NEW_STUFF 0
+#define ONLY_USE_NEW_STUFF 1
+
 void
 mount_info::sort ()
 {
   for (int i = 0; i < nmounts; i++)
-    native_sorted[i] = posix_sorted[i] = i;
+    native_sorted[i] = posix_sorted[i] = shortest_native_sorted[i] = longest_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);
+  qsort (longest_posix_sorted, nmounts, sizeof (longest_posix_sorted[0]), sort_by_longest_posix_name);
+  qsort (shortest_native_sorted, nmounts, sizeof (shortest_native_sorted[0]), sort_by_shortest_native_name);
+  qsort (shortest_native_sorted, nmounts, sizeof (shortest_native_sorted[0]), sort_posix_subdirs_before_parents);
+  /* Disabling my new crap. */
+  #if DISABLE_NEW_STUFF
+  for (int i = 0; i < nmounts; i++)
+  {
+      longest_posix_sorted[i] = native_sorted[i];
+      shortest_native_sorted[i] = posix_sorted[i];
+  }
+  #else
+  #if ONLY_USE_NEW_STUFF
+  for (int i = 0; i < nmounts; i++)
+  {
+      native_sorted[i] = longest_posix_sorted[i];
+      posix_sorted[i] = shortest_native_sorted[i];
+  }
+  #endif
+  #endif
+  for (int i = 0; i < nmounts; i++)
+  {
+      mount_item *mi = mount + shortest_native_sorted[i];
+      debug_printf ("shortest_native_sorted (subdirs before parents)[%d] %12s       %12s", i, mi->native_path, mi->posix_path);
+  }
+  for (int i = 0; i < nmounts; i++)
+  {
+      mount_item *mi = mount + longest_posix_sorted[i];
+      debug_printf ("longest_posix_sorted[%d] %12s       %12s", i, mi->native_path, mi->posix_path);
+  }
 }
 
 /* Add an entry to the mount table.
@@ -1541,12 +1679,9 @@ mount_info::add_item (const char *native, const char *posix,
   if (i == nmounts)
     nmounts++;
 
-  if (strcmp (posixtmp, "/usr/bin") == 0)
+  if (strcmp (posixtmp, "/bin") == 0)
     got_usr_bin = true;
 
-  if (strcmp (posixtmp, "/usr/lib") == 0)
-    got_usr_lib = true;
-
   if (posixtmp[0] == '/' && posixtmp[1] == '\0' && !(mountflags & MOUNT_CYGDRIVE))
     root_idx = i;
 
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index ffe71ee..4323cb1 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -2811,7 +2811,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
 		     dom, name,
 		     sid.string ((char *) sidstr),
 		     home ?: "/home/", home ? L"" : name,
-		     shell ?: "/bin/bash");
+		     shell ?: "/usr/bin/bash");
   if (gecos)
     free (gecos);
   if (home)
