You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2009/10/11 12:10:37 UTC

svn commit: r824046 - in /commons/sandbox/runtime/trunk/src/main/native: Makefile.msc.in include/acr_file.h include/arch/windows/acr_arch.h os/unix/finfo.c os/win32/dir.c os/win32/dirent.c os/win32/finfo.c

Author: mturk
Date: Sun Oct 11 10:10:37 2009
New Revision: 824046

URL: http://svn.apache.org/viewvc?rev=824046&view=rev
Log:
Implement windows FileInfo and Directory API

Modified:
    commons/sandbox/runtime/trunk/src/main/native/Makefile.msc.in
    commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h
    commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h
    commons/sandbox/runtime/trunk/src/main/native/os/unix/finfo.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/dirent.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/finfo.c

Modified: commons/sandbox/runtime/trunk/src/main/native/Makefile.msc.in
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/Makefile.msc.in?rev=824046&r1=824045&r2=824046&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/Makefile.msc.in (original)
+++ commons/sandbox/runtime/trunk/src/main/native/Makefile.msc.in Sun Oct 11 10:10:37 2009
@@ -118,7 +118,6 @@
 	$(SRCDIR)/os/win32/fsysio.$(OBJ) \
 	$(SRCDIR)/os/win32/main.$(OBJ) \
 	$(SRCDIR)/os/win32/platform.$(OBJ) \
-	$(SRCDIR)/os/win32/pipe.$(OBJ) \
 	$(SRCDIR)/os/win32/proc.$(OBJ) \
 	$(SRCDIR)/os/win32/os.$(OBJ) \
 	$(SRCDIR)/os/win32/ios.$(OBJ) \

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h?rev=824046&r1=824045&r2=824046&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_file.h Sun Oct 11 10:10:37 2009
@@ -298,8 +298,11 @@
  * @param fname FileInfo.Name field.
  * @param type  FileInfo.Type field.
  */
-ACR_DECLARE(jobject) ACR_NewFileInfoObject(JNIEnv *env,
-                                           const acr_pchar_t *fname, int type);
+ACR_DECLARE(jobject) ACR_NewFileInfoObjectA(JNIEnv *env,
+                                            const char *fname, int type);
+
+ACR_DECLARE(jobject) ACR_NewFileInfoObjectW(JNIEnv *env,
+                                            const wchar_t *fname, int type);
 
 #ifdef __cplusplus
 }

Modified: commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h?rev=824046&r1=824045&r2=824046&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h Sun Oct 11 10:10:37 2009
@@ -308,6 +308,17 @@
     return;
 }
 
+static ACR_INLINE void FileTimeToMsecTime(acr_time_t *result, LPFILETIME input)
+{
+    /* Convert FILETIME one 64 bit number so we can work with it. */
+    *result  = ((LARGE_INTEGER *)input)->QuadPart;
+    /* Convert from 100 nano-sec periods to micro-seconds. */
+    *result /= 10000;
+    /* Convert from Windows epoch to Unix epoch */
+    *result -= ACR_DELTA_EPOCH_IN_USEC;
+    return;
+}
+
 
 static ACR_INLINE void UsecTimeToFileTime(LPFILETIME result, acr_time_t t)
 {
@@ -315,6 +326,12 @@
     return;
 }
 
+static ACR_INLINE void MsecTimeToFileTime(LPFILETIME result, acr_time_t t)
+{
+    ((LARGE_INTEGER *)result)->QuadPart = (t + ACR_DELTA_EPOCH_IN_USEC) * 10000;
+    return;
+}
+
 static ACR_INLINE void x_free(void *p)
 {
     if (p != NULL) {
@@ -419,6 +436,17 @@
                                     */
 } DIR;
 
+/** Dirent API
+ */
+DIR  *opendir(const char *);
+int   closedir(DIR *);
+void  rewinddir(DIR *);
+off_t telldir(DIR *);
+int   readdir_r(DIR *, struct dirent *, struct dirent **r);
+void  seekdir(DIR *, off_t);
+
+
+
 #define _NSIG       32  /* counting 0; could be 33 (mask is 1-32) */
 
 #define SIGHUP      1   /* hangup */

Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/finfo.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/finfo.c?rev=824046&r1=824045&r2=824046&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/finfo.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/finfo.c Sun Oct 11 10:10:37 2009
@@ -165,8 +165,8 @@
     ACR_UnloadClass(_E, &_clazzn);
 }
 
-ACR_DECLARE(jobject) ACR_NewFileInfoObject(JNIEnv *_E, const char *fname,
-                                           int type)
+ACR_DECLARE(jobject) ACR_NewFileInfoObjectA(JNIEnv *_E, const char *fname,
+                                            int type)
 {
     jstring name;
     if ((name = ACR_NewJavaStringA(_E, fname)))
@@ -175,6 +175,16 @@
         return NULL;
 }
 
+ACR_DECLARE(jobject) ACR_NewFileInfoObjectW(JNIEnv *_E, const wchar_t *fname,
+                                            int type)
+{
+    jstring name;
+    if ((name = ACR_NewJavaStringW(_E, fname)))
+        return (*_E)->NewObject(_E, _clazzn.i, J4MID(0001), type);
+    else
+        return NULL;
+}
+
 static void _fill0(ACR_JNISTDARGS, struct_stat_t *info, jboolean full)
 {
     SET_IFIELD_I(0000, _O, ACR_UnixModeToPerms(info->st_mode));

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c?rev=824046&r1=824045&r2=824046&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c Sun Oct 11 10:10:37 2009
@@ -1,19 +1,3 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
 #include "acr.h"
 #include "acr_private.h"
 #include "acr_arch.h"
@@ -25,6 +9,280 @@
 #include "acr_port.h"
 
 /**
- * Windows file info functions
+ * Windows directory functions
  *
  */
+
+static int descriptor_cleanup(ACR_JNISTDARGS,
+                              acr_descriptor_cb_type_e cm,
+                              acr_descriptor_cb_t *dp)
+{
+    int rc = ACR_SUCCESS;
+    switch (cm) {
+        case ACR_DESC_FINALIZE:
+        case ACR_DESC_CLOSE:
+            if (dp->dp != NULL) {
+                if (closedir((DIR *)dp->dp))
+                    rc = ACR_GET_OS_ERROR();
+            }
+            else
+                rc = ACR_EBADF;
+        break;
+        default:
+            rc = ACR_ENOTIMPL;
+        break;
+    }
+    return rc;
+}
+
+ACR_IO_EXPORT_DECLARE(jobject, Directory, open0)(ACR_JNISTDARGS, jstring name)
+{
+    DIR     *dir;
+    jobject  dd = NULL;
+    int      rc = 0;
+
+    WITH_CSTR(name) {
+        if ((dir = opendir(J2S(name)))) {
+            dd = ACR_DescriptorCreate(_E, ACR_DT_DIR, -1, dir,
+                                      descriptor_cleanup);
+        }
+        else
+            rc = ACR_GET_OS_ERROR();
+    } END_WITH_CSTR(name);
+    ACR_THROW_IO_IF_ERR(rc);
+    return dd;
+}
+
+ACR_IO_EXPORT_DECLARE(jstring, Directory, read0)(ACR_JNISTDARGS, jobject dd)
+{
+    DIR     *dir;
+    int      rc = 0;
+    jstring  rv = NULL;
+
+    dir = (DIR *)ACR_DescriptorGetPtr(_E, dd);
+    if (dir) {
+        struct dirent  ds;
+        struct dirent *dp;
+        for (;;) {
+            if (!readdir_r(dir, &ds, &dp)) {
+                if (dp) {
+                    if (*(dp->d_name) == '.' && (*(dp->d_name + 1) == '\0' ||
+                                                (*(dp->d_name + 1) == '.'  &&
+                                                 *(dp->d_name + 2) == '\0'))) {
+                        /* Skip . and .. directory entires
+                         */
+                        continue;
+                    }
+                    /* Not at end of dir */
+                    rv = ACR_NewJavaStringA(_E, dp->d_name);
+                }
+                else
+                    break;
+            }
+            else {
+                /* readdir_r failed */
+                rc = ACR_GET_OS_ERROR();
+                break;
+            }
+        }
+    }
+    ACR_THROW_IO_IF_ERR(rc);
+    return rv;
+}
+
+ACR_IO_EXPORT_DECLARE(jobject, Directory, read1)(ACR_JNISTDARGS, jobject dd)
+{
+    DIR     *dir;
+    int      rc = 0;
+    jobject  rv = NULL;
+
+    dir = (DIR *)ACR_DescriptorGetPtr(_E, dd);
+    if (dir) {
+        struct dirent  ds;
+        struct dirent *dp;
+        for (;;) {
+            if (!readdir_r(dir, &ds, &dp)) {
+                if (dp) {
+                    int type;
+                    if (*(dp->d_name) == '.' && (*(dp->d_name + 1) == '\0' ||
+                                                (*(dp->d_name + 1) == '.'  &&
+                                                 *(dp->d_name + 2) == '\0'))) {
+                        /* Skip . and .. directory entires
+                         */
+                        continue;
+                    }
+                    /* Determine the type of the enty
+                     */
+                    if (dp->d_type & FILE_ATTRIBUTE_DIRECTORY)
+                        type = ACR_FT_DIR;
+                    else if (dp->d_type & FILE_ATTRIBUTE_REPARSE_POINT)
+                        type = ACR_FT_LNK;
+                    else if (dp->d_type & FILE_ATTRIBUTE_DEVICE)
+                        type = ACR_FT_CHR;
+                    else
+                        type = ACR_FT_REG;
+                    rv = ACR_NewFileInfoObjectA(_E, dp->d_name, type);
+                }
+                else
+                    break;
+            }
+            else {
+                /* readdir_r failed */
+                rc = ACR_GET_OS_ERROR();
+                break;
+            }
+        }
+    }
+    ACR_THROW_IO_IF_ERR(rc);
+    return rv;
+}
+
+ACR_IO_EXPORT_DECLARE(void, Directory, rewind0)(ACR_JNISTDARGS, jobject dd)
+{
+    DIR     *dir;
+    if (( dir = (DIR *)ACR_DescriptorGetPtr(_E, dd))) {
+        rewinddir(dir);
+    }
+}
+
+ACR_IO_EXPORT_DECLARE(jlong, Directory, tell0)(ACR_JNISTDARGS, jobject dd)
+{
+    DIR     *dir;
+    off_t    pos = -1;
+    int      rc  =  0;
+
+    if (( dir = (DIR *)ACR_DescriptorGetPtr(_E, dd))) {
+        pos = telldir(dir);
+        if (pos == -1)
+            rc = ACR_GET_OS_ERROR();
+    }
+    else
+        rc = ACR_EBADF;
+    ACR_THROW_IO_IF_ERR(rc);
+    return (jlong)pos;
+}
+
+ACR_IO_EXPORT_DECLARE(void, Directory, seek0)(ACR_JNISTDARGS, jobject dd,
+                                              jlong off)
+{
+    DIR     *dir;
+
+    if (( dir = (DIR *)ACR_DescriptorGetPtr(_E, dd))) {
+        seekdir(dir, (off_t)off);
+    }
+}
+
+static int _mkdir0(const wchar_t *name, int perms)
+{
+    SECURITY_ATTRIBUTES sa;
+
+    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+    /* Allow access only to owner and Administrators Group */
+    sa.lpSecurityDescriptor = ACR_StdSecurityDescriptor(INVALID_HANDLE_VALUE,
+                                                        ACR_DT_FILE, perms);
+
+    if (CreateDirectoryW(name, &sa))
+        return 0;
+    else
+        return ACR_GET_OS_ERROR();
+}
+
+static __inline void FS2BS(wchar_t *path)
+{
+    while (*path) {
+        if (*path == L'/')
+            *path = L'\\';
+        path++;
+    }
+}
+
+static int _mkdir1(const wchar_t *name, int perms)
+{
+    int rc;
+
+    rc = _mkdir0(name, perms);
+    if (rc == ERROR_ALREADY_EXISTS)
+        return 0;
+    if (rc == ERROR_PATH_NOT_FOUND) {  /* Missing an intermediate dir */
+        wchar_t *pos;
+        wchar_t *dir = ACR_StrdupW(INVALID_HANDLE_VALUE, THROW_NMARK, name);
+        if (!dir)
+            return ACR_ENOMEM;
+        FS2BS(dir);
+        if ((pos = wcsrchr(dir, L'\\'))) {
+            *pos = L'\0';
+            if (*dir) {
+                rc = _mkdir1(dir, perms);
+            }
+        }
+        x_free(dir);
+    }
+    return rc;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, Directory, mkdir0)(ACR_JNISTDARGS, jstring name,
+                                               jint perms)
+{
+    int      rc = 0;
+
+    WITH_WSTR(name) {
+        rc = _mkdir0(J2W(name), perms);
+    } END_WITH_WSTR(name);
+    return rc;
+}
+
+ACR_IO_EXPORT_DECLARE(jint, Directory, mkdir1)(ACR_JNISTDARGS, jstring name,
+                                               jint perms)
+{
+    int      rc = 0;
+
+    WITH_WSTR(name) {
+        rc = _mkdir1(J2W(name), perms);
+    } END_WITH_WSTR(name);
+    return rc;
+}
+
+ACR_IO_EXPORT_DECLARE(jstring, Directory, tmpdir0)(ACR_JNISTDARGS, jstring path,
+                                                   jstring prefix)
+{
+    int      rc   = 0;
+    wchar_t *tmpd = NULL;
+
+    UNREFERENCED_O;
+
+    WITH_ZWSTR(path) {
+    WITH_ZWSTR(prefix) {
+        /* Provide INVALID_HANDLE_VALUE for JNIEnv
+         * so that in case of failure, exception doesn't get thrown
+         */
+        tmpd = ACR_TempDirMake(INVALID_HANDLE_VALUE, J2W(path), J2W(prefix));
+        if (!tmpd)
+            rc = ACR_GET_OS_ERROR();
+    } END_WITH_WSTR(prefix);
+    } END_WITH_WSTR(path);
+    if (rc) {
+        ACR_THROW_IO_IF_ERR(rc);
+        return NULL;
+    }
+    else {
+        jstring rv = ACR_NewJavaStringW(_E, tmpd);
+        x_free(tmpd);
+        return rv;
+    }
+}
+
+ACR_IO_EXPORT_DECLARE(jstring, Directory, tmpdir1)(ACR_JNISTDARGS,
+                                                   jstring paths)
+{
+    const wchar_t *tmpd = NULL;
+
+    UNREFERENCED_O;
+
+    WITH_ZWSTR(paths) {
+        tmpd = ACR_TempPathGet(INVALID_HANDLE_VALUE, J2W(paths));
+    } END_WITH_WSTR(paths);
+    if (tmpd)
+        return ACR_NewJavaStringW(_E, tmpd);
+    else
+        return NULL;
+}

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/dirent.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/dirent.c?rev=824046&r1=824045&r2=824046&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/dirent.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/dirent.c Sun Oct 11 10:10:37 2009
@@ -181,7 +181,7 @@
         if (mblen == 0 || mblen > 1024)
             return GetLastError();
         entry->d_ino    = 0;
-        entry->d_type   = 0;
+        entry->d_type   = wfind.dwFileAttributes;
         entry->d_off    = dir->d_stat;
         entry->d_reclen = (unsigned short)(mblen - 1);
         *result = entry;

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/finfo.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/finfo.c?rev=824046&r1=824045&r2=824046&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/finfo.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/finfo.c Sun Oct 11 10:10:37 2009
@@ -14,15 +14,17 @@
  * limitations under the License.
  */
 
+
 #include "acr.h"
 #include "acr_private.h"
 #include "acr_arch.h"
+#include "acr_clazz.h"
+#include "acr_descriptor.h"
 #include "acr_port.h"
 #include "acr_error.h"
 #include "acr_string.h"
-#include "acr_descriptor.h"
+#include "acr_users.h"
 #include "acr_file.h"
-#include "acr_port.h"
 
 /**
  * Windows file info functions
@@ -121,6 +123,12 @@
 
 J_DECLARE_M_ID(0001) = {
     NULL,
+    "<init>",
+    "(Ljava/lang/String;I)V"
+};
+
+J_DECLARE_M_ID(0002) = {
+    NULL,
     "setType",
     "(I)V"
 };
@@ -146,6 +154,7 @@
     J_LOAD_IFIELD(0012);
     J_LOAD_METHOD(0000);
     J_LOAD_METHOD(0001);
+    J_LOAD_METHOD(0002);
 
     return ACR_SUCCESS;
 }
@@ -154,3 +163,348 @@
 {
     ACR_UnloadClass(_E, &_clazzn);
 }
+
+ACR_DECLARE(jobject) ACR_NewFileInfoObjectA(JNIEnv *_E, const char *fname,
+                                            int type)
+{
+    jstring name;
+    if ((name = ACR_NewJavaStringA(_E, fname)))
+        return (*_E)->NewObject(_E, _clazzn.i, J4MID(0001), type);
+    else
+        return NULL;
+}
+
+ACR_DECLARE(jobject) ACR_NewFileInfoObjectW(JNIEnv *_E, const wchar_t *fname,
+                                            int type)
+{
+    jstring name;
+    if ((name = ACR_NewJavaStringW(_E, fname)))
+        return (*_E)->NewObject(_E, _clazzn.i, J4MID(0001), type);
+    else
+        return NULL;
+}
+
+static void _fill0(ACR_JNISTDARGS, BY_HANDLE_FILE_INFORMATION *info)
+{
+    acr_time_t time;
+    ULARGE_INTEGER u;
+
+    SET_IFIELD_I(0003, _O, info->nNumberOfLinks);
+    u.LowPart  = info->nFileSizeLow;
+    u.HighPart = info->nFileSizeHigh;
+    SET_IFIELD_J(0004, _O, u.QuadPart);
+    SET_IFIELD_J(0005, _O, u.QuadPart);
+    FileTimeToMsecTime(&time, &info->ftLastAccessTime);
+    SET_IFIELD_J(0006, _O, time);
+    FileTimeToMsecTime(&time, &info->ftLastWriteTime);
+    SET_IFIELD_J(0007, _O, time);
+    FileTimeToMsecTime(&time, &info->ftCreationTime);
+    SET_IFIELD_J(0008, _O, time);
+    u.LowPart  = info->nFileIndexLow;
+    u.HighPart = info->nFileIndexHigh;
+    u.QuadPart += ((UINT64)info->dwVolumeSerialNumber << 30);
+    SET_IFIELD_J(0011, _O, u.QuadPart);
+    SET_IFIELD_J(0012, _O, info->dwVolumeSerialNumber);
+
+}
+
+extern PSID acr_everyone_sid;
+
+/* Left bit shifts from World scope to given scope */
+typedef enum prot_scope_e {
+    prot_scope_world = 0,
+    prot_scope_group = 4,
+    prot_scope_user =  8
+} prot_scope_e;
+
+static int convert_prot(ACCESS_MASK acc, prot_scope_e scope)
+{
+    /* These choices are based on the single filesystem bit that controls
+     * the given behavior.  They are -not- recommended for any set protection
+     * function, such a function should -set- use GENERIC_READ/WRITE/EXECUTE
+     */
+    int prot = 0;
+    if (acc & FILE_EXECUTE)
+        prot |= ACR_FPROT_WEXECUTE;
+    if (acc & FILE_WRITE_DATA)
+        prot |= ACR_FPROT_WWRITE;
+    if (acc & FILE_READ_DATA)
+        prot |= ACR_FPROT_WREAD;
+    return (prot << scope);
+}
+
+static int resolve_prot(PSID user, PSID group, PACL dacl)
+{
+    TRUSTEE_W ident = { NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID };
+    ACCESS_MASK acc;
+    int protection = 0;
+    /*
+     * This function is only invoked for WinNT,
+     * there is no reason for os_level testing here.
+     */
+    if (user) {
+        ident.TrusteeType = TRUSTEE_IS_USER;
+        ident.ptstrName = user;
+        /* GetEffectiveRightsFromAcl isn't supported under Win9x,
+         * which shouldn't come as a surprize.  Since we are passing
+         * TRUSTEE_IS_SID, always skip the A->W layer.
+         */
+        if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) {
+            protection |= convert_prot(acc, prot_scope_user);
+        }
+    }
+    /* Windows NT: did not return group rights.
+     * Windows 2000 returns group rights information.
+     * Since WinNT kernels don't follow the unix model of
+     * group associations, this all all pretty mute.
+     */
+    if (group) {
+        ident.TrusteeType = TRUSTEE_IS_GROUP;
+        ident.ptstrName = group;
+        if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) {
+            protection |= convert_prot(acc, prot_scope_group);
+        }
+    }
+    if (acr_everyone_sid) {
+        ident.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+        ident.ptstrName = acr_everyone_sid;
+        if (GetEffectiveRightsFromAclW(dacl, &ident, &acc) == ERROR_SUCCESS) {
+            protection |= convert_prot(acc, prot_scope_world);
+        }
+    }
+    return protection;
+}
+
+static int _fill1(ACR_JNISTDARGS, HANDLE ih, DWORD attrs, jboolean full)
+{
+    int  rc;
+    int  prot;
+    PSID usr = NULL;
+    PSID grp = NULL;
+    PACL acl = NULL;
+    SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
+    PSECURITY_DESCRIPTOR sd = NULL;
+
+    if (full)
+        si |= (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
+    rc = GetSecurityInfo(ih,
+                         SE_FILE_OBJECT,
+                         si,
+                         full ? &usr : NULL,
+                         full ? &grp : NULL,
+                         &acl,
+                         NULL,
+                         &sd);
+    if (rc != ERROR_SUCCESS) {
+        return rc;
+    }
+    if (full) {
+        SET_IFIELD_O(0001, _O, ACR_UserObjectCreateFromId(_E,  usr));
+        SET_IFIELD_O(0002, _O, ACR_GroupObjectCreateFromId(_E, grp));
+    }
+    prot = resolve_prot(usr, grp, acl);
+    if (attrs & FILE_ATTRIBUTE_READONLY) {
+        /* Clear any WRITE attributes */
+        prot &= ~ACR_FPROT_UWRITE;
+        prot &= ~ACR_FPROT_GWRITE;
+        prot &= ~ACR_FPROT_WWRITE;
+    }
+    if (attrs & FILE_ATTRIBUTE_HIDDEN) {
+        /* XXX: Hidden files are non-executable? */
+        prot &= ~ACR_FPROT_UEXECUTE;
+        prot &= ~ACR_FPROT_GEXECUTE;
+        prot &= ~ACR_FPROT_WEXECUTE;
+    }
+    SET_IFIELD_I(0000, _O, prot);
+
+    LocalFree(sd);
+    return 0;
+}
+
+static int _ftype0(DWORD attrs)
+{
+    int type = ACR_FT_REG;
+
+    if (attrs & FILE_ATTRIBUTE_DIRECTORY)
+        type = ACR_FT_DIR;
+    else if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
+        type = ACR_FT_LNK;
+    else if (attrs & FILE_ATTRIBUTE_DEVICE)
+        type = ACR_FT_CHR;
+    return type;
+}
+
+static jobject _stat0(JNIEnv *_E, const wchar_t *fname,
+                      jboolean link, jboolean full)
+{
+    jobject fi;
+    BY_HANDLE_FILE_INFORMATION info;
+    HANDLE ih;
+    int    rc = 0;
+    int    type;
+
+    ih = CreateFileW(fname,
+                     0, /* Query attributes without accessing the file */
+                     FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                     NULL,
+                     OPEN_EXISTING,
+                     FILE_FLAG_BACKUP_SEMANTICS,
+                     NULL);
+    if (IS_INVALID_HANDLE(ih)) {
+        ACR_THROW_IO_ERRNO();
+        return NULL;
+    }
+    if (!GetFileInformationByHandle(ih, &info)) {
+        rc = ACR_GET_OS_ERROR();
+        goto finally;
+    }
+    type = _ftype0(info.dwFileAttributes);
+
+    fi = (*_E)->NewObject(_E, _clazzn.i, J4MID(0000), type);
+    if (!fi) {
+        CloseHandle(ih);
+        return NULL;
+    }
+    if (full) {
+        /* Resolve full path name
+         */
+        wchar_t *path;
+        wchar_t *name = acr_GetAbsolutePath(_E, ih, fname);
+        SET_IFIELD_W(0009, fi, name);
+        if ((path = wcsrchr(name, L'\\')))
+            SET_IFIELD_W(0010, fi, path);
+        else {
+            if ((path = wcsrchr(name, L'/')))
+                SET_IFIELD_W(0010, fi, path);
+            else
+                SET_IFIELD_W(0010, fi, name);
+        }
+        x_free(name);
+    }
+    _fill0(_E, fi, &info);
+    rc = _fill1(_E, fi, ih, info.dwFileAttributes, full);
+
+finally:
+    CloseHandle(ih);
+    if (rc) {
+        ACR_THROW_IO_IF_ERR(rc);
+        fi = NULL;
+    }
+    return fi;
+}
+
+static jobject _stat1(JNIEnv *_E, int file, jboolean full)
+{
+    jobject fi;
+    BY_HANDLE_FILE_INFORMATION info;
+    int    rc = 0;
+    int    type;
+    acr_file_t *f = (acr_file_t *)ACR_IOH_FDATA(file);
+
+    if (ACR_IOH_FTYPE(file) != ACR_DT_FILE) {
+        ACR_THROW_IO_IF_ERR(ACR_EFTYPE);
+        return NULL;
+    }
+    if (IS_INVALID_HANDLE(f)) {
+        ACR_THROW_IO_IF_ERR(ACR_EBADF);
+        return NULL;
+    }
+
+
+    if (!GetFileInformationByHandle(f->fd, &info)) {
+        rc = ACR_GET_OS_ERROR();
+        goto finally;
+    }
+    type = _ftype0(info.dwFileAttributes);
+
+    fi = (*_E)->NewObject(_E, _clazzn.i, J4MID(0000), type);
+    if (!fi) {
+        return NULL;
+    }
+    if (full) {
+        /* Resolve base name
+         */
+        wchar_t *path;
+        SET_IFIELD_W(0009, fi, f->name);
+        if ((path = wcsrchr(f->name, L'\\')))
+            SET_IFIELD_W(0010, fi, path + 1);
+        else {
+            if ((path = wcsrchr(f->name, L'/')))
+                SET_IFIELD_W(0010, fi, path + 1);
+            else
+                SET_IFIELD_W(0010, fi, f->name);
+        }
+    }
+    _fill0(_E, fi, &info);
+    rc = _fill1(_E, fi, f->fd, info.dwFileAttributes, full);
+
+finally:
+    if (rc) {
+        ACR_THROW_IO_IF_ERR(rc);
+        fi = NULL;
+    }
+    return fi;
+}
+
+static int _stat2(ACR_JNISTDARGS, const wchar_t *fname, jboolean link)
+{
+    BY_HANDLE_FILE_INFORMATION info;
+    HANDLE ih;
+    int    rc = 0;
+
+    ih = CreateFileW(fname,
+                     0, /* Query attributes without accessing the file */
+                     FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                     NULL,
+                     OPEN_EXISTING,
+                     FILE_FLAG_BACKUP_SEMANTICS,
+                     NULL);
+    if (IS_INVALID_HANDLE(ih)) {
+        return ACR_GET_OS_ERROR();
+    }
+    if (!GetFileInformationByHandle(ih, &info)) {
+        rc = ACR_GET_OS_ERROR();
+        goto finally;
+    }
+    CALL_VMETHOD1(0002, _O, _ftype0(info.dwFileAttributes));
+    _fill0(_E, _O, &info);
+    rc = _fill1(_E, _O, ih, info.dwFileAttributes, JNI_TRUE);
+
+finally:
+    CloseHandle(ih);
+    return rc;
+}
+
+
+ACR_IO_EXPORT_DECLARE(jobject, File, stat0)(ACR_JNISTDARGS,
+                                            jstring fname,
+                                            jboolean link,
+                                            jboolean full)
+{
+    jobject fi = NULL;
+    WITH_WSTR(fname) {
+        fi = _stat0(_E, J2W(fname), link, full);
+    } END_WITH_WSTR(fname);
+
+    return fi;
+}
+
+
+ACR_IO_EXPORT_DECLARE(jint, FileInfo, stat0)(ACR_JNISTDARGS,
+                                             jstring fname,
+                                             jboolean link)
+{
+    int rc = 0;
+    WITH_WSTR(fname) {
+        rc = _stat2(_E, _O, J2W(fname), link);
+    } END_WITH_WSTR(fname);
+
+    return rc;
+}
+
+ACR_IO_EXPORT_DECLARE(jobject, FileWrapper, stat0)(ACR_JNISTDARGS,
+                                                   jint fd,
+                                                   jboolean full)
+{
+    return  _stat1(_E, fd, full);
+}