mirror of
https://github.com/mirror/make.git
synced 2025-02-24 18:50:25 +08:00
Fix tmpfile on MS-Windows.
w32/compat/posixfcn.c (tmpfile): New function, a replacement for the Windows libc version.
This commit is contained in:
parent
f8786092ad
commit
98197303b1
@ -1,5 +1,8 @@
|
||||
2013-10-02 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
* w32/compat/posixfcn.c (tmpfile): New function, a replacement for
|
||||
the Windows libc version.
|
||||
|
||||
Fix $abspath on Cygwin when HAVE_DOS_PATHS is in effect.
|
||||
* function.c (IS_ABSOLUTE) [__CYGWIN__]: Special definition for
|
||||
Cygwin.
|
||||
|
@ -257,6 +257,106 @@ same_stream (FILE *f1, FILE *f2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A replacement for tmpfile, since the MSVCRT implementation creates
|
||||
the file in the root directory of the current drive, which might
|
||||
not be writable by our user. Most of the code borrowed from
|
||||
create_batch_file, see job.c. */
|
||||
FILE *
|
||||
tmpfile (void)
|
||||
{
|
||||
char temp_path[MAXPATHLEN];
|
||||
unsigned path_size = GetTempPath (sizeof temp_path, temp_path);
|
||||
int path_is_dot = 0;
|
||||
/* The following variable is static so we won't try to reuse a name
|
||||
that was generated a little while ago, because that file might
|
||||
not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below,
|
||||
which tells the OS it doesn't need to flush the cache to disk.
|
||||
If the file is not yet on disk, we might think the name is
|
||||
available, while it really isn't. This happens in parallel
|
||||
builds, where Make doesn't wait for one job to finish before it
|
||||
launches the next one. */
|
||||
static unsigned uniq = 0;
|
||||
static int second_loop = 0;
|
||||
const char base[] = "gmake_tmpf";
|
||||
const unsigned sizemax = sizeof base - 1 + 4 + 10 + 10;
|
||||
unsigned pid = GetCurrentProcessId ();
|
||||
|
||||
if (path_size == 0)
|
||||
{
|
||||
path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
|
||||
path_is_dot = 1;
|
||||
}
|
||||
|
||||
++uniq;
|
||||
if (uniq >= 0x10000 && !second_loop)
|
||||
{
|
||||
/* If we already had 64K batch files in this
|
||||
process, make a second loop through the numbers,
|
||||
looking for free slots, i.e. files that were
|
||||
deleted in the meantime. */
|
||||
second_loop = 1;
|
||||
uniq = 1;
|
||||
}
|
||||
while (path_size > 0 &&
|
||||
path_size + sizemax < sizeof temp_path &&
|
||||
!(uniq >= 0x10000 && second_loop))
|
||||
{
|
||||
sprintf (temp_path + path_size,
|
||||
"%s%s%u-%x.tmp",
|
||||
temp_path[path_size - 1] == '\\' ? "" : "\\",
|
||||
base, pid, uniq);
|
||||
HANDLE h = CreateFile (temp_path, /* file name */
|
||||
GENERIC_READ | GENERIC_WRITE | DELETE, /* desired access */
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
|
||||
NULL, /* default security attributes */
|
||||
CREATE_NEW, /* creation disposition */
|
||||
FILE_ATTRIBUTE_NORMAL | /* flags and attributes */
|
||||
FILE_ATTRIBUTE_TEMPORARY |
|
||||
FILE_FLAG_DELETE_ON_CLOSE,
|
||||
NULL); /* no template file */
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const DWORD er = GetLastError ();
|
||||
|
||||
if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
++uniq;
|
||||
if (uniq == 0x10000 && !second_loop)
|
||||
{
|
||||
second_loop = 1;
|
||||
uniq = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The temporary path is not guaranteed to exist, or might
|
||||
not be writable by user. Use the current directory as
|
||||
fallback. */
|
||||
else if (path_is_dot == 0)
|
||||
{
|
||||
path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
|
||||
path_is_dot = 1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
errno = EACCES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int fd = _open_osfhandle ((intptr_t)h, 0);
|
||||
|
||||
return _fdopen (fd, "w+b");
|
||||
}
|
||||
}
|
||||
|
||||
if (uniq >= 0x10000)
|
||||
errno = EEXIST;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* !NO_OUTPUT_SYNC */
|
||||
|
||||
#if MAKE_LOAD
|
||||
|
Loading…
Reference in New Issue
Block a user