From adef8db0ae5ed1eb6f8edb88b2685ea6316ea35f Mon Sep 17 00:00:00 2001
From: Pierre Humblet <phumblet@phumblet.no-ip.org>
Date: Mon, 9 May 2005 02:39:34 +0000
Subject: [PATCH] 2005-05-09  Pierre Humblet <pierre.humblet@ieee.org>

        * fhandler.h (class fhandler_netdrive): New class.
        * fhandler_netdrive.cc (fhandler_netdrive::fhandler_netdrive): New constructor.
        (fhandler_netdrive::exists): New method.
        (fhandler_netdrive::fstat): Ditto.
        (fhandler_netdrive::readdir): Ditto.
        (fhandler_netdrive::open): Ditto.
        * dtable.cc (build_fh_pc): Handle case FH_NETDRIVE.
        * path.cc (isvirtual_dev): Add FH_NETDRIVE.
        (mount_info::conv_to_win32_path): Detect netdrive device and bypass mount
        search for network paths.
---
 winsup/cygwin/ChangeLog            | 14 ++++++
 winsup/cygwin/dtable.cc            |  3 ++
 winsup/cygwin/fhandler.h           | 10 ++++
 winsup/cygwin/fhandler_netdrive.cc | 76 +++++++++++++++++++++++++++++-
 winsup/cygwin/path.cc              | 16 ++++++-
 5 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 510d450d5..1d45551a8 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,16 @@
+2005-05-09  Pierre Humblet <pierre.humblet@ieee.org>
+
+	* fhandler.h (class fhandler_netdrive): New class.
+	* fhandler_netdrive.cc (fhandler_netdrive::fhandler_netdrive): New constructor.
+	(fhandler_netdrive::exists): New method.
+	(fhandler_netdrive::fstat): Ditto.
+	(fhandler_netdrive::readdir): Ditto.
+	(fhandler_netdrive::open): Ditto.
+	* dtable.cc (build_fh_pc): Handle case FH_NETDRIVE.
+	* path.cc (isvirtual_dev): Add FH_NETDRIVE.
+	(mount_info::conv_to_win32_path): Detect netdrive device and bypass mount
+	search for network paths.
+
 2005-05-08  Christopher Faylor  <cgf@timesys.com>
 
 	* dcrt0.cc (get_cygwin_startup_info): New function pulled from
@@ -50,6 +63,7 @@
 
 	* fhandler_socket.cc (get_inet_addr): Add missing __seterrno call.
 
+	
 2005-05-01  Christopher Faylor  <cgf@timesys.com>
 
 	* fhandler_tty.cc (fhandler_tty_slave::read): Actually read input when
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index 2f011e6fb..575be7434 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -454,6 +454,9 @@ build_fh_pc (path_conv& pc)
 	  case FH_PROCESS:
 	    fh = cnew (fhandler_process) ();
 	    break;
+	  case FH_NETDRIVE:
+	    fh = cnew (fhandler_netdrive) ();
+	    break;
 	  case FH_TTY:
 	    {
 	      if (myself->ctty == TTY_CONSOLE)
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 04c5d399b..b8cdfd0fe 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1203,6 +1203,16 @@ class fhandler_proc: public fhandler_virtual
   bool fill_filebuf ();
 };
 
+class fhandler_netdrive: public fhandler_virtual
+{
+ public:
+  fhandler_netdrive ();
+  int exists();
+  struct dirent *readdir (DIR *);
+  int open (int flags, mode_t mode = 0);
+  int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+};
+
 class fhandler_registry: public fhandler_proc
 {
  private:
diff --git a/winsup/cygwin/fhandler_netdrive.cc b/winsup/cygwin/fhandler_netdrive.cc
index 187b49504..82a4a49e0 100644
--- a/winsup/cygwin/fhandler_netdrive.cc
+++ b/winsup/cygwin/fhandler_netdrive.cc
@@ -1,4 +1,4 @@
-/* fhandler_netdrive.cc: fhandler for //XXX/x handling
+/* fhandler_netdrive.cc: fhandler for // and //MACHINE handling
 
    Copyright 2005 Red Hat, Inc.
 
@@ -8,3 +8,77 @@ 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 <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include <assert.h>
+
+/* Returns 0 if path doesn't exist, >0 if path is a directory,
+   -1 if path is a file, -2 if it's a symlink.  */
+int
+fhandler_netdrive::exists ()
+{
+  return 1;
+}
+
+fhandler_netdrive::fhandler_netdrive ():
+  fhandler_virtual ()
+{
+}
+
+int
+fhandler_netdrive::fstat (struct __stat64 *buf)
+{
+  const char *path = get_name ();
+  debug_printf ("fstat (%s)", path);
+
+  (void) fhandler_base::fstat (buf);
+
+  buf->st_mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+
+  return 0;
+}
+
+struct dirent *
+fhandler_netdrive::readdir (DIR * dir)
+{
+  return NULL;
+}
+
+int
+fhandler_netdrive::open (int flags, mode_t mode)
+{
+  int res = fhandler_virtual::open (flags, mode);
+  if (!res)
+    goto out;
+
+  nohandle (true);
+
+  if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+    {
+      set_errno (EEXIST);
+      res = 0;
+      goto out;
+    }
+  else if (flags & O_WRONLY)
+    {
+      set_errno (EISDIR);
+      res = 0;
+      goto out;
+    }
+
+  res = 1;
+  set_flags ((flags & ~O_TEXT) | O_BINARY | O_DIROPEN);
+  set_open_status ();
+out:
+  syscall_printf ("%d = fhandler_netdrive::open (%p, %d)", res, flags, mode);
+  return res;
+}
+
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 49aeea4b3..71275d652 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -154,7 +154,8 @@ struct win_shortcut_hdr
   (path_prefix_p (proc, (path), proc_len))
 
 #define isvirtual_dev(devn) \
-  (devn == FH_CYGDRIVE || devn == FH_PROC || devn == FH_REGISTRY || devn == FH_PROCESS)
+  (devn == FH_CYGDRIVE || devn == FH_PROC || devn == FH_REGISTRY \
+   || devn == FH_PROCESS || devn == FH_NETDRIVE )
 
 /* Return non-zero if PATH1 is a prefix of PATH2.
    Both are assumed to be of the same path style and / vs \ usage.
@@ -1517,6 +1518,19 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
     }
 
   MALLOC_CHECK;
+  /* If the path is on a network drive, 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;