Index: trunk/src/kmk/Makefile.kmk
===================================================================
--- trunk/src/kmk/Makefile.kmk	(revision 2700)
+++ trunk/src/kmk/Makefile.kmk	(revision 2702)
@@ -130,5 +130,4 @@
 	w32/subproc/sub_proc.c \
 	w32/subproc/w32err.c \
-	w32/compat/dirent.c \
 	w32/pathstuff.c \
 	w32/imagecache.c
Index: trunk/src/kmk/config.h.win
===================================================================
--- trunk/src/kmk/config.h.win	(revision 2700)
+++ trunk/src/kmk/config.h.win	(revision 2702)
@@ -273,5 +273,5 @@
 
 /* Define to 1 if you have the <sys/stat.h> header file. */
-/* #define HAVE_SYS_STAT_H 1 */
+#define HAVE_SYS_STAT_H 1
 
 /* Define to 1 if you have the <sys/timeb.h> header file. */
@@ -384,5 +384,5 @@
 
 /* Define if struct stat contains a nanoseconds field */
-/* #undef ST_MTIM_NSEC */
+#define ST_MTIM_NSEC tv_nsec
 
 /* Define to 1 on System V Release 4. */
@@ -523,14 +523,15 @@
 #endif
 
-/* bird hacks - similar in mscfakes.h */
-#include <sys/stat.h>
+/* bird stat hacks. */
 #include <io.h>
 #include <direct.h>
-#ifndef STAT_REDEFINED_ALREADY
-# define STAT_REDEFINED_ALREADY
-# undef stat
-# define stat(_path, _st) bird_w32_stat(_path, _st)
-extern int bird_w32_stat(const char *, struct stat *);
-#endif
+#include "nt/ntstat.h"
+
+/* bird dirent hack. */
+#define _DIRENT_H /* see w32/dirent.h */
+#include "nt/ntdir.h"
+#define _DIRENT_HAVE_D_NAMLEN 1
+#define _DIRENT_HAVE_D_TYPE   1
+
 
 /* cygwin sucks to much in one end or the other. */
Index: trunk/src/kmk/dir.c
===================================================================
--- trunk/src/kmk/dir.c	(revision 2700)
+++ trunk/src/kmk/dir.c	(revision 2702)
@@ -121,4 +121,5 @@
 
 #ifdef WINDOWS32
+#include <Windows.h>
 #include "pathstuff.h"
 #endif
@@ -244,4 +245,7 @@
 # define FS_NTFS     0x2
 # define FS_UNKNOWN  0x4
+# ifdef KMK
+    time_t last_updated; /**< The last time the directory was re-read. */
+# endif
 #else
 # ifdef VMS
@@ -611,4 +615,7 @@
 	      dc->ctime = st.st_ctime;
               dc->mtime = st.st_mtime;
+# ifdef KMK
+              dc->last_updated = time(NULL);
+# endif
 
               /*
@@ -691,5 +698,7 @@
   struct dirent *d;
 #ifdef WINDOWS32
+# ifndef KMK
   struct stat st;
+# endif
   int rehash = 0;
 #endif
@@ -745,5 +754,5 @@
   if (dir->dirstream == 0)
     {
-#ifdef WINDOWS32
+#if defined(WINDOWS32) && !defined(KMK)
       /*
        * Check to see if directory has changed since last read. FAT
@@ -751,5 +760,9 @@
        * on directories (ugh!).
        */
+# ifdef KMK
+      if (dir->path_key && time(NULL) > dc->last_updated + 2) /* KMK: Only recheck every 2 seconds. */
+# else
       if (dir->path_key)
+# endif
 	{
           if ((dir->fs_flags & FS_FAT) != 0)
@@ -758,5 +771,10 @@
 	      rehash = 1;
 	    }
+# ifdef KMK
+	  else if (   birdStatModTimeOnly (dir->path_key, &st.st_mtim, 1) == 0
+                   && st.st_mtime > dir->mtime)
+# else
 	  else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime)
+# endif
 	    {
 	      /* reset date stamp to show most recent re-process.  */
@@ -765,4 +783,5 @@
 	    }
 
+
           /* If it has been already read in, all done.  */
 	  if (!rehash)
@@ -773,4 +792,7 @@
           if (!dir->dirstream)
             return 0;
+# ifdef KMK
+          dc->last_updated = time(NULL);
+# endif
 	}
       else
@@ -1400,4 +1422,17 @@
 #endif
 
+#ifdef KMK
+static int dir_exists_p (const char *dirname)
+{
+  if (file_exists_p (dirname))
+    {
+      struct directory *dir = find_directory (dirname);
+      if (dir != NULL && dir->contents && dir->contents->dirfiles.ht_vec != NULL)
+        return 1;
+    }
+  return 0;
+}
+#endif
+
 void
 dir_setup_glob (glob_t *gl)
@@ -1409,4 +1444,8 @@
 #ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */
   gl->gl_lstat = local_stat;
+#endif
+#ifdef KMK
+  gl->gl_exists = file_exists_p;
+  gl->gl_isdir = dir_exists_p;
 #endif
   /* We don't bother setting gl_lstat, since glob never calls it.
@@ -1436,2 +1475,3 @@
 #endif /* CONFIG_WITH_ALLOC_CACHES */
 }
+
Index: trunk/src/kmk/function.c
===================================================================
--- trunk/src/kmk/function.c	(revision 2700)
+++ trunk/src/kmk/function.c	(revision 2702)
@@ -4438,16 +4438,16 @@
                   const char *src = comp;
                   const char *end = strchr (comp, PATH_SEPARATOR_CHAR);
-                  size_t comp_len = end ? (size_t)(end - comp) : strlen (comp);
-                  if (!comp_len)
+                  size_t src_len = end ? (size_t)(end - comp) : strlen (comp);
+                  if (!src_len)
                     {
-                      comp_len = 1;
+                      src_len = 1;
                       src = ".";
                     }
-                  if (len + comp_len + 2 + 4 < GET_PATH_MAX) /* +4 for .exe */
+                  if (len + src_len + 2 + 4 < GET_PATH_MAX) /* +4 for .exe */
                     {
-                      memcpy (buf, comp, comp_len);
-                      buf [comp_len] = '/';
-                      memcpy (&buf[comp_len + 1], cur, len);
-                      buf[comp_len + 1 + len] = '\0';
+                      memcpy (buf, src, src_len);
+                      buf [src_len] = '/';
+                      memcpy (&buf[src_len + 1], cur, len);
+                      buf[src_len + 1 + len] = '\0';
 
                       if (func_which_test_x (buf))
Index: trunk/src/kmk/glob/glob.c
===================================================================
--- trunk/src/kmk/glob/glob.c	(revision 2700)
+++ trunk/src/kmk/glob/glob.c	(revision 2702)
@@ -807,8 +807,15 @@
       /* Return the directory if we don't check for error or if it exists.  */
       if ((flags & GLOB_NOCHECK)
+#ifdef KMK
+	  || (flags & GLOB_ALTDIRFUNC
+	      ? (*pglob->gl_isdir) (dirname)
+	      : __stat (dirname, &st) == 0 && S_ISDIR (st.st_mode))
+#else
 	  || (((flags & GLOB_ALTDIRFUNC)
 	       ? (*pglob->gl_stat) (dirname, &st)
 	       : __stat (dirname, &st)) == 0
-	      && S_ISDIR (st.st_mode)))
+	      && S_ISDIR (st.st_mode))
+#endif
+	  )
 	{
 	  pglob->gl_pathv
@@ -954,7 +961,13 @@
 
 		  /* First check whether this really is a directory.  */
+#ifdef KMK
+		  if (flags & GLOB_ALTDIRFUNC
+		      ? !pglob->gl_isdir (dir)
+		      : __stat (dir, &st) != 0 || !S_ISDIR (st.st_mode))
+#else
 		  if (((flags & GLOB_ALTDIRFUNC)
 		       ? (*pglob->gl_stat) (dir, &st) : __stat (dir, &st)) != 0
 		      || !S_ISDIR (st.st_mode))
+#endif
 		    /* No directory, ignore this entry.  */
 		    continue;
@@ -1029,8 +1042,14 @@
       struct stat st;
       for (i = oldcount; i < pglob->gl_pathc; ++i)
+#ifdef KMK
+	if (flags & GLOB_ALTDIRFUNC
+	    ? pglob->gl_isdir (pglob->gl_pathv[i])
+	    : __stat (pglob->gl_pathv[i], &st) == 0 && S_ISDIR (st.st_mode) )
+#else
 	if (((flags & GLOB_ALTDIRFUNC)
 	     ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st)
 	     : __stat (pglob->gl_pathv[i], &st)) == 0
 	    && S_ISDIR (st.st_mode))
+#endif
 	  {
  	    size_t len = strlen (pglob->gl_pathv[i]) + 2;
@@ -1262,7 +1281,11 @@
 	  memcpy (&fullname[dirlen + 1], pattern, patlen + 1);
 # endif
+# ifdef KMK
+	  if (flags & GLOB_ALTDIRFUNC ? pglob->gl_exists (fullname) : __stat (fullname, &st) == 0)
+# else
 	  if (((flags & GLOB_ALTDIRFUNC)
 	       ? (*pglob->gl_stat) (fullname, &st)
 	       : __stat (fullname, &st)) == 0)
+# endif
 	    /* We found this file to be existing.  Now tell the rest
 	       of the function to copy this name into the result.  */
Index: trunk/src/kmk/glob/glob.h
===================================================================
--- trunk/src/kmk/glob/glob.h	(revision 2700)
+++ trunk/src/kmk/glob/glob.h	(revision 2702)
@@ -137,4 +137,8 @@
     int (*gl_stat) __PMT ((__const char *, struct stat *));
 #endif
+#ifdef KMK
+    int (*gl_exists) __PMT ((__const char *));
+    int (*gl_isdir) __PMT ((__const char *));
+#endif
   } glob_t;
 
Index: trunk/src/kmk/kmkbuiltin/cp.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/cp.c	(revision 2700)
+++ trunk/src/kmk/kmkbuiltin/cp.c	(revision 2702)
@@ -83,5 +83,5 @@
 
 #if defined(_MSC_VER) || defined(__gnu_linux__) || defined(__linux__)
-extern char *strlcpy(char *, const char *, size_t);
+extern size_t strlcpy(char *, const char *, size_t);
 #endif
 
Index: trunk/src/kmk/kmkbuiltin/mscfakes.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/mscfakes.c	(revision 2700)
+++ trunk/src/kmk/kmkbuiltin/mscfakes.c	(revision 2702)
@@ -109,6 +109,6 @@
 
 
-static int
-msc_set_errno(DWORD dwErr)
+int
+birdSetErrno(DWORD dwErr)
 {
     switch (dwErr)
@@ -184,5 +184,5 @@
     DWORD fAttr = GetFileAttributes(pszPath);
     if (fAttr == INVALID_FILE_ATTRIBUTES)
-        rc = msc_set_errno(GetLastError());
+        rc = birdSetErrno(GetLastError());
     else if (fMustBeDir & !(fAttr & FILE_ATTRIBUTE_DIRECTORY))
     {
@@ -200,5 +200,5 @@
             fAttr |= FILE_ATTRIBUTE_READONLY;
         if (!SetFileAttributes(pszPath, fAttr))
-            rc = msc_set_errno(GetLastError());
+            rc = birdSetErrno(GetLastError());
     }
 
@@ -224,5 +224,5 @@
     DWORD fAttr = GetFileAttributes(pszPath);
     if (fAttr == INVALID_FILE_ATTRIBUTES)
-        rc = msc_set_errno(GetLastError());
+        rc = birdSetErrno(GetLastError());
     else if (fMustBeDir & !(fAttr & FILE_ATTRIBUTE_DIRECTORY))
     {
@@ -245,5 +245,5 @@
             fAttr |= FILE_ATTRIBUTE_READONLY;
         if (!SetFileAttributes(pszPath, fAttr))
-            rc = msc_set_errno(GetLastError());
+            rc = birdSetErrno(GetLastError());
     }
 
@@ -283,5 +283,5 @@
     if (s_pfnCreateHardLinkA(pszLink, pszDst, NULL))
         return 0;
-    return msc_set_errno(GetLastError());
+    return birdSetErrno(GetLastError());
 }
 
@@ -535,42 +535,2 @@
 
 
-/*
- * Workaround for directory names with trailing slashes.
- */
-#undef stat
-int
-bird_w32_stat(const char *path, struct stat *st)
-{
-    int rc = stat(path, st);
-    if (    rc != 0
-        &&  errno == ENOENT
-        &&  *path != '\0')
-    {
-        char *slash = strchr(path, '\0') - 1;
-        if (*slash == '/' || *slash == '\\')
-        {
-            size_t len_path = slash - path + 1;
-            char *tmp = alloca(len_path + 4);
-            memcpy(tmp, path, len_path);
-            tmp[len_path] = '.';
-            tmp[len_path + 1] = '\0';
-            errno = 0;
-            rc = stat(tmp, st);
-            if (    rc == 0
-                &&  !S_ISDIR(st->st_mode))
-            {
-                errno = ENOTDIR;
-                rc = -1;
-            }
-        }
-    }
-#ifdef KMK_PRF
-    {
-        int err = errno;
-        fprintf(stderr, "stat(%s,) -> %d/%d\n", path, rc, errno);
-        errno = err;
-    }
-#endif
-    return rc;
-}
-
Index: trunk/src/kmk/kmkbuiltin/mscfakes.h
===================================================================
--- trunk/src/kmk/kmkbuiltin/mscfakes.h	(revision 2700)
+++ trunk/src/kmk/kmkbuiltin/mscfakes.h	(revision 2702)
@@ -39,41 +39,9 @@
 #include <io.h>
 #include <direct.h>
+#include "nt/ntstat.h"
 #if defined(MSC_DO_64_BIT_IO) && _MSC_VER >= 1400 /* We want 64-bit file lengths here when possible. */
 # define off_t __int64
-# undef stat
-# define stat  _stat64
-# define fstat _fstat64
 # define lseek _lseeki64
-#else
-# ifndef STAT_REDEFINED_ALREADY
-#  define STAT_REDEFINED_ALREADY
-#  undef stat
-#  define stat(_path, _st) bird_w32_stat(_path, _st)
-extern int bird_w32_stat(const char *, struct stat *);
-# endif
 #endif
-
-#ifndef S_ISDIR
-# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
-#endif
-#ifndef S_ISREG
-# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
-#endif
-#define S_ISLNK(m)  0
-#define	S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC)
-#define	S_IXUSR _S_IEXEC
-#define	S_IWUSR _S_IWRITE
-#define	S_IRUSR _S_IREAD
-#define S_IRWXG 0000070
-#define S_IRGRP	0000040
-#define S_IWGRP	0000020
-#define S_IXGRP 0000010
-#define S_IRWXO 0000007
-#define S_IROTH	0000004
-#define S_IWOTH	0000002
-#define S_IXOTH 0000001
-#define	S_ISUID 0004000
-#define	S_ISGID 0002000
-#define ALLPERMS 0000777
 
 #undef  PATH_MAX
@@ -141,5 +109,4 @@
 #define geteuid()  0
 #define getegid()  0
-#define lstat(path, s) stat(path, s)
 int lchmod(const char *path, mode_t mode);
 int msc_chmod(const char *path, mode_t mode);
@@ -172,4 +139,11 @@
 int writev(int fd, const struct iovec *vector, int count);
 
+
+
+/*
+ * MSC fake internals / helpers.
+ */
+int birdSetErrno(unsigned dwErr);
+
 #endif /* _MSC_VER */
 #endif
Index: trunk/src/kmk/kmkbuiltin/rm.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/rm.c	(revision 2700)
+++ trunk/src/kmk/kmkbuiltin/rm.c	(revision 2702)
@@ -499,5 +499,9 @@
 				rval = undelete(f);
 				operation = "undelete";
+#ifndef _MSC_VER
 			} else if (S_ISDIR(sb.st_mode)) {
+#else
+			} else if (S_ISDIR(sb.st_mode) || sb.st_dirsymlink) {
+#endif
 				rval = rmdir(f);
 				operation = "rmdir";
Index: trunk/src/kmk/w32/include/dirent.h
===================================================================
--- trunk/src/kmk/w32/include/dirent.h	(revision 2700)
+++ trunk/src/kmk/w32/include/dirent.h	(revision 2702)
@@ -18,4 +18,10 @@
 #ifndef _DIRENT_H
 #define _DIRENT_H
+
+#ifdef KMK
+# include <windows.h>
+# include "nt/ntdir.h"
+
+#else /* !KMK */
 
 #ifdef __MINGW32__
@@ -58,3 +64,4 @@
 
 #endif  /* !__MINGW32__ */
+#endif  /* !KMK */
 #endif
Index: trunk/src/lib/Makefile.kmk
===================================================================
--- trunk/src/lib/Makefile.kmk	(revision 2700)
+++ trunk/src/lib/Makefile.kmk	(revision 2702)
@@ -5,5 +5,5 @@
 
 #
-# Copyright (c) 2006-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+# Copyright (c) 2006-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
 #
 # This file is part of kBuild.
@@ -37,8 +37,14 @@
 kUtil_TEMPLATE = LIB
 kUtil_DEFS.win = __WIN__
-kUtil_SOURCES = crc32.c md5.c
+kUtil_SOURCES = \
+	crc32.c \
+	md5.c
 kUtil_SOURCES.win = \
 	nt_fullpath.c \
-	quoted_spawn.c
+	quoted_spawn.c \
+       nt/nthlpcore.c \
+       nt/nthlpfs.c \
+       nt/ntdir.c \
+       nt/ntstat.c
 kUtil_SOURCES.solaris = \
 	restartable-syscall-wrappers.c
@@ -57,4 +63,10 @@
 wrapper_NOINST = 1
 
+PROGRAMS.win += tstNtStat
+tstNtStat_TEMPLATE = BIN
+tstNtStat_SOURCES = nt/tstNtStat.c
+tstNtStat_LIBS = $(LIB_KUTIL)
+tstNtStat_NOINST = 1
+
 include $(FILE_KBUILD_SUB_FOOTER)
 
Index: trunk/src/lib/nt/ntdir.c
===================================================================
--- trunk/src/lib/nt/ntdir.c	(revision 2702)
+++ trunk/src/lib/nt/ntdir.c	(revision 2702)
@@ -0,0 +1,322 @@
+/* $Id$ */
+/** @file
+ * MSC + NT opendir, readdir, telldir, seekdir, and closedir.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <stdio.h>
+#include <errno.h>
+#include <malloc.h>
+
+#include "ntstuff.h"
+#include "nthlp.h"
+#include "ntdir.h"
+
+
+/**
+ * Internal worker for birdStatModTimeOnly.
+ */
+static BirdDir_T *birdDirOpenInternal(const char *pszPath, const char *pszFilter, int fMinimalInfo)
+{
+    HANDLE hFile = birdOpenFile(pszPath,
+                                FILE_READ_DATA | SYNCHRONIZE,
+                                FILE_ATTRIBUTE_NORMAL,
+                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                FILE_OPEN,
+                                FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
+                                OBJ_CASE_INSENSITIVE);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        /*
+         * Allocate a handle.
+         */
+        BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir));
+        if (pDir)
+        {
+            pDir->uMagic     = BIRD_DIR_MAGIC;
+            pDir->pvHandle   = (void *)hFile;
+            pDir->uDev       = 0;
+            pDir->offPos     = 0;
+            pDir->fHaveData  = 0;
+            pDir->fFirst     = 1;
+            pDir->iInfoClass = fMinimalInfo ? MyFileNamesInformation : MyFileIdFullDirectoryInformation;
+            pDir->offBuf     = 0;
+            pDir->cbBuf      = 0;
+            pDir->pabBuf     = NULL;
+            return pDir;
+        }
+
+        birdCloseFile(hFile);
+        birdSetErrnoToNoMem();
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Implements opendir.
+ */
+BirdDir_T *birdDirOpen(const char *pszPath)
+{
+    return birdDirOpenInternal(pszPath, NULL, 1 /*fMinimalInfo*/);
+}
+
+
+static int birdDirReadMore(BirdDir_T *pDir)
+{
+    MY_NTSTATUS         rcNt;
+    MY_IO_STATUS_BLOCK  Ios;
+    int                 fFirst;
+
+    /*
+     * Retrieve the volume serial number + creation time and create the
+     * device number the first time around.  Also allocate a buffer.
+     */
+    fFirst = pDir->fFirst;
+    if (fFirst)
+    {
+        union
+        {
+            MY_FILE_FS_VOLUME_INFORMATION VolInfo;
+            unsigned char abBuf[1024];
+        } uBuf;
+
+        Ios.Information = 0;
+        Ios.u.Status    = -1;
+        rcNt = g_pfnNtQueryVolumeInformationFile((HANDLE)pDir->pvHandle, &Ios, &uBuf, sizeof(uBuf), MyFileFsVolumeInformation);
+        if (MY_NT_SUCCESS(rcNt))
+            rcNt = Ios.u.Status;
+        if (MY_NT_SUCCESS(rcNt))
+            pDir->uDev = uBuf.VolInfo.VolumeSerialNumber
+                       | (uBuf.VolInfo.VolumeCreationTime.QuadPart << 32);
+        else
+            pDir->uDev = 0;
+
+        /*
+         * Allocate a buffer.
+         */
+        pDir->cbBuf = 0x20000;
+        pDir->pabBuf = birdMemAlloc(pDir->cbBuf);
+        if (!pDir->pabBuf)
+            return birdSetErrnoToNoMem();
+
+        pDir->fFirst = 0;
+    }
+
+    /*
+     * Read another buffer full.
+     */
+    Ios.Information = 0;
+    Ios.u.Status    = -1;
+
+    rcNt = g_pfnNtQueryDirectoryFile((HANDLE)pDir->pvHandle,
+                                     NULL,      /* hEvent */
+                                     NULL,      /* pfnApcComplete */
+                                     NULL,      /* pvApcCompleteCtx */
+                                     &Ios,
+                                     pDir->pabBuf,
+                                     pDir->cbBuf,
+                                     (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass,
+                                     FALSE,     /* fReturnSingleEntry */
+                                     NULL,      /* Filter / restart pos. */
+                                     FALSE);    /* fRestartScan */
+    if (!MY_NT_SUCCESS(rcNt))
+    {
+        int rc;
+        if (rcNt == MY_STATUS_NO_MORE_FILES)
+            rc = 0;
+        else
+            rc = birdSetErrnoFromNt(rcNt);
+        pDir->fHaveData = 0;
+        pDir->offBuf    = pDir->cbBuf;
+        return rc;
+    }
+
+    pDir->offBuf    = 0;
+    pDir->fHaveData = 1;
+
+    return 0;
+}
+
+
+static int birdDirCopyNameToEntry(WCHAR const *pwcName, ULONG cbName, BirdDirEntry_T *pEntry)
+{
+    int cchOut = WideCharToMultiByte(CP_ACP, 0,
+                                     pwcName, cbName / sizeof(WCHAR),
+                                     pEntry->d_name, sizeof(pEntry->d_name) - 1,
+                                     NULL, NULL);
+    if (cchOut > 0)
+    {
+        pEntry->d_name[cchOut] = '\0';
+        pEntry->d_namlen = (unsigned __int16)cchOut;
+        pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cchOut + 1] - (size_t)pEntry);
+        return 0;
+    }
+    return -1;
+}
+
+
+
+/**
+ * Implements readdir_r().
+ */
+int birdDirReadReentrant(BirdDir_T *pDir, BirdDirEntry_T *pEntry, BirdDirEntry_T **ppResult)
+{
+    int fSkipEntry;
+
+    *ppResult = NULL;
+
+    if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
+        return birdSetErrnoToBadFileNo();
+
+    do
+    {
+        ULONG offNext;
+        ULONG cbMinCur;
+
+        /*
+         * Read more?
+         */
+        if (!pDir->fHaveData)
+        {
+            if (birdDirReadMore(pDir) != 0)
+                return -1;
+            if (!pDir->fHaveData)
+                return 0;
+        }
+
+        /*
+         * Convert the NT data to the unixy output structure.
+         */
+        fSkipEntry = 0;
+        switch (pDir->iInfoClass)
+        {
+            case MyFileNamesInformation:
+            {
+                MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
+                if (   pDir->offBuf          >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION
+                    || pInfo->FileNameLength >= pDir->cbBuf
+                    || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf)
+                {
+                    fSkipEntry = 1;
+                    continue;
+                }
+
+                pEntry->d_ino           = 0;
+                pEntry->d_size          = 0;
+                pEntry->d_type          = DT_UNKNOWN;
+                pEntry->d_dirsymlink    = 0;
+                pEntry->d_reclen        = 0;
+                pEntry->d_namlen        = 0;
+                if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
+                    fSkipEntry = 1;
+
+                cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength;
+                offNext  = pInfo->NextEntryOffset;
+                break;
+            }
+
+            //case MyFileIdBothDirectoryInformation:
+            //{
+            //    MY_FILE_BOTH_DIR_INFORMATION
+            //
+            //}
+
+            default:
+                return birdSetErrnoToBadFileNo();
+        }
+
+        /*
+         * Advance.
+         */
+        if (   offNext >= cbMinCur
+            && offNext < pDir->cbBuf)
+            pDir->offBuf += offNext;
+        else
+        {
+            pDir->fHaveData = 0;
+            pDir->offBuf    = pDir->cbBuf;
+        }
+        pDir->offPos++;
+    } while (fSkipEntry);
+
+
+    /*
+     * Successful return.
+     */
+    *ppResult = pEntry;
+    return 0;
+}
+
+
+/**
+ * Implements readdir().
+ */
+BirdDirEntry_T *birdDirRead(BirdDir_T *pDir)
+{
+    BirdDirEntry_T *pRet = NULL;
+    birdDirReadReentrant(pDir, &pDir->DirEntry, &pRet);
+    return pRet;
+}
+
+
+/**
+ * Implements telldir().
+ */
+long birdDirTell(BirdDir_T *pDir)
+{
+    if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
+        return birdSetErrnoToBadFileNo();
+    return pDir->offPos;
+}
+
+
+void birdDirSeek(BirdDir_T *pDir, long offDir);
+
+
+/**
+ * Implements closedir().
+ */
+int             birdDirClose(BirdDir_T *pDir)
+{
+    if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
+        return birdSetErrnoToBadFileNo();
+
+    pDir->uMagic++;
+    birdCloseFile((HANDLE)pDir->pvHandle);
+    pDir->pvHandle = (void *)INVALID_HANDLE_VALUE;
+    birdMemFree(pDir->pabBuf);
+    pDir->pabBuf = NULL;
+    birdMemFree(pDir);
+
+    return 0;
+}
Index: trunk/src/lib/nt/ntdir.h
===================================================================
--- trunk/src/lib/nt/ntdir.h	(revision 2702)
+++ trunk/src/lib/nt/ntdir.h	(revision 2702)
@@ -0,0 +1,115 @@
+/* $Id$ */
+/** @file
+ * MSC + NT opendir, readdir, closedir and friends.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+#ifndef ___nt_ntdir_h
+#define ___nt_ntdir_h
+
+#include "nttypes.h"
+#include "ntstat.h"
+
+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;
+    /** The record length. */
+    unsigned __int16    d_reclen;
+    /** The name length. */
+    unsigned __int16    d_namlen;
+    /** The name. */
+    char                d_name[512 - 8 - 8 - 1 - 1 - 2 - 2];
+} BirdDirEntry_T;
+
+/** @name d_type values.
+ * @{ */
+#define DT_UNKNOWN           0
+#define DT_FIFO              1
+#define DT_CHR               2
+#define DT_DIR               4
+#define DT_BLK               6
+#define DT_REG               8
+#define DT_LNK              10
+#define DT_SOCK             12
+#define DT_WHT              14
+/** @}  */
+
+typedef struct BirdDir
+{
+    /** Magic value. */
+    unsigned            uMagic;
+    /** The directory handle. */
+    void               *pvHandle;
+    /** The device number (st_dev). */
+    unsigned __int64    uDev;
+    /** The current position. */
+    long                offPos;
+
+    /** Set if we haven't yet read anything. */
+    int                 fFirst;
+    /** Set if we have data in the buffer. */
+    int                 fHaveData;
+    /** The info type we're querying. */
+    int                 iInfoClass;
+    /** The current buffer position. */
+    unsigned            offBuf;
+    /** The number of bytes allocated for pabBuf. */
+    unsigned            cbBuf;
+    /** Buffer of size cbBuf. */
+    unsigned char      *pabBuf;
+
+    /** Static directory entry. */
+    BirdDirEntry_T      DirEntry;
+} BirdDir_T;
+/** Magic value for BirdDir. */
+#define BIRD_DIR_MAGIC      0x19731120
+
+
+BirdDir_T      *birdDirOpen(const char *pszPath);
+BirdDirEntry_T *birdDirRead(BirdDir_T *pDir);
+long            birdDirTell(BirdDir_T *pDir);
+void            birdDirSeek(BirdDir_T *pDir, long offDir);
+int             birdDirClose(BirdDir_T *pDir);
+
+#define opendir                     birdDirOpen
+#define readdir                     birdDirRead
+#define telldir                     birdDirTell
+#define seekdir                     birdDirSeek
+#define rewinddir(a_pDir, a_offDir) birdDirSeek(a_pDir, 0)
+#define closedir                    birdDirClose
+#define _D_NAMLEN(a_pEnt)           ((a_pEnt)->d_namlen)
+typedef BirdDir_T DIR;
+
+#endif
+
Index: trunk/src/lib/nt/nthlp.h
===================================================================
--- trunk/src/lib/nt/nthlp.h	(revision 2702)
+++ trunk/src/lib/nt/nthlp.h	(revision 2702)
@@ -0,0 +1,62 @@
+/* $Id$ */
+/** @file
+ * MSC + NT helper functions.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+#ifndef ___nt_nthlp_h
+#define ___nt_nthlp_h
+
+#include "ntstuff.h"
+
+
+/** Lazy resolving of the NTDLL imports. */
+#define birdResolveImports() do { if (g_fResolvedNtImports) {} else birdResolveImportsWorker(); } while (0)
+void        birdResolveImportsWorker(void);
+extern int  g_fResolvedNtImports;
+
+void       *birdTmpAlloc(size_t cb);
+void        birdTmpFree(void *pv);
+
+void       *birdMemAlloc(size_t cb);
+void       *birdMemAllocZ(size_t cb);
+void        birdMemFree(void *pv);
+
+int         birdSetErrnoFromNt(MY_NTSTATUS rcNt);
+int         birdSetErrnoFromWin32(DWORD dwErr);
+int         birdSetErrnoToNoMem(void);
+int         birdSetErrnoToInvalidArg(void);
+int         birdSetErrnoToBadFileNo(void);
+
+
+HANDLE      birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
+                         ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs);
+void        birdCloseFile(HANDLE hFile);
+
+
+#endif
+
Index: trunk/src/lib/nt/nthlpcore.c
===================================================================
--- trunk/src/lib/nt/nthlpcore.c	(revision 2702)
+++ trunk/src/lib/nt/nthlpcore.c	(revision 2702)
@@ -0,0 +1,437 @@
+/* $Id$ */
+/** @file
+ * MSC + NT core helpers functions and globals.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <errno.h>
+#include "nthlp.h"
+#if 1
+# include <stdio.h>
+#endif
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+MY_NTSTATUS (WINAPI *g_pfnNtClose)(HANDLE);
+MY_NTSTATUS (WINAPI *g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *,
+                                        PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
+MY_NTSTATUS (WINAPI *g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS);
+MY_NTSTATUS (WINAPI *g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FS_INFORMATION_CLASS);
+MY_NTSTATUS (WINAPI *g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *,
+                                                PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN,
+                                                MY_UNICODE_STRING *, BOOLEAN);
+BOOLEAN     (WINAPI *g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *);
+MY_NTSTATUS (WINAPI *g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN);
+
+
+static struct
+{
+    FARPROC    *ppfn;
+    const char *pszName;
+} const g_apfnDynamicNtdll[] =
+{
+    { (FARPROC *)&g_pfnNtClose,                         "NtClose" },
+    { (FARPROC *)&g_pfnNtCreateFile,                    "NtCreateFile" },
+    { (FARPROC *)&g_pfnNtQueryInformationFile,          "NtQueryInformationFile" },
+    { (FARPROC *)&g_pfnNtQueryVolumeInformationFile,    "NtQueryVolumeInformationFile" },
+    { (FARPROC *)&g_pfnNtQueryDirectoryFile,            "NtQueryDirectoryFile" },
+    { (FARPROC *)&g_pfnRtlDosPathNameToNtPathName_U,    "RtlDosPathNameToNtPathName_U" },
+    { (FARPROC *)&g_pfnRtlAnsiStringToUnicodeString,    "RtlAnsiStringToUnicodeString" },
+};
+/** Set to 1 if we've successfully resolved the imports, otherwise 0. */
+int g_fResolvedNtImports = 0;
+
+
+
+void birdResolveImportsWorker(void)
+{
+    HMODULE     hMod = LoadLibraryW(L"ntdll.dll");
+    int         i    = sizeof(g_apfnDynamicNtdll) / sizeof(g_apfnDynamicNtdll[0]);
+    while (i-- > 0)
+    {
+        const char *pszSym = g_apfnDynamicNtdll[i].pszName;
+        FARPROC     pfn;
+        *g_apfnDynamicNtdll[i].ppfn = pfn = GetProcAddress(hMod, pszSym);
+        if (!pfn)
+        {
+            /* Write short message and die. */
+            static const char   s_szMsg[] = "\r\nFatal error resolving NTDLL.DLL symbols!\r\nSymbol: ";
+            DWORD               cbWritten;
+            if (   !WriteFile(GetStdHandle(STD_ERROR_HANDLE), s_szMsg, sizeof(s_szMsg) - 1, &cbWritten, NULL)
+                || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), pszSym, (DWORD)strlen(pszSym), &cbWritten, NULL)
+                || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), "\r\n", sizeof("\r\n") - 1, &cbWritten, NULL)
+                )
+                *(void **)i = NULL;
+            ExitProcess(127);
+        }
+    }
+
+    g_fResolvedNtImports = 1;
+}
+
+
+void *birdTmpAlloc(size_t cb)
+{
+    return malloc(cb);
+}
+
+
+void birdTmpFree(void *pv)
+{
+    if (pv)
+        free(pv);
+}
+
+
+void *birdMemAlloc(size_t cb)
+{
+    return malloc(cb);
+}
+
+
+void *birdMemAllocZ(size_t cb)
+{
+    return calloc(cb, 1);
+}
+
+
+void birdMemFree(void *pv)
+{
+    if (pv)
+        free(pv);
+}
+
+
+int birdErrnoFromNtStatus(MY_NTSTATUS rcNt)
+{
+    switch (rcNt)
+    {
+        /* EPERM            =  1 */
+        /* ENOENT           =  2 */
+        case STATUS_NOT_FOUND:
+        case STATUS_OBJECT_NAME_NOT_FOUND:
+        case STATUS_OBJECT_PATH_NOT_FOUND:
+        case STATUS_OBJECT_NAME_INVALID:
+        case STATUS_INVALID_COMPUTER_NAME:
+        case STATUS_VARIABLE_NOT_FOUND:
+        case STATUS_MESSAGE_NOT_FOUND:
+        case STATUS_DLL_NOT_FOUND:
+        case STATUS_ORDINAL_NOT_FOUND:
+        case STATUS_ENTRYPOINT_NOT_FOUND:
+        case STATUS_PATH_NOT_COVERED:
+        case STATUS_BAD_NETWORK_PATH:
+        case STATUS_DFS_EXIT_PATH_FOUND:
+        case RPC_NT_OBJECT_NOT_FOUND:
+            return ENOENT;
+        /* ESRCH            =  3 */
+        case STATUS_PROCESS_NOT_IN_JOB:
+            return ESRCH;
+        /* EINTR            =  4 */
+        case STATUS_ALERTED:
+        case STATUS_USER_APC:
+            return EINTR;
+        /* EIO              =  5 */
+        /* ENXIO            =  6 */
+        /* E2BIG            =  7 */
+        /* ENOEXEC          =  8 */
+        case STATUS_INVALID_IMAGE_FORMAT:
+        case STATUS_INVALID_IMAGE_NE_FORMAT:
+        case STATUS_INVALID_IMAGE_LE_FORMAT:
+        case STATUS_INVALID_IMAGE_NOT_MZ:
+        case STATUS_INVALID_IMAGE_PROTECT:
+        case STATUS_INVALID_IMAGE_WIN_16:
+        case STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT:
+        case STATUS_IMAGE_CHECKSUM_MISMATCH:
+        case STATUS_IMAGE_MP_UP_MISMATCH:
+        case STATUS_IMAGE_MACHINE_TYPE_MISMATCH:
+        case STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE:
+        case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
+        case STATUS_SECTION_NOT_IMAGE:
+        case STATUS_INVALID_IMAGE_WIN_32:
+        case STATUS_INVALID_IMAGE_WIN_64:
+        case STATUS_INVALID_IMAGE_HASH:
+        case STATUS_IMAGE_CERT_REVOKED:
+            return ENOEXEC;
+        /* EBADF            =  9 */
+        case STATUS_INVALID_HANDLE:
+        case STATUS_PORT_CLOSED:
+        case STATUS_OPLOCK_HANDLE_CLOSED:
+        case STATUS_HANDLES_CLOSED:
+        case STATUS_FILE_FORCED_CLOSED:
+            return EBADF;
+        /* ECHILD           = 10 */
+        /* EAGAIN           = 11 */
+        case STATUS_WMI_TRY_AGAIN:
+        case STATUS_GRAPHICS_TRY_AGAIN_LATER:
+        case STATUS_GRAPHICS_TRY_AGAIN_NOW:
+            return EAGAIN;
+        /* ENOMEM           = 12 */
+        case STATUS_NO_MEMORY:
+        case STATUS_HV_INSUFFICIENT_MEMORY:
+        case STATUS_INSUFFICIENT_RESOURCES:
+        case STATUS_REMOTE_RESOURCES:
+        case STATUS_INSUFF_SERVER_RESOURCES:
+            return ENOMEM;
+        /* EACCES           = 13 */
+        case STATUS_ACCESS_DENIED:
+        case STATUS_NETWORK_ACCESS_DENIED:
+        case RPC_NT_PROXY_ACCESS_DENIED:
+        case STATUS_CTX_SHADOW_DENIED:
+        case STATUS_CTX_WINSTATION_ACCESS_DENIED:
+            return EACCES;
+        /* EFAULT           = 14 */
+        case STATUS_ACCESS_VIOLATION:
+        case STATUS_HARDWARE_MEMORY_ERROR:
+            return EFAULT;
+        /* EBUSY            = 16 */
+        case STATUS_PIPE_BUSY:
+        case STATUS_RESOURCE_IN_USE:
+            return EBUSY;
+        /* EEXIST           = 17 */
+        case STATUS_OBJECT_NAME_EXISTS:
+        case STATUS_OBJECT_NAME_COLLISION:
+        case STATUS_DUPLICATE_NAME:
+            return EEXIST;
+        /* EXDEV            = 18 */
+        /* ENODEV           = 19 */
+        /* ENOTDIR          = 20 */
+        case STATUS_NOT_A_DIRECTORY:
+        case STATUS_DIRECTORY_IS_A_REPARSE_POINT:
+        case STATUS_OBJECT_PATH_SYNTAX_BAD:
+        case STATUS_OBJECT_PATH_INVALID:
+        case STATUS_OBJECT_TYPE_MISMATCH:
+            return ENOTDIR;
+        /* EISDIR           = 21 */
+        case STATUS_FILE_IS_A_DIRECTORY:
+            return EISDIR;
+        /* EINVAL           = 22 */
+        case STATUS_INVALID_PARAMETER:
+        case STATUS_INVALID_PARAMETER_1:
+        case STATUS_INVALID_PARAMETER_2:
+        case STATUS_INVALID_PARAMETER_3:
+        case STATUS_INVALID_PARAMETER_4:
+        case STATUS_INVALID_PARAMETER_5:
+        case STATUS_INVALID_PARAMETER_6:
+        case STATUS_INVALID_PARAMETER_7:
+        case STATUS_INVALID_PARAMETER_8:
+        case STATUS_INVALID_PARAMETER_9:
+        case STATUS_INVALID_PARAMETER_10:
+        case STATUS_INVALID_PARAMETER_11:
+        case STATUS_INVALID_PARAMETER_12:
+        case STATUS_INVALID_PARAMETER_MIX:
+            return EINVAL;
+        /* ENFILE           = 23 */
+        /* EMFILE           = 24 */
+        case STATUS_TOO_MANY_OPENED_FILES:
+            return EMFILE;
+        /* ENOTTY           = 25 */
+        /* EFBIG            = 27 */
+        /* ENOSPC           = 28 */
+        case STATUS_DISK_FULL:
+            return ENOSPC;
+        /* ESPIPE           = 29 */
+        /* EROFS            = 30 */
+        /* EMLINK           = 31 */
+        /* EPIPE            = 32 */
+        case STATUS_PIPE_BROKEN:
+        case RPC_NT_PIPE_CLOSED:
+            return EPIPE;
+        /* EDOM             = 33 */
+        /* ERANGE           = 34 */
+        /* EDEADLK          = 36 */
+        case STATUS_POSSIBLE_DEADLOCK:
+            return EDEADLK;
+        /* ENAMETOOLONG     = 38 */
+        case STATUS_NAME_TOO_LONG:
+            return ENAMETOOLONG;
+        /* ENOLCK           = 39 */
+        /* ENOSYS           = 40 */
+        case STATUS_NOT_SUPPORTED:
+            return ENOSYS;
+        /* ENOTEMPTY        = 41 */
+        case STATUS_DIRECTORY_NOT_EMPTY:
+            return ENOTEMPTY;
+        /* EILSEQ           = 42 */
+        /* EADDRINUSE       = 100 */
+        /* EADDRNOTAVAIL    = 101 */
+        /* EAFNOSUPPORT     = 102 */
+        /* EALREADY         = 103 */
+        case STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED:
+        case STATUS_DEVICE_ALREADY_ATTACHED:
+        case STATUS_PORT_ALREADY_SET:
+        case STATUS_IMAGE_ALREADY_LOADED:
+        case STATUS_TOKEN_ALREADY_IN_USE:
+        case STATUS_IMAGE_ALREADY_LOADED_AS_DLL:
+        case STATUS_ADDRESS_ALREADY_EXISTS:
+        case STATUS_ADDRESS_ALREADY_ASSOCIATED:
+            return EALREADY;
+        /* EBADMSG          = 104 */
+        /* ECANCELED        = 105 */
+        /* ECONNABORTED     = 106 */
+        /* ECONNREFUSED     = 107 */
+        /* ECONNRESET       = 108 */
+        /* EDESTADDRREQ     = 109 */
+        /* EHOSTUNREACH     = 110 */
+        case STATUS_HOST_UNREACHABLE:
+            return EHOSTUNREACH;
+        /* EIDRM            = 111 */
+        /* EINPROGRESS      = 112 */
+        /* EISCONN          = 113 */
+        /* ELOOP            = 114 */
+        /* EMSGSIZE         = 115 */
+        /* ENETDOWN         = 116 */
+        /* ENETRESET        = 117 */
+        /* ENETUNREACH      = 118 */
+        case STATUS_NETWORK_UNREACHABLE:
+            return ENETUNREACH;
+        /* ENOBUFS          = 119 */
+        /* ENODATA          = 120 */
+        /* ENOLINK          = 121 */
+        /* ENOMSG           = 122 */
+        /* ENOPROTOOPT      = 123 */
+        /* ENOSR            = 124 */
+        /* ENOSTR           = 125 */
+        /* ENOTCONN         = 126 */
+        /* ENOTRECOVERABLE  = 127 */
+        /* ENOTSOCK         = 128 */
+        /* ENOTSUP          = 129 */
+        /* EOPNOTSUPP       = 130 */
+        /* EOTHER           = 131 */
+        /* EOVERFLOW        = 132 */
+        /* EOWNERDEAD       = 133 */
+        /* EPROTO           = 134 */
+        /* EPROTONOSUPPORT  = 135 */
+        /* EPROTOTYPE       = 136 */
+        /* ETIME            = 137 */
+        /* ETIMEDOUT        = 138 */
+        case STATUS_VIRTUAL_CIRCUIT_CLOSED:
+        case STATUS_TIMEOUT:
+            return ETIMEDOUT;
+
+        /* ETXTBSY          = 139 */
+        case STATUS_SHARING_VIOLATION:
+            return ETXTBSY;
+        /* EWOULDBLOCK      = 140 */
+    }
+
+#if 1
+    __debugbreak();
+    fprintf(stderr, "rcNt=%#x (%d)\n", rcNt, rcNt);
+#endif
+    return EINVAL;
+}
+
+
+int birdSetErrnoFromNt(MY_NTSTATUS rcNt)
+{
+    errno = birdErrnoFromNtStatus(rcNt);
+    return -1;
+}
+
+
+int birdSetErrnoFromWin32(DWORD dwErr)
+{
+    switch (dwErr)
+    {
+        default:
+        case ERROR_INVALID_FUNCTION:        errno = EINVAL; break;
+        case ERROR_FILE_NOT_FOUND:          errno = ENOENT; break;
+        case ERROR_PATH_NOT_FOUND:          errno = ENOENT; break;
+        case ERROR_TOO_MANY_OPEN_FILES:     errno = EMFILE; break;
+        case ERROR_ACCESS_DENIED:           errno = EACCES; break;
+        case ERROR_INVALID_HANDLE:          errno = EBADF; break;
+        case ERROR_ARENA_TRASHED:           errno = ENOMEM; break;
+        case ERROR_NOT_ENOUGH_MEMORY:       errno = ENOMEM; break;
+        case ERROR_INVALID_BLOCK:           errno = ENOMEM; break;
+        case ERROR_BAD_ENVIRONMENT:         errno = E2BIG; break;
+        case ERROR_BAD_FORMAT:              errno = ENOEXEC; break;
+        case ERROR_INVALID_ACCESS:          errno = EINVAL; break;
+        case ERROR_INVALID_DATA:            errno = EINVAL; break;
+        case ERROR_INVALID_DRIVE:           errno = ENOENT; break;
+        case ERROR_CURRENT_DIRECTORY:       errno = EACCES; break;
+        case ERROR_NOT_SAME_DEVICE:         errno = EXDEV; break;
+        case ERROR_NO_MORE_FILES:           errno = ENOENT; break;
+        case ERROR_LOCK_VIOLATION:          errno = EACCES; break;
+        case ERROR_BAD_NETPATH:             errno = ENOENT; break;
+        case ERROR_NETWORK_ACCESS_DENIED:   errno = EACCES; break;
+        case ERROR_BAD_NET_NAME:            errno = ENOENT; break;
+        case ERROR_FILE_EXISTS:             errno = EEXIST; break;
+        case ERROR_CANNOT_MAKE:             errno = EACCES; break;
+        case ERROR_FAIL_I24:                errno = EACCES; break;
+        case ERROR_INVALID_PARAMETER:       errno = EINVAL; break;
+        case ERROR_NO_PROC_SLOTS:           errno = EAGAIN; break;
+        case ERROR_DRIVE_LOCKED:            errno = EACCES; break;
+        case ERROR_BROKEN_PIPE:             errno = EPIPE; break;
+        case ERROR_DISK_FULL:               errno = ENOSPC; break;
+        case ERROR_INVALID_TARGET_HANDLE:   errno = EBADF; break;
+        case ERROR_WAIT_NO_CHILDREN:        errno = ECHILD; break;
+        case ERROR_CHILD_NOT_COMPLETE:      errno = ECHILD; break;
+        case ERROR_DIRECT_ACCESS_HANDLE:    errno = EBADF; break;
+        case ERROR_NEGATIVE_SEEK:           errno = EINVAL; break;
+        case ERROR_SEEK_ON_DEVICE:          errno = EACCES; break;
+        case ERROR_DIR_NOT_EMPTY:           errno = ENOTEMPTY; break;
+        case ERROR_NOT_LOCKED:              errno = EACCES; break;
+        case ERROR_BAD_PATHNAME:            errno = ENOENT; break;
+        case ERROR_MAX_THRDS_REACHED:       errno = EAGAIN; break;
+        case ERROR_LOCK_FAILED:             errno = EACCES; break;
+        case ERROR_ALREADY_EXISTS:          errno = EEXIST; break;
+        case ERROR_FILENAME_EXCED_RANGE:    errno = ENOENT; break;
+        case ERROR_NESTING_NOT_ALLOWED:     errno = EAGAIN; break;
+#ifdef EMLINK
+        case ERROR_TOO_MANY_LINKS:          errno = EMLINK; break;
+#endif
+    }
+
+    return -1;
+}
+
+
+int birdSetErrnoToNoMem(void)
+{
+    errno = ENOMEM;
+    return -1;
+}
+
+
+int birdSetErrnoToInvalidArg(void)
+{
+    errno = EINVAL;
+    return -1;
+}
+
+
+int birdSetErrnoToBadFileNo(void)
+{
+    errno = EBADF;
+    return -1;
+}
+
Index: trunk/src/lib/nt/nthlpfs.c
===================================================================
--- trunk/src/lib/nt/nthlpfs.c	(revision 2702)
+++ trunk/src/lib/nt/nthlpfs.c	(revision 2702)
@@ -0,0 +1,246 @@
+/* $Id$ */
+/** @file
+ * MSC + NT helpers for file system related functions.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "nthlp.h"
+
+
+
+static int birdHasTrailingSlash(const char *pszPath)
+{
+    char ch, ch2;
+
+    /* Skip leading slashes. */
+    while ((ch = *pszPath) == '/' || ch == '\\')
+        pszPath++;
+    if (ch == '\0')
+        return 0;
+
+    /* Find the last char. */
+    while ((ch2 = *++pszPath) != '\0')
+        ch = ch2;
+
+    return ch == '/' || ch == '\\' || ch == ':';
+}
+
+
+static int birdIsPathDirSpec(const char *pszPath)
+{
+    char ch, ch2;
+
+    /* Check for empty string. */
+    ch = *pszPath;
+    if (ch == '\0')
+        return 0;
+
+    /* Find the last char. */
+    while ((ch2 = *++pszPath) != '\0')
+        ch = ch2;
+
+    return ch == '/' || ch == '\\' || ch == ':';
+}
+
+#ifndef BIRD_USE_WIN32
+
+static int birdDosToNtPath(const char *pszPath, MY_UNICODE_STRING *pNtPath)
+{
+    MY_NTSTATUS         rcNt;
+    WCHAR               wszTmp[4096];
+    MY_UNICODE_STRING   TmpUniStr;
+    MY_ANSI_STRING      Src;
+
+    pNtPath->Length = pNtPath->MaximumLength = 0;
+    pNtPath->Buffer = NULL;
+
+    /*
+     * Convert the input to wide char.
+     */
+    Src.Buffer              = (PCHAR)pszPath;
+    Src.MaximumLength       = Src.Length = (USHORT)strlen(pszPath);
+
+    TmpUniStr.Length        = 0;
+    TmpUniStr.MaximumLength = sizeof(wszTmp) - sizeof(WCHAR);
+    TmpUniStr.Buffer        = wszTmp;
+
+    rcNt = g_pfnRtlAnsiStringToUnicodeString(&TmpUniStr, &Src, FALSE);
+    if (MY_NT_SUCCESS(rcNt))
+    {
+        if (TmpUniStr.Length > 0 && !(TmpUniStr.Length & 1))
+        {
+            wszTmp[TmpUniStr.Length / sizeof(WCHAR)] = '\0';
+
+            /*
+             * Convert the wide DOS path to an NT path.
+             */
+            if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, pNtPath, NULL, FALSE))
+                return 0;
+        }
+        rcNt = -1;
+    }
+    return birdSetErrnoFromNt(rcNt);
+}
+
+
+static void birdFreeNtPath(MY_UNICODE_STRING *pNtPath)
+{
+    HeapFree(GetProcessHeap(), 0, pNtPath->Buffer);
+    pNtPath->Buffer = NULL;
+}
+
+#endif /* !BIRD_USE_WIN32 */
+
+
+HANDLE birdOpenFile(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
+                    ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs)
+{
+    static int          s_fHaveOpenReparsePoint = -1;
+    HANDLE              hFile;
+#ifdef BIRD_USE_WIN32
+    SECURITY_ATTRIBUTES SecAttr;
+    DWORD               dwErr;
+    DWORD               fW32Disp;
+    DWORD               fW32Flags;
+#else
+    MY_UNICODE_STRING   NtPath;
+    MY_NTSTATUS         rcNt;
+#endif
+
+    birdResolveImports();
+
+    if (birdIsPathDirSpec(pszPath))
+        fCreateOptions |= FILE_DIRECTORY_FILE;
+    if (  (fCreateOptions & FILE_OPEN_REPARSE_POINT)
+        && s_fHaveOpenReparsePoint == 0)
+        fCreateOptions &= ~FILE_OPEN_REPARSE_POINT;
+
+#ifdef BIRD_USE_WIN32
+    /* NT -> W32 */
+
+    SecAttr.nLength              = sizeof(SecAttr);
+    SecAttr.lpSecurityDescriptor = NULL;
+    SecAttr.bInheritHandle       = fObjAttribs & OBJ_INHERIT ? TRUE : FALSE;
+
+    fW32Flags = 0;
+    if (!(fObjAttribs & OBJ_CASE_INSENSITIVE))
+        fW32Flags |= FILE_FLAG_POSIX_SEMANTICS;
+    if (fCreateOptions & FILE_OPEN_FOR_BACKUP_INTENT)
+        fW32Flags |= FILE_FLAG_BACKUP_SEMANTICS;
+    if (fCreateOptions & FILE_OPEN_REPARSE_POINT)
+        fW32Flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+    //?? if (fCreateOptions & FILE_DIRECTORY_FILE)
+    //??    fW32Flags |= ;
+
+    switch (fCreateDisposition)
+    {
+        case FILE_OPEN:             fW32Disp = OPEN_EXISTING; break;
+        case FILE_CREATE:           fW32Disp = CREATE_NEW; break;
+        case FILE_OPEN_IF:          fW32Disp = OPEN_ALWAYS; break;
+        case FILE_OVERWRITE_IF:     fW32Disp = CREATE_ALWAYS; break;
+        default:
+            __debugbreak();
+            return INVALID_HANDLE_VALUE;
+    }
+
+    hFile = CreateFileA(pszPath, fDesiredAccess, fShareAccess, &SecAttr, fW32Disp, fW32Flags, NULL /*hTemplateFile*/);
+    if (hFile != INVALID_HANDLE_VALUE)
+        return hFile;
+
+    dwErr = GetLastError();
+
+    /* Deal with FILE_FLAG_OPEN_REPARSE_POINT the first times around. */
+    if (   dwErr == ERROR_INVALID_PARAMETER
+        && s_fHaveOpenReparsePoint < 0
+        && (fCreateOptions & FILE_OPEN_REPARSE_POINT) )
+    {
+        fCreateOptions &= ~FILE_OPEN_REPARSE_POINT;
+        fW32Flags      &= ~FILE_FLAG_OPEN_REPARSE_POINT;
+        hFile = CreateFileA(pszPath, fDesiredAccess, fFileAttribs, &SecAttr, fW32Disp, fW32Flags, NULL /*hTemplateFile*/);
+        if (hFile != INVALID_HANDLE_VALUE)
+        {
+            s_fHaveOpenReparsePoint = 0;
+            return hFile;
+        }
+    }
+
+    birdSetErrnoFromWin32(dwErr);
+
+#else
+    /*
+     * Call the NT API directly.
+     */
+    if (birdDosToNtPath(pszPath, &NtPath) == 0)
+    {
+        MY_IO_STATUS_BLOCK      Ios;
+        MY_OBJECT_ATTRIBUTES    ObjAttr;
+
+        Ios.Information = -1;
+        Ios.u.Status = 0;
+
+        MyInitializeObjectAttributes(&ObjAttr, &NtPath, fObjAttribs, NULL /*hRoot*/, NULL /*pSecAttr*/);
+
+        rcNt = g_pfnNtCreateFile(&hFile,
+                                 fDesiredAccess,
+                                 &ObjAttr,
+                                 &Ios,
+                                 NULL,   /* cbFileInitialAlloc */
+                                 fFileAttribs,
+                                 fShareAccess,
+                                 fCreateDisposition,
+                                 fCreateOptions,
+                                 NULL,   /* pEaBuffer */
+                                 0);     /* cbEaBuffer*/
+        if (MY_NT_SUCCESS(rcNt))
+        {
+            birdFreeNtPath(&NtPath);
+            return hFile;
+        }
+
+        birdFreeNtPath(&NtPath);
+        birdSetErrnoFromNt(rcNt);
+    }
+
+#endif
+    return INVALID_HANDLE_VALUE;
+}
+
+
+void birdCloseFile(HANDLE hFile)
+{
+#ifdef BIRD_USE_WIN32
+    CloseHandle(hFile);
+#else
+    birdResolveImports();
+    g_pfnNtClose(hFile);
+#endif
+}
+
Index: trunk/src/lib/nt/ntstat.c
===================================================================
--- trunk/src/lib/nt/ntstat.c	(revision 2702)
+++ trunk/src/lib/nt/ntstat.c	(revision 2702)
@@ -0,0 +1,470 @@
+/* $Id$ */
+/** @file
+ * MSC + NT stat, lstat and fstat.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <stdio.h>
+#include <errno.h>
+#include <malloc.h>
+
+#include "ntstuff.h"
+#include "nthlp.h"
+#include "ntstat.h"
+
+
+#undef stat
+
+static int birdIsExecutableExtension(const char *pszExt)
+{
+    return  !strcmp(pszExt, "exe")
+         || !strcmp(pszExt, "cmd")
+         || !strcmp(pszExt, "bat")
+         || !strcmp(pszExt, "vbs")
+         || !strcmp(pszExt, "com")
+         ;
+}
+
+
+static int birdIsFileExecutable(const char *pszName)
+{
+    const char     *pszExt = NULL;
+    char            szExt[8];
+    size_t          cchExt;
+    unsigned        i;
+    char            ch;
+
+    /* Look for a 3 char extension. */
+    ch = *pszName++;
+    if (!ch)
+        return 0;
+
+    while ((ch = *pszName++) != '\0')
+        if (ch == '.')
+            pszExt = pszName;
+
+    if (!pszExt)
+        return 0;
+    pszExt++;
+    cchExt = pszName - pszExt;
+    if (cchExt != 3)
+        return 0;
+
+    /* Copy the extension out and lower case it. */
+    for (i = 0; i < cchExt; i++, pszExt++)
+    {
+        ch = *pszExt;
+        if (ch >= 'A' && ch <= 'Z')
+            ch += 'a' - 'A';
+        szExt[i] = ch;
+    }
+    szExt[i] = '\0';
+
+    return birdIsExecutableExtension(szExt);
+}
+
+
+static int birdIsFileExecutableW(WCHAR const *pwcName, ULONG cwcName)
+{
+    char            szExt[8];
+    unsigned        cchExt;
+    unsigned        i;
+    WCHAR const    *pwc;
+
+    /* Look for a 3 char extension. */
+    if (cwcName > 2 && pwcName[cwcName - 2] == '.')
+        return 0;
+    else if (cwcName > 3 && pwcName[cwcName - 3] == '.')
+        return 0;
+    else if (cwcName > 4 && pwcName[cwcName - 4] == '.')
+        cchExt = 3;
+    else
+        return 0;
+
+    /* Copy the extension out and lower case it. */
+    pwc = &pwcName[cwcName - cchExt];
+    for (i = 0; i < cchExt; i++, pwc++)
+    {
+        WCHAR wc = *pwc;
+        if (wc >= 'A' && wc <= 'Z')
+            wc += 'a' - 'A';
+        else if (wc > 255)
+            wc = 255;
+        szExt[i] = (char)wc;
+    }
+    szExt[i] = '\0';
+
+    return birdIsExecutableExtension(szExt);
+}
+
+
+static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const char *pszName,
+                                         MY_FILE_NAME_INFORMATION *pNameInfo, __int16 *pfIsDirSymlink)
+{
+    unsigned short fMode;
+
+    /* File type. */
+    if (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
+    {
+        MY_FILE_ATTRIBUTE_TAG_INFORMATION   TagInfo;
+        MY_IO_STATUS_BLOCK                  Ios;
+        MY_NTSTATUS                         rcNt;
+        Ios.Information = 0;
+        Ios.u.Status    = -1;
+        rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation);
+        if (   !MY_NT_SUCCESS(rcNt)
+            || !MY_NT_SUCCESS(Ios.u.Status)
+            || TagInfo.ReparseTag != IO_REPARSE_TAG_SYMLINK)
+            fAttribs &= ~FILE_ATTRIBUTE_REPARSE_POINT;
+    }
+
+    if (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
+    {
+        *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY);
+        fMode = S_IFLNK;
+    }
+    else
+    {
+        *pfIsDirSymlink = 0;
+        if (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
+            fMode = S_IFDIR;
+        else
+            fMode = S_IFREG;
+    }
+
+    /* Access mask. */
+    fMode |= S_IROTH | S_IRGRP | S_IRUSR;
+    if (!(fAttribs & FILE_ATTRIBUTE_READONLY))
+        fMode |= S_IWOTH | S_IWGRP | S_IWUSR;
+    if (   (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
+        || (pszName
+            ? birdIsFileExecutable(pszName)
+            : birdIsFileExecutableW(pNameInfo->FileName, pNameInfo->FileNameLength)) )
+        fMode |= S_IXOTH | S_IXGRP | S_IXUSR;
+
+    return fMode;
+}
+
+
+static void birdNtTimeToTimeSpec(__int64 iNtTime, BirdTimeSpec_T *pTimeSpec)
+{
+    iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS;
+    pTimeSpec->tv_sec  = iNtTime / 10000000;
+    pTimeSpec->tv_nsec = (iNtTime % 10000000) * 100;
+}
+
+
+int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
+{
+    int                      rc;
+    MY_NTSTATUS              rcNt;
+#if 0
+    ULONG                    cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000;
+    MY_FILE_ALL_INFORMATION *pAll  = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll);
+    if (pAll)
+    {
+        MY_IO_STATUS_BLOCK Ios;
+        Ios.Information = 0;
+        Ios.u.Status    = -1;
+        rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation);
+        if (MY_NT_SUCCESS(rcNt))
+            rcNt = Ios.u.Status;
+        if (MY_NT_SUCCESS(rcNt))
+        {
+            pStat->st_mode          = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
+                                                         &pAll->NameInformation, &pStat->st_dirsymlink);
+            pStat->st_padding0[0]   = 0;
+            pStat->st_padding0[1]   = 0;
+            pStat->st_size          = pAll->StandardInformation.EndOfFile.QuadPart;
+            birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart,   &pStat->st_birthtim);
+            birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart,     &pStat->st_ctim);
+            birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart,  &pStat->st_mtim);
+            birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim);
+            pStat->st_ino           = pAll->InternalInformation.IndexNumber.QuadPart;
+            pStat->st_nlink         = pAll->StandardInformation.NumberOfLinks;
+            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        = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
+                                    / BIRD_STAT_BLOCK_SIZE;
+
+            /* Get the serial number, reusing the buffer from above. */
+            rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation);
+            if (MY_NT_SUCCESS(rcNt))
+                rcNt = Ios.u.Status;
+            if (MY_NT_SUCCESS(rcNt))
+            {
+                MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll;
+                pStat->st_dev       = pVolInfo->VolumeSerialNumber
+                                    | (pVolInfo->VolumeCreationTime.QuadPart << 32);
+                rc = 0;
+            }
+            else
+            {
+                pStat->st_dev       = 0;
+                rc = birdSetErrnoFromNt(rcNt);
+            }
+        }
+        else
+            rc = birdSetErrnoFromNt(rcNt);
+    }
+    else
+        rc = birdSetErrnoToNoMem();
+#else
+    ULONG                           cbNameInfo = 0;
+    MY_FILE_NAME_INFORMATION       *pNameInfo  = NULL;
+    MY_FILE_STANDARD_INFORMATION    StdInfo;
+    MY_FILE_BASIC_INFORMATION       BasicInfo;
+    MY_FILE_INTERNAL_INFORMATION    InternalInfo;
+    MY_IO_STATUS_BLOCK              Ios;
+
+    Ios.Information = 0;
+    Ios.u.Status    = -1;
+    rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation);
+    if (MY_NT_SUCCESS(rcNt))
+        rcNt = Ios.u.Status;
+    if (MY_NT_SUCCESS(rcNt))
+        rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
+    if (MY_NT_SUCCESS(rcNt))
+        rcNt = Ios.u.Status;
+    if (MY_NT_SUCCESS(rcNt))
+        rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
+    if (MY_NT_SUCCESS(rcNt))
+        rcNt = Ios.u.Status;
+    if (MY_NT_SUCCESS(rcNt) && !pszPath)
+    {
+        cbNameInfo = 0x10020;
+        pNameInfo  = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
+        rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation);
+        if (MY_NT_SUCCESS(rcNt))
+            rcNt = Ios.u.Status;
+    }
+
+    if (MY_NT_SUCCESS(rcNt))
+    {
+        pStat->st_mode          = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
+                                                     pNameInfo, &pStat->st_dirsymlink);
+        pStat->st_padding0[0]   = 0;
+        pStat->st_padding0[1]   = 0;
+        pStat->st_size          = StdInfo.EndOfFile.QuadPart;
+        birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart,   &pStat->st_birthtim);
+        birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart,     &pStat->st_ctim);
+        birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart,  &pStat->st_mtim);
+        birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim);
+        pStat->st_ino           = InternalInfo.IndexNumber.QuadPart;
+        pStat->st_nlink         = StdInfo.NumberOfLinks;
+        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        = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
+                                / BIRD_STAT_BLOCK_SIZE;
+
+        /* Get the serial number, reusing the buffer from above. */
+        if (!cbNameInfo)
+        {
+            cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024;
+            pNameInfo  = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
+        }
+        rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation);
+        if (MY_NT_SUCCESS(rcNt))
+            rcNt = Ios.u.Status;
+        if (MY_NT_SUCCESS(rcNt))
+        {
+            MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo;
+            pStat->st_dev       = pVolInfo->VolumeSerialNumber
+                                | (pVolInfo->VolumeCreationTime.QuadPart << 32);
+            rc = 0;
+        }
+        else
+        {
+            pStat->st_dev       = 0;
+            rc = birdSetErrnoFromNt(rcNt);
+        }
+    }
+    else
+        rc = birdSetErrnoFromNt(rcNt);
+
+#endif
+    return rc;
+}
+
+
+static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
+{
+    int rc;
+    HANDLE hFile = birdOpenFile(pszPath,
+                                FILE_READ_ATTRIBUTES,
+                                FILE_ATTRIBUTE_NORMAL,
+                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                FILE_OPEN,
+                                FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
+                                OBJ_CASE_INSENSITIVE);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        rc = birdStatHandle(hFile, pStat, pszPath);
+        birdCloseFile(hFile);
+
+#if 0
+        {
+            static char s_szPrev[256];
+            size_t cchPath = strlen(pszPath);
+            if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0)
+                fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
+            else
+                memcpy(s_szPrev, pszPath, cchPath + 1);
+        }
+#endif
+        //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
+    }
+    else
+    {
+        //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
+
+        /* On things like pagefile.sys we may get sharing violation. */
+        if (GetLastError() == ERROR_SHARING_VIOLATION)
+        {
+            /** @todo Fall back on the parent directory enum if we run into a sharing
+             *        violation. */
+        }
+        rc = -1;
+    }
+
+#if 1
+    if (strchr(pszPath, ';'))
+        __debugbreak();
+#endif
+
+    return rc;
+}
+
+
+/**
+ * Implements UNIX fstat().
+ */
+int birdStatOnFd(int fd, BirdStat_T *pStat)
+{
+    int     rc;
+    HANDLE  hFile = (HANDLE)_get_osfhandle(fd);
+    if (hFile != INVALID_HANDLE_VALUE)
+        rc = birdStatHandle(hFile, pStat, NULL);
+    else
+        rc = -1;
+    return rc;
+}
+
+
+/**
+ * Implements UNIX stat().
+ */
+int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
+{
+    return birdStatInternal(pszPath, pStat, 1 /*fFollow*/);
+}
+
+
+/**
+ * Implements UNIX lstat().
+ */
+int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
+{
+    return birdStatInternal(pszPath, pStat, 0 /*fFollow*/);
+}
+
+
+/**
+ * Internal worker for birdStatModTimeOnly.
+ */
+static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo)
+{
+    int rc;
+    HANDLE hFile = birdOpenFile(pszPath,
+                                FILE_READ_ATTRIBUTES,
+                                FILE_ATTRIBUTE_NORMAL,
+                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                FILE_OPEN,
+                                FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT),
+                                OBJ_CASE_INSENSITIVE);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        MY_NTSTATUS         rcNt = 0;
+        MY_IO_STATUS_BLOCK  Ios;
+        Ios.Information = 0;
+        Ios.u.Status    = -1;
+
+        if (pBasicInfo)
+        {
+            rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation);
+            if (MY_NT_SUCCESS(rcNt))
+                rcNt = Ios.u.Status;
+        }
+        birdCloseFile(hFile);
+
+        if (!MY_NT_SUCCESS(rcNt))
+            birdSetErrnoFromNt(rcNt);
+    }
+    else
+    {
+        //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
+
+        /* On things like pagefile.sys we may get sharing violation. */
+        if (GetLastError() == ERROR_SHARING_VIOLATION)
+        {
+            /** @todo Fall back on the parent directory enum if we run into a sharing
+             *        violation. */
+        }
+        rc = -1;
+    }
+    return rc;
+}
+
+
+/**
+ * Special function for getting the modification time.
+ */
+int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink)
+{
+    MY_FILE_BASIC_INFORMATION BasicInfo;
+    int rc = birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo);
+    if (!rc)
+        birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec);
+    return rc;
+}
+
+
+
Index: trunk/src/lib/nt/ntstat.h
===================================================================
--- trunk/src/lib/nt/ntstat.h	(revision 2702)
+++ trunk/src/lib/nt/ntstat.h	(revision 2702)
@@ -0,0 +1,124 @@
+/* $Id$ */
+/** @file
+ * MSC + NT stat, lstat and fstat implementation and wrappers.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+#ifndef ___nt_ntstat_h
+#define ___nt_ntstat_h
+
+#include "nttypes.h"
+
+#include <sys/stat.h>
+#include <io.h>
+#include <direct.h>
+
+#undef stat
+#undef lstat
+#undef fstat
+
+
+/** The distance between the NT and unix epochs given in NT time (units of 100
+ *  ns). */
+#define BIRD_NT_EPOCH_OFFSET_UNIX_100NS 116444736000000000LL
+
+typedef struct BirdStat
+{
+    unsigned __int16    st_mode;
+    unsigned __int16    st_dirsymlink;
+    unsigned __int16    st_padding0[2];
+    __int64             st_size;
+    BirdTimeSpec_T      st_atim;
+    BirdTimeSpec_T      st_mtim;
+    BirdTimeSpec_T      st_ctim;
+    BirdTimeSpec_T      st_birthtim;
+    unsigned __int64    st_ino;
+    unsigned __int64    st_dev;
+    unsigned __int32    st_nlink;
+    unsigned __int16    st_rdev;
+    __int16             st_uid;
+    __int16             st_gid;
+    unsigned __int16    st_padding1[3];
+    unsigned __int32    st_blksize;
+    __int64             st_blocks;
+} BirdStat_T;
+
+#define BIRD_STAT_BLOCK_SIZE    512
+
+#define st_atime        st_atim.tv_sec
+#define st_ctime        st_ctim.tv_sec
+#define st_mtime        st_mtim.tv_sec
+#define st_birthtime    st_birthtim.tv_sec
+
+int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat);
+int birdStatOnLink(const char *pszPath, BirdStat_T *pStat);
+int birdStatOnFd(int fd, BirdStat_T *pStat);
+int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink);
+
+#define STAT_REDEFINED_ALREADY
+
+#define stat                            BirdStat
+#define BirdStat(a_pszPath, a_pStat)    birdStatFollowLink(a_pszPath, a_pStat)
+#define lstat(a_pszPath, a_pStat)       birdStatOnLink(a_pszPath, a_pStat)
+#define fstat(a_fd, a_pStat)            birdStatOnFd(a_fd, a_pStat)
+
+
+#ifndef _S_IFLNK
+# define _S_IFLNK       0xa000
+#endif
+#ifndef S_IFLNK
+# define S_IFLNK        _S_IFLNK
+#endif
+
+#ifndef S_ISLNK
+# define S_ISLNK(m)     (((m) & _S_IFMT) == _S_IFLNK)
+#endif
+#ifndef S_ISDIR
+# define S_ISDIR(m)     (((m) & _S_IFMT) == _S_IFDIR)
+#endif
+#ifndef S_ISREG
+# define S_ISREG(m)     (((m) & _S_IFMT) == _S_IFREG)
+#endif
+
+#define	S_IRWXU        (_S_IREAD | _S_IWRITE | _S_IEXEC)
+#define	S_IXUSR        _S_IEXEC
+#define	S_IWUSR        _S_IWRITE
+#define	S_IRUSR        _S_IREAD
+#define S_IRWXG        0000070
+#define S_IRGRP	       0000040
+#define S_IWGRP	       0000020
+#define S_IXGRP        0000010
+#define S_IRWXO        0000007
+#define S_IROTH	       0000004
+#define S_IWOTH	       0000002
+#define S_IXOTH        0000001
+#define	S_ISUID        0004000
+#define	S_ISGID        0002000
+#define ALLPERMS       0000777
+
+#endif
+
Index: trunk/src/lib/nt/ntstuff.h
===================================================================
--- trunk/src/lib/nt/ntstuff.h	(revision 2702)
+++ trunk/src/lib/nt/ntstuff.h	(revision 2702)
@@ -0,0 +1,357 @@
+/* $Id$ */
+/** @file
+ * Definitions, types, prototypes and globals for NT.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+
+#ifndef ___nt_ntstuff_h
+#define ___nt_ntstuff_h
+
+#define timeval timeval_Windows
+#define WIN32_NO_STATUS
+#include <Windows.h>
+#undef WIN32_NO_STATUS
+#include <ntstatus.h>
+#undef timeval
+
+
+/** @defgroup grp_nt_ntstuff NT Stuff
+ * @{ */
+
+typedef LONG MY_NTSTATUS;
+typedef ULONG MY_ACCESS_MASK;
+
+typedef struct MY_IO_STATUS_BLOCK
+{
+    union
+    {
+        MY_NTSTATUS     Status;
+        PVOID           Pointer;
+    } u;
+    ULONG_PTR           Information;
+} MY_IO_STATUS_BLOCK;
+
+typedef VOID WINAPI MY_IO_APC_ROUTINE(PVOID, MY_IO_STATUS_BLOCK *, ULONG);
+
+typedef struct MY_UNICODE_STRING
+{
+    USHORT              Length;
+    USHORT              MaximumLength;
+    PWSTR               Buffer;
+} MY_UNICODE_STRING;
+
+typedef struct MY_STRING
+{
+    USHORT              Length;
+    USHORT              MaximumLength;
+    PCHAR               Buffer;
+} MY_STRING;
+typedef MY_STRING MY_ANSI_STRING;
+
+typedef struct MY_OBJECT_ATTRIBUTES
+{
+    ULONG               Length;
+    HANDLE              RootDirectory;
+    MY_UNICODE_STRING  *ObjectName;
+    ULONG               Attributes;
+    PVOID               SecurityDescriptor;
+    PVOID               SecurityQualityOfService;
+} MY_OBJECT_ATTRIBUTES;
+
+#define MyInitializeObjectAttributes(a_pAttr, a_pName, a_fAttribs, a_hRoot, a_pSecDesc) \
+    do { \
+        (a_pAttr)->Length                   = sizeof(MY_OBJECT_ATTRIBUTES); \
+        (a_pAttr)->RootDirectory            = (a_hRoot); \
+        (a_pAttr)->Attributes               = (a_fAttribs); \
+        (a_pAttr)->ObjectName               = (a_pName); \
+        (a_pAttr)->SecurityDescriptor       = (a_pSecDesc); \
+        (a_pAttr)->SecurityQualityOfService = NULL; \
+    } while (0)
+
+
+
+typedef struct MY_FILE_BASIC_INFORMATION
+{
+    LARGE_INTEGER   CreationTime;
+    LARGE_INTEGER   LastAccessTime;
+    LARGE_INTEGER   LastWriteTime;
+    LARGE_INTEGER   ChangeTime;
+    ULONG           FileAttributes;
+} MY_FILE_BASIC_INFORMATION;
+
+typedef struct MY_FILE_STANDARD_INFORMATION
+{
+    LARGE_INTEGER   AllocationSize;
+    LARGE_INTEGER   EndOfFile;
+    ULONG           NumberOfLinks;
+    BOOLEAN         DeletePending;
+    BOOLEAN         Directory;
+} MY_FILE_STANDARD_INFORMATION;
+
+typedef struct MY_FILE_INTERNAL_INFORMATION
+{
+    LARGE_INTEGER   IndexNumber;
+} MY_FILE_INTERNAL_INFORMATION;
+
+typedef struct MY_FILE_EA_INFORMATION
+{
+    ULONG           EaSize;
+} MY_FILE_EA_INFORMATION;
+
+typedef struct MY_FILE_ACCESS_INFORMATION
+{
+    ACCESS_MASK     AccessFlags;
+} MY_FILE_ACCESS_INFORMATION;
+
+typedef struct MY_FILE_POSITION_INFORMATION
+{
+    LARGE_INTEGER   CurrentByteOffset;
+} MY_FILE_POSITION_INFORMATION;
+
+typedef struct MY_FILE_MODE_INFORMATION
+{
+    ULONG           Mode;
+} MY_FILE_MODE_INFORMATION;
+
+typedef struct MY_FILE_ALIGNMENT_INFORMATION
+{
+    ULONG           AlignmentRequirement;
+} MY_FILE_ALIGNMENT_INFORMATION;
+
+typedef struct MY_FILE_NAME_INFORMATION
+{
+    ULONG           FileNameLength;
+    WCHAR           FileName[1];
+} MY_FILE_NAME_INFORMATION;
+
+typedef struct MY_FILE_ALL_INFORMATION
+{
+    MY_FILE_BASIC_INFORMATION       BasicInformation;
+    MY_FILE_STANDARD_INFORMATION    StandardInformation;
+    MY_FILE_INTERNAL_INFORMATION    InternalInformation;
+    MY_FILE_EA_INFORMATION          EaInformation;
+    MY_FILE_ACCESS_INFORMATION      AccessInformation;
+    MY_FILE_POSITION_INFORMATION    PositionInformation;
+    MY_FILE_MODE_INFORMATION        ModeInformation;
+    MY_FILE_ALIGNMENT_INFORMATION   AlignmentInformation;
+    MY_FILE_NAME_INFORMATION        NameInformation;
+} MY_FILE_ALL_INFORMATION;
+
+typedef struct MY_FILE_ATTRIBUTE_TAG_INFORMATION
+{
+    ULONG           FileAttributes;
+    ULONG           ReparseTag;
+} MY_FILE_ATTRIBUTE_TAG_INFORMATION;
+
+
+typedef struct MY_FILE_NAMES_INFORMATION
+{
+    ULONG           NextEntryOffset;
+    ULONG           FileIndex;
+    ULONG           FileNameLength;
+    WCHAR           FileName[1];
+} MY_FILE_NAMES_INFORMATION;
+/** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */
+#define MIN_SIZEOF_MY_FILE_NAMES_INFORMATION  (4 + 4 + 4)
+
+
+typedef enum MY_FILE_INFORMATION_CLASS
+{
+    MyFileDirectoryInformation                     = 1,
+    MyFileFullDirectoryInformation,             /* = 2  */
+    MyFileBothDirectoryInformation,             /* = 3  */
+    MyFileBasicInformation,                     /* = 4  */
+    MyFileStandardInformation,                  /* = 5  */
+    MyFileInternalInformation,                  /* = 6  */
+    MyFileEaInformation,                        /* = 7  */
+    MyFileAccessInformation,                    /* = 8  */
+    MyFileNameInformation,                      /* = 9  */
+    MyFileRenameInformation,                    /* = 10 */
+    MyFileLinkInformation,                      /* = 11 */
+    MyFileNamesInformation,                     /* = 12 */
+    MyFileDispositionInformation,               /* = 13 */
+    MyFilePositionInformation,                  /* = 14 */
+    MyFileFullEaInformation,                    /* = 15 */
+    MyFileModeInformation,                      /* = 16 */
+    MyFileAlignmentInformation,                 /* = 17 */
+    MyFileAllInformation,                       /* = 18 */
+    MyFileAllocationInformation,                /* = 19 */
+    MyFileEndOfFileInformation,                 /* = 20 */
+    MyFileAlternateNameInformation,             /* = 21 */
+    MyFileStreamInformation,                    /* = 22 */
+    MyFilePipeInformation,                      /* = 23 */
+    MyFilePipeLocalInformation,                 /* = 24 */
+    MyFilePipeRemoteInformation,                /* = 25 */
+    MyFileMailslotQueryInformation,             /* = 26 */
+    MyFileMailslotSetInformation,               /* = 27 */
+    MyFileCompressionInformation,               /* = 28 */
+    MyFileObjectIdInformation,                  /* = 29 */
+    MyFileCompletionInformation,                /* = 30 */
+    MyFileMoveClusterInformation,               /* = 31 */
+    MyFileQuotaInformation,                     /* = 32 */
+    MyFileReparsePointInformation,              /* = 33 */
+    MyFileNetworkOpenInformation,               /* = 34 */
+    MyFileAttributeTagInformation,              /* = 35 */
+    MyFileTrackingInformation,                  /* = 36 */
+    MyFileIdBothDirectoryInformation,           /* = 37 */
+    MyFileIdFullDirectoryInformation,           /* = 38 */
+    MyFileValidDataLengthInformation,           /* = 39 */
+    MyFileShortNameInformation,                 /* = 40 */
+    MyFileIoCompletionNotificationInformation,  /* = 41 */
+    MyFileIoStatusBlockRangeInformation,        /* = 42 */
+    MyFileIoPriorityHintInformation,            /* = 43 */
+    MyFileSfioReserveInformation,               /* = 44 */
+    MyFileSfioVolumeInformation,                /* = 45 */
+    MyFileHardLinkInformation,                  /* = 46 */
+    MyFileProcessIdsUsingFileInformation,       /* = 47 */
+    MyFileNormalizedNameInformation,            /* = 48 */
+    MyFileNetworkPhysicalNameInformation,       /* = 49 */
+    MyFileIdGlobalTxDirectoryInformation,       /* = 50 */
+    MyFileIsRemoteDeviceInformation,            /* = 51 */
+    MyFileAttributeCacheInformation,            /* = 52 */
+    MyFileNumaNodeInformation,                  /* = 53 */
+    MyFileStandardLinkInformation,              /* = 54 */
+    MyFileRemoteProtocolInformation,            /* = 55 */
+    MyFileMaximumInformation
+} MY_FILE_INFORMATION_CLASS;
+
+
+typedef struct MY_FILE_FS_VOLUME_INFORMATION
+{
+    LARGE_INTEGER   VolumeCreationTime;
+    ULONG           VolumeSerialNumber;
+    ULONG           VolumeLabelLength;
+    BOOLEAN         SupportsObjects;
+    WCHAR           VolumeLabel[1];
+} MY_FILE_FS_VOLUME_INFORMATION;
+
+typedef enum MY_FSINFOCLASS
+{
+    MyFileFsVolumeInformation                      = 1,
+    MyFileFsLabelInformation,                   /* = 2  */
+    MyFileFsSizeInformation,                    /* = 3  */
+    MyFileFsDeviceInformation,                  /* = 4  */
+    MyFileFsAttributeInformation,               /* = 5  */
+    MyFileFsControlInformation,                 /* = 6  */
+    MyFileFsFullSizeInformation,                /* = 7  */
+    MyFileFsObjectIdInformation,                /* = 8  */
+    MyFileFsDriverPathInformation,              /* = 9  */
+    MyFileFsVolumeFlagsInformation,             /* = 10 */
+    MyFileFsMaximumInformation
+} MY_FS_INFORMATION_CLASS;
+
+
+typedef struct MY_RTLP_CURDIR_REF
+{
+    LONG            RefCount;
+    HANDLE          Handle;
+} MY_RTLP_CURDIR_REF;
+
+typedef struct MY_RTL_RELATIVE_NAME_U
+{
+    MY_UNICODE_STRING   RelativeName;
+    HANDLE              ContainingDirectory;
+    MY_RTLP_CURDIR_REF  CurDirRef;
+} MY_RTL_RELATIVE_NAME_U;
+
+
+#ifndef OBJ_INHERIT
+# define OBJ_INHERIT                        0x00000002U
+# define OBJ_PERMANENT                      0x00000010U
+# define OBJ_EXCLUSIVE                      0x00000020U
+# define OBJ_CASE_INSENSITIVE               0x00000040U
+# define OBJ_OPENIF                         0x00000080U
+# define OBJ_OPENLINK                       0x00000100U
+# define OBJ_KERNEL_HANDLE                  0x00000200U
+# define OBJ_FORCE_ACCESS_CHECK             0x00000400U
+# define OBJ_VALID_ATTRIBUTES               0x000007f2U
+#endif
+
+#ifndef FILE_OPEN
+# define FILE_SUPERSEDE                     0x00000000U
+# define FILE_OPEN                          0x00000001U
+# define FILE_CREATE                        0x00000002U
+# define FILE_OPEN_IF                       0x00000003U
+# define FILE_OVERWRITE                     0x00000004U
+# define FILE_OVERWRITE_IF                  0x00000005U
+# define FILE_MAXIMUM_DISPOSITION           0x00000005U
+#endif
+
+#ifndef FILE_DIRECTORY_FILE
+# define FILE_DIRECTORY_FILE                0x00000001U
+# define FILE_WRITE_THROUGH                 0x00000002U
+# define FILE_SEQUENTIAL_ONLY               0x00000004U
+# define FILE_NO_INTERMEDIATE_BUFFERING     0x00000008U
+# define FILE_SYNCHRONOUS_IO_ALERT          0x00000010U
+# define FILE_SYNCHRONOUS_IO_NONALERT       0x00000020U
+# define FILE_NON_DIRECTORY_FILE            0x00000040U
+# define FILE_CREATE_TREE_CONNECTION        0x00000080U
+# define FILE_COMPLETE_IF_OPLOCKED          0x00000100U
+# define FILE_NO_EA_KNOWLEDGE               0x00000200U
+# define FILE_OPEN_REMOTE_INSTANCE          0x00000400U
+# define FILE_RANDOM_ACCESS                 0x00000800U
+# define FILE_DELETE_ON_CLOSE               0x00001000U
+# define FILE_OPEN_BY_FILE_ID               0x00002000U
+# define FILE_OPEN_FOR_BACKUP_INTENT        0x00004000U
+# define FILE_NO_COMPRESSION                0x00008000U
+# define FILE_RESERVE_OPFILTER              0x00100000U
+# define FILE_OPEN_REPARSE_POINT            0x00200000U
+# define FILE_OPEN_NO_RECALL                0x00400000U
+# define FILE_OPEN_FOR_FREE_SPACE_QUERY     0x00800000U
+#endif
+
+
+/** @name NT status codes and associated macros.
+ * @{ */
+#define MY_NT_SUCCESS(a_ntRc)               ((MY_NTSTATUS)(a_ntRc) >= 0)
+#define MY_NT_FAILURE(a_ntRc)               ((MY_NTSTATUS)(a_ntRc) <  0)
+#define MY_STATUS_NO_MORE_FILES             ((MY_NTSTATUS)0x80000006)
+/** @}  */
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+extern MY_NTSTATUS (WINAPI * g_pfnNtClose)(HANDLE);
+extern MY_NTSTATUS (WINAPI * g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *,
+                                                PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
+extern MY_NTSTATUS (WINAPI * g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *,
+                                                          PVOID, LONG, MY_FILE_INFORMATION_CLASS);
+extern MY_NTSTATUS (WINAPI * g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *,
+                                                                PVOID, LONG, MY_FS_INFORMATION_CLASS);
+extern MY_NTSTATUS (WINAPI * g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *,
+                                                        PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN,
+                                                        MY_UNICODE_STRING *, BOOLEAN);
+extern BOOLEAN     (WINAPI * g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *);
+extern MY_NTSTATUS (WINAPI * g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN);
+
+
+/** @} */
+
+#endif
+
Index: trunk/src/lib/nt/nttypes.h
===================================================================
--- trunk/src/lib/nt/nttypes.h	(revision 2702)
+++ trunk/src/lib/nt/nttypes.h	(revision 2702)
@@ -0,0 +1,49 @@
+/* $Id$ */
+/** @file
+ * MSC + NT basic & common types, various definitions.
+ */
+
+/*
+ * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+#ifndef ___nt_nttypes_h
+#define ___nt_nttypes_h
+
+#include <sys/types.h>
+
+typedef struct BirdTimeSpec
+{
+    __int64       tv_sec;
+    __int32       tv_nsec;
+    __int32       tv_padding0;
+} BirdTimeSpec_T;
+
+/** The distance between the NT and unix epochs given in NT time (units of 100
+ *  ns). */
+#define BIRD_NT_EPOCH_OFFSET_UNIX_100NS 116444736000000000LL
+
+#endif
+
+
Index: trunk/src/lib/nt/tstNtStat.c
===================================================================
--- trunk/src/lib/nt/tstNtStat.c	(revision 2702)
+++ trunk/src/lib/nt/tstNtStat.c	(revision 2702)
@@ -0,0 +1,156 @@
+/* $Id$ */
+/** @file
+ * Manual lstat/stat testcase.
+ */
+
+/*
+ * Copyright (c) 2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <stdio.h>
+#include <errno.h>
+#include "ntstat.h"
+
+
+static int IsLeapYear(int iYear)
+{
+    return iYear % 4 == 0
+        && (   iYear % 100 != 0
+            || iYear % 400 == 0);
+}
+
+static int DaysInMonth(int iYear, int iMonth)
+{
+    switch (iMonth)
+    {
+        case 1:
+        case 3:
+        case 5:
+        case 7:
+        case 8:
+        case 10:
+        case 12:
+            return 31;
+        case 4:
+        case 6:
+        case 9:
+        case 11:
+            return 30;
+        case 2:
+            return IsLeapYear(iYear) ? 29 : 28;
+
+        default:
+            *(void **)(size_t)iMonth = 0; /* crash! */
+            return 0;
+    }
+}
+
+
+static char *FormatTimeSpec(char *pszBuf, BirdTimeSpec_T const *pTimeSpec)
+{
+    if (pTimeSpec->tv_sec >= 0)
+    {
+        int     iYear  = 1970;
+        int     iMonth = 1;
+        int     iDay   = 1;
+        int     iHour  = 0;
+        int     iMin   = 0;
+        int     iSec   = 0;
+        __int64 cSecs  = pTimeSpec->tv_sec;
+
+        /* lazy bird approach, find date, day by day */
+        while (cSecs >= 24*3600)
+        {
+            if (   iDay < 28
+                || iDay < DaysInMonth(iYear, iMonth))
+                iDay++;
+            else
+            {
+                if (iMonth < 12)
+                    iMonth++;
+                else
+                {
+                    iYear++;
+                    iMonth = 1;
+                }
+                iDay = 1;
+            }
+            cSecs -= 24*3600;
+        }
+
+        iHour  = (int)cSecs / 3600;
+        cSecs %= 3600;
+        iMin   = (int)cSecs / 60;
+        iSec   = (int)cSecs % 60;
+
+        sprintf(pszBuf, "%04d-%02d-%02dT%02u:%02u:%02u.%09u (%I64d.%09u)",
+                iYear, iMonth, iDay, iHour, iMin, iSec, pTimeSpec->tv_nsec,
+                pTimeSpec->tv_sec, pTimeSpec->tv_nsec);
+    }
+    else
+        sprintf(pszBuf, "%I64d.%09u (before 1970-01-01)", pTimeSpec->tv_sec, pTimeSpec->tv_nsec);
+    return pszBuf;
+}
+
+
+int main(int argc, char **argv)
+{
+    int rc = 0;
+    int i;
+
+    for (i = 1; i < argc; i++)
+    {
+        struct stat st;
+        if (lstat(argv[i], &st) == 0)
+        {
+            char szBuf[256];
+            printf("%s:\n", argv[i]);
+            printf("  st_mode:          %o\n", st.st_mode);
+            printf("  st_dirsymlink:    %d\n", st.st_dirsymlink);
+            printf("  st_size:          %I64u (%#I64x)\n", st.st_size, st.st_size);
+            printf("  st_atim:          %s\n", FormatTimeSpec(szBuf, &st.st_atim));
+            printf("  st_mtim:          %s\n", FormatTimeSpec(szBuf, &st.st_mtim));
+            printf("  st_ctim:          %s\n", FormatTimeSpec(szBuf, &st.st_ctim));
+            printf("  st_birthtim:      %s\n", FormatTimeSpec(szBuf, &st.st_birthtim));
+            printf("  st_ino:           %#I64x\n", st.st_ino);
+            printf("  st_dev:           %#I64x\n", st.st_dev);
+            printf("  st_nlink:         %u\n", st.st_nlink);
+            printf("  st_rdev:          %#x\n", st.st_rdev);
+            printf("  st_uid:           %d\n", st.st_uid);
+            printf("  st_gid:           %d\n", st.st_gid);
+            printf("  st_blksize:       %d (%#x)\n", st.st_blksize, st.st_blksize);
+            printf("  st_blocks:        %I64u (%#I64x)\n", st.st_blocks, st.st_blocks);
+        }
+        else
+        {
+            fprintf(stderr, "stat failed on '%s': errno=%u\n", argv[i], errno);
+            rc = 1;
+        }
+    }
+    return rc;
+}
+
