Blame winpr/libwinpr/path/shell.c

Packit Service fa4841
/**
Packit Service fa4841
 * WinPR: Windows Portable Runtime
Packit Service fa4841
 * Path Functions
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <stdio.h>
Packit Service fa4841
#include <stdlib.h>
Packit Service fa4841
#include <string.h>
Packit Service fa4841
#include <sys/stat.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/platform.h>
Packit Service fa4841
#include <winpr/heap.h>
Packit Service fa4841
#include <winpr/file.h>
Packit Service fa4841
#include <winpr/tchar.h>
Packit Service fa4841
#include <winpr/environment.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/path.h>
Packit Service fa4841
Packit Service fa4841
#if defined(__IOS__)
Packit Service fa4841
#include "shell_ios.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#if defined(WIN32)
Packit Service b1ea74
#include <shlobj.h>
Packit Service fa4841
#else
Packit Service fa4841
#include <errno.h>
Packit Service fa4841
#include <dirent.h>
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
static char* GetPath_XDG_CONFIG_HOME(void);
Packit Service fa4841
static char* GetPath_XDG_RUNTIME_DIR(void);
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * SHGetKnownFolderPath function:
Packit Service fa4841
 * http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188/
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * XDG Base Directory Specification:
Packit Service fa4841
 * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
static char* GetEnvAlloc(LPCSTR lpName)
Packit Service fa4841
{
Packit Service fa4841
	DWORD length;
Packit Service fa4841
	char* env = NULL;
Packit Service fa4841
	length = GetEnvironmentVariableA(lpName, NULL, 0);
Packit Service fa4841
Packit Service fa4841
	if (length > 0)
Packit Service fa4841
	{
Packit Service fa4841
		env = malloc(length);
Packit Service fa4841
Packit Service fa4841
		if (!env)
Packit Service fa4841
			return NULL;
Packit Service fa4841
Packit Service fa4841
		if (GetEnvironmentVariableA(lpName, env, length) != length - 1)
Packit Service fa4841
		{
Packit Service fa4841
			free(env);
Packit Service fa4841
			return NULL;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return env;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static char* GetPath_HOME(void)
Packit Service fa4841
{
Packit Service fa4841
	char* path = NULL;
Packit Service fa4841
#ifdef _WIN32
Packit Service fa4841
	path = GetEnvAlloc("UserProfile");
Packit Service fa4841
#elif defined(__IOS__)
Packit Service fa4841
	path = ios_get_home();
Packit Service fa4841
#else
Packit Service fa4841
	path = GetEnvAlloc("HOME");
Packit Service fa4841
#endif
Packit Service fa4841
	return path;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static char* GetPath_TEMP(void)
Packit Service fa4841
{
Packit Service fa4841
	char* path = NULL;
Packit Service fa4841
#ifdef _WIN32
Packit Service fa4841
	path = GetEnvAlloc("TEMP");
Packit Service fa4841
#elif defined(__IOS__)
Packit Service fa4841
	path = ios_get_temp();
Packit Service fa4841
#else
Packit Service fa4841
	path = GetEnvAlloc("TMPDIR");
Packit Service fa4841
Packit Service fa4841
	if (!path)
Packit Service fa4841
		path = _strdup("/tmp");
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	return path;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static char* GetPath_XDG_DATA_HOME(void)
Packit Service fa4841
{
Packit Service fa4841
	char* path = NULL;
Packit Service fa4841
#if defined(WIN32) || defined(__IOS__)
Packit Service fa4841
	path = GetPath_XDG_CONFIG_HOME();
Packit Service fa4841
#else
Packit Service b1ea74
	size_t size;
Packit Service fa4841
	char* home = NULL;
Packit Service fa4841
	/**
Packit Service b1ea74
	 * There is a single base directory relative to which user-specific data files should be
Packit Service b1ea74
	 * written. This directory is defined by the environment variable $XDG_DATA_HOME.
Packit Service fa4841
	 *
Packit Service b1ea74
	 * $XDG_DATA_HOME defines the base directory relative to which user specific data files should
Packit Service b1ea74
	 * be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to
Packit Service b1ea74
	 * $HOME/.local/share should be used.
Packit Service fa4841
	 */
Packit Service fa4841
	path = GetEnvAlloc("XDG_DATA_HOME");
Packit Service fa4841
Packit Service fa4841
	if (path)
Packit Service fa4841
		return path;
Packit Service fa4841
Packit Service fa4841
	home = GetPath_HOME();
Packit Service fa4841
Packit Service fa4841
	if (!home)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	size = strlen(home) + strlen("/.local/share") + 1;
Packit Service b1ea74
	path = (char*)malloc(size);
Packit Service fa4841
Packit Service fa4841
	if (!path)
Packit Service fa4841
	{
Packit Service fa4841
		free(home);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	sprintf_s(path, size, "%s%s", home, "/.local/share");
Packit Service fa4841
	free(home);
Packit Service fa4841
#endif
Packit Service fa4841
	return path;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static char* GetPath_XDG_CONFIG_HOME(void)
Packit Service fa4841
{
Packit Service fa4841
	char* path = NULL;
Packit Service fa4841
#if defined(WIN32) && !defined(_UWP)
Packit Service fa4841
	path = calloc(MAX_PATH, sizeof(char));
Packit Service fa4841
Packit Service fa4841
	if (!path)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (FAILED(SHGetFolderPathA(0, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path)))
Packit Service fa4841
	{
Packit Service fa4841
		free(path);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#elif defined(__IOS__)
Packit Service fa4841
	path = ios_get_data();
Packit Service fa4841
#else
Packit Service b1ea74
	size_t size;
Packit Service fa4841
	char* home = NULL;
Packit Service fa4841
	/**
Packit Service b1ea74
	 * There is a single base directory relative to which user-specific configuration files should
Packit Service b1ea74
	 * be written. This directory is defined by the environment variable $XDG_CONFIG_HOME.
Packit Service fa4841
	 *
Packit Service b1ea74
	 * $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration
Packit Service b1ea74
	 * files should be stored. If $XDG_CONFIG_HOME is either not set or empty, a default equal to
Packit Service b1ea74
	 * $HOME/.config should be used.
Packit Service fa4841
	 */
Packit Service fa4841
	path = GetEnvAlloc("XDG_CONFIG_HOME");
Packit Service fa4841
Packit Service fa4841
	if (path)
Packit Service fa4841
		return path;
Packit Service fa4841
Packit Service fa4841
	home = GetPath_HOME();
Packit Service fa4841
Packit Service fa4841
	if (!home)
Packit Service fa4841
		home = GetPath_TEMP();
Packit Service fa4841
Packit Service fa4841
	if (!home)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	size = strlen(home) + strlen("/.config") + 1;
Packit Service b1ea74
	path = (char*)malloc(size);
Packit Service fa4841
Packit Service fa4841
	if (!path)
Packit Service fa4841
	{
Packit Service fa4841
		free(home);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	sprintf_s(path, size, "%s%s", home, "/.config");
Packit Service fa4841
	free(home);
Packit Service fa4841
#endif
Packit Service fa4841
	return path;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static char* GetPath_XDG_CACHE_HOME(void)
Packit Service fa4841
{
Packit Service fa4841
	char* path = NULL;
Packit Service fa4841
	char* home = NULL;
Packit Service fa4841
#if defined(WIN32)
Packit Service fa4841
	home = GetPath_XDG_RUNTIME_DIR();
Packit Service fa4841
Packit Service fa4841
	if (home)
Packit Service fa4841
	{
Packit Service fa4841
		path = GetCombinedPath(home, "cache");
Packit Service fa4841
Packit Service fa4841
		if (!PathFileExistsA(path))
Packit Service fa4841
			if (!CreateDirectoryA(path, NULL))
Packit Service fa4841
				path = NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(home);
Packit Service fa4841
#elif defined(__IOS__)
Packit Service fa4841
	path = ios_get_cache();
Packit Service fa4841
#else
Packit Service b1ea74
	size_t size;
Packit Service fa4841
	/**
Packit Service b1ea74
	 * There is a single base directory relative to which user-specific non-essential (cached) data
Packit Service b1ea74
	 * should be written. This directory is defined by the environment variable $XDG_CACHE_HOME.
Packit Service fa4841
	 *
Packit Service b1ea74
	 * $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data
Packit Service b1ea74
	 * files should be stored. If $XDG_CACHE_HOME is either not set or empty, a default equal to
Packit Service b1ea74
	 * $HOME/.cache should be used.
Packit Service fa4841
	 */
Packit Service fa4841
	path = GetEnvAlloc("XDG_CACHE_HOME");
Packit Service fa4841
Packit Service fa4841
	if (path)
Packit Service fa4841
		return path;
Packit Service fa4841
Packit Service fa4841
	home = GetPath_HOME();
Packit Service fa4841
Packit Service fa4841
	if (!home)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	size = strlen(home) + strlen("/.cache") + 1;
Packit Service b1ea74
	path = (char*)malloc(size);
Packit Service fa4841
Packit Service fa4841
	if (!path)
Packit Service fa4841
	{
Packit Service fa4841
		free(home);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	sprintf_s(path, size, "%s%s", home, "/.cache");
Packit Service fa4841
	free(home);
Packit Service fa4841
#endif
Packit Service fa4841
	return path;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* GetPath_XDG_RUNTIME_DIR(void)
Packit Service fa4841
{
Packit Service fa4841
	char* path = NULL;
Packit Service fa4841
#if defined(WIN32) && !defined(_UWP)
Packit Service fa4841
	path = calloc(MAX_PATH, sizeof(char));
Packit Service fa4841
Packit Service fa4841
	if (!path)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service b1ea74
	if (FAILED(SHGetFolderPathA(0, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path)))
Packit Service fa4841
	{
Packit Service fa4841
		free(path);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#else
Packit Service fa4841
	/**
Packit Service b1ea74
	 * There is a single base directory relative to which user-specific runtime files and other file
Packit Service b1ea74
	 * objects should be placed. This directory is defined by the environment variable
Packit Service b1ea74
	 * $XDG_RUNTIME_DIR.
Packit Service fa4841
	 *
Packit Service b1ea74
	 * $XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential
Packit Service b1ea74
	 * runtime files and other file objects (such as sockets, named pipes, ...) should be stored.
Packit Service b1ea74
	 * The directory MUST be owned by the user, and he MUST be the only one having read and write
Packit Service b1ea74
	 * access to it. Its Unix access mode MUST be 0700.
Packit Service fa4841
	 *
Packit Service b1ea74
	 * The lifetime of the directory MUST be bound to the user being logged in. It MUST be created
Packit Service b1ea74
	 * when the user first logs in and if the user fully logs out the directory MUST be removed. If
Packit Service b1ea74
	 * the user logs in more than once he should get pointed to the same directory, and it is
Packit Service b1ea74
	 * mandatory that the directory continues to exist from his first login to his last logout on
Packit Service b1ea74
	 * the system, and not removed in between. Files in the directory MUST not survive reboot or a
Packit Service fa4841
	 * full logout/login cycle.
Packit Service fa4841
	 *
Packit Service b1ea74
	 * The directory MUST be on a local file system and not shared with any other system. The
Packit Service b1ea74
	 * directory MUST by fully-featured by the standards of the operating system. More specifically,
Packit Service b1ea74
	 * on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper
Packit Service b1ea74
	 * permissions, file locking, sparse files, memory mapping, file change notifications, a
Packit Service b1ea74
	 * reliable hard link count must be supported, and no restrictions on the file name character
Packit Service b1ea74
	 * set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To
Packit Service b1ea74
	 * ensure that your files are not removed, they should have their access time timestamp modified
Packit Service b1ea74
	 * at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
Packit Service fa4841
	 *
Packit Service b1ea74
	 * If $XDG_RUNTIME_DIR is not set applications should fall back to a replacement directory with
Packit Service b1ea74
	 * similar capabilities and print a warning message. Applications should use this directory for
Packit Service b1ea74
	 * communication and synchronization purposes and should not place larger files in it, since it
Packit Service b1ea74
	 * might reside in runtime memory and cannot necessarily be swapped out to disk.
Packit Service fa4841
	 */
Packit Service fa4841
	path = GetEnvAlloc("XDG_RUNTIME_DIR");
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
	if (path)
Packit Service fa4841
		return path;
Packit Service fa4841
Packit Service fa4841
	path = GetPath_TEMP();
Packit Service fa4841
	return path;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* GetKnownPath(int id)
Packit Service fa4841
{
Packit Service fa4841
	char* path = NULL;
Packit Service fa4841
Packit Service fa4841
	switch (id)
Packit Service fa4841
	{
Packit Service fa4841
		case KNOWN_PATH_HOME:
Packit Service fa4841
			path = GetPath_HOME();
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case KNOWN_PATH_TEMP:
Packit Service fa4841
			path = GetPath_TEMP();
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case KNOWN_PATH_XDG_DATA_HOME:
Packit Service fa4841
			path = GetPath_XDG_DATA_HOME();
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case KNOWN_PATH_XDG_CONFIG_HOME:
Packit Service fa4841
			path = GetPath_XDG_CONFIG_HOME();
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case KNOWN_PATH_XDG_CACHE_HOME:
Packit Service fa4841
			path = GetPath_XDG_CACHE_HOME();
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case KNOWN_PATH_XDG_RUNTIME_DIR:
Packit Service fa4841
			path = GetPath_XDG_RUNTIME_DIR();
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			path = NULL;
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return path;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* GetKnownSubPath(int id, const char* path)
Packit Service fa4841
{
Packit Service fa4841
	char* subPath;
Packit Service fa4841
	char* knownPath;
Packit Service fa4841
	knownPath = GetKnownPath(id);
Packit Service fa4841
Packit Service fa4841
	if (!knownPath)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	subPath = GetCombinedPath(knownPath, path);
Packit Service fa4841
	free(knownPath);
Packit Service fa4841
	return subPath;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* GetEnvironmentPath(char* name)
Packit Service fa4841
{
Packit Service fa4841
	char* env = NULL;
Packit Service fa4841
	DWORD nSize;
Packit Service fa4841
	nSize = GetEnvironmentVariableA(name, NULL, 0);
Packit Service fa4841
Packit Service fa4841
	if (nSize)
Packit Service fa4841
	{
Packit Service b1ea74
		env = (LPSTR)malloc(nSize);
Packit Service fa4841
Packit Service fa4841
		if (!env)
Packit Service fa4841
			return NULL;
Packit Service fa4841
Packit Service fa4841
		if (GetEnvironmentVariableA(name, env, nSize) != nSize - 1)
Packit Service fa4841
		{
Packit Service fa4841
			free(env);
Packit Service fa4841
			return NULL;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return env;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* GetEnvironmentSubPath(char* name, const char* path)
Packit Service fa4841
{
Packit Service fa4841
	char* env;
Packit Service fa4841
	char* subpath;
Packit Service fa4841
	env = GetEnvironmentPath(name);
Packit Service fa4841
Packit Service fa4841
	if (!env)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	subpath = GetCombinedPath(env, path);
Packit Service fa4841
	free(env);
Packit Service fa4841
	return subpath;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* GetCombinedPath(const char* basePath, const char* subPath)
Packit Service fa4841
{
Packit Service fa4841
	int length;
Packit Service fa4841
	HRESULT status;
Packit Service fa4841
	char* path = NULL;
Packit Service fa4841
	char* subPathCpy;
Packit Service fa4841
	int basePathLength = 0;
Packit Service fa4841
	int subPathLength = 0;
Packit Service fa4841
Packit Service fa4841
	if (basePath)
Packit Service b1ea74
		basePathLength = (int)strlen(basePath);
Packit Service fa4841
Packit Service fa4841
	if (subPath)
Packit Service b1ea74
		subPathLength = (int)strlen(subPath);
Packit Service fa4841
Packit Service fa4841
	length = basePathLength + subPathLength + 1;
Packit Service b1ea74
	path = (char*)malloc(length + 1);
Packit Service fa4841
Packit Service fa4841
	if (!path)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (basePath)
Packit Service fa4841
		CopyMemory(path, basePath, basePathLength);
Packit Service fa4841
Packit Service fa4841
	path[basePathLength] = '\0';
Packit Service fa4841
Packit Service fa4841
	if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
Packit Service fa4841
	{
Packit Service fa4841
		free(path);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!subPath)
Packit Service fa4841
		return path;
Packit Service fa4841
Packit Service fa4841
	subPathCpy = _strdup(subPath);
Packit Service fa4841
Packit Service fa4841
	if (!subPathCpy)
Packit Service fa4841
	{
Packit Service fa4841
		free(path);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
Packit Service fa4841
	{
Packit Service fa4841
		free(path);
Packit Service fa4841
		free(subPathCpy);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	status = NativePathCchAppendA(path, length + 1, subPathCpy);
Packit Service fa4841
	free(subPathCpy);
Packit Service fa4841
Packit Service fa4841
	if (FAILED(status))
Packit Service fa4841
	{
Packit Service fa4841
		free(path);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
		return path;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL PathMakePathA(LPCSTR path, LPSECURITY_ATTRIBUTES lpAttributes)
Packit Service fa4841
{
Packit Service fa4841
#if defined(_UWP)
Packit Service fa4841
	return FALSE;
Packit Service fa4841
#elif defined(_WIN32)
Packit Service fa4841
	return (SHCreateDirectoryExA(NULL, path, lpAttributes) == ERROR_SUCCESS);
Packit Service fa4841
#else
Packit Service fa4841
	const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
Packit Service fa4841
	char* dup;
Packit Service fa4841
	char* p;
Packit Service fa4841
	BOOL result = TRUE;
Packit Service bb5c11
	/* we only operate on a non-null, absolute path */
Packit Service b1ea74
#if defined(__OS2__)
Packit Service b1ea74
Packit Service b1ea74
	if (!path)
Packit Service b1ea74
		return FALSE;
Packit Service b1ea74
Packit Service b1ea74
#else
Packit Service b1ea74
Packit Service fa4841
	if (!path || *path != delim)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service b1ea74
#endif
Packit Service b1ea74
Packit Service fa4841
	if (!(dup = _strdup(path)))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service b1ea74
#ifdef __OS2__
Packit Service b1ea74
	p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
Packit Service b1ea74
Packit Service b1ea74
	while (p)
Packit Service b1ea74
#else
Packit Service fa4841
	for (p = dup; p;)
Packit Service b1ea74
#endif
Packit Service fa4841
	{
Packit Service fa4841
		if ((p = strchr(p + 1, delim)))
Packit Service b1ea74
			*p = '\0';
Packit Service fa4841
Packit Service fa4841
		if (mkdir(dup, 0777) != 0)
Packit Service fa4841
			if (errno != EEXIST)
Packit Service fa4841
			{
Packit Service fa4841
				result = FALSE;
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
		if (p)
Packit Service fa4841
			*p = delim;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(dup);
Packit Service fa4841
	return (result);
Packit Service fa4841
#endif
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#if !defined(_WIN32) || defined(_UWP)
Packit Service fa4841
Packit Service b1ea74
BOOL PathIsRelativeA(LPCSTR pszPath)
Packit Service b1ea74
{
Packit Service b1ea74
	if (!pszPath)
Packit Service b1ea74
		return FALSE;
Packit Service b1ea74
Packit Service b1ea74
	return pszPath[0] != '/';
Packit Service b1ea74
}
Packit Service b1ea74
Packit Service b1ea74
BOOL PathIsRelativeW(LPCWSTR pszPath)
Packit Service b1ea74
{
Packit Service b1ea74
	LPSTR lpFileNameA = NULL;
Packit Service b1ea74
	BOOL ret;
Packit Service b1ea74
Packit Service b1ea74
	if (ConvertFromUnicode(CP_UTF8, 0, pszPath, -1, &lpFileNameA, 0, NULL, NULL) < 1)
Packit Service b1ea74
		return FALSE;
Packit Service b1ea74
Packit Service b1ea74
	ret = PathIsRelativeA(lpFileNameA);
Packit Service b1ea74
	free(lpFileNameA);
Packit Service b1ea74
	return ret;
Packit Service b1ea74
}
Packit Service b1ea74
Packit Service fa4841
BOOL PathFileExistsA(LPCSTR pszPath)
Packit Service fa4841
{
Packit Service fa4841
	struct stat stat_info;
Packit Service fa4841
Packit Service fa4841
	if (stat(pszPath, &stat_info) != 0)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL PathFileExistsW(LPCWSTR pszPath)
Packit Service fa4841
{
Packit Service fa4841
	LPSTR lpFileNameA = NULL;
Packit Service fa4841
	BOOL ret;
Packit Service fa4841
Packit Service fa4841
	if (ConvertFromUnicode(CP_UTF8, 0, pszPath, -1, &lpFileNameA, 0, NULL, NULL) < 1)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	ret = PathFileExistsA(lpFileNameA);
Packit Service fa4841
	free(lpFileNameA);
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
Packit Service fa4841
{
Packit Service fa4841
	struct dirent* dp;
Packit Service fa4841
	int empty = 1;
Packit Service fa4841
	DIR* dir = opendir(pszPath);
Packit Service fa4841
Packit Service fa4841
	if (dir == NULL) /* Not a directory or doesn't exist */
Packit Service fa4841
		return 1;
Packit Service fa4841
Packit Service fa4841
	while ((dp = readdir(dir)) != NULL)
Packit Service fa4841
	{
Packit Service fa4841
		if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
Packit Service b1ea74
			continue; /* Skip . and .. */
Packit Service fa4841
Packit Service fa4841
		empty = 0;
Packit Service fa4841
		break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	closedir(dir);
Packit Service fa4841
	return empty;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
Packit Service fa4841
{
Packit Service fa4841
	LPSTR lpFileNameA = NULL;
Packit Service fa4841
	BOOL ret;
Packit Service fa4841
Packit Service fa4841
	if (ConvertFromUnicode(CP_UTF8, 0, pszPath, -1, &lpFileNameA, 0, NULL, NULL) < 1)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	ret = PathIsDirectoryEmptyA(lpFileNameA);
Packit Service fa4841
	free(lpFileNameA);
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#else
Packit Service fa4841
Packit Service fa4841
#ifdef _WIN32
Packit Service fa4841
#pragma comment(lib, "shlwapi.lib")
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#endif