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);