diff options
Diffstat (limited to 'src/pmdk/src/libpmem2/usc_windows.c')
-rw-r--r-- | src/pmdk/src/libpmem2/usc_windows.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/src/pmdk/src/libpmem2/usc_windows.c b/src/pmdk/src/libpmem2/usc_windows.c new file mode 100644 index 000000000..1a949bc2e --- /dev/null +++ b/src/pmdk/src/libpmem2/usc_windows.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2020, Intel Corporation */ + +/* + * usc_windows.c -- pmem2 usc function for windows + */ + +#include "alloc.h" +#include "source.h" +#include "out.h" +#include "libpmem2.h" +#include "pmem2_utils.h" +#define GUID_SIZE sizeof("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") +#define VOLUME_PATH_SIZE sizeof("\\\\?\\Volume{}") + (GUID_SIZE - 2 /* \0 */) + +/* + * get_volume_handle -- returns volume handle + */ +static int +get_volume_handle(HANDLE handle, HANDLE *volume_handle) +{ + wchar_t *volume; + wchar_t tmp[10]; + DWORD len = + GetFinalPathNameByHandleW(handle, tmp, 10, VOLUME_NAME_GUID); + + if (len == 0) { + ERR("!!GetFinalPathNameByHandleW"); + return pmem2_lasterror_to_err(); + } + + len *= sizeof(wchar_t); + + int err; + volume = pmem2_malloc(len, &err); + if (volume == NULL) + return err; + + if (!GetFinalPathNameByHandleW(handle, volume, len, + VOLUME_NAME_GUID)) { + Free(volume); + ERR("!!GetFinalPathNameByHandleW"); + return pmem2_lasterror_to_err(); + } + + ASSERTeq(volume[VOLUME_PATH_SIZE], '\\'); + volume[VOLUME_PATH_SIZE] = '\0'; + + *volume_handle = CreateFileW(volume, /* path to the file */ + /* request access to send ioctl to the file */ + FILE_READ_ATTRIBUTES, + /* do not block access to the file */ + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, /* security attributes */ + OPEN_EXISTING, /* open only if it exists */ + FILE_ATTRIBUTE_NORMAL, /* no attributes */ + NULL); /* used only for new files */ + + Free(volume); + if (*volume_handle == INVALID_HANDLE_VALUE) { + ERR("!!CreateFileW"); + return pmem2_lasterror_to_err(); + } + + return 0; +} + +static int +get_device_guid(HANDLE handle, GUID *guid) +{ + HANDLE vHandle; + int ret = get_volume_handle(handle, &vHandle); + if (vHandle == INVALID_HANDLE_VALUE) + return ret; + + STORAGE_DEVICE_NUMBER_EX sdn; + sdn.DeviceNumber = -1; + DWORD dwBytesReturned = 0; + if (!DeviceIoControl(vHandle, + IOCTL_STORAGE_GET_DEVICE_NUMBER_EX, + NULL, 0, + &sdn, sizeof(sdn), + &dwBytesReturned, NULL)) { + /* + * IOCTL_STORAGE_GET_DEVICE_NUMBER_EX is not supported + * on this server + */ + ERR( + "Getting device id (IOCTL_STORAGE_GET_DEVICE_NUMBER_EX) is not supported on this system"); + CloseHandle(vHandle); + return PMEM2_E_NOSUPP; + } + *guid = sdn.DeviceGuid; + + CloseHandle(vHandle); + return 0; +} + +int +pmem2_source_device_idW(const struct pmem2_source *src, wchar_t *id, + size_t *len) +{ + PMEM2_ERR_CLR(); + + if (src->type == PMEM2_SOURCE_ANON) { + ERR("Anonymous source does not have device id"); + return PMEM2_E_NOSUPP; + } + + ASSERTeq(src->type, PMEM2_SOURCE_HANDLE); + + if (id == NULL) { + *len = GUID_SIZE * sizeof(*id); + return 0; + } + + if (*len < GUID_SIZE * sizeof(*id)) { + ERR("id buffer is to small"); + return PMEM2_E_BUFFER_TOO_SMALL; + } + + GUID guid; + int ret = get_device_guid(src->value.handle, &guid); + if (ret) + return ret; + + _snwprintf(id, GUID_SIZE, + L"%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", + guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], + guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], + guid.Data4[7]); + return 0; +} + +int +pmem2_source_device_idU(const struct pmem2_source *src, char *id, size_t *len) +{ + PMEM2_ERR_CLR(); + + if (src->type == PMEM2_SOURCE_ANON) { + ERR("Anonymous source does not have device id"); + return PMEM2_E_NOSUPP; + } + + ASSERTeq(src->type, PMEM2_SOURCE_HANDLE); + + if (id == NULL) { + *len = GUID_SIZE * sizeof(*id); + return 0; + } + if (*len < GUID_SIZE * sizeof(*id)) { + ERR("id buffer is to small"); + return PMEM2_E_BUFFER_TOO_SMALL; + } + + GUID guid; + int ret = get_device_guid(src->value.handle, &guid); + if (ret) + return ret; + + if (util_snprintf(id, GUID_SIZE, + "%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", + guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], + guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], + guid.Data4[7]) < 0) { + ERR("!snprintf"); + return PMEM2_E_ERRNO; + } + + return 0; +} + +int +pmem2_source_device_usc(const struct pmem2_source *src, uint64_t *usc) +{ + LOG(3, "cfg %p, usc %p", src, usc); + PMEM2_ERR_CLR(); + + if (src->type == PMEM2_SOURCE_ANON) { + ERR("Anonymous source does not support unsafe shutdown count"); + return PMEM2_E_NOSUPP; + } + + ASSERTeq(src->type, PMEM2_SOURCE_HANDLE); + + *usc = 0; + + HANDLE vHandle; + int err = get_volume_handle(src->value.handle, &vHandle); + if (vHandle == INVALID_HANDLE_VALUE) + return err; + + STORAGE_PROPERTY_QUERY prop; + DWORD dwSize; + prop.PropertyId = StorageDeviceUnsafeShutdownCount; + prop.QueryType = PropertyExistsQuery; + prop.AdditionalParameters[0] = 0; + STORAGE_DEVICE_UNSAFE_SHUTDOWN_COUNT ret; + + BOOL bResult = DeviceIoControl(vHandle, + IOCTL_STORAGE_QUERY_PROPERTY, + &prop, sizeof(prop), + &ret, sizeof(ret), + (LPDWORD)&dwSize, (LPOVERLAPPED)NULL); + + if (!bResult) { + ERR( + "Getting unsafe shutdown count is not supported on this system"); + CloseHandle(vHandle); + return PMEM2_E_NOSUPP; + } + prop.QueryType = PropertyStandardQuery; + bResult = DeviceIoControl(vHandle, + IOCTL_STORAGE_QUERY_PROPERTY, + &prop, sizeof(prop), + &ret, sizeof(ret), + (LPDWORD)&dwSize, (LPOVERLAPPED)NULL); + + CloseHandle(vHandle); + if (!bResult) { + ERR("!!DeviceIoControl"); + return pmem2_lasterror_to_err(); + } + + *usc = ret.UnsafeShutdownCount; + + return 0; +} |