OSDN Git Service

* devices.h: Move a few device major numbers. Fix typo of FH_UDP.
[pf3gnuchains/sourceware.git] / winsup / cygwin / dtable.cc
1 /* dtable.cc: file descriptor support.
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #define  __INSIDE_CYGWIN_NET__
12
13 #include "winsup.h"
14 #include <sys/socket.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <sys/cygwin.h>
19 #include <assert.h>
20 #include <ntdef.h>
21 #include <winnls.h>
22
23 #define USE_SYS_TYPES_FD_SET
24 #include <winsock.h>
25 #include "pinfo.h"
26 #include "cygerrno.h"
27 #include "perprocess.h"
28 #include "security.h"
29 #include "path.h"
30 #include "fhandler.h"
31 #include "dtable.h"
32 #include "cygheap.h"
33 #include "ntdll.h"
34
35 static const NO_COPY DWORD std_consts[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
36                                            STD_ERROR_HANDLE};
37
38 static const char *handle_to_fn (HANDLE, char *);
39
40 static const char NO_COPY unknown_file[] = "some disk file";
41
42 /* Set aside space for the table of fds */
43 void
44 dtable_init (void)
45 {
46   if (!cygheap->fdtab.size)
47     cygheap->fdtab.extend (NOFILE_INCR);
48 }
49
50 void __stdcall
51 set_std_handle (int fd)
52 {
53   if (fd == 0)
54     SetStdHandle (std_consts[fd], cygheap->fdtab[fd]->get_handle ());
55   else if (fd <= 2)
56     SetStdHandle (std_consts[fd], cygheap->fdtab[fd]->get_output_handle ());
57 }
58
59 int
60 dtable::extend (int howmuch)
61 {
62   int new_size = size + howmuch;
63   fhandler_base **newfds;
64
65   if (howmuch <= 0)
66     return 0;
67
68   if (new_size > (100 * NOFILE_INCR))
69     {
70       set_errno (EMFILE);
71       return 0;
72     }
73
74   /* Try to allocate more space for fd table. We can't call realloc ()
75      here to preserve old table if memory allocation fails */
76
77   if (!(newfds = (fhandler_base **) ccalloc (HEAP_ARGV, new_size, sizeof newfds[0])))
78     {
79       debug_printf ("calloc failed");
80       set_errno (ENOMEM);
81       return 0;
82     }
83   if (fds)
84     {
85       cfree (fds);
86       memcpy (newfds, fds, size * sizeof (fds[0]));
87     }
88
89   size = new_size;
90   fds = newfds;
91   debug_printf ("size %d, fds %p", size, fds);
92   return 1;
93 }
94
95 void
96 dtable::get_debugger_info ()
97 {
98   if (being_debugged ())
99     {
100       char std[3][sizeof ("/dev/ttyNNNN")];
101       std[0][0] = std[1][0] = std [2][0] = '\0';
102       char buf[sizeof ("cYgstd %x") + 32];
103       sprintf (buf, "cYgstd %x %x %x", (unsigned) &std, sizeof (std[0]), 3);
104       OutputDebugString (buf);
105       for (int i = 0; i < 3; i++)
106         if (std[i][0])
107           {
108             HANDLE h = GetStdHandle (std_consts[i]);
109             fhandler_base *fh = build_fh_name (std[i]);
110             if (!fh)
111               continue;
112             fds[i] = fh;
113             if (!fh->open ((i ? O_WRONLY : O_RDONLY) | O_BINARY, 0777))
114               release (i);
115             else
116               CloseHandle (h);
117           }
118     }
119 }
120
121 /* Initialize the file descriptor/handle mapping table.
122    This function should only be called when a cygwin function is invoked
123    by a non-cygwin function, i.e., it should only happen very rarely. */
124
125 void
126 dtable::stdio_init ()
127 {
128   extern void set_console_ctty ();
129   /* Set these before trying to output anything from strace.
130      Also, always set them even if we're to pick up our parent's fds
131      in case they're missed.  */
132
133   if (myself->ppid_handle || ISSTATE (myself, PID_CYGPARENT))
134     return;
135
136   HANDLE in = GetStdHandle (STD_INPUT_HANDLE);
137   HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE);
138   HANDLE err = GetStdHandle (STD_ERROR_HANDLE);
139
140   init_std_file_from_handle (0, in);
141
142   /* STD_ERROR_HANDLE has been observed to be the same as
143      STD_OUTPUT_HANDLE.  We need separate handles (e.g. using pipes
144      to pass data from child to parent).  */
145   if (out == err)
146     {
147       /* Since this code is not invoked for forked tasks, we don't have
148          to worry about the close-on-exec flag here.  */
149       if (!DuplicateHandle (hMainProc, out, hMainProc, &err, 0,
150                              1, DUPLICATE_SAME_ACCESS))
151         {
152           /* If that fails, do this as a fall back.  */
153           err = out;
154           system_printf ("couldn't make stderr distinct from stdout");
155         }
156     }
157
158   init_std_file_from_handle (1, out);
159   init_std_file_from_handle (2, err);
160   /* Assign the console as the controlling tty for this process if we actually
161      have a console and no other controlling tty has been assigned. */
162   if (myself->ctty < 0 && GetConsoleCP () > 0)
163     set_console_ctty ();
164 }
165
166 int
167 dtable::find_unused_handle (int start)
168 {
169   AssertResourceOwner (LOCK_FD_LIST, READ_LOCK);
170   do
171     {
172       for (size_t i = start; i < size; i++)
173         /* See if open -- no need for overhead of not_open */
174         if (fds[i] == NULL)
175           return i;
176     }
177   while (extend (NOFILE_INCR));
178   return -1;
179 }
180
181 void
182 dtable::release (int fd)
183 {
184   if (!not_open (fd))
185     {
186       if (fds[fd]->need_fixup_before ())
187         dec_need_fixup_before ();
188       delete fds[fd];
189       fds[fd] = NULL;
190     }
191 }
192
193 extern "C" int
194 cygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin,
195                             DWORD myaccess)
196 {
197   if (fd == -1)
198     fd = cygheap->fdtab.find_unused_handle ();
199   fhandler_base *fh = build_fh_name (name);
200   cygheap->fdtab[fd] = fh;
201   fh->init (handle, myaccess, bin ?: fh->pc_binmode ());
202   return fd;
203 }
204
205 void
206 dtable::init_std_file_from_handle (int fd, HANDLE handle)
207 {
208   const char *name = NULL;
209   CONSOLE_SCREEN_BUFFER_INFO buf;
210   struct sockaddr sa;
211   int sal = sizeof (sa);
212   DCB dcb;
213   unsigned bin = O_BINARY;
214   device dev;
215
216   dev.devn = 0;         /* FIXME: device */
217   first_fd_for_open = 0;
218
219   if (!not_open (fd))
220     return;
221
222   SetLastError (0);
223   DWORD ft = GetFileType (handle);
224   if (ft != FILE_TYPE_UNKNOWN || GetLastError () != ERROR_INVALID_HANDLE)
225     {
226       /* See if we can consoleify it */
227       if (GetConsoleScreenBufferInfo (handle, &buf))
228         {
229           if (ISSTATE (myself, PID_USETTY))
230             dev.parse ("/dev/tty");
231           else
232             dev = *console_dev;
233         }
234       else if (GetNumberOfConsoleInputEvents (handle, (DWORD *) &buf))
235         {
236           if (ISSTATE (myself, PID_USETTY))
237             dev.parse ("/dev/tty");
238           else
239             dev = *console_dev;
240         }
241       else if (ft == FILE_TYPE_PIPE)
242         {
243           if (fd == 0)
244             dev = *piper_dev;
245           else
246             dev = *pipew_dev;
247         }
248       else if (wsock_started && getpeername ((SOCKET) handle, &sa, &sal) == 0)
249         dev = *tcp_dev;
250       else if (GetCommState (handle, &dcb))
251         dev.parse ("/dev/ttyS0");
252       else
253         {
254           name = handle_to_fn (handle, (char *) alloca (MAX_PATH + 100));
255           bin = 0;
256         }
257     }
258
259   if (!name && !dev)
260     fds[fd] = NULL;
261   else
262     {
263       fhandler_base *fh;
264
265       if (dev)
266         fh = build_fh_dev (dev);
267       else
268         fh = build_fh_name (name);
269
270       if (fh)
271         cygheap->fdtab[fd] = fh;
272
273       if (!bin)
274         {
275           bin = fh->get_default_fmode (O_RDWR);
276           if (bin)
277             /* nothing */;
278           else if (dev)
279             bin = O_BINARY;
280           else if (name != unknown_file)
281             bin = fh->pc_binmode ();
282         }
283
284       fh->init (handle, GENERIC_READ | GENERIC_WRITE, bin);
285       set_std_handle (fd);
286       paranoid_printf ("fd %d, handle %p", fd, handle);
287     }
288 }
289
290 #define cnew(name) new ((void *) ccalloc (HEAP_FHANDLER, 1, sizeof (name))) name
291 fhandler_base *
292 build_fh_name (const char *name, HANDLE h, unsigned opt, suffix_info *si)
293 {
294   path_conv pc (name, opt | PC_NULLEMPTY | PC_FULL | PC_POSIX, si);
295   if (pc.error)
296     {
297       set_errno (pc.error);
298       return cnew (fhandler_nodevice) ();
299     }
300
301   if (!pc.exists () && h)
302     pc.fillin (h);
303
304   return build_fh_pc (pc);
305 }
306
307 fhandler_base *
308 build_fh_dev (const device& dev, const char *unix_name)
309 {
310   path_conv pc (dev);
311   char *w32buf = const_cast<char *> (pc.get_win32 ());
312
313   __small_sprintf (w32buf, dev.fmt, dev.minor);
314   if (unix_name)
315     pc.set_normalized_path (unix_name);
316   else if (!dev.upper)
317     pc.set_normalized_path (dev.name);
318   else
319     {
320       pc.set_normalized_path (w32buf);
321       for (char *p = strchr (pc.normalized_path, '\\');
322            p;
323            p = strchr (p + 1, '\\'))
324         *p = '/';
325     }
326   return build_fh_pc (pc);
327 }
328
329 fhandler_base *
330 build_fh_pc (path_conv& pc)
331 {
332   fhandler_base *fh = NULL;
333
334   if (pc.dev.upper)
335     switch (pc.dev.major)
336       {
337       case DEV_TTYS_MAJOR:
338         fh = cnew (fhandler_tty_slave) ();
339         break;
340       case DEV_TTYM_MAJOR:
341         fh = cnew (fhandler_tty_master) ();
342         break;
343       case DEV_CYGDRIVE_MAJOR:
344         fh = cnew (fhandler_cygdrive) ();
345         break;
346       case DEV_FLOPPY_MAJOR:
347       case DEV_CDROM_MAJOR:
348       case DEV_SD_MAJOR:
349       case DEV_RAWDRIVE_MAJOR:
350         fh = cnew (fhandler_dev_floppy) ();
351         break;
352       case DEV_TAPE_MAJOR:
353         fh = cnew (fhandler_dev_tape) ();
354         break;
355       }
356   else
357     switch (pc.dev)
358       {
359       case FH_CONSOLE:
360       case FH_CONIN:
361       case FH_CONOUT:
362         fh = cnew (fhandler_console) ();
363         break;
364       case FH_CYGDRIVE:
365         fh = cnew (fhandler_cygdrive) ();
366         break;
367       case FH_PTYM:
368         fh = cnew (fhandler_pty_master) ();
369         break;
370       case FH_WINDOWS:
371         fh = cnew (fhandler_windows) ();
372         break;
373       case FH_SERIAL:
374         fh = cnew (fhandler_serial) ();
375         break;
376       case FH_FIFO:
377         fh = cnew (fhandler_fifo) ();
378         break;
379       case FH_PIPE:
380       case FH_PIPER:
381       case FH_PIPEW:
382         fh = cnew (fhandler_pipe) ();
383         break;
384       case FH_TCP:
385       case FH_UDP:
386       case FH_ICMP:
387       case FH_UNIX:
388       case FH_STREAM:
389       case FH_DGRAM:
390         fh = cnew (fhandler_socket) ();
391         break;
392       case FH_FS:
393         fh = cnew (fhandler_disk_file) ();
394         break;
395       case FH_NULL:
396         fh = cnew (fhandler_dev_null) ();
397         break;
398       case FH_ZERO:
399         fh = cnew (fhandler_dev_zero) ();
400         break;
401       case FH_RANDOM:
402       case FH_URANDOM:
403         fh = cnew (fhandler_dev_random) ();
404         break;
405       case FH_MEM:
406       case FH_PORT:
407         fh = cnew (fhandler_dev_mem) ();
408         break;
409       case FH_CLIPBOARD:
410         fh = cnew (fhandler_dev_clipboard) ();
411         break;
412       case FH_OSS_DSP:
413         fh = cnew (fhandler_dev_dsp) ();
414         break;
415       case FH_PROC:
416         fh = cnew (fhandler_proc) ();
417         break;
418       case FH_REGISTRY:
419         fh = cnew (fhandler_registry) ();
420         break;
421       case FH_PROCESS:
422         fh = cnew (fhandler_process) ();
423         break;
424       case FH_TTY:
425         {
426           device newdev = pc.dev;
427           newdev.tty_to_real_device ();
428           switch (newdev)
429             {
430             case FH_CONSOLE:
431               fh = cnew (fhandler_console) ();
432               break;
433             case FH_TTYS:
434               fh = cnew (fhandler_tty_slave) ();
435               break;
436             }
437         }
438     }
439
440   if (!fh)
441     fh = cnew (fhandler_nodevice) ();
442
443   fh->set_name (pc);
444
445   debug_printf ("fh %p", fh);
446   return fh;
447 }
448
449 fhandler_base *
450 dtable::dup_worker (fhandler_base *oldfh)
451 {
452   fhandler_base *newfh = build_fh_pc (oldfh->pc);
453   *newfh = *oldfh;
454   newfh->set_io_handle (NULL);
455   if (oldfh->dup (newfh))
456     {
457       cfree (newfh);
458       newfh = NULL;
459       return NULL;
460     }
461
462   newfh->set_close_on_exec_flag (0);
463   MALLOC_CHECK;
464   debug_printf ("duped '%s' old %p, new %p", oldfh->get_name (), oldfh->get_io_handle (), newfh->get_io_handle ());
465   return newfh;
466 }
467
468 int
469 dtable::dup2 (int oldfd, int newfd)
470 {
471   int res = -1;
472   fhandler_base *newfh = NULL;  // = NULL to avoid an incorrect warning
473
474   MALLOC_CHECK;
475   debug_printf ("dup2 (%d, %d)", oldfd, newfd);
476   SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
477
478   if (not_open (oldfd))
479     {
480       syscall_printf ("fd %d not open", oldfd);
481       set_errno (EBADF);
482       goto done;
483     }
484
485   if (newfd < 0)
486     {
487       syscall_printf ("new fd out of bounds: %d", newfd);
488       set_errno (EBADF);
489       goto done;
490     }
491
492   if (newfd == oldfd)
493     {
494       res = 0;
495       goto done;
496     }
497
498   if ((newfh = dup_worker (fds[oldfd])) == NULL)
499     {
500       res = -1;
501       goto done;
502     }
503
504   debug_printf ("newfh->io_handle %p, oldfh->io_handle %p",
505                 newfh->get_io_handle (), fds[oldfd]->get_io_handle ());
506
507   if (!not_open (newfd))
508     close (newfd);
509   else if ((size_t) newfd < size)
510     /* nothing to do */;
511   else if (find_unused_handle (newfd) < 0)
512     {
513       newfh->close ();
514       res = -1;
515       goto done;
516     }
517
518   fds[newfd] = newfh;
519
520   if ((res = newfd) <= 2)
521     set_std_handle (res);
522
523 done:
524   MALLOC_CHECK;
525   ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
526   syscall_printf ("%d = dup2 (%d, %d)", res, oldfd, newfd);
527
528   return res;
529 }
530
531 fhandler_fifo *
532 dtable::find_fifo (ATOM hill)
533 {
534   SetResourceLock (LOCK_FD_LIST, READ_LOCK, "dup");
535   for (unsigned i = 0; i < size; i++)
536     {
537       fhandler_base *fh = fds[i];
538       if (fh && fh->isfifo () && ((fhandler_fifo *) fh)->get_atom () == hill)
539         return (fhandler_fifo *) fh;
540     }
541   return NULL;
542 }
543
544 select_record *
545 dtable::select_read (int fd, select_record *s)
546 {
547   if (not_open (fd))
548     {
549       set_errno (EBADF);
550       return NULL;
551     }
552   fhandler_base *fh = fds[fd];
553   s = fh->select_read (s);
554   s->fd = fd;
555   s->fh = fh;
556   s->saw_error = 0;
557   debug_printf ("%s fd %d", fh->get_name (), fd);
558   return s;
559 }
560
561 select_record *
562 dtable::select_write (int fd, select_record *s)
563 {
564   if (not_open (fd))
565     {
566       set_errno (EBADF);
567       return NULL;
568     }
569   fhandler_base *fh = fds[fd];
570   s = fh->select_write (s);
571   s->fd = fd;
572   s->fh = fh;
573   s->saw_error = 0;
574   debug_printf ("%s fd %d", fh->get_name (), fd);
575   return s;
576 }
577
578 select_record *
579 dtable::select_except (int fd, select_record *s)
580 {
581   if (not_open (fd))
582     {
583       set_errno (EBADF);
584       return NULL;
585     }
586   fhandler_base *fh = fds[fd];
587   s = fh->select_except (s);
588   s->fd = fd;
589   s->fh = fh;
590   s->saw_error = 0;
591   debug_printf ("%s fd %d", fh->get_name (), fd);
592   return s;
593 }
594
595 /* Function to walk the fd table after an exec and perform
596    per-fhandler type fixups. */
597 void
598 dtable::fixup_before_fork (DWORD target_proc_id)
599 {
600   SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fixup_before_fork");
601   fhandler_base *fh;
602   for (size_t i = 0; i < size; i++)
603     if ((fh = fds[i]) != NULL)
604       {
605         debug_printf ("fd %d (%s)", i, fh->get_name ());
606         fh->fixup_before_fork_exec (target_proc_id);
607       }
608   ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fixup_before_fork");
609 }
610
611 void
612 dtable::fixup_before_exec (DWORD target_proc_id)
613 {
614   SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fixup_before_exec");
615   fhandler_base *fh;
616   for (size_t i = 0; i < size; i++)
617     if ((fh = fds[i]) != NULL && !fh->get_close_on_exec ())
618       {
619         debug_printf ("fd %d (%s)", i, fh->get_name ());
620         fh->fixup_before_fork_exec (target_proc_id);
621       }
622   ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fixup_before_exec");
623 }
624
625 void
626 dtable::set_file_pointers_for_exec ()
627 {
628   SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "set_file_pointers_for_exec");
629   fhandler_base *fh;
630   for (size_t i = 0; i < size; i++)
631     if ((fh = fds[i]) != NULL && fh->get_flags () & O_APPEND)
632       SetFilePointer (fh->get_handle (), 0, 0, FILE_END);
633   ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fixup_before_exec");
634 }
635
636 void
637 dtable::fixup_after_exec (HANDLE parent)
638 {
639   first_fd_for_open = 0;
640   fhandler_base *fh;
641   for (size_t i = 0; i < size; i++)
642     if ((fh = fds[i]) != NULL)
643       {
644         fh->clear_readahead ();
645         if (fh->get_close_on_exec ())
646           release (i);
647         else
648           {
649             fh->fixup_after_exec (parent);
650             if (i == 0)
651               SetStdHandle (std_consts[i], fh->get_io_handle ());
652             else if (i <= 2)
653               SetStdHandle (std_consts[i], fh->get_output_handle ());
654           }
655       }
656 }
657
658 void
659 dtable::fixup_after_fork (HANDLE parent)
660 {
661   fhandler_base *fh;
662   for (size_t i = 0; i < size; i++)
663     if ((fh = fds[i]) != NULL)
664       {
665         if (fh->get_close_on_exec () || fh->get_need_fork_fixup ())
666           {
667             debug_printf ("fd %d (%s)", i, fh->get_name ());
668             fh->fixup_after_fork (parent);
669           }
670         if (i == 0)
671           SetStdHandle (std_consts[i], fh->get_io_handle ());
672         else if (i <= 2)
673           SetStdHandle (std_consts[i], fh->get_output_handle ());
674       }
675 }
676
677 int
678 dtable::vfork_child_dup ()
679 {
680   fhandler_base **newtable;
681   SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
682   newtable = (fhandler_base **) ccalloc (HEAP_ARGV, size, sizeof (fds[0]));
683   int res = 1;
684
685   /* Remove impersonation */
686   cygheap->user.deimpersonate ();
687
688   for (size_t i = 0; i < size; i++)
689     if (not_open (i))
690       continue;
691     else if ((newtable[i] = dup_worker (fds[i])) != NULL)
692       newtable[i]->set_close_on_exec (fds[i]->get_close_on_exec ());
693     else
694       {
695         res = 0;
696         set_errno (EBADF);
697         goto out;
698       }
699
700   fds_on_hold = fds;
701   fds = newtable;
702
703 out:
704   /* Restore impersonation */
705   cygheap->user.reimpersonate ();
706
707   ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup");
708   return 1;
709 }
710
711 void
712 dtable::vfork_parent_restore ()
713 {
714   SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "restore");
715
716   close_all_files ();
717   fhandler_base **deleteme = fds;
718   fds = fds_on_hold;
719   fds_on_hold = NULL;
720   cfree (deleteme);
721
722   ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "restore");
723   return;
724 }
725
726 void
727 dtable::vfork_child_fixup ()
728 {
729   if (!fds_on_hold)
730     return;
731   debug_printf ("here");
732   fhandler_base **saveme = fds;
733   fds = fds_on_hold;
734
735   fhandler_base *fh;
736   for (int i = 0; i < (int) cygheap->fdtab.size; i++)
737     if ((fh = cygheap->fdtab[i]) != NULL)
738       {
739         fh->clear_readahead ();
740         if (fh->get_close_on_exec ())
741           release (i);
742         else
743           {
744             fh->close ();
745             cygheap->fdtab.release (i);
746           }
747       }
748
749   fds = saveme;
750   cfree (fds_on_hold);
751   fds_on_hold = NULL;
752
753   return;
754 }
755
756 #define DEVICE_PREFIX "\\device\\"
757 #define DEVICE_PREFIX_LEN sizeof (DEVICE_PREFIX) - 1
758 #define REMOTE "\\Device\\LanmanRedirector\\"
759 #define REMOTE_LEN sizeof (REMOTE) - 1
760
761 static const char *
762 handle_to_fn (HANDLE h, char *posix_fn)
763 {
764   OBJECT_NAME_INFORMATION *ntfn;
765   char fnbuf[32768];
766
767   memset (fnbuf, 0, sizeof (fnbuf));
768   ntfn = (OBJECT_NAME_INFORMATION *) fnbuf;
769   ntfn->Name.MaximumLength = sizeof (fnbuf) - sizeof (*ntfn);
770   ntfn->Name.Buffer = (WCHAR *) (ntfn + 1);
771
772   DWORD res = NtQueryObject (h, ObjectNameInformation, ntfn, sizeof (fnbuf), NULL);
773
774   if (res)
775     {
776       strcpy (posix_fn, unknown_file);
777       debug_printf ("NtQueryObject failed");
778       return unknown_file;
779     }
780
781   // NT seems to do this on an unopened file
782   if (!ntfn->Name.Buffer)
783     {
784       debug_printf ("nt->Name.Buffer == NULL");
785       return NULL;
786     }
787
788   ntfn->Name.Buffer[ntfn->Name.Length / sizeof (WCHAR)] = 0;
789
790   char win32_fn[MAX_PATH + 100];
791   sys_wcstombs (win32_fn, ntfn->Name.Buffer, ntfn->Name.Length);
792   debug_printf ("nt name '%s'", win32_fn);
793   if (!strncasematch (win32_fn, DEVICE_PREFIX, DEVICE_PREFIX_LEN)
794       || !QueryDosDevice (NULL, fnbuf, sizeof (fnbuf)))
795     return strcpy (posix_fn, win32_fn);
796
797   char *p = strechr (win32_fn + DEVICE_PREFIX_LEN, '\\');
798
799   int n = p - win32_fn;
800   int maxmatchlen = 0;
801   char *maxmatchdos = NULL;
802   for (char *s = fnbuf; *s; s = strchr (s, '\0') + 1)
803     {
804       char device[MAX_PATH + 10];
805       device[MAX_PATH + 9] = '\0';
806       if (strchr (s, ':') == NULL)
807         continue;
808       if (!QueryDosDevice (s, device, sizeof (device) - 1))
809         continue;
810       char *q = strrchr (device, ';');
811       if (q)
812         {
813           char *r = strchr (q, '\\');
814           if (r)
815             strcpy (q, r + 1);
816         }
817       int devlen = strlen (device);
818       if (device[devlen - 1] == '\\')
819         device[--devlen] = '\0';
820       if (devlen < maxmatchlen)
821         continue;
822       if (!strncasematch (device, win32_fn, devlen) ||
823           (win32_fn[devlen] != '\0' && win32_fn[devlen] != '\\'))
824         continue;
825       maxmatchlen = devlen;
826       maxmatchdos = s;
827       debug_printf ("current match '%s'", device);
828     }
829
830   char *w32 = win32_fn;
831   if (maxmatchlen)
832     {
833       n = strlen (maxmatchdos);
834       if (maxmatchdos[n - 1] == '\\')
835         n--;
836       w32 += maxmatchlen - n;
837       memcpy (w32, maxmatchdos, n);
838       w32[n] = '\\';
839     }
840   else if (strncasematch (w32, REMOTE, REMOTE_LEN))
841     {
842       w32 += REMOTE_LEN - 2;
843       *w32 = '\\';
844       debug_printf ("remote drive");
845     }
846
847
848   debug_printf ("derived path '%s'", w32);
849   cygwin_conv_to_full_posix_path (w32, posix_fn);
850   return posix_fn;
851 }