mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-13 08:29:53 +00:00
256 lines
7.4 KiB
C++
256 lines
7.4 KiB
C++
/* Functions used by the Windows port of libgccjit.
|
|
Copyright (C) 2020-2022 Free Software Foundation, Inc.
|
|
Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include "config.h"
|
|
|
|
/* Required for rand_s */
|
|
#define _CRT_RAND_S
|
|
|
|
#include <cstdio>
|
|
#include <cstdint>
|
|
|
|
#include "jit-w32.h"
|
|
|
|
#include "libiberty.h"
|
|
|
|
#include <accctrl.h>
|
|
#include <aclapi.h>
|
|
|
|
namespace gcc {
|
|
namespace jit {
|
|
void
|
|
print_last_error (void)
|
|
{
|
|
LPSTR psz = NULL;
|
|
DWORD dwErrorCode;
|
|
dwErrorCode = GetLastError();
|
|
const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
|
|
| FORMAT_MESSAGE_IGNORE_INSERTS
|
|
| FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
| FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
|
NULL,
|
|
dwErrorCode,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
reinterpret_cast<LPSTR>(&psz),
|
|
0,
|
|
NULL);
|
|
if (cchMsg > 0)
|
|
{
|
|
fprintf (stderr, "%s\n", psz);
|
|
LocalFree (psz);
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr, "Failed to retrieve error message string for error %lu\n",
|
|
dwErrorCode);
|
|
}
|
|
}
|
|
|
|
/* Helper function used for getting the SID belonging to the current user. */
|
|
static TOKEN_USER*
|
|
get_TOKEN_USER_current_user ()
|
|
{
|
|
TOKEN_USER *result = NULL;
|
|
|
|
HANDLE process_token = INVALID_HANDLE_VALUE;
|
|
|
|
DWORD token_user_info_len;
|
|
TOKEN_USER *token_user = NULL;
|
|
|
|
/* Get current process access token. */
|
|
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ,
|
|
&process_token))
|
|
return NULL;
|
|
|
|
/* Get necessary buffer size. */
|
|
if (!GetTokenInformation(process_token, TokenUser, NULL, 0, &token_user_info_len)
|
|
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
goto cleanup;
|
|
|
|
token_user = (TOKEN_USER*) new char[token_user_info_len];
|
|
|
|
/* Get info about the user of the process */
|
|
if (!GetTokenInformation (process_token, TokenUser, token_user,
|
|
token_user_info_len, &token_user_info_len))
|
|
goto cleanup;
|
|
|
|
result = token_user;
|
|
|
|
cleanup:
|
|
if (process_token != INVALID_HANDLE_VALUE)
|
|
CloseHandle(process_token);
|
|
|
|
if (token_user != NULL && result == NULL)
|
|
delete[] (char*)token_user;
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Helper function to create a directory with permissions such that only the
|
|
current user can access it. */
|
|
static bool
|
|
create_directory_for_current_user (const char * path)
|
|
{
|
|
PACL pACL = NULL;
|
|
EXPLICIT_ACCESS ea;
|
|
SECURITY_ATTRIBUTES sa;
|
|
SECURITY_DESCRIPTOR SD;
|
|
DWORD dwRes;
|
|
bool result = true;
|
|
TOKEN_USER *token_user = NULL;
|
|
|
|
token_user = get_TOKEN_USER_current_user();
|
|
if (!token_user)
|
|
return false;
|
|
|
|
memset (&ea, 0, sizeof (EXPLICIT_ACCESS));
|
|
ea.grfAccessPermissions = GENERIC_ALL; /* Access to all. */
|
|
ea.grfAccessMode = SET_ACCESS; /* Set access and revoke everything else. */
|
|
/* This is necessary for the Windows Explorer GUI to show the correct tick
|
|
boxes in the "Security" tab. */
|
|
ea.grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
|
|
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
|
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
|
|
ea.Trustee.ptstrName = (char*) token_user->User.Sid;
|
|
|
|
/* Create a new ACL that contains the new ACEs. */
|
|
dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
|
|
if (dwRes != ERROR_SUCCESS)
|
|
return false;
|
|
|
|
if (!InitializeSecurityDescriptor (&SD,
|
|
SECURITY_DESCRIPTOR_REVISION))
|
|
goto cleanup;
|
|
|
|
/* Add the ACL to the security descriptor. */
|
|
if (!SetSecurityDescriptorDacl (&SD,
|
|
TRUE, /* use pACL */
|
|
pACL,
|
|
FALSE)) /* not a default DACL */
|
|
goto cleanup;
|
|
|
|
/* Initialize a security attributes structure. */
|
|
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = &SD;
|
|
sa.bInheritHandle = FALSE;
|
|
|
|
/* Finally create the directory */
|
|
if (!CreateDirectoryA (path, &sa))
|
|
result = false;
|
|
|
|
cleanup:
|
|
if (pACL)
|
|
LocalFree (pACL);
|
|
|
|
if (token_user)
|
|
delete[] (char*)token_user;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
char *
|
|
win_mkdtemp (void)
|
|
{
|
|
char lpTempPathBuffer[MAX_PATH];
|
|
|
|
/* Gets the temp path env string (no guarantee it's a valid path). */
|
|
DWORD dwRetVal = GetTempPath (MAX_PATH, lpTempPathBuffer);
|
|
if (dwRetVal > MAX_PATH || (dwRetVal == 0))
|
|
{
|
|
print_last_error ();
|
|
return NULL;
|
|
}
|
|
|
|
/* Check that the directory actually exists. */
|
|
DWORD dwAttrib = GetFileAttributes (lpTempPathBuffer);
|
|
bool temp_path_exists = (dwAttrib != INVALID_FILE_ATTRIBUTES
|
|
&& (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
if (!temp_path_exists)
|
|
{
|
|
fprintf (stderr, "Path returned by GetTempPath does not exist: %s\n",
|
|
lpTempPathBuffer);
|
|
}
|
|
|
|
/* Make sure there is enough space in the buffer for the prefix and random
|
|
number.*/
|
|
int temp_path_buffer_len = dwRetVal;
|
|
const int appended_len = strlen ("\\libgccjit-123456");
|
|
if (temp_path_buffer_len + appended_len + 1 >= MAX_PATH)
|
|
{
|
|
fprintf (stderr, "Temporary file path too long for generation of random"
|
|
" directories: %s", lpTempPathBuffer);
|
|
}
|
|
|
|
/* This is all the space we have in the buffer to store the random number and
|
|
prefix. */
|
|
int extraspace = MAX_PATH - temp_path_buffer_len - 1;
|
|
|
|
int tries;
|
|
const int max_tries = 1000;
|
|
|
|
for (tries = 0; tries < max_tries; ++tries)
|
|
{
|
|
/* Get a random number in [0; UINT_MAX]. */
|
|
unsigned int rand_num;
|
|
if (rand_s (&rand_num) != 0)
|
|
{
|
|
fprintf (stderr,
|
|
"Failed to create a random number using rand_s(): %s\n",
|
|
_strerror (NULL));
|
|
return NULL;
|
|
}
|
|
|
|
/* Create 6 digits random number. */
|
|
rand_num = ((double)rand_num / ((double) UINT_MAX + 1 ) * 1000000);
|
|
|
|
/* Copy the prefix and random number to the buffer. */
|
|
snprintf (&lpTempPathBuffer[temp_path_buffer_len], extraspace,
|
|
"\\libgccjit-%06u", rand_num);
|
|
|
|
if (create_directory_for_current_user (lpTempPathBuffer))
|
|
break; // success!
|
|
|
|
/* If we can't create the directory because we got unlucky and the
|
|
directory already exists retry, otherwise fail. */
|
|
if (GetLastError () != ERROR_ALREADY_EXISTS)
|
|
{
|
|
print_last_error ();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (tries == max_tries)
|
|
{
|
|
fprintf (stderr, "Failed to create a random directory in %s\n",
|
|
lpTempPathBuffer);
|
|
return NULL;
|
|
}
|
|
|
|
{
|
|
int allocate_len = temp_path_buffer_len + appended_len + 1;
|
|
char * result = XNEWVEC (char, allocate_len);
|
|
strcpy (result, lpTempPathBuffer);
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|