summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2018-09-29 19:10:13 +0800
committerruki <[email protected]>2018-09-29 19:10:13 +0800
commit2f283df97b8527cc69c3139efec7ad27a6851611 (patch)
treeb9cf0d0c6c85408e44aeadbe244656f359da9c9f
parent5ab49e216d230bcced6b2884f19a70260019bfb3 (diff)
improve to create symlink
-rw-r--r--core/src/tbox/src/tbox/platform/posix/file.c33
-rw-r--r--core/src/tbox/src/tbox/platform/windows/file.c53
-rw-r--r--core/src/tbox/src/tbox/platform/windows/interface/kernel32.c55
-rw-r--r--core/src/tbox/src/tbox/platform/windows/interface/kernel32.h75
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
*/