diff options
| author | ruki <[email protected]> | 2018-09-29 19:10:13 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2018-09-29 19:10:13 +0800 |
| commit | 2f283df97b8527cc69c3139efec7ad27a6851611 (patch) | |
| tree | b9cf0d0c6c85408e44aeadbe244656f359da9c9f | |
| parent | 5ab49e216d230bcced6b2884f19a70260019bfb3 (diff) | |
improve to create symlink
4 files changed, 158 insertions, 58 deletions
diff --git a/core/src/tbox/src/tbox/platform/posix/file.c b/core/src/tbox/src/tbox/platform/posix/file.c index 7c67a3566..bc592e54d 100644 --- a/core/src/tbox/src/tbox/platform/posix/file.c +++ b/core/src/tbox/src/tbox/platform/posix/file.c @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright (C) 2009 - 2017, TBOOX Open Source Group. + * Copyright (C) 2009 - 2018, TBOOX Open Source Group. * * @author ruki * @file file.c @@ -73,11 +73,6 @@ tb_file_ref_t tb_file_init(tb_char_t const* path, tb_size_t mode) if (mode & TB_FILE_MODE_DIRECT) flags |= O_DIRECT; #endif - // for native aio aicp -#if defined(TB_CONFIG_ASIO_HAVE_NAIO) - if (mode & TB_FILE_MODE_ASIO) flags |= O_DIRECT; -#endif - // noblock flags |= O_NONBLOCK; @@ -93,10 +88,12 @@ tb_file_ref_t tb_file_init(tb_char_t const* path, tb_size_t mode) tb_long_t fd = open(path, flags, modes); if (fd < 0 && (mode & TB_FILE_MODE_CREAT)) { +#ifndef TB_CONFIG_MICRO_ENABLE // open it again after creating the file directory tb_char_t dir[TB_PATH_MAXN]; if (tb_directory_create(tb_path_directory(path, dir, sizeof(dir)))) fd = open(path, flags, modes); +#endif } // trace @@ -561,8 +558,16 @@ tb_bool_t tb_file_rename(tb_char_t const* path, tb_char_t const* dest) dest = tb_path_absolute(dest, full1, TB_PATH_MAXN); tb_assert_and_check_return_val(dest, tb_false); - // rename - return !rename(path, dest)? tb_true : tb_false; + // attempt to rename it directly + if (!rename(path, dest)) return tb_true; + else + { + // attempt to rename it again after creating directory + tb_char_t dir[TB_PATH_MAXN]; + if (tb_directory_create(tb_path_directory(dest, dir, sizeof(dir)))) + return !rename(path, dest); + } + return tb_false; } tb_bool_t tb_file_link(tb_char_t const* path, tb_char_t const* dest) { @@ -579,7 +584,15 @@ tb_bool_t tb_file_link(tb_char_t const* path, tb_char_t const* dest) dest = tb_path_absolute(dest, full1, TB_PATH_MAXN); tb_assert_and_check_return_val(dest, tb_false); - // symlink - return !symlink(path, dest)? tb_true : tb_false; + // attempt to link it directly + if (!symlink(path, dest)) return tb_true; + else + { + // attempt to link it again after creating directory + tb_char_t dir[TB_PATH_MAXN]; + if (tb_directory_create(tb_path_directory(dest, dir, sizeof(dir)))) + return !symlink(path, dest); + } + return tb_false; } #endif diff --git a/core/src/tbox/src/tbox/platform/windows/file.c b/core/src/tbox/src/tbox/platform/windows/file.c index 62ba7b86d..82e7e6db8 100644 --- a/core/src/tbox/src/tbox/platform/windows/file.c +++ b/core/src/tbox/src/tbox/platform/windows/file.c @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright (C) 2009 - 2017, TBOOX Open Source Group. + * Copyright (C) 2009 - 2018, TBOOX Open Source Group. * * @author ruki * @file file.c @@ -33,6 +33,17 @@ #include "interface/interface.h" /* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2) +#endif + +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +# define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1) +#endif + +/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t tb_file_mkdir(tb_wchar_t const* path) @@ -99,7 +110,6 @@ tb_file_ref_t tb_file_init(tb_char_t const* path, tb_size_t mode) // init attr DWORD attr = FILE_ATTRIBUTE_NORMAL; - if (mode & TB_FILE_MODE_ASIO) attr |= FILE_FLAG_OVERLAPPED; if (mode & TB_FILE_MODE_DIRECT) attr |= FILE_FLAG_NO_BUFFERING; // init file @@ -137,7 +147,7 @@ tb_bool_t tb_file_exit(tb_file_ref_t file) tb_assert_and_check_return_val(file, tb_false); // close it - return CloseHandle(file)? tb_true : tb_false; + return CloseHandle((HANDLE)file)? tb_true : tb_false; } tb_long_t tb_file_read(tb_file_ref_t file, tb_byte_t* data, tb_size_t size) { @@ -149,7 +159,7 @@ tb_long_t tb_file_read(tb_file_ref_t file, tb_byte_t* data, tb_size_t size) // read DWORD real_size = 0; - return ReadFile(file, data, (DWORD)size, &real_size, tb_null)? (tb_long_t)real_size : -1; + return ReadFile((HANDLE)file, data, (DWORD)size, &real_size, tb_null)? (tb_long_t)real_size : -1; } tb_long_t tb_file_writ(tb_file_ref_t file, tb_byte_t const* data, tb_size_t size) { @@ -161,7 +171,7 @@ tb_long_t tb_file_writ(tb_file_ref_t file, tb_byte_t const* data, tb_size_t size // writ DWORD real_size = 0; - return WriteFile(file, data, (DWORD)size, &real_size, tb_null)? (tb_long_t)real_size : -1; + return WriteFile((HANDLE)file, data, (DWORD)size, &real_size, tb_null)? (tb_long_t)real_size : -1; } tb_long_t tb_file_pread(tb_file_ref_t file, tb_byte_t* data, tb_size_t size, tb_hize_t offset) { @@ -351,7 +361,7 @@ tb_bool_t tb_file_sync(tb_file_ref_t file) tb_assert_and_check_return_val(file, tb_false); // sync it - return FlushFileBuffers(file)? tb_true : tb_false; + return FlushFileBuffers((HANDLE)file)? tb_true : tb_false; } tb_hong_t tb_file_seek(tb_file_ref_t file, tb_hong_t offset, tb_size_t mode) { @@ -362,7 +372,7 @@ tb_hong_t tb_file_seek(tb_file_ref_t file, tb_hong_t offset, tb_size_t mode) LARGE_INTEGER o = {{0}}; LARGE_INTEGER p = {{0}}; o.QuadPart = (LONGLONG)offset; - return SetFilePointerEx(file, o, &p, (DWORD)mode)? (tb_hong_t)p.QuadPart : -1; + return SetFilePointerEx((HANDLE)file, o, &p, (DWORD)mode)? (tb_hong_t)p.QuadPart : -1; } tb_hong_t tb_file_offset(tb_file_ref_t file) { @@ -383,7 +393,7 @@ tb_hize_t tb_file_size(tb_file_ref_t file) // the file size LARGE_INTEGER p = {{0}}; - return pGetFileSizeEx(file, &p)? (tb_hong_t)p.QuadPart : 0; + return pGetFileSizeEx((HANDLE)file, &p)? (tb_hong_t)p.QuadPart : 0; } tb_bool_t tb_file_info(tb_char_t const* path, tb_file_info_t* info) { @@ -504,10 +514,17 @@ tb_bool_t tb_file_rename(tb_char_t const* path, tb_char_t const* dest) } tb_bool_t tb_file_link(tb_char_t const* path, tb_char_t const* dest) { -#if 0 // check tb_assert_and_check_return_val(path && dest, tb_false); + // support symbolic link? >= vista + tb_kernel32_CreateSymbolicLinkW_t pCreateSymbolicLinkW = tb_kernel32()->CreateSymbolicLinkW; + tb_check_return_val(pCreateSymbolicLinkW, tb_false); + + // not exists? + tb_file_info_t info = {0}; + if (!tb_file_info(path, &info)) return tb_false; + // the full path tb_wchar_t full0[TB_PATH_MAXN]; if (!tb_path_absolute_w(path, full0, TB_PATH_MAXN)) return tb_false; @@ -516,14 +533,14 @@ tb_bool_t tb_file_link(tb_char_t const* path, tb_char_t const* dest) tb_wchar_t full1[TB_PATH_MAXN]; if (!tb_path_absolute_w(dest, full1, TB_PATH_MAXN)) return tb_false; - // not exists? - tb_file_info_t info = {0}; - if (!tb_file_info(full0, &info)) return tb_false; + // make directory + tb_file_mkdir(full1); - // symlink, supported: >= vista - return !CreateSymbolicLinkW(full1, full0, info.bdir? SYMBOLIC_LINK_FLAG_DIRECTORY : 0)? tb_true : tb_false; -#else - tb_trace_noimpl(); - return tb_false; -#endif + // attempt to link it directly without admin privilege. + tb_bool_t isdir = (info.type == TB_FILE_TYPE_DIRECTORY); + if (pCreateSymbolicLinkW(full1, full0, (isdir? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) + return tb_true; + + // attempt to link it directly with admin privilege + return (tb_bool_t)pCreateSymbolicLinkW(full1, full0, isdir? SYMBOLIC_LINK_FLAG_DIRECTORY : 0); } diff --git a/core/src/tbox/src/tbox/platform/windows/interface/kernel32.c b/core/src/tbox/src/tbox/platform/windows/interface/kernel32.c index 8c0821b18..26d257814 100644 --- a/core/src/tbox/src/tbox/platform/windows/interface/kernel32.c +++ b/core/src/tbox/src/tbox/platform/windows/interface/kernel32.c @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright (C) 2009 - 2017, TBOOX Open Source Group. + * Copyright (C) 2009 - 2018, TBOOX Open Source Group. * * @author ruki * @file kernel32.c @@ -27,6 +27,7 @@ * includes */ #include "kernel32.h" +#include "ws2_32.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation @@ -39,11 +40,10 @@ static tb_bool_t tb_kernel32_instance_init(tb_handle_t instance, tb_cpointer_t p // the kernel32 module HANDLE module = GetModuleHandleA("kernel32.dll"); - if (!module) module = tb_dynamic_init("kernel32.dll"); + if (!module) module = (HANDLE)tb_dynamic_init("kernel32.dll"); tb_assert_and_check_return_val(module, tb_false); // init interfaces -// TB_INTERFACE_LOAD(kernel32, CancelIoEx); TB_INTERFACE_LOAD(kernel32, RtlCaptureStackBackTrace); TB_INTERFACE_LOAD(kernel32, GetFileSizeEx); TB_INTERFACE_LOAD(kernel32, GetQueuedCompletionStatusEx); @@ -51,7 +51,6 @@ static tb_bool_t tb_kernel32_instance_init(tb_handle_t instance, tb_cpointer_t p TB_INTERFACE_LOAD(kernel32, GetEnvironmentVariableW); TB_INTERFACE_LOAD(kernel32, SetEnvironmentVariableW); TB_INTERFACE_LOAD(kernel32, CreateProcessW); - TB_INTERFACE_LOAD(kernel32, CloseHandle); TB_INTERFACE_LOAD(kernel32, WaitForSingleObject); TB_INTERFACE_LOAD(kernel32, WaitForMultipleObjects); TB_INTERFACE_LOAD(kernel32, GetExitCodeProcess); @@ -61,6 +60,8 @@ static tb_bool_t tb_kernel32_instance_init(tb_handle_t instance, tb_cpointer_t p TB_INTERFACE_LOAD(kernel32, GetEnvironmentStringsW); TB_INTERFACE_LOAD(kernel32, FreeEnvironmentStringsW); TB_INTERFACE_LOAD(kernel32, SetHandleInformation); + TB_INTERFACE_LOAD(kernel32, SetFileCompletionNotificationModes); + TB_INTERFACE_LOAD(kernel32, CreateSymbolicLinkW); // ok return tb_true; @@ -82,3 +83,49 @@ tb_kernel32_ref_t tb_kernel32() // ok return &s_kernel32; } +tb_bool_t tb_kernel32_has_SetFileCompletionNotificationModes() +{ + static tb_long_t s_ok = 0; + if (!s_ok) + { + LPWSAPROTOCOL_INFOW lpProtocolInfo = tb_null; + do + { + // no this interface? + if (!tb_kernel32()->SetFileCompletionNotificationModes) + break; + + // allocate a 16K buffer to retrieve all the protocol providers + DWORD dwBufferLen = 16384; + lpProtocolInfo = (LPWSAPROTOCOL_INFOW)tb_malloc(dwBufferLen); + tb_assert_and_check_break(lpProtocolInfo); + + // get protocol info + tb_int_t iNuminfo = tb_ws2_32()->WSAEnumProtocolsW(tb_null, lpProtocolInfo, &dwBufferLen); + tb_check_break(iNuminfo != SOCKET_ERROR); + + // has XP1_IFS_HANDLES? see https://support.microsoft.com/kb/2568167 for details + tb_int_t i = 0; + for (i = 0; i < iNuminfo; i++) + { + if (!(lpProtocolInfo[i].dwServiceFlags1 & XP1_IFS_HANDLES)) + break; + } + tb_check_break(i == iNuminfo); + + // ok + s_ok = 1; + + } while (0); + + // free protocol info + if (lpProtocolInfo) tb_free(lpProtocolInfo); + lpProtocolInfo = tb_null; + + // failed + if (!s_ok) s_ok = -1; + } + + // ok? + return s_ok == 1; +} diff --git a/core/src/tbox/src/tbox/platform/windows/interface/kernel32.h b/core/src/tbox/src/tbox/platform/windows/interface/kernel32.h index 14b1a3a39..873a67da6 100644 --- a/core/src/tbox/src/tbox/platform/windows/interface/kernel32.h +++ b/core/src/tbox/src/tbox/platform/windows/interface/kernel32.h @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright (C) 2009 - 2017, TBOOX Open Source Group. + * Copyright (C) 2009 - 2018, TBOOX Open Source Group. * * @author ruki * @file kernel32.h @@ -73,9 +73,6 @@ typedef BOOL (WINAPI* tb_kernel32_SetEnvironmentVariableW_t)(LPCWSTR lpName, LPC // the CreateProcessW func type typedef BOOL (WINAPI* tb_kernel32_CreateProcessW_t)(LPCWSTR lpApplicationName, LPCWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); -// the CloseHandle func type -typedef BOOL (WINAPI* tb_kernel32_CloseHandle_t)(HANDLE hObject); - // the WaitForSingleObject func type typedef DWORD (WINAPI* tb_kernel32_WaitForSingleObject_t)(HANDLE hHandle, DWORD dwMilliseconds); @@ -103,62 +100,68 @@ typedef DWORD (WINAPI* tb_kernel32_FreeEnvironmentStringsW_t)(LPWCH lpszEnvironm // the SetHandleInformation func type typedef BOOL (WINAPI* tb_kernel32_SetHandleInformation_t)(HANDLE hObject, DWORD dwMask, DWORD dwFlags); +// the SetFileCompletionNotificationModes func type +typedef BOOL (WINAPI* tb_kernel32_SetFileCompletionNotificationModes_t)(HANDLE FileHandle, UCHAR Flags); + +// the CreateSymbolicLinkW func type +typedef BOOLEAN (WINAPI* tb_kernel32_CreateSymbolicLinkW_t)(LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags); + // the kernel32 interfaces type typedef struct __tb_kernel32_t { - // CancelIoEx -// tb_kernel32_CancelIoEx_t CancelIoEx; - // CaptureStackBackTrace - tb_kernel32_RtlCaptureStackBackTrace_t RtlCaptureStackBackTrace; + tb_kernel32_RtlCaptureStackBackTrace_t RtlCaptureStackBackTrace; // GetFileSizeEx - tb_kernel32_GetFileSizeEx_t GetFileSizeEx; + tb_kernel32_GetFileSizeEx_t GetFileSizeEx; // GetQueuedCompletionStatusEx - tb_kernel32_GetQueuedCompletionStatusEx_t GetQueuedCompletionStatusEx; + tb_kernel32_GetQueuedCompletionStatusEx_t GetQueuedCompletionStatusEx; // InterlockedCompareExchange64 - tb_kernel32_InterlockedCompareExchange64_t InterlockedCompareExchange64; + tb_kernel32_InterlockedCompareExchange64_t InterlockedCompareExchange64; // GetEnvironmentVariableW - tb_kernel32_GetEnvironmentVariableW_t GetEnvironmentVariableW; + tb_kernel32_GetEnvironmentVariableW_t GetEnvironmentVariableW; // SetEnvironmentVariableW - tb_kernel32_SetEnvironmentVariableW_t SetEnvironmentVariableW; + tb_kernel32_SetEnvironmentVariableW_t SetEnvironmentVariableW; // CreateProcessW - tb_kernel32_CreateProcessW_t CreateProcessW; - - // CloseHandle - tb_kernel32_CloseHandle_t CloseHandle; + tb_kernel32_CreateProcessW_t CreateProcessW; // WaitForSingleObject - tb_kernel32_WaitForSingleObject_t WaitForSingleObject; + tb_kernel32_WaitForSingleObject_t WaitForSingleObject; // WaitForMultipleObjects - tb_kernel32_WaitForMultipleObjects_t WaitForMultipleObjects; + tb_kernel32_WaitForMultipleObjects_t WaitForMultipleObjects; // GetExitCodeProcess - tb_kernel32_GetExitCodeProcess_t GetExitCodeProcess; + tb_kernel32_GetExitCodeProcess_t GetExitCodeProcess; // TerminateProcess - tb_kernel32_TerminateProcess_t TerminateProcess; + tb_kernel32_TerminateProcess_t TerminateProcess; // SuspendThread - tb_kernel32_SuspendThread_t SuspendThread; + tb_kernel32_SuspendThread_t SuspendThread; // ResumeThread - tb_kernel32_ResumeThread_t ResumeThread; + tb_kernel32_ResumeThread_t ResumeThread; // GetEnvironmentStringsW - tb_kernel32_GetEnvironmentStringsW_t GetEnvironmentStringsW; + tb_kernel32_GetEnvironmentStringsW_t GetEnvironmentStringsW; // FreeEnvironmentStringsW - tb_kernel32_FreeEnvironmentStringsW_t FreeEnvironmentStringsW; + tb_kernel32_FreeEnvironmentStringsW_t FreeEnvironmentStringsW; // SetHandleInformation - tb_kernel32_SetHandleInformation_t SetHandleInformation; + tb_kernel32_SetHandleInformation_t SetHandleInformation; + + // SetFileCompletionNotificationModes + tb_kernel32_SetFileCompletionNotificationModes_t SetFileCompletionNotificationModes; + + // CreateSymbolicLinkW + tb_kernel32_CreateSymbolicLinkW_t CreateSymbolicLinkW; }tb_kernel32_t, *tb_kernel32_ref_t; @@ -172,6 +175,26 @@ typedef struct __tb_kernel32_t */ tb_kernel32_ref_t tb_kernel32(tb_noarg_t); +/* has SetFileCompletionNotificationModes? + * + * Verifies that SetFileCompletionNotificationModes Windows API is present on the system + * and is safe to use. + * + * We can uses the SetFileCompletionNotificationModes Windows API to skip calling GetQueuedCompletionStatus + * if an IO operation completes synchronously. + * + * There is a known bug where SetFileCompletionNotificationModes crashes on some systems + * (see https://support.microsoft.com/kb/2568167 for details). + * + * It's not safe to skip completion notifications for UDP: + * https://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx + * + * So we can only use it to skip tcp completion notifications. + * + * @return tb_true or tb_false + */ +tb_bool_t tb_kernel32_has_SetFileCompletionNotificationModes(); + /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ |
