Imported Upstream version 4.0
[platform/upstream/make.git] / w32 / compat / posixfcn.c
1 /* Replacements for Posix functions and Posix functionality for MS-Windows.
2
3 Copyright (C) 2013 Free Software Foundation, Inc.
4 This file is part of GNU Make.
5
6 GNU Make is free software; you can redistribute it and/or modify it under the
7 terms of the GNU General Public License as published by the Free Software
8 Foundation; either version 3 of the License, or (at your option) any later
9 version.
10
11 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along with
16 this 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.  */
33 int
34 fcntl (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
146 static 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.  */
153 void
154 record_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.  */
169 intptr_t
170 create_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.  */
202 int
203 same_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.  */
264 FILE *
265 tmpfile (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
369 static DWORD last_err;
370
371 void *
372 dlopen (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
402 char *
403 dlerror (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
425 void *
426 dlsym (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
443 int
444 dlclose (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