This is the mail archive of the cygwin-developers mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Accessing native NT namespace as filesystem


On Sep  3 11:02, Christopher Faylor wrote:
> On Fri, Sep 03, 2010 at 09:58:00AM +0200, Corinna Vinschen wrote:
> >Oooohkeeey.  I still like /proc/sys more, though.  It just *sounds*
> >better, imho.  Could you all live with that, too?
> 
> No!  Absolutely not!  Red is a much better color for a bikeshed!
> 
> cgf
> (/proc/sys is fine)

Super!

Attached is the more or less final patch which uses /proc/sys.

I also improved cygwin_conv_path to generate always valid Win32 paths
from paths via the native NT namespace, for instance

  /proc/sys/Device/CdRom0  ->  \\.\GLOBALROOT\Device\CdRom0

or

  /dev/sda1  ->  \\.\GLOBALROOT\Device\Harddisk0\Partition1

The patch also contains a change to cygpath which now groks the
GLOBALROOT prefix and still tries to find a better, shorter match by
searching the \??\ DOS device namespace, *iff* the path points into the
\Device directory.  So, by using cygpath, you can still get something
really short like this:

  $ cygpath -w /dev/sda1
  \\.\C:
  $ cygpath -w /proc/sys/Device/CdRom0
  \\.\D:

If the path is not the path to the block device, but a path to a file
on the block device, cygpath now takes this even a step beyond:

  $ cygpath -w /proc/sys/Device/CdRom0/foo
  D:\foo

So it removes the \\.\ prefix if the path is a perfectly valid DOS
standard pathname even without the prefix.  If it's shorter than MAX_PATH.

Please have a look.  If nobody finds something terribly wrong, I'll
check this in on Monday.


Corinna


P.S, this is neat:

  $ ln -s /proc/sys/SystemRoot /WINDOWS

  You neither have to know the drive letter of the system drive, nor the
  actual name of the systemroot (Windows, WINNT, whatever).  Very
  helpful if you have a machine with multiple Windows installations.


	* Makefile.in (DLL_OFILES): Add fhandler_procsys.o.
	* devices.h (enum fh_devices): Add FH_PROCSYS.
	* devices.in (dev_procsys_storage): New device.
	* devices.cc: Regenerate.
	* fhandler.h (proc_len): Convert to size_t.
	(procsys): Declare.
	(procsys_len): Declare.
	(enum virtual_ftype_t): Move here from fhandler_virtual.h.
	Add members supported by fhandler_procsys.
	(fhandler_virtual::exists): Return virtual_ftype_t.  Change
	in all derived classes.
	(class fhandler_procsys): New class.
	(fhandler_union): Add fhandler_procnet and fhandler_procsys members.
	* fhandler_disk_file.cc (__DIR_mounts::check_missing_mount): Use
	ro_u_proc.
	(fhandler_base::fstat_by_name): Add special case for virtual
	directories.
	* fhandler_netdrive.cc (fhandler_netdrive::exists): Return
	virtual_ftype_t.
	* fhandler_proc.cc (proc_tab): Sort alphabetically.  Use _VN macro
	to store length.
	(proc_len): Change to size_t.
	(proc_tab_cmp): New static function.
	(virt_tab_search): New function to search entry in virt_tab_t
	arrays.  Use throughout in /proc and sibling classes instead of
	loop.
	(fhandler_proc::exists): Return virtual_ftype_t.
	* fhandler_process.cc (process_tab): Sort alphabetically.  Use _VN
	macro to store length.
	(fhandler_process::exists): Return virtual_ftype_t.
	(fhandler_process::open): Simplify code.
	* fhandler_procnet.cc (procnet_tab): Sort alphabetically.  Use _VN
	macro to store length.
	(fhandler_procnet::exists): Return virtual_ftype_t.
	(fhandler_procnet::open): Simplify.
	* fhandler_procsys.cc: New file.
	* fhandler_registry.cc (fhandler_registry::exists): Return
	virtual_ftype_t.
	* fhandler_virtual.cc (fhandler_virtual::exists): Ditto.
	* fhandler_virtual.h (enum virtual_ftype_t): Move to fhandler.h.
	(virt_tab_t): Add name_len member.
	(_VN): New macro.
	(virt_tab_search): Declare.
	* mount.cc (mount_info::conv_to_win32_path): Fix comment.
	backslashify isprocsys_dev paths, rather than just copying as
	other proc paths.
	* ntdll.h (STATUS_OBJECT_TYPE_MISMATCH): Define
	(STATUS_INSTANCE_NOT_AVAILABLE): Define.
	(STATUS_PIPE_NOT_AVAILABLE): Define.
	(STATUS_INVALID_PIPE_STATE): Define.
	(STATUS_PIPE_BUSY): Define.
	(SYMBOLIC_LINK_QUERY): Define.
	(NtOpenSymbolicLinkObject): Declare.
	(NtQuerySymbolicLinkObject): Declare.
	* path.cc (path_conv::check): Accommodate fact that exists method
	returns virtual_ftype_t now.  Add cases for new virtual_ftype_t
	types.
	(cygwin_conv_path): Add GLOBALROOT prefix to native device paths.
	Make sure to strip \\?\ prefix only for actual filesystem-based
	paths, not for all paths.
	* path.h (isproc_dev): Add FH_PROCSYS.
	(isprocsys_dev): Define.

	* cygpath.cc (RtlEqualUnicodePathPrefix): New help function.
	(HARDDISK_PREFIX): Move.
	(GLOBALROOT_PREFIX): Define.
	(get_device_name): Take GLOBALROOT_PREFIX into account.
	Improve check for path to allow filesystem access via block devices.
	Potentially drop \\.\ prefix if resulting path is a valid DOS
	pathname.
	(do_pathconv): Make sure to drop \\?\ prefix only if path is
	actually a filesystem based path.
	(print_version): Fix copyright.

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat
Index: cygwin/Makefile.in
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/Makefile.in,v
retrieving revision 1.237
diff -u -p -r1.237 Makefile.in
--- cygwin/Makefile.in	21 Aug 2010 18:57:36 -0000	1.237
+++ cygwin/Makefile.in	3 Sep 2010 20:16:58 -0000
@@ -141,13 +141,14 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o
 	fhandler.o fhandler_clipboard.o fhandler_console.o fhandler_disk_file.o \
 	fhandler_dsp.o fhandler_fifo.o fhandler_floppy.o fhandler_mailslot.o \
 	fhandler_mem.o fhandler_netdrive.o fhandler_nodevice.o fhandler_proc.o \
-	fhandler_process.o fhandler_procnet.o fhandler_random.o fhandler_raw.o \
-	fhandler_registry.o fhandler_serial.o fhandler_socket.o fhandler_tape.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 \
-	glob_pattern_p.o globals.o grp.o heap.o hookapi.o inet_addr.o inet_network.o \
-	init.o ioctl.o ipc.o kernel32.o libstdcxx_wrapper.o localtime.o lsearch.o \
-	malloc_wrapper.o minires-os-if.o minires.o miscfuncs.o mktemp.o mmap.o msg.o \
+	fhandler_process.o fhandler_procnet.o fhandler_procsys.o fhandler_random.o \
+	fhandler_raw.o fhandler_registry.o fhandler_serial.o fhandler_socket.o \
+	fhandler_tape.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 glob_pattern_p.o globals.o grp.o heap.o hookapi.o \
+	inet_addr.o inet_network.o init.o ioctl.o ipc.o kernel32.o \
+	libstdcxx_wrapper.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 nfs.o nftw.o nlsfuncs.o ntea.o passwd.o path.o \
 	pinfo.o pipe.o poll.o posix_ipc.o pseudo-reloc.o pthread.o random.o \
 	regcomp.o regerror.o regexec.o regfree.o registry.o resource.o rexec.o \
Index: cygwin/devices.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/devices.cc,v
retrieving revision 1.31
diff -u -p -r1.31 devices.cc
--- cygwin/devices.cc	3 Jan 2009 05:12:20 -0000	1.31
+++ cygwin/devices.cc	3 Sep 2010 20:16:59 -0000
@@ -24,6 +24,9 @@ const device dev_proc_storage =
 const device dev_procnet_storage =
   {"", {FH_PROCNET}, ""};
 
+const device dev_procsys_storage =
+  {"", {FH_PROCSYS}, ""};
+
 const device dev_netdrive_storage =
   {"", {FH_NETDRIVE}, ""};
 
Index: cygwin/devices.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/devices.h,v
retrieving revision 1.25
diff -u -p -r1.25 devices.h
--- cygwin/devices.h	20 Jan 2009 17:22:11 -0000	1.25
+++ cygwin/devices.h	3 Sep 2010 20:16:59 -0000
@@ -1,6 +1,6 @@
 /* devices.h
 
-   Copyright 2002, 2003, 2004, 2005 Red Hat, Inc.
+   Copyright 2002, 2003, 2004, 2005, 2007, 2009, 2010 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -53,6 +53,7 @@ enum fh_devices
   FH_DEV     = FHDEV (0, 245),
   FH_PROCNET = FHDEV (0, 244),
   FH_PROCESSFD = FHDEV (0, 243),
+  FH_PROCSYS = FHDEV (0, 242),
 
   DEV_FLOPPY_MAJOR = 2,
   FH_FLOPPY  = FHDEV (DEV_FLOPPY_MAJOR, 0),
Index: cygwin/devices.in
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/devices.in,v
retrieving revision 1.22
diff -u -p -r1.22 devices.in
--- cygwin/devices.in	3 Jan 2009 05:12:20 -0000	1.22
+++ cygwin/devices.in	3 Sep 2010 20:16:59 -0000
@@ -20,6 +20,9 @@ const device dev_proc_storage =
 const device dev_procnet_storage =
   {"", {FH_PROCNET}, ""};
 
+const device dev_procsys_storage =
+  {"", {FH_PROCSYS}, ""};
+
 const device dev_netdrive_storage =
   {"", {FH_NETDRIVE}, ""};
 
Index: cygwin/dtable.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/dtable.cc,v
retrieving revision 1.216
diff -u -p -r1.216 dtable.cc
--- cygwin/dtable.cc	15 Jun 2010 12:05:14 -0000	1.216
+++ cygwin/dtable.cc	3 Sep 2010 20:17:00 -0000
@@ -540,6 +540,9 @@ build_fh_pc (path_conv& pc, bool set_nam
 	case FH_PROCNET:
 	  fh = cnew (fhandler_procnet) ();
 	  break;
+	case FH_PROCSYS:
+	  fh = cnew (fhandler_procsys) ();
+	  break;
 	case FH_NETDRIVE:
 	  fh = cnew (fhandler_netdrive) ();
 	  break;
Index: cygwin/fhandler.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler.h,v
retrieving revision 1.403
diff -u -p -r1.403 fhandler.h
--- cygwin/fhandler.h	5 Jul 2010 16:59:55 -0000	1.403
+++ cygwin/fhandler.h	3 Sep 2010 20:17:00 -0000
@@ -34,7 +34,9 @@ extern const char *windows_device_names[
 extern struct __cygwin_perfile *perfile_table;
 #define __fmode (*(user_data->fmode_ptr))
 extern const char proc[];
-extern const int proc_len;
+extern const size_t proc_len;
+extern const char procsys[];
+extern const size_t procsys_len;
 
 class select_record;
 class select_stuff;
@@ -99,6 +101,20 @@ enum del_lock_called_from {
   after_exec
 };
 
+enum virtual_ftype_t {
+  virt_blk = -7,	/* Block special */
+  virt_chr = -6,	/* Character special */
+  virt_fsfile = -5,	/* FS-based file via /proc/sys */
+  virt_socket = -4,	/* Socket */
+  virt_pipe = -3,	/* Pipe */
+  virt_symlink = -2,	/* Symlink */
+  virt_file = -1,	/* Regular file */
+  virt_none = 0,	/* Invalid, Error */
+  virt_directory = 1,	/* Directory */
+  virt_rootdir = 2,	/* Root directory of virtual FS */
+  virt_fsdir = 3,	/* FS-based directory via /proc/sys */
+};
+
 class fhandler_base
 {
   friend class dtable;
@@ -1331,7 +1347,7 @@ class fhandler_virtual : public fhandler
   fhandler_virtual ();
   virtual ~fhandler_virtual();
 
-  virtual int exists();
+  virtual virtual_ftype_t exists();
   DIR *opendir (int fd) __attribute__ ((regparm (2)));
   long telldir (DIR *);
   void seekdir (DIR *, long);
@@ -1357,7 +1373,7 @@ class fhandler_proc: public fhandler_vir
 {
  public:
   fhandler_proc ();
-  int exists();
+  virtual_ftype_t exists();
   int readdir (DIR *, dirent *) __attribute__ ((regparm (3)));
   static DWORD get_proc_fhandler(const char *path);
 
@@ -1366,11 +1382,30 @@ class fhandler_proc: public fhandler_vir
   bool fill_filebuf ();
 };
 
+class fhandler_procsys: public fhandler_virtual
+{
+ public:
+  fhandler_procsys ();
+  virtual_ftype_t exists(struct __stat64 *buf) __attribute__ ((regparm (2)));
+  virtual_ftype_t exists();
+  DIR *opendir (int fd) __attribute__ ((regparm (2)));
+  int readdir (DIR *, dirent *) __attribute__ ((regparm (3)));
+  long telldir (DIR *);
+  void seekdir (DIR *, long);
+  int closedir (DIR *);
+  int open (int flags, mode_t mode = 0);
+  int close ();
+  void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+  ssize_t __stdcall write (const void *ptr, size_t len);
+  int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+  bool fill_filebuf ();
+};
+
 class fhandler_netdrive: public fhandler_virtual
 {
  public:
   fhandler_netdrive ();
-  int exists();
+  virtual_ftype_t exists();
   int readdir (DIR *, dirent *) __attribute__ ((regparm (3)));
   void seekdir (DIR *, long);
   void rewinddir (DIR *);
@@ -1388,7 +1423,7 @@ class fhandler_registry: public fhandler
  public:
   fhandler_registry ();
   void set_name (path_conv &pc);
-  int exists();
+  virtual_ftype_t exists();
   int readdir (DIR *, dirent *) __attribute__ ((regparm (3)));
   long telldir (DIR *);
   void seekdir (DIR *, long);
@@ -1408,7 +1443,7 @@ class fhandler_process: public fhandler_
   pid_t pid;
  public:
   fhandler_process ();
-  int exists();
+  virtual_ftype_t exists();
   DIR *opendir (int fd) __attribute__ ((regparm (2)));
   int readdir (DIR *, dirent *) __attribute__ ((regparm (3)));
   int open (int flags, mode_t mode = 0);
@@ -1421,7 +1456,7 @@ class fhandler_procnet: public fhandler_
   pid_t pid;
  public:
   fhandler_procnet ();
-  int exists();
+  virtual_ftype_t exists();
   int readdir (DIR *, dirent *) __attribute__ ((regparm (3)));
   int open (int flags, mode_t mode = 0);
   int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
@@ -1462,6 +1497,8 @@ typedef union
   char __pipe[sizeof (fhandler_pipe)];
   char __proc[sizeof (fhandler_proc)];
   char __process[sizeof (fhandler_process)];
+  char __procnet[sizeof (fhandler_procnet)];
+  char __procsys[sizeof (fhandler_procsys)];
   char __pty_master[sizeof (fhandler_pty_master)];
   char __registry[sizeof (fhandler_registry)];
   char __serial[sizeof (fhandler_serial)];
Index: cygwin/fhandler_disk_file.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_disk_file.cc,v
retrieving revision 1.334
diff -u -p -r1.334 fhandler_disk_file.cc
--- cygwin/fhandler_disk_file.cc	20 Aug 2010 11:18:58 -0000	1.334
+++ cygwin/fhandler_disk_file.cc	3 Sep 2010 20:17:00 -0000
@@ -118,7 +118,7 @@ public:
 	    {
 	      found[__DIR_PROC] = true;
 	      if (retname)
-		RtlInitUnicodeString (retname, L"proc");
+		*retname = ro_u_proc;
 	      return 2;
 	    }
 	  if (!found[__DIR_CYGDRIVE])
@@ -474,7 +474,10 @@ fhandler_base::fstat_by_name (struct __s
      entry, as in other calls to fstat_helper. */
   if (pc.is_rep_symlink ())
     fdi_buf.fdi.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
-  pc.file_attributes (fdi_buf.fdi.FileAttributes);
+  /* If basename.Length is 0, the file is a virtual directory.  The attributes
+     from fdi_buf are incorrect, so don't copy. */
+  if (basename.Length > 0)
+    pc.file_attributes (fdi_buf.fdi.FileAttributes);
   return fstat_helper (buf,
 		       fdi_buf.fdi.ChangeTime.QuadPart
 		       ? &fdi_buf.fdi.ChangeTime : &fdi_buf.fdi.LastWriteTime,
Index: cygwin/fhandler_netdrive.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_netdrive.cc,v
retrieving revision 1.29
diff -u -p -r1.29 fhandler_netdrive.cc
--- cygwin/fhandler_netdrive.cc	1 Sep 2010 18:24:10 -0000	1.29
+++ cygwin/fhandler_netdrive.cc	3 Sep 2010 20:17:00 -0000
@@ -145,14 +145,14 @@ create_thread_and_wait (int what, PVOID 
 
 /* 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
+virtual_ftype_t
 fhandler_netdrive::exists ()
 {
   char *to;
   const char *from;
   size_t len = strlen (get_name ());
   if (len == 2)
-    return 1;
+    return virt_rootdir;
   char namebuf[len + 1];
   for (to = namebuf, from = get_name (); *from; to++, from++)
     *to = (*from == '/') ? '\\' : *from;
@@ -166,7 +166,7 @@ fhandler_netdrive::exists ()
 				      &nr, &nh, 0, "WNetOpenEnum");
   if (nh.dom)
     WNetCloseEnum (nh.dom);
-  return ret != NO_ERROR ? 0 : 1;
+  return ret != NO_ERROR ? virt_none : virt_directory;
 }
 
 fhandler_netdrive::fhandler_netdrive ():
Index: cygwin/fhandler_proc.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_proc.cc,v
retrieving revision 1.92
diff -u -p -r1.92 fhandler_proc.cc
--- cygwin/fhandler_proc.cc	27 Aug 2010 09:08:32 -0000	1.92
+++ cygwin/fhandler_proc.cc	3 Sep 2010 20:17:00 -0000
@@ -46,23 +46,24 @@ static _off64_t format_proc_filesystems 
 
 /* names of objects in /proc */
 static const virt_tab_t proc_tab[] = {
-  { ".",	  FH_PROC,	virt_directory,	NULL },
-  { "..",	  FH_PROC,	virt_directory,	NULL },
-  { "loadavg",	  FH_PROC,	virt_file,	format_proc_loadavg },
-  { "meminfo",	  FH_PROC,	virt_file,	format_proc_meminfo },
-  { "registry",	  FH_REGISTRY,	virt_directory,	NULL  },
-  { "stat",	  FH_PROC,	virt_file,	format_proc_stat },
-  { "version",	  FH_PROC,	virt_file,	format_proc_version },
-  { "uptime",	  FH_PROC,	virt_file,	format_proc_uptime },
-  { "cpuinfo",	  FH_PROC,	virt_file,	format_proc_cpuinfo },
-  { "partitions", FH_PROC,	virt_file,	format_proc_partitions },
-  { "self",	  FH_PROC,	virt_symlink,	format_proc_self },
-  { "mounts",	  FH_PROC,	virt_symlink,	format_proc_mounts },
-  { "registry32", FH_REGISTRY,	virt_directory,	NULL },
-  { "registry64", FH_REGISTRY,	virt_directory,	NULL },
-  { "net",	  FH_PROCNET,	virt_directory,	NULL },
-  { "filesystems", FH_PROC,	virt_file,	format_proc_filesystems },
-  { NULL,	  0,		virt_none,	NULL }
+  { _VN ("."),		 FH_PROC,	virt_directory,	NULL },
+  { _VN (".."),		 FH_PROC,	virt_directory,	NULL },
+  { _VN ("cpuinfo"),	 FH_PROC,	virt_file,	format_proc_cpuinfo },
+  { _VN ("filesystems"), FH_PROC,	virt_file,	format_proc_filesystems },
+  { _VN ("loadavg"),	 FH_PROC,	virt_file,	format_proc_loadavg },
+  { _VN ("meminfo"),	 FH_PROC,	virt_file,	format_proc_meminfo },
+  { _VN ("mounts"),	 FH_PROC,	virt_symlink,	format_proc_mounts },
+  { _VN ("net"),	 FH_PROCNET,	virt_directory,	NULL },
+  { _VN ("partitions"),  FH_PROC,	virt_file,	format_proc_partitions },
+  { _VN ("registry"),	 FH_REGISTRY,	virt_directory,	NULL  },
+  { _VN ("registry32"),  FH_REGISTRY,	virt_directory,	NULL },
+  { _VN ("registry64"),  FH_REGISTRY,	virt_directory,	NULL },
+  { _VN ("self"),	 FH_PROC,	virt_symlink,	format_proc_self },
+  { _VN ("stat"),	 FH_PROC,	virt_file,	format_proc_stat },
+  { _VN ("sys"),	 FH_PROCSYS,	virt_directory,	NULL },
+  { _VN ("uptime"),	 FH_PROC,	virt_file,	format_proc_uptime },
+  { _VN ("version"),	 FH_PROC,	virt_file,	format_proc_version },
+  { NULL, 0,	   	 0,		virt_none,	NULL }
 };
 
 #define PROC_DIR_COUNT 4
@@ -71,11 +72,37 @@ static const int PROC_LINK_COUNT = (size
 
 /* name of the /proc filesystem */
 const char proc[] = "/proc";
-const int proc_len = sizeof (proc) - 1;
+const size_t proc_len = sizeof (proc) - 1;
 
-/* Auxillary function that returns the fhandler associated with the given path
-   this is where it would be nice to have pattern matching in C - polymorphism
-   just doesn't cut it. */
+/* bsearch compare function. */
+static int
+proc_tab_cmp (const void *key, const void *memb)
+{
+  int ret = strncmp (((virt_tab_t *) key)->name, ((virt_tab_t *) memb)->name,
+		     ((virt_tab_t *) memb)->name_len);
+  if (!ret && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '\0' && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '/')
+    return 1;
+  return ret;
+}
+
+/* Helper function to perform a binary search of  the incoming pathname
+   against the alpha-sorted virtual file table. */
+virt_tab_t *
+virt_tab_search (const char *path, bool prefix, const virt_tab_t *table,
+		 size_t nelem)
+{
+  virt_tab_t key = { path, 0, 0, virt_none, NULL };
+  virt_tab_t *entry = (virt_tab_t *) bsearch (&key, table, nelem,
+					      sizeof (virt_tab_t),
+					      proc_tab_cmp);
+  if (entry && (path[entry->name_len] == '\0'
+		|| (prefix && path[entry->name_len] == '/')))
+    return entry;
+  return NULL;
+}
+
+/* Auxillary function that returns the fhandler associated with the given
+   path. */
 DWORD
 fhandler_proc::get_proc_fhandler (const char *path)
 {
@@ -91,12 +118,10 @@ fhandler_proc::get_proc_fhandler (const 
   if (*path == 0)
     return FH_PROC;
 
-  for (int i = 0; proc_tab[i].name; i++)
-    {
-      if (path_prefix_p (proc_tab[i].name, path, strlen (proc_tab[i].name),
-			 false))
-	return proc_tab[i].fhandler;
-    }
+  virt_tab_t *entry = virt_tab_search (path, true, proc_tab,
+				       PROC_LINK_COUNT);
+  if (entry)
+    return entry->fhandler;
 
   if (pinfo (atoi (path)))
     return FH_PROCESS;
@@ -120,7 +145,7 @@ fhandler_proc::get_proc_fhandler (const 
 
 /* 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
+virtual_ftype_t
 fhandler_proc::exists ()
 {
   const char *path = get_name ();
@@ -128,12 +153,13 @@ fhandler_proc::exists ()
   path += proc_len;
   if (*path == 0)
     return virt_rootdir;
-  for (int i = 0; proc_tab[i].name; i++)
-    if (!strcmp (path + 1, proc_tab[i].name))
-      {
-	fileid = i;
-	return proc_tab[i].type;
-      }
+  virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
+				       PROC_LINK_COUNT);
+  if (entry)
+    {
+      fileid = entry - proc_tab;
+      return entry->type;
+    }
   return virt_none;
 }
 
@@ -163,21 +189,21 @@ fhandler_proc::fstat (struct __stat64 *b
     }
   else
     {
-      path++;
-      for (int i = 0; proc_tab[i].name; i++)
-	if (!strcmp (path, proc_tab[i].name))
-	  {
-	    if (proc_tab[i].type == virt_directory)
-	      buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
-	    else if (proc_tab[i].type == virt_symlink)
-	      buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
-	    else
-	      {
-		buf->st_mode &= NO_X;
-		buf->st_mode |= S_IFREG;
-	      }
-	    return 0;
-	  }
+      virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
+					   PROC_LINK_COUNT);
+      if (entry)
+	{
+	  if (entry->type == virt_directory)
+	    buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+	  else if (entry->type == virt_symlink)
+	    buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
+	  else
+	    {
+	      buf->st_mode &= NO_X;
+	      buf->st_mode |= S_IFREG;
+	    }
+	  return 0;
+	}
     }
   set_errno (ENOENT);
   return -1;
Index: cygwin/fhandler_process.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_process.cc,v
retrieving revision 1.91
diff -u -p -r1.91 fhandler_process.cc
--- cygwin/fhandler_process.cc	18 May 2010 14:30:50 -0000	1.91
+++ cygwin/fhandler_process.cc	3 Sep 2010 20:17:00 -0000
@@ -53,28 +53,28 @@ static _off64_t format_process_mounts (v
 
 static const virt_tab_t process_tab[] =
 {
-  { ".",          FH_PROCESS,   virt_directory, NULL },
-  { "..",         FH_PROCESS,   virt_directory, NULL },
-  { "ppid",       FH_PROCESS,   virt_file,      format_process_ppid },
-  { "winpid",     FH_PROCESS,   virt_file,	format_process_winpid },
-  { "winexename", FH_PROCESS,   virt_file,      format_process_winexename },
-  { "status",     FH_PROCESS,   virt_file,      format_process_status },
-  { "uid",        FH_PROCESS,   virt_file,      format_process_uid },
-  { "gid",        FH_PROCESS,   virt_file,      format_process_gid },
-  { "pgid",       FH_PROCESS,   virt_file,      format_process_pgid },
-  { "sid",        FH_PROCESS,   virt_file,      format_process_sid },
-  { "ctty",       FH_PROCESS,   virt_file,      format_process_ctty },
-  { "stat",       FH_PROCESS,   virt_file,      format_process_stat },
-  { "statm",      FH_PROCESS,   virt_file,      format_process_statm },
-  { "cmdline",    FH_PROCESS,   virt_file,      format_process_cmdline },
-  { "maps",       FH_PROCESS,   virt_file,      format_process_maps },
-  { "fd",         FH_PROCESSFD, virt_directory, format_process_fd },
-  { "exename",    FH_PROCESS,   virt_file,      format_process_exename },
-  { "root",       FH_PROCESS,   virt_symlink,   format_process_root },
-  { "exe",        FH_PROCESS,   virt_symlink,   format_process_exename },
-  { "cwd",        FH_PROCESS,   virt_symlink,   format_process_cwd },
-  { "mounts",     FH_PROCESS,   virt_file,      format_process_mounts },
-  { NULL,         0,            virt_none,      NULL }
+  { _VN ("."),          FH_PROCESS,   virt_directory, NULL },
+  { _VN (".."),         FH_PROCESS,   virt_directory, NULL },
+  { _VN ("cmdline"),    FH_PROCESS,   virt_file,      format_process_cmdline },
+  { _VN ("ctty"),       FH_PROCESS,   virt_file,      format_process_ctty },
+  { _VN ("cwd"),        FH_PROCESS,   virt_symlink,   format_process_cwd },
+  { _VN ("exe"),        FH_PROCESS,   virt_symlink,   format_process_exename },
+  { _VN ("exename"),    FH_PROCESS,   virt_file,      format_process_exename },
+  { _VN ("fd"),         FH_PROCESSFD, virt_directory, format_process_fd },
+  { _VN ("gid"),        FH_PROCESS,   virt_file,      format_process_gid },
+  { _VN ("maps"),       FH_PROCESS,   virt_file,      format_process_maps },
+  { _VN ("mounts"),     FH_PROCESS,   virt_file,      format_process_mounts },
+  { _VN ("pgid"),       FH_PROCESS,   virt_file,      format_process_pgid },
+  { _VN ("ppid"),       FH_PROCESS,   virt_file,      format_process_ppid },
+  { _VN ("root"),       FH_PROCESS,   virt_symlink,   format_process_root },
+  { _VN ("sid"),        FH_PROCESS,   virt_file,      format_process_sid },
+  { _VN ("stat"),       FH_PROCESS,   virt_file,      format_process_stat },
+  { _VN ("statm"),      FH_PROCESS,   virt_file,      format_process_statm },
+  { _VN ("status"),     FH_PROCESS,   virt_file,      format_process_status },
+  { _VN ("uid"),        FH_PROCESS,   virt_file,      format_process_uid },
+  { _VN ("winexename"), FH_PROCESS,   virt_file,      format_process_winexename },
+  { _VN ("winpid"),     FH_PROCESS,   virt_file,      format_process_winpid },
+  { NULL, 0,	        0,            virt_none,      NULL }
 };
 
 static const int PROCESS_LINK_COUNT =
@@ -90,7 +90,7 @@ static bool get_mem_values (DWORD dwProc
  * -1 if path is a file, -2 if path is a symlink, -3 if path is a pipe,
  * -4 if path is a socket.
  */
-int
+virtual_ftype_t
 fhandler_process::exists ()
 {
   const char *path = get_name ();
@@ -99,21 +99,20 @@ fhandler_process::exists ()
   while (*path != 0 && !isdirsep (*path))
     path++;
   if (*path == 0)
-    return 2;
+    return virt_rootdir;
 
-  for (int i = 0; process_tab[i].name; i++)
+  virt_tab_t *entry = virt_tab_search (path + 1, true, process_tab,
+				       PROCESS_LINK_COUNT);
+  if (entry)
     {
-      if (!strcmp (path + 1, process_tab[i].name))
+      if (!path[entry->name_len + 1])
 	{
-	  fileid = i;
-	  return process_tab[i].type;
+	  fileid = entry - process_tab;
+	  return entry->type;
 	}
-      if (process_tab[i].type == virt_directory
-	  && !strncmp (path + 1, process_tab[i].name,
-		       strlen (process_tab[i].name))
-	  && path[1 + strlen (process_tab[i].name)] == '/')
+      if (entry->type == virt_directory)
 	{
-	  fileid = i;
+	  fileid = entry - process_tab;
 	  if (fill_filebuf ())
 	    return virt_symlink;
 	  /* Check for nameless device entries. */
@@ -232,8 +231,6 @@ out:
 int
 fhandler_process::open (int flags, mode_t mode)
 {
-  int process_file_no = -1;
-
   int res = fhandler_virtual::open (flags, mode);
   if (!res)
     goto out;
@@ -267,29 +264,15 @@ fhandler_process::open (int flags, mode_
 	}
     }
 
-  process_file_no = -1;
-  for (int i = 0; process_tab[i].name; i++)
-    {
-      if (path_prefix_p (process_tab[i].name, path + 1,
-			 strlen (process_tab[i].name), false))
-	process_file_no = i;
-    }
-  if (process_file_no == -1)
+  virt_tab_t *entry;
+  entry = virt_tab_search (path + 1, true, process_tab, PROCESS_LINK_COUNT);
+  if (!entry)
     {
-      if (flags & O_CREAT)
-	{
-	  set_errno (EROFS);
-	  res = 0;
-	  goto out;
-	}
-      else
-	{
-	  set_errno (ENOENT);
-	  res = 0;
-	  goto out;
-	}
+      set_errno ((flags & O_CREAT) ? EROFS : ENOENT);
+      res = 0;
+      goto out;
     }
-  if (process_tab[process_file_no].fhandler == FH_PROCESSFD)
+  if (entry->fhandler == FH_PROCESSFD)
     {
       flags |= O_DIROPEN;
       goto success;
@@ -301,7 +284,7 @@ fhandler_process::open (int flags, mode_
       goto out;
     }
 
-  fileid = process_file_no;
+  fileid = entry - process_tab;
   if (!fill_filebuf ())
 	{
 	  res = 0;
Index: cygwin/fhandler_procnet.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_procnet.cc,v
retrieving revision 1.11
diff -u -p -r1.11 fhandler_procnet.cc
--- cygwin/fhandler_procnet.cc	20 Jan 2009 18:04:32 -0000	1.11
+++ cygwin/fhandler_procnet.cc	3 Sep 2010 20:17:00 -0000
@@ -39,10 +39,10 @@ static _off64_t format_procnet_ifinet6 (
 
 static const virt_tab_t procnet_tab[] =
 {
-  { ".",        FH_PROCNET, virt_directory, NULL },
-  { "..",       FH_PROCNET, virt_directory, NULL },
-  { "if_inet6", FH_PROCNET, virt_file,      format_procnet_ifinet6 },
-  { NULL,       0,          virt_none,      NULL }
+  { _VN ("."),        FH_PROCNET, virt_directory, NULL },
+  { _VN (".."),       FH_PROCNET, virt_directory, NULL },
+  { _VN ("if_inet6"), FH_PROCNET, virt_file,      format_procnet_ifinet6 },
+  { NULL, 0,          0,          virt_none,      NULL }
 };
 
 static const int PROCNET_LINK_COUNT =
@@ -52,7 +52,7 @@ static const int PROCNET_LINK_COUNT =
  * -1 if path is a file, -2 if path is a symlink, -3 if path is a pipe,
  * -4 if path is a socket.
  */
-int
+virtual_ftype_t
 fhandler_procnet::exists ()
 {
   const char *path = get_name ();
@@ -61,20 +61,21 @@ fhandler_procnet::exists ()
   while (*path != 0 && !isdirsep (*path))
     path++;
   if (*path == 0)
-    return 1;
+    return virt_rootdir;
 
-  for (int i = 0; procnet_tab[i].name; i++)
-    if (!strcmp (path + 1, procnet_tab[i].name))
-      {
-	if (procnet_tab[i].type == virt_file)
-	  {
-	    if (!wincap.has_gaa_prefixes ()
-	    	|| !get_adapters_addresses (NULL, AF_INET6))
-	      return virt_none;
-	  }
-	fileid = i;
-	return procnet_tab[i].type;
-      }
+  virt_tab_t *entry = virt_tab_search (path + 1, false, procnet_tab,
+				       PROCNET_LINK_COUNT);
+  if (entry)
+    {
+      if (entry->type == virt_file)
+	{
+	  if (!wincap.has_gaa_prefixes ()
+	      || !get_adapters_addresses (NULL, AF_INET6))
+	    return virt_none;
+	}
+      fileid = entry - procnet_tab;
+      return entry->type;
+    }
   return virt_none;
 }
 
@@ -129,8 +130,6 @@ out:
 int
 fhandler_procnet::open (int flags, mode_t mode)
 {
-  int process_file_no = -1;
-
   int res = fhandler_virtual::open (flags, mode);
   if (!res)
     goto out;
@@ -163,27 +162,13 @@ fhandler_procnet::open (int flags, mode_
 	}
     }
 
-  process_file_no = -1;
-  for (int i = 0; procnet_tab[i].name; i++)
+  virt_tab_t *entry;
+  entry = virt_tab_search (path + 1, true, procnet_tab, PROCNET_LINK_COUNT);
+  if (!entry)
     {
-      if (path_prefix_p (procnet_tab[i].name, path + 1,
-			 strlen (procnet_tab[i].name), false))
-	process_file_no = i;
-    }
-  if (process_file_no == -1)
-    {
-      if (flags & O_CREAT)
-	{
-	  set_errno (EROFS);
-	  res = 0;
-	  goto out;
-	}
-      else
-	{
-	  set_errno (ENOENT);
-	  res = 0;
-	  goto out;
-	}
+      set_errno ((flags & O_CREAT) ? EROFS : ENOENT);
+      res = 0;
+      goto out;
     }
   if (flags & O_WRONLY)
     {
@@ -192,7 +177,7 @@ fhandler_procnet::open (int flags, mode_
       goto out;
     }
 
-  fileid = process_file_no;
+  fileid = entry - procnet_tab;
   if (!fill_filebuf ())
 	{
 	  res = 0;
Index: cygwin/fhandler_procsys.cc
===================================================================
RCS file: cygwin/fhandler_procsys.cc
diff -N cygwin/fhandler_procsys.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cygwin/fhandler_procsys.cc	3 Sep 2010 20:17:00 -0000
@@ -0,0 +1,415 @@
+/* fhandler_procsys.cc: fhandler for native NT namespace.
+
+   Copyright 2010 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 <stdlib.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include <winioctl.h>
+#include "ntdll.h"
+#include "tls_pbuf.h"
+
+#include <dirent.h>
+
+/* Path of the /proc/sys filesystem */
+const char procsys[] = "/proc/sys";
+const size_t procsys_len = sizeof (procsys) - 1;
+
+#define mk_unicode_path(p) \
+	WCHAR namebuf[strlen (get_name ()) + 1]; \
+	{ \
+	  const char *from; \
+	  PWCHAR to; \
+	  for (to = namebuf, from = get_name () + procsys_len; *from; \
+	       to++, from++) \
+	    /* The NT device namespace is ASCII only. */ \
+	    *to = (*from == '/') ? L'\\' : (WCHAR) *from; \
+	  if (to == namebuf) \
+	    *to++ = L'\\'; \
+	  *to = L'\0'; \
+	  RtlInitUnicodeString ((p), namebuf); \
+	}
+
+/* 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.  */
+virtual_ftype_t
+fhandler_procsys::exists (struct __stat64 *buf)
+{
+  UNICODE_STRING path; \
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
+  NTSTATUS status;
+  HANDLE h;
+  FILE_BASIC_INFORMATION fbi;
+  virtual_ftype_t file_type = virt_chr;
+
+  if (strlen (get_name ()) == procsys_len)
+    return virt_rootdir;
+  mk_unicode_path (&path);
+  /* First try to open as file/device to get more info. */
+  InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);
+  status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES, &attr, &io,
+		       FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
+  if (status == STATUS_OBJECT_PATH_NOT_FOUND)
+    return virt_none;
+  /* If the name isn't found, or we get this dreaded sharing violation, let
+     the caller try again as normal file. */
+  if (status == STATUS_OBJECT_NAME_NOT_FOUND
+      || status == STATUS_NO_MEDIA_IN_DEVICE
+      || status == STATUS_SHARING_VIOLATION)
+    return virt_fsfile;	/* Just try again as normal file. */
+  /* Check for pipe errors, which make a good hint... */
+  if (status >= STATUS_PIPE_NOT_AVAILABLE && status <= STATUS_PIPE_BUSY)
+    file_type = virt_pipe;
+  else if (status == STATUS_ACCESS_DENIED)
+    {
+      /* Check if this is just some file or dir on a real FS to circumvent
+         most permission problems. */
+      status = NtQueryAttributesFile (&attr, &fbi);
+      if (NT_SUCCESS (status))
+	return (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+	       ? virt_fsdir : virt_fsfile;
+    }
+  else if (NT_SUCCESS (status))
+    {
+      NTSTATUS dev_stat;
+      FILE_FS_DEVICE_INFORMATION ffdi;
+
+      /* If requested, check permissions. */
+      if (buf)
+      	get_object_attribute (h, &buf->st_uid, &buf->st_gid, &buf->st_mode);
+      /* Check for the device type. */
+      dev_stat = NtQueryVolumeInformationFile (h, &io, &ffdi, sizeof ffdi,
+					       FileFsDeviceInformation);
+      /* And check for file attributes.  If we get them, we peeked into
+	 a real FS through /proc/sys. */
+      status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
+				       FileBasicInformation);
+      NtClose (h);
+      if (NT_SUCCESS (dev_stat))
+	{
+	  if (ffdi.DeviceType == FILE_DEVICE_NAMED_PIPE)
+	    file_type = NT_SUCCESS (status) ? virt_pipe : virt_blk;
+	  else if (NT_SUCCESS (status))
+	    file_type = (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+			? virt_fsdir : virt_fsfile;
+	  else if (ffdi.DeviceType == FILE_DEVICE_DISK
+		   || ffdi.DeviceType == FILE_DEVICE_CD_ROM
+		   || ffdi.DeviceType == FILE_DEVICE_VIRTUAL_DISK)
+	    file_type = virt_blk;
+	}
+    }
+  /* Then check if it's a symlink. */
+  status = NtOpenSymbolicLinkObject (&h, READ_CONTROL | SYMBOLIC_LINK_QUERY,
+				     &attr);
+  if (NT_SUCCESS (status))
+    {
+      /* If requested, check permissions. */
+      if (buf)
+      	get_object_attribute (h, &buf->st_uid, &buf->st_gid, &buf->st_mode);
+      NtClose (h);
+      return virt_symlink;
+    }
+  /* Eventually, test if it's an object directory. */
+  status = NtOpenDirectoryObject (&h, READ_CONTROL | DIRECTORY_QUERY, &attr);
+  if (NT_SUCCESS (status))
+    {
+      /* If requested, check permissions. */
+      if (buf)
+      	get_object_attribute (h, &buf->st_uid, &buf->st_gid, &buf->st_mode);
+      NtClose (h);
+      return virt_directory;
+    }
+  else if (status == STATUS_ACCESS_DENIED)
+    return virt_directory;
+  /* Give up.  Just treat as character device. */
+  return file_type;
+}
+
+virtual_ftype_t
+fhandler_procsys::exists ()
+{
+  return exists (NULL);
+}
+
+fhandler_procsys::fhandler_procsys ():
+  fhandler_virtual ()
+{
+}
+
+bool
+fhandler_procsys::fill_filebuf ()
+{
+  /* The NT device namespace is ASCII only. */
+  char *fnamep;
+  UNICODE_STRING path, target;
+  OBJECT_ATTRIBUTES attr;
+  NTSTATUS status;
+  HANDLE h;
+  tmp_pathbuf tp;
+
+  mk_unicode_path (&path);
+  if (path.Buffer[path.Length / sizeof (WCHAR) - 1] == L'\\')
+    path.Length -= sizeof (WCHAR);
+  InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);
+  status = NtOpenSymbolicLinkObject (&h, SYMBOLIC_LINK_QUERY, &attr);
+  if (!NT_SUCCESS (status))
+    return false;
+  RtlInitEmptyUnicodeString (&target, tp.w_get (),
+			     (NT_MAX_PATH - 1) * sizeof (WCHAR));
+  status = NtQuerySymbolicLinkObject (h, &target, NULL);
+  NtClose (h);
+  if (!NT_SUCCESS (status))
+    return false;
+  size_t len = sys_wcstombs (NULL, 0, target.Buffer,
+			     target.Length / sizeof (WCHAR));
+  filebuf = (char *) crealloc_abort (filebuf, procsys_len + len + 1);
+  sys_wcstombs (fnamep = stpcpy (filebuf, procsys), len + 1, target.Buffer,
+		target.Length / sizeof (WCHAR));
+  while ((fnamep = strchr (fnamep, '\\')))
+    *fnamep = '/';
+  return true;
+}
+
+int
+fhandler_procsys::fstat (struct __stat64 *buf)
+{
+  const char *path = get_name ();
+  debug_printf ("fstat (%s)", path);
+
+  fhandler_base::fstat (buf);
+  /* Best bet. */
+  buf->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+  buf->st_uid = 544;
+  buf->st_gid = 18;
+  buf->st_dev = buf->st_rdev = dev ().devn;
+  buf->st_ino = get_ino ();
+  switch (exists (buf))
+    {
+    case virt_directory:
+    case virt_rootdir:
+    case virt_fsdir:
+      buf->st_mode |= S_IFDIR;
+      if (buf->st_mode & S_IRUSR)
+	buf->st_mode |= S_IXUSR;
+      if (buf->st_mode & S_IRGRP)
+	buf->st_mode |= S_IXGRP;
+      if (buf->st_mode & S_IROTH)
+	buf->st_mode |= S_IXOTH;
+      break;
+    case virt_file:
+    case virt_fsfile:
+      buf->st_mode |= S_IFREG;
+      break;
+    case virt_symlink:
+      buf->st_mode |= S_IFLNK;
+      break;
+    case virt_pipe:
+      buf->st_mode |= S_IFIFO;
+      break;
+    case virt_socket:
+      buf->st_mode |= S_IFSOCK;
+      break;
+    case virt_chr:
+      buf->st_mode |= S_IFCHR;
+      break;
+    case virt_blk:
+      buf->st_mode |= S_IFBLK;
+      break;
+    default:
+      set_errno (ENOENT);
+      return -1;
+    }
+  return 0;
+}
+
+DIR *
+fhandler_procsys::opendir (int fd)
+{
+  UNICODE_STRING path;
+  OBJECT_ATTRIBUTES attr;
+  NTSTATUS status;
+  HANDLE h;
+  DIR *dir = fhandler_virtual::opendir (fd);
+
+  mk_unicode_path (&path);
+  InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);
+  status = NtOpenDirectoryObject (&h, DIRECTORY_QUERY, &attr);
+  if (!NT_SUCCESS (status))
+    {
+      free (dir);
+      __seterrno_from_nt_status (status);
+      return NULL;
+    }
+  dir->__handle = h;
+  return dir;
+}
+
+int
+fhandler_procsys::readdir (DIR *dir, dirent *de)
+{
+  NTSTATUS status;
+  struct fdbi
+  {
+    DIRECTORY_BASIC_INFORMATION dbi;
+    WCHAR buf[2][NAME_MAX + 1];
+  } f;
+  int res = EBADF;
+
+  if (dir->__handle != INVALID_HANDLE_VALUE)
+    {
+      BOOLEAN restart = dir->__d_position ? FALSE : TRUE;
+      status = NtQueryDirectoryObject (dir->__handle, &f, sizeof f, TRUE,
+				       restart, (PULONG) &dir->__d_position,
+				       NULL);
+      if (!NT_SUCCESS (status))
+	res = ENMFILE;
+      else
+	{
+	  sys_wcstombs (de->d_name, NAME_MAX + 1, f.dbi.ObjectName.Buffer,
+			f.dbi.ObjectName.Length / sizeof (WCHAR));
+	  de->d_ino = hash_path_name (get_ino (), de->d_name);
+	  de->d_type = 0;
+	  res = 0;
+	}
+    }
+  syscall_printf ("%d = readdir (%p, %p)", res, dir, de);
+  return res;
+}
+
+long
+fhandler_procsys::telldir (DIR *dir)
+{
+  return dir->__d_position;
+}
+
+void
+fhandler_procsys::seekdir (DIR *dir, long pos)
+{
+  dir->__d_position = pos;
+}
+
+int
+fhandler_procsys::closedir (DIR *dir)
+{
+  if (dir->__handle != INVALID_HANDLE_VALUE)
+    {
+      NtClose (dir->__handle);
+      dir->__handle = INVALID_HANDLE_VALUE;
+    }
+  return fhandler_virtual::closedir (dir);
+}
+
+void __stdcall
+fhandler_procsys::read (void *ptr, size_t& len)
+{
+  NTSTATUS status;
+  IO_STATUS_BLOCK io;
+  LARGE_INTEGER off = { QuadPart:0LL };
+
+  status = NtReadFile (get_handle (), NULL, NULL, NULL, &io, ptr, len,
+		       &off, NULL);
+  if (!NT_SUCCESS (status))
+    {
+      __seterrno_from_nt_status (status);
+      len = -1;
+    }
+  else
+    len = io.Information;
+}
+
+ssize_t __stdcall
+fhandler_procsys::write (const void *ptr, size_t len)
+{
+  return fhandler_base::raw_write (ptr, len);
+}
+
+int
+fhandler_procsys::open (int flags, mode_t mode)
+{
+  UNICODE_STRING path;
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
+  NTSTATUS status;
+  HANDLE h;
+  ULONG access;
+  ULONG options = FILE_OPEN_FOR_BACKUP_INTENT;
+
+
+  int res = fhandler_virtual::open (flags, mode);
+  if (!res)
+    goto out;
+
+  if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL) || (flags & O_TRUNC))
+    {
+      set_errno (EINVAL);
+      res = 0;
+      goto out;
+    }
+  mk_unicode_path (&path);
+  InitializeObjectAttributes (&attr, &path, OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
+			      NULL, NULL);
+  switch (exists ())
+    {
+    case virt_directory:
+    case virt_rootdir:
+      if ((flags & O_ACCMODE) != O_RDONLY)
+	{
+	  set_errno (EISDIR);
+	  res = 0;
+	  goto out;
+	}
+      nohandle (true);
+      res = 1;
+      goto out;
+    default:
+      break;
+    }
+  if ((flags & O_ACCMODE) == O_RDONLY)
+    access = GENERIC_READ;
+  else if ((flags & O_ACCMODE) == O_WRONLY)
+    access = GENERIC_WRITE | READ_CONTROL | FILE_READ_ATTRIBUTES;
+  else
+    access = GENERIC_READ | GENERIC_WRITE;
+  if (flags & O_SYNC)
+    options |= FILE_WRITE_THROUGH;
+  if (flags & O_DIRECT)
+    options |= FILE_NO_INTERMEDIATE_BUFFERING;
+  if (!(flags & O_NONBLOCK))
+    {
+      access |= SYNCHRONIZE;
+      options |= FILE_SYNCHRONOUS_IO_NONALERT;
+    }
+  status = NtOpenFile (&h, access, &attr, &io, FILE_SHARE_VALID_FLAGS, options);
+  if (!NT_SUCCESS (status))
+    {
+      __seterrno_from_nt_status (status);
+      res = 0;
+      goto out;
+    }
+  set_io_handle (h);
+  set_open_status ();
+  res = 1;
+out:
+  syscall_printf ("%d = fhandler_procsys::open (%p, %d)", res, flags, mode);
+  return res;
+}
+
+int
+fhandler_procsys::close ()
+{
+  if (!nohandle ())
+    NtClose (get_handle ());
+  return fhandler_virtual::close ();
+}
Index: cygwin/fhandler_registry.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_registry.cc,v
retrieving revision 1.62
diff -u -p -r1.62 fhandler_registry.cc
--- cygwin/fhandler_registry.cc	1 Sep 2010 10:30:52 -0000	1.62
+++ cygwin/fhandler_registry.cc	3 Sep 2010 20:17:01 -0000
@@ -268,10 +268,11 @@ multi_wcstombs (char *dst, size_t len, c
  * final component is there. This gets round the problem of not having security access
  * to the final key in the path.
  */
-int
+virtual_ftype_t
 fhandler_registry::exists ()
 {
-  int file_type = 0, index = 0, pathlen;
+  virtual_ftype_t file_type = virt_none;
+  int index = 0, pathlen;
   DWORD buf_size = NAME_MAX + 1;
   LONG error;
   wchar_t buf[buf_size];
@@ -285,7 +286,7 @@ fhandler_registry::exists ()
     path++;
   else
     {
-      file_type = 2;
+      file_type = virt_rootdir;
       goto out;
     }
   pathlen = strlen (path);
@@ -302,7 +303,7 @@ fhandler_registry::exists ()
 	if (path_prefix_p (registry_listing[i], path,
 			   strlen (registry_listing[i]), true))
 	  {
-	    file_type = 1;
+	    file_type = virt_directory;
 	    break;
 	  }
     }
@@ -317,12 +318,12 @@ fhandler_registry::exists ()
       if (!val_only)
 	hKey = open_key (path, KEY_READ, wow64, false);
       if (hKey != (HKEY) INVALID_HANDLE_VALUE || get_errno () == EACCES)
-	file_type = 1;
+	file_type = virt_directory;
       else
 	{
 	  hKey = open_key (path, KEY_READ, wow64, true);
 	  if (hKey == (HKEY) INVALID_HANDLE_VALUE)
-	    return 0;
+	    return virt_none;
 
 	  if (hKey == HKEY_PERFORMANCE_DATA)
 	    {
@@ -332,13 +333,14 @@ fhandler_registry::exists ()
 	         So allow access to the generic names and to
 	         (blank separated) lists of counter numbers.
 	         Never allow access to "Add", see above comment.  */
-	      for (int i = 0; i < PERF_DATA_FILE_COUNT && file_type == 0; i++)
+	      for (int i = 0; i < PERF_DATA_FILE_COUNT
+			      && file_type == virt_none; i++)
 		{
 		  if (strcasematch (perf_data_files[i], file))
-		    file_type = -1;
+		    file_type = virt_file;
 		}
-	      if (file_type == 0 && !file[strspn (file, " 0123456789")])
-		file_type = -1;
+	      if (file_type == virt_none && !file[strspn (file, " 0123456789")])
+		file_type = virt_file;
 	      goto out;
 	    }
 
@@ -351,7 +353,7 @@ fhandler_registry::exists ()
 		{
 		  if (!wcscasecmp (buf, dec_file))
 		    {
-		      file_type = 1;
+		      file_type = virt_directory;
 		      goto out;
 		    }
 		    buf_size = NAME_MAX + 1;
@@ -372,7 +374,7 @@ fhandler_registry::exists ()
 	    {
 	      if (!wcscasecmp (buf, dec_file))
 		{
-		  file_type = -1;
+		  file_type = virt_file;
 		  goto out;
 		}
 	      buf_size = NAME_MAX + 1;
@@ -418,32 +420,32 @@ fhandler_registry::fstat (struct __stat6
 {
   fhandler_base::fstat (buf);
   buf->st_mode &= ~_IFMT & NO_W;
-  int file_type = exists ();
+  virtual_ftype_t file_type = exists ();
   switch (file_type)
     {
-    case 0:
+    case virt_none:
       set_errno (ENOENT);
       return -1;
-    case 1:
+    case virt_directory:
       buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
       break;
-    case 2:
+    case virt_rootdir:
       buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
       buf->st_nlink = ROOT_KEY_COUNT;
       break;
     default:
-    case -1:
+    case virt_file:
       buf->st_mode |= S_IFREG;
       buf->st_mode &= NO_X;
       break;
     }
-  if (file_type != 0 && file_type != 2)
+  if (file_type != virt_none && file_type != virt_rootdir)
     {
       HKEY hKey;
       const char *path = get_name () + proc_len + prefix_len + 2;
       hKey =
 	open_key (path, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, wow64,
-		  (file_type < 0) ? true : false);
+		  (file_type < virt_none) ? true : false);
 
       if (hKey == HKEY_PERFORMANCE_DATA)
 	/* RegQueryInfoKey () always returns write time 0,
@@ -461,7 +463,7 @@ fhandler_registry::fstat (struct __stat6
 	      to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
 	      buf->st_ctim = buf->st_birthtim = buf->st_mtim;
 	      time_as_timestruc_t (&buf->st_atim);
-	      if (file_type > 0)
+	      if (file_type > virt_none)
 		buf->st_nlink = subkey_count + 2;
 	      else
 		{
@@ -508,7 +510,7 @@ fhandler_registry::fstat (struct __stat6
 		  buf->st_uid = uid;
 		  buf->st_gid = gid;
 		  buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
-		  if (file_type > 0)
+		  if (file_type > virt_none)
 		    buf->st_mode |= S_IFDIR;
 		  else
 		    buf->st_mode &= NO_X;
Index: cygwin/fhandler_virtual.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_virtual.cc,v
retrieving revision 1.52
diff -u -p -r1.52 fhandler_virtual.cc
--- cygwin/fhandler_virtual.cc	5 Jul 2010 16:59:56 -0000	1.52
+++ cygwin/fhandler_virtual.cc	3 Sep 2010 20:17:01 -0000
@@ -225,10 +225,10 @@ fhandler_virtual::open (int flags, mode_
   return 1;
 }
 
-int
+virtual_ftype_t
 fhandler_virtual::exists ()
 {
-  return 0;
+  return virt_none;
 }
 
 bool
Index: cygwin/fhandler_virtual.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_virtual.h,v
retrieving revision 1.1
diff -u -p -r1.1 fhandler_virtual.h
--- cygwin/fhandler_virtual.h	20 Jan 2009 17:22:11 -0000	1.1
+++ cygwin/fhandler_virtual.h	3 Sep 2010 20:17:01 -0000
@@ -1,6 +1,6 @@
 /* fhandler_virtual.h: Header for virtual fhandlers
 
-   Copyright 2009 Red Hat, Inc.
+   Copyright 2009, 2010 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -8,20 +8,15 @@ This software is a copyrighted work lice
 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
-enum virtual_ftype_t {
-  virt_socket = -4,
-  virt_pipe = -3,
-  virt_symlink = -2,
-  virt_file = -1,
-  virt_none = 0,
-  virt_directory = 1,
-  virt_rootdir = 2
-};
-
 struct virt_tab_t {
   const char *name;
+  size_t name_len;
   __dev32_t fhandler;
   virtual_ftype_t type;
   _off64_t (*format_func)(void *data, char *&);
 };
 
+#define _VN(s)	s, sizeof (s) - 1
+
+extern virt_tab_t *virt_tab_search (const char *, bool, const virt_tab_t *,
+				    size_t);
Index: cygwin/mount.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/mount.cc,v
retrieving revision 1.64
diff -u -p -r1.64 mount.cc
--- cygwin/mount.cc	25 Aug 2010 09:20:11 -0000	1.64
+++ cygwin/mount.cc	3 Sep 2010 20:17:01 -0000
@@ -520,7 +520,7 @@ mount_info::conv_to_win32_path (const ch
     }
 
   MALLOC_CHECK;
-  /* If the path is on a network drive or a //./ resp.//?/ path prefix,
+  /* 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] == '/')
@@ -550,7 +550,16 @@ mount_info::conv_to_win32_path (const ch
       if (dev.devn == FH_BAD)
 	return ENOENT;
       set_flags (flags, PATH_BINARY);
-      strcpy (dst, src_path);
+      if (isprocsys_dev (dev.devn))
+	{
+	  if (src_path[procsys_len])
+	    backslashify (src_path + procsys_len, dst, 0);
+	  else
+	    stpcpy (dst, "\\");
+	  set_flags (flags, (unsigned) cygdrive_flags);
+	}
+      else
+	strcpy (dst, src_path);
       goto out;
     }
   /* Check if the cygdrive prefix was specified.  If so, just strip
Index: cygwin/ntdll.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/ntdll.h,v
retrieving revision 1.101
diff -u -p -r1.101 ntdll.h
--- cygwin/ntdll.h	27 Aug 2010 17:58:43 -0000	1.101
+++ cygwin/ntdll.h	3 Sep 2010 20:17:01 -0000
@@ -28,6 +28,7 @@
 #define STATUS_NO_MEDIA_IN_DEVICE     ((NTSTATUS) 0xc0000013)
 #define STATUS_ACCESS_DENIED          ((NTSTATUS) 0xc0000022)
 #define STATUS_BUFFER_TOO_SMALL       ((NTSTATUS) 0xc0000023)
+#define STATUS_OBJECT_TYPE_MISMATCH   ((NTSTATUS) 0xc0000024)
 #define STATUS_OBJECT_NAME_INVALID    ((NTSTATUS) 0xc0000033)
 #define STATUS_OBJECT_NAME_NOT_FOUND  ((NTSTATUS) 0xc0000034)
 #define STATUS_OBJECT_PATH_NOT_FOUND  ((NTSTATUS) 0xc000003A)
@@ -40,6 +41,10 @@
 #define STATUS_DELETE_PENDING         ((NTSTATUS) 0xc0000056)
 #define STATUS_DISK_FULL              ((NTSTATUS) 0xc000007f)
 #define STATUS_WORKING_SET_QUOTA      ((NTSTATUS) 0xc00000a1)
+#define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xc00000ab)
+#define STATUS_PIPE_NOT_AVAILABLE     ((NTSTATUS) 0xc00000ac)
+#define STATUS_INVALID_PIPE_STATE     ((NTSTATUS) 0xc00000ad)
+#define STATUS_PIPE_BUSY              ((NTSTATUS) 0xc00000ae)
 #define STATUS_NOT_SUPPORTED          ((NTSTATUS) 0xc00000bb)
 #define STATUS_BAD_NETWORK_PATH       ((NTSTATUS) 0xc00000be)
 #define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xc00000c3)
@@ -208,6 +213,8 @@ typedef struct _FILE_ID_BOTH_DIR_INFORMA
 #define DIRECTORY_CREATE_SUBDIRECTORY 8
 #define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|0x0f)
 
+#define SYMBOLIC_LINK_QUERY 1
+
 #define EVENT_QUERY_STATE 1
 #define SEMAPHORE_QUERY_STATE 1
 
@@ -927,6 +934,8 @@ extern "C"
   NTSTATUS NTAPI NtOpenMutant (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
   NTSTATUS NTAPI NtOpenSection (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
   NTSTATUS NTAPI NtOpenSemaphore (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
+  NTSTATUS NTAPI NtOpenSymbolicLinkObject (PHANDLE, ACCESS_MASK,
+					   POBJECT_ATTRIBUTES);
   /* WARNING!  Don't rely on the timestamp information returned by
      NtQueryAttributesFile.  Only the DOS file attribute info is reliable. */
   NTSTATUS NTAPI NtQueryAttributesFile (POBJECT_ATTRIBUTES,
@@ -956,6 +965,7 @@ extern "C"
 
   NTSTATUS NTAPI NtQuerySecurityObject (HANDLE, SECURITY_INFORMATION,
 					PSECURITY_DESCRIPTOR, ULONG, PULONG);
+  NTSTATUS NTAPI NtQuerySymbolicLinkObject (HANDLE, PUNICODE_STRING, PULONG);
   NTSTATUS NTAPI NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS,
 				       PVOID, ULONG, PULONG);
   NTSTATUS NTAPI NtQueryVolumeInformationFile (HANDLE, IO_STATUS_BLOCK *,
Index: cygwin/path.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/path.cc,v
retrieving revision 1.605
diff -u -p -r1.605 path.cc
--- cygwin/path.cc	31 Aug 2010 13:48:04 -0000	1.605
+++ cygwin/path.cc	3 Sep 2010 20:17:02 -0000
@@ -761,8 +761,8 @@ path_conv::check (const char *src, unsig
 	    {
 	      /* FIXME: Calling build_fhandler here is not the right way to handle this. */
 	      fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy);
-	      int file_type = fh->exists ();
-	      if (file_type == -2)
+	      virtual_ftype_t file_type = fh->exists ();
+	      if (file_type == virt_symlink)
 		{
 		  fh->fill_filebuf ();
 		  symlen = sym.set (fh->get_filebuf ());
@@ -770,31 +770,62 @@ path_conv::check (const char *src, unsig
 	      delete fh;
 	      switch (file_type)
 		{
-		  case 1:
-		  case 2:
+		  case virt_directory:
+		  case virt_rootdir:
 		    if (component == 0)
 		      fileattr = FILE_ATTRIBUTE_DIRECTORY;
 		    break;
-		  case -1:
+		  case virt_file:
 		    if (component == 0)
 		      fileattr = 0;
 		    break;
-		  case -2:	/* /proc/self or /proc/<pid>/symlinks */
+		  case virt_symlink:
 		    goto is_virtual_symlink;
-		  case -3:	/* /proc/<pid>/fd/pipe:[] */
+		  case virt_pipe:
 		    if (component == 0)
 		      {
 			fileattr = 0;
 			dev.parse (FH_PIPE);
 		      }
 		    break;
-		  case -4:	/* /proc/<pid>/fd/socket:[] */
+		  case virt_socket:
 		    if (component == 0)
 		      {
 			fileattr = 0;
 			dev.parse (FH_TCP);
 		      }
 		    break;
+		  case virt_fsdir:
+		  case virt_fsfile:
+		    dev.parse (FH_FS);
+		    goto is_fs_via_procsys;
+		  case virt_blk:
+		    /* If it has been recognized as block special device, and
+		       the trailing slash has been requested, the target path
+		       is definitely a FS-based path.  So we convert this to a
+		       FH_FS device.  The path is just lacking the trailing
+		       backslash which converts it from a block device to a
+		       file system's root directory. */
+		    if (component || need_directory)
+		      {
+			dev.parse (FH_FS);
+			if (component == 0)
+			  {
+			    strcat (full_path, "\\");
+			    fileattr = FILE_ATTRIBUTE_DIRECTORY;
+			  }
+			else
+			  fileattr = 0;
+			goto out;
+		      }
+		    /*FALLTHRU*/
+		  case virt_chr:
+		    if (component == 0)
+		      {
+			fileattr = 0;
+			dev.parse (FH_PROCSYS);
+		      }
+		    break;
 		  default:
 		    if (component == 0)
 		      fileattr = INVALID_FILE_ATTRIBUTES;
@@ -841,6 +872,8 @@ path_conv::check (const char *src, unsig
 	  if (is_msdos)
 	    sym.pflags |= PATH_NOPOSIX | PATH_NOACL;
 
+is_fs_via_procsys:
+
 	  symlen = sym.check (full_path, suff, fs, conv_handle);
 
 is_virtual_symlink:
@@ -2850,6 +2883,14 @@ cygwin_conv_path (cygwin_conv_path_t wha
 	    if (buf[1] != ':') /* native UNC path */
 	      *(buf += 2) = '\\';
 	  }
+	else if (*buf == '\\')
+	  {
+	    /* Device name points to somewhere else in the NT namespace. 
+	       Use GLOBALROOT prefix to convert to Win32 path. */
+	    char *p = stpcpy (buf, "\\\\.\\GLOBALROOT");
+	    sys_wcstombs (p, NT_MAX_PATH - (p - buf),
+			  up->Buffer, up->Length / sizeof (WCHAR));
+	  }
 	lsiz = strlen (buf) + 1;
 	/* TODO: Incoming "." is a special case which leads to a trailing
 	   backslash ".\\" in the Win32 path.  That's a result of the
@@ -2891,7 +2932,8 @@ cygwin_conv_path (cygwin_conv_path_t wha
 	     quite a bunch of Win32 functions, especially in user32.dll,
 	     apparently, which don't grok long path names at all, not even
 	     in the UNICODE API. */
-	  if (lsiz <= MAX_PATH + 4 || (path[5] != L':' && lsiz <= MAX_PATH + 6))
+	  if ((path[5] == L':' && lsiz <= MAX_PATH + 4)
+	      || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6))
 	    {
 	      path += 4;
 	      lsiz -= 4;
@@ -2902,6 +2944,13 @@ cygwin_conv_path (cygwin_conv_path_t wha
 		}
 	    }
 	}
+      else if (*path == L'\\')
+	{
+	  /* Device name points to somewhere else in the NT namespace. 
+	     Use GLOBALROOT prefix to convert to Win32 path. */
+	  to = (void *) wcpcpy ((wchar_t *) to, L"\\\\.\\GLOBALROOT");
+	  lsiz += sizeof ("\\\\.\\GLOBALROOT") - 1;
+	}
       /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */
       if (relative && !strcmp ((const char *) from, ".")
 	  && !wcscmp (path, L".\\"))
@@ -2943,10 +2992,10 @@ cygwin_conv_path (cygwin_conv_path_t wha
     case CCP_POSIX_TO_WIN_A:
     case CCP_WIN_A_TO_POSIX:
     case CCP_WIN_W_TO_POSIX:
-      strcpy ((char *) to, buf);
+      stpcpy ((char *) to, buf);
       break;
     case CCP_POSIX_TO_WIN_W:
-      wcscpy ((PWCHAR) to, path);
+      wcpcpy ((PWCHAR) to, path);
       break;
     }
   return 0;
Index: cygwin/path.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/path.h,v
retrieving revision 1.145
diff -u -p -r1.145 path.h
--- cygwin/path.h	4 Jul 2010 17:12:26 -0000	1.145
+++ cygwin/path.h	3 Sep 2010 20:17:02 -0000
@@ -18,7 +18,9 @@ details. */
 
 #define isproc_dev(devn) \
   (devn == FH_PROC || devn == FH_REGISTRY || devn == FH_PROCESS || \
-   devn == FH_PROCNET)
+   devn == FH_PROCNET || devn == FH_PROCSYS)
+
+#define isprocsys_dev(devn) (devn == FH_PROCSYS)
 
 #define isvirtual_dev(devn) \
   (isproc_dev (devn) || devn == FH_CYGDRIVE || devn == FH_NETDRIVE)
Index: utils/cygpath.cc
===================================================================
RCS file: /cvs/src/src/winsup/utils/cygpath.cc,v
retrieving revision 1.63
diff -u -p -r1.63 cygpath.cc
--- utils/cygpath.cc	28 Aug 2010 11:22:37 -0000	1.63
+++ utils/cygpath.cc	3 Sep 2010 20:17:02 -0000
@@ -134,11 +134,23 @@ static inline BOOLEAN
 RtlAllocateUnicodeString (PUNICODE_STRING uni, ULONG size)
 {
   uni->Length = 0;
-  uni->MaximumLength = 512;
+  uni->MaximumLength = size / sizeof (WCHAR);
   uni->Buffer = (WCHAR *) malloc (size);
   return uni->Buffer != NULL;
 }
 
+static inline BOOLEAN
+RtlEqualUnicodePathPrefix (PUNICODE_STRING path, PUNICODE_STRING prefix,
+			   BOOLEAN caseinsensitive)
+  {
+    UNICODE_STRING p;
+
+    p.Length = p.MaximumLength = prefix->Length < path->Length
+				 ? prefix->Length : path->Length;
+    p.Buffer = path->Buffer;
+    return RtlEqualUnicodeString (&p, prefix, caseinsensitive);
+  }
+
 static size_t
 my_wcstombs (char *dest, const wchar_t *src, size_t n)
 {
@@ -148,6 +160,9 @@ my_wcstombs (char *dest, const wchar_t *
     return wcstombs (dest, src, n);
 }
 
+#define	HARDDISK_PREFIX		L"\\Device\\Harddisk"
+#define	GLOBALROOT_PREFIX	"\\\\.\\GLOBALROOT"
+
 static char *
 get_device_name (char *path)
 {
@@ -156,18 +171,21 @@ get_device_name (char *path)
   OBJECT_ATTRIBUTES ntobj;
   NTSTATUS status;
   HANDLE lnk, dir;
+  bool got_one = false;
   char *ret = strdup (path);
   PDIRECTORY_BASIC_INFORMATION odi = (PDIRECTORY_BASIC_INFORMATION)
 				     alloca (4096);
   BOOLEAN restart;
   ULONG cont;
 
+  if (!strncasecmp (path, GLOBALROOT_PREFIX "\\", sizeof (GLOBALROOT_PREFIX)))
+    path += sizeof (GLOBALROOT_PREFIX) - 1;
   if (strncasecmp (path, "\\Device\\", 8))
     return ret;
 
-  if (!RtlAllocateUnicodeString (&ntdev, 65536))
+  if (!RtlAllocateUnicodeString (&ntdev, 65534))
     return ret;
-  if (!RtlAllocateUnicodeString (&tgtdev, 65536))
+  if (!RtlAllocateUnicodeString (&tgtdev, 65534))
     return ret;
   RtlInitAnsiString (&ans, path);
   RtlAnsiStringToUnicodeString (&ntdev, &ans, FALSE);
@@ -185,7 +203,8 @@ get_device_name (char *path)
 	goto out;
       RtlCopyUnicodeString (&ntdev, &tgtdev);
     }
-  else if (status != STATUS_OBJECT_TYPE_MISMATCH)
+  else if (status != STATUS_OBJECT_TYPE_MISMATCH
+	   && status != STATUS_OBJECT_PATH_SYNTAX_BAD)
     goto out;
 
   for (int i = 0; i < 2; ++i)
@@ -221,12 +240,19 @@ get_device_name (char *path)
 	  ZwClose (lnk);
 	  if (!NT_SUCCESS (status))
 	    continue;
-	  if (RtlEqualUnicodeString (&ntdev, &tgtdev, TRUE))
+	  if (tgtdev.Length /* There's actually a symlink pointing to an
+			       empty string: \??\GLOBALROOT -> "" */
+	      && RtlEqualUnicodePathPrefix (&ntdev, &tgtdev, TRUE))
 	    {
 	      /* If the comparison succeeds, the name of the directory entry is
 		 a valid DOS device name, if prepended with "\\.\".  Return that
 		 valid DOS path. */
+	      wchar_t *trailing = NULL;
+	      if (ntdev.Length > tgtdev.Length)
+		trailing = ntdev.Buffer + tgtdev.Length / sizeof (WCHAR);
 	      ULONG len = RtlUnicodeStringToAnsiSize (&odi->ObjectName);
+	      if (trailing)
+		len += my_wcstombs (NULL, trailing, 0);
 	      free (ret);
 	      ret = (char *) malloc (len + 4);
 	      strcpy (ret, "\\\\.\\");
@@ -234,15 +260,30 @@ get_device_name (char *path)
 	      ans.MaximumLength = len;
 	      ans.Buffer = ret + 4;
 	      RtlUnicodeStringToAnsiString (&ans, &odi->ObjectName, FALSE);
+	      if (trailing)
+		my_wcstombs (ans.Buffer + ans.Length, trailing,
+			     ans.MaximumLength - ans.Length);
+	      ans.Buffer[ans.MaximumLength - 1] = '\0';
+	      got_one = true;
 	      /* Special case for local disks:  It's most feasible if the
 		 DOS device name reflects the DOS drive, so we check for this
 		 explicitly and only return prematurely if so. */
-#define	      HARDDISK_PREFIX	L"\\Device\\Harddisk"
 	      if (ntdev.Length < wcslen (HARDDISK_PREFIX)
 		  || wcsncasecmp (ntdev.Buffer, HARDDISK_PREFIX, 8) != 0
 		  || (odi->ObjectName.Length == 2 * sizeof (WCHAR)
 		      && odi->ObjectName.Buffer[1] == L':'))
 		{
+		  if (trailing)
+		    {
+		      /* If there's a trailing path, it's a perfectly valid
+			 DOS pathname without the \\.\ prefix.  Unless it's
+			 longer than MAX_PATH - 1 in which case it needs 
+			 the \\?\ prefix. */
+		      if (len = strlen (ret + 4) >= MAX_PATH)
+			ret[2] = '?';
+		      else
+			memmove (ret, ret + 4, strlen (ret + 4) + 1);
+		    }
 		  ZwClose (dir);
 		  goto out;
 		}
@@ -254,6 +295,13 @@ get_device_name (char *path)
 out:
   free (tgtdev.Buffer);
   free (ntdev.Buffer);
+  if (!got_one)
+    {
+      free (ret);
+      ret = (char *) malloc (sizeof (GLOBALROOT_PREFIX) + strlen (path));
+      if (ret)
+      	stpcpy (stpcpy (ret, GLOBALROOT_PREFIX), path);
+    }
   return ret;
 }
 
@@ -787,10 +835,12 @@ do_pathconv (char *filename)
 	  tmp = buf;
 	  if (strncmp (buf, "\\\\?\\", 4) == 0)
 	    {
-	      len = 4;
-	      if (strncmp (buf + 4, "UNC\\", 4) == 0)
+	      len = 0;
+	      if (buf[5] == ':')
+		len = 4;
+	      else if (!strncmp (buf + 4, "UNC\\", 4))
 		len = 6;
-	      if (strlen (buf) < MAX_PATH + len)
+	      if (len && strlen (buf) < MAX_PATH + len)
 		{
 		  tmp += len;
 		  if (len == 6)
@@ -829,7 +879,7 @@ print_version ()
 cygpath (cygwin) %.*s\n\
 Path Conversion Utility\n\
 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, \n\
-          2007, 2008 Red Hat, Inc.\n\
+          2007, 2008, 2009, 2010 Red Hat, Inc.\n\
 Compiled on %s\n\
 ", len, v, __DATE__);
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]