1 /* Functions used by the Windows port of libgccjit.
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 /* Required for rand_s */
31 #include "libiberty.h"
39 print_last_error (void)
43 dwErrorCode
= GetLastError();
44 const DWORD cchMsg
= FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
45 | FORMAT_MESSAGE_IGNORE_INSERTS
46 | FORMAT_MESSAGE_ALLOCATE_BUFFER
47 | FORMAT_MESSAGE_MAX_WIDTH_MASK
,
50 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
51 reinterpret_cast<LPSTR
>(&psz
),
56 fprintf (stderr
, "%s\n", psz
);
61 fprintf (stderr
, "Failed to retrieve error message string for error %lu\n",
66 /* Helper function used for getting the SID belonging to the current user. */
68 get_TOKEN_USER_current_user ()
70 TOKEN_USER
*result
= NULL
;
72 HANDLE process_token
= INVALID_HANDLE_VALUE
;
74 DWORD token_user_info_len
;
75 TOKEN_USER
*token_user
= NULL
;
77 /* Get current process access token. */
78 if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ
,
82 /* Get necessary buffer size. */
83 if (!GetTokenInformation(process_token
, TokenUser
, NULL
, 0, &token_user_info_len
)
84 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
87 token_user
= (TOKEN_USER
*) new char[token_user_info_len
];
89 /* Get info about the user of the process */
90 if (!GetTokenInformation (process_token
, TokenUser
, token_user
,
91 token_user_info_len
, &token_user_info_len
))
97 if (process_token
!= INVALID_HANDLE_VALUE
)
98 CloseHandle(process_token
);
100 if (token_user
!= NULL
&& result
== NULL
)
101 delete[] (char*)token_user
;
106 /* Helper function to create a directory with permissions such that only the
107 current user can access it. */
109 create_directory_for_current_user (const char * path
)
113 SECURITY_ATTRIBUTES sa
;
114 SECURITY_DESCRIPTOR SD
;
117 TOKEN_USER
*token_user
= NULL
;
119 token_user
= get_TOKEN_USER_current_user();
123 memset (&ea
, 0, sizeof (EXPLICIT_ACCESS
));
124 ea
.grfAccessPermissions
= GENERIC_ALL
; /* Access to all. */
125 ea
.grfAccessMode
= SET_ACCESS
; /* Set access and revoke everything else. */
126 /* This is necessary for the Windows Explorer GUI to show the correct tick
127 boxes in the "Security" tab. */
128 ea
.grfInheritance
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
;
129 ea
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
130 ea
.Trustee
.TrusteeType
= TRUSTEE_IS_USER
;
131 ea
.Trustee
.ptstrName
= (char*) token_user
->User
.Sid
;
133 /* Create a new ACL that contains the new ACEs. */
134 dwRes
= SetEntriesInAcl(1, &ea
, NULL
, &pACL
);
135 if (dwRes
!= ERROR_SUCCESS
)
138 if (!InitializeSecurityDescriptor (&SD
,
139 SECURITY_DESCRIPTOR_REVISION
))
142 /* Add the ACL to the security descriptor. */
143 if (!SetSecurityDescriptorDacl (&SD
,
146 FALSE
)) /* not a default DACL */
149 /* Initialize a security attributes structure. */
150 sa
.nLength
= sizeof (SECURITY_ATTRIBUTES
);
151 sa
.lpSecurityDescriptor
= &SD
;
152 sa
.bInheritHandle
= FALSE
;
154 /* Finally create the directory */
155 if (!CreateDirectoryA (path
, &sa
))
163 delete[] (char*)token_user
;
172 char lpTempPathBuffer
[MAX_PATH
];
174 /* Gets the temp path env string (no guarantee it's a valid path). */
175 DWORD dwRetVal
= GetTempPath (MAX_PATH
, lpTempPathBuffer
);
176 if (dwRetVal
> MAX_PATH
|| (dwRetVal
== 0))
182 /* Check that the directory actually exists. */
183 DWORD dwAttrib
= GetFileAttributes (lpTempPathBuffer
);
184 bool temp_path_exists
= (dwAttrib
!= INVALID_FILE_ATTRIBUTES
185 && (dwAttrib
& FILE_ATTRIBUTE_DIRECTORY
));
186 if (!temp_path_exists
)
188 fprintf (stderr
, "Path returned by GetTempPath does not exist: %s\n",
192 /* Make sure there is enough space in the buffer for the prefix and random
194 int temp_path_buffer_len
= dwRetVal
;
195 const int appended_len
= strlen ("\\libgccjit-123456");
196 if (temp_path_buffer_len
+ appended_len
+ 1 >= MAX_PATH
)
198 fprintf (stderr
, "Temporary file path too long for generation of random"
199 " directories: %s", lpTempPathBuffer
);
202 /* This is all the space we have in the buffer to store the random number and
204 int extraspace
= MAX_PATH
- temp_path_buffer_len
- 1;
207 const int max_tries
= 1000;
209 for (tries
= 0; tries
< max_tries
; ++tries
)
211 /* Get a random number in [0; UINT_MAX]. */
212 unsigned int rand_num
;
213 if (rand_s (&rand_num
) != 0)
216 "Failed to create a random number using rand_s(): %s\n",
221 /* Create 6 digits random number. */
222 rand_num
= ((double)rand_num
/ ((double) UINT_MAX
+ 1 ) * 1000000);
224 /* Copy the prefix and random number to the buffer. */
225 snprintf (&lpTempPathBuffer
[temp_path_buffer_len
], extraspace
,
226 "\\libgccjit-%06u", rand_num
);
228 if (create_directory_for_current_user (lpTempPathBuffer
))
231 /* If we can't create the directory because we got unlucky and the
232 directory already exists retry, otherwise fail. */
233 if (GetLastError () != ERROR_ALREADY_EXISTS
)
240 if (tries
== max_tries
)
242 fprintf (stderr
, "Failed to create a random directory in %s\n",
248 int allocate_len
= temp_path_buffer_len
+ appended_len
+ 1;
249 char * result
= XNEWVEC (char, allocate_len
);
250 strcpy (result
, lpTempPathBuffer
);