Index: trunk/src/kmk/kmkbuiltin/fts.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/fts.c	(revision 2707)
+++ trunk/src/kmk/kmkbuiltin/fts.c	(revision 2708)
@@ -127,10 +127,12 @@
 static FTSENT	*fts_sort(FTS *, FTSENT *, size_t);
 static u_short	 fts_stat(FTS *, FTSENT *, int);
+#ifdef _MSC_VER
+static u_short   fts_stat_dirent(FTS *sp, FTSENT *p, int follow, struct dirent *pDirEnt);
+#endif
 static int	 fts_safe_changedir(const FTS *, const FTSENT *, int,
     const char *);
 
 #ifdef _MSC_VER
-#undef HAVE_STRUCT_DIRENT_D_NAMLEN
-#undef HAVE_FCHDIR
+# undef HAVE_FCHDIR
 #endif
 
@@ -387,5 +389,5 @@
 		if (chdir(sp->fts_rdir))
 			saved_errno =  errno;
-        free(sp->fts_rdir);
+		free(sp->fts_rdir);
 		sp->fts_rdir = NULL;
 #endif
@@ -786,4 +788,6 @@
 	else
 		oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
+#elif defined(_MSC_VER)
+# define __opendir2(path, flag) birdDirOpenExtraInfo(path)
 #else
 #define __opendir2(path, flag) opendir(path)
@@ -941,6 +945,11 @@
 			} else
 				p->fts_accpath = p->fts_name;
+
 			/* Stat it. */
+#ifdef _MSC_VER
+			p->fts_info = fts_stat_dirent(sp, p, 0, dp);
+#else
 			p->fts_info = fts_stat(sp, p, 0);
+#endif
 
 			/* Decrement link count if applicable. */
@@ -1012,9 +1021,12 @@
 }
 
+#ifdef _MSC_VER
+/** Special version of fts_stat that takes the information from the directory
+ *  entry returned by readdir().
+ *
+ *  Directory listing returns all the stat information on systems likes
+ *  Windows and OS/2. */
 static u_short
-fts_stat(sp, p, follow)
-	FTS *sp;
-	FTSENT *p;
-	int follow;
+fts_stat_dirent(FTS *sp, FTSENT *p, int follow, struct dirent *pDirEnt)
 {
 	FTSENT *t;
@@ -1030,34 +1042,20 @@
 	sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
 
-#ifdef FTS_WHITEOUT
-	/* check for whiteout */
-	if (p->fts_flags & FTS_ISW) {
-		if (sbp != &sb) {
-			memset(sbp, '\0', sizeof (*sbp));
-			sbp->st_mode = S_IFWHT;
-		}
-		return (FTS_W);
-	}
-#endif
+	/*
+	 * Copy over the stat info from the direntry.
+	 */
+	*sbp = pDirEnt->d_stat;
 
 	/*
 	 * If doing a logical walk, or application requested FTS_FOLLOW, do
-	 * a stat(2).  If that fails, check for a non-existent symlink.  If
-	 * fail, set the errno from the stat call.
-	 */
-	if (ISSET(FTS_LOGICAL) || follow) {
+	 * a stat(2) on symlinks.  If that fails, assume non-existent
+	 * symlink and set the errno from the stat call.
+	 */
+	if (S_ISLNK(sbp->st_mode) && (ISSET(FTS_LOGICAL) || follow)) {
 		if (stat(p->fts_accpath, sbp)) {
 			saved_errno = errno;
-			if (!lstat(p->fts_accpath, sbp)) {
-				errno = 0;
-				return (FTS_SLNONE);
-			}
-			p->fts_errno = saved_errno;
-			goto err;
-		}
-	} else if (lstat(p->fts_accpath, sbp)) {
-		p->fts_errno = errno;
-err:		memset(sbp, 0, sizeof(struct STAT));
-		return (FTS_NS);
+			errno = 0;
+			return (FTS_SLNONE);
+		}
 	}
 
@@ -1087,4 +1085,96 @@
 		if (ino && dev) /** @todo ino emulation on windows... */
 #endif
+		    for (t = p->fts_parent;
+			t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+			    if (ino == t->fts_ino && dev == t->fts_dev) {
+				    p->fts_cycle = t;
+				    return (FTS_DC);
+			    }
+		return (FTS_D);
+	}
+	if (S_ISLNK(sbp->st_mode))
+		return (FTS_SL);
+	if (S_ISREG(sbp->st_mode))
+		return (FTS_F);
+	return (FTS_DEFAULT);
+}
+
+#endif /* fts_stat_dirent */
+
+static u_short
+fts_stat(sp, p, follow)
+	FTS *sp;
+	FTSENT *p;
+	int follow;
+{
+	FTSENT *t;
+	dev_t dev;
+	ino_t ino;
+	struct STAT *sbp, sb;
+	int saved_errno;
+
+	_DIAGASSERT(sp != NULL);
+	_DIAGASSERT(p != NULL);
+
+	/* If user needs stat info, stat buffer already allocated. */
+	sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
+
+#ifdef FTS_WHITEOUT
+	/* check for whiteout */
+	if (p->fts_flags & FTS_ISW) {
+		if (sbp != &sb) {
+			memset(sbp, '\0', sizeof (*sbp));
+			sbp->st_mode = S_IFWHT;
+		}
+		return (FTS_W);
+	}
+#endif
+
+	/*
+	 * If doing a logical walk, or application requested FTS_FOLLOW, do
+	 * a stat(2).  If that fails, check for a non-existent symlink.  If
+	 * fail, set the errno from the stat call.
+	 */
+	if (ISSET(FTS_LOGICAL) || follow) {
+		if (stat(p->fts_accpath, sbp)) {
+			saved_errno = errno;
+			if (!lstat(p->fts_accpath, sbp)) {
+				errno = 0;
+				return (FTS_SLNONE);
+			}
+			p->fts_errno = saved_errno;
+			goto err;
+		}
+	} else if (lstat(p->fts_accpath, sbp)) {
+		p->fts_errno = errno;
+err:		memset(sbp, 0, sizeof(struct STAT));
+		return (FTS_NS);
+	}
+
+	if (S_ISDIR(sbp->st_mode)) {
+		/*
+		 * Set the device/inode.  Used to find cycles and check for
+		 * crossing mount points.  Also remember the link count, used
+		 * in fts_build to limit the number of stat calls.  It is
+		 * understood that these fields are only referenced if fts_info
+		 * is set to FTS_D.
+		 */
+		dev = p->fts_dev = sbp->st_dev;
+		ino = p->fts_ino = sbp->st_ino;
+		p->fts_nlink = sbp->st_nlink;
+
+		if (ISDOT(p->fts_name))
+			return (FTS_DOT);
+
+		/*
+		 * Cycle detection is done by brute force when the directory
+		 * is first encountered.  If the tree gets deep enough or the
+		 * number of symbolic links to directories is high enough,
+		 * something faster might be worthwhile.
+		 */
+
+#ifdef _MSC_VER
+		if (ino && dev) /** @todo ino emulation on windows... */
+#endif
 		for (t = p->fts_parent;
 		    t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
Index: trunk/src/lib/nt/ntdir.c
===================================================================
--- trunk/src/lib/nt/ntdir.c	(revision 2707)
+++ trunk/src/lib/nt/ntdir.c	(revision 2708)
@@ -92,4 +92,13 @@
 
 
+/**
+ * Alternative opendir, with extra stat() info returned by readdir().
+ */
+BirdDir_T *birdDirOpenExtraInfo(const char *pszPath)
+{
+    return birdDirOpenInternal(pszPath, NULL, 0 /*fMinimalInfo*/);
+}
+
+
 static int birdDirReadMore(BirdDir_T *pDir)
 {
@@ -229,11 +238,11 @@
                 {
                     fSkipEntry = 1;
+                    pDir->fHaveData = 0;
                     continue;
                 }
 
-                pEntry->d_ino           = 0;
-                pEntry->d_size          = 0;
+                memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat));
+                pEntry->d_stat.st_mode  = S_IFMT;
                 pEntry->d_type          = DT_UNKNOWN;
-                pEntry->d_dirsymlink    = 0;
                 pEntry->d_reclen        = 0;
                 pEntry->d_namlen        = 0;
@@ -246,9 +255,42 @@
             }
 
-            //case MyFileIdBothDirectoryInformation:
-            //{
-            //    MY_FILE_BOTH_DIR_INFORMATION
-            //
-            //}
+            case MyFileIdFullDirectoryInformation:
+            {
+                MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
+                if (   pDir->offBuf          >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION
+                    || pInfo->FileNameLength >= pDir->cbBuf
+                    || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf)
+                {
+                    fSkipEntry = 1;
+                    pDir->fHaveData = 0;
+                    continue;
+                }
+
+                pEntry->d_type          = DT_UNKNOWN;
+                pEntry->d_reclen        = 0;
+                pEntry->d_namlen        = 0;
+                if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
+                    fSkipEntry = 1;
+                birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo, pEntry->d_name);
+                pEntry->d_stat.st_dev   = pDir->uDev;
+                switch (pEntry->d_stat.st_mode & S_IFMT)
+                {
+                    case S_IFREG:       pEntry->d_type = DT_REG; break;
+                    case S_IFDIR:       pEntry->d_type = DT_DIR; break;
+                    case S_IFLNK:       pEntry->d_type = DT_LNK; break;
+                    case S_IFIFO:       pEntry->d_type = DT_FIFO; break;
+                    case S_IFCHR:       pEntry->d_type = DT_CHR; break;
+                    default:
+#ifndef NDEBUG
+                        __debugbreak();
+#endif
+                        pEntry->d_type = DT_UNKNOWN;
+                        break;
+                }
+
+                cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength;
+                offNext  = pInfo->NextEntryOffset;
+                break;
+            }
 
             default:
Index: trunk/src/lib/nt/ntdir.h
===================================================================
--- trunk/src/lib/nt/ntdir.h	(revision 2707)
+++ trunk/src/lib/nt/ntdir.h	(revision 2708)
@@ -37,19 +37,18 @@
 typedef struct dirent
 {
-    /** File ID if available. */
-    unsigned __int64    d_ino;
-    /** The file size. */
-    unsigned __int64    d_size;
-    /** The name type. */
-    unsigned char       d_type;
-    /** Qualifies the DT_LNK d_type value. */
-    unsigned char       d_dirsymlink;
+    /** Optional stat information.
+     * Only provided if using birdDirOpenExtraInfo(). */
+    BirdStat_T          d_stat;
     /** The record length. */
     unsigned __int16    d_reclen;
     /** The name length. */
     unsigned __int16    d_namlen;
+    /** The name type. */
+    unsigned char       d_type;
     /** The name. */
-    char                d_name[512 - 8 - 8 - 1 - 1 - 2 - 2];
+    char                d_name[512 - sizeof(BirdStat_T) - 2 - 2 - 1];
 } BirdDirEntry_T;
+
+#define d_ino           d_stat.st_ino;
 
 /** @name d_type values.
@@ -98,4 +97,5 @@
 
 BirdDir_T      *birdDirOpen(const char *pszPath);
+BirdDir_T      *birdDirOpenExtraInfo(const char *pszPath);
 BirdDirEntry_T *birdDirRead(BirdDir_T *pDir);
 long            birdDirTell(BirdDir_T *pDir);
Index: trunk/src/lib/nt/ntstat.c
===================================================================
--- trunk/src/lib/nt/ntstat.c	(revision 2707)
+++ trunk/src/lib/nt/ntstat.c	(revision 2708)
@@ -184,4 +184,36 @@
 
 
+/**
+ * Fills in a stat structure from an MY_FILE_ID_FULL_DIR_INFORMATION entry.
+ *
+ * @param   pStat               The stat structure.
+ * @param   pBuf                The MY_FILE_ID_FULL_DIR_INFORMATION entry.
+ * @param   pszPath             Optionally, the path for X bit checks.
+ */
+void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
+{
+    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
+                                                 NULL, &pStat->st_dirsymlink);
+    pStat->st_padding0[0]   = 0;
+    pStat->st_padding0[1]   = 0;
+    pStat->st_size          = pBuf->EndOfFile.QuadPart;
+    birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart,   &pStat->st_birthtim);
+    birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart,     &pStat->st_ctim);
+    birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart,  &pStat->st_mtim);
+    birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
+    pStat->st_ino           = pBuf->FileId.QuadPart;
+    pStat->st_nlink         = 1;
+    pStat->st_rdev          = 0;
+    pStat->st_uid           = 0;
+    pStat->st_gid           = 0;
+    pStat->st_padding1[0]   = 0;
+    pStat->st_padding1[1]   = 0;
+    pStat->st_padding1[2]   = 0;
+    pStat->st_blksize       = 65536;
+    pStat->st_blocks        = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
+                            / BIRD_STAT_BLOCK_SIZE;
+}
+
+
 int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
 {
@@ -394,24 +426,5 @@
                      * Convert the data.
                      */
-                    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
-                                                                 NULL, &pStat->st_dirsymlink);
-                    pStat->st_padding0[0]   = 0;
-                    pStat->st_padding0[1]   = 0;
-                    pStat->st_size          = pBuf->EndOfFile.QuadPart;
-                    birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart,   &pStat->st_birthtim);
-                    birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart,     &pStat->st_ctim);
-                    birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart,  &pStat->st_mtim);
-                    birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
-                    pStat->st_ino           = pBuf->FileId.QuadPart;
-                    pStat->st_nlink         = 1;
-                    pStat->st_rdev          = 0;
-                    pStat->st_uid           = 0;
-                    pStat->st_gid           = 0;
-                    pStat->st_padding1[0]   = 0;
-                    pStat->st_padding1[1]   = 0;
-                    pStat->st_padding1[2]   = 0;
-                    pStat->st_blksize       = 65536;
-                    pStat->st_blocks        = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
-                                            / BIRD_STAT_BLOCK_SIZE;
+                    birdStatFillFromFileIdFullDirInfo(pStat, pBuf, pszPath);
 
                     /* Get the serial number, reusing the buffer from above. */
Index: trunk/src/lib/nt/ntstat.h
===================================================================
--- trunk/src/lib/nt/ntstat.h	(revision 2707)
+++ trunk/src/lib/nt/ntstat.h	(revision 2708)
@@ -79,4 +79,7 @@
 int birdStatOnFd(int fd, BirdStat_T *pStat);
 int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink);
+#ifdef ___nt_ntstuff_h
+void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath);
+#endif
 
 #define STAT_REDEFINED_ALREADY
Index: trunk/src/lib/nt/ntstuff.h
===================================================================
--- trunk/src/lib/nt/ntstuff.h	(revision 2707)
+++ trunk/src/lib/nt/ntstuff.h	(revision 2708)
@@ -197,4 +197,6 @@
     WCHAR           FileName[1];
 } MY_FILE_ID_FULL_DIR_INFORMATION;
+/** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */
+#define MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION  ( (size_t)&((MY_FILE_ID_FULL_DIR_INFORMATION *)0)->FileName )
 
 
