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/05/20 17:35:40 UTC

svn commit: r776738 - /commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c

Author: mturk
Date: Wed May 20 15:35:40 2009
New Revision: 776738

URL: http://svn.apache.org/viewvc?rev=776738&view=rev
Log:
Implement Windows XP symlinks -- directories only

Modified:
    commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c?rev=776738&r1=776737&r2=776738&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c Wed May 20 15:35:40 2009
@@ -109,27 +109,111 @@
     jboolean rc = JNI_FALSE;
 
     UNREFERENCED_O;
-    if (!ACR_HAVE_LATE_DLL_FUNC(CreateSymbolicLinkW)) {
-        ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENOTIMPL, 0);
-        return JNI_FALSE;
-    }
+
     WITH_WSTR(target) {
     WITH_WSTR(lnkname) {
-        DWORD dwFlags = 0;
+        char  *mpb = NULL;
+        DWORD  dwFlags = 0;
         size_t tlen = wcslen(J2W(target));
-        if (tlen > 0 && J2W(target)[tlen - 1] == L'\\')
+
+        if (ACR_FileTypeGet(NULL, J2W(target)) == ACR_FT_DIR) {
             dwFlags = SYMBOLIC_LINK_FLAG_DIRECTORORY;
-        if (!CreateSymbolicLinkW(J2W(lnkname), J2W(target), dwFlags)) {
-            int err = ACR_GET_OS_ERROR();
-            if (ACR_STATUS_IS_EACCES(err)) {
-                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ESECURITY, 0);
+        }
+        else if (tlen > 0 && (J2W(target)[tlen - 1 ] == L'\\' ||
+                              J2W(target)[tlen - 1 ] == L'/')) {
+            dwFlags = SYMBOLIC_LINK_FLAG_DIRECTORORY;
+        }
+        if (ACR_HAVE_LATE_DLL_FUNC(CreateSymbolicLinkW)) {
+            if (!CreateSymbolicLinkW(J2W(lnkname), J2W(target), dwFlags)) {
+                int err = ACR_GET_OS_ERROR();
+                if (ACR_STATUS_IS_EACCES(err)) {
+                    ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ESECURITY, 0);
+                }
+                else if (!ACR_STATUS_IS_EEXIST(err)) {
+                    ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO, err);
+                }
             }
-            else if (!ACR_STATUS_IS_EEXIST(err)) {
-                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO, err);
+            else
+                rc = JNI_TRUE;
+        }
+        else if (dwFlags ==  SYMBOLIC_LINK_FLAG_DIRECTORORY) {
+            HANDLE token = NULL;
+            HANDLE hlink = INVALID_HANDLE_VALUE;
+            PREPARSE_DATA_BUFFER rdb;
+            DWORD dlen;
+            wchar_t fpath[ACR_HBUFF_SIZ];
+
+            mpb = ACR_Calloc(_E, THROW_FMARK,
+                             MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+            if (!mpb) {
+                goto bailout;
             }
+            if (!GetFullPathNameW(J2W(target), ACR_HBUFF_LEN,  fpath, NULL)) {
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO,
+                                   ACR_GET_OS_ERROR());
+                goto bailout;
+            }
+            tlen = wcslen(fpath);
+            if (tlen > 0 && fpath[tlen - 1] == L'\\') {
+                fpath[--tlen] = L'\0';
+            }
+
+            if (!CreateDirectoryW(J2W(lnkname), NULL)) {
+                /* Failed to create link name directory */
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO,
+                                   ACR_GET_OS_ERROR());
+                goto bailout;
+            }
+            if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) {
+                TOKEN_PRIVILEGES tp;
+                if (LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid)) {
+                    tp.PrivilegeCount = 1;
+                    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+                    AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
+                                          NULL, NULL);
+                }
+                CloseHandle(token);
+            }
+            hlink = CreateFileW(J2W(lnkname),
+                                GENERIC_WRITE,
+                                0,
+                                NULL,
+                                OPEN_EXISTING,
+                                FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+                                NULL);
+            if (hlink == INVALID_HANDLE_VALUE) {
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO,
+                                   ACR_GET_OS_ERROR());
+                goto bailout;
+            }
+            rdb = (PREPARSE_DATA_BUFFER)mpb;
+            rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+
+            wcscpy(rdb->MountPointReparseBuffer.PathBuffer, L"\\??\\");
+            wcscat(rdb->MountPointReparseBuffer.PathBuffer, fpath);
+            tlen = wcslen(rdb->MountPointReparseBuffer.PathBuffer);
+
+            rdb->MountPointReparseBuffer.SubstituteNameLength = tlen  * sizeof(wchar_t);
+            rdb->MountPointReparseBuffer.PrintNameOffset = (tlen + 1) * sizeof(wchar_t);
+            rdb->ReparseDataLength = sizeof(rdb->MountPointReparseBuffer) + ((tlen + 1) * sizeof(wchar_t));
+
+            if (!DeviceIoControl(hlink, FSCTL_SET_REPARSE_POINT,
+                                 rdb, rdb->ReparseDataLength + 8,
+                                 NULL, 0, &dlen, NULL)) {
+                ACR_ThrowException(_E, THROW_NMARK, ACR_EX_EIO,
+                                   ACR_GET_OS_ERROR());
+            }
+            else {
+                rc = JNI_TRUE;
+            }
+            CloseHandle(hlink);
         }
-        else
-            rc = JNI_TRUE;
+        else {
+            ACR_ThrowException(_E, THROW_NMARK, ACR_EX_ENOTIMPL, 0);
+        }
+        bailout:
+        if (mpb)
+            free(mpb);
     } END_WITH_WSTR(lnkname);
     } END_WITH_WSTR(target);