OSDN Git Service

* fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Simplify.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / fhandler_disk_file.cc
1 /* fhandler_disk_file.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4    2005, 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include <stdlib.h>
14 #include <sys/acl.h>
15 #include <sys/statvfs.h>
16 #include "cygerrno.h"
17 #include "security.h"
18 #include "path.h"
19 #include "fhandler.h"
20 #include "dtable.h"
21 #include "cygheap.h"
22 #include "shared_info.h"
23 #include "pinfo.h"
24 #include "ntdll.h"
25 #include "tls_pbuf.h"
26 #include "pwdgrp.h"
27 #include <winioctl.h>
28
29 #define _COMPILING_NEWLIB
30 #include <dirent.h>
31
32 class __DIR_mounts
33 {
34   int            count;
35   const char    *parent_dir;
36   int            parent_dir_len;
37   UNICODE_STRING mounts[MAX_MOUNTS];
38   bool           found[MAX_MOUNTS + 2];
39   UNICODE_STRING cygdrive;
40
41 #define __DIR_PROC      (MAX_MOUNTS)
42 #define __DIR_CYGDRIVE  (MAX_MOUNTS+1)
43
44   __ino64_t eval_ino (int idx)
45     {
46       __ino64_t ino = 0;
47       char fname[parent_dir_len + mounts[idx].Length + 2];
48       struct __stat64 st;
49
50       char *c = stpcpy (fname, parent_dir);
51       if (c[- 1] != '/')
52         *c++ = '/';
53       sys_wcstombs (c, mounts[idx].Length + 1,
54                     mounts[idx].Buffer, mounts[idx].Length / sizeof (WCHAR));
55       path_conv pc (fname, PC_SYM_NOFOLLOW | PC_POSIX);
56       if (!stat_worker (pc, &st))
57         ino = st.st_ino;
58       return ino;
59     }
60
61 public:
62   __DIR_mounts (const char *posix_path)
63   : parent_dir (posix_path)
64     {
65       parent_dir_len = strlen (parent_dir);
66       count = mount_table->get_mounts_here (parent_dir, parent_dir_len, mounts,
67                                             &cygdrive);
68       rewind ();
69     }
70   ~__DIR_mounts ()
71     {
72       for (int i = 0; i < count; ++i)
73         RtlFreeUnicodeString (&mounts[i]);
74       RtlFreeUnicodeString (&cygdrive);
75     }
76   __ino64_t check_mount (PUNICODE_STRING fname, __ino64_t ino,
77                          bool eval = true)
78     {
79       if (parent_dir_len == 1)  /* root dir */
80         {
81           if (RtlEqualUnicodeString (fname, &ro_u_proc, FALSE))
82             {
83               found[__DIR_PROC] = true;
84               return 2;
85             }
86           if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2
87               && RtlEqualUnicodeString (fname, &cygdrive, FALSE))
88             {
89               found[__DIR_CYGDRIVE] = true;
90               return 2;
91             }
92         }
93       for (int i = 0; i < count; ++i)
94         if (RtlEqualUnicodeString (fname, &mounts[i], FALSE))
95           {
96             found[i] = true;
97             return eval ? eval_ino (i) : 1;
98           }
99       return ino;
100     }
101   __ino64_t check_missing_mount (PUNICODE_STRING retname = NULL)
102     {
103       for (int i = 0; i < count; ++i)
104         if (!found[i])
105           {
106             found[i] = true;
107             if (retname)
108               {
109                 *retname = mounts[i];
110                 return eval_ino (i);
111               }
112             return 1;
113           }
114       if (parent_dir_len == 1)  /* root dir */
115         {
116           if (!found[__DIR_PROC])
117             {
118               found[__DIR_PROC] = true;
119               if (retname)
120                 *retname = ro_u_proc;
121               return 2;
122             }
123           if (!found[__DIR_CYGDRIVE])
124             {
125               found[__DIR_CYGDRIVE] = true;
126               if (cygdrive.Length > 0)
127                 {
128                   if (retname)
129                     *retname = cygdrive;
130                   return 2;
131                 }
132             }
133         }
134       return 0;
135     }
136     void rewind () { memset (found, 0, sizeof found); }
137 };
138
139 inline bool
140 path_conv::isgood_inode (__ino64_t ino) const
141 {
142   /* We can't trust remote inode numbers of only 32 bit.  That means,
143      all remote inode numbers when running under NT4, as well as remote NT4
144      NTFS, as well as shares of Samba version < 3.0.
145      The known exception are SFU NFS shares, which return the valid 32 bit
146      inode number from the remote file system unchanged. */
147   return hasgood_inode () && (ino > UINT32_MAX || !isremote () || fs_is_nfs ());
148 }
149
150 /* Check reparse point for type.  IO_REPARSE_TAG_MOUNT_POINT types are
151    either volume mount points, which are treated as directories, or they
152    are directory mount points, which are treated as symlinks.
153    IO_REPARSE_TAG_SYMLINK types are always symlinks.  We don't know
154    anything about other reparse points, so they are treated as unknown.  */
155 static inline int
156 readdir_check_reparse_point (POBJECT_ATTRIBUTES attr)
157 {
158   DWORD ret = DT_UNKNOWN;
159   IO_STATUS_BLOCK io;
160   HANDLE reph;
161   UNICODE_STRING subst;
162
163   if (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, attr, &io,
164                               FILE_SHARE_VALID_FLAGS,
165                               FILE_OPEN_FOR_BACKUP_INTENT
166                               | FILE_OPEN_REPARSE_POINT)))
167     {
168       PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER)
169                   alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
170       if (NT_SUCCESS (NtFsControlFile (reph, NULL, NULL, NULL,
171                       &io, FSCTL_GET_REPARSE_POINT, NULL, 0,
172                       (LPVOID) rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)))
173         {
174           if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
175             {
176               RtlInitCountedUnicodeString (&subst, 
177                   (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
178                             + rp->MountPointReparseBuffer.SubstituteNameOffset),
179                   rp->MountPointReparseBuffer.SubstituteNameLength);
180               /* Only volume mountpoints are treated as directories. */
181               if (RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE))
182                 ret = DT_DIR;
183               else
184                 ret = DT_LNK;
185             }
186           else if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
187             ret = DT_LNK;
188           NtClose (reph);
189         }
190     }
191   return ret;
192 }
193
194 inline __ino64_t
195 path_conv::get_ino_by_handle (HANDLE hdl)
196 {
197   IO_STATUS_BLOCK io;
198   FILE_INTERNAL_INFORMATION fai;
199
200   if (NT_SUCCESS (NtQueryInformationFile (hdl, &io, &fai, sizeof fai,
201                                           FileInternalInformation))
202       && isgood_inode (fai.FileId.QuadPart))
203     return fai.FileId.QuadPart;
204   return 0;
205 }
206
207 #if 0
208 /* This function is obsolete.  We're keeping it in so we don't forget
209    that we already did all that at one point. */
210 unsigned __stdcall
211 path_conv::ndisk_links (DWORD nNumberOfLinks)
212 {
213   if (!isdir () || isremote ())
214     return nNumberOfLinks;
215
216   OBJECT_ATTRIBUTES attr;
217   IO_STATUS_BLOCK io;
218   HANDLE fh;
219
220   if (!NT_SUCCESS (NtOpenFile (&fh, SYNCHRONIZE | FILE_LIST_DIRECTORY,
221                                get_object_attr (attr, sec_none_nih),
222                                &io, FILE_SHARE_VALID_FLAGS,
223                                FILE_SYNCHRONOUS_IO_NONALERT
224                                | FILE_OPEN_FOR_BACKUP_INTENT
225                                | FILE_DIRECTORY_FILE)))
226     return nNumberOfLinks;
227
228   unsigned count = 0;
229   bool first = true;
230   PFILE_BOTH_DIRECTORY_INFORMATION fdibuf = (PFILE_BOTH_DIRECTORY_INFORMATION)
231                                        alloca (65536);
232   __DIR_mounts *dir = new __DIR_mounts (normalized_path);
233   while (NT_SUCCESS (NtQueryDirectoryFile (fh, NULL, NULL, NULL, &io, fdibuf,
234                                            65536, FileBothDirectoryInformation,
235                                            FALSE, NULL, first)))
236     {
237       if (first)
238         {
239           first = false;
240           /* All directories have . and .. as their first entries.
241              If . is not present as first entry, we're on a drive's
242              root direcotry, which doesn't have these entries. */
243           if (fdibuf->FileNameLength != 2 || fdibuf->FileName[0] != L'.')
244             count = 2;
245         }
246       for (PFILE_BOTH_DIRECTORY_INFORMATION pfdi = fdibuf;
247            pfdi;
248            pfdi = (PFILE_BOTH_DIRECTORY_INFORMATION)
249                   (pfdi->NextEntryOffset ? (PBYTE) pfdi + pfdi->NextEntryOffset
250                                          : NULL))
251         {
252           switch (pfdi->FileAttributes
253                   & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
254             {
255             case FILE_ATTRIBUTE_DIRECTORY:
256               /* Just a directory */
257               ++count;
258               break;
259             case FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT:
260               /* Volume mount point or symlink to directory */
261               {
262                 UNICODE_STRING fname;
263
264                 RtlInitCountedUnicodeString (&fname, pfdi->FileName,
265                                              pfdi->FileNameLength);
266                 InitializeObjectAttributes (&attr, &fname,
267                                             objcaseinsensitive (), fh, NULL);
268                 if (is_volume_mountpoint (&attr))
269                   ++count;
270               }
271               break;
272             default:
273               break;
274             }
275           UNICODE_STRING fname;
276           RtlInitCountedUnicodeString (&fname, pfdi->FileName,
277                                        pfdi->FileNameLength);
278           dir->check_mount (&fname, 0, false);
279         }
280     }
281   while (dir->check_missing_mount ())
282     ++count;
283   NtClose (fh);
284   delete dir;
285   return count;
286 }
287 #endif
288
289 /* For files on NFS shares, we request an EA of type NfsV3Attributes.
290    This returns the content of a struct fattr3 as defined in RFC 1813.
291    The content is the NFS equivalent of struct stat. so there's not much
292    to do here except for copying. */
293 int __stdcall
294 fhandler_base::fstat_by_nfs_ea (struct __stat64 *buf)
295 {
296   fattr3 *nfs_attr = pc.nfsattr ();
297
298   if (get_io_handle ())
299     {
300       /* NFS stumbles over its own caching.  If you write to the file,
301          a subsequent fstat does not return the actual size of the file,
302          but the size at the time the handle has been opened.  Unless
303          access through another handle invalidates the caching within the
304          NFS client. */
305       if (get_access () & GENERIC_WRITE)
306         FlushFileBuffers (get_io_handle ());
307       nfs_fetch_fattr3 (get_io_handle (), nfs_attr);
308     }
309   buf->st_dev = nfs_attr->fsid;
310   buf->st_ino = nfs_attr->fileid;
311   buf->st_mode = (nfs_attr->mode & 0xfff)
312                  | nfs_type_mapping[nfs_attr->type & 7];
313   buf->st_nlink = nfs_attr->nlink;
314   /* FIXME: How to convert UNIX uid/gid to Windows SIDs? */
315 #if 0
316   buf->st_uid = nfs_attr->uid;
317   buf->st_gid = nfs_attr->gid;
318 #else
319   buf->st_uid = myself->uid;
320   buf->st_gid = myself->gid;
321 #endif
322   buf->st_rdev = makedev (nfs_attr->rdev.specdata1,
323                           nfs_attr->rdev.specdata2);
324   buf->st_size = nfs_attr->size;
325   buf->st_blksize = PREFERRED_IO_BLKSIZE;
326   buf->st_blocks = nfs_attr->used / 512;
327   buf->st_atim = nfs_attr->atime;
328   buf->st_mtim = nfs_attr->mtime;
329   buf->st_ctim = nfs_attr->ctime;
330   return 0;
331 }
332
333 int __stdcall
334 fhandler_base::fstat_by_handle (struct __stat64 *buf)
335 {
336   /* Don't use FileAllInformation info class.  It returns a pathname rather
337      than a filename, so it needs a really big buffer for no good reason
338      since we don't need the name anyway.  So we just call the three info
339      classes necessary to get all information required by stat(2). */
340   FILE_STANDARD_INFORMATION fsi;
341   FILE_INTERNAL_INFORMATION fii;
342
343   HANDLE h = get_stat_handle ();
344   NTSTATUS status = 0;
345   IO_STATUS_BLOCK io;
346
347   /* If the file has been opened for other purposes than stat, we can't rely
348      on the information stored in pc.fnoi.  So we overwrite them here. */
349   if (get_io_handle ())
350     {
351       PFILE_NETWORK_OPEN_INFORMATION pfnoi = pc.fnoi ();
352       status = NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi,
353                                       FileNetworkOpenInformation);
354       if (!NT_SUCCESS (status))
355        {
356          debug_printf ("%p = NtQueryInformationFile(%S, "
357                        "FileNetworkOpenInformation)",
358                        status, pc.get_nt_native_path ());
359          return -1;
360        }
361     }
362   if (!pc.hasgood_inode ())
363     fsi.NumberOfLinks = 1;
364   else
365     {
366       status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
367                                        FileStandardInformation);
368       if (!NT_SUCCESS (status))
369         {
370           debug_printf ("%p = NtQueryInformationFile(%S, "
371                         "FileStandardInformation)",
372                         status, pc.get_nt_native_path ());
373           return -1;
374         }
375       if (!ino)
376         {
377           status = NtQueryInformationFile (h, &io, &fii, sizeof fii,
378                                            FileInternalInformation);
379           if (!NT_SUCCESS (status))
380             {
381               debug_printf ("%p = NtQueryInformationFile(%S, "
382                             "FileInternalInformation)",
383                             status, pc.get_nt_native_path ());
384               return -1;
385             }
386           ino = fii.FileId.QuadPart;
387         }
388     }
389   return fstat_helper (buf, fsi.NumberOfLinks);
390 }
391
392 int __stdcall
393 fhandler_base::fstat_by_name (struct __stat64 *buf)
394 {
395   NTSTATUS status;
396   OBJECT_ATTRIBUTES attr;
397   IO_STATUS_BLOCK io;
398   UNICODE_STRING dirname;
399   UNICODE_STRING basename;
400   HANDLE dir;
401   struct {
402     FILE_ID_BOTH_DIR_INFORMATION fdi;
403     WCHAR buf[NAME_MAX + 1];
404   } fdi_buf;
405
406   if (!ino && pc.hasgood_inode ()
407       && wincap.has_fileid_dirinfo () && !pc.has_buggy_fileid_dirinfo ())
408     {
409       RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, &basename);
410       InitializeObjectAttributes (&attr, &dirname, pc.objcaseinsensitive (),
411                                   NULL, NULL);
412       status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
413                            &attr, &io, FILE_SHARE_VALID_FLAGS,
414                            FILE_SYNCHRONOUS_IO_NONALERT
415                            | FILE_OPEN_FOR_BACKUP_INTENT
416                            | FILE_DIRECTORY_FILE);
417       if (!NT_SUCCESS (status))
418         debug_printf ("%p = NtOpenFile(%S)", status,
419                       pc.get_nt_native_path ());
420       else
421         {
422           status = NtQueryDirectoryFile (dir, NULL, NULL, NULL, &io,
423                                          &fdi_buf.fdi, sizeof fdi_buf,
424                                          FileIdBothDirectoryInformation,
425                                          TRUE, &basename, TRUE);
426           NtClose (dir);
427           if (!NT_SUCCESS (status))
428             debug_printf ("%p = NtQueryDirectoryFile(%S)", status,
429                           pc.get_nt_native_path ());
430           else
431             ino = fdi_buf.fdi.FileId.QuadPart;
432         }
433     }
434   return fstat_helper (buf, 1);
435 }
436
437 int __stdcall
438 fhandler_base::fstat_fs (struct __stat64 *buf)
439 {
440   int res = -1;
441   int oret;
442   int open_flags = O_RDONLY | O_BINARY;
443
444   if (get_stat_handle ())
445     {
446       if (!nohandle () && !is_fs_special ())
447         res = pc.fs_is_nfs () ? fstat_by_nfs_ea (buf) : fstat_by_handle (buf);
448       if (res)
449         res = fstat_by_name (buf);
450       return res;
451     }
452   /* First try to open with generic read access.  This allows to read the file
453      in fstat_helper (when checking for executability) without having to
454      re-open it.  Opening a file can take a lot of time on network drives
455      so we try to avoid that. */
456   oret = open_fs (open_flags, 0);
457   if (!oret)
458     {
459       query_open (query_read_attributes);
460       oret = open_fs (open_flags, 0);
461     }
462   if (oret)
463     {
464       /* We now have a valid handle, regardless of the "nohandle" state.
465          Since fhandler_base::open only calls CloseHandle if !nohandle,
466          we have to set it to false before calling close and restore
467          the state afterwards. */
468       res = pc.fs_is_nfs () ? fstat_by_nfs_ea (buf) : fstat_by_handle (buf);
469       bool no_handle = nohandle ();
470       nohandle (false);
471       close_fs ();
472       nohandle (no_handle);
473       set_io_handle (NULL);
474     }
475   if (res)
476     res = fstat_by_name (buf);
477
478   return res;
479 }
480
481 int __stdcall
482 fhandler_base::fstat_helper (struct __stat64 *buf,
483                              DWORD nNumberOfLinks)
484 {
485   IO_STATUS_BLOCK st;
486   FILE_COMPRESSION_INFORMATION fci;
487   HANDLE h = get_stat_handle ();
488   PFILE_NETWORK_OPEN_INFORMATION pfnoi = pc.fnoi ();
489   ULONG attributes = pc.file_attributes ();
490
491   to_timestruc_t ((PFILETIME) &pfnoi->LastAccessTime, &buf->st_atim);
492   to_timestruc_t ((PFILETIME) &pfnoi->LastWriteTime, &buf->st_mtim);
493   /* If the ChangeTime is 0, the underlying FS doesn't support this timestamp
494      (FAT for instance).  If so, it's faked using LastWriteTime. */
495   to_timestruc_t (pfnoi->ChangeTime.QuadPart ? (PFILETIME) &pfnoi->ChangeTime
496                                             : (PFILETIME) &pfnoi->LastWriteTime,
497                   &buf->st_ctim);
498   to_timestruc_t ((PFILETIME) &pfnoi->CreationTime, &buf->st_birthtim);
499   buf->st_rdev = buf->st_dev = get_dev ();
500   buf->st_size = (_off64_t) pfnoi->EndOfFile.QuadPart;
501   /* The number of links to a directory includes the number of subdirectories
502      in the directory, since all those subdirectories point to it.  However,
503      this is painfully slow, so we do without it. */
504 #if 0
505   buf->st_nlink = pc.ndisk_links (nNumberOfLinks);
506 #else
507   buf->st_nlink = nNumberOfLinks;
508 #endif
509
510   /* Enforce namehash as inode number on untrusted file systems. */
511   if (ino && pc.isgood_inode (ino))
512     buf->st_ino = (__ino64_t) ino;
513   else
514     buf->st_ino = get_ino ();
515
516   buf->st_blksize = PREFERRED_IO_BLKSIZE;
517
518   if (pfnoi->AllocationSize.QuadPart >= 0LL)
519     /* A successful NtQueryInformationFile returns the allocation size
520        correctly for compressed and sparse files as well. */
521     buf->st_blocks = (pfnoi->AllocationSize.QuadPart + S_BLKSIZE - 1)
522                      / S_BLKSIZE;
523   else if (::has_attribute (attributes, FILE_ATTRIBUTE_COMPRESSED
524                                         | FILE_ATTRIBUTE_SPARSE_FILE)
525            && h && !is_fs_special ()
526            && !NtQueryInformationFile (h, &st, (PVOID) &fci, sizeof fci,
527                                        FileCompressionInformation))
528     /* Otherwise we request the actual amount of bytes allocated for
529        compressed and sparsed files. */
530     buf->st_blocks = (fci.CompressedFileSize.QuadPart + S_BLKSIZE - 1)
531                      / S_BLKSIZE;
532   else
533     /* Otherwise compute no. of blocks from file size. */
534     buf->st_blocks  = (buf->st_size + S_BLKSIZE - 1) / S_BLKSIZE;
535
536   buf->st_mode = 0;
537   /* Using a side effect: get_file_attributes checks for directory.
538      This is used, to set S_ISVTX, if needed.  */
539   if (pc.isdir ())
540     buf->st_mode = S_IFDIR;
541   else if (pc.issymlink ())
542     {
543       buf->st_size = pc.get_symlink_length ();
544       /* symlinks are everything for everyone! */
545       buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
546       get_file_attribute (h, pc, NULL,
547                           &buf->st_uid, &buf->st_gid);
548       goto done;
549     }
550   else if (pc.issocket ())
551     buf->st_mode = S_IFSOCK;
552
553   if (!get_file_attribute (is_fs_special () && !pc.issocket () ? NULL : h, pc,
554                            &buf->st_mode, &buf->st_uid, &buf->st_gid))
555     {
556       /* If read-only attribute is set, modify ntsec return value */
557       if (::has_attribute (attributes, FILE_ATTRIBUTE_READONLY)
558           && !pc.isdir () && !pc.issymlink ())
559         buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
560
561       if (buf->st_mode & S_IFMT)
562         /* nothing */;
563       else if (!is_fs_special ())
564         buf->st_mode |= S_IFREG;
565       else
566         {
567           buf->st_dev = buf->st_rdev = dev ();
568           buf->st_mode = dev ().mode;
569           buf->st_size = 0;
570         }
571     }
572   else
573     {
574       buf->st_mode |= STD_RBITS;
575
576       if (!::has_attribute (attributes, FILE_ATTRIBUTE_READONLY))
577         buf->st_mode |= STD_WBITS;
578       /* | S_IWGRP | S_IWOTH; we don't give write to group etc */
579
580       if (pc.isdir ())
581         buf->st_mode |= S_IFDIR | STD_WBITS | STD_XBITS;
582       else if (buf->st_mode & S_IFMT)
583         /* nothing */;
584       else if (is_fs_special ())
585         {
586           buf->st_dev = buf->st_rdev = dev ();
587           buf->st_mode = dev ().mode;
588           buf->st_size = 0;
589         }
590       else
591         {
592           buf->st_mode |= S_IFREG;
593           /* Check suffix for executable file. */
594           if (pc.exec_state () == dont_know_if_executable)
595             {
596               PUNICODE_STRING path = pc.get_nt_native_path ();
597
598               if (RtlEqualUnicodePathSuffix (path, &ro_u_exe, TRUE)
599                   || RtlEqualUnicodePathSuffix (path, &ro_u_lnk, TRUE)
600                   || RtlEqualUnicodePathSuffix (path, &ro_u_com, TRUE))
601                 pc.set_exec ();
602             }
603           /* No known suffix, check file header.  This catches binaries and
604              shebang scripts. */
605           if (pc.exec_state () == dont_know_if_executable)
606             {
607               LARGE_INTEGER off = { QuadPart:0LL };
608               char magic[3];
609               NTSTATUS status = 0;
610               IO_STATUS_BLOCK io;
611               bool opened = false;
612
613               if (h == get_handle ())
614                 {
615                   /* We have been opened via fstat.  We have to re-open the
616                      file.  Either the file is not opened for reading, or the
617                      read will change the file position. */
618                   OBJECT_ATTRIBUTES attr;
619                   pc.init_reopen_attr (&attr, h);
620                   status = NtOpenFile (&h, SYNCHRONIZE | FILE_READ_DATA,
621                                        &attr, &io, FILE_SHARE_VALID_FLAGS,
622                                        FILE_OPEN_FOR_BACKUP_INTENT
623                                        | FILE_OPEN_REPARSE_POINT);
624                   if (!NT_SUCCESS (status))
625                     debug_printf ("%p = NtOpenFile(%S)", status,
626                                   pc.get_nt_native_path ());
627                   else
628                     opened = true;
629                 }
630               if (NT_SUCCESS (status))
631                 {
632                   status = NtReadFile (h, NULL, NULL, NULL,
633                                        &io, magic, 3, &off, NULL);
634                   status = wait_pending (status, h, io);
635                   if (!NT_SUCCESS (status))
636                     debug_printf ("%p = NtReadFile(%S)", status,
637                                   pc.get_nt_native_path ());
638                   else if (has_exec_chars (magic, io.Information))
639                     {
640                       /* Heureka, it's an executable */
641                       pc.set_exec ();
642                       buf->st_mode |= STD_XBITS;
643                     }
644                 }
645               if (opened)
646                 NtClose (h);
647             }
648         }
649       if (pc.exec_state () == is_executable)
650         buf->st_mode |= STD_XBITS;
651
652       /* This fakes the permissions of all files to match the current umask. */
653       buf->st_mode &= ~(cygheap->umask);
654       /* If the FS supports ACLs, we're here because we couldn't even open
655          the file for READ_CONTROL access.  Chances are high that the file's
656          security descriptor has no ACE for "Everyone", so we should not fake
657          any access for "others". */
658       if (has_acls ())
659         buf->st_mode &= ~(S_IROTH | S_IWOTH | S_IXOTH);
660     }
661
662  done:
663   syscall_printf ("0 = fstat (%S, %p) st_atime=%x st_size=%D, st_mode=%p, "
664                   "st_ino=%D, sizeof=%d",
665                   pc.get_nt_native_path (), buf, buf->st_atime, buf->st_size,
666                   buf->st_mode, buf->st_ino, sizeof (*buf));
667   return 0;
668 }
669
670 int __stdcall
671 fhandler_disk_file::fstat (struct __stat64 *buf)
672 {
673   return fstat_fs (buf);
674 }
675
676 int __stdcall
677 fhandler_disk_file::fstatvfs (struct statvfs *sfs)
678 {
679   int ret = -1, opened = 0;
680   NTSTATUS status;
681   IO_STATUS_BLOCK io;
682   FILE_FS_FULL_SIZE_INFORMATION full_fsi;
683   FILE_FS_SIZE_INFORMATION fsi;
684   /* We must not use the stat handle here, even if it exists.  The handle
685      has been opened with FILE_OPEN_REPARSE_POINT, thus, in case of a volume
686      mount point, it points to the FS of the mount point, rather than to the
687      mounted FS. */
688   HANDLE fh = get_handle ();
689
690   if (!fh)
691     {
692       OBJECT_ATTRIBUTES attr;
693       opened = NT_SUCCESS (NtOpenFile (&fh, READ_CONTROL,
694                                        pc.get_object_attr (attr, sec_none_nih),
695                                        &io, FILE_SHARE_VALID_FLAGS,
696                                        FILE_OPEN_FOR_BACKUP_INTENT));
697       if (!opened)
698         {
699           /* Can't open file.  Try again with parent dir. */
700           UNICODE_STRING dirname;
701           RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, NULL);
702           attr.ObjectName = &dirname;
703           opened = NT_SUCCESS (NtOpenFile (&fh, READ_CONTROL, &attr, &io,
704                                            FILE_SHARE_VALID_FLAGS,
705                                            FILE_OPEN_FOR_BACKUP_INTENT));
706           if (!opened)
707             goto out;
708         }
709     }
710
711   sfs->f_files = ULONG_MAX;
712   sfs->f_ffree = ULONG_MAX;
713   sfs->f_favail = ULONG_MAX;
714   sfs->f_fsid = pc.fs_serial_number ();
715   sfs->f_flag = pc.fs_flags ();
716   sfs->f_namemax = pc.fs_name_len ();
717   /* Get allocation related information.  Try to get "full" information
718      first, which is only available since W2K.  If that fails, try to
719      retrieve normal allocation information. */
720   status = NtQueryVolumeInformationFile (fh, &io, &full_fsi, sizeof full_fsi,
721                                          FileFsFullSizeInformation);
722   if (NT_SUCCESS (status))
723     {
724       sfs->f_bsize = full_fsi.BytesPerSector * full_fsi.SectorsPerAllocationUnit;
725       sfs->f_frsize = sfs->f_bsize;
726       sfs->f_blocks = full_fsi.TotalAllocationUnits.LowPart;
727       sfs->f_bfree = full_fsi.ActualAvailableAllocationUnits.LowPart;
728       sfs->f_bavail = full_fsi.CallerAvailableAllocationUnits.LowPart;
729       if (sfs->f_bfree > sfs->f_bavail)
730         {
731           /* Quotas active.  We can't trust TotalAllocationUnits. */
732           NTFS_VOLUME_DATA_BUFFER nvdb;
733
734           status = NtFsControlFile (fh, NULL, NULL, NULL, &io,
735                                     FSCTL_GET_NTFS_VOLUME_DATA,
736                                     NULL, 0, &nvdb, sizeof nvdb);
737           if (!NT_SUCCESS (status))
738             debug_printf ("%p = NtFsControlFile(%S, FSCTL_GET_NTFS_VOLUME_DATA)",
739                           status, pc.get_nt_native_path ());
740           else
741             sfs->f_blocks = nvdb.TotalClusters.QuadPart;
742         }
743       ret = 0;
744     }
745   else
746     {
747       status = NtQueryVolumeInformationFile (fh, &io, &fsi, sizeof fsi,
748                                              FileFsSizeInformation);
749       if (!NT_SUCCESS (status))
750         {
751           __seterrno_from_nt_status (status);
752           goto out;
753         }
754       sfs->f_bsize = fsi.BytesPerSector * fsi.SectorsPerAllocationUnit;
755       sfs->f_frsize = sfs->f_bsize;
756       sfs->f_blocks = fsi.TotalAllocationUnits.LowPart;
757       sfs->f_bfree = fsi.AvailableAllocationUnits.LowPart;
758       sfs->f_bavail = sfs->f_bfree;
759       ret = 0;
760     }
761 out:
762   if (opened)
763     NtClose (fh);
764   syscall_printf ("%d = fstatvfs (%s, %p)", ret, get_name (), sfs);
765   return ret;
766 }
767
768 int __stdcall
769 fhandler_disk_file::fchmod (mode_t mode)
770 {
771   extern int chmod_device (path_conv& pc, mode_t mode);
772   int res = -1;
773   int oret = 0;
774   NTSTATUS status;
775   IO_STATUS_BLOCK io;
776
777   if (pc.is_fs_special ())
778     return chmod_device (pc, mode);
779
780   if (!get_handle ())
781     {
782       query_open (query_write_dac);
783       if (!(oret = open (O_BINARY, 0)))
784         {
785           /* Need WRITE_DAC|WRITE_OWNER to write ACLs. */
786           if (pc.has_acls ())
787             return -1;
788           /* Otherwise FILE_WRITE_ATTRIBUTES is sufficient. */
789           query_open (query_write_attributes);
790           if (!(oret = open (O_BINARY, 0)))
791             return -1;
792         }
793     }
794
795   if (pc.fs_is_nfs ())
796     {
797       /* chmod on NFS shares works by writing an EA of type NfsV3Attributes.
798          Only type and mode have to be set.  Apparently type isn't checked
799          for consistency, so it's sufficent to set it to NF3REG all the time. */
800       struct {
801         FILE_FULL_EA_INFORMATION ffei;
802         char buf[sizeof (NFS_V3_ATTR) + sizeof (fattr3)];
803       } ffei_buf;
804       ffei_buf.ffei.NextEntryOffset = 0;
805       ffei_buf.ffei.Flags = 0;
806       ffei_buf.ffei.EaNameLength = sizeof (NFS_V3_ATTR) - 1;
807       ffei_buf.ffei.EaValueLength = sizeof (fattr3);
808       strcpy (ffei_buf.ffei.EaName, NFS_V3_ATTR);
809       fattr3 *nfs_attr = (fattr3 *) (ffei_buf.ffei.EaName
810                                      + ffei_buf.ffei.EaNameLength + 1);
811       memset (nfs_attr, 0, sizeof (fattr3));
812       nfs_attr->type = NF3REG;
813       nfs_attr->mode = mode;
814       status = NtSetEaFile (get_handle (), &io,
815                             &ffei_buf.ffei, sizeof ffei_buf);
816       if (!NT_SUCCESS (status))
817         __seterrno_from_nt_status (status);
818       else
819         res = 0;
820       goto out;
821     }
822
823   if (pc.has_acls ())
824     {
825       if (pc.isdir ())
826         mode |= S_IFDIR;
827       if (!set_file_attribute (get_handle (), pc,
828                                ILLEGAL_UID, ILLEGAL_GID, mode))
829         res = 0;
830     }
831
832   /* If the mode has any write bits set, the DOS R/O flag is in the way. */
833   if (mode & (S_IWUSR | S_IWGRP | S_IWOTH))
834     pc &= (DWORD) ~FILE_ATTRIBUTE_READONLY;
835   else if (!pc.has_acls ())     /* Never set DOS R/O if security is used. */
836     pc |= (DWORD) FILE_ATTRIBUTE_READONLY;
837   if (S_ISSOCK (mode))
838     pc |= (DWORD) FILE_ATTRIBUTE_SYSTEM;
839
840   status = NtSetAttributesFile (get_handle (), pc.file_attributes ());
841   /* MVFS needs a good amount of kicking to be convinced that it has to write
842      back metadata changes and to invalidate the cached metadata information
843      stored for the given handle.  This method to open a second handle to
844      the file and write the same metadata information twice has been found
845      experimentally: http://cygwin.com/ml/cygwin/2009-07/msg00533.html */
846   if (pc.fs_is_mvfs () && NT_SUCCESS (status) && !oret)
847     {
848       OBJECT_ATTRIBUTES attr;
849       HANDLE fh;
850
851       pc.init_reopen_attr (&attr, get_handle ());
852       if (NT_SUCCESS (NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES, &attr, &io,
853                                   FILE_SHARE_VALID_FLAGS,
854                                   FILE_OPEN_FOR_BACKUP_INTENT)))
855         {
856           NtSetAttributesFile (fh, pc.file_attributes ());
857           NtClose (fh);
858         }
859     }
860   /* Correct NTFS security attributes have higher priority */
861   if (!pc.has_acls ())
862     {
863       if (!NT_SUCCESS (status))
864         __seterrno_from_nt_status (status);
865       else
866         res = 0;
867     }
868
869 out:
870   if (oret)
871     close_fs ();
872
873   return res;
874 }
875
876 int __stdcall
877 fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid)
878 {
879   int oret = 0;
880
881   if (!pc.has_acls ())
882     {
883       /* fake - if not supported, pretend we're like win95
884          where it just works */
885       /* FIXME: Could be supported on NFS when user->uid mapping is in place. */
886       return 0;
887     }
888
889   if (!get_handle ())
890     {
891       query_open (query_write_control);
892       if (!(oret = fhandler_disk_file::open (O_BINARY, 0)))
893         return -1;
894     }
895
896   mode_t attrib = 0;
897   if (pc.isdir ())
898     attrib |= S_IFDIR;
899   __uid32_t old_uid;
900   int res = get_file_attribute (get_handle (), pc, &attrib, &old_uid, NULL);
901   if (!res)
902     {
903       /* Typical Windows default ACLs can contain permissions for one
904          group, while being owned by another user/group.  The permission
905          bits returned above are pretty much useless then.  Creating a
906          new ACL with these useless permissions results in a potentially
907          broken symlink.  So what we do here is to set the underlying
908          permissions of symlinks to a sensible value which allows the
909          world to read the symlink and only the new owner to change it. */
910       if (pc.issymlink ())
911         attrib = S_IFLNK | STD_RBITS | STD_WBITS;
912       res = set_file_attribute (get_handle (), pc, uid, gid, attrib);
913       /* If you're running a Samba server which has no winbidd running, the
914          uid<->SID mapping is disfunctional.  Even trying to chown to your
915          own account fails since the account used on the server is the UNIX
916          account which gets used for the standard user mapping.  This is a
917          default mechanism which doesn't know your real Windows SID.
918          There are two possible error codes in different Samba releases for
919          this situation, one of them is unfortunately the not very significant
920          STATUS_ACCESS_DENIED.  Instead of relying on the error codes, we're
921          using the below very simple heuristic.  If set_file_attribute failed,
922          and the original user account was either already unknown, or one of
923          the standard UNIX accounts, we're faking success. */
924       if (res == -1 && pc.fs_is_samba ())
925         {
926           cygsid sid;
927
928           if (old_uid == ILLEGAL_UID
929               || (sid.getfrompw (internal_getpwuid (old_uid))
930                   && EqualPrefixSid (sid, well_known_samba_unix_user_fake_sid)))
931             {
932               debug_printf ("Faking chown worked on standalone Samba");
933               res = 0;
934             }
935         }
936     }
937   if (oret)
938     close_fs ();
939
940   return res;
941 }
942
943 int _stdcall
944 fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp)
945 {
946   int res = -1;
947   int oret = 0;
948
949   if (!pc.has_acls ())
950     {
951 cant_access_acl:
952       switch (cmd)
953         {
954           struct __stat64 st;
955
956           case SETACL:
957             /* Open for writing required to be able to set ctime
958                (even though setting the ACL is just pretended). */
959             if (!get_handle ())
960               oret = open (O_WRONLY | O_BINARY, 0);
961             res = 0;
962             break;
963           case GETACL:
964             if (!aclbufp)
965               set_errno (EFAULT);
966             else if (nentries < MIN_ACL_ENTRIES)
967               set_errno (ENOSPC);
968             else
969               {
970                 if (!fstat (&st))
971                   {
972                     aclbufp[0].a_type = USER_OBJ;
973                     aclbufp[0].a_id = st.st_uid;
974                     aclbufp[0].a_perm = (st.st_mode & S_IRWXU) >> 6;
975                     aclbufp[1].a_type = GROUP_OBJ;
976                     aclbufp[1].a_id = st.st_gid;
977                     aclbufp[1].a_perm = (st.st_mode & S_IRWXG) >> 3;
978                     aclbufp[2].a_type = OTHER_OBJ;
979                     aclbufp[2].a_id = ILLEGAL_GID;
980                     aclbufp[2].a_perm = st.st_mode & S_IRWXO;
981                     aclbufp[3].a_type = CLASS_OBJ;
982                     aclbufp[3].a_id = ILLEGAL_GID;
983                     aclbufp[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
984                     res = MIN_ACL_ENTRIES;
985                   }
986               }
987             break;
988           case GETACLCNT:
989             res = MIN_ACL_ENTRIES;
990             break;
991           default:
992             set_errno (EINVAL);
993             break;
994         }
995     }
996   else
997     {
998       if ((cmd == SETACL && !get_handle ())
999           || (cmd != SETACL && !get_stat_handle ()))
1000         {
1001           query_open (cmd == SETACL ? query_write_control : query_read_control);
1002           if (!(oret = open (O_BINARY, 0)))
1003             {
1004               if (cmd == GETACL || cmd == GETACLCNT)
1005                 goto cant_access_acl;
1006               return -1;
1007             }
1008         }
1009       switch (cmd)
1010         {
1011           case SETACL:
1012             if (!aclsort32 (nentries, 0, aclbufp))
1013               {
1014                 bool rw = false;
1015                 res = setacl (get_handle (), pc, nentries, aclbufp, rw);
1016                 if (rw)
1017                   {
1018                     IO_STATUS_BLOCK io;
1019                     FILE_BASIC_INFORMATION fbi;
1020                     fbi.CreationTime.QuadPart
1021                     = fbi.LastAccessTime.QuadPart
1022                     = fbi.LastWriteTime.QuadPart
1023                     = fbi.ChangeTime.QuadPart = 0LL;
1024                     fbi.FileAttributes = (pc.file_attributes ()
1025                                           & ~FILE_ATTRIBUTE_READONLY)
1026                                          ?: FILE_ATTRIBUTE_NORMAL;
1027                     NtSetInformationFile (get_handle (), &io, &fbi, sizeof fbi,
1028                                           FileBasicInformation);
1029                   }
1030               }
1031             break;
1032           case GETACL:
1033             if (!aclbufp)
1034               set_errno(EFAULT);
1035             else
1036               res = getacl (get_stat_handle (), pc, nentries, aclbufp);
1037               /* For this ENOSYS case, see security.cc:get_file_attribute(). */
1038               if (res == -1 && get_errno () == ENOSYS)
1039                 goto cant_access_acl;
1040             break;
1041           case GETACLCNT:
1042             res = getacl (get_stat_handle (), pc, 0, NULL);
1043             /* Ditto. */
1044             if (res == -1 && get_errno () == ENOSYS)
1045               goto cant_access_acl;
1046             break;
1047           default:
1048             set_errno (EINVAL);
1049             break;
1050         }
1051     }
1052
1053   if (oret)
1054     close_fs ();
1055
1056   return res;
1057 }
1058
1059 ssize_t
1060 fhandler_disk_file::fgetxattr (const char *name, void *value, size_t size)
1061 {
1062   if (pc.is_fs_special ())
1063     {
1064       set_errno (ENOTSUP);
1065       return -1;
1066     }
1067   return read_ea (get_handle (), pc, name, (char *) value, size);
1068 }
1069
1070 int
1071 fhandler_disk_file::fsetxattr (const char *name, const void *value, size_t size,
1072                                int flags)
1073 {
1074   if (pc.is_fs_special ())
1075     {
1076       set_errno (ENOTSUP);
1077       return -1;
1078     }
1079   return write_ea (get_handle (), pc, name, (const char *) value, size, flags);
1080 }
1081
1082 int
1083 fhandler_disk_file::fadvise (_off64_t offset, _off64_t length, int advice)
1084 {
1085   if (advice < POSIX_FADV_NORMAL || advice > POSIX_FADV_NOREUSE)
1086     {
1087       set_errno (EINVAL);
1088       return -1;
1089     }
1090
1091   /* Windows only supports advice flags for the whole file.  We're using
1092      a simplified test here so that we don't have to ask for the actual
1093      file size.  Length == 0 means all bytes starting at offset anyway.
1094      So we only actually follow the advice, if it's given for offset == 0. */
1095   if (offset != 0)
1096     return 0;
1097
1098   /* We only support normal and sequential mode for now.  Everything which
1099      is not POSIX_FADV_SEQUENTIAL is treated like POSIX_FADV_NORMAL. */
1100   if (advice != POSIX_FADV_SEQUENTIAL)
1101     advice = POSIX_FADV_NORMAL;
1102
1103   IO_STATUS_BLOCK io;
1104   FILE_MODE_INFORMATION fmi;
1105   NTSTATUS status = NtQueryInformationFile (get_handle (), &io,
1106                                             &fmi, sizeof fmi,
1107                                             FileModeInformation);
1108   if (!NT_SUCCESS (status))
1109     __seterrno_from_nt_status (status);
1110   else
1111     {
1112       fmi.Mode &= ~FILE_SEQUENTIAL_ONLY;
1113       if (advice == POSIX_FADV_SEQUENTIAL)
1114         fmi.Mode |= FILE_SEQUENTIAL_ONLY;
1115       status = NtSetInformationFile (get_handle (), &io, &fmi, sizeof fmi,
1116                                      FileModeInformation);
1117       if (NT_SUCCESS (status))
1118         return 0;
1119       __seterrno_from_nt_status (status);
1120     }
1121
1122   return -1;
1123 }
1124
1125 int
1126 fhandler_disk_file::ftruncate (_off64_t length, bool allow_truncate)
1127 {
1128   int res = -1;
1129
1130   if (length < 0 || !get_handle ())
1131     set_errno (EINVAL);
1132   else if (pc.isdir ())
1133     set_errno (EISDIR);
1134   else if (!(get_access () & GENERIC_WRITE))
1135     set_errno (EBADF);
1136   else
1137     {
1138       NTSTATUS status;
1139       IO_STATUS_BLOCK io;
1140       FILE_STANDARD_INFORMATION fsi;
1141       FILE_END_OF_FILE_INFORMATION feofi;
1142
1143       status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
1144                                        FileStandardInformation);
1145       if (!NT_SUCCESS (status))
1146         {
1147           __seterrno_from_nt_status (status);
1148           return -1;
1149         }
1150
1151       /* If called through posix_fallocate, silently succeed if length
1152          is less than the file's actual length. */
1153       if (!allow_truncate && length < fsi.EndOfFile.QuadPart)
1154         return 0;
1155
1156       feofi.EndOfFile.QuadPart = length;
1157       /* Create sparse files only when called through ftruncate, not when
1158          called through posix_fallocate. */
1159       if (allow_truncate
1160           && (pc.fs_flags () & FILE_SUPPORTS_SPARSE_FILES)
1161           && length >= fsi.EndOfFile.QuadPart + (128 * 1024))
1162         {
1163           status = NtFsControlFile (get_handle (), NULL, NULL, NULL, &io,
1164                                     FSCTL_SET_SPARSE, NULL, 0, NULL, 0);
1165           syscall_printf ("%p = NtFsControlFile(%S, FSCTL_SET_SPARSE)",
1166                           status, pc.get_nt_native_path ());
1167         }
1168       status = NtSetInformationFile (get_handle (), &io,
1169                                      &feofi, sizeof feofi,
1170                                      FileEndOfFileInformation);
1171       if (!NT_SUCCESS (status))
1172         __seterrno_from_nt_status (status);
1173       else
1174         res = 0;
1175     }
1176   return res;
1177 }
1178
1179 int
1180 fhandler_disk_file::link (const char *newpath)
1181 {
1182   size_t nlen = strlen (newpath);
1183   path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_POSIX | PC_NULLEMPTY, stat_suffixes);
1184   if (newpc.error)
1185     {
1186       set_errno (newpc.error);
1187       return -1;
1188     }
1189
1190   if (newpc.exists ())
1191     {
1192       syscall_printf ("file '%S' exists?", newpc.get_nt_native_path ());
1193       set_errno (EEXIST);
1194       return -1;
1195     }
1196
1197   if (isdirsep (newpath[nlen - 1]) || has_dot_last_component (newpath, false))
1198     {
1199       set_errno (ENOENT);
1200       return -1;
1201     }
1202
1203   char new_buf[nlen + 5];
1204   if (!newpc.error)
1205     {
1206       /* If the original file is a lnk special file (except for sockets),
1207          and if the original file has a .lnk suffix, add one to the hardlink
1208          as well. */
1209       if (pc.is_lnk_special () && !pc.issocket ()
1210           && RtlEqualUnicodePathSuffix (pc.get_nt_native_path (),
1211                                         &ro_u_lnk, TRUE))
1212         {
1213           /* Shortcut hack. */
1214           stpcpy (stpcpy (new_buf, newpath), ".lnk");
1215           newpath = new_buf;
1216           newpc.check (newpath, PC_SYM_NOFOLLOW);
1217         }
1218       else if (!pc.isdir ()
1219                && pc.is_binary ()
1220                && RtlEqualUnicodePathSuffix (pc.get_nt_native_path (),
1221                                              &ro_u_exe, TRUE)
1222                && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
1223                                               &ro_u_exe, TRUE))
1224         {
1225           /* Executable hack. */
1226           stpcpy (stpcpy (new_buf, newpath), ".exe");
1227           newpath = new_buf;
1228           newpc.check (newpath, PC_SYM_NOFOLLOW);
1229         }
1230     }
1231
1232   /* We only need READ_CONTROL access so the handle returned in pc is
1233      sufficient.  And if the file couldn't be opened with READ_CONTROL
1234      access in path_conv, we won't be able to do it here anyway. */
1235   HANDLE fh = get_stat_handle ();
1236   if (!fh)
1237     {
1238       set_errno (EACCES);
1239       return -1;
1240     }
1241   PUNICODE_STRING tgt = newpc.get_nt_native_path ();
1242   ULONG size = sizeof (FILE_LINK_INFORMATION) + tgt->Length;
1243   PFILE_LINK_INFORMATION pfli = (PFILE_LINK_INFORMATION) alloca (size);
1244   pfli->ReplaceIfExists = FALSE;
1245   pfli->RootDirectory = NULL;
1246   memcpy (pfli->FileName, tgt->Buffer, pfli->FileNameLength = tgt->Length);
1247
1248   NTSTATUS status;
1249   IO_STATUS_BLOCK io;
1250   status = NtSetInformationFile (fh, &io, pfli, size, FileLinkInformation);
1251   if (!NT_SUCCESS (status))
1252     {
1253       if (status == STATUS_INVALID_DEVICE_REQUEST)
1254         {
1255           /* FS doesn't support hard links.  Linux returns EPERM. */
1256           set_errno (EPERM);
1257           return -1;
1258         }
1259       else
1260         {
1261           __seterrno_from_nt_status (status);
1262           return -1;
1263         }
1264     }
1265   return 0;
1266 }
1267
1268 int
1269 fhandler_disk_file::utimens (const struct timespec *tvp)
1270 {
1271   return utimens_fs (tvp);
1272 }
1273
1274 int
1275 fhandler_base::utimens_fs (const struct timespec *tvp)
1276 {
1277   struct timespec timeofday;
1278   struct timespec tmp[2];
1279   bool closeit = false;
1280
1281   if (!get_handle ())
1282     {
1283       query_open (query_write_attributes);
1284       if (!open_fs (O_BINARY, 0))
1285         {
1286           /* It's documented in MSDN that FILE_WRITE_ATTRIBUTES is sufficient
1287              to change the timestamps.  Unfortunately it's not sufficient for a
1288              remote HPFS which requires GENERIC_WRITE, so we just retry to open
1289              for writing, though this fails for R/O files of course. */
1290           query_open (no_query);
1291           if (!open_fs (O_WRONLY | O_BINARY, 0))
1292             {
1293               syscall_printf ("Opening file failed");
1294               return -1;
1295             }
1296         }
1297       closeit = true;
1298     }
1299
1300   clock_gettime (CLOCK_REALTIME, &timeofday);
1301   if (!tvp)
1302     tmp[1] = tmp[0] = timeofday;
1303   else
1304     {
1305       if ((tvp[0].tv_nsec < UTIME_NOW || tvp[0].tv_nsec > 999999999L)
1306           || (tvp[1].tv_nsec < UTIME_NOW || tvp[1].tv_nsec > 999999999L))
1307         {
1308           if (closeit)
1309             close_fs ();
1310           set_errno (EINVAL);
1311           return -1;
1312         }
1313       tmp[0] = (tvp[0].tv_nsec == UTIME_NOW) ? timeofday : tvp[0];
1314       tmp[1] = (tvp[1].tv_nsec == UTIME_NOW) ? timeofday : tvp[1];
1315     }
1316   debug_printf ("incoming lastaccess %08x %08x", tmp[0].tv_sec, tmp[0].tv_nsec);
1317
1318   IO_STATUS_BLOCK io;
1319   FILE_BASIC_INFORMATION fbi;
1320
1321   fbi.CreationTime.QuadPart = 0LL;
1322   /* UTIME_OMIT is handled in timespec_to_filetime by setting FILETIME to 0. */
1323   timespec_to_filetime (&tmp[0], (LPFILETIME) &fbi.LastAccessTime);
1324   timespec_to_filetime (&tmp[1], (LPFILETIME) &fbi.LastWriteTime);
1325   fbi.ChangeTime.QuadPart = 0LL;
1326   fbi.FileAttributes = 0;
1327   NTSTATUS status = NtSetInformationFile (get_handle (), &io, &fbi, sizeof fbi,
1328                                           FileBasicInformation);
1329   /* For this special case for MVFS see the comment in
1330      fhandler_disk_file::fchmod. */
1331   if (pc.fs_is_mvfs () && NT_SUCCESS (status) && !closeit)
1332     {
1333       OBJECT_ATTRIBUTES attr;
1334       HANDLE fh;
1335
1336       pc.init_reopen_attr (&attr, get_handle ());
1337       if (NT_SUCCESS (NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES, &attr, &io,
1338                                   FILE_SHARE_VALID_FLAGS,
1339                                   FILE_OPEN_FOR_BACKUP_INTENT)))
1340         {
1341           NtSetInformationFile (fh, &io, &fbi, sizeof fbi,
1342                                 FileBasicInformation);
1343           NtClose (fh);
1344         }
1345     }
1346   if (closeit)
1347     close_fs ();
1348   /* Opening a directory on a 9x share from a NT machine works(!), but
1349      then NtSetInformationFile fails with STATUS_NOT_SUPPORTED.  Oh well... */
1350   if (!NT_SUCCESS (status) && status != STATUS_NOT_SUPPORTED)
1351     {
1352       __seterrno_from_nt_status (status);
1353       return -1;
1354     }
1355   return 0;
1356 }
1357
1358 fhandler_disk_file::fhandler_disk_file () :
1359   fhandler_base ()
1360 {
1361 }
1362
1363 fhandler_disk_file::fhandler_disk_file (path_conv &pc) :
1364   fhandler_base ()
1365 {
1366   set_name (pc);
1367 }
1368
1369 int
1370 fhandler_disk_file::open (int flags, mode_t mode)
1371 {
1372   return open_fs (flags, mode);
1373 }
1374
1375 int
1376 fhandler_base::open_fs (int flags, mode_t mode)
1377 {
1378   /* Unfortunately NT allows to open directories for writing, but that's
1379      disallowed according to SUSv3. */
1380   if (pc.isdir () && (flags & O_ACCMODE) != O_RDONLY)
1381     {
1382       set_errno (EISDIR);
1383       return 0;
1384     }
1385
1386   int res = fhandler_base::open (flags | O_DIROPEN, mode);
1387   if (!res)
1388     goto out;
1389
1390   /* This is for file systems known for having a buggy CreateFile call
1391      which might return a valid HANDLE without having actually opened
1392      the file.
1393      The only known file system to date is the SUN NFS Solstice Client 3.1
1394      which returns a valid handle when trying to open a file in a nonexistent
1395      directory. */
1396   if (pc.has_buggy_open () && !pc.exists ())
1397     {
1398       debug_printf ("Buggy open detected.");
1399       close_fs ();
1400       set_errno (ENOENT);
1401       return 0;
1402     }
1403
1404     ino = pc.get_ino_by_handle (get_handle ());
1405     /* A unique ID is necessary to recognize fhandler entries which are
1406        duplicated by dup(2) or fork(2). */
1407     AllocateLocallyUniqueId ((PLUID) &unique_id);
1408
1409 out:
1410   syscall_printf ("%d = fhandler_disk_file::open (%S, %p)", res,
1411                   pc.get_nt_native_path (), flags);
1412   return res;
1413 }
1414
1415 ssize_t __stdcall
1416 fhandler_disk_file::pread (void *buf, size_t count, _off64_t offset)
1417 {
1418   ssize_t res;
1419   _off64_t curpos = lseek (0, SEEK_CUR);
1420   if (curpos < 0 || lseek (offset, SEEK_SET) < 0)
1421     res = -1;
1422   else
1423     {
1424       size_t tmp_count = count;
1425       read (buf, tmp_count);
1426       if (lseek (curpos, SEEK_SET) >= 0)
1427         res = (ssize_t) tmp_count;
1428       else
1429         res = -1;
1430     }
1431   debug_printf ("%d = pread (%p, %d, %d)\n", res, buf, count, offset);
1432   return res;
1433 }
1434
1435 ssize_t __stdcall
1436 fhandler_disk_file::pwrite (void *buf, size_t count, _off64_t offset)
1437 {
1438   int res;
1439   _off64_t curpos = lseek (0, SEEK_CUR);
1440   if (curpos < 0 || lseek (offset, SEEK_SET) < 0)
1441     res = curpos;
1442   else
1443     {
1444       res = (ssize_t) write (buf, count);
1445       if (lseek (curpos, SEEK_SET) < 0)
1446         res = -1;
1447     }
1448   debug_printf ("%d = pwrite (%p, %d, %d)\n", res, buf, count, offset);
1449   return res;
1450 }
1451
1452 int
1453 fhandler_disk_file::mkdir (mode_t mode)
1454 {
1455   int res = -1;
1456   SECURITY_ATTRIBUTES sa = sec_none_nih;
1457   NTSTATUS status;
1458   HANDLE dir;
1459   OBJECT_ATTRIBUTES attr;
1460   IO_STATUS_BLOCK io;
1461   PFILE_FULL_EA_INFORMATION p = NULL;
1462   ULONG plen = 0;
1463
1464   if (pc.fs_is_nfs ())
1465     {
1466       /* When creating a dir on an NFS share, we have to set the
1467          file mode by writing a NFS fattr3 structure with the
1468          correct mode bits set. */
1469       plen = sizeof (FILE_FULL_EA_INFORMATION) + sizeof (NFS_V3_ATTR)
1470              + sizeof (fattr3);
1471       p = (PFILE_FULL_EA_INFORMATION) alloca (plen);
1472       p->NextEntryOffset = 0;
1473       p->Flags = 0;
1474       p->EaNameLength = sizeof (NFS_V3_ATTR) - 1;
1475       p->EaValueLength = sizeof (fattr3);
1476       strcpy (p->EaName, NFS_V3_ATTR);
1477       fattr3 *nfs_attr = (fattr3 *) (p->EaName + p->EaNameLength + 1);
1478       memset (nfs_attr, 0, sizeof (fattr3));
1479       nfs_attr->type = NF3DIR;
1480       nfs_attr->mode = (mode & 07777) & ~cygheap->umask;
1481     }
1482   status = NtCreateFile (&dir, FILE_LIST_DIRECTORY | SYNCHRONIZE,
1483                          pc.get_object_attr (attr, sa), &io, NULL,
1484                          FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_VALID_FLAGS,
1485                          FILE_CREATE,
1486                          FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
1487                          | FILE_OPEN_FOR_BACKUP_INTENT,
1488                          p, plen);
1489   if (NT_SUCCESS (status))
1490     {
1491       if (has_acls ())
1492         set_file_attribute (dir, pc, ILLEGAL_UID, ILLEGAL_GID,
1493                             S_JUSTCREATED | S_IFDIR
1494                             | ((mode & 07777) & ~cygheap->umask));
1495       NtClose (dir);
1496       res = 0;
1497     }
1498   else
1499     __seterrno_from_nt_status (status);
1500
1501   return res;
1502 }
1503
1504 int
1505 fhandler_disk_file::rmdir ()
1506 {
1507   extern NTSTATUS unlink_nt (path_conv &pc);
1508
1509   if (!pc.isdir ())
1510     {
1511       set_errno (ENOTDIR);
1512       return -1;
1513     }
1514   if (!pc.exists ())
1515     {
1516       set_errno (ENOENT);
1517       return -1;
1518     }
1519
1520   NTSTATUS status = unlink_nt (pc);
1521
1522   /* Check for existence of remote dirs after trying to delete them.
1523      Two reasons:
1524      - Sometimes SMB indicates failure when it really succeeds.
1525      - Removing a directory on a Samba drive using an old Samba version
1526        sometimes doesn't return an error, if the directory can't be removed
1527        because it's not empty. */
1528   if (isremote ())
1529     {
1530       OBJECT_ATTRIBUTES attr;
1531       FILE_BASIC_INFORMATION fbi;
1532       NTSTATUS q_status;
1533
1534       q_status = NtQueryAttributesFile (pc.get_object_attr (attr, sec_none_nih),                                        &fbi);
1535       if (!NT_SUCCESS (status) && q_status == STATUS_OBJECT_NAME_NOT_FOUND)
1536         status = STATUS_SUCCESS;
1537       else if (NT_SUCCESS (status) && NT_SUCCESS (q_status))
1538         status = STATUS_DIRECTORY_NOT_EMPTY;
1539     }
1540   if (!NT_SUCCESS (status))
1541     {
1542       __seterrno_from_nt_status (status);
1543       return -1;
1544     }
1545   return 0;
1546 }
1547
1548 /* This is the minimal number of entries which fit into the readdir cache.
1549    The number of bytes allocated by the cache is determined by this number,
1550    To tune caching, just tweak this number.  To get a feeling for the size,
1551    the size of the readdir cache is DIR_NUM_ENTRIES * 624 + 4 bytes.  */
1552
1553 #define DIR_NUM_ENTRIES 100             /* Cache size 62404 bytes */
1554
1555 #define DIR_BUF_SIZE    (DIR_NUM_ENTRIES \
1556                          * (sizeof (FILE_ID_BOTH_DIR_INFORMATION) \
1557                             + (NAME_MAX + 1) * sizeof (WCHAR)))
1558
1559 struct __DIR_cache
1560 {
1561   char  __cache[DIR_BUF_SIZE];  /* W2K needs this buffer 8 byte aligned. */
1562   ULONG __pos;
1563 };
1564
1565 #define d_cachepos(d)   (((__DIR_cache *) (d)->__d_dirname)->__pos)
1566 #define d_cache(d)      (((__DIR_cache *) (d)->__d_dirname)->__cache)
1567
1568 #define d_mounts(d)     ((__DIR_mounts *) (d)->__d_internal)
1569
1570 DIR *
1571 fhandler_disk_file::opendir (int fd)
1572 {
1573   DIR *dir;
1574   DIR *res = NULL;
1575
1576   if (!pc.isdir ())
1577     set_errno (ENOTDIR);
1578   else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
1579     set_errno (ENOMEM);
1580   else if ((dir->__d_dirname = (char *) malloc ( sizeof (struct __DIR_cache)))
1581            == NULL)
1582     {
1583       set_errno (ENOMEM);
1584       goto free_dir;
1585     }
1586   else if ((dir->__d_dirent =
1587             (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
1588     {
1589       set_errno (ENOMEM);
1590       goto free_dirname;
1591     }
1592   else
1593     {
1594       cygheap_fdnew cfd;
1595       if (cfd < 0 && fd < 0)
1596         goto free_dirent;
1597
1598       dir->__d_dirent->__d_version = __DIRENT_VERSION;
1599       dir->__d_cookie = __DIRENT_COOKIE;
1600       dir->__handle = INVALID_HANDLE_VALUE;
1601       dir->__d_position = 0;
1602       dir->__flags = (get_name ()[0] == '/' && get_name ()[1] == '\0')
1603                      ? dirent_isroot : 0;
1604       dir->__d_internal = (unsigned) new __DIR_mounts (get_name ());
1605       d_cachepos (dir) = 0;
1606
1607       if (!pc.iscygdrive ())
1608         {
1609           if (fd < 0)
1610             {
1611               /* opendir() case.  Initialize with given directory name and
1612                  NULL directory handle. */
1613               OBJECT_ATTRIBUTES attr;
1614               NTSTATUS status;
1615               IO_STATUS_BLOCK io;
1616               /* Tools like ls(1) call dirfd() to fetch the directory
1617                  descriptor for calls to facl or fstat.  The tight access mask
1618                  used so far is not sufficient to reuse the handle for these
1619                  calls, instead the facl/fstat calls find the handle to be
1620                  unusable and have to re-open the file for reading attributes
1621                  and control data.  So, what we do here is to try to open the
1622                  directory with more relaxed access mask which enables to use
1623                  the handle for the aforementioned purpose.  This should work
1624                  in almost all cases.  Only if it doesn't work due to
1625                  permission problems, we drop the additional access bits and
1626                  try again. */
1627               ACCESS_MASK fstat_mask = READ_CONTROL | FILE_READ_ATTRIBUTES;
1628
1629               do
1630                 {
1631                   status = NtOpenFile (&get_handle (),
1632                                        SYNCHRONIZE | FILE_LIST_DIRECTORY
1633                                        | fstat_mask,
1634                                        pc.get_object_attr (attr, sec_none_nih),
1635                                        &io, FILE_SHARE_VALID_FLAGS,
1636                                        FILE_SYNCHRONOUS_IO_NONALERT
1637                                        | FILE_OPEN_FOR_BACKUP_INTENT
1638                                        | FILE_DIRECTORY_FILE);
1639                   if (!NT_SUCCESS (status))
1640                     {
1641                       if (status == STATUS_ACCESS_DENIED && fstat_mask)
1642                         fstat_mask = 0;
1643                       else
1644                         {
1645                           __seterrno_from_nt_status (status);
1646                           goto free_mounts;
1647                         }
1648                     }
1649                 }
1650               while (!NT_SUCCESS (status));
1651             }
1652
1653           /* FileIdBothDirectoryInformation is apparently unsupported on
1654              XP when accessing directories on UDF.  When trying to use it
1655              so, NtQueryDirectoryFile returns with STATUS_ACCESS_VIOLATION.
1656              It's not clear if the call isn't also unsupported on other
1657              OS/FS combinations (say, Win2K/CDFS or so).  Instead of
1658              testing in readdir for yet another error code, let's use
1659              FileIdBothDirectoryInformation only on filesystems supporting
1660              persistent ACLs, FileBothDirectoryInformation otherwise.
1661
1662              NFS clients hide dangling symlinks from directory queries,
1663              unless you use the FileNamesInformation info class.
1664              On newer NFS clients (>=Vista) FileIdBothDirectoryInformation
1665              works fine, but only if the NFS share is mounted to a drive
1666              letter.  TODO: We don't test that here for now, but it might
1667              be worth to test if there's a speed gain in using
1668              FileIdBothDirectoryInformation, because it doesn't require to
1669              open the file to read the inode number. */
1670           if (pc.hasgood_inode ())
1671             {
1672               dir->__flags |= dirent_set_d_ino;
1673               if (pc.fs_is_nfs ())
1674                 dir->__flags |= dirent_nfs_d_ino;
1675               else if (wincap.has_fileid_dirinfo ()
1676                        && !pc.has_buggy_fileid_dirinfo ())
1677                 dir->__flags |= dirent_get_d_ino;
1678             }
1679         }
1680       if (fd >= 0)
1681         dir->__d_fd = fd;
1682       else
1683         {
1684           /* Filling cfd with `this' (aka storing this in the file
1685              descriptor table should only happen after it's clear that
1686              opendir doesn't fail, otherwise we end up cfree'ing the
1687              fhandler twice, once in opendir() in dir.cc, the second
1688              time on exit.  Nasty, nasty... */
1689           cfd = this;
1690           dir->__d_fd = cfd;
1691           if (pc.iscygdrive ())
1692             cfd->nohandle (true);
1693         }
1694       set_close_on_exec (true);
1695       dir->__fh = this;
1696       res = dir;
1697     }
1698
1699   syscall_printf ("%p = opendir (%s)", res, get_name ());
1700   return res;
1701
1702 free_mounts:
1703   delete d_mounts (dir);
1704 free_dirent:
1705   free (dir->__d_dirent);
1706 free_dirname:
1707   free (dir->__d_dirname);
1708 free_dir:
1709   free (dir);
1710   return res;
1711 }
1712
1713 __ino64_t __stdcall
1714 readdir_get_ino (const char *path, bool dot_dot)
1715 {
1716   char *fname;
1717   struct __stat64 st;
1718   HANDLE hdl;
1719   OBJECT_ATTRIBUTES attr;
1720   IO_STATUS_BLOCK io;
1721   __ino64_t ino = 0;
1722
1723   if (dot_dot)
1724     {
1725       fname = (char *) alloca (strlen (path) + 4);
1726       char *c = stpcpy (fname, path);
1727       if (c[-1] != '/')
1728         *c++ = '/';
1729       strcpy (c, "..");
1730       path = fname;
1731     }
1732   path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX | PC_NOWARN | PC_KEEP_HANDLE);
1733   if (pc.isspecial ())
1734     {
1735       if (!stat_worker (pc, &st))
1736         ino = st.st_ino;
1737     }
1738   else if (!pc.hasgood_inode ())
1739     ino = hash_path_name (0, pc.get_nt_native_path ());
1740   else if ((hdl = pc.handle ()) != NULL
1741            || NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL,
1742                                       pc.get_object_attr (attr, sec_none_nih),
1743                                       &io, FILE_SHARE_VALID_FLAGS,
1744                                       FILE_OPEN_FOR_BACKUP_INTENT
1745                                       | (pc.is_rep_symlink ()
1746                                       ? FILE_OPEN_REPARSE_POINT : 0)))
1747           )
1748     {
1749       ino = pc.get_ino_by_handle (hdl);
1750       if (!ino)
1751         ino = hash_path_name (0, pc.get_nt_native_path ());
1752     }
1753   return ino;
1754 }
1755
1756 int
1757 fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
1758                                     DWORD attr, PUNICODE_STRING fname)
1759 {
1760   if (w32_err)
1761     {
1762       bool added = false;
1763       if ((de->d_ino = d_mounts (dir)->check_missing_mount (fname)))
1764         added = true;
1765       if (!added)
1766         {
1767           fname->Length = 0;
1768           return geterrno_from_win_error (w32_err);
1769         }
1770
1771       attr = 0;
1772       dir->__flags &= ~dirent_set_d_ino;
1773     }
1774
1775   /* Set d_type if type can be determined from file attributes.  For .lnk
1776      symlinks, d_type will be reset below.  Reparse points can be NTFS
1777      symlinks, even if they have the FILE_ATTRIBUTE_DIRECTORY flag set. */
1778   if (attr &&
1779       !(attr & (~FILE_ATTRIBUTE_VALID_FLAGS | FILE_ATTRIBUTE_REPARSE_POINT)))
1780     {
1781       if (attr & FILE_ATTRIBUTE_DIRECTORY)
1782         de->d_type = DT_DIR;
1783       /* FILE_ATTRIBUTE_SYSTEM might denote system-bit type symlinks. */
1784       else if (!(attr & FILE_ATTRIBUTE_SYSTEM))
1785         de->d_type = DT_REG;
1786     }
1787
1788   /* Check for directory reparse point.  These are potential volume mount
1789      points which have another inode than the underlying directory. */
1790   if ((attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
1791       == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
1792     {
1793       HANDLE reph;
1794       OBJECT_ATTRIBUTES attr;
1795       IO_STATUS_BLOCK io;
1796
1797       InitializeObjectAttributes (&attr, fname, pc.objcaseinsensitive (),
1798                                   get_handle (), NULL);
1799       de->d_type = readdir_check_reparse_point (&attr);
1800       if (de->d_type == DT_DIR)
1801         {
1802           /* Volume mountpoints are treated as directories.  We have to fix
1803              the inode number, otherwise we have the inode number of the
1804              mount point, rather than the inode number of the toplevel
1805              directory of the mounted drive. */
1806           if (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, &attr, &io,
1807                                       FILE_SHARE_VALID_FLAGS,
1808                                       FILE_OPEN_FOR_BACKUP_INTENT)))
1809             {
1810               de->d_ino = pc.get_ino_by_handle (reph);
1811               NtClose (reph);
1812             }
1813         }
1814     }
1815
1816   /* Check for Windows shortcut. If it's a Cygwin or U/WIN symlink, drop the
1817      .lnk suffix and set d_type accordingly. */
1818   if ((attr & (FILE_ATTRIBUTE_DIRECTORY
1819                | FILE_ATTRIBUTE_REPARSE_POINT
1820                | FILE_ATTRIBUTE_READONLY)) == FILE_ATTRIBUTE_READONLY
1821       && fname->Length > 4 * sizeof (WCHAR))
1822     {
1823       UNICODE_STRING uname;
1824
1825       RtlInitCountedUnicodeString (&uname,
1826                                    fname->Buffer
1827                                    + fname->Length / sizeof (WCHAR) - 4,
1828                                    4 * sizeof (WCHAR));
1829       if (RtlEqualUnicodeString (&uname, &ro_u_lnk, TRUE))
1830         {
1831           tmp_pathbuf tp;
1832           UNICODE_STRING fbuf;
1833
1834           tp.u_get (&fbuf);
1835           RtlCopyUnicodeString (&fbuf, pc.get_nt_native_path ());
1836           RtlAppendUnicodeToString (&fbuf, L"\\");
1837           RtlAppendUnicodeStringToString (&fbuf, fname);
1838           fbuf.Buffer += 4; /* Skip leading \??\ */
1839           fbuf.Length -= 4 * sizeof (WCHAR);
1840           if (fbuf.Buffer[1] != L':') /* UNC path */
1841             {
1842               *(fbuf.Buffer += 2) = L'\\';
1843               fbuf.Length -= 2 * sizeof (WCHAR);
1844             }
1845           path_conv fpath (&fbuf, PC_SYM_NOFOLLOW);
1846           if (fpath.issymlink ())
1847             {
1848               fname->Length -= 4 * sizeof (WCHAR);
1849               de->d_type = DT_LNK;
1850             }
1851           else if (fpath.isfifo ())
1852             {
1853               fname->Length -= 4 * sizeof (WCHAR);
1854               de->d_type = DT_FIFO;
1855             }
1856           else if (fpath.is_fs_special ())
1857             {
1858               fname->Length -= 4 * sizeof (WCHAR);
1859               de->d_type = S_ISCHR (fpath.dev.mode) ? DT_CHR : DT_BLK;
1860             }
1861         }
1862     }
1863
1864   sys_wcstombs (de->d_name, NAME_MAX + 1, fname->Buffer,
1865                 fname->Length / sizeof (WCHAR));
1866
1867   /* Don't try to optimize relative to dir->__d_position.  On several
1868      filesystems it's no safe bet that "." and ".." entries always
1869      come first. */
1870   if (de->d_name[0] == '.')
1871     {
1872       if (de->d_name[1] == '\0')
1873         dir->__flags |= dirent_saw_dot;
1874       else if (de->d_name[1] == '.' && de->d_name[2] == '\0')
1875         dir->__flags |= dirent_saw_dot_dot;
1876     }
1877   return 0;
1878 }
1879
1880 int
1881 fhandler_disk_file::readdir (DIR *dir, dirent *de)
1882 {
1883   int res = 0;
1884   NTSTATUS status = STATUS_SUCCESS;
1885   PFILE_ID_BOTH_DIR_INFORMATION buf = NULL;
1886   PWCHAR FileName;
1887   ULONG FileNameLength;
1888   ULONG FileAttributes = 0;
1889   IO_STATUS_BLOCK io;
1890   UNICODE_STRING fname;
1891
1892   /* d_cachepos always refers to the next cache entry to use.  If it's 0
1893      we must reload the cache. */
1894   if (d_cachepos (dir) == 0)
1895     {
1896       if ((dir->__flags & dirent_get_d_ino))
1897         {
1898           status = NtQueryDirectoryFile (get_handle (), NULL, NULL, NULL, &io,
1899                                          d_cache (dir), DIR_BUF_SIZE,
1900                                          FileIdBothDirectoryInformation,
1901                                          FALSE, NULL, dir->__d_position == 0);
1902           /* FileIdBothDirectoryInformation isn't supported for remote drives
1903              on NT4 and 2K systems, and it's also not supported on 2K at all,
1904              when accessing network drives on any remote OS.  There are also
1905              hacked versions of Samba 3.0.x out there (Debian-based it seems),
1906              which return STATUS_NOT_SUPPORTED rather than handling this info
1907              class.  We just fall back to using a standard directory query in
1908              this case and note this case using the dirent_get_d_ino flag. */
1909           if (!NT_SUCCESS (status) && status != STATUS_NO_MORE_FILES
1910               && (status == STATUS_INVALID_LEVEL
1911                   || status == STATUS_NOT_SUPPORTED
1912                   || status == STATUS_INVALID_PARAMETER
1913                   || status == STATUS_INVALID_NETWORK_RESPONSE
1914                   || status == STATUS_INVALID_INFO_CLASS))
1915             dir->__flags &= ~dirent_get_d_ino;
1916           /* Something weird happens on Samba up to version 3.0.21c, which is
1917              fixed in 3.0.22.  FileIdBothDirectoryInformation seems to work
1918              nicely, but only up to the 128th entry in the directory.  After
1919              reaching this entry, the next call to NtQueryDirectoryFile
1920              (FileIdBothDirectoryInformation) returns STATUS_INVALID_LEVEL.
1921              Why should we care, we can just switch to
1922              FileBothDirectoryInformation, isn't it?  Nope!  The next call to
1923              NtQueryDirectoryFile(FileBothDirectoryInformation) actually
1924              returns STATUS_NO_MORE_FILES, regardless how many files are left
1925              unread in the directory.  This does not happen when using
1926              FileBothDirectoryInformation right from the start, but since
1927              we can't decide whether the server we're talking with has this
1928              bug or not, we end up serving Samba shares always in the slow
1929              mode using FileBothDirectoryInformation.  So, what we do here is
1930              to implement the solution suggested by Andrew Tridgell,  we just
1931              reread all entries up to dir->d_position using
1932              FileBothDirectoryInformation.
1933              However, We do *not* mark this server as broken and fall back to
1934              using FileBothDirectoryInformation further on.  This would slow
1935              down every access to such a server, even for directories under
1936              128 entries.  Also, bigger dirs only suffer from one additional
1937              call per full directory scan, which shouldn't be too big a hit.
1938              This can easily be changed if necessary. */
1939           if (status == STATUS_INVALID_LEVEL && dir->__d_position)
1940             {
1941               d_cachepos (dir) = 0;
1942               for (int cnt = 0; cnt < dir->__d_position; ++cnt)
1943                 {
1944                   if (d_cachepos (dir) == 0)
1945                     {
1946                       status = NtQueryDirectoryFile (get_handle (), NULL, NULL,
1947                                            NULL, &io, d_cache (dir),
1948                                            DIR_BUF_SIZE,
1949                                            FileBothDirectoryInformation,
1950                                            FALSE, NULL, cnt == 0);
1951                       if (!NT_SUCCESS (status))
1952                         goto go_ahead;
1953                     }
1954                   buf = (PFILE_ID_BOTH_DIR_INFORMATION) (d_cache (dir)
1955                                                          + d_cachepos (dir));
1956                   if (buf->NextEntryOffset == 0)
1957                     d_cachepos (dir) = 0;
1958                   else
1959                     d_cachepos (dir) += buf->NextEntryOffset;
1960                 }
1961               goto go_ahead;
1962             }
1963         }
1964       if (!(dir->__flags & dirent_get_d_ino))
1965         status = NtQueryDirectoryFile (get_handle (), NULL, NULL, NULL, &io,
1966                                        d_cache (dir), DIR_BUF_SIZE,
1967                                        (dir->__flags & dirent_nfs_d_ino)
1968                                        ? FileNamesInformation
1969                                        : FileBothDirectoryInformation,
1970                                        FALSE, NULL, dir->__d_position == 0);
1971     }
1972
1973 go_ahead:
1974
1975   if (status == STATUS_NO_MORE_FILES)
1976     /*nothing*/;
1977   else if (!NT_SUCCESS (status))
1978     debug_printf ("NtQueryDirectoryFile failed, status %p, win32 error %lu",
1979                   status, RtlNtStatusToDosError (status));
1980   else
1981     {
1982       buf = (PFILE_ID_BOTH_DIR_INFORMATION) (d_cache (dir) + d_cachepos (dir));
1983       if (buf->NextEntryOffset == 0)
1984         d_cachepos (dir) = 0;
1985       else
1986         d_cachepos (dir) += buf->NextEntryOffset;
1987       if ((dir->__flags & dirent_get_d_ino))
1988         {
1989           FileName = buf->FileName;
1990           FileNameLength = buf->FileNameLength;
1991           FileAttributes = buf->FileAttributes;
1992           if ((dir->__flags & dirent_set_d_ino))
1993             de->d_ino = buf->FileId.QuadPart;
1994         }
1995       else if ((dir->__flags & dirent_nfs_d_ino))
1996         {
1997           FileName = ((PFILE_NAMES_INFORMATION) buf)->FileName;
1998           FileNameLength = ((PFILE_NAMES_INFORMATION) buf)->FileNameLength;
1999         }
2000       else
2001         {
2002           FileName = ((PFILE_BOTH_DIRECTORY_INFORMATION) buf)->FileName;
2003           FileNameLength =
2004                 ((PFILE_BOTH_DIRECTORY_INFORMATION) buf)->FileNameLength;
2005           FileAttributes =
2006                 ((PFILE_BOTH_DIRECTORY_INFORMATION) buf)->FileAttributes;
2007         }
2008       RtlInitCountedUnicodeString (&fname, FileName, FileNameLength);
2009       de->d_ino = d_mounts (dir)->check_mount (&fname, de->d_ino);
2010       if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino))
2011         {
2012           /* Don't try to optimize relative to dir->__d_position.  On several
2013              filesystems it's no safe bet that "." and ".." entries always
2014              come first. */
2015           if (FileNameLength == sizeof (WCHAR) && FileName[0] == '.')
2016             de->d_ino = pc.get_ino_by_handle (get_handle ());
2017           else if (FileNameLength == 2 * sizeof (WCHAR)
2018                    && FileName[0] == L'.' && FileName[1] == L'.')
2019             {
2020               if (!(dir->__flags & dirent_isroot))
2021                 de->d_ino = readdir_get_ino (get_name (), true);
2022               else
2023                 de->d_ino = pc.get_ino_by_handle (get_handle ());
2024             }
2025           else
2026             {
2027               OBJECT_ATTRIBUTES attr;
2028               HANDLE hdl;
2029               NTSTATUS f_status;
2030
2031               InitializeObjectAttributes (&attr, &fname,
2032                                           pc.objcaseinsensitive (),
2033                                           get_handle (), NULL);
2034               /* FILE_OPEN_REPARSE_POINT on NFS is a no-op, so the normal
2035                  NtOpenFile here returns the inode number of the symlink target,
2036                  rather than the inode number of the symlink itself.
2037                  
2038                  Worse, trying to open a symlink without setting the special
2039                  "ActOnSymlink" EA triggers a bug in Windows 7 which results
2040                  in a timeout of up to 20 seconds, followed by two exceptions
2041                  in the NT kernel.
2042
2043                  Since both results are far from desirable, we open symlinks
2044                  on NFS so that we get the right inode and a happy W7.
2045                  And, since some filesystems choke on the EAs, we don't
2046                  use them unconditionally. */
2047               f_status = (dir->__flags & dirent_nfs_d_ino)
2048                          ? NtCreateFile (&hdl, READ_CONTROL, &attr, &io,
2049                                          NULL, 0, FILE_SHARE_VALID_FLAGS,
2050                                          FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT,
2051                                          &nfs_aol_ffei, sizeof nfs_aol_ffei)
2052                          : NtOpenFile (&hdl, READ_CONTROL, &attr, &io,
2053                                        FILE_SHARE_VALID_FLAGS,
2054                                        FILE_OPEN_FOR_BACKUP_INTENT
2055                                        | FILE_OPEN_REPARSE_POINT);
2056               if (NT_SUCCESS (f_status))
2057                 {
2058                   /* We call NtQueryInformationFile here, rather than
2059                      pc.get_ino_by_handle(), otherwise we can't short-circuit
2060                      dirent_set_d_ino correctly. */
2061                   FILE_INTERNAL_INFORMATION fai;
2062                   f_status = NtQueryInformationFile (hdl, &io, &fai, sizeof fai,
2063                                                      FileInternalInformation);
2064                   NtClose (hdl);
2065                   if (NT_SUCCESS (f_status))
2066                     {
2067                       if (pc.isgood_inode (fai.FileId.QuadPart))
2068                         de->d_ino = fai.FileId.QuadPart;
2069                       else
2070                         /* Untrusted file system.  Don't try to fetch inode
2071                            number again. */
2072                         dir->__flags &= ~dirent_set_d_ino;
2073                     }
2074                 }
2075             }
2076         }
2077     }
2078
2079   if (!(res = readdir_helper (dir, de, RtlNtStatusToDosError (status),
2080                               FileAttributes, &fname)))
2081     dir->__d_position++;
2082   else if (!(dir->__flags & dirent_saw_dot))
2083     {
2084       strcpy (de->d_name , ".");
2085       de->d_ino = pc.get_ino_by_handle (get_handle ());
2086       de->d_type = DT_DIR;
2087       dir->__d_position++;
2088       dir->__flags |= dirent_saw_dot;
2089       res = 0;
2090     }
2091   else if (!(dir->__flags & dirent_saw_dot_dot))
2092     {
2093       strcpy (de->d_name , "..");
2094       if (!(dir->__flags & dirent_isroot))
2095         de->d_ino = readdir_get_ino (get_name (), true);
2096       else
2097         de->d_ino = pc.get_ino_by_handle (get_handle ());
2098       de->d_type = DT_DIR;
2099       dir->__d_position++;
2100       dir->__flags |= dirent_saw_dot_dot;
2101       res = 0;
2102     }
2103
2104   syscall_printf ("%d = readdir (%p, %p) (L\"%lS\" > \"%ls\") (attr %p > type %d)",
2105                   res, dir, &de, res ? NULL : &fname, res ? "***" : de->d_name,
2106                   FileAttributes, de->d_type);
2107   return res;
2108 }
2109
2110 long
2111 fhandler_disk_file::telldir (DIR *dir)
2112 {
2113   return dir->__d_position;
2114 }
2115
2116 void
2117 fhandler_disk_file::seekdir (DIR *dir, long loc)
2118 {
2119   rewinddir (dir);
2120   while (loc > dir->__d_position)
2121     if (!::readdir (dir))
2122       break;
2123 }
2124
2125 void
2126 fhandler_disk_file::rewinddir (DIR *dir)
2127 {
2128   d_cachepos (dir) = 0;
2129   if (wincap.has_buggy_restart_scan () && isremote ())
2130     {
2131       /* This works around a W2K bug.  The RestartScan parameter in calls
2132          to NtQueryDirectoryFile on remote shares is ignored, thus
2133          resulting in not being able to rewind on remote shares.  By
2134          reopening the directory, we get a fresh new directory pointer. */
2135       OBJECT_ATTRIBUTES attr;
2136       NTSTATUS status;
2137       IO_STATUS_BLOCK io;
2138       HANDLE new_dir;
2139
2140       pc.init_reopen_attr (&attr, get_handle ());
2141       status = NtOpenFile (&new_dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
2142                            &attr, &io, FILE_SHARE_VALID_FLAGS,
2143                            FILE_SYNCHRONOUS_IO_NONALERT
2144                            | FILE_OPEN_FOR_BACKUP_INTENT
2145                            | FILE_DIRECTORY_FILE);
2146       if (!NT_SUCCESS (stat))
2147         debug_printf ("Unable to reopen dir %s, NT error: %p",
2148                       get_name (), status);
2149       else
2150         {
2151           NtClose (get_handle ());
2152           set_io_handle (new_dir);
2153         }
2154     }
2155   dir->__d_position = 0;
2156   d_mounts (dir)->rewind ();
2157 }
2158
2159 int
2160 fhandler_disk_file::closedir (DIR *dir)
2161 {
2162   int res = 0;
2163   NTSTATUS status;
2164
2165   delete d_mounts (dir);
2166   if (!get_handle ())
2167     /* ignore */;
2168   else if (get_handle () == INVALID_HANDLE_VALUE)
2169     {
2170       set_errno (EBADF);
2171       res = -1;
2172     }
2173   else if (!NT_SUCCESS (status = NtClose (get_handle ())))
2174     {
2175       __seterrno_from_nt_status (status);
2176       res = -1;
2177     }
2178   syscall_printf ("%d = closedir (%p, %s)", res, dir, get_name ());
2179   return res;
2180 }
2181
2182 fhandler_cygdrive::fhandler_cygdrive () :
2183   fhandler_disk_file (), ndrives (0), pdrive (NULL)
2184 {
2185 }
2186
2187 int
2188 fhandler_cygdrive::open (int flags, mode_t mode)
2189 {
2190   if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2191     {
2192       set_errno (EEXIST);
2193       return 0;
2194     }
2195   if (flags & O_WRONLY)
2196     {
2197       set_errno (EISDIR);
2198       return 0;
2199     }
2200   flags |= O_DIROPEN;
2201   set_flags (flags);
2202   nohandle (true);
2203   return 1;
2204 }
2205
2206 int
2207 fhandler_cygdrive::close ()
2208 {
2209   return 0;
2210 }
2211
2212 void
2213 fhandler_cygdrive::set_drives ()
2214 {
2215   pdrive = pdrive_buf;
2216   ndrives = GetLogicalDriveStrings (sizeof pdrive_buf, pdrive_buf) / DRVSZ;
2217 }
2218
2219 int
2220 fhandler_cygdrive::fstat (struct __stat64 *buf)
2221 {
2222   fhandler_base::fstat (buf);
2223   buf->st_ino = 2;
2224   buf->st_mode = S_IFDIR | STD_RBITS | STD_XBITS;
2225   if (!ndrives)
2226     set_drives ();
2227   char flptst[] = "X:";
2228   int n = ndrives;
2229   for (const char *p = pdrive; p && *p; p = strchr (p, '\0') + 1)
2230     if (is_floppy ((flptst[0] = *p, flptst))
2231         || GetFileAttributes (p) == INVALID_FILE_ATTRIBUTES)
2232       n--;
2233   buf->st_nlink = n + 2;
2234   return 0;
2235 }
2236
2237 DIR *
2238 fhandler_cygdrive::opendir (int fd)
2239 {
2240   DIR *dir;
2241
2242   dir = fhandler_disk_file::opendir (fd);
2243   if (dir && !ndrives)
2244     set_drives ();
2245
2246   return dir;
2247 }
2248
2249 int
2250 fhandler_cygdrive::readdir (DIR *dir, dirent *de)
2251 {
2252   char flptst[] = "X:";
2253
2254   while (true)
2255     {
2256       if (!pdrive || !*pdrive)
2257         {
2258           if (!(dir->__flags & dirent_saw_dot))
2259             {
2260               de->d_name[0] = '.';
2261               de->d_name[1] = '\0';
2262               de->d_ino = 2;
2263             }
2264           return ENMFILE;
2265         }
2266       if (!is_floppy ((flptst[0] = *pdrive, flptst))
2267           && GetFileAttributes (pdrive) != INVALID_FILE_ATTRIBUTES)
2268         break;
2269       pdrive = strchr (pdrive, '\0') + 1;
2270     }
2271   *de->d_name = cyg_tolower (*pdrive);
2272   de->d_name[1] = '\0';
2273   user_shared->warned_msdos = true;
2274   de->d_ino = readdir_get_ino (pdrive, false);
2275   dir->__d_position++;
2276   pdrive = strchr (pdrive, '\0') + 1;
2277   syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name);
2278   return 0;
2279 }
2280
2281 void
2282 fhandler_cygdrive::rewinddir (DIR *dir)
2283 {
2284   pdrive = pdrive_buf;
2285   dir->__d_position = 0;
2286 }
2287
2288 int
2289 fhandler_cygdrive::closedir (DIR *dir)
2290 {
2291   pdrive = pdrive_buf;
2292   return 0;
2293 }