mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-31 01:35:11 +02:00
Reworked Path Resolution Function
- Reworked resolved_path() into resolved_path_utf16() that combined utf16 conversion and path conditioning into a single function. This eliminated the previously non-threadsafe resolved_path() function. - Adjusted functions to use resolved_path_utf16(). - Collapsed copy_file() function that was only used once. - Corrected compilation errors when debug4() and debug5() are enabled.
This commit is contained in:
parent
c1aaa5d5a3
commit
bd6408058a
@ -439,10 +439,10 @@ fileio_open(const char *path_utf8, int flags, mode_t mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if opening null device, point to Windows equivalent */
|
/* if opening null device, point to Windows equivalent */
|
||||||
if (strncmp(path_utf8, NULL_DEVICE, strlen(NULL_DEVICE)+1) == 0)
|
if (strcmp(path_utf8, NULL_DEVICE) == 0)
|
||||||
path_utf8 = "NUL";
|
path_utf8 = NULL_DEVICE_WIN;
|
||||||
|
|
||||||
if ((path_utf16 = utf8_to_utf16(path_utf8)) == NULL) {
|
if ((path_utf16 = resolved_path_utf16(path_utf8)) == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
debug3("utf8_to_utf16 failed for file:%s error:%d", path_utf8, GetLastError());
|
debug3("utf8_to_utf16 failed for file:%s error:%d", path_utf8, GetLastError());
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -774,7 +774,7 @@ fileio_stat_or_lstat_internal(const char *path, struct _stat64 *buf, int do_lsta
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((wpath = utf8_to_utf16(path)) == NULL) {
|
if ((wpath = resolved_path_utf16(path)) == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
debug3("utf8_to_utf16 failed for file:%s error:%d", path, GetLastError());
|
debug3("utf8_to_utf16 failed for file:%s error:%d", path, GetLastError());
|
||||||
return -1;
|
return -1;
|
||||||
@ -1013,8 +1013,6 @@ fileio_readlink(const char *path, char *buf, size_t bufsiz)
|
|||||||
* for more info: https://msdn.microsoft.com/en-us/library/cc232006.aspx
|
* for more info: https://msdn.microsoft.com/en-us/library/cc232006.aspx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
debug4("readlink - io:%p", pio);
|
|
||||||
|
|
||||||
typedef struct _REPARSE_DATA_BUFFER_SYMLINK {
|
typedef struct _REPARSE_DATA_BUFFER_SYMLINK {
|
||||||
ULONG ReparseTag;
|
ULONG ReparseTag;
|
||||||
USHORT ReparseDataLength;
|
USHORT ReparseDataLength;
|
||||||
@ -1041,7 +1039,7 @@ fileio_readlink(const char *path, char *buf, size_t bufsiz)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((wpath = utf8_to_utf16(path)) == NULL) {
|
if ((wpath = resolved_path_utf16(path)) == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -1131,8 +1129,8 @@ fileio_symlink(const char *target, const char *linkpath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DWORD ret = 0;
|
DWORD ret = 0;
|
||||||
wchar_t *target_utf16 = utf8_to_utf16(resolved_path(target));
|
wchar_t *target_utf16 = resolved_path_utf16(target);
|
||||||
wchar_t *linkpath_utf16 = utf8_to_utf16(resolved_path(linkpath));
|
wchar_t *linkpath_utf16 = resolved_path_utf16(linkpath);
|
||||||
wchar_t *resolved_utf16 = _wcsdup(target_utf16);
|
wchar_t *resolved_utf16 = _wcsdup(target_utf16);
|
||||||
if (target_utf16 == NULL || linkpath_utf16 == NULL || resolved_utf16 == NULL) {
|
if (target_utf16 == NULL || linkpath_utf16 == NULL || resolved_utf16 == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
|
@ -229,15 +229,14 @@ dlsym(HMODULE handle, const char *symbol)
|
|||||||
FILE *
|
FILE *
|
||||||
w32_fopen_utf8(const char *input_path, const char *mode)
|
w32_fopen_utf8(const char *input_path, const char *mode)
|
||||||
{
|
{
|
||||||
wchar_t wpath[PATH_MAX], wmode[5];
|
wchar_t *wmode = NULL, *wpath = NULL;
|
||||||
FILE* f;
|
FILE* f = NULL;
|
||||||
char utf8_bom[] = { 0xEF,0xBB,0xBF };
|
char utf8_bom[] = { 0xEF,0xBB,0xBF };
|
||||||
char first3_bytes[3];
|
char first3_bytes[3];
|
||||||
int status = 1;
|
int status = 1;
|
||||||
errno_t r = 0;
|
errno_t r = 0;
|
||||||
char *path = NULL;
|
|
||||||
|
|
||||||
if (mode[1] != '\0') {
|
if (mode == NULL || mode[1] != '\0') {
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -248,28 +247,21 @@ w32_fopen_utf8(const char *input_path, const char *mode)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = resolved_path(input_path);
|
|
||||||
|
|
||||||
/* if opening null device, point to Windows equivalent */
|
/* if opening null device, point to Windows equivalent */
|
||||||
if (0 == strncmp(path, NULL_DEVICE, strlen(NULL_DEVICE)+1)) {
|
if (strcmp(input_path, NULL_DEVICE) == 0)
|
||||||
if ((r = wcsncpy_s(wpath, PATH_MAX, L"NUL", 3)) != 0) {
|
input_path = NULL_DEVICE_WIN;
|
||||||
debug3("wcsncpy_s failed with error: %d.", r);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
status = MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, PATH_MAX);
|
|
||||||
|
|
||||||
if ((0 == status) ||
|
wpath = resolved_path_utf16(input_path);
|
||||||
(0 == MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, 5))) {
|
wmode = utf8_to_utf16(mode);
|
||||||
errno = EFAULT;
|
if (wpath == NULL || wmode == NULL)
|
||||||
debug3("WideCharToMultiByte failed for %c - ERROR:%d", path, GetLastError());
|
{
|
||||||
return NULL;
|
errno = ENOMEM;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((_wfopen_s(&f, wpath, wmode) != 0) || (f == NULL)) {
|
if ((_wfopen_s(&f, wpath, wmode) != 0) || (f == NULL)) {
|
||||||
debug3("Failed to open file:%s error:%d", path, errno);
|
debug3("Failed to open file:%S error:%d", wpath, errno);
|
||||||
return NULL;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BOM adjustments for file streams*/
|
/* BOM adjustments for file streams*/
|
||||||
@ -277,7 +269,7 @@ w32_fopen_utf8(const char *input_path, const char *mode)
|
|||||||
/* write UTF-8 BOM - should we ?*/
|
/* write UTF-8 BOM - should we ?*/
|
||||||
/*if (fwrite(utf8_bom, sizeof(utf8_bom), 1, f) != 1) {
|
/*if (fwrite(utf8_bom, sizeof(utf8_bom), 1, f) != 1) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return NULL;
|
goto cleanup;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
} else if (mode[0] == 'r' && fseek(f, 0, SEEK_SET) != EBADF) {
|
} else if (mode[0] == 'r' && fseek(f, 0, SEEK_SET) != EBADF) {
|
||||||
@ -288,6 +280,13 @@ w32_fopen_utf8(const char *input_path, const char *mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
if (wpath)
|
||||||
|
free(wpath);
|
||||||
|
if (wmode)
|
||||||
|
free(wmode);
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,7 +510,7 @@ int
|
|||||||
w32_chmod(const char *pathname, mode_t mode)
|
w32_chmod(const char *pathname, mode_t mode)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolved_path(pathname));
|
wchar_t *resolvedPathName_utf16 = resolved_path_utf16(pathname);
|
||||||
if (resolvedPathName_utf16 == NULL) {
|
if (resolvedPathName_utf16 == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
@ -639,7 +638,7 @@ w32_utimes(const char *filename, struct timeval *tvp)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
FILETIME acttime, modtime;
|
FILETIME acttime, modtime;
|
||||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolved_path(filename));
|
wchar_t *resolvedPathName_utf16 = resolved_path_utf16(filename);
|
||||||
if (resolvedPathName_utf16 == NULL) {
|
if (resolvedPathName_utf16 == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
@ -671,19 +670,13 @@ link(const char *oldpath, const char *newpath)
|
|||||||
int
|
int
|
||||||
w32_rename(const char *old_name, const char *new_name)
|
w32_rename(const char *old_name, const char *new_name)
|
||||||
{
|
{
|
||||||
char old_name_resolved[PATH_MAX] = {0, };
|
|
||||||
char new_name_resolved[PATH_MAX] = {0, };
|
|
||||||
|
|
||||||
if (old_name == NULL || new_name == NULL) {
|
if (old_name == NULL || new_name == NULL) {
|
||||||
errno = EFAULT;
|
errno = EFAULT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy_s(old_name_resolved, _countof(old_name_resolved), resolved_path(old_name));
|
wchar_t *resolvedOldPathName_utf16 = resolved_path_utf16(old_name);
|
||||||
strcpy_s(new_name_resolved, _countof(new_name_resolved), resolved_path(new_name));
|
wchar_t *resolvedNewPathName_utf16 = resolved_path_utf16(new_name);
|
||||||
|
|
||||||
wchar_t *resolvedOldPathName_utf16 = utf8_to_utf16(old_name_resolved);
|
|
||||||
wchar_t *resolvedNewPathName_utf16 = utf8_to_utf16(new_name_resolved);
|
|
||||||
|
|
||||||
if (NULL == resolvedOldPathName_utf16 || NULL == resolvedNewPathName_utf16) {
|
if (NULL == resolvedOldPathName_utf16 || NULL == resolvedNewPathName_utf16) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
@ -695,18 +688,18 @@ w32_rename(const char *old_name, const char *new_name)
|
|||||||
* 1) if the new_name is file, then delete it so that _wrename will succeed.
|
* 1) if the new_name is file, then delete it so that _wrename will succeed.
|
||||||
* 2) if the new_name is directory and it is empty then delete it so that _wrename will succeed.
|
* 2) if the new_name is directory and it is empty then delete it so that _wrename will succeed.
|
||||||
*/
|
*/
|
||||||
struct _stat64 st;
|
struct w32_stat st;
|
||||||
if (fileio_stat(resolved_path(new_name_resolved), &st) != -1) {
|
if (w32_stat(new_name, &st) != -1) {
|
||||||
if (((st.st_mode & _S_IFMT) == _S_IFREG))
|
if (((st.st_mode & _S_IFMT) == _S_IFREG))
|
||||||
w32_unlink(new_name_resolved);
|
w32_unlink(new_name);
|
||||||
else {
|
else {
|
||||||
DIR *dirp = opendir(new_name_resolved);
|
DIR *dirp = opendir(new_name);
|
||||||
if (NULL != dirp) {
|
if (NULL != dirp) {
|
||||||
struct dirent *dp = readdir(dirp);
|
struct dirent *dp = readdir(dirp);
|
||||||
closedir(dirp);
|
closedir(dirp);
|
||||||
|
|
||||||
if (dp == NULL)
|
if (dp == NULL)
|
||||||
w32_rmdir(new_name_resolved);
|
w32_rmdir(new_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -721,7 +714,7 @@ w32_rename(const char *old_name, const char *new_name)
|
|||||||
int
|
int
|
||||||
w32_unlink(const char *path)
|
w32_unlink(const char *path)
|
||||||
{
|
{
|
||||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolved_path(path));
|
wchar_t *resolvedPathName_utf16 = resolved_path_utf16(path);
|
||||||
if (NULL == resolvedPathName_utf16) {
|
if (NULL == resolvedPathName_utf16) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
@ -736,7 +729,7 @@ w32_unlink(const char *path)
|
|||||||
int
|
int
|
||||||
w32_rmdir(const char *path)
|
w32_rmdir(const char *path)
|
||||||
{
|
{
|
||||||
wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolved_path(path));
|
wchar_t *resolvedPathName_utf16 = resolved_path_utf16(path);
|
||||||
if (NULL == resolvedPathName_utf16) {
|
if (NULL == resolvedPathName_utf16) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
@ -796,7 +789,7 @@ int
|
|||||||
w32_mkdir(const char *path_utf8, unsigned short mode)
|
w32_mkdir(const char *path_utf8, unsigned short mode)
|
||||||
{
|
{
|
||||||
int curmask;
|
int curmask;
|
||||||
wchar_t *path_utf16 = utf8_to_utf16(resolved_path(path_utf8));
|
wchar_t *path_utf16 = resolved_path_utf16(path_utf8);
|
||||||
if (path_utf16 == NULL) {
|
if (path_utf16 == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
@ -820,20 +813,20 @@ w32_mkdir(const char *path_utf8, unsigned short mode)
|
|||||||
int
|
int
|
||||||
w32_stat(const char *input_path, struct w32_stat *buf)
|
w32_stat(const char *input_path, struct w32_stat *buf)
|
||||||
{
|
{
|
||||||
return fileio_stat(resolved_path(input_path), (struct _stat64*)buf);
|
return fileio_stat(input_path, (struct _stat64*)buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
w32_lstat(const char *input_path, struct w32_stat *buf)
|
w32_lstat(const char *input_path, struct w32_stat *buf)
|
||||||
{
|
{
|
||||||
return fileio_lstat(resolved_path(input_path), (struct _stat64*)buf);
|
return fileio_lstat(input_path, (struct _stat64*)buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if file is symbolic link, copy its link into "link" */
|
/* if file is symbolic link, copy its link into "link" */
|
||||||
int
|
int
|
||||||
readlink(const char *path, char *link, int linklen)
|
readlink(const char *path, char *link, int linklen)
|
||||||
{
|
{
|
||||||
return fileio_readlink(resolved_path(path), link, linklen);
|
return fileio_readlink(path, link, linklen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert forward slash to back slash */
|
/* convert forward slash to back slash */
|
||||||
@ -915,44 +908,55 @@ realpath(const char *path, char resolved[PATH_MAX])
|
|||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is not thread safe.
|
wchar_t*
|
||||||
* TODO - It uses static memory. Is this a good design?
|
resolved_path_utf16(const char *input_path)
|
||||||
*/
|
|
||||||
char*
|
|
||||||
resolved_path(const char *input_path)
|
|
||||||
{
|
{
|
||||||
static char resolved_path[PATH_MAX] = {0,};
|
|
||||||
static char newPath[PATH_MAX] = { '\0', };
|
|
||||||
errno_t r = 0;
|
|
||||||
|
|
||||||
if (!input_path) return NULL;
|
if (!input_path) return NULL;
|
||||||
|
|
||||||
/* If filename contains __PROGRAMDATA__ then expand it to %programData% and return the resolved path */
|
wchar_t * resolved_path = utf8_to_utf16(input_path);
|
||||||
if ((strlen(input_path) >= strlen(PROGRAM_DATA)) && (memcmp(input_path, PROGRAM_DATA, strlen(PROGRAM_DATA)) == 0)) {
|
if (resolved_path == NULL)
|
||||||
resolved_path[0] = '\0';
|
return NULL;
|
||||||
strcat_s(resolved_path, _countof(resolved_path), get_program_data_path());
|
|
||||||
strcat_s(resolved_path, _countof(resolved_path), &input_path[strlen(PROGRAM_DATA)]);
|
|
||||||
|
|
||||||
return resolved_path; /* return here as its doesn't start with "/" */
|
int resolved_len = (int) wcslen(resolved_path);
|
||||||
|
const int variable_len = (int) wcslen(PROGRAM_DATAW);
|
||||||
|
|
||||||
|
/* search for program data flag and switch it with the real path */
|
||||||
|
if (_wcsnicmp(resolved_path, PROGRAM_DATAW, variable_len) == 0) {
|
||||||
|
wchar_t * program_data = get_program_data_path();
|
||||||
|
const int programdata_len = (int) wcslen(program_data);
|
||||||
|
const int changed_req = programdata_len - variable_len;
|
||||||
|
|
||||||
|
/* allocate more memory if required */
|
||||||
|
if (changed_req > 0) {
|
||||||
|
wchar_t * resolved_path_new = realloc(resolved_path,
|
||||||
|
(resolved_len + changed_req + 1) * sizeof(wchar_t));
|
||||||
|
if (resolved_path == NULL) {
|
||||||
|
free(resolved_path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else resolved_path = resolved_path_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shift memory contents over based on side of the new string */
|
||||||
|
memmove(resolved_path + variable_len + changed_req, resolved_path + variable_len,
|
||||||
|
(resolved_len - variable_len + 1) * sizeof(wchar_t));
|
||||||
|
memcpy(resolved_path, program_data, programdata_len * sizeof(wchar_t));
|
||||||
|
resolved_len += changed_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy_s(resolved_path, _countof(resolved_path), input_path);
|
if (resolved_path[0] == L'/' && iswalpha(resolved_path[1]) && resolved_path[2] == L':') {
|
||||||
if (resolved_path[0] == '/' && resolved_path[1]) {
|
|
||||||
if (resolved_path[2] == ':') {
|
|
||||||
if (resolved_path[3] == '\0') {
|
|
||||||
/* make "/x:" as "x:\\" */
|
|
||||||
resolved_path[0] = resolved_path[1];
|
|
||||||
resolved_path[1] = resolved_path[2];
|
|
||||||
resolved_path[2] = '\\';
|
|
||||||
resolved_path[3] = '\0';
|
|
||||||
|
|
||||||
return resolved_path;
|
/* shift memory to remove forward slash including null terminator */
|
||||||
} else
|
memmove(resolved_path, resolved_path + 1, (resolved_len + 1 - 1) * sizeof(wchar_t));
|
||||||
return (char *)(resolved_path + 1); /* skip the first "/" */
|
|
||||||
|
/* if just a drive letter path, make x: into x:\ */
|
||||||
|
if (resolved_path[2] == L'\0') {
|
||||||
|
resolved_path[2] = L'\\';
|
||||||
|
resolved_path[3] = L'\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (char *)resolved_path;
|
return resolved_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -963,7 +967,7 @@ statvfs(const char *path, struct statvfs *buf)
|
|||||||
DWORD freeClusters;
|
DWORD freeClusters;
|
||||||
DWORD totalClusters;
|
DWORD totalClusters;
|
||||||
|
|
||||||
wchar_t* path_utf16 = utf8_to_utf16(resolved_path(path));
|
wchar_t* path_utf16 = resolved_path_utf16(path);
|
||||||
if (path_utf16 && (GetDiskFreeSpaceW(path_utf16, §orsPerCluster, &bytesPerSector,
|
if (path_utf16 && (GetDiskFreeSpaceW(path_utf16, §orsPerCluster, &bytesPerSector,
|
||||||
&freeClusters, &totalClusters) == TRUE)) {
|
&freeClusters, &totalClusters) == TRUE)) {
|
||||||
debug5("path : [%s]", path);
|
debug5("path : [%s]", path);
|
||||||
@ -1433,23 +1437,19 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
wchar_t*
|
||||||
get_program_data_path()
|
get_program_data_path()
|
||||||
{
|
{
|
||||||
if (ssh_cfg_dir_path) return ssh_cfg_dir_path;
|
static wchar_t ssh_cfg_dir_path_w[PATH_MAX] = L"";
|
||||||
|
if (wcslen(ssh_cfg_dir_path_w) > 0) return ssh_cfg_dir_path_w;
|
||||||
|
|
||||||
wchar_t ssh_cfg_dir_path_w[PATH_MAX] = {0, };
|
int return_val = ExpandEnvironmentStringsW(L"%ProgramData%", ssh_cfg_dir_path_w, PATH_MAX);
|
||||||
int return_val = ExpandEnvironmentStringsW(L"%programData%", ssh_cfg_dir_path_w, PATH_MAX);
|
|
||||||
if (return_val > PATH_MAX)
|
if (return_val > PATH_MAX)
|
||||||
fatal("%s, buffer too small to expand:%s", __func__, "%programData%");
|
fatal("%s, buffer too small to expand:%s", __func__, "%ProgramData%");
|
||||||
else if (!return_val)
|
else if (!return_val)
|
||||||
fatal("%s, failed to expand:%s error:%s", __func__, "%programData%", GetLastError());
|
fatal("%s, failed to expand:%s error:%s", __func__, "%ProgramData%", GetLastError());
|
||||||
|
|
||||||
ssh_cfg_dir_path = utf16_to_utf8(ssh_cfg_dir_path_w);
|
|
||||||
if(!ssh_cfg_dir_path)
|
|
||||||
fatal("%s utf16_to_utf8 failed", __func__);
|
|
||||||
|
|
||||||
return ssh_cfg_dir_path;
|
return ssh_cfg_dir_path_w;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Windows absolute paths - \abc, /abc, c:\abc, c:/abc, __PROGRAMDATA__\openssh\sshd_config */
|
/* Windows absolute paths - \abc, /abc, c:\abc, c:/abc, __PROGRAMDATA__\openssh\sshd_config */
|
||||||
@ -1469,28 +1469,15 @@ is_absolute_path(const char *path)
|
|||||||
|
|
||||||
/* return -1 - in case of failure, 0 - success */
|
/* return -1 - in case of failure, 0 - success */
|
||||||
int
|
int
|
||||||
create_directory_withsddl(char *path, char *sddl)
|
create_directory_withsddl(wchar_t *path_w, wchar_t *sddl_w)
|
||||||
{
|
{
|
||||||
struct stat st;
|
if (GetFileAttributesW(path_w) == INVALID_FILE_ATTRIBUTES) {
|
||||||
if (stat(path, &st) < 0) {
|
|
||||||
PSECURITY_DESCRIPTOR pSD = NULL;
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
||||||
SECURITY_ATTRIBUTES sa;
|
SECURITY_ATTRIBUTES sa;
|
||||||
memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
|
memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
|
||||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
sa.bInheritHandle = FALSE;
|
sa.bInheritHandle = FALSE;
|
||||||
|
|
||||||
wchar_t *path_w = utf8_to_utf16(path);
|
|
||||||
if (!path_w) {
|
|
||||||
error("%s utf8_to_utf16() has failed to convert string:%s", __func__, path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t *sddl_w = utf8_to_utf16(sddl);
|
|
||||||
if (!sddl_w) {
|
|
||||||
error("%s utf8_to_utf16() has failed to convert string:%s", __func__, sddl);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl_w, SDDL_REVISION, &pSD, NULL) == FALSE) {
|
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl_w, SDDL_REVISION, &pSD, NULL) == FALSE) {
|
||||||
error("ConvertStringSecurityDescriptorToSecurityDescriptorW failed with error code %d", GetLastError());
|
error("ConvertStringSecurityDescriptorToSecurityDescriptorW failed with error code %d", GetLastError());
|
||||||
return -1;
|
return -1;
|
||||||
@ -1510,33 +1497,3 @@ create_directory_withsddl(char *path, char *sddl)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return -1 - in case of failure, 0 - success */
|
|
||||||
int
|
|
||||||
copy_file(char *source, char *destination)
|
|
||||||
{
|
|
||||||
if (!source || !destination) return 0;
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
if ((stat(source, &st) >= 0) && (stat(destination, &st) < 0)) {
|
|
||||||
wchar_t *source_w = utf8_to_utf16(source);
|
|
||||||
if (!source_w) {
|
|
||||||
error("%s utf8_to_utf16() has failed to convert string:%s", __func__, source_w);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t *destination_w = utf8_to_utf16(destination);
|
|
||||||
if (!destination_w) {
|
|
||||||
error("%s utf8_to_utf16() has failed to convert string:%s", __func__, destination_w);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CopyFileW(source_w, destination_w, FALSE)) {
|
|
||||||
error("Failed to copy %ls to %ls, error:%d", source_w, destination_w, GetLastError());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -9,21 +9,23 @@
|
|||||||
goto cleanup; \
|
goto cleanup; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define NULL_DEVICE "/dev/null"
|
#define NULL_DEVICE "/dev/null"
|
||||||
|
#define NULL_DEVICE_WIN "NUL"
|
||||||
|
|
||||||
#define IsWin7OrLess() (!IsWindows8OrGreater())
|
#define IsWin7OrLess() (!IsWindows8OrGreater())
|
||||||
|
|
||||||
#define IS_INVALID_HANDLE(h) ( ((NULL == h) || (INVALID_HANDLE_VALUE == h)) ? 1 : 0 )
|
#define IS_INVALID_HANDLE(h) ( ((NULL == h) || (INVALID_HANDLE_VALUE == h)) ? 1 : 0 )
|
||||||
#define IS_VALID_HANDLE(h) (!IS_INVALID_HANDLE(h))
|
#define IS_VALID_HANDLE(h) (!IS_INVALID_HANDLE(h))
|
||||||
#define PROGRAM_DATA "__PROGRAMDATA__"
|
#define PROGRAM_DATA "__PROGRAMDATA__"
|
||||||
|
#define PROGRAM_DATAW L"__PROGRAMDATA__"
|
||||||
|
|
||||||
#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError())
|
#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError())
|
||||||
|
|
||||||
static char *machine_domain_name;
|
static char *machine_domain_name;
|
||||||
static char *ssh_cfg_dir_path = NULL;
|
|
||||||
|
|
||||||
/* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */
|
/* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */
|
||||||
char * resolved_path(const char *);
|
wchar_t * resolved_path_utf16(const char *);
|
||||||
void w32posix_initialize();
|
void w32posix_initialize();
|
||||||
void w32posix_done();
|
void w32posix_done();
|
||||||
char* w32_programdir();
|
char* w32_programdir();
|
||||||
@ -37,9 +39,8 @@ int file_attr_to_st_mode(wchar_t * path, DWORD attributes);
|
|||||||
void invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t);
|
void invalid_parameter_handler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t);
|
||||||
void to_lower_case(char *s);
|
void to_lower_case(char *s);
|
||||||
int get_machine_domain_name(wchar_t *domain, int size);
|
int get_machine_domain_name(wchar_t *domain, int size);
|
||||||
char* get_program_data_path();
|
wchar_t* get_program_data_path();
|
||||||
HANDLE get_user_token(char* user);
|
HANDLE get_user_token(char* user);
|
||||||
int load_user_profile(HANDLE user_token, char* user);
|
int load_user_profile(HANDLE user_token, char* user);
|
||||||
int copy_file(char *source, char *destination);
|
int create_directory_withsddl(wchar_t *path, wchar_t *sddl);
|
||||||
int create_directory_withsddl(char *path, char *sddl);
|
|
||||||
int is_absolute_path(const char *);
|
int is_absolute_path(const char *);
|
@ -57,7 +57,7 @@ static VOID CALLBACK
|
|||||||
ReadAPCProc(_In_ ULONG_PTR dwParam)
|
ReadAPCProc(_In_ ULONG_PTR dwParam)
|
||||||
{
|
{
|
||||||
struct w32_io* pio = (struct w32_io*)dwParam;
|
struct w32_io* pio = (struct w32_io*)dwParam;
|
||||||
debug5("TermRead CB - io:%p, bytes: %d, pending: %d, error: %d", pio, read_status.transferred,
|
debug5("TermRead CB - io:%p, bytes: %d, pending: %d, error: %d", pio, pio->read_details.completed,
|
||||||
pio->read_details.pending, pio->sync_read_status.error);
|
pio->read_details.pending, pio->sync_read_status.error);
|
||||||
pio->read_details.error = pio->sync_read_status.error;
|
pio->read_details.error = pio->sync_read_status.error;
|
||||||
pio->read_details.remaining = pio->sync_read_status.transferred;
|
pio->read_details.remaining = pio->sync_read_status.transferred;
|
||||||
@ -171,7 +171,7 @@ static VOID CALLBACK
|
|||||||
WriteAPCProc(_In_ ULONG_PTR dwParam)
|
WriteAPCProc(_In_ ULONG_PTR dwParam)
|
||||||
{
|
{
|
||||||
struct w32_io* pio = (struct w32_io*)dwParam;
|
struct w32_io* pio = (struct w32_io*)dwParam;
|
||||||
debug5("TermWrite CB - io:%p, bytes: %d, pending: %d, error: %d", pio, write_status.transferred,
|
debug5("TermWrite CB - io:%p, bytes: %d, pending: %d, error: %d", pio, pio->write_details.completed,
|
||||||
pio->write_details.pending, pio->sync_write_status.error);
|
pio->write_details.pending, pio->sync_write_status.error);
|
||||||
pio->write_details.error = pio->sync_write_status.error;
|
pio->write_details.error = pio->sync_write_status.error;
|
||||||
pio->write_details.remaining -= pio->sync_write_status.transferred;
|
pio->write_details.remaining -= pio->sync_write_status.transferred;
|
||||||
|
@ -57,7 +57,6 @@ check_secure_file_permission(const char *input_path, struct passwd * pw)
|
|||||||
struct passwd * pwd = pw;
|
struct passwd * pwd = pw;
|
||||||
char *bad_user = NULL;
|
char *bad_user = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char *path = NULL;
|
|
||||||
|
|
||||||
if (pwd == NULL)
|
if (pwd == NULL)
|
||||||
if ((pwd = getpwuid(0)) == NULL)
|
if ((pwd = getpwuid(0)) == NULL)
|
||||||
@ -70,8 +69,7 @@ check_secure_file_permission(const char *input_path, struct passwd * pw)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = resolved_path(input_path);
|
if ((path_utf16 = resolved_path_utf16(input_path)) == NULL) {
|
||||||
if ((path_utf16 = utf8_to_utf16(path)) == NULL) {
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -81,7 +79,7 @@ check_secure_file_permission(const char *input_path, struct passwd * pw)
|
|||||||
if ((error_code = GetNamedSecurityInfoW(path_utf16, SE_FILE_OBJECT,
|
if ((error_code = GetNamedSecurityInfoW(path_utf16, SE_FILE_OBJECT,
|
||||||
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||||
&owner_sid, NULL, &dacl, NULL, &pSD)) != ERROR_SUCCESS) {
|
&owner_sid, NULL, &dacl, NULL, &pSD)) != ERROR_SUCCESS) {
|
||||||
debug3("failed to retrieve the owner sid and dacl of file %s with error code: %d", path, error_code);
|
debug3("failed to retrieve the owner sid and dacl of file %S with error code: %d", path_utf16, error_code);
|
||||||
errno = EOTHER;
|
errno = EOTHER;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -94,7 +92,7 @@ check_secure_file_permission(const char *input_path, struct passwd * pw)
|
|||||||
if (!IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) &&
|
if (!IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) &&
|
||||||
!IsWellKnownSid(owner_sid, WinLocalSystemSid) &&
|
!IsWellKnownSid(owner_sid, WinLocalSystemSid) &&
|
||||||
!EqualSid(owner_sid, user_sid)) {
|
!EqualSid(owner_sid, user_sid)) {
|
||||||
debug3("Bad owner on %s", path);
|
debug3("Bad owner on %S", path_utf16);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -136,7 +134,7 @@ check_secure_file_permission(const char *input_path, struct passwd * pw)
|
|||||||
debug3("ConvertSidToSidString failed with %d. ", GetLastError());
|
debug3("ConvertSidToSidString failed with %d. ", GetLastError());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
debug3("Bad permissions. Try removing permissions for user: %s on file %s.", bad_user, path);
|
debug3("Bad permissions. Try removing permissions for user: %s on file %S.", bad_user, path_utf16);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,7 +474,7 @@ w32_open(const char *pathname, int flags, ... /* arg */)
|
|||||||
va_end(valist);
|
va_end(valist);
|
||||||
}
|
}
|
||||||
|
|
||||||
pio = fileio_open(resolved_path(pathname), flags, mode);
|
pio = fileio_open(pathname, flags, mode);
|
||||||
|
|
||||||
if (pio == NULL)
|
if (pio == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -110,13 +110,11 @@ openlog_file()
|
|||||||
while (tail > module_path && *tail != L'\\' && *tail != L'/')
|
while (tail > module_path && *tail != L'\\' && *tail != L'/')
|
||||||
tail--;
|
tail--;
|
||||||
|
|
||||||
char ssh_cfg_path[PATH_MAX] = {0 ,};
|
wchar_t ssh_root_path[PATH_MAX] = {0 ,};
|
||||||
strcat_s(ssh_cfg_path, _countof(ssh_cfg_path), get_program_data_path()); /* "%programData%" */
|
wcscat_s(ssh_root_path, _countof(ssh_root_path), get_program_data_path()); /* "%programData%" */
|
||||||
strcat_s(ssh_cfg_path, _countof(ssh_cfg_path), "\\ssh"); /* "%programData%\\ssh" */
|
wcscat_s(ssh_root_path, _countof(ssh_root_path), L"\\ssh"); /* "%programData%\\ssh" */
|
||||||
|
|
||||||
wchar_t* ssh_root_path_w = utf8_to_utf16(ssh_cfg_path); /* "%programData%\\ssh" */
|
if ((wcsncat_s(log_file, PATH_MAX + 12, ssh_root_path, wcslen(ssh_root_path)) != 0) ||
|
||||||
|
|
||||||
if ((wcsncat_s(log_file, PATH_MAX + 12, ssh_root_path_w, wcslen(ssh_root_path_w)) != 0) ||
|
|
||||||
(wcsncat_s(log_file, PATH_MAX + 12, logs_dir, 6) != 0) ||
|
(wcsncat_s(log_file, PATH_MAX + 12, logs_dir, 6) != 0) ||
|
||||||
(wcsncat_s(log_file, PATH_MAX + 12, tail + 1, wcslen(tail + 1) - 3) != 0 ) ||
|
(wcsncat_s(log_file, PATH_MAX + 12, tail + 1, wcslen(tail + 1) - 3) != 0 ) ||
|
||||||
(wcsncat_s(log_file, PATH_MAX + 12, L"log", 3) != 0))
|
(wcsncat_s(log_file, PATH_MAX + 12, L"log", 3) != 0))
|
||||||
|
@ -108,7 +108,7 @@ opendir(const char *name)
|
|||||||
if (name && strcmp(name, "/") == 0)
|
if (name && strcmp(name, "/") == 0)
|
||||||
return openrootdir(name);
|
return openrootdir(name);
|
||||||
|
|
||||||
if ((wname = utf8_to_utf16(resolved_path(name))) == NULL) {
|
if ((wname = resolved_path_utf16(name)) == NULL) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -162,34 +162,32 @@ static void
|
|||||||
create_prgdata_ssh_folder()
|
create_prgdata_ssh_folder()
|
||||||
{
|
{
|
||||||
/* create ssh cfg folder */
|
/* create ssh cfg folder */
|
||||||
char ssh_cfg_dir[PATH_MAX] = { 0, };
|
wchar_t ssh_cfg_dir[PATH_MAX] = { 0, };
|
||||||
strcpy_s(ssh_cfg_dir, _countof(ssh_cfg_dir), get_program_data_path());
|
wcscpy_s(ssh_cfg_dir, _countof(ssh_cfg_dir), get_program_data_path());
|
||||||
strcat_s(ssh_cfg_dir, _countof(ssh_cfg_dir), "\\ssh");
|
wcscat_s(ssh_cfg_dir, _countof(ssh_cfg_dir), L"\\ssh");
|
||||||
if (create_directory_withsddl(ssh_cfg_dir, "O:BAD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1200a9;;;AU)") < 0) {
|
if (create_directory_withsddl(ssh_cfg_dir, L"O:BAD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1200a9;;;AU)") < 0) {
|
||||||
printf("failed to create %s", ssh_cfg_dir);
|
printf("failed to create %s", ssh_cfg_dir);
|
||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create logs folder */
|
/* create logs folder */
|
||||||
char logs_dir[PATH_MAX] = { 0, };
|
wchar_t logs_dir[PATH_MAX] = { 0, };
|
||||||
strcat_s(logs_dir, _countof(logs_dir), ssh_cfg_dir);
|
wcscat_s(logs_dir, _countof(logs_dir), ssh_cfg_dir);
|
||||||
strcat_s(logs_dir, _countof(logs_dir), "\\logs");
|
wcscat_s(logs_dir, _countof(logs_dir), L"\\logs");
|
||||||
if (create_directory_withsddl(logs_dir, "O:BAD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)") < 0) {
|
if (create_directory_withsddl(logs_dir, L"O:BAD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)") < 0) {
|
||||||
printf("failed to create %s", logs_dir);
|
printf("failed to create %s", logs_dir);
|
||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* COPY sshd_config_default to %programData%\openssh\sshd_config */
|
/* copy sshd_config_default to %programData%\ssh\sshd_config */
|
||||||
char sshd_config_path[PATH_MAX] = { 0, };
|
wchar_t sshd_config_path[PATH_MAX] = { 0, };
|
||||||
strcat_s(sshd_config_path, _countof(sshd_config_path), ssh_cfg_dir);
|
wcscat_s(sshd_config_path, _countof(sshd_config_path), ssh_cfg_dir);
|
||||||
strcat_s(sshd_config_path, _countof(sshd_config_path), "\\sshd_config");
|
wcscat_s(sshd_config_path, _countof(sshd_config_path), L"\\sshd_config");
|
||||||
struct stat st;
|
if (GetFileAttributesW(sshd_config_path) == INVALID_FILE_ATTRIBUTES) {
|
||||||
if (stat(sshd_config_path, &st) < 0) {
|
wchar_t sshd_config_default_path[PATH_MAX] = { 0, };
|
||||||
char sshd_config_default_path[PATH_MAX] = { 0, };
|
swprintf_s(sshd_config_default_path, PATH_MAX, L"%S\\%s", w32_programdir(), L"sshd_config_default");
|
||||||
strcat_s(sshd_config_default_path, _countof(sshd_config_default_path), w32_programdir());
|
|
||||||
strcat_s(sshd_config_default_path, _countof(sshd_config_default_path), "\\sshd_config_default");
|
|
||||||
|
|
||||||
if (copy_file(sshd_config_default_path, sshd_config_path) < 0) {
|
if (CopyFileW(sshd_config_default_path, sshd_config_path, TRUE) == 0) {
|
||||||
printf("Failed to copy %s to %s, error:%d", sshd_config_default_path, sshd_config_path, GetLastError());
|
printf("Failed to copy %s to %s, error:%d", sshd_config_default_path, sshd_config_path, GetLastError());
|
||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
@ -261,7 +259,7 @@ int wmain(int argc, wchar_t **wargv) {
|
|||||||
wchar_t* path_utf16;
|
wchar_t* path_utf16;
|
||||||
argc_original = argc;
|
argc_original = argc;
|
||||||
wargv_original = wargv;
|
wargv_original = wargv;
|
||||||
|
|
||||||
/* change current directory to sshd.exe root */
|
/* change current directory to sshd.exe root */
|
||||||
if ( (path_utf16 = utf8_to_utf16(w32_programdir())) == NULL)
|
if ( (path_utf16 = utf8_to_utf16(w32_programdir())) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -64,31 +64,38 @@ test_sanitizedpath()
|
|||||||
{
|
{
|
||||||
TEST_START("win32 program dir");
|
TEST_START("win32 program dir");
|
||||||
|
|
||||||
char *win32prgdir = w32_programdir();
|
char *win32prgdir_utf8 = w32_programdir();
|
||||||
ASSERT_PTR_NE(win32prgdir, NULL);
|
ASSERT_PTR_NE(win32prgdir_utf8, NULL);
|
||||||
|
|
||||||
ASSERT_PTR_EQ(resolved_path(NULL), NULL);
|
ASSERT_PTR_EQ(resolved_path_utf16(NULL), NULL);
|
||||||
|
|
||||||
char *ret = resolved_path(win32prgdir);
|
wchar_t *win32prgdir = utf8_to_utf16(win32prgdir_utf8);
|
||||||
retValue = strcmp(win32prgdir, ret);
|
wchar_t *ret = resolved_path_utf16(win32prgdir_utf8);
|
||||||
|
retValue = wcscmp(win32prgdir, ret);
|
||||||
ASSERT_INT_EQ(retValue, 0);
|
ASSERT_INT_EQ(retValue, 0);
|
||||||
|
free(ret);
|
||||||
|
|
||||||
char win32prgdir_len = strlen(win32prgdir);
|
char win32prgdir_len = strlen(win32prgdir_utf8);
|
||||||
char *tmp_path = malloc(win32prgdir_len + 2); /* 1-NULL and 1-adding "/" */
|
char *tmp_path = malloc(win32prgdir_len + 2); /* 1-NULL and 1-adding "/" */
|
||||||
tmp_path[0] = '/';
|
tmp_path[0] = '/';
|
||||||
strncpy(tmp_path+1, win32prgdir, win32prgdir_len);
|
strcpy(tmp_path+1, win32prgdir_utf8);
|
||||||
tmp_path[win32prgdir_len+1] = '\0';
|
tmp_path[win32prgdir_len+1] = '\0';
|
||||||
|
|
||||||
ret = resolved_path(tmp_path);
|
ret = resolved_path_utf16(tmp_path);
|
||||||
retValue = strcmp(win32prgdir, ret);
|
retValue = wcscmp(win32prgdir, ret);
|
||||||
ASSERT_INT_EQ(retValue, 0);
|
ASSERT_INT_EQ(retValue, 0);
|
||||||
|
free(ret);
|
||||||
|
|
||||||
char *s1 = malloc(4), *s2 = malloc(4);
|
char s1[4];
|
||||||
|
wchar_t s2[4];
|
||||||
s1[0] = '/', s1[1] = win32prgdir[0], s1[2] = ':', s1[3] = '\0';
|
s1[0] = '/', s1[1] = win32prgdir[0], s1[2] = ':', s1[3] = '\0';
|
||||||
s2[0] = win32prgdir[0], s2[1] = ':', s2[2] = '\\', s2[3] = '\0';
|
s2[0] = win32prgdir[0], s2[1] = ':', s2[2] = '\\', s2[3] = '\0';
|
||||||
ret = resolved_path(s1);
|
ret = resolved_path_utf16(s1);
|
||||||
retValue = strcmp(ret, s2);
|
retValue = wcscmp(ret, s2);
|
||||||
ASSERT_INT_EQ(retValue, 0);
|
ASSERT_INT_EQ(retValue, 0);
|
||||||
|
free(ret);
|
||||||
|
|
||||||
|
free(win32prgdir);
|
||||||
|
|
||||||
TEST_DONE();
|
TEST_DONE();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user