VirtualBox

source: kBuild/vendor/gnumake/current/w32/compat/posixfcn.c

Last change on this file was 3138, checked in by bird, 7 years ago

Imported make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6) from https://git.savannah.gnu.org/git/make.git.

  • Property svn:eol-style set to native
File size: 13.8 KB
Line 
1/* Replacements for Posix functions and Posix functionality for MS-Windows.
2
3Copyright (C) 2013-2016 Free Software Foundation, Inc.
4This file is part of GNU Make.
5
6GNU Make is free software; you can redistribute it and/or modify it under the
7terms of the GNU General Public License as published by the Free Software
8Foundation; either version 3 of the License, or (at your option) any later
9version.
10
11GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License along with
16this program. If not, see <http://www.gnu.org/licenses/>. */
17
18#include <string.h>
19#include <io.h>
20#include <stdarg.h>
21#include <errno.h>
22#include <windows.h>
23
24#include "dlfcn.h"
25
26#include "makeint.h"
27#include "job.h"
28
29#ifndef NO_OUTPUT_SYNC
30/* Support for OUTPUT_SYNC and related functionality. */
31
32/* Emulation of fcntl that supports only F_GETFD and F_SETLKW. */
33int
34fcntl (intptr_t fd, int cmd, ...)
35{
36 va_list ap;
37
38 va_start (ap, cmd);
39
40 switch (cmd)
41 {
42 case F_GETFD:
43 va_end (ap);
44 /* Could have used GetHandleInformation, but that isn't
45 supported on Windows 9X. */
46 if (_get_osfhandle (fd) == -1)
47 return -1;
48 return 0;
49 case F_SETLKW:
50 {
51 void *buf = va_arg (ap, void *);
52 struct flock *fl = (struct flock *)buf;
53 HANDLE hmutex = (HANDLE)fd;
54 static struct flock last_fl;
55 short last_type = last_fl.l_type;
56
57 va_end (ap);
58
59 if (hmutex == INVALID_HANDLE_VALUE || !hmutex)
60 return -1;
61
62 last_fl = *fl;
63
64 switch (fl->l_type)
65 {
66
67 case F_WRLCK:
68 {
69 DWORD result;
70
71 if (last_type == F_WRLCK)
72 {
73 /* Don't call WaitForSingleObject if we already
74 own the mutex, because doing so will require
75 us to call ReleaseMutex an equal number of
76 times, before the mutex is actually
77 released. */
78 return 0;
79 }
80
81 result = WaitForSingleObject (hmutex, INFINITE);
82 switch (result)
83 {
84 case WAIT_OBJECT_0:
85 /* We don't care if the mutex owner crashed or
86 exited. */
87 case WAIT_ABANDONED:
88 return 0;
89 case WAIT_FAILED:
90 case WAIT_TIMEOUT: /* cannot happen, really */
91 {
92 DWORD err = GetLastError ();
93
94 /* Invalidate the last command. */
95 memset (&last_fl, 0, sizeof (last_fl));
96
97 switch (err)
98 {
99 case ERROR_INVALID_HANDLE:
100 case ERROR_INVALID_FUNCTION:
101 errno = EINVAL;
102 return -1;
103 default:
104 errno = EDEADLOCK;
105 return -1;
106 }
107 }
108 }
109 }
110 case F_UNLCK:
111 {
112 /* FIXME: Perhaps we should call ReleaseMutex
113 repatedly until it errors out, to make sure the
114 mutext is released even if we somehow managed to
115 to take ownership multiple times? */
116 BOOL status = ReleaseMutex (hmutex);
117
118 if (status)
119 return 0;
120 else
121 {
122 DWORD err = GetLastError ();
123
124 if (err == ERROR_NOT_OWNER)
125 errno = EPERM;
126 else
127 {
128 memset (&last_fl, 0, sizeof (last_fl));
129 errno = EINVAL;
130 }
131 return -1;
132 }
133 }
134 default:
135 errno = ENOSYS;
136 return -1;
137 }
138 }
139 default:
140 errno = ENOSYS;
141 va_end (ap);
142 return -1;
143 }
144}
145
146static intptr_t mutex_handle = -1;
147
148/* Record in a static variable the mutex handle we were requested to
149 use. That nameless mutex was created by the top-level Make, and
150 its handle was passed to us via inheritance. The value of that
151 handle is passed via the command-line arguments, so that we know
152 which handle to use. */
153void
154record_sync_mutex (const char *str)
155{
156 char *endp;
157 intptr_t hmutex = strtol (str, &endp, 16);
158
159 if (*endp == '\0')
160 mutex_handle = hmutex;
161 else
162 {
163 mutex_handle = -1;
164 errno = EINVAL;
165 }
166}
167
168/* Create a new mutex or reuse one created by our parent. */
169intptr_t
170create_mutex (void)
171{
172 SECURITY_ATTRIBUTES secattr;
173 intptr_t hmutex = -1;
174
175 /* If we have a mutex handle passed from the parent Make, just use
176 that. */
177 if (mutex_handle > 0)
178 return mutex_handle;
179
180 /* We are the top-level Make, and we want the handle to be inherited
181 by our child processes. */
182 secattr.nLength = sizeof (secattr);
183 secattr.lpSecurityDescriptor = NULL; /* use default security descriptor */
184 secattr.bInheritHandle = TRUE;
185
186 hmutex = (intptr_t)CreateMutex (&secattr, FALSE, NULL);
187 if (!hmutex)
188 {
189 DWORD err = GetLastError ();
190
191 fprintf (stderr, "CreateMutex: error %lu\n", err);
192 errno = ENOLCK;
193 hmutex = -1;
194 }
195
196 mutex_handle = hmutex;
197 return hmutex;
198}
199
200/* Return non-zero if F1 and F2 are 2 streams representing the same
201 file or pipe or device. */
202int
203same_stream (FILE *f1, FILE *f2)
204{
205 HANDLE fh1 = (HANDLE)_get_osfhandle (fileno (f1));
206 HANDLE fh2 = (HANDLE)_get_osfhandle (fileno (f2));
207
208 /* Invalid file descriptors get treated as different streams. */
209 if (fh1 && fh1 != INVALID_HANDLE_VALUE
210 && fh2 && fh2 != INVALID_HANDLE_VALUE)
211 {
212 if (fh1 == fh2)
213 return 1;
214 else
215 {
216 DWORD ftyp1 = GetFileType (fh1), ftyp2 = GetFileType (fh2);
217
218 if (ftyp1 != ftyp2
219 || ftyp1 == FILE_TYPE_UNKNOWN || ftyp2 == FILE_TYPE_UNKNOWN)
220 return 0;
221 else if (ftyp1 == FILE_TYPE_CHAR)
222 {
223 /* For character devices, check if they both refer to a
224 console. This loses if both handles refer to the
225 null device (FIXME!), but in that case we don't care
226 in the context of Make. */
227 DWORD conmode1, conmode2;
228
229 /* Each process on Windows can have at most 1 console,
230 so if both handles are for the console device, they
231 are the same. We also compare the console mode to
232 distinguish between stdin and stdout/stderr. */
233 if (GetConsoleMode (fh1, &conmode1)
234 && GetConsoleMode (fh2, &conmode2)
235 && conmode1 == conmode2)
236 return 1;
237 }
238 else
239 {
240 /* For disk files and pipes, compare their unique
241 attributes. */
242 BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
243
244 /* Pipes get zero in the volume serial number, but do
245 appear to have meaningful information in file index
246 attributes. We test file attributes as well, for a
247 good measure. */
248 if (GetFileInformationByHandle (fh1, &bhfi1)
249 && GetFileInformationByHandle (fh2, &bhfi2))
250 return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
251 && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow
252 && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
253 && bhfi1.dwFileAttributes == bhfi2.dwFileAttributes);
254 }
255 }
256 }
257 return 0;
258}
259
260/* A replacement for tmpfile, since the MSVCRT implementation creates
261 the file in the root directory of the current drive, which might
262 not be writable by our user. Most of the code borrowed from
263 create_batch_file, see job.c. */
264FILE *
265tmpfile (void)
266{
267 char temp_path[MAXPATHLEN];
268 unsigned path_size = GetTempPath (sizeof temp_path, temp_path);
269 int path_is_dot = 0;
270 /* The following variable is static so we won't try to reuse a name
271 that was generated a little while ago, because that file might
272 not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below,
273 which tells the OS it doesn't need to flush the cache to disk.
274 If the file is not yet on disk, we might think the name is
275 available, while it really isn't. This happens in parallel
276 builds, where Make doesn't wait for one job to finish before it
277 launches the next one. */
278 static unsigned uniq = 0;
279 static int second_loop = 0;
280 const char base[] = "gmake_tmpf";
281 const unsigned sizemax = sizeof base - 1 + 4 + 10 + 10;
282 unsigned pid = GetCurrentProcessId ();
283
284 if (path_size == 0)
285 {
286 path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
287 path_is_dot = 1;
288 }
289
290 ++uniq;
291 if (uniq >= 0x10000 && !second_loop)
292 {
293 /* If we already had 64K batch files in this
294 process, make a second loop through the numbers,
295 looking for free slots, i.e. files that were
296 deleted in the meantime. */
297 second_loop = 1;
298 uniq = 1;
299 }
300 while (path_size > 0 &&
301 path_size + sizemax < sizeof temp_path &&
302 !(uniq >= 0x10000 && second_loop))
303 {
304 HANDLE h;
305
306 sprintf (temp_path + path_size,
307 "%s%s%u-%x.tmp",
308 temp_path[path_size - 1] == '\\' ? "" : "\\",
309 base, pid, uniq);
310 h = CreateFile (temp_path, /* file name */
311 GENERIC_READ | GENERIC_WRITE | DELETE, /* desired access */
312 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
313 NULL, /* default security attributes */
314 CREATE_NEW, /* creation disposition */
315 FILE_ATTRIBUTE_NORMAL | /* flags and attributes */
316 FILE_ATTRIBUTE_TEMPORARY |
317 FILE_FLAG_DELETE_ON_CLOSE,
318 NULL); /* no template file */
319
320 if (h == INVALID_HANDLE_VALUE)
321 {
322 const DWORD er = GetLastError ();
323
324 if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS)
325 {
326 ++uniq;
327 if (uniq == 0x10000 && !second_loop)
328 {
329 second_loop = 1;
330 uniq = 1;
331 }
332 }
333
334 /* The temporary path is not guaranteed to exist, or might
335 not be writable by user. Use the current directory as
336 fallback. */
337 else if (path_is_dot == 0)
338 {
339 path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
340 path_is_dot = 1;
341 }
342
343 else
344 {
345 errno = EACCES;
346 break;
347 }
348 }
349 else
350 {
351 int fd = _open_osfhandle ((intptr_t)h, 0);
352
353 return _fdopen (fd, "w+b");
354 }
355 }
356
357 if (uniq >= 0x10000)
358 errno = EEXIST;
359 return NULL;
360}
361
362#endif /* !NO_OUTPUT_SYNC */
363
364#if MAKE_LOAD
365
366/* Support for dynamic loading of objects. */
367
368
369static DWORD last_err;
370
371void *
372dlopen (const char *file, int mode)
373{
374 char dllfn[MAX_PATH], *p;
375 HANDLE dllhandle;
376
377 if ((mode & ~(RTLD_LAZY | RTLD_NOW | RTLD_GLOBAL)) != 0)
378 {
379 errno = EINVAL;
380 last_err = ERROR_INVALID_PARAMETER;
381 return NULL;
382 }
383
384 if (!file)
385 dllhandle = GetModuleHandle (NULL);
386 else
387 {
388 /* MSDN says to be sure to use backslashes in the DLL file name. */
389 strcpy (dllfn, file);
390 for (p = dllfn; *p; p++)
391 if (*p == '/')
392 *p = '\\';
393
394 dllhandle = LoadLibrary (dllfn);
395 }
396 if (!dllhandle)
397 last_err = GetLastError ();
398
399 return dllhandle;
400}
401
402char *
403dlerror (void)
404{
405 static char errbuf[1024];
406 DWORD ret;
407
408 if (!last_err)
409 return NULL;
410
411 ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
412 | FORMAT_MESSAGE_IGNORE_INSERTS,
413 NULL, last_err, 0, errbuf, sizeof (errbuf), NULL);
414 while (ret > 0 && (errbuf[ret - 1] == '\n' || errbuf[ret - 1] == '\r'))
415 --ret;
416
417 errbuf[ret] = '\0';
418 if (!ret)
419 sprintf (errbuf, "Error code %lu", last_err);
420
421 last_err = 0;
422 return errbuf;
423}
424
425void *
426dlsym (void *handle, const char *name)
427{
428 FARPROC addr = NULL;
429
430 if (!handle || handle == INVALID_HANDLE_VALUE)
431 {
432 last_err = ERROR_INVALID_PARAMETER;
433 return NULL;
434 }
435
436 addr = GetProcAddress (handle, name);
437 if (!addr)
438 last_err = GetLastError ();
439
440 return (void *)addr;
441}
442
443int
444dlclose (void *handle)
445{
446 if (!handle || handle == INVALID_HANDLE_VALUE)
447 return -1;
448 if (!FreeLibrary (handle))
449 return -1;
450
451 return 0;
452}
453
454
455#endif /* MAKE_LOAD */
456
457
458/* MS runtime's isatty returns non-zero for any character device,
459 including the null device, which is not what we want. */
460int
461isatty (int fd)
462{
463 HANDLE fh = (HANDLE) _get_osfhandle (fd);
464 DWORD con_mode;
465
466 if (fh == INVALID_HANDLE_VALUE)
467 {
468 errno = EBADF;
469 return 0;
470 }
471 if (GetConsoleMode (fh, &con_mode))
472 return 1;
473
474 errno = ENOTTY;
475 return 0;
476}
477
478char *
479ttyname (int fd)
480{
481 /* This "knows" that Make only asks about stdout and stderr. A more
482 sophisticated implementation should test whether FD is open for
483 input or output. We can do that by looking at the mode returned
484 by GetConsoleMode. */
485 return "CONOUT$";
486}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette